github-router 0.3.249 → 0.3.255
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attribution-settings-CegtE0TY.js +2347 -0
- package/dist/attribution-settings-CegtE0TY.js.map +1 -0
- package/dist/auth-CP4q2CjO.js +44 -0
- package/dist/auth-CP4q2CjO.js.map +1 -0
- package/dist/browser-ext/background.js +8 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/check-usage-6PB5IUFb.js +43 -0
- package/dist/check-usage-6PB5IUFb.js.map +1 -0
- package/dist/claude-BiZxoNWq.js +593 -0
- package/dist/claude-BiZxoNWq.js.map +1 -0
- package/dist/client-CQMfroGV.js +413 -0
- package/dist/client-CQMfroGV.js.map +1 -0
- package/dist/codex-ST21X3WF.js +85 -0
- package/dist/codex-ST21X3WF.js.map +1 -0
- package/dist/debug-CjmE9sgG.js +81 -0
- package/dist/debug-CjmE9sgG.js.map +1 -0
- package/dist/engine-DNCX0Hfd.js +2 -0
- package/dist/{lifecycle-DHZsVN8j.js → exec-DTO2oin0.js} +3 -130
- package/dist/exec-DTO2oin0.js.map +1 -0
- package/dist/file-log-reporter-IFQcL5IK.js +158 -0
- package/dist/file-log-reporter-IFQcL5IK.js.map +1 -0
- package/dist/gate-discovery-CepmbZnc.js +635 -0
- package/dist/gate-discovery-CepmbZnc.js.map +1 -0
- package/dist/get-copilot-usage-DD1N0Xlh.js +11 -0
- package/dist/get-copilot-usage-DD1N0Xlh.js.map +1 -0
- package/dist/hook-mcp-client-DBvm9608.js +136 -0
- package/dist/hook-mcp-client-DBvm9608.js.map +1 -0
- package/dist/internal-artifact-open-D2cQ2QCw.js +319 -0
- package/dist/internal-artifact-open-D2cQ2QCw.js.map +1 -0
- package/dist/internal-first-mate-guard-7v2CtMA6.js +2 -0
- package/dist/internal-first-mate-guard-La0tIjTU.js +126 -0
- package/dist/internal-first-mate-guard-La0tIjTU.js.map +1 -0
- package/dist/internal-plan-review-ipnT3bhj.js +114 -0
- package/dist/internal-plan-review-ipnT3bhj.js.map +1 -0
- package/dist/internal-prompt-submit-DOj75_hh.js +121 -0
- package/dist/internal-prompt-submit-DOj75_hh.js.map +1 -0
- package/dist/internal-session-bind-DwK2iGW0.js +133 -0
- package/dist/internal-session-bind-DwK2iGW0.js.map +1 -0
- package/dist/internal-stop-hook-CNPGJm63.js +212 -0
- package/dist/internal-stop-hook-CNPGJm63.js.map +1 -0
- package/dist/internal-stop-review-AUcFssrW.js +122 -0
- package/dist/internal-stop-review-AUcFssrW.js.map +1 -0
- package/dist/internal-worker-guard-Lu8VHj5k.js +75 -0
- package/dist/internal-worker-guard-Lu8VHj5k.js.map +1 -0
- package/dist/internal-workspace-header-BRMz0Yql.js +24 -0
- package/dist/internal-workspace-header-BRMz0Yql.js.map +1 -0
- package/dist/lifecycle-Byw5s1G8.js +134 -0
- package/dist/lifecycle-Byw5s1G8.js.map +1 -0
- package/dist/lifecycle-D80CaWie.js +2 -0
- package/dist/{lifecycle-CUf1UDrH.js → lifecycle-DD88ka3f.js} +3 -3
- package/dist/{lifecycle-CUf1UDrH.js.map → lifecycle-DD88ka3f.js.map} +1 -1
- package/dist/lifecycle-DzqCqDlM.js +2 -0
- package/dist/main.js +43 -12884
- package/dist/main.js.map +1 -1
- package/dist/mcp-workspace-header-CGJbNeHb.js +21 -0
- package/dist/mcp-workspace-header-CGJbNeHb.js.map +1 -0
- package/dist/models-B6UnGyRo.js +158 -0
- package/dist/models-B6UnGyRo.js.map +1 -0
- package/dist/orchestration-hRU4TdWr.js +39 -0
- package/dist/orchestration-hRU4TdWr.js.map +1 -0
- package/dist/{paths-BjTMI_xK.js → paths-C1cLZ7Ga.js} +52 -20
- package/dist/paths-C1cLZ7Ga.js.map +1 -0
- package/dist/paths-CwKwc2pi.js +2 -0
- package/dist/{peer-mcp-personas-DJzLpfDJ.js → peer-mcp-personas-BDet588n.js} +1006 -2488
- package/dist/peer-mcp-personas-BDet588n.js.map +1 -0
- package/dist/plan-review-hook-C8x0uKPf.js +159 -0
- package/dist/plan-review-hook-C8x0uKPf.js.map +1 -0
- package/dist/prompt-submit-hook-BrkkLAAB.js +153 -0
- package/dist/prompt-submit-hook-BrkkLAAB.js.map +1 -0
- package/dist/provision-DSkPa5hY.js +656 -0
- package/dist/provision-DSkPa5hY.js.map +1 -0
- package/dist/serve-sa_7c-yD.js +1511 -0
- package/dist/serve-sa_7c-yD.js.map +1 -0
- package/dist/server-setup-DcO9qvN3.js +4776 -0
- package/dist/server-setup-DcO9qvN3.js.map +1 -0
- package/dist/start-siGxuZhO.js +129 -0
- package/dist/start-siGxuZhO.js.map +1 -0
- package/dist/stop-gate-hook-DQc2KV7B.js +686 -0
- package/dist/stop-gate-hook-DQc2KV7B.js.map +1 -0
- package/dist/stop-gate-policy-CHwWbuF_.js +268 -0
- package/dist/stop-gate-policy-CHwWbuF_.js.map +1 -0
- package/dist/token-R2ocFC3M.js +1054 -0
- package/dist/token-R2ocFC3M.js.map +1 -0
- package/dist/version-_Q1WpsQp.js +32 -0
- package/dist/version-_Q1WpsQp.js.map +1 -0
- package/dist/worker-dispatch-Bj1uYyG9.js +222 -0
- package/dist/worker-dispatch-Bj1uYyG9.js.map +1 -0
- package/package.json +1 -1
- package/dist/engine-BuuHUb4t.js +0 -2
- package/dist/lifecycle-0rXrwjWk.js +0 -2
- package/dist/lifecycle-DHZsVN8j.js.map +0 -1
- package/dist/lifecycle-hzPwXc3I.js +0 -2
- package/dist/paths-BjTMI_xK.js.map +0 -1
- package/dist/paths-D3XgmTcQ.js +0 -2
- package/dist/peer-mcp-personas-DJzLpfDJ.js.map +0 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/lib/mcp-workspace-header.ts
|
|
2
|
+
/** Header the per-session MCP headersHelper emits, carrying the calling Claude
|
|
3
|
+
* session's working directory. The /mcp handler uses it as the default
|
|
4
|
+
* `workspace` for repo-scoped tools so a machine-wide `serve` targets the
|
|
5
|
+
* active repo, not the proxy launch cwd. */
|
|
6
|
+
const MCP_WORKSPACE_HEADER = "X-GH-Workspace";
|
|
7
|
+
/** stdout JSON the headersHelper prints; Claude merges it into the connection
|
|
8
|
+
* headers. `cwd` is the helper's own process cwd = the session's project dir. */
|
|
9
|
+
function buildWorkspaceHeaderJson(cwd) {
|
|
10
|
+
return JSON.stringify({ [MCP_WORKSPACE_HEADER]: cwd });
|
|
11
|
+
}
|
|
12
|
+
/** Command string Claude runs as the headersHelper. Mirrors
|
|
13
|
+
* buildPromptSubmitHookCommand's quoting (src/lib/orchestration/prompt-submit-hook.ts). */
|
|
14
|
+
function buildWorkspaceHeaderHelperCommand(execPath, scriptPath) {
|
|
15
|
+
const q = (s) => `"${s}"`;
|
|
16
|
+
return scriptPath && scriptPath !== execPath ? `${q(execPath)} ${q(scriptPath)} internal-workspace-header` : `${q(execPath)} internal-workspace-header`;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { buildWorkspaceHeaderHelperCommand as n, buildWorkspaceHeaderJson as r, MCP_WORKSPACE_HEADER as t };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=mcp-workspace-header-CGJbNeHb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-workspace-header-CGJbNeHb.js","names":[],"sources":["../src/lib/mcp-workspace-header.ts"],"sourcesContent":["/** Header the per-session MCP headersHelper emits, carrying the calling Claude\n * session's working directory. The /mcp handler uses it as the default\n * `workspace` for repo-scoped tools so a machine-wide `serve` targets the\n * active repo, not the proxy launch cwd. */\nexport const MCP_WORKSPACE_HEADER = \"X-GH-Workspace\"\n\n/** stdout JSON the headersHelper prints; Claude merges it into the connection\n * headers. `cwd` is the helper's own process cwd = the session's project dir. */\nexport function buildWorkspaceHeaderJson(cwd: string): string {\n return JSON.stringify({ [MCP_WORKSPACE_HEADER]: cwd })\n}\n\n/** Command string Claude runs as the headersHelper. Mirrors\n * buildPromptSubmitHookCommand's quoting (src/lib/orchestration/prompt-submit-hook.ts). */\nexport function buildWorkspaceHeaderHelperCommand(execPath: string, scriptPath: string | undefined): string {\n const q = (s: string): string => `\"${s}\"`\n return scriptPath && scriptPath !== execPath\n ? `${q(execPath)} ${q(scriptPath)} internal-workspace-header`\n : `${q(execPath)} internal-workspace-header`\n}\n"],"mappings":";;;;;AAIA,MAAa,uBAAuB;;;AAIpC,SAAgB,yBAAyB,KAAqB;CAC5D,OAAO,KAAK,UAAU,GAAG,uBAAuB,IAAI,CAAC;AACvD;;;AAIA,SAAgB,kCAAkC,UAAkB,YAAwC;CAC1G,MAAM,KAAK,MAAsB,IAAI,EAAE;CACvC,OAAO,cAAc,eAAe,WAChC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,8BAChC,GAAG,EAAE,QAAQ,EAAE;AACrB"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { i as ensurePaths } from "./paths-C1cLZ7Ga.js";
|
|
2
|
+
import { p as getModels, r as setupGitHubToken, t as setupCopilotToken } from "./token-R2ocFC3M.js";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
import consola from "consola";
|
|
5
|
+
//#region src/models.ts
|
|
6
|
+
const models = defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "models",
|
|
9
|
+
description: "List available GitHub Copilot models and their capabilities. Pass an optional pattern to filter (case-insensitive substring match on id, name, vendor, family)."
|
|
10
|
+
},
|
|
11
|
+
args: {
|
|
12
|
+
pattern: {
|
|
13
|
+
type: "positional",
|
|
14
|
+
required: false,
|
|
15
|
+
description: "Substring to filter models by (matches id, name, vendor, or family)."
|
|
16
|
+
},
|
|
17
|
+
json: {
|
|
18
|
+
type: "boolean",
|
|
19
|
+
default: false,
|
|
20
|
+
description: "Emit raw JSON instead of the pretty layout."
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
async run({ args }) {
|
|
24
|
+
await ensurePaths();
|
|
25
|
+
await setupGitHubToken();
|
|
26
|
+
try {
|
|
27
|
+
await setupCopilotToken();
|
|
28
|
+
} catch (err) {
|
|
29
|
+
consola.error("Failed to obtain Copilot token:", err);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
let catalog;
|
|
33
|
+
try {
|
|
34
|
+
catalog = await getModels();
|
|
35
|
+
} catch (err) {
|
|
36
|
+
consola.error("Failed to fetch Copilot model catalog:", err);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
const all = catalog.data;
|
|
40
|
+
const pattern = args.pattern?.toString().trim();
|
|
41
|
+
const filtered = pattern ? filterModels(all, pattern) : all;
|
|
42
|
+
if (args.json) {
|
|
43
|
+
process.stdout.write(`${JSON.stringify(filtered, null, 2)}\n`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (filtered.length === 0) {
|
|
47
|
+
consola.warn(`No models matched "${pattern}". ${all.length} models available — try a different substring or run without an argument to list everything.`);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
const grouped = groupByVendor(filtered);
|
|
51
|
+
const lines = [];
|
|
52
|
+
const header = pattern ? `${filtered.length}/${all.length} models match "${pattern}"` : `${all.length} models available`;
|
|
53
|
+
lines.push(header);
|
|
54
|
+
lines.push("");
|
|
55
|
+
for (const [vendor, list] of grouped) {
|
|
56
|
+
lines.push(`▾ ${vendor} (${list.length})`);
|
|
57
|
+
for (const model of list) lines.push(...formatModel(model));
|
|
58
|
+
lines.push("");
|
|
59
|
+
}
|
|
60
|
+
process.stdout.write(lines.join("\n"));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
function filterModels(models, pattern) {
|
|
64
|
+
const needle = pattern.toLowerCase();
|
|
65
|
+
return models.filter((m) => {
|
|
66
|
+
return [
|
|
67
|
+
m.id,
|
|
68
|
+
m.name,
|
|
69
|
+
m.vendor,
|
|
70
|
+
m.capabilities.family,
|
|
71
|
+
m.capabilities.type,
|
|
72
|
+
m.model_picker_category ?? ""
|
|
73
|
+
].join(" ").toLowerCase().includes(needle);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function groupByVendor(models) {
|
|
77
|
+
const map = /* @__PURE__ */ new Map();
|
|
78
|
+
for (const m of models) {
|
|
79
|
+
const key = m.vendor || "(unknown vendor)";
|
|
80
|
+
const bucket = map.get(key);
|
|
81
|
+
if (bucket) bucket.push(m);
|
|
82
|
+
else map.set(key, [m]);
|
|
83
|
+
}
|
|
84
|
+
return [...map.entries()].sort(([a], [b]) => a.localeCompare(b));
|
|
85
|
+
}
|
|
86
|
+
function formatModel(model) {
|
|
87
|
+
const lines = [];
|
|
88
|
+
const tags = [];
|
|
89
|
+
if (model.preview) tags.push("preview");
|
|
90
|
+
if (model.is_chat_default) tags.push("chat-default");
|
|
91
|
+
if (model.is_chat_fallback) tags.push("chat-fallback");
|
|
92
|
+
if (model.billing?.is_premium) tags.push("premium");
|
|
93
|
+
if (model.billing?.restricted_to?.length) tags.push(`restricted:${model.billing.restricted_to.join("/")}`);
|
|
94
|
+
if (model.policy && model.policy.state !== "enabled") tags.push(`policy:${model.policy.state}`);
|
|
95
|
+
const tagStr = tags.length > 0 ? ` [${tags.join(", ")}]` : "";
|
|
96
|
+
lines.push(` • ${model.id}${tagStr}`);
|
|
97
|
+
if (model.name && model.name !== model.id) lines.push(` name: ${model.name}`);
|
|
98
|
+
const meta = [`family: ${model.capabilities.family}`, `type: ${model.capabilities.type}`];
|
|
99
|
+
if (model.capabilities.tokenizer) meta.push(`tokenizer: ${model.capabilities.tokenizer}`);
|
|
100
|
+
if (model.version) meta.push(`version: ${model.version}`);
|
|
101
|
+
lines.push(` ${meta.join(" · ")}`);
|
|
102
|
+
const limits = model.capabilities.limits;
|
|
103
|
+
const limitParts = [];
|
|
104
|
+
if (limits) {
|
|
105
|
+
if (limits.max_context_window_tokens) limitParts.push(`ctx ${formatTokens(limits.max_context_window_tokens)}`);
|
|
106
|
+
else if (limits.max_prompt_tokens) limitParts.push(`prompt ${formatTokens(limits.max_prompt_tokens)}`);
|
|
107
|
+
if (limits.max_output_tokens) limitParts.push(`out ${formatTokens(limits.max_output_tokens)}`);
|
|
108
|
+
if (limits.max_non_streaming_output_tokens && limits.max_non_streaming_output_tokens !== limits.max_output_tokens) limitParts.push(`out-non-stream ${formatTokens(limits.max_non_streaming_output_tokens)}`);
|
|
109
|
+
if (limits.max_inputs) limitParts.push(`inputs ${limits.max_inputs}`);
|
|
110
|
+
if (limits.vision?.max_prompt_images) limitParts.push(`images ${limits.vision.max_prompt_images}`);
|
|
111
|
+
}
|
|
112
|
+
if (limitParts.length > 0) lines.push(` limits: ${limitParts.join(" · ")}`);
|
|
113
|
+
const supports = model.capabilities.supports;
|
|
114
|
+
const supportFlags = [];
|
|
115
|
+
if (supports) {
|
|
116
|
+
if (supports.tool_calls) supportFlags.push("tools");
|
|
117
|
+
if (supports.parallel_tool_calls) supportFlags.push("parallel-tools");
|
|
118
|
+
if (supports.streaming) supportFlags.push("streaming");
|
|
119
|
+
if (supports.vision) supportFlags.push("vision");
|
|
120
|
+
if (supports.structured_outputs) supportFlags.push("structured-outputs");
|
|
121
|
+
if (supports.dimensions) supportFlags.push("dimensions");
|
|
122
|
+
if (supports.adaptive_thinking) {
|
|
123
|
+
const min = supports.min_thinking_budget;
|
|
124
|
+
const max = supports.max_thinking_budget;
|
|
125
|
+
const range = min !== void 0 && max !== void 0 ? `(${formatTokens(min)}-${formatTokens(max)})` : "";
|
|
126
|
+
supportFlags.push(`adaptive-thinking${range}`);
|
|
127
|
+
}
|
|
128
|
+
if (supports.reasoning_effort && supports.reasoning_effort.length > 0) supportFlags.push(`reasoning:${supports.reasoning_effort.join("/")}`);
|
|
129
|
+
}
|
|
130
|
+
if (supportFlags.length > 0) lines.push(` supports: ${supportFlags.join(", ")}`);
|
|
131
|
+
if (model.supported_endpoints && model.supported_endpoints.length > 0) lines.push(` endpoints: ${model.supported_endpoints.join(", ")}`);
|
|
132
|
+
if (model.billing) {
|
|
133
|
+
const billParts = [];
|
|
134
|
+
if (model.billing.is_premium) billParts.push("premium");
|
|
135
|
+
if (typeof model.billing.multiplier === "number") billParts.push(`×${model.billing.multiplier}`);
|
|
136
|
+
if (billParts.length > 0) lines.push(` billing: ${billParts.join(" ")}`);
|
|
137
|
+
}
|
|
138
|
+
return lines;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Format a token count in a compact human-readable form: `1024` →
|
|
142
|
+
* `1k`, `4096` → `4k`, `131072` → `128k`, `1048576` → `1M`. Prefer
|
|
143
|
+
* binary multiples (mebi, kibi) since Claude Code / Copilot context
|
|
144
|
+
* windows are reported in binary units (`1M context` = 1024 × 1024
|
|
145
|
+
* tokens). Fall back to decimal (`64k` for `64000`) when the value
|
|
146
|
+
* is a clean decimal multiple but not binary.
|
|
147
|
+
*/
|
|
148
|
+
function formatTokens(n) {
|
|
149
|
+
if (n >= 1048576 && n % 1048576 === 0) return `${n / 1048576}M`;
|
|
150
|
+
if (n >= 1024 && n % 1024 === 0) return `${n / 1024}k`;
|
|
151
|
+
if (n >= 1e6 && n % 1e6 === 0) return `${n / 1e6}M`;
|
|
152
|
+
if (n >= 1e3 && n % 1e3 === 0) return `${n / 1e3}k`;
|
|
153
|
+
return `${n}`;
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
export { models };
|
|
157
|
+
|
|
158
|
+
//# sourceMappingURL=models-B6UnGyRo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"models-B6UnGyRo.js","names":[],"sources":["../src/models.ts"],"sourcesContent":["import { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { ensurePaths } from \"./lib/paths\"\nimport { setupCopilotToken, setupGitHubToken } from \"./lib/token\"\nimport { getModels, type Model } from \"./services/copilot/get-models\"\n\nexport const models = defineCommand({\n meta: {\n name: \"models\",\n description:\n \"List available GitHub Copilot models and their capabilities. Pass an optional pattern to filter (case-insensitive substring match on id, name, vendor, family).\",\n },\n args: {\n pattern: {\n type: \"positional\",\n required: false,\n description:\n \"Substring to filter models by (matches id, name, vendor, or family).\",\n },\n json: {\n type: \"boolean\",\n default: false,\n description: \"Emit raw JSON instead of the pretty layout.\",\n },\n },\n async run({ args }) {\n await ensurePaths()\n await setupGitHubToken()\n try {\n await setupCopilotToken()\n } catch (err) {\n consola.error(\"Failed to obtain Copilot token:\", err)\n process.exit(1)\n }\n\n let catalog: Awaited<ReturnType<typeof getModels>>\n try {\n catalog = await getModels()\n } catch (err) {\n consola.error(\"Failed to fetch Copilot model catalog:\", err)\n process.exit(1)\n }\n\n const all = catalog.data\n const pattern = args.pattern?.toString().trim()\n const filtered = pattern ? filterModels(all, pattern) : all\n\n if (args.json) {\n process.stdout.write(`${JSON.stringify(filtered, null, 2)}\\n`)\n return\n }\n\n if (filtered.length === 0) {\n consola.warn(\n `No models matched \"${pattern}\". ${all.length} models available — try a different substring or run without an argument to list everything.`,\n )\n process.exit(1)\n }\n\n const grouped = groupByVendor(filtered)\n const lines: Array<string> = []\n const header = pattern\n ? `${filtered.length}/${all.length} models match \"${pattern}\"`\n : `${all.length} models available`\n lines.push(header)\n lines.push(\"\")\n for (const [vendor, list] of grouped) {\n lines.push(`▾ ${vendor} (${list.length})`)\n for (const model of list) {\n lines.push(...formatModel(model))\n }\n lines.push(\"\")\n }\n process.stdout.write(lines.join(\"\\n\"))\n },\n})\n\nfunction filterModels(models: Array<Model>, pattern: string): Array<Model> {\n const needle = pattern.toLowerCase()\n return models.filter((m) => {\n const haystack = [\n m.id,\n m.name,\n m.vendor,\n m.capabilities.family,\n m.capabilities.type,\n m.model_picker_category ?? \"\",\n ]\n .join(\" \")\n .toLowerCase()\n return haystack.includes(needle)\n })\n}\n\nfunction groupByVendor(models: Array<Model>): Array<[string, Array<Model>]> {\n const map = new Map<string, Array<Model>>()\n for (const m of models) {\n const key = m.vendor || \"(unknown vendor)\"\n const bucket = map.get(key)\n if (bucket) bucket.push(m)\n else map.set(key, [m])\n }\n // Stable vendor order: alphabetical for predictability.\n return [...map.entries()].sort(([a], [b]) => a.localeCompare(b))\n}\n\n/**\n * Test-only exports. Not part of the public CLI surface — kept out of\n * the default export so they don't show up in IDE autocomplete on\n * `import { ... } from \"github-router/models\"` consumers.\n */\nexport const __testing = { filterModels, groupByVendor, formatModel, formatTokens }\n\nfunction formatModel(model: Model): Array<string> {\n const lines: Array<string> = []\n const tags: Array<string> = []\n if (model.preview) tags.push(\"preview\")\n if (model.is_chat_default) tags.push(\"chat-default\")\n if (model.is_chat_fallback) tags.push(\"chat-fallback\")\n if (model.billing?.is_premium) tags.push(\"premium\")\n if (model.billing?.restricted_to?.length) {\n tags.push(`restricted:${model.billing.restricted_to.join(\"/\")}`)\n }\n if (model.policy && model.policy.state !== \"enabled\") {\n tags.push(`policy:${model.policy.state}`)\n }\n const tagStr = tags.length > 0 ? ` [${tags.join(\", \")}]` : \"\"\n lines.push(` • ${model.id}${tagStr}`)\n if (model.name && model.name !== model.id) {\n lines.push(` name: ${model.name}`)\n }\n const meta: Array<string> = [\n `family: ${model.capabilities.family}`,\n `type: ${model.capabilities.type}`,\n ]\n if (model.capabilities.tokenizer) {\n meta.push(`tokenizer: ${model.capabilities.tokenizer}`)\n }\n if (model.version) {\n meta.push(`version: ${model.version}`)\n }\n lines.push(` ${meta.join(\" · \")}`)\n\n const limits = model.capabilities.limits\n const limitParts: Array<string> = []\n if (limits) {\n if (limits.max_context_window_tokens) {\n limitParts.push(`ctx ${formatTokens(limits.max_context_window_tokens)}`)\n } else if (limits.max_prompt_tokens) {\n limitParts.push(`prompt ${formatTokens(limits.max_prompt_tokens)}`)\n }\n if (limits.max_output_tokens) {\n limitParts.push(`out ${formatTokens(limits.max_output_tokens)}`)\n }\n if (\n limits.max_non_streaming_output_tokens\n && limits.max_non_streaming_output_tokens !== limits.max_output_tokens\n ) {\n limitParts.push(\n `out-non-stream ${formatTokens(limits.max_non_streaming_output_tokens)}`,\n )\n }\n if (limits.max_inputs) limitParts.push(`inputs ${limits.max_inputs}`)\n if (limits.vision?.max_prompt_images) {\n limitParts.push(`images ${limits.vision.max_prompt_images}`)\n }\n }\n if (limitParts.length > 0) {\n lines.push(` limits: ${limitParts.join(\" · \")}`)\n }\n\n const supports = model.capabilities.supports\n const supportFlags: Array<string> = []\n if (supports) {\n if (supports.tool_calls) supportFlags.push(\"tools\")\n if (supports.parallel_tool_calls) supportFlags.push(\"parallel-tools\")\n if (supports.streaming) supportFlags.push(\"streaming\")\n if (supports.vision) supportFlags.push(\"vision\")\n if (supports.structured_outputs) supportFlags.push(\"structured-outputs\")\n if (supports.dimensions) supportFlags.push(\"dimensions\")\n if (supports.adaptive_thinking) {\n const min = supports.min_thinking_budget\n const max = supports.max_thinking_budget\n const range\n = min !== undefined && max !== undefined\n ? `(${formatTokens(min)}-${formatTokens(max)})`\n : \"\"\n supportFlags.push(`adaptive-thinking${range}`)\n }\n if (supports.reasoning_effort && supports.reasoning_effort.length > 0) {\n supportFlags.push(`reasoning:${supports.reasoning_effort.join(\"/\")}`)\n }\n }\n if (supportFlags.length > 0) {\n lines.push(` supports: ${supportFlags.join(\", \")}`)\n }\n\n if (model.supported_endpoints && model.supported_endpoints.length > 0) {\n lines.push(` endpoints: ${model.supported_endpoints.join(\", \")}`)\n }\n if (model.billing) {\n const billParts: Array<string> = []\n if (model.billing.is_premium) billParts.push(\"premium\")\n if (typeof model.billing.multiplier === \"number\") {\n billParts.push(`×${model.billing.multiplier}`)\n }\n if (billParts.length > 0) {\n lines.push(` billing: ${billParts.join(\" \")}`)\n }\n }\n return lines\n}\n\n/**\n * Format a token count in a compact human-readable form: `1024` →\n * `1k`, `4096` → `4k`, `131072` → `128k`, `1048576` → `1M`. Prefer\n * binary multiples (mebi, kibi) since Claude Code / Copilot context\n * windows are reported in binary units (`1M context` = 1024 × 1024\n * tokens). Fall back to decimal (`64k` for `64000`) when the value\n * is a clean decimal multiple but not binary.\n */\nfunction formatTokens(n: number): string {\n if (n >= 1_048_576 && n % 1_048_576 === 0) return `${n / 1_048_576}M`\n if (n >= 1024 && n % 1024 === 0) return `${n / 1024}k`\n if (n >= 1_000_000 && n % 1_000_000 === 0) return `${n / 1_000_000}M`\n if (n >= 1000 && n % 1000 === 0) return `${n / 1000}k`\n return `${n}`\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { i as parseIntEnv, o as runCommandCapture } from "./exec-DTO2oin0.js";
|
|
2
|
+
import "./stop-gate-hook-DQc2KV7B.js";
|
|
3
|
+
//#region src/lib/orchestration/live-exec.ts
|
|
4
|
+
/**
|
|
5
|
+
* Live `ExecFn` for the gate runner — runs the kernel's SEALED gate command in a
|
|
6
|
+
* workspace via the project's Windows-safe exec helper (`runCommandCapture` →
|
|
7
|
+
* `buildExecInvocation`, which handles cmd.exe quoting on Windows). Only the
|
|
8
|
+
* kernel's sealed gate commands flow through here (tests/types/lint/build),
|
|
9
|
+
* never a producer-authored string, so a simple whitespace split into argv is
|
|
10
|
+
* safe for these fixed commands. A command that can't run (spawn error / killed)
|
|
11
|
+
* counts as a non-zero exit, never a throw — the gate runner treats it as
|
|
12
|
+
* not-passed.
|
|
13
|
+
*
|
|
14
|
+
* This is the one piece of the gate engine that touches a real subprocess; it is
|
|
15
|
+
* model-free and cross-platform, so it is exercised directly in CI (unlike the
|
|
16
|
+
* worker/worktree/model adapters, which need the gated E2E harness).
|
|
17
|
+
*/
|
|
18
|
+
/** Per-command wall-clock cap so a hung gate command (watch-mode test, a process
|
|
19
|
+
* waiting on stdin, a stale lockfile) is tree-killed instead of hanging the
|
|
20
|
+
* caller forever. Generous (a real typecheck/test/lint can take minutes) but
|
|
21
|
+
* bounded; override with GH_ROUTER_GATE_CMD_TIMEOUT_MS. A timeout kills the
|
|
22
|
+
* command (code null) which the gate runner treats as not-passed. */
|
|
23
|
+
const CMD_TIMEOUT_MS = parseIntEnv(process.env.GH_ROUTER_GATE_CMD_TIMEOUT_MS) ?? 6e5;
|
|
24
|
+
const liveExec = async ({ command, cwd }) => {
|
|
25
|
+
const argv = command.trim().split(/\s+/).filter(Boolean);
|
|
26
|
+
if (argv.length === 0) return { exitCode: 1 };
|
|
27
|
+
try {
|
|
28
|
+
return { exitCode: (await runCommandCapture(argv, {
|
|
29
|
+
cwd,
|
|
30
|
+
timeoutMs: CMD_TIMEOUT_MS
|
|
31
|
+
})).code ?? 1 };
|
|
32
|
+
} catch {
|
|
33
|
+
return { exitCode: 1 };
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
export { liveExec as t };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=orchestration-hRU4TdWr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestration-hRU4TdWr.js","names":[],"sources":["../src/lib/orchestration/live-exec.ts"],"sourcesContent":["/**\n * Live `ExecFn` for the gate runner — runs the kernel's SEALED gate command in a\n * workspace via the project's Windows-safe exec helper (`runCommandCapture` →\n * `buildExecInvocation`, which handles cmd.exe quoting on Windows). Only the\n * kernel's sealed gate commands flow through here (tests/types/lint/build),\n * never a producer-authored string, so a simple whitespace split into argv is\n * safe for these fixed commands. A command that can't run (spawn error / killed)\n * counts as a non-zero exit, never a throw — the gate runner treats it as\n * not-passed.\n *\n * This is the one piece of the gate engine that touches a real subprocess; it is\n * model-free and cross-platform, so it is exercised directly in CI (unlike the\n * worker/worktree/model adapters, which need the gated E2E harness).\n */\n\nimport { runCommandCapture } from \"~/lib/exec\"\n\nimport { type ExecFn } from \"./gate-runner\"\nimport { parseIntEnv } from \"../exec\"\n\n/** Per-command wall-clock cap so a hung gate command (watch-mode test, a process\n * waiting on stdin, a stale lockfile) is tree-killed instead of hanging the\n * caller forever. Generous (a real typecheck/test/lint can take minutes) but\n * bounded; override with GH_ROUTER_GATE_CMD_TIMEOUT_MS. A timeout kills the\n * command (code null) which the gate runner treats as not-passed. */\nconst CMD_TIMEOUT_MS =\n parseIntEnv(process.env.GH_ROUTER_GATE_CMD_TIMEOUT_MS) ?? 600_000\n\nexport const liveExec: ExecFn = async ({ command, cwd }) => {\n const argv = command.trim().split(/\\s+/).filter(Boolean)\n if (argv.length === 0) return { exitCode: 1 }\n try {\n const r = await runCommandCapture(argv, { cwd, timeoutMs: CMD_TIMEOUT_MS })\n // `code` is null when killed by signal/timeout → treat as a failed gate.\n return { exitCode: r.code ?? 1 }\n } catch {\n return { exitCode: 1 }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAM,iBACJ,YAAY,QAAQ,IAAI,6BAA6B,KAAK;AAE5D,MAAa,WAAmB,OAAO,EAAE,SAAS,UAAU;CAC1D,MAAM,OAAO,QAAQ,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO;CACvD,IAAI,KAAK,WAAW,GAAG,OAAO,EAAE,UAAU,EAAE;CAC5C,IAAI;EAGF,OAAO,EAAE,WAAU,MAFH,kBAAkB,MAAM;GAAE;GAAK,WAAW;EAAe,CAAC,EAAA,CAErD,QAAQ,EAAE;CACjC,QAAQ;EACN,OAAO,EAAE,UAAU,EAAE;CACvB;AACF"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import consola from "consola";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import { randomBytes } from "node:crypto";
|
|
3
4
|
import fs from "node:fs/promises";
|
|
4
5
|
import os from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
6
|
//#region src/lib/paths.ts
|
|
7
7
|
function appDir() {
|
|
8
8
|
return path.join(os.homedir(), ".local", "share", "github-router");
|
|
@@ -221,12 +221,12 @@ async function ensurePaths() {
|
|
|
221
221
|
consola.debug("Peer-agent .md sweep skipped:", err);
|
|
222
222
|
});
|
|
223
223
|
await (async () => {
|
|
224
|
-
await (await import("./lifecycle-
|
|
224
|
+
await (await import("./lifecycle-DzqCqDlM.js")).sweepStaleWorktreesAtBoot();
|
|
225
225
|
})().catch((err) => {
|
|
226
226
|
consola.debug("Worker worktree boot sweep skipped:", err);
|
|
227
227
|
});
|
|
228
228
|
await (async () => {
|
|
229
|
-
await (await import("./lifecycle-
|
|
229
|
+
await (await import("./lifecycle-D80CaWie.js")).sweepStaleColbertMetaAtBoot();
|
|
230
230
|
})().catch((err) => {
|
|
231
231
|
consola.debug("ColBERT meta boot sweep skipped:", err);
|
|
232
232
|
});
|
|
@@ -717,58 +717,90 @@ async function assertOnboardingGateInjected(targetDir) {
|
|
|
717
717
|
* of `sourceDir` and we don't reintroduce a confused-deputy vector.
|
|
718
718
|
* - Files copy only if source mtime > target mtime (idempotent).
|
|
719
719
|
*/
|
|
720
|
-
|
|
720
|
+
/**
|
|
721
|
+
* Max file operations in flight across the WHOLE mirror walk.
|
|
722
|
+
*
|
|
723
|
+
* The walk is I/O-bound over hundreds of independent small files, so it
|
|
724
|
+
* parallelizes well: measured 1021ms serial vs 311ms at this limit for a real
|
|
725
|
+
* 394-file / 4.7MB `~/.claude` (Windows 11, 16 cores). It must be BOUNDED
|
|
726
|
+
* rather than a bare `Promise.all` over every entry — the mirror is re-copied
|
|
727
|
+
* on every launch (the target is a fresh per-launch dir, so the mtime skip
|
|
728
|
+
* below never fires across launches), and firing hundreds of simultaneous
|
|
729
|
+
* `copyFile`s just trades one bottleneck for file-handle exhaustion.
|
|
730
|
+
*
|
|
731
|
+
* The limit is shared across the recursion via a semaphore rather than applied
|
|
732
|
+
* per-directory: a per-directory bound would multiply with nesting depth and
|
|
733
|
+
* stop being a bound at all.
|
|
734
|
+
*/
|
|
735
|
+
const MIRROR_COPY_CONCURRENCY = 16;
|
|
736
|
+
/** Counting semaphore. FIFO, so a deep subtree cannot starve a shallow one. */
|
|
737
|
+
function createSemaphore(limit) {
|
|
738
|
+
let active = 0;
|
|
739
|
+
const waiters = [];
|
|
740
|
+
return async function withSlot(fn) {
|
|
741
|
+
if (active >= limit) await new Promise((resolve) => waiters.push(resolve));
|
|
742
|
+
else active++;
|
|
743
|
+
try {
|
|
744
|
+
return await fn();
|
|
745
|
+
} finally {
|
|
746
|
+
const next = waiters.shift();
|
|
747
|
+
if (next) next();
|
|
748
|
+
else active--;
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
async function mirrorDirRecursive(sourceDir, targetDir, relPath, withSlot = createSemaphore(MIRROR_COPY_CONCURRENCY)) {
|
|
721
753
|
const sourcePath = path.join(sourceDir, relPath);
|
|
722
754
|
let entries;
|
|
723
755
|
try {
|
|
724
|
-
entries = await fs.readdir(sourcePath);
|
|
756
|
+
entries = await withSlot(() => fs.readdir(sourcePath));
|
|
725
757
|
} catch (err) {
|
|
726
758
|
if (err.code === "ENOENT") return;
|
|
727
759
|
consola.debug(`mirrorDirRecursive: cannot readdir ${sourcePath}:`, err);
|
|
728
760
|
return;
|
|
729
761
|
}
|
|
730
|
-
|
|
762
|
+
await Promise.all(entries.map(async (name) => {
|
|
731
763
|
if (relPath === "") {
|
|
732
764
|
const policy = policyFor(name);
|
|
733
|
-
if (policy === "ISOLATED" || policy === "SHARED")
|
|
765
|
+
if (policy === "ISOLATED" || policy === "SHARED") return;
|
|
734
766
|
}
|
|
735
767
|
const childRel = relPath === "" ? name : path.join(relPath, name);
|
|
736
|
-
if (relPath === "agents" && PEER_AGENT_MD_FILENAME.test(name))
|
|
768
|
+
if (relPath === "agents" && PEER_AGENT_MD_FILENAME.test(name)) return;
|
|
737
769
|
const childSource = path.join(sourceDir, childRel);
|
|
738
770
|
const childTarget = path.join(targetDir, childRel);
|
|
739
771
|
let stats;
|
|
740
772
|
try {
|
|
741
|
-
stats = await fs.lstat(childSource);
|
|
773
|
+
stats = await withSlot(() => fs.lstat(childSource));
|
|
742
774
|
} catch (err) {
|
|
743
775
|
consola.debug(`mirrorDirRecursive: cannot lstat ${childSource}:`, err);
|
|
744
|
-
|
|
776
|
+
return;
|
|
745
777
|
}
|
|
746
778
|
if (stats.isSymbolicLink()) {
|
|
747
779
|
consola.debug(`mirrorDirRecursive: skipping symlink ${childSource} (security policy)`);
|
|
748
|
-
|
|
780
|
+
return;
|
|
749
781
|
}
|
|
750
782
|
if (stats.isDirectory()) {
|
|
751
|
-
await fs.mkdir(childTarget, { recursive: true });
|
|
752
|
-
await mirrorDirRecursive(sourceDir, targetDir, childRel);
|
|
753
|
-
|
|
783
|
+
await withSlot(() => fs.mkdir(childTarget, { recursive: true }));
|
|
784
|
+
await mirrorDirRecursive(sourceDir, targetDir, childRel, withSlot);
|
|
785
|
+
return;
|
|
754
786
|
}
|
|
755
787
|
if (stats.isFile()) {
|
|
756
788
|
let needsCopy = true;
|
|
757
789
|
try {
|
|
758
|
-
const targetStat = await fs.lstat(childTarget);
|
|
790
|
+
const targetStat = await withSlot(() => fs.lstat(childTarget));
|
|
759
791
|
if (targetStat.isFile() && targetStat.mtimeMs >= stats.mtimeMs) needsCopy = false;
|
|
760
792
|
} catch (err) {
|
|
761
793
|
if (err.code !== "ENOENT") consola.debug(`mirrorDirRecursive: lstat target ${childTarget}:`, err);
|
|
762
794
|
}
|
|
763
|
-
if (!needsCopy)
|
|
795
|
+
if (!needsCopy) return;
|
|
764
796
|
try {
|
|
765
|
-
await fs.copyFile(childSource, childTarget, fs.constants.COPYFILE_FICLONE);
|
|
797
|
+
await withSlot(() => fs.copyFile(childSource, childTarget, fs.constants.COPYFILE_FICLONE));
|
|
766
798
|
} catch (err) {
|
|
767
799
|
consola.debug(`mirrorDirRecursive: copy ${childSource} → ${childTarget}:`, err);
|
|
768
800
|
}
|
|
769
|
-
|
|
801
|
+
return;
|
|
770
802
|
}
|
|
771
|
-
}
|
|
803
|
+
}));
|
|
772
804
|
}
|
|
773
805
|
/**
|
|
774
806
|
* Create or refresh a directory symlink `<mirrorDir>/<name>` →
|
|
@@ -1110,4 +1142,4 @@ async function removeOwnClaudeConfigMirror() {
|
|
|
1110
1142
|
//#endregion
|
|
1111
1143
|
export { isUnderClaudeConfigMirror as a, sweepStalePeerAgentMdFiles as c, writeRuntimeFileSecure as d, ensurePaths as i, sweepStaleRuntimeFiles as l, PEER_AGENT_MD_FILENAME as n, removeOwnClaudeConfigMirror as o, ensureClaudeConfigMirror as r, sweepStaleClaudeConfigMirrors as s, PATHS as t, writeArtifactCredsToMirror as u };
|
|
1112
1144
|
|
|
1113
|
-
//# sourceMappingURL=paths-
|
|
1145
|
+
//# sourceMappingURL=paths-C1cLZ7Ga.js.map
|