github-router 0.3.323 → 0.3.324

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.
Files changed (27) hide show
  1. package/dist/{attribution-settings-CX-kIrT8.js → attribution-settings-sTUXqFzx.js} +366 -9
  2. package/dist/attribution-settings-sTUXqFzx.js.map +1 -0
  3. package/dist/browser-ext/manifest.json +1 -1
  4. package/dist/{claude-Cq1xGzbI.js → claude-Bni6m56W.js} +5 -5
  5. package/dist/{claude-Cq1xGzbI.js.map → claude-Bni6m56W.js.map} +1 -1
  6. package/dist/{codex-INt1hc_5.js → codex-DAnu246m.js} +2 -2
  7. package/dist/{codex-INt1hc_5.js.map → codex-DAnu246m.js.map} +1 -1
  8. package/dist/hooks.mjs +26 -0
  9. package/dist/hooks.sha256 +1 -1
  10. package/dist/{internal-first-mate-guard-mvfZal_M.js → internal-first-mate-guard-Cj_g7RFr.js} +2 -2
  11. package/dist/{internal-first-mate-guard-mvfZal_M.js.map → internal-first-mate-guard-Cj_g7RFr.js.map} +1 -1
  12. package/dist/{internal-first-mate-guard-Dvd1vZ4l.js → internal-first-mate-guard-ZqPHrYlh.js} +1 -1
  13. package/dist/{internal-worker-guard-BSoS4wzV.js → internal-worker-guard-Dd14aDXQ.js} +2 -2
  14. package/dist/{internal-worker-guard-BSoS4wzV.js.map → internal-worker-guard-Dd14aDXQ.js.map} +1 -1
  15. package/dist/main.js +6 -6
  16. package/dist/{serve-TiUhvpVp.js → serve-BGGcy8Nq.js} +6 -5
  17. package/dist/serve-BGGcy8Nq.js.map +1 -0
  18. package/dist/{server-setup-CgbHmupe.js → server-setup-CZ3tEsgq.js} +53 -2
  19. package/dist/server-setup-CZ3tEsgq.js.map +1 -0
  20. package/dist/{start-DNzOFabp.js → start-XFIxMRkE.js} +2 -2
  21. package/dist/{start-DNzOFabp.js.map → start-XFIxMRkE.js.map} +1 -1
  22. package/dist/{worker-dispatch-DwS99DXz.js → worker-dispatch-CcQygiAA.js} +27 -1
  23. package/dist/{worker-dispatch-DwS99DXz.js.map → worker-dispatch-CcQygiAA.js.map} +1 -1
  24. package/package.json +1 -1
  25. package/dist/attribution-settings-CX-kIrT8.js.map +0 -1
  26. package/dist/serve-TiUhvpVp.js.map +0 -1
  27. package/dist/server-setup-CgbHmupe.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  import { D as toolbeltEnabled, an as colbertDegradedWarning, bn as DEFAULT_CODEX_MODEL, in as hasSupportedBrowserInstalled, on as provisionAndIndexColbert, rn as provisionBrowserAssets, un as warmTreeSitterPool, xn as DEFAULT_CODEX_MODEL_FALLBACKS } from "./peer-mcp-personas-DcAErb_d.js";
2
2
  import { t as state } from "./state-BlMpEFAt.js";
3
3
  import { d as resolveModel, u as resolveCodexModel } from "./token-Css-ARGL.js";
4
- import { R as runSelfUpdate, a as sharedServerArgs, d as enableFileLogging, i as setupAndServe, n as getCodexEnvVars, r as parseSharedArgs, s as startKeepAwake, u as listModelsForEndpoint } from "./server-setup-CgbHmupe.js";
4
+ import { R as runSelfUpdate, a as sharedServerArgs, d as enableFileLogging, i as setupAndServe, n as getCodexEnvVars, r as parseSharedArgs, s as startKeepAwake, u as listModelsForEndpoint } from "./server-setup-CZ3tEsgq.js";
5
5
  import { i as launchChild, t as provisionToolbelt } from "./provision-B-a5KUCL.js";
6
6
  import { defineCommand } from "citty";
7
7
  import consola from "consola";
@@ -85,4 +85,4 @@ const codex = defineCommand({
85
85
  //#endregion
86
86
  export { codex };
87
87
 
88
- //# sourceMappingURL=codex-INt1hc_5.js.map
88
+ //# sourceMappingURL=codex-DAnu246m.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"codex-INt1hc_5.js","names":[],"sources":["../src/codex.ts"],"sourcesContent":["import process from \"node:process\"\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { enableFileLogging } from \"./lib/file-log-reporter\"\nimport { launchChild } from \"./lib/launch\"\nimport { listModelsForEndpoint } from \"./lib/model-validation\"\nimport {\n DEFAULT_CODEX_MODEL,\n DEFAULT_CODEX_MODEL_FALLBACKS,\n} from \"./lib/port\"\nimport {\n getCodexEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\nimport { runSelfUpdate } from \"./lib/self-update\"\nimport { state } from \"./lib/state\"\nimport { toolbeltEnabled } from \"./lib/toolbelt\"\nimport { provisionToolbelt } from \"./lib/toolbelt/provision\"\nimport { colbertDegradedWarning, provisionAndIndexColbert } from \"./lib/colbert\"\nimport { startKeepAwake } from \"./lib/keep-awake\"\nimport { warmTreeSitterPool } from \"./lib/tree-sitter-pool/pool\"\nimport { provisionBrowserAssets } from \"./lib/browser-mcp/provision\"\nimport { hasSupportedBrowserInstalled } from \"./lib/browser-mcp/browser-detect\"\nimport { resolveCodexModel, resolveModel } from \"./lib/utils\"\n\nexport const codex = defineCommand({\n meta: {\n name: \"codex\",\n description: \"Start the proxy server and launch Codex CLI\",\n },\n args: {\n ...sharedServerArgs,\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Override the default model for Codex CLI\",\n },\n },\n async run({ args }) {\n if (!process.stdout.isTTY) {\n consola.error(\"The codex subcommand requires a TTY (interactive terminal).\")\n process.exit(1)\n }\n\n const parsed = parseSharedArgs(args as unknown as Record<string, unknown>)\n\n let server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]\n let serverUrl: string\n try {\n const result = await setupAndServe({\n ...parsed,\n port: parsed.port, // undefined = random port\n silent: true,\n })\n server = result.server\n serverUrl = result.serverUrl\n } catch (error) {\n consola.error(\"Failed to start server:\", error instanceof Error ? error.message : error)\n process.exit(1)\n }\n\n // Best-effort self-update (detached, applies next launch).\n void runSelfUpdate({ selfUpdate: args[\"self-update\"] !== false })\n\n // Materialize the LLM toolbelt in the background (PATH prepend is in\n // getCodexEnvVars). Best-effort; never blocks launch.\n if (toolbeltEnabled()) {\n void provisionToolbelt().catch(() => {})\n }\n\n // Best-effort ColBERT semantic-search provision + background index of\n // the launch cwd. Opt-IN via --search (no-op otherwise); never blocks\n // launch, never throws.\n void provisionAndIndexColbert()\n\n // Surface a terminally-failed semantic index to the HUMAN (see the note\n // in claude.ts). Fire-and-forget; lexical search still works.\n void colbertDegradedWarning(undefined, { logsToFile: true })\n .then((warning) => {\n if (warning) process.stderr.write(`${warning}\\n`)\n })\n .catch(() => {})\n\n // Best-effort, bounded launch warm-up: ready one tree-sitter worker.\n // Opt out with GH_ROUTER_DISABLE_TS_POOL_WARMUP=1.\n void warmTreeSitterPool()\n\n // Best-effort: keep the machine awake while the proxy/Codex session\n // runs (win32 default-on; opt out GH_ROUTER_DISABLE_KEEP_AWAKE=1).\n // Self-registered SIGINT/SIGTERM/exit reaper releases the assertion.\n startKeepAwake()\n\n // Best-effort: materialize the browser extension + bridge into the\n // stable app-dir and stamp the running version. Gated inline (browse\n // opt-in + a supported browser) rather than via browserToolsEnabled()\n // so the codex command path doesn't eagerly pull the compressor /\n // worker-agent graph. Never blocks launch, never throws.\n const browseOptIn =\n state.browseEnabled || process.env.GH_ROUTER_ENABLE_BROWSE === \"1\"\n if (browseOptIn && hasSupportedBrowserInstalled()) {\n void provisionBrowserAssets().catch((err) =>\n consola.debug(\"Browser extension provisioning failed:\", err),\n )\n }\n\n const usingDefault = !args.model\n const requestedModel = args.model ?? DEFAULT_CODEX_MODEL\n\n // Resolve model before printing success message (so we show the actual model)\n // but enable file logging first so resolution warnings go to file, not terminal\n enableFileLogging()\n\n let codexModel = resolveCodexModel(requestedModel)\n if (codexModel !== requestedModel) {\n consola.info(`Model \"${requestedModel}\" resolved to \"${codexModel}\"`)\n }\n\n // For the implicit-default path only: honor the explicit fallback order\n // (DEFAULT_CODEX_MODEL, then DEFAULT_CODEX_MODEL_FALLBACKS led by gpt-5.5)\n // by cache presence BEFORE resolveCodexModel's codex-slug-preferring\n // \"best /responses model\" safety net. `resolveModel` (NOT resolveCodexModel)\n // walks the chain, so the codex-slug preference can't shadow an\n // earlier-in-chain named fallback (e.g. gpt-5.5) that IS present. The\n // resolveCodexModel result above stays as the FINAL safety net, used only\n // when none of the named chain entries is in the catalog.\n if (usingDefault && state.models) {\n const inCache = (id: string) =>\n state.models?.data.some((m) => m.id === id) ?? false\n const firstPresent = [DEFAULT_CODEX_MODEL, ...DEFAULT_CODEX_MODEL_FALLBACKS]\n .map((id) => resolveModel(id))\n .find((id) => inCache(id))\n if (firstPresent) {\n if (firstPresent !== codexModel) {\n consola.info(\n `Default model \"${DEFAULT_CODEX_MODEL}\" not in your Copilot model list; falling back to \"${firstPresent}\".`,\n )\n }\n codexModel = firstPresent\n }\n }\n\n // Validate model exists in Copilot model list\n const modelEntry = state.models?.data.find((m) => m.id === codexModel)\n if (!modelEntry) {\n const available = listModelsForEndpoint(\"/responses\")\n consola.warn(\n `Model \"${codexModel}\" not found. Available codex models: ${available.join(\", \")}`,\n )\n } else {\n const ctx = modelEntry.capabilities?.limits?.max_context_window_tokens\n if (ctx) consola.info(`Model context window: ${ctx.toLocaleString()} tokens`)\n }\n\n // Print to stderr directly — consola's terminal reporter is already gone\n process.stderr.write(`Server ready on ${serverUrl}, launching Codex CLI (${codexModel})...\\n`)\n\n const envVars = getCodexEnvVars(serverUrl)\n const extraArgs = ((args as unknown as Record<string, unknown>)._ as string[]) ?? []\n\n launchChild(\n {\n kind: \"codex\",\n envVars,\n extraArgs,\n model: codexModel,\n serverUrl,\n },\n server,\n )\n },\n})\n"],"mappings":";;;;;;;;;AA6BA,MAAa,QAAQ,cAAc;CACjC,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM;EACJ,GAAG;EACH,OAAO;GACL,OAAO;GACP,MAAM;GACN,aAAa;EACf;CACF;CACA,MAAM,IAAI,EAAE,QAAQ;EAClB,IAAI,CAAC,QAAQ,OAAO,OAAO;GACzB,QAAQ,MAAM,6DAA6D;GAC3E,QAAQ,KAAK,CAAC;EAChB;EAEA,MAAM,SAAS,gBAAgB,IAA0C;EAEzE,IAAI;EACJ,IAAI;EACJ,IAAI;GACF,MAAM,SAAS,MAAM,cAAc;IACjC,GAAG;IACH,MAAM,OAAO;IACb,QAAQ;GACV,CAAC;GACD,SAAS,OAAO;GAChB,YAAY,OAAO;EACrB,SAAS,OAAO;GACd,QAAQ,MAAM,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,KAAK;GACvF,QAAQ,KAAK,CAAC;EAChB;EAGA,cAAmB,EAAE,YAAY,KAAK,mBAAmB,MAAM,CAAC;EAIhE,IAAI,gBAAgB,GAClB,kBAAuB,CAAC,CAAC,YAAY,CAAC,CAAC;EAMzC,yBAA8B;EAI9B,uBAA4B,KAAA,GAAW,EAAE,YAAY,KAAK,CAAC,CAAC,CACzD,MAAM,YAAY;GACjB,IAAI,SAAS,QAAQ,OAAO,MAAM,GAAG,QAAQ,GAAG;EAClD,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;EAIjB,mBAAwB;EAKxB,eAAe;EASf,KADE,MAAM,iBAAiB,QAAQ,IAAI,4BAA4B,QAC9C,6BAA6B,GAC9C,uBAA4B,CAAC,CAAC,OAAO,QACnC,QAAQ,MAAM,0CAA0C,GAAG,CAC7D;EAGF,MAAM,eAAe,CAAC,KAAK;EAC3B,MAAM,iBAAiB,KAAK,SAAA;EAI5B,kBAAkB;EAElB,IAAI,aAAa,kBAAkB,cAAc;EACjD,IAAI,eAAe,gBACjB,QAAQ,KAAK,UAAU,eAAe,iBAAiB,WAAW,EAAE;EAWtE,IAAI,gBAAgB,MAAM,QAAQ;GAChC,MAAM,WAAW,OACf,MAAM,QAAQ,KAAK,MAAM,MAAM,EAAE,OAAO,EAAE,KAAK;GACjD,MAAM,eAAe,CAAC,qBAAqB,GAAG,6BAA6B,CAAC,CACzE,KAAK,OAAO,aAAa,EAAE,CAAC,CAAC,CAC7B,MAAM,OAAO,QAAQ,EAAE,CAAC;GAC3B,IAAI,cAAc;IAChB,IAAI,iBAAiB,YACnB,QAAQ,KACN,kBAAkB,oBAAoB,qDAAqD,aAAa,GAC1G;IAEF,aAAa;GACf;EACF;EAGA,MAAM,aAAa,MAAM,QAAQ,KAAK,MAAM,MAAM,EAAE,OAAO,UAAU;EACrE,IAAI,CAAC,YAAY;GACf,MAAM,YAAY,sBAAsB,YAAY;GACpD,QAAQ,KACN,UAAU,WAAW,uCAAuC,UAAU,KAAK,IAAI,GACjF;EACF,OAAO;GACL,MAAM,MAAM,WAAW,cAAc,QAAQ;GAC7C,IAAI,KAAK,QAAQ,KAAK,yBAAyB,IAAI,eAAe,EAAE,QAAQ;EAC9E;EAGA,QAAQ,OAAO,MAAM,mBAAmB,UAAU,yBAAyB,WAAW,OAAO;EAE7F,MAAM,UAAU,gBAAgB,SAAS;EACzC,MAAM,YAAc,KAA4C,KAAkB,CAAC;EAEnF,YACE;GACE,MAAM;GACN;GACA;GACA,OAAO;GACP;EACF,GACA,MACF;CACF;AACF,CAAC"}
1
+ {"version":3,"file":"codex-DAnu246m.js","names":[],"sources":["../src/codex.ts"],"sourcesContent":["import process from \"node:process\"\n\nimport { defineCommand } from \"citty\"\nimport consola from \"consola\"\n\nimport { enableFileLogging } from \"./lib/file-log-reporter\"\nimport { launchChild } from \"./lib/launch\"\nimport { listModelsForEndpoint } from \"./lib/model-validation\"\nimport {\n DEFAULT_CODEX_MODEL,\n DEFAULT_CODEX_MODEL_FALLBACKS,\n} from \"./lib/port\"\nimport {\n getCodexEnvVars,\n parseSharedArgs,\n setupAndServe,\n sharedServerArgs,\n} from \"./lib/server-setup\"\nimport { runSelfUpdate } from \"./lib/self-update\"\nimport { state } from \"./lib/state\"\nimport { toolbeltEnabled } from \"./lib/toolbelt\"\nimport { provisionToolbelt } from \"./lib/toolbelt/provision\"\nimport { colbertDegradedWarning, provisionAndIndexColbert } from \"./lib/colbert\"\nimport { startKeepAwake } from \"./lib/keep-awake\"\nimport { warmTreeSitterPool } from \"./lib/tree-sitter-pool/pool\"\nimport { provisionBrowserAssets } from \"./lib/browser-mcp/provision\"\nimport { hasSupportedBrowserInstalled } from \"./lib/browser-mcp/browser-detect\"\nimport { resolveCodexModel, resolveModel } from \"./lib/utils\"\n\nexport const codex = defineCommand({\n meta: {\n name: \"codex\",\n description: \"Start the proxy server and launch Codex CLI\",\n },\n args: {\n ...sharedServerArgs,\n model: {\n alias: \"m\",\n type: \"string\",\n description: \"Override the default model for Codex CLI\",\n },\n },\n async run({ args }) {\n if (!process.stdout.isTTY) {\n consola.error(\"The codex subcommand requires a TTY (interactive terminal).\")\n process.exit(1)\n }\n\n const parsed = parseSharedArgs(args as unknown as Record<string, unknown>)\n\n let server: Awaited<ReturnType<typeof setupAndServe>>[\"server\"]\n let serverUrl: string\n try {\n const result = await setupAndServe({\n ...parsed,\n port: parsed.port, // undefined = random port\n silent: true,\n })\n server = result.server\n serverUrl = result.serverUrl\n } catch (error) {\n consola.error(\"Failed to start server:\", error instanceof Error ? error.message : error)\n process.exit(1)\n }\n\n // Best-effort self-update (detached, applies next launch).\n void runSelfUpdate({ selfUpdate: args[\"self-update\"] !== false })\n\n // Materialize the LLM toolbelt in the background (PATH prepend is in\n // getCodexEnvVars). Best-effort; never blocks launch.\n if (toolbeltEnabled()) {\n void provisionToolbelt().catch(() => {})\n }\n\n // Best-effort ColBERT semantic-search provision + background index of\n // the launch cwd. Opt-IN via --search (no-op otherwise); never blocks\n // launch, never throws.\n void provisionAndIndexColbert()\n\n // Surface a terminally-failed semantic index to the HUMAN (see the note\n // in claude.ts). Fire-and-forget; lexical search still works.\n void colbertDegradedWarning(undefined, { logsToFile: true })\n .then((warning) => {\n if (warning) process.stderr.write(`${warning}\\n`)\n })\n .catch(() => {})\n\n // Best-effort, bounded launch warm-up: ready one tree-sitter worker.\n // Opt out with GH_ROUTER_DISABLE_TS_POOL_WARMUP=1.\n void warmTreeSitterPool()\n\n // Best-effort: keep the machine awake while the proxy/Codex session\n // runs (win32 default-on; opt out GH_ROUTER_DISABLE_KEEP_AWAKE=1).\n // Self-registered SIGINT/SIGTERM/exit reaper releases the assertion.\n startKeepAwake()\n\n // Best-effort: materialize the browser extension + bridge into the\n // stable app-dir and stamp the running version. Gated inline (browse\n // opt-in + a supported browser) rather than via browserToolsEnabled()\n // so the codex command path doesn't eagerly pull the compressor /\n // worker-agent graph. Never blocks launch, never throws.\n const browseOptIn =\n state.browseEnabled || process.env.GH_ROUTER_ENABLE_BROWSE === \"1\"\n if (browseOptIn && hasSupportedBrowserInstalled()) {\n void provisionBrowserAssets().catch((err) =>\n consola.debug(\"Browser extension provisioning failed:\", err),\n )\n }\n\n const usingDefault = !args.model\n const requestedModel = args.model ?? DEFAULT_CODEX_MODEL\n\n // Resolve model before printing success message (so we show the actual model)\n // but enable file logging first so resolution warnings go to file, not terminal\n enableFileLogging()\n\n let codexModel = resolveCodexModel(requestedModel)\n if (codexModel !== requestedModel) {\n consola.info(`Model \"${requestedModel}\" resolved to \"${codexModel}\"`)\n }\n\n // For the implicit-default path only: honor the explicit fallback order\n // (DEFAULT_CODEX_MODEL, then DEFAULT_CODEX_MODEL_FALLBACKS led by gpt-5.5)\n // by cache presence BEFORE resolveCodexModel's codex-slug-preferring\n // \"best /responses model\" safety net. `resolveModel` (NOT resolveCodexModel)\n // walks the chain, so the codex-slug preference can't shadow an\n // earlier-in-chain named fallback (e.g. gpt-5.5) that IS present. The\n // resolveCodexModel result above stays as the FINAL safety net, used only\n // when none of the named chain entries is in the catalog.\n if (usingDefault && state.models) {\n const inCache = (id: string) =>\n state.models?.data.some((m) => m.id === id) ?? false\n const firstPresent = [DEFAULT_CODEX_MODEL, ...DEFAULT_CODEX_MODEL_FALLBACKS]\n .map((id) => resolveModel(id))\n .find((id) => inCache(id))\n if (firstPresent) {\n if (firstPresent !== codexModel) {\n consola.info(\n `Default model \"${DEFAULT_CODEX_MODEL}\" not in your Copilot model list; falling back to \"${firstPresent}\".`,\n )\n }\n codexModel = firstPresent\n }\n }\n\n // Validate model exists in Copilot model list\n const modelEntry = state.models?.data.find((m) => m.id === codexModel)\n if (!modelEntry) {\n const available = listModelsForEndpoint(\"/responses\")\n consola.warn(\n `Model \"${codexModel}\" not found. Available codex models: ${available.join(\", \")}`,\n )\n } else {\n const ctx = modelEntry.capabilities?.limits?.max_context_window_tokens\n if (ctx) consola.info(`Model context window: ${ctx.toLocaleString()} tokens`)\n }\n\n // Print to stderr directly — consola's terminal reporter is already gone\n process.stderr.write(`Server ready on ${serverUrl}, launching Codex CLI (${codexModel})...\\n`)\n\n const envVars = getCodexEnvVars(serverUrl)\n const extraArgs = ((args as unknown as Record<string, unknown>)._ as string[]) ?? []\n\n launchChild(\n {\n kind: \"codex\",\n envVars,\n extraArgs,\n model: codexModel,\n serverUrl,\n },\n server,\n )\n },\n})\n"],"mappings":";;;;;;;;;AA6BA,MAAa,QAAQ,cAAc;CACjC,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM;EACJ,GAAG;EACH,OAAO;GACL,OAAO;GACP,MAAM;GACN,aAAa;EACf;CACF;CACA,MAAM,IAAI,EAAE,QAAQ;EAClB,IAAI,CAAC,QAAQ,OAAO,OAAO;GACzB,QAAQ,MAAM,6DAA6D;GAC3E,QAAQ,KAAK,CAAC;EAChB;EAEA,MAAM,SAAS,gBAAgB,IAA0C;EAEzE,IAAI;EACJ,IAAI;EACJ,IAAI;GACF,MAAM,SAAS,MAAM,cAAc;IACjC,GAAG;IACH,MAAM,OAAO;IACb,QAAQ;GACV,CAAC;GACD,SAAS,OAAO;GAChB,YAAY,OAAO;EACrB,SAAS,OAAO;GACd,QAAQ,MAAM,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,KAAK;GACvF,QAAQ,KAAK,CAAC;EAChB;EAGA,cAAmB,EAAE,YAAY,KAAK,mBAAmB,MAAM,CAAC;EAIhE,IAAI,gBAAgB,GAClB,kBAAuB,CAAC,CAAC,YAAY,CAAC,CAAC;EAMzC,yBAA8B;EAI9B,uBAA4B,KAAA,GAAW,EAAE,YAAY,KAAK,CAAC,CAAC,CACzD,MAAM,YAAY;GACjB,IAAI,SAAS,QAAQ,OAAO,MAAM,GAAG,QAAQ,GAAG;EAClD,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;EAIjB,mBAAwB;EAKxB,eAAe;EASf,KADE,MAAM,iBAAiB,QAAQ,IAAI,4BAA4B,QAC9C,6BAA6B,GAC9C,uBAA4B,CAAC,CAAC,OAAO,QACnC,QAAQ,MAAM,0CAA0C,GAAG,CAC7D;EAGF,MAAM,eAAe,CAAC,KAAK;EAC3B,MAAM,iBAAiB,KAAK,SAAA;EAI5B,kBAAkB;EAElB,IAAI,aAAa,kBAAkB,cAAc;EACjD,IAAI,eAAe,gBACjB,QAAQ,KAAK,UAAU,eAAe,iBAAiB,WAAW,EAAE;EAWtE,IAAI,gBAAgB,MAAM,QAAQ;GAChC,MAAM,WAAW,OACf,MAAM,QAAQ,KAAK,MAAM,MAAM,EAAE,OAAO,EAAE,KAAK;GACjD,MAAM,eAAe,CAAC,qBAAqB,GAAG,6BAA6B,CAAC,CACzE,KAAK,OAAO,aAAa,EAAE,CAAC,CAAC,CAC7B,MAAM,OAAO,QAAQ,EAAE,CAAC;GAC3B,IAAI,cAAc;IAChB,IAAI,iBAAiB,YACnB,QAAQ,KACN,kBAAkB,oBAAoB,qDAAqD,aAAa,GAC1G;IAEF,aAAa;GACf;EACF;EAGA,MAAM,aAAa,MAAM,QAAQ,KAAK,MAAM,MAAM,EAAE,OAAO,UAAU;EACrE,IAAI,CAAC,YAAY;GACf,MAAM,YAAY,sBAAsB,YAAY;GACpD,QAAQ,KACN,UAAU,WAAW,uCAAuC,UAAU,KAAK,IAAI,GACjF;EACF,OAAO;GACL,MAAM,MAAM,WAAW,cAAc,QAAQ;GAC7C,IAAI,KAAK,QAAQ,KAAK,yBAAyB,IAAI,eAAe,EAAE,QAAQ;EAC9E;EAGA,QAAQ,OAAO,MAAM,mBAAmB,UAAU,yBAAyB,WAAW,OAAO;EAE7F,MAAM,UAAU,gBAAgB,SAAS;EACzC,MAAM,YAAc,KAA4C,KAAkB,CAAC;EAEnF,YACE;GACE,MAAM;GACN;GACA;GACA,OAAO;GACP;EACF,GACA,MACF;CACF;AACF,CAAC"}
package/dist/hooks.mjs CHANGED
@@ -37942,6 +37942,32 @@ var init_worker_dispatch = __esmMin((() => {
37942
37942
  BROWSE_WORKER_MODE = "browse";
37943
37943
  ALL_WORKER_DISPATCH_MODES = [...CORE_WORKER_MODES, BROWSE_WORKER_MODE];
37944
37944
  ALL_WORKER_DISPATCH_MODES.map(dispatcherAgentName);
37945
+ Object.freeze({
37946
+ "gather-context-explore": Object.freeze({
37947
+ dispatcher: "explore",
37948
+ modelAlias: "gh-router-skill-gather-context-explore-high",
37949
+ timeoutMs: 18e4,
37950
+ worktree: false
37951
+ }),
37952
+ "implement-task": Object.freeze({
37953
+ dispatcher: "implement",
37954
+ modelAlias: "gh-router-skill-implement-task-max",
37955
+ timeoutMs: 6e5,
37956
+ worktree: true
37957
+ }),
37958
+ "review-pass1": Object.freeze({
37959
+ dispatcher: "review",
37960
+ modelAlias: "gh-router-skill-review-pass1-max",
37961
+ timeoutMs: 3e5,
37962
+ worktree: false
37963
+ }),
37964
+ "review-pass2": Object.freeze({
37965
+ dispatcher: "review",
37966
+ modelAlias: "gh-router-skill-review-pass2-medium",
37967
+ timeoutMs: 3e5,
37968
+ worktree: false
37969
+ })
37970
+ });
37945
37971
  }));
37946
37972
  //#endregion
37947
37973
  //#region src/lib/first-mate/operator-shaping.ts
package/dist/hooks.sha256 CHANGED
@@ -1 +1 @@
1
- b036d6c5927a94f0be3d0ad0a5fa85cb3d87057fa335476543603a78a9fa4da4
1
+ 0c41af7b6fd0be72727a561b08419facca3e73627faa6696bbd196143045fb97
@@ -1,5 +1,5 @@
1
1
  import { t as buildSelfCommand } from "./self-invocation-opSXHEs0.js";
2
- import { a as dispatcherAgentName, t as ALL_WORKER_DISPATCH_MODES } from "./worker-dispatch-DwS99DXz.js";
2
+ import { a as dispatcherAgentName, t as ALL_WORKER_DISPATCH_MODES } from "./worker-dispatch-CcQygiAA.js";
3
3
  import { defineCommand } from "citty";
4
4
  import { readFileSync } from "node:fs";
5
5
  //#region src/lib/first-mate/operator-shaping.ts
@@ -124,4 +124,4 @@ function buildFirstMateGuardHookCommand(invocation) {
124
124
  //#endregion
125
125
  export { assertShapingInstalled as i, buildFirstMateGuardHookCommand as n, internalFirstMateGuard as r, FIRST_MATE_GUARD_MATCHER as t };
126
126
 
127
- //# sourceMappingURL=internal-first-mate-guard-mvfZal_M.js.map
127
+ //# sourceMappingURL=internal-first-mate-guard-Cj_g7RFr.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal-first-mate-guard-mvfZal_M.js","names":[],"sources":["../src/lib/first-mate/operator-shaping.ts","../src/internal-first-mate-guard.ts"],"sourcesContent":["/**\n * Operator-mode steering for github-router `--agents` sessions.\n *\n * In first-mate/operator mode the spawned Claude is the cloud-agent operator, not\n * the product implementer. Product implementation is steered to GitHub cloud\n * agents by first-mate guidance and the gh-first-mate skill. This module no\n * longer hard-blocks local file writes or shell commands: Edit/Write/NotebookEdit\n * and Bash remain available as escape hatches when needed.\n *\n * The only enforced main-operator boundary is that local worker/orchestrate MCP\n * tools stay subagent-only. The main operator should invoke the worker-* Agent\n * subagents or delegate to GitHub cloud agents rather than calling\n * `mcp__workers__*` / `mcp__orchestrate__*` directly.\n */\n\nimport {\n ALL_WORKER_DISPATCH_MODES,\n dispatcherAgentName,\n type WorkerDispatchMode,\n} from \"../worker-dispatch\"\n\n/** Tools denied to the main operator by exact name. */\nexport const OPERATOR_DENIED_TOOLS = [] as const\n\n/** MCP prefixes denied to the main operator; these remain subagent-only. */\nexport const OPERATOR_DENIED_MCP_PREFIXES = [\"mcp__workers__\", \"mcp__orchestrate__\"] as const\n\n/** Tools explicitly preserved (documented; used by assertion tests). */\nexport const OPERATOR_KEPT_TOOLS = [\n \"Agent\",\n \"Task\",\n \"Edit\",\n \"Write\",\n \"NotebookEdit\",\n \"Bash\",\n \"Read\",\n \"Grep\",\n \"Glob\",\n \"mcp__first-mate__\",\n] as const\n\n/**\n * Least-privilege note for what the cloud agents themselves may touch — the\n * operator scopes missions to specific repos and forbids irreversible actions\n * without human approval (see first-mate house rules). This constant documents\n * the intent for the launcher/README; enforcement of the cloud-agent scope is\n * the GitHub agent-token scope (repo/workflow) + the mission house_rules.\n */\nexport const CLOUD_AGENT_SCOPE_NOTE =\n \"Cloud agents operate only within mission-listed repos; merges, releases, \" +\n \"Pages, and deletes require explicit human approval (first-mate merge gate).\"\n\nexport interface OperatorToolInput extends Record<string, unknown> {\n agent_type?: unknown\n}\n\nexport interface PreToolUseDecision {\n block: boolean\n reason?: string\n}\n\n/**\n * Decide whether a tool call must be blocked for the main operator. Pure — used\n * both by the PreToolUse hook handler and by config-assertion tests. When\n * operator mode is off, nothing is blocked (normal sessions unaffected).\n */\nfunction parseWorkerMode(toolName: string): WorkerDispatchMode | null {\n const workersPrefix = \"mcp__workers__\"\n if (!toolName.startsWith(workersPrefix)) return null\n const mode = toolName.slice(workersPrefix.length)\n return (ALL_WORKER_DISPATCH_MODES as ReadonlyArray<string>).includes(mode) ? (mode as WorkerDispatchMode) : null\n}\n\nfunction isMatchingWorkerDispatcher(toolName: string, input?: OperatorToolInput): boolean {\n const mode = parseWorkerMode(toolName)\n if (mode === null) return false\n return input?.agent_type === dispatcherAgentName(mode)\n}\n\nexport function shouldDenyOperatorTool(\n toolName: string,\n operatorMode: boolean,\n input?: OperatorToolInput,\n): boolean {\n if (!operatorMode) return false\n if (isMatchingWorkerDispatcher(toolName, input)) return false\n return OPERATOR_DENIED_MCP_PREFIXES.some((prefix) => toolName.startsWith(prefix))\n}\n\n/**\n * M4 — fail-CLOSED. If operator/`--agents` mode is active but the reduced\n * worker/orchestrate guard could NOT be installed (e.g. settings.json unwritable),\n * the operator session must NOT start with direct main-thread worker/orchestrate\n * MCP calls available. Non-agents sessions are never affected.\n */\nexport function assertShapingInstalled(agentsMode: boolean, injectionSucceeded: boolean): void {\n if (agentsMode && !injectionSucceeded) {\n throw new Error(\n \"cloud-agent operator mode requires the worker/orchestrate PreToolUse hook, \" +\n \"but it could not be installed — refusing to start an unguarded operator session.\",\n )\n }\n}\n\n/**\n * The PreToolUse hook decision for a given tool name in operator mode.\n *\n * Bash and file-authoring tools are always allowed. Only direct main-operator\n * calls to local worker/orchestrate MCP tools are blocked so those backends stay\n * reachable through the worker-* Agent subagents rather than the lead context.\n */\nexport function operatorPreToolUse(\n toolName: string,\n operatorMode: boolean,\n input?: OperatorToolInput,\n): PreToolUseDecision {\n if (!operatorMode) return { block: false }\n if (shouldDenyOperatorTool(toolName, operatorMode, input)) {\n return {\n block: true,\n reason: `${toolName} is subagent-only in cloud-agent operator mode — use the worker-* Agent subagents or delegate implementation to a GitHub cloud agent via the first-mate MCP instead of calling local worker/orchestrate MCP tools from the main operator.`,\n }\n }\n return { block: false }\n}\n","/**\n * The internal `internal-first-mate-guard` subcommand: a PreToolUse hook that\n * keeps local worker/orchestrate MCP tools subagent-only in cloud-agent OPERATOR\n * mode. It is injected into the spawned Claude session's settings ONLY in\n * `--agents`/operator mode, with a matcher scoped to those MCP tool prefixes.\n *\n * Reads the PreToolUse payload from stdin (`{tool_name, tool_input, ...}`) and,\n * if the tool is denied in operator mode, blocks via exit code 2 with a reason\n * on stderr (the repo's hook convention). Bash and file-authoring tools are not\n * matched by this guard and are not blocked.\n */\nimport { defineCommand } from \"citty\"\n\nimport { readFileSync } from \"node:fs\"\n\nimport { operatorPreToolUse, type OperatorToolInput } from \"./lib/first-mate/operator-shaping\"\nimport { buildSelfCommand, type SelfInvocation } from \"./lib/hook-launcher/self-invocation\"\n\nfunction readStdinSync(): string {\n try {\n return readFileSync(0, \"utf8\")\n } catch {\n return \"\"\n }\n}\n\nexport const internalFirstMateGuard = defineCommand({\n meta: {\n name: \"internal-first-mate-guard\",\n description: \"PreToolUse guard enforcing cloud-agent operator capability shaping.\",\n },\n run() {\n let toolName = \"\"\n let hookInput: OperatorToolInput | undefined\n let parsed: boolean\n try {\n const payload = JSON.parse(readStdinSync()) as {\n tool_name?: unknown\n tool_input?: unknown\n agent_type?: unknown\n }\n if (typeof payload.tool_name === \"string\") toolName = payload.tool_name\n if (typeof payload.agent_type === \"string\") hookInput = { agent_type: payload.agent_type }\n parsed = true\n } catch {\n parsed = false // fail-closed below for a named-but-unparseable payload\n }\n if (toolName.length === 0) {\n // Nothing to guard (empty/absent tool name) → allow. But if the payload\n // did not even parse we cannot know it was empty; the matcher only routes\n // the denied tools here, so a parse failure means one of THOSE arrived\n // unreadable → fail-closed.\n if (!parsed) {\n process.stderr.write(\"operator guard: unparseable PreToolUse payload — blocking (fail-closed)\")\n process.exit(2)\n }\n process.exit(0)\n }\n // This hook is only injected in operator mode, so operatorMode = true.\n const decision = operatorPreToolUse(toolName, true, hookInput)\n if (decision.block) {\n process.stderr.write(decision.reason ?? `${toolName} is disabled in operator mode`)\n process.exit(2) // exit 2 blocks the tool call (Claude Code hook convention)\n }\n process.exit(0)\n },\n})\n\n/** The regex matcher scoping the guard hook to exactly the denied tools. */\nexport const FIRST_MATE_GUARD_MATCHER = \"mcp__workers__.*|mcp__orchestrate__.*\"\n\n/** Build the hook command string that runs this subcommand. */\nexport function buildFirstMateGuardHookCommand(invocation: SelfInvocation): string {\n return buildSelfCommand(invocation, \"internal-first-mate-guard\")\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,+BAA+B,CAAC,kBAAkB,oBAAoB;;;;;;AAyCnF,SAAS,gBAAgB,UAA6C;CAEpE,IAAI,CAAC,SAAS,WAAW,gBAAa,GAAG,OAAO;CAChD,MAAM,OAAO,SAAS,MAAM,EAAoB;CAChD,OAAQ,0BAAoD,SAAS,IAAI,IAAK,OAA8B;AAC9G;AAEA,SAAS,2BAA2B,UAAkB,OAAoC;CACxF,MAAM,OAAO,gBAAgB,QAAQ;CACrC,IAAI,SAAS,MAAM,OAAO;CAC1B,OAAO,OAAO,eAAe,oBAAoB,IAAI;AACvD;AAEA,SAAgB,uBACd,UACA,cACA,OACS;CACT,IAAI,CAAC,cAAc,OAAO;CAC1B,IAAI,2BAA2B,UAAU,KAAK,GAAG,OAAO;CACxD,OAAO,6BAA6B,MAAM,WAAW,SAAS,WAAW,MAAM,CAAC;AAClF;;;;;;;AAQA,SAAgB,uBAAuB,YAAqB,oBAAmC;CAC7F,IAAI,cAAc,CAAC,oBACjB,MAAM,IAAI,MACR,6JAEF;AAEJ;;;;;;;;AASA,SAAgB,mBACd,UACA,cACA,OACoB;CACpB,IAAI,CAAC,cAAc,OAAO,EAAE,OAAO,MAAM;CACzC,IAAI,uBAAuB,UAAU,cAAc,KAAK,GACtD,OAAO;EACL,OAAO;EACP,QAAQ,GAAG,SAAS;CACtB;CAEF,OAAO,EAAE,OAAO,MAAM;AACxB;;;;;;;;;;;;;;AC1GA,SAAS,gBAAwB;CAC/B,IAAI;EACF,OAAO,aAAa,GAAG,MAAM;CAC/B,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,yBAAyB,cAAc;CAClD,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM;EACJ,IAAI,WAAW;EACf,IAAI;EACJ,IAAI;EACJ,IAAI;GACF,MAAM,UAAU,KAAK,MAAM,cAAc,CAAC;GAK1C,IAAI,OAAO,QAAQ,cAAc,UAAU,WAAW,QAAQ;GAC9D,IAAI,OAAO,QAAQ,eAAe,UAAU,YAAY,EAAE,YAAY,QAAQ,WAAW;GACzF,SAAS;EACX,QAAQ;GACN,SAAS;EACX;EACA,IAAI,SAAS,WAAW,GAAG;GAKzB,IAAI,CAAC,QAAQ;IACX,QAAQ,OAAO,MAAM,yEAAyE;IAC9F,QAAQ,KAAK,CAAC;GAChB;GACA,QAAQ,KAAK,CAAC;EAChB;EAEA,MAAM,WAAW,mBAAmB,UAAU,MAAM,SAAS;EAC7D,IAAI,SAAS,OAAO;GAClB,QAAQ,OAAO,MAAM,SAAS,UAAU,GAAG,SAAS,8BAA8B;GAClF,QAAQ,KAAK,CAAC;EAChB;EACA,QAAQ,KAAK,CAAC;CAChB;AACF,CAAC;;AAGD,MAAa,2BAA2B;;AAGxC,SAAgB,+BAA+B,YAAoC;CACjF,OAAO,iBAAiB,YAAY,2BAA2B;AACjE"}
1
+ {"version":3,"file":"internal-first-mate-guard-Cj_g7RFr.js","names":[],"sources":["../src/lib/first-mate/operator-shaping.ts","../src/internal-first-mate-guard.ts"],"sourcesContent":["/**\n * Operator-mode steering for github-router `--agents` sessions.\n *\n * In first-mate/operator mode the spawned Claude is the cloud-agent operator, not\n * the product implementer. Product implementation is steered to GitHub cloud\n * agents by first-mate guidance and the gh-first-mate skill. This module no\n * longer hard-blocks local file writes or shell commands: Edit/Write/NotebookEdit\n * and Bash remain available as escape hatches when needed.\n *\n * The only enforced main-operator boundary is that local worker/orchestrate MCP\n * tools stay subagent-only. The main operator should invoke the worker-* Agent\n * subagents or delegate to GitHub cloud agents rather than calling\n * `mcp__workers__*` / `mcp__orchestrate__*` directly.\n */\n\nimport {\n ALL_WORKER_DISPATCH_MODES,\n dispatcherAgentName,\n type WorkerDispatchMode,\n} from \"../worker-dispatch\"\n\n/** Tools denied to the main operator by exact name. */\nexport const OPERATOR_DENIED_TOOLS = [] as const\n\n/** MCP prefixes denied to the main operator; these remain subagent-only. */\nexport const OPERATOR_DENIED_MCP_PREFIXES = [\"mcp__workers__\", \"mcp__orchestrate__\"] as const\n\n/** Tools explicitly preserved (documented; used by assertion tests). */\nexport const OPERATOR_KEPT_TOOLS = [\n \"Agent\",\n \"Task\",\n \"Edit\",\n \"Write\",\n \"NotebookEdit\",\n \"Bash\",\n \"Read\",\n \"Grep\",\n \"Glob\",\n \"mcp__first-mate__\",\n] as const\n\n/**\n * Least-privilege note for what the cloud agents themselves may touch — the\n * operator scopes missions to specific repos and forbids irreversible actions\n * without human approval (see first-mate house rules). This constant documents\n * the intent for the launcher/README; enforcement of the cloud-agent scope is\n * the GitHub agent-token scope (repo/workflow) + the mission house_rules.\n */\nexport const CLOUD_AGENT_SCOPE_NOTE =\n \"Cloud agents operate only within mission-listed repos; merges, releases, \" +\n \"Pages, and deletes require explicit human approval (first-mate merge gate).\"\n\nexport interface OperatorToolInput extends Record<string, unknown> {\n agent_type?: unknown\n}\n\nexport interface PreToolUseDecision {\n block: boolean\n reason?: string\n}\n\n/**\n * Decide whether a tool call must be blocked for the main operator. Pure — used\n * both by the PreToolUse hook handler and by config-assertion tests. When\n * operator mode is off, nothing is blocked (normal sessions unaffected).\n */\nfunction parseWorkerMode(toolName: string): WorkerDispatchMode | null {\n const workersPrefix = \"mcp__workers__\"\n if (!toolName.startsWith(workersPrefix)) return null\n const mode = toolName.slice(workersPrefix.length)\n return (ALL_WORKER_DISPATCH_MODES as ReadonlyArray<string>).includes(mode) ? (mode as WorkerDispatchMode) : null\n}\n\nfunction isMatchingWorkerDispatcher(toolName: string, input?: OperatorToolInput): boolean {\n const mode = parseWorkerMode(toolName)\n if (mode === null) return false\n return input?.agent_type === dispatcherAgentName(mode)\n}\n\nexport function shouldDenyOperatorTool(\n toolName: string,\n operatorMode: boolean,\n input?: OperatorToolInput,\n): boolean {\n if (!operatorMode) return false\n if (isMatchingWorkerDispatcher(toolName, input)) return false\n return OPERATOR_DENIED_MCP_PREFIXES.some((prefix) => toolName.startsWith(prefix))\n}\n\n/**\n * M4 — fail-CLOSED. If operator/`--agents` mode is active but the reduced\n * worker/orchestrate guard could NOT be installed (e.g. settings.json unwritable),\n * the operator session must NOT start with direct main-thread worker/orchestrate\n * MCP calls available. Non-agents sessions are never affected.\n */\nexport function assertShapingInstalled(agentsMode: boolean, injectionSucceeded: boolean): void {\n if (agentsMode && !injectionSucceeded) {\n throw new Error(\n \"cloud-agent operator mode requires the worker/orchestrate PreToolUse hook, \" +\n \"but it could not be installed — refusing to start an unguarded operator session.\",\n )\n }\n}\n\n/**\n * The PreToolUse hook decision for a given tool name in operator mode.\n *\n * Bash and file-authoring tools are always allowed. Only direct main-operator\n * calls to local worker/orchestrate MCP tools are blocked so those backends stay\n * reachable through the worker-* Agent subagents rather than the lead context.\n */\nexport function operatorPreToolUse(\n toolName: string,\n operatorMode: boolean,\n input?: OperatorToolInput,\n): PreToolUseDecision {\n if (!operatorMode) return { block: false }\n if (shouldDenyOperatorTool(toolName, operatorMode, input)) {\n return {\n block: true,\n reason: `${toolName} is subagent-only in cloud-agent operator mode — use the worker-* Agent subagents or delegate implementation to a GitHub cloud agent via the first-mate MCP instead of calling local worker/orchestrate MCP tools from the main operator.`,\n }\n }\n return { block: false }\n}\n","/**\n * The internal `internal-first-mate-guard` subcommand: a PreToolUse hook that\n * keeps local worker/orchestrate MCP tools subagent-only in cloud-agent OPERATOR\n * mode. It is injected into the spawned Claude session's settings ONLY in\n * `--agents`/operator mode, with a matcher scoped to those MCP tool prefixes.\n *\n * Reads the PreToolUse payload from stdin (`{tool_name, tool_input, ...}`) and,\n * if the tool is denied in operator mode, blocks via exit code 2 with a reason\n * on stderr (the repo's hook convention). Bash and file-authoring tools are not\n * matched by this guard and are not blocked.\n */\nimport { defineCommand } from \"citty\"\n\nimport { readFileSync } from \"node:fs\"\n\nimport { operatorPreToolUse, type OperatorToolInput } from \"./lib/first-mate/operator-shaping\"\nimport { buildSelfCommand, type SelfInvocation } from \"./lib/hook-launcher/self-invocation\"\n\nfunction readStdinSync(): string {\n try {\n return readFileSync(0, \"utf8\")\n } catch {\n return \"\"\n }\n}\n\nexport const internalFirstMateGuard = defineCommand({\n meta: {\n name: \"internal-first-mate-guard\",\n description: \"PreToolUse guard enforcing cloud-agent operator capability shaping.\",\n },\n run() {\n let toolName = \"\"\n let hookInput: OperatorToolInput | undefined\n let parsed: boolean\n try {\n const payload = JSON.parse(readStdinSync()) as {\n tool_name?: unknown\n tool_input?: unknown\n agent_type?: unknown\n }\n if (typeof payload.tool_name === \"string\") toolName = payload.tool_name\n if (typeof payload.agent_type === \"string\") hookInput = { agent_type: payload.agent_type }\n parsed = true\n } catch {\n parsed = false // fail-closed below for a named-but-unparseable payload\n }\n if (toolName.length === 0) {\n // Nothing to guard (empty/absent tool name) → allow. But if the payload\n // did not even parse we cannot know it was empty; the matcher only routes\n // the denied tools here, so a parse failure means one of THOSE arrived\n // unreadable → fail-closed.\n if (!parsed) {\n process.stderr.write(\"operator guard: unparseable PreToolUse payload — blocking (fail-closed)\")\n process.exit(2)\n }\n process.exit(0)\n }\n // This hook is only injected in operator mode, so operatorMode = true.\n const decision = operatorPreToolUse(toolName, true, hookInput)\n if (decision.block) {\n process.stderr.write(decision.reason ?? `${toolName} is disabled in operator mode`)\n process.exit(2) // exit 2 blocks the tool call (Claude Code hook convention)\n }\n process.exit(0)\n },\n})\n\n/** The regex matcher scoping the guard hook to exactly the denied tools. */\nexport const FIRST_MATE_GUARD_MATCHER = \"mcp__workers__.*|mcp__orchestrate__.*\"\n\n/** Build the hook command string that runs this subcommand. */\nexport function buildFirstMateGuardHookCommand(invocation: SelfInvocation): string {\n return buildSelfCommand(invocation, \"internal-first-mate-guard\")\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,+BAA+B,CAAC,kBAAkB,oBAAoB;;;;;;AAyCnF,SAAS,gBAAgB,UAA6C;CAEpE,IAAI,CAAC,SAAS,WAAW,gBAAa,GAAG,OAAO;CAChD,MAAM,OAAO,SAAS,MAAM,EAAoB;CAChD,OAAQ,0BAAoD,SAAS,IAAI,IAAK,OAA8B;AAC9G;AAEA,SAAS,2BAA2B,UAAkB,OAAoC;CACxF,MAAM,OAAO,gBAAgB,QAAQ;CACrC,IAAI,SAAS,MAAM,OAAO;CAC1B,OAAO,OAAO,eAAe,oBAAoB,IAAI;AACvD;AAEA,SAAgB,uBACd,UACA,cACA,OACS;CACT,IAAI,CAAC,cAAc,OAAO;CAC1B,IAAI,2BAA2B,UAAU,KAAK,GAAG,OAAO;CACxD,OAAO,6BAA6B,MAAM,WAAW,SAAS,WAAW,MAAM,CAAC;AAClF;;;;;;;AAQA,SAAgB,uBAAuB,YAAqB,oBAAmC;CAC7F,IAAI,cAAc,CAAC,oBACjB,MAAM,IAAI,MACR,6JAEF;AAEJ;;;;;;;;AASA,SAAgB,mBACd,UACA,cACA,OACoB;CACpB,IAAI,CAAC,cAAc,OAAO,EAAE,OAAO,MAAM;CACzC,IAAI,uBAAuB,UAAU,cAAc,KAAK,GACtD,OAAO;EACL,OAAO;EACP,QAAQ,GAAG,SAAS;CACtB;CAEF,OAAO,EAAE,OAAO,MAAM;AACxB;;;;;;;;;;;;;;AC1GA,SAAS,gBAAwB;CAC/B,IAAI;EACF,OAAO,aAAa,GAAG,MAAM;CAC/B,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,yBAAyB,cAAc;CAClD,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM;EACJ,IAAI,WAAW;EACf,IAAI;EACJ,IAAI;EACJ,IAAI;GACF,MAAM,UAAU,KAAK,MAAM,cAAc,CAAC;GAK1C,IAAI,OAAO,QAAQ,cAAc,UAAU,WAAW,QAAQ;GAC9D,IAAI,OAAO,QAAQ,eAAe,UAAU,YAAY,EAAE,YAAY,QAAQ,WAAW;GACzF,SAAS;EACX,QAAQ;GACN,SAAS;EACX;EACA,IAAI,SAAS,WAAW,GAAG;GAKzB,IAAI,CAAC,QAAQ;IACX,QAAQ,OAAO,MAAM,yEAAyE;IAC9F,QAAQ,KAAK,CAAC;GAChB;GACA,QAAQ,KAAK,CAAC;EAChB;EAEA,MAAM,WAAW,mBAAmB,UAAU,MAAM,SAAS;EAC7D,IAAI,SAAS,OAAO;GAClB,QAAQ,OAAO,MAAM,SAAS,UAAU,GAAG,SAAS,8BAA8B;GAClF,QAAQ,KAAK,CAAC;EAChB;EACA,QAAQ,KAAK,CAAC;CAChB;AACF,CAAC;;AAGD,MAAa,2BAA2B;;AAGxC,SAAgB,+BAA+B,YAAoC;CACjF,OAAO,iBAAiB,YAAY,2BAA2B;AACjE"}
@@ -1,2 +1,2 @@
1
- import { r as internalFirstMateGuard } from "./internal-first-mate-guard-mvfZal_M.js";
1
+ import { r as internalFirstMateGuard } from "./internal-first-mate-guard-Cj_g7RFr.js";
2
2
  export { internalFirstMateGuard };
@@ -1,4 +1,4 @@
1
- import { i as decideWorkerGuard, u as parseModesCsv } from "./worker-dispatch-DwS99DXz.js";
1
+ import { i as decideWorkerGuard, u as parseModesCsv } from "./worker-dispatch-CcQygiAA.js";
2
2
  import { defineCommand } from "citty";
3
3
  import { readFileSync } from "node:fs";
4
4
  //#region src/internal-worker-guard.ts
@@ -72,4 +72,4 @@ const internalWorkerGuard = defineCommand({
72
72
  //#endregion
73
73
  export { internalWorkerGuard };
74
74
 
75
- //# sourceMappingURL=internal-worker-guard-BSoS4wzV.js.map
75
+ //# sourceMappingURL=internal-worker-guard-Dd14aDXQ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal-worker-guard-BSoS4wzV.js","names":[],"sources":["../src/internal-worker-guard.ts"],"sourcesContent":["/**\n * The internal `internal-worker-guard` subcommand: the executable a spawned\n * Claude Code session's `PreToolUse` hook invokes for the workers tools\n * (registered into the mirrored settings.json by the launcher, with a matcher\n * scoped to `^mcp__<workersKey>__(explore|…)$`).\n *\n * It enforces the \"workers are non-blocking\" invariant: the MAIN agent (and any\n * non-dispatcher subagent) is DENIED a raw `mcp__<workersKey>__<mode>` call and\n * redirected to the matching background `worker-<mode>` dispatcher subagent; the\n * dispatcher's own call (identified by `agent_type` in the payload) is ALLOWED.\n * All the logic lives in the pure `decideWorkerGuard` (worker-dispatch.ts); this\n * entry is just stdin → decide → stdout.\n *\n * Output contract (Claude Code PreToolUse):\n * - ALLOW → print nothing, exit 0 (normal permission flow proceeds).\n * - DENY → print the `{hookSpecificOutput:{permissionDecision:\"deny\",…}}`\n * JSON to stdout, exit 0 (the JSON, not the exit code, blocks it).\n * Fail CLOSED: an unparseable payload for a matched worker tool is denied.\n */\n\nimport { defineCommand } from \"citty\"\n\nimport { readFileSync } from \"node:fs\"\n\nimport { decideWorkerGuard, parseModesCsv } from \"./lib/worker-dispatch\"\n\n/**\n * Read the hook payload from stdin SYNCHRONOUSLY (`readFileSync(0)`) — same\n * rationale as `internal-prompt-submit`: an async stdin read leaves an in-flight\n * libuv FS request that races Windows process teardown. Hooks always receive\n * piped stdin (guarded against an interactive TTY; any error → \"\").\n */\nfunction readStdin(): string {\n try {\n if (process.stdin.isTTY) return \"\"\n return readFileSync(0, \"utf8\")\n } catch {\n return \"\"\n }\n}\n\nexport const internalWorkerGuard = defineCommand({\n meta: {\n name: \"internal-worker-guard\",\n description:\n \"Internal: the workers PreToolUse guard. Denies a raw mcp__<workers>__<mode> \"\n + \"call from the main agent (redirecting to the worker-<mode> background subagent) \"\n + \"and allows it from the dispatcher subagent. Fails closed.\",\n },\n args: {\n \"workers-key\": {\n type: \"string\",\n description: \"Resolved workers MCP config key (bare `workers` or `gh-router-workers`).\",\n required: true,\n },\n modes: {\n type: \"string\",\n description: \"CSV of active worker modes, e.g. `explore,implement,review,plan,test`.\",\n required: false,\n },\n },\n run(ctx) {\n try {\n const stdin = readStdin()\n const workersKey = String(ctx.args[\"workers-key\"] ?? \"\").trim()\n // Defensive: with no resolved key we cannot recognize any worker tool, so\n // there is nothing to guard — allow (print nothing). This never happens in\n // practice (the launcher only registers the hook with a real key).\n if (workersKey.length > 0) {\n const modes = parseModesCsv(\n typeof ctx.args.modes === \"string\" ? ctx.args.modes : undefined,\n )\n const { output } = decideWorkerGuard({ stdin, workersKey, modes })\n if (output) process.stdout.write(output)\n }\n } catch {\n /* never throw out of a hook — a crash would surface as an opaque tool error */\n }\n // Natural exit (code 0): the permissionDecision in the JSON (not the exit\n // code) blocks a denied call. A hard process.exit() races libuv stdio\n // teardown on Windows.\n process.exitCode = 0\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAS,YAAoB;CAC3B,IAAI;EACF,IAAI,QAAQ,MAAM,OAAO,OAAO;EAChC,OAAO,aAAa,GAAG,MAAM;CAC/B,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,sBAAsB,cAAc;CAC/C,MAAM;EACJ,MAAM;EACN,aACE;CAGJ;CACA,MAAM;EACJ,eAAe;GACb,MAAM;GACN,aAAa;GACb,UAAU;EACZ;EACA,OAAO;GACL,MAAM;GACN,aAAa;GACb,UAAU;EACZ;CACF;CACA,IAAI,KAAK;EACP,IAAI;GACF,MAAM,QAAQ,UAAU;GACxB,MAAM,aAAa,OAAO,IAAI,KAAK,kBAAkB,EAAE,CAAC,CAAC,KAAK;GAI9D,IAAI,WAAW,SAAS,GAAG;IACzB,MAAM,QAAQ,cACZ,OAAO,IAAI,KAAK,UAAU,WAAW,IAAI,KAAK,QAAQ,KAAA,CACxD;IACA,MAAM,EAAE,WAAW,kBAAkB;KAAE;KAAO;KAAY;IAAM,CAAC;IACjE,IAAI,QAAQ,QAAQ,OAAO,MAAM,MAAM;GACzC;EACF,QAAQ,CAER;EAIA,QAAQ,WAAW;CACrB;AACF,CAAC"}
1
+ {"version":3,"file":"internal-worker-guard-Dd14aDXQ.js","names":[],"sources":["../src/internal-worker-guard.ts"],"sourcesContent":["/**\n * The internal `internal-worker-guard` subcommand: the executable a spawned\n * Claude Code session's `PreToolUse` hook invokes for the workers tools\n * (registered into the mirrored settings.json by the launcher, with a matcher\n * scoped to `^mcp__<workersKey>__(explore|…)$`).\n *\n * It enforces the \"workers are non-blocking\" invariant: the MAIN agent (and any\n * non-dispatcher subagent) is DENIED a raw `mcp__<workersKey>__<mode>` call and\n * redirected to the matching background `worker-<mode>` dispatcher subagent; the\n * dispatcher's own call (identified by `agent_type` in the payload) is ALLOWED.\n * All the logic lives in the pure `decideWorkerGuard` (worker-dispatch.ts); this\n * entry is just stdin → decide → stdout.\n *\n * Output contract (Claude Code PreToolUse):\n * - ALLOW → print nothing, exit 0 (normal permission flow proceeds).\n * - DENY → print the `{hookSpecificOutput:{permissionDecision:\"deny\",…}}`\n * JSON to stdout, exit 0 (the JSON, not the exit code, blocks it).\n * Fail CLOSED: an unparseable payload for a matched worker tool is denied.\n */\n\nimport { defineCommand } from \"citty\"\n\nimport { readFileSync } from \"node:fs\"\n\nimport { decideWorkerGuard, parseModesCsv } from \"./lib/worker-dispatch\"\n\n/**\n * Read the hook payload from stdin SYNCHRONOUSLY (`readFileSync(0)`) — same\n * rationale as `internal-prompt-submit`: an async stdin read leaves an in-flight\n * libuv FS request that races Windows process teardown. Hooks always receive\n * piped stdin (guarded against an interactive TTY; any error → \"\").\n */\nfunction readStdin(): string {\n try {\n if (process.stdin.isTTY) return \"\"\n return readFileSync(0, \"utf8\")\n } catch {\n return \"\"\n }\n}\n\nexport const internalWorkerGuard = defineCommand({\n meta: {\n name: \"internal-worker-guard\",\n description:\n \"Internal: the workers PreToolUse guard. Denies a raw mcp__<workers>__<mode> \"\n + \"call from the main agent (redirecting to the worker-<mode> background subagent) \"\n + \"and allows it from the dispatcher subagent. Fails closed.\",\n },\n args: {\n \"workers-key\": {\n type: \"string\",\n description: \"Resolved workers MCP config key (bare `workers` or `gh-router-workers`).\",\n required: true,\n },\n modes: {\n type: \"string\",\n description: \"CSV of active worker modes, e.g. `explore,implement,review,plan,test`.\",\n required: false,\n },\n },\n run(ctx) {\n try {\n const stdin = readStdin()\n const workersKey = String(ctx.args[\"workers-key\"] ?? \"\").trim()\n // Defensive: with no resolved key we cannot recognize any worker tool, so\n // there is nothing to guard — allow (print nothing). This never happens in\n // practice (the launcher only registers the hook with a real key).\n if (workersKey.length > 0) {\n const modes = parseModesCsv(\n typeof ctx.args.modes === \"string\" ? ctx.args.modes : undefined,\n )\n const { output } = decideWorkerGuard({ stdin, workersKey, modes })\n if (output) process.stdout.write(output)\n }\n } catch {\n /* never throw out of a hook — a crash would surface as an opaque tool error */\n }\n // Natural exit (code 0): the permissionDecision in the JSON (not the exit\n // code) blocks a denied call. A hard process.exit() races libuv stdio\n // teardown on Windows.\n process.exitCode = 0\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,SAAS,YAAoB;CAC3B,IAAI;EACF,IAAI,QAAQ,MAAM,OAAO,OAAO;EAChC,OAAO,aAAa,GAAG,MAAM;CAC/B,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAa,sBAAsB,cAAc;CAC/C,MAAM;EACJ,MAAM;EACN,aACE;CAGJ;CACA,MAAM;EACJ,eAAe;GACb,MAAM;GACN,aAAa;GACb,UAAU;EACZ;EACA,OAAO;GACL,MAAM;GACN,aAAa;GACb,UAAU;EACZ;CACF;CACA,IAAI,KAAK;EACP,IAAI;GACF,MAAM,QAAQ,UAAU;GACxB,MAAM,aAAa,OAAO,IAAI,KAAK,kBAAkB,EAAE,CAAC,CAAC,KAAK;GAI9D,IAAI,WAAW,SAAS,GAAG;IACzB,MAAM,QAAQ,cACZ,OAAO,IAAI,KAAK,UAAU,WAAW,IAAI,KAAK,QAAQ,KAAA,CACxD;IACA,MAAM,EAAE,WAAW,kBAAkB;KAAE;KAAO;KAAY;IAAM,CAAC;IACjE,IAAI,QAAQ,QAAQ,OAAO,MAAM,MAAM;GACzC;EACF,QAAQ,CAER;EAIA,QAAQ,WAAW;CACrB;AACF,CAAC"}
package/dist/main.js CHANGED
@@ -47,10 +47,10 @@ const main = defineCommand({
47
47
  },
48
48
  subCommands: {
49
49
  auth: () => import("./auth-DSLN1arH.js").then((m) => m.auth),
50
- start: () => import("./start-DNzOFabp.js").then((m) => m.start),
51
- claude: () => import("./claude-Cq1xGzbI.js").then((m) => m.claude),
52
- codex: () => import("./codex-INt1hc_5.js").then((m) => m.codex),
53
- serve: () => import("./serve-TiUhvpVp.js").then((m) => m.serve),
50
+ start: () => import("./start-XFIxMRkE.js").then((m) => m.start),
51
+ claude: () => import("./claude-Bni6m56W.js").then((m) => m.claude),
52
+ codex: () => import("./codex-DAnu246m.js").then((m) => m.codex),
53
+ serve: () => import("./serve-BGGcy8Nq.js").then((m) => m.serve),
54
54
  models: () => import("./models-B9tdaM6B.js").then((m) => m.models),
55
55
  "check-usage": () => import("./check-usage-B_12ALvf.js").then((m) => m.checkUsage),
56
56
  debug: () => import("./debug-D8iD6G4O.js").then((m) => m.debug),
@@ -61,8 +61,8 @@ const main = defineCommand({
61
61
  "internal-session-bind": () => import("./internal-session-bind-BVQy7Vd4.js").then((m) => m.internalSessionBind),
62
62
  "internal-workspace-header": () => import("./internal-workspace-header-booLOzwD.js").then((m) => m.internalWorkspaceHeader),
63
63
  "internal-artifact-open": () => import("./internal-artifact-open-U-Ht7R-O.js").then((m) => m.internalArtifactOpen),
64
- "internal-first-mate-guard": () => import("./internal-first-mate-guard-Dvd1vZ4l.js").then((m) => m.internalFirstMateGuard),
65
- "internal-worker-guard": () => import("./internal-worker-guard-BSoS4wzV.js").then((m) => m.internalWorkerGuard),
64
+ "internal-first-mate-guard": () => import("./internal-first-mate-guard-ZqPHrYlh.js").then((m) => m.internalFirstMateGuard),
65
+ "internal-worker-guard": () => import("./internal-worker-guard-Dd14aDXQ.js").then((m) => m.internalWorkerGuard),
66
66
  "internal-fast-dispatch-guard": () => import("./internal-fast-dispatch-guard-uztSu0c8.js").then((m) => m.internalFastDispatchGuard),
67
67
  "internal-max-dispatch-guard": () => import("./internal-max-dispatch-guard-CxG_c3cc.js").then((m) => m.internalMaxDispatchGuard),
68
68
  "internal-aic-status": () => import("./internal-aic-status-BaUKlisM.js").then((m) => m.internalAicStatus)
@@ -4,12 +4,12 @@ import { r as ensureClaudeConfigMirror, s as removeOwnClaudeConfigMirror, t as P
4
4
  import { t as state } from "./state-BlMpEFAt.js";
5
5
  import { d as resolveModel, m as getGitHubUser } from "./token-Css-ARGL.js";
6
6
  import { n as killChildProcessTree, o as resolveExecutable, s as runCommandCapture } from "./exec-COUT4QsS.js";
7
- import { R as runSelfUpdate, a as sharedServerArgs, c as stopKeepAwake, i as setupAndServe, j as resolveLaunchProfile, l as injectModelPickerSettingsFile, r as parseSharedArgs, s as startKeepAwake, t as getClaudeCodeEnvVars } from "./server-setup-CgbHmupe.js";
7
+ import { R as runSelfUpdate, a as sharedServerArgs, c as stopKeepAwake, i as setupAndServe, j as resolveLaunchProfile, l as injectModelPickerSettingsFile, r as parseSharedArgs, s as startKeepAwake, t as getClaudeCodeEnvVars } from "./server-setup-CZ3tEsgq.js";
8
8
  import { n as hookLauncherDegradedWarning, r as resolveSelfInvocation } from "./self-invocation-opSXHEs0.js";
9
9
  import { r as getCodexVersion, t as provisionToolbelt } from "./provision-B-a5KUCL.js";
10
10
  import { s as injectStopHookIntoSettingsFile } from "./stop-gate-hook-DvNM8zFf.js";
11
- import { l as guardToolMatcher, n as activeDispatchModes, r as buildWorkerGuardHookCommand } from "./worker-dispatch-DwS99DXz.js";
12
- import { C as writePeerMcpRuntimeFiles, S as workersKeyOf, _ as sanitizeServeSettingsEnv, a as appendPeerAwarenessToMirroredClaudeMd, b as resolveCodexCliBackend, c as buildOperatingDefaultsDirective, d as prependStyleDirectiveToMirroredClaudeMd, g as planModeAllowRules, h as injectAllowRules, i as writeInjectedSkill, m as configureServeDefaultPermissionMode, n as INJECTED_SKILLS, o as appendToolbeltAwarenessToMirroredClaudeMd, p as SEAMLESS_BUILTIN_TOOLS, t as injectAttributionSuppressionIntoSettingsFile, u as prependOperatingDefaultsToMirroredClaudeMd, v as BUILTIN_SUBAGENT_DEFINITIONS, x as resolveGroupKeysFromMirror, y as injectPeerMcpIntoMirror } from "./attribution-settings-CX-kIrT8.js";
11
+ import { l as guardToolMatcher, n as activeDispatchModes, r as buildWorkerGuardHookCommand } from "./worker-dispatch-CcQygiAA.js";
12
+ import { C as writePeerMcpRuntimeFiles, S as workersKeyOf, _ as sanitizeServeSettingsEnv, a as appendPeerAwarenessToMirroredClaudeMd, b as resolveCodexCliBackend, c as buildOperatingDefaultsDirective, d as prependStyleDirectiveToMirroredClaudeMd, g as planModeAllowRules, h as injectAllowRules, i as writeInjectedSkill, m as configureServeDefaultPermissionMode, n as INJECTED_SKILLS, o as appendToolbeltAwarenessToMirroredClaudeMd, p as SEAMLESS_BUILTIN_TOOLS, t as injectAttributionSuppressionIntoSettingsFile, u as prependOperatingDefaultsToMirroredClaudeMd, v as BUILTIN_SUBAGENT_DEFINITIONS, x as resolveGroupKeysFromMirror, y as injectPeerMcpIntoMirror } from "./attribution-settings-sTUXqFzx.js";
13
13
  import { i as planReviewEnabled, t as buildPlanReviewHookCommand } from "./plan-review-hook-BlsGnG02.js";
14
14
  import { t as buildPromptSubmitHookCommand } from "./prompt-submit-hook-BJFLzCaT.js";
15
15
  import { defineCommand } from "citty";
@@ -539,7 +539,8 @@ function resolveServeNativeAgentOptions() {
539
539
  * SDK-spawned claude reads them from the mirror's `.claude.json`,
540
540
  * - the peer-critic / worker / implementer subagents (`.md` files written into
541
541
  * the mirror's `agents/`),
542
- * - the gh-* skills (research / orchestrate / floor-keeper / worker).
542
+ * - the gh-* skills (research / gather-context / plan / implement /
543
+ * orchestrate / floor-keeper / worker).
543
544
  *
544
545
  * Best-effort: on any failure Claude still works, just without the extras.
545
546
  * Must run AFTER `ensureClaudeConfigMirror()` and BEFORE CloudCLI is spawned.
@@ -1559,4 +1560,4 @@ const serve = defineCommand({
1559
1560
  //#endregion
1560
1561
  export { serve };
1561
1562
 
1562
- //# sourceMappingURL=serve-TiUhvpVp.js.map
1563
+ //# sourceMappingURL=serve-BGGcy8Nq.js.map