Skip to content

Commit 47afb9f

Browse files
Copilotpelikhan
andauthored
Merge main into branch and recompile workflows
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
2 parents 15b3b30 + 9c19e9c commit 47afb9f

14 files changed

Lines changed: 984 additions & 931 deletions

File tree

.github/extensions/agentic-workflows-dashboard/dashboard-cli.mjs

Lines changed: 104 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,126 @@ import { constants as fsConstants } from "node:fs";
33
import { access } from "node:fs/promises";
44
import { join } from "node:path";
55

6-
function execp(bin, args, cwd) {
6+
const INSTALL_COMMAND = "gh extension install github/gh-aw";
7+
8+
function combineOutput(stdout, stderr) {
9+
return [stdout, stderr].filter(Boolean).join("\n").trim();
10+
}
11+
12+
function execp(bin, args, cwd, { combineIO = false, execFileFn = execFile, env = process.env } = {}) {
713
return new Promise((resolve, reject) => {
8-
execFile(
14+
execFileFn(
915
bin,
1016
args,
1117
{
1218
cwd,
13-
env: { ...process.env, NO_COLOR: "1", GH_NO_UPDATE_NOTIFIER: "1" },
19+
env: { ...env, CI: "1", NO_COLOR: "1", GH_NO_UPDATE_NOTIFIER: "1" },
1420
maxBuffer: 10 * 1024 * 1024,
1521
},
1622
(err, stdout, stderr) => {
17-
if (err) reject(Object.assign(err, { stderr: stderr ?? "" }));
18-
else resolve(stdout);
23+
const output = combineOutput(stdout ?? "", stderr ?? "");
24+
if (err) reject(Object.assign(err, { stderr: stderr ?? "", stdout: stdout ?? "", output }));
25+
else resolve(combineIO ? output : stdout);
1926
}
2027
);
2128
});
2229
}
2330

24-
export function createGhAwRunner({ getWorkspacePath }) {
31+
function parseVersionFromOutput(output) {
32+
const trimmed = String(output ?? "").trim();
33+
if (!trimmed) return "";
34+
const match = trimmed.match(/gh(?:-aw| aw) version ([^\r\n]+)/i);
35+
return match?.[1]?.trim() ?? "";
36+
}
37+
38+
function isMissingGhAwExtension(error) {
39+
const output = String(error?.output ?? error?.stderr ?? error?.message ?? "");
40+
return /extension not found:\s*aw/i.test(output) || /unknown command ["']aw["'] for ["']gh["']/i.test(output);
41+
}
42+
43+
async function findDevBinary(cwd, accessFn = access, platform = process.platform) {
44+
const devBin = join(cwd, platform === "win32" ? "gh-aw.exe" : "gh-aw");
45+
try {
46+
await accessFn(devBin, fsConstants.X_OK);
47+
return devBin;
48+
} catch {
49+
return null;
50+
}
51+
}
52+
53+
export function createGhAwRunner({ getWorkspacePath, accessFn = access, execFileFn = execFile, platform = process.platform, env = process.env }) {
54+
async function runExec(bin, args, cwd, options) {
55+
return execp(bin, args, cwd, { ...options, execFileFn, env });
56+
}
57+
2558
return async function runGhAw(args) {
2659
const cwd = getWorkspacePath();
27-
const isWin = process.platform === "win32";
28-
const devBin = join(cwd, isWin ? "gh-aw.exe" : "gh-aw");
60+
const devBin = await findDevBinary(cwd, accessFn, platform);
61+
if (devBin) {
62+
return runExec(devBin, args, cwd);
63+
}
64+
65+
return runExec("gh", ["aw", ...args], cwd);
66+
};
67+
}
68+
69+
export function createGhAwRunnerWithStatus(options) {
70+
const runGhAw = createGhAwRunner(options);
71+
const getStatus = async () => {
72+
const cwd = options.getWorkspacePath();
73+
const devBin = await findDevBinary(cwd, options.accessFn ?? access, options.platform ?? process.platform);
74+
75+
if (devBin) {
76+
const output = await execp(devBin, ["version"], cwd, {
77+
combineIO: true,
78+
execFileFn: options.execFileFn ?? execFile,
79+
env: options.env ?? process.env,
80+
});
81+
return {
82+
available: true,
83+
source: "dev-binary",
84+
version: parseVersionFromOutput(output) || "unknown",
85+
command: `${devBin} version`,
86+
installCommand: INSTALL_COMMAND,
87+
};
88+
}
89+
2990
try {
30-
await access(devBin, fsConstants.X_OK);
31-
return await execp(devBin, args, cwd);
32-
} catch {
33-
return await execp("gh", ["aw", ...args], cwd);
91+
const output = await execp("gh", ["aw", "version"], cwd, {
92+
combineIO: true,
93+
execFileFn: options.execFileFn ?? execFile,
94+
env: options.env ?? process.env,
95+
});
96+
return {
97+
available: true,
98+
source: "gh-extension",
99+
version: parseVersionFromOutput(output) || "unknown",
100+
command: "gh aw version",
101+
installCommand: INSTALL_COMMAND,
102+
};
103+
} catch (error) {
104+
if (isMissingGhAwExtension(error)) {
105+
return {
106+
available: false,
107+
source: "missing",
108+
version: "",
109+
command: "gh aw version",
110+
installCommand: INSTALL_COMMAND,
111+
message: "gh aw is not installed. Install the GitHub CLI extension to use the dashboard outside a local dev build.",
112+
};
113+
}
114+
115+
return {
116+
available: false,
117+
source: "error",
118+
version: "",
119+
command: "gh aw version",
120+
installCommand: INSTALL_COMMAND,
121+
message: String(error?.output ?? error?.stderr ?? error?.message ?? "Failed to detect gh aw."),
122+
};
34123
}
35124
};
125+
126+
runGhAw.getStatus = getStatus;
127+
return runGhAw;
36128
}

.github/extensions/agentic-workflows-dashboard/extension.mjs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import { fileURLToPath } from "node:url";
55

66
import { createCanvas, joinSession } from "@github/copilot-sdk/extension";
77

8-
import { createGhAwRunner } from "./dashboard-cli.mjs";
8+
import { createGhAwRunnerWithStatus } from "./dashboard-cli.mjs";
99
import { DEFAULT_LOG_TIMEOUT_MINUTES, DEFAULT_RUN_COUNT } from "./dashboard-config.mjs";
1010
import { createDashboardDataAccess } from "./dashboard-data.mjs";
1111

1212
const __dirname = dirname(fileURLToPath(import.meta.url));
1313
const servers = new Map();
1414
let workspacePath = process.cwd();
15-
const runGhAw = createGhAwRunner({ getWorkspacePath: () => workspacePath });
15+
const runGhAw = createGhAwRunnerWithStatus({ getWorkspacePath: () => workspacePath });
1616
const dataAccess = createDashboardDataAccess({ runGhAw });
1717

1818
// ---------------------------------------------------------------------------
@@ -63,6 +63,8 @@ async function startServer() {
6363
res.end(await readFile(join(__dirname, "web", "pagination.js"), "utf8"));
6464
} else if (pathname === "/api/status") {
6565
sendJson(await dataAccess.getDefinitions());
66+
} else if (pathname === "/api/cli-status") {
67+
sendJson(await runGhAw.getStatus());
6668
} else if (pathname === "/api/experiments") {
6769
sendJson(await dataAccess.getExperiments());
6870
} else if (pathname === "/api/runs") {

0 commit comments

Comments
 (0)