github-router 0.3.229 → 0.3.238

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/main.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { $ as searchWeb, $t as UPSTREAM_FETCH_TIMEOUT_MS, A as trustRepo, At as createResponses, Bt as warmTreeSitterPool, C as fileLastPromptStore, Cn as copilotBaseUrl, Ct as shimDefaultsToXhigh, D as repoRoot, Dt as assembleResponsesPayload, E as repoFingerprint, En as state, Et as getTokenCount, Ft as provisionBrowserAssets, G as buildEnv, Gt as buildWorkspaceHeaderHelperCommand, Ht as DEFINITION_OF_GREATNESS, It as hasSupportedBrowserInstalled, J as toolbeltEnabled, Jt as toolbeltPathOverride, K as availableToolCommands, Kt as buildWorkspaceHeaderJson, Lt as provisionAndIndexColbert, M as resolveSealedGate, Mt as MAX_RESPONSE_BODY_BYTES, Nt as readResponseBodyCapped, O as stopGateEnabledForRepo, Ot as resolveMcpToolTimeoutMs, Pt as parseJsonOrDiagnose, Q as assetFor, Qt as DEFAULT_PORT, Rt as extractTarGzMember, S as fileFindingsStore, Sn as GITHUB_API_BASE_URL, St as workerToolsEnabled, T as isSubagentContext, Tn as githubHeaders, Tt as createMessages, Ut as shouldUseInsecureTls, Vt as CONDENSED_OPERATING_SEQUENCE, Wt as ArtifactClient, X as vscodeRipgrepPath, Xt as DEFAULT_CODEX_MODEL, Y as toolbeltSkipSet, Yt as DEFAULT_CLAUDE_MODEL_FALLBACKS, Z as TOOLBELT_TOOLS, Zt as DEFAULT_CODEX_MODEL_FALLBACKS, _ as stopGateDisabled, _n as getModels, _t as browserToolsEnabled, a as buildPeerAwarenessSnippet, an as setupCopilotToken, at as buildAnthropicErrorEvent, b as stopReviewEnabled, bn as HTTPError, bt as nativeSubagentModel, c as personasFor, cn as tryRefreshAndRetry, ct as logStreamError, d as buildStopHookCommand, dn as cacheVSCodeVersion, dt as handleMcpDelete, en as UPSTREAM_INACTIVITY_TIMEOUT_MS, et as ADVISOR_INTERNAL_TOOL_NAME, f as captureLaunchBaseline, fn as filterBetaHeader, ft as handleMcpPost, g as launchBaselineKey, gn as sleep$1, gt as browserCompoundToolsEnabled, h as injectStopHookIntoSettingsFile, hn as resolveModel, ht as browseAgentEnabled, i as buildAgentPrompt, in as withInstallLock, it as isAdvisorRequested, j as liveExec, jt as createChatCompletions, k as stopReviewStateDir, kt as pickEndpoint, l as buildArtifactOpenHookCommand, ln as cacheCopilotVersion, lt as readIteratorWithTimeout, m as fileBlockBudget, mn as resolveCodexModel, mt as artifactToolsEnabled, n as MCP_GROUPS, nn as pickClaudeDefault, nt as buildAdvisorStream, o as buildPeerAwarenessSummary, on as setupGitHubAgentToken, ot as buildOpenAIErrorEvent, p as decideStopHook, pn as isNullish, pt as agentToolsEnabled, q as buildToolbeltAwareness, qt as collapsePathKeys, r as assertMcpToolSurfaceConsistent, rn as getPackageVersion, rt as injectAdvisorTool, s as enumerateInjectedMcpToolNames, sn as setupGitHubToken, st as isControllerClosedError, t as GROUP_META, tn as generateRandomPort, tt as ADVISOR_TOOL_INSTRUCTIONS, u as buildSessionBindHookCommand, un as cacheModels, ut as relayAnthropicStream, v as stopGateId, vn as getGitHubUser, vt as fleetToolsEnabled, w as fileReviewDebounce, wn as copilotHeaders, wt as countTokens, x as fileBaselineStore, xn as forwardError, xt as standInToolEnabled, y as stopGatePlanMode, yn as fetchWithTransientRetry, yt as geminiAvailable, zt as extractZipMember } from "./peer-mcp-personas-BKwMCOsl.js";
3
- import { a as isUnderClaudeConfigMirror, d as writeRuntimeFileSecure, i as ensurePaths, o as removeOwnClaudeConfigMirror, r as ensureClaudeConfigMirror, t as PATHS, u as writeArtifactCredsToMirror } from "./paths-BO22pMUb.js";
4
- import { c as killManagedTree, d as runCommandCapture, f as runCommandVoid, l as parseBoolEnv, s as killChildProcessTree, u as resolveExecutable } from "./lifecycle-D-1CYr1Y.js";
5
- import { a as sweepRegistry } from "./lifecycle-bPdiXjYB.js";
2
+ import { $ as searchWeb, $t as DEFAULT_CLAUDE_MODEL_FALLBACKS, A as trustRepo, An as state, At as getTokenCount, Bt as hasSupportedBrowserInstalled, C as fileLastPromptStore, Cn as fetchWithTransientRetry, Ct as scoutModel, D as repoRoot, Dn as copilotBaseUrl, Dt as shimDefaultsToXhigh, E as repoFingerprint, En as GITHUB_API_BASE_URL, Et as workerToolsEnabled, Ft as createChatCompletions, G as buildEnv, Gt as CONDENSED_OPERATING_SEQUENCE, Ht as extractTarGzMember, It as MAX_RESPONSE_BODY_BYTES, J as toolbeltEnabled, Jt as ArtifactClient, K as availableToolCommands, Kt as DEFINITION_OF_GREATNESS, Lt as readResponseBodyCapped, M as resolveSealedGate, Mt as resolveMcpToolTimeoutMs, Nt as pickEndpoint, O as stopGateEnabledForRepo, On as copilotHeaders, Ot as countTokens, Pt as createResponses, Q as assetFor, Qt as toolbeltPathOverride, Rt as parseJsonOrDiagnose, S as fileFindingsStore, Sn as getGitHubUser, St as reviewerModel, T as isSubagentContext, Tn as forwardError, Tt as standInToolEnabled, Ut as extractZipMember, Vt as provisionAndIndexColbert, Wt as warmTreeSitterPool, X as vscodeRipgrepPath, Xt as buildWorkspaceHeaderJson, Y as toolbeltSkipSet, Yt as buildWorkspaceHeaderHelperCommand, Z as TOOLBELT_TOOLS, Zt as collapsePathKeys, _ as stopGateDisabled, _n as isNullish, _t as browserCompoundToolsEnabled, a as buildPeerAwarenessSnippet, an as generateRandomPort, at as buildAnthropicErrorEvent, b as stopReviewEnabled, bn as sleep$1, bt as geminiAvailable, c as personasFor, cn as withInstallLock, ct as logStreamError, d as buildStopHookCommand, dn as setupGitHubToken, dt as handleMcpDelete, en as DEFAULT_CODEX_MODEL, et as ADVISOR_INTERNAL_TOOL_NAME, f as captureLaunchBaseline, fn as tryRefreshAndRetry, ft as handleMcpPost, g as launchBaselineKey, gn as filterBetaHeader, gt as browseAgentEnabled, h as injectStopHookIntoSettingsFile, hn as cacheVSCodeVersion, ht as brainstormModel, i as buildAgentPrompt, in as UPSTREAM_INACTIVITY_TIMEOUT_MS, it as isAdvisorRequested, j as liveExec, jt as assembleResponsesPayload, k as stopReviewStateDir, kn as githubHeaders, kt as createMessages, l as buildArtifactOpenHookCommand, ln as setupCopilotToken, lt as readIteratorWithTimeout, m as fileBlockBudget, mn as cacheModels, mt as artifactToolsEnabled, n as MCP_GROUPS, nn as DEFAULT_PORT, nt as buildAdvisorStream, o as buildPeerAwarenessSummary, on as pickClaudeDefault, ot as buildOpenAIErrorEvent, p as decideStopHook, pn as cacheCopilotVersion, pt as agentToolsEnabled, q as buildToolbeltAwareness, qt as shouldUseInsecureTls, r as assertMcpToolSurfaceConsistent, rn as UPSTREAM_FETCH_TIMEOUT_MS, rt as injectAdvisorTool, s as enumerateInjectedMcpToolNames, sn as getPackageVersion, st as isControllerClosedError, t as GROUP_META, tn as DEFAULT_CODEX_MODEL_FALLBACKS, tt as ADVISOR_TOOL_INSTRUCTIONS, u as buildSessionBindHookCommand, un as setupGitHubAgentToken, ut as relayAnthropicStream, v as stopGateId, vn as resolveCodexModel, vt as browserToolsEnabled, w as fileReviewDebounce, wn as HTTPError, wt as scribeModel, x as fileBaselineStore, xn as getModels, xt as nativeSubagentModel, y as stopGatePlanMode, yn as resolveModel, yt as fleetToolsEnabled, zt as provisionBrowserAssets } from "./peer-mcp-personas-CDja7arT.js";
3
+ import { a as isUnderClaudeConfigMirror, d as writeRuntimeFileSecure, i as ensurePaths, o as removeOwnClaudeConfigMirror, r as ensureClaudeConfigMirror, t as PATHS, u as writeArtifactCredsToMirror } from "./paths-Srxs-aR-.js";
4
+ import { c as killManagedTree, d as resolveExecutable, f as runCommandCapture, l as parseBoolEnv, p as runCommandVoid, s as killChildProcessTree, u as parseIntEnv } from "./lifecycle-C-9_vhyM.js";
5
+ import { a as sweepRegistry } from "./lifecycle-Cuuj40CW.js";
6
6
  import { defineCommand, runMain } from "citty";
7
7
  import consola from "consola";
8
8
  import { createHash, randomBytes, randomUUID } from "node:crypto";
@@ -979,7 +979,7 @@ function dispatcherDescription(mode) {
979
979
  return `${{
980
980
  explore: "Non-blocking `explore` worker: dispatches a read-only autonomous worker (its own context) in the background and delivers its summary as a completion notification.",
981
981
  implement: "Non-blocking `implement` worker: dispatches an autonomous coding worker (read/write/bash) that ALWAYS runs in an isolated git worktree and returns the diff (for in-place edits use the `implementer` subagent), in the background, and delivers its result as a completion notification.",
982
- review: "Non-blocking `review` worker: dispatches a read-only reviewer that reads the code itself to verify a change or claim, in the background, and delivers findings as a completion notification.",
982
+ review: "Non-blocking `review` worker: the backgrounded counterpart of the `reviewer` subagent, running a cross-lab model. In a git workspace it takes an isolated worktree and can therefore VERIFY rather than only read: reproduce a failure, run the build or suite to check a claim, and author a throwaway probe test. Outside git it degrades to read-only rather than failing. Returns severity-ranked findings with file:line and a go/no-go, as a completion notification. Use `explore` instead when you just need to find or understand something.",
983
983
  plan: "Non-blocking `plan` worker: dispatches a read-only planner that returns an ordered implementation plan, in the background, and delivers it as a completion notification.",
984
984
  test: "Non-blocking `test` worker: dispatches an independent test author (in an isolated git worktree) that writes tests trying to break the implementation, in the background, and delivers pass/fail as a completion notification.",
985
985
  browse: "Non-blocking `browse` worker: dispatches an autonomous browser agent in the background and delivers its result as a completion notification."
@@ -1243,6 +1243,75 @@ const BUILTIN_SUBAGENT_DEFINITIONS = {
1243
1243
  prompt: "You are a planning agent. Read the codebase (read-only — do not modify files) to design a concrete, ordered implementation plan for the task: the approach, the specific files to change, reuse of existing utilities, risks, and how the result will be verified. Return the plan as your final message."
1244
1244
  }
1245
1245
  };
1246
+ /** Empty-string-safe read of an optional model id. */
1247
+ function nonEmptyModel(id) {
1248
+ return id && id.length > 0 ? id : void 0;
1249
+ }
1250
+ /**
1251
+ * The shared "prefer the dedicated tools over shell" steer, appended to every
1252
+ * native subagent prompt. `bashUses` names the work that legitimately belongs in
1253
+ * Bash for that agent (`builds` for a coder, `repros` for an investigator), the
1254
+ * only token that ever differed across the three hand-copied variants this
1255
+ * replaces.
1256
+ *
1257
+ * Deliberately NOT merged with `FILE_TOOL_GUIDANCE` in
1258
+ * `anthropic-translate/anthropic-request.ts`: that one is injected at the shim
1259
+ * boundary and therefore only reaches shim-routed (non-Claude) models. When a
1260
+ * native falls back to the lead's Claude model the shim is bypassed entirely, so
1261
+ * this prompt-level copy is the only coverage that survives. Two layers, two
1262
+ * different reasons to exist.
1263
+ */
1264
+ function fileToolSteer(bashUses) {
1265
+ return `Use the dedicated Edit/Write/Read tools for file changes and Grep/Glob for search; reserve Bash for running ${bashUses}, tests, and git. Do not shell out (sed/awk/python/here-docs) to read or edit files.`;
1266
+ }
1267
+ /** The read-only half of `fileToolSteer`, for agents that never write. */
1268
+ function readOnlyToolSteer() {
1269
+ return "Use Read to read files and Grep/Glob plus the semantic code search tool to find them; Bash is for read-only inspection such as git log, git blame, and git show. Do not modify any file, and do not run mutating commands.";
1270
+ }
1271
+ /**
1272
+ * `tools:` allowlist for the read-only natives (`scout`, `brainstorm`), modelled
1273
+ * on Claude Code's own `Explore`/`Plan` built-ins, which run with every tool
1274
+ * EXCEPT Agent / Artifact / ExitPlanMode / Edit / Write / NotebookEdit — note
1275
+ * that Anthropic's own read-only agent keeps Bash, which is what makes `git log`
1276
+ * and `git blame` reachable.
1277
+ *
1278
+ * Two deliberate deviations, both forced by the frontmatter format:
1279
+ *
1280
+ * 1. `tools:` is a POSITIVE allowlist with no "all except" form, so the
1281
+ * complement has to be spelled out. Rather than enumerate every harness tool
1282
+ * (which varies by Claude Code version, and would silently drop anything
1283
+ * added later), this lists the read / search / shell core that a read-only
1284
+ * agent actually uses. Tools added by a future release are NOT inherited by
1285
+ * these two agents; that is the price of real enforcement over a prompt that
1286
+ * merely asks nicely.
1287
+ * 2. The workers and orchestrate MCP groups are excluded on the same reasoning
1288
+ * that makes `Explore` drop `Agent`: both spawn further agents, so leaving
1289
+ * them in would reintroduce exactly the recursion that exclusion prevents.
1290
+ *
1291
+ * NOT A SANDBOX. `Bash` is retained because Anthropic's own read-only built-in
1292
+ * retains it, and without it an explorer cannot run `git log` / `git blame` /
1293
+ * `git show`, which is most of what repository archaeology needs. A shell is a
1294
+ * general write primitive, so "read-only" here means the agent has no dedicated
1295
+ * mutation tool and is instructed not to mutate, NOT that mutation is
1296
+ * impossible. Dropping Edit/Write still removes the path a model reaches for by
1297
+ * default. If a future change needs a hard guarantee, this allowlist is not
1298
+ * where it can be made.
1299
+ *
1300
+ * `searchKey` is the RESOLVED group key, not the bare literal: a user-side
1301
+ * `mcpServers` collision renames the group (`gh-router-search`, …), and a
1302
+ * hardcoded `mcp__search__*` would then grant nothing at all.
1303
+ */
1304
+ function readOnlyToolAllowlist(searchKey) {
1305
+ return [
1306
+ "Read",
1307
+ "Grep",
1308
+ "Glob",
1309
+ "Bash",
1310
+ "WebFetch",
1311
+ "WebSearch",
1312
+ `mcp__${searchKey}__*`
1313
+ ];
1314
+ }
1246
1315
  /**
1247
1316
  * Build the JSON payload for `claude --agents <path>`.
1248
1317
  *
@@ -1275,22 +1344,42 @@ function buildPeerAgentDefinitions(opts) {
1275
1344
  }),
1276
1345
  ...peersMcp
1277
1346
  };
1278
- const nativeModel = opts.nativeSubagentModel && opts.nativeSubagentModel.length > 0 ? opts.nativeSubagentModel : void 0;
1347
+ const nativeModel = nonEmptyModel(opts.nativeSubagentModel);
1348
+ const reviewerModel$1 = nonEmptyModel(opts.reviewerModel);
1349
+ const brainstormModel$1 = nonEmptyModel(opts.brainstormModel);
1350
+ const scoutModel$1 = nonEmptyModel(opts.scoutModel);
1351
+ const scribeModel$1 = nonEmptyModel(opts.scribeModel);
1279
1352
  const modelField = nativeModel ? { model: nativeModel } : {};
1353
+ const searchKey = opts.groupKeys.search ?? GROUP_META.search.preferredKey;
1354
+ const searchMcp = opts.serverUrl ? { mcpServers: { [searchKey]: httpEntryFor(opts.serverUrl, "search", opts.nonce, opts.workspaceHeaderCmd) } } : {};
1280
1355
  out.implementer = {
1281
1356
  description: nativeModel ? `Bounded implementation subagent running ${nativeModel} (strong non-Claude coder, maximum reasoning). Use proactively for well-scoped coding tasks — edits, small features, fixes — to keep the lead's context focused; runs in its own context. Model is overridable at spawn.` : `Bounded implementation subagent (native tools, runs on the lead's model in its own context). Use proactively for well-scoped coding tasks — edits, small features, fixes — to keep the lead's context focused. Model is overridable at spawn.`,
1282
- prompt: "You are a bounded implementation subagent for well-scoped coding tasks. Implement the requested change surgically, matching the surrounding code style and minimizing unrelated churn. Use the dedicated Edit/Write/Read tools for file changes and Grep/Glob for search; reserve Bash for running builds, tests, and git — do not shell out (sed/awk/python/here-docs) to read or edit files. Verify with the project's build or tests where applicable. Do the work yourself — do not spawn further subagents. Report exactly what changed and any risks.",
1357
+ prompt: "You are a bounded implementation subagent for well-scoped coding tasks. Implement the requested change surgically, matching the surrounding code style and minimizing unrelated churn. " + fileToolSteer("builds") + " Verify with the project's build or tests where applicable. Do the work yourself — do not spawn further subagents. Report exactly what changed and any risks.",
1283
1358
  ...modelField
1284
1359
  };
1285
- out.debugger = {
1286
- description: nativeModel ? `Root-cause & debugging subagent running ${nativeModel} at maximum reasoning. Use proactively for reproducing a bug end to end, isolating the true root cause, and proposing a minimal fix investigation-heavy work best kept off the lead's context; runs in its own context. Model is overridable at spawn.` : `Root-cause & debugging subagent (native tools, runs on the lead's model in its own context). Use proactively for reproducing a bug end to end, isolating the true root cause, and proposing a minimal fix kept off the lead's context. Model is overridable at spawn.`,
1287
- prompt: "You are a root-cause debugging subagent. Reproduce the failure end to end first — as close to how a real user hits it as you can before theorizing. Form hypotheses and test them against the actual code and runtime: read the code, run the repro with Bash, and add temporary instrumentation only if needed (remove it after). Identify the true root cause, not a symptom; if a fix is in scope, make it minimal and verify the repro now passes. Use the dedicated Edit/Write/Read tools for file changes and Grep/Glob for search; reserve Bash for running repros, tests, and git do not shell out (sed/awk/python/here-docs) to read or edit files. Do the work yourself — do not spawn further subagents. Report the root cause with evidence, the fix (if any), and any residual risks.",
1288
- ...modelField
1360
+ out.reviewer = {
1361
+ description: reviewerModel$1 ? `Feedback subagent running ${reviewerModel$1}, a DIFFERENT lab from both the lead and the implementer, so its blind spots are decorrelated from whoever produced the work. Use proactively when something already exists and you want it assessed: a diff, a plan, a document, a failing test. Unlike the stateless peer critics, it reads the repo and can RUN things, so prefer it whenever the assessment needs execution or repo context (reproduce a failure, run the suite, bisect); prefer a peer critic when you already hold the artifact and want a fresh-context opinion on it. Model is overridable at spawn.` : `Feedback subagent (native tools, runs on the lead's model in its own context). Use proactively when something already exists and you want it assessed: a diff, a plan, a document, a failing test. Unlike the stateless peer critics, it reads the repo and can RUN things, so prefer it whenever the assessment needs execution or repo context; prefer a peer critic when you already hold the artifact and want a fresh-context opinion on it. Model is overridable at spawn.`,
1362
+ prompt: "You are a feedback subagent. Your job is to tell the caller what is actually true about the artifact you are given — code, a plan, a document, a failure report — and what is wrong with it. Verify against the ACTUAL code by reading it; never assume. Do whatever the assessment requires: reproduce a failure end to end as close to how a real user hits it as you can, form hypotheses and test them against the code and runtime, and isolate the true root cause rather than a symptom. Where the change warrants it, author tests that try to BREAK the implementation (edge cases, error paths, and the acceptance criteria as executable checks), run them, and report which pass and which fail; do NOT modify production code just to make tests pass. " + fileToolSteer("builds") + " Do the work yourself — do not spawn further subagents. Report severity-ranked findings with `file:line` citations, the evidence behind each, and end with a clear go/no-go.",
1363
+ ...reviewerModel$1 ? { model: reviewerModel$1 } : {}
1289
1364
  };
1290
- out["qa-engineer"] = {
1291
- description: nativeModel ? `Review, testing & QA subagent running ${nativeModel} at maximum reasoning. Use proactively to review a change for correctness, author and run tests that try to break it, and give a severity-ranked go/no-go while keeping the lead's context focused; runs in its own context. Model is overridable at spawn.` : `Review, testing & QA subagent (native tools, runs on the lead's model in its own context). Use proactively to review a change for correctness, author and run tests that try to break it, and give a severity-ranked go/no-go. Model is overridable at spawn.`,
1292
- prompt: "You are a review, testing, and QA subagent. Verify correctness against the ACTUAL code by reading it never assume. Where the change warrants it, author tests that try to BREAK the implementation (edge cases, error paths, and the acceptance criteria as executable checks), then run them and report which pass and which fail; do NOT modify production code just to make tests pass. Use the dedicated Edit/Write/Read tools for file changes and Grep/Glob for search; reserve Bash for running builds, tests, and git do not shell out (sed/awk/python/here-docs) to read or edit files. Do the work yourself do not spawn further subagents. Report severity-ranked findings with `file:line` citations and end with a clear go/no-go.",
1293
- ...modelField
1365
+ out.brainstorm = {
1366
+ description: brainstormModel$1 ? `Divergent-options subagent running ${brainstormModel$1} (third lab, for approaches the lead would not generate). Use proactively BEFORE an approach is chosen. Pass the decision, the constraints, what you have already ruled out, and the cost of being wrong; pass your current leading approach too if you have one, and it will try to beat it rather than restate it. Read-only; it proposes, then hands off to implementer. Model is overridable at spawn.` : `Divergent-options subagent (runs on the lead's model in its own context). Use proactively BEFORE an approach is chosen. Pass the decision, the constraints, what you have already ruled out, and the cost of being wrong; pass your current leading approach too if you have one, and it will try to beat it rather than restate it. Read-only; it proposes, then hands off to implementer. Model is overridable at spawn.`,
1367
+ prompt: "You are a divergent-options subagent: the lead's sounding board while an approach is still open. Your job is to surface the option the lead would not have reached on its own. If the caller states its current leading approach, your job is to try to beat it, and you close with one verdict: `replace`, `retain`, or `insufficient evidence`. `replace` requires naming a concrete alternative that dominates it and the evidence that decides between them. `retain` is a real answer and a useful one: say it plainly when the approach survives a genuine attempt to beat it. Manufactured disagreement is as useless as agreement; do neither. If the caller states no leading approach, generate independently and let the lead compare. Return 3 to 5 approaches that differ in MECHANISM, not in phrasing. For each: how it works, what it costs, what would have to be true for it to be the right answer, and the failure mode that would kill it. Near-duplicate options are the failure mode to avoid — if only one real approach exists, say so plainly and explain why the alternatives are dead, because one honest option beats four padded ones. Screen EVERY candidate against this repository and this environment before you rank them, then verify the one you are about to recommend can actually run here: read the code path it depends on, the guard that would refuse it, the artifact it assumes exists. A recommendation that cannot execute is worse than no recommendation. If checking kills your front-runner, rerank and say so. Ground every option in what the repository actually contains, and prefer reusing what is already there over inventing something new. " + readOnlyToolSteer() + " Do the work yourself — do not spawn further subagents.",
1368
+ tools: readOnlyToolAllowlist(searchKey),
1369
+ ...brainstormModel$1 ? { model: brainstormModel$1 } : {},
1370
+ ...searchMcp
1371
+ };
1372
+ if (scoutModel$1) out.scout = {
1373
+ description: `Read-only exploration subagent running ${scoutModel$1} (fast and cheap, so repository lookups do not run at the lead's model rates). Use proactively to find or understand something in the codebase: it sweeps widely and returns conclusions with file:line references rather than file dumps. Model is overridable at spawn.`,
1374
+ prompt: "You are a read-only exploration subagent. Answer the question by investigating the repository: cast a wide net, then narrow. Return the conclusion, not the raw material — cite `file:line` for anything load-bearing and quote only the lines that matter. If the answer is that something does not exist, say so explicitly and describe where you looked. " + readOnlyToolSteer() + " Do the work yourself — do not spawn further subagents.",
1375
+ tools: readOnlyToolAllowlist(searchKey),
1376
+ model: scoutModel$1,
1377
+ ...searchMcp
1378
+ };
1379
+ out.scribe = {
1380
+ description: scribeModel$1 ? `Documentation subagent running ${scribeModel$1}. Use proactively for prose that trails the code: docs, ADRs, CLAUDE.md sections, changelog entries, and README updates that have gone stale. Keeps low-glamour upkeep off the lead's context. Model is overridable at spawn.` : `Documentation subagent (runs on the lead's model in its own context). Use proactively for prose that trails the code: docs, ADRs, CLAUDE.md sections, changelog entries, and README updates that have gone stale. Model is overridable at spawn.`,
1381
+ prompt: "You are a documentation subagent. Write and maintain the prose that trails the code: docs, ADRs, CLAUDE.md sections, changelog entries, README rows. Read the code before describing it — every claim you write must be checkable against the repository as it is now, not as a summary said it was. Match the surrounding document's voice, structure, and level of detail. Prefer updating an existing document over adding a new one, and delete what has become false rather than layering a correction on top of it. " + fileToolSteer("builds") + " Do the work yourself — do not spawn further subagents. Report which documents changed and any claim you could not verify.",
1382
+ ...scribeModel$1 ? { model: scribeModel$1 } : {}
1294
1383
  };
1295
1384
  if (opts.workerToolsAvailable) {
1296
1385
  const workersKey = workersKeyOf(opts.groupKeys);
@@ -1628,6 +1717,10 @@ async function writePeerMcpRuntimeFiles(serverUrl, opts) {
1628
1717
  workerToolsAvailable: opts.workerToolsAvailable,
1629
1718
  browseAvailable: opts.browseAvailable,
1630
1719
  nativeSubagentModel: opts.nativeSubagentModel,
1720
+ reviewerModel: opts.reviewerModel,
1721
+ brainstormModel: opts.brainstormModel,
1722
+ scoutModel: opts.scoutModel,
1723
+ scribeModel: opts.scribeModel,
1631
1724
  nonce,
1632
1725
  codexHome,
1633
1726
  serverUrl,
@@ -2894,7 +2987,7 @@ async function discoverGateCommands(cwd, opts) {
2894
2987
  if (files.length === 0) return null;
2895
2988
  let result;
2896
2989
  try {
2897
- const { runWorkerAgent } = await import("./engine-v9-pEKoD.js");
2990
+ const { runWorkerAgent } = await import("./engine-5VxiBAdY.js");
2898
2991
  result = await runWorkerAgent({
2899
2992
  mode: "explore",
2900
2993
  workspace: root,
@@ -4079,7 +4172,7 @@ const STYLE_DIRECTIVE = "Write concisely without losing detail. Use a natural hu
4079
4172
  * Self-referentially compliant with the style directive: no em dashes, no
4080
4173
  * Claude / Anthropic attribution.
4081
4174
  */
4082
- const OPERATING_DEFAULTS_DIRECTIVE = "## Operating defaults (apply when the user has not specified otherwise; the user's explicit direction and the domain's own standards always override)\n\nOrchestrate. Delegate research, implementation, review, and large reads to the right subagent, worker, or model (the `implementer`, `debugger`, and `qa-engineer` native subagents for bounded implementation, root-cause debugging, and review/testing respectively; worker-* agents for background non-blocking runs; Task subagents for parallel work; peer critics for review) so your own context stays free to reason and collaborate with the user. Prefer parallel delegation for independent work. Do trivial, surgical, and last-mile work directly; delegate the rest rather than doing it yourself and filling your own context. Delegate to a subagent by default whenever one can do the work without loss of quality: the main thread is where you think with and respond to the user, and its context window is a finite shared resource, so protect it by pushing heavy or exploratory work outward and keeping only the conclusions.\n\nAim high. Default to radical simplicity and a relentless focus on the user's real experience: design for the person and the job to be done, not the demo. Reason about the whole system from first principles, anticipating scale and the long arc rather than patching the surface. Work backwards from the outcome the user actually needs. Question every assumption and prefer what you can derive, reproduce, or test.\n\nEngineering excellence. When making technical decisions, give little weight to development cost; prefer quality, simplicity, robustness, scalability, and long-term maintainability. Fix a bug by first reproducing it end to end, as close to how a real user hits it as you can, so you solve the real problem and not a symptom. When testing a product end to end, be picky about the UI and obsessed with pixel perfection: if something clearly looks off, even when it is unrelated to your task, get it fixed along the way. Hold that same bar for the codebase itself: a lint error, a failing test, or a flaky test is worth fixing the moment you see it, whoever introduced it. Fold it into your current work rather than letting it derail the task the user actually asked for.";
4175
+ const OPERATING_DEFAULTS_DIRECTIVE = "## Operating defaults (apply when the user has not specified otherwise; the user's explicit direction and the domain's own standards always override)\n\nOrchestrate. Delegate research, implementation, review, and large reads to the right subagent, worker, or model. Reach for `implementer` when you know what to build, `reviewer` when something exists and you want it assessed (including reproducing and root-causing a failure), `brainstorm` when you do not yet know which approach to take, `scout` to find or understand something in the repo, and `scribe` for docs and ADRs that trail the code; worker-* agents for background non-blocking runs; Task subagents for parallel work; peer critics for review. That keeps your own context free to reason and collaborate with the user. Prefer parallel delegation for independent work. Do trivial, surgical, and last-mile work directly; delegate the rest rather than doing it yourself and filling your own context. Delegate to a subagent by default whenever one can do the work without loss of quality: the main thread is where you think with and respond to the user, and its context window is a finite shared resource, so protect it by pushing heavy or exploratory work outward and keeping only the conclusions.\n\nAim high. Default to radical simplicity and a relentless focus on the user's real experience: design for the person and the job to be done, not the demo. Reason about the whole system from first principles, anticipating scale and the long arc rather than patching the surface. Work backwards from the outcome the user actually needs. Question every assumption and prefer what you can derive, reproduce, or test.\n\nEngineering excellence. When making technical decisions, give little weight to development cost; prefer quality, simplicity, robustness, scalability, and long-term maintainability. Fix a bug by first reproducing it end to end, as close to how a real user hits it as you can, so you solve the real problem and not a symptom. When testing a product end to end, be picky about the UI and obsessed with pixel perfection: if something clearly looks off, even when it is unrelated to your task, get it fixed along the way. Hold that same bar for the codebase itself: a lint error, a failing test, or a flaky test is worth fixing the moment you see it, whoever introduced it. Fold it into your current work rather than letting it derail the task the user actually asked for.";
4083
4176
  /**
4084
4177
  * Condensed digest of OPERATING_DEFAULTS_DIRECTIVE for the spawned session's
4085
4178
  * system prompt (--append-system-prompt). The FULL directive is prepended to
@@ -4820,8 +4913,27 @@ function keepDisplayOn() {
4820
4913
  const ES_CONTINUOUS = 2147483648;
4821
4914
  const ES_SYSTEM_REQUIRED = 1;
4822
4915
  const ES_DISPLAY_REQUIRED = 2;
4823
- /** Default time to wait for the helper's `OK` readiness line. */
4824
- const DEFAULT_READY_TIMEOUT_MS = 5e3;
4916
+ /** Default time to wait for the helper's `OK` readiness line.
4917
+ *
4918
+ * Sized for the slowest LEGITIMATE path, not the typical one. The script's
4919
+ * `Add-Type -MemberDefinition` compiles a C# P/Invoke shim through csc.exe on
4920
+ * first use, and that compile happens BEFORE the `OK` line is printed. On a
4921
+ * cold machine (a fresh CI runner, a laptop that just booted, a host with
4922
+ * aggressive on-access AV scanning) it routinely takes well over five seconds.
4923
+ *
4924
+ * CORRECTION to the rationale this constant shipped with. An earlier version of
4925
+ * this comment (and the commit that raised the value) claimed a short timeout
4926
+ * made the user "silently lose keep-awake". That is wrong, and a cross-lab
4927
+ * reviewer caught it: `startKeepAwake` does nothing with `ready` but
4928
+ * `consola.debug` it (`index.ts:128`). The handle is retained and the child
4929
+ * keeps running, so the assertion is still set, just later than we observed it.
4930
+ *
4931
+ * The real cost of a tight value is therefore a LYING LOG, not a lost feature:
4932
+ * we report "inactive" for a helper that is about to work. That is still worth
4933
+ * fixing, because a false negative in a diagnostic is how you lose an afternoon
4934
+ * chasing a working feature. Waiting longer costs nothing either way, since the
4935
+ * readiness promise is awaited in the background and never blocks launch. */
4936
+ const DEFAULT_READY_TIMEOUT_MS = 2e4;
4825
4937
  /**
4826
4938
  * The execution-state flags to assert. Always `ES_CONTINUOUS |
4827
4939
  * ES_SYSTEM_REQUIRED` (machine stays awake); adds `ES_DISPLAY_REQUIRED`
@@ -5222,7 +5334,7 @@ function initProxyFromEnv() {
5222
5334
  //#endregion
5223
5335
  //#region package.json
5224
5336
  var name = "github-router";
5225
- var version$1 = "0.3.229";
5337
+ var version$1 = "0.3.238";
5226
5338
 
5227
5339
  //#endregion
5228
5340
  //#region src/lib/approval.ts
@@ -5347,7 +5459,7 @@ function detectCapabilityMismatch(info, model) {
5347
5459
  * that should get a probe row added.
5348
5460
  *
5349
5461
  * Format (single line, deterministic-ish key order):
5350
- * [fields] path=<P> body_keys=<csv> tool_field_keys=<csv> beta_values=<csv>
5462
+ * [fields] path=<P> body_keys=<csv> tool_field_keys=<csv> beta_values=<csv> agent=<id|->
5351
5463
  *
5352
5464
  * Where:
5353
5465
  * - `body_keys` is the alphabetical union of top-level keys in the
@@ -5357,13 +5469,19 @@ function detectCapabilityMismatch(info, model) {
5357
5469
  * - `beta_values` is the comma-split anthropic-beta header value as
5358
5470
  * received (NOT filtered) — captures what the client sends, not
5359
5471
  * what we forward
5472
+ * - `agent` is Claude Code's `x-claude-code-agent-id` header, or `-` for
5473
+ * main-loop traffic. Without it a capture cannot tell a subagent request
5474
+ * from a main-loop one, which is exactly the question you need answered
5475
+ * when reasoning about per-agent request shape (does a subagent send a
5476
+ * `thinking` block?). The header value is opaque to us and is logged
5477
+ * verbatim.
5360
5478
  */
5361
5479
  function logRequestFields(opts) {
5362
5480
  if (process.env.GH_ROUTER_LOG_FIELDS !== "1") return;
5363
5481
  const bodyKeys = collectTopLevelKeys(opts.body);
5364
5482
  const toolFieldKeys = collectToolFieldKeys(opts.body);
5365
5483
  const betaValues = (opts.betaHeader ?? "").split(",").map((v) => v.trim()).filter(Boolean);
5366
- consola.info(`[fields] path=${opts.path} body_keys=${bodyKeys.join(",")} tool_field_keys=${toolFieldKeys.join(",")} beta_values=${betaValues.join(",")}`);
5484
+ consola.info(`[fields] path=${opts.path} body_keys=${bodyKeys.join(",")} tool_field_keys=${toolFieldKeys.join(",")} beta_values=${betaValues.join(",")} agent=${opts.agentId && opts.agentId.length > 0 ? opts.agentId : "-"}`);
5367
5485
  }
5368
5486
  function collectTopLevelKeys(body) {
5369
5487
  if (!body || typeof body !== "object" || Array.isArray(body)) return [];
@@ -6306,20 +6424,29 @@ function parseDisableParallelToolUse(toolChoice) {
6306
6424
  return toolChoice.disable_parallel_tool_use === true ? false : void 0;
6307
6425
  }
6308
6426
  /** Default absent Anthropic `thinking` to an effort, clamped by the model.
6309
- * OpenAI-frontier shim models (gpt-5.6-sol/gpt-5.5) default to xhigh so the
6310
- * native gpt-5.6-sol subagents (implementer/debugger/qa-engineer) and any
6311
- * `-m gpt-5.6-sol` main-loop session reason at max when the client sends no
6312
- * `thinking` block; every other shim model stays high. The
6313
- * `supported.includes("xhigh")` guard makes the intent explicit rather than
6314
- * trusting clampEffort to silently degrade. Opt out with
6315
- * `GH_ROUTER_DISABLE_FRONTIER_XHIGH_DEFAULT=1`. Returns undefined for a model
6316
- * that advertises NO `reasoning_effort` allowlist (may not support reasoning;
6317
- * forcing an effort could 400). Note: an explicit client `thinking` budget is
6318
- * handled by parseReasoningEffort and is NOT affected by this default. */
6427
+ * Every shim model defaults to `high`, so a client level maps to the identical
6428
+ * provider level (low→low, medium→medium, high→high, xhigh→xhigh) and `high` is
6429
+ * the only value the router injects on its own. There is deliberately NO floor:
6430
+ * an explicit client budget that buckets to `medium` yields `medium`, because a
6431
+ * one-directional max() would mean the router silently overriding the level the
6432
+ * user chose.
6433
+ *
6434
+ * Opt in to the previous behavior (xhigh for the OpenAI frontier models when no
6435
+ * thinking is sent) with `GH_ROUTER_FRONTIER_XHIGH_DEFAULT=1`. This replaces the
6436
+ * old opt-OUT `GH_ROUTER_DISABLE_FRONTIER_XHIGH_DEFAULT`, whose meaning would
6437
+ * have inverted under the new default.
6438
+ *
6439
+ * Two honest limits, both pre-existing: the level is bucketed from a token
6440
+ * budget so the mapping is lossy at the boundaries, and `clampEffort` moves a
6441
+ * level the model does not advertise (gemini has no `xhigh`). Returns undefined
6442
+ * for a model that advertises NO `reasoning_effort` allowlist, which leaves the
6443
+ * provider's own default rather than `high` — forcing an effort there could 400.
6444
+ * An explicit client `thinking` budget is handled by parseReasoningEffort and is
6445
+ * NOT affected by this default. */
6319
6446
  function defaultReasoningEffort(model) {
6320
6447
  const supported = model?.capabilities?.supports?.reasoning_effort;
6321
6448
  if (!(Array.isArray(supported) && supported.length > 0)) return void 0;
6322
- return clampEffort(parseBoolEnv(process.env.GH_ROUTER_DISABLE_FRONTIER_XHIGH_DEFAULT) !== true && model?.id != null && shimDefaultsToXhigh(model.id) && supported.includes("xhigh") ? "xhigh" : "high", supported);
6449
+ return clampEffort(parseBoolEnv(process.env.GH_ROUTER_FRONTIER_XHIGH_DEFAULT) === true && model?.id != null && shimDefaultsToXhigh(model.id) && supported.includes("xhigh") ? "xhigh" : "high", supported);
6323
6450
  }
6324
6451
  /**
6325
6452
  * Map Anthropic `thinking` to a Responses reasoning effort, clamped to the
@@ -7367,7 +7494,8 @@ async function handleCompletion(c) {
7367
7494
  logRequestFields({
7368
7495
  path: c.req.path,
7369
7496
  body: parsedForLog,
7370
- betaHeader: c.req.header("anthropic-beta")
7497
+ betaHeader: c.req.header("anthropic-beta"),
7498
+ agentId: c.req.header("x-claude-code-agent-id")
7371
7499
  });
7372
7500
  }
7373
7501
  if (state.manualApprove) await awaitApproval();
@@ -9014,7 +9142,11 @@ const claude = defineCommand({
9014
9142
  groupKeys,
9015
9143
  workerToolsAvailable: workerToolsEnabled(),
9016
9144
  browseAvailable: browseAgentEnabled(),
9017
- nativeSubagentModel: nativeSubagentModel()
9145
+ nativeSubagentModel: nativeSubagentModel(),
9146
+ reviewerModel: reviewerModel(),
9147
+ brainstormModel: brainstormModel(),
9148
+ scoutModel: scoutModel(),
9149
+ scribeModel: scribeModel()
9018
9150
  });
9019
9151
  state.peerMcpNonce = runtime.nonce;
9020
9152
  envVars.GH_ROUTER_HOOK_MCP_URL = serverUrl;
@@ -9217,6 +9349,7 @@ const claude = defineCommand({
9217
9349
  powerBrowseAvailable: state.powerBrowseEnabled,
9218
9350
  fleetAvailable: fleetToolsEnabled(),
9219
9351
  agentToolsAvailable: agentToolsEnabled(),
9352
+ scoutAvailable: scoutModel() != null,
9220
9353
  groupKeys
9221
9354
  });
9222
9355
  peerAwarenessSnippet = peerSnippet;
@@ -10147,7 +10280,7 @@ const internalStopHook = defineCommand({
10147
10280
  } catch {}
10148
10281
  let decision;
10149
10282
  try {
10150
- const timeoutEnv = Number.parseInt(process.env.GH_ROUTER_STOP_GATE_TIMEOUT_MS ?? "", 10);
10283
+ const timeoutEnv = parseIntEnv(process.env.GH_ROUTER_STOP_GATE_TIMEOUT_MS);
10151
10284
  const mode = dynamicMode();
10152
10285
  decision = await decideStopHook({
10153
10286
  stdin,
@@ -10159,7 +10292,7 @@ const internalStopHook = defineCommand({
10159
10292
  baseline: fileBaselineStore(nodePath.join(tmpdir(), "gh-router-stopgate-baseline")),
10160
10293
  isEnabledForRepo: (cwd) => stopGateEnabledForRepo(cwd),
10161
10294
  resolveChecks: mode ? buildResolveChecks(mode) : void 0,
10162
- timeoutMs: Number.isFinite(timeoutEnv) && timeoutEnv > 0 ? timeoutEnv : void 0,
10295
+ timeoutMs: timeoutEnv,
10163
10296
  planMode: stopGatePlanMode(),
10164
10297
  reviewDebounce: reviewEnabled ? fileReviewDebounce(stopReviewStateDir()) : void 0,
10165
10298
  spawnReview: reviewEnabled ? (ctx) => spawnStopReview(ctx, {
@@ -11007,6 +11140,10 @@ async function provisionServeEnhancements(serverUrl, opts = {}) {
11007
11140
  workerToolsAvailable: workerToolsEnabled(),
11008
11141
  browseAvailable: browseAllowed && browseAgentEnabled(),
11009
11142
  nativeSubagentModel: nativeSubagentModel(),
11143
+ reviewerModel: reviewerModel(),
11144
+ brainstormModel: brainstormModel(),
11145
+ scoutModel: scoutModel(),
11146
+ scribeModel: scribeModel(),
11010
11147
  builtinSubagents: BUILTIN_SUBAGENT_DEFINITIONS
11011
11148
  });
11012
11149
  state.peerMcpNonce = runtime.nonce;
@@ -11025,6 +11162,7 @@ async function provisionServeEnhancements(serverUrl, opts = {}) {
11025
11162
  compoundBrowseAvailable: browseAllowed && browserCompoundToolsEnabled(),
11026
11163
  powerBrowseAvailable: browseAllowed && state.powerBrowseEnabled,
11027
11164
  agentToolsAvailable: firstMateAllowed,
11165
+ scoutAvailable: scoutModel() != null,
11028
11166
  groupKeys
11029
11167
  })).catch((err) => consola.warn(`Peer-awareness CLAUDE.md append failed: ${String(err)}`));
11030
11168
  await prependStyleDirectiveToMirroredClaudeMd().catch((err) => consola.warn(`Style-directive CLAUDE.md prepend failed: ${String(err)}`));