github-router 0.3.263 → 0.3.270

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 (77) hide show
  1. package/dist/{attribution-settings-DFIVIRG8.js → attribution-settings-of5gJM5a.js} +4 -4
  2. package/dist/{attribution-settings-DFIVIRG8.js.map → attribution-settings-of5gJM5a.js.map} +1 -1
  3. package/dist/{auth-WA88cE9q.js → auth-DIFbHOu0.js} +3 -3
  4. package/dist/{auth-WA88cE9q.js.map → auth-DIFbHOu0.js.map} +1 -1
  5. package/dist/browser-bridge/index.js +67 -27
  6. package/dist/browser-ext/manifest.json +1 -1
  7. package/dist/{check-usage-v2apGKz7.js → check-usage-DfnrR-d_.js} +4 -4
  8. package/dist/{check-usage-v2apGKz7.js.map → check-usage-DfnrR-d_.js.map} +1 -1
  9. package/dist/{claude-BCI3Sx6_.js → claude-BlzCUbVq.js} +15 -14
  10. package/dist/{claude-BCI3Sx6_.js.map → claude-BlzCUbVq.js.map} +1 -1
  11. package/dist/{codex-DyJIrbJt.js → codex-BaFcXOyg.js} +5 -5
  12. package/dist/{codex-DyJIrbJt.js.map → codex-BaFcXOyg.js.map} +1 -1
  13. package/dist/{debug-vshv4nIv.js → debug-CuuxCk_J.js} +2 -2
  14. package/dist/{debug-vshv4nIv.js.map → debug-CuuxCk_J.js.map} +1 -1
  15. package/dist/engine-mwIgHJoi.js +2 -0
  16. package/dist/{exec-DTO2oin0.js → exec-y8C_MU8A.js} +89 -18
  17. package/dist/exec-y8C_MU8A.js.map +1 -0
  18. package/dist/{gate-discovery-cMbt8Ct2.js → gate-discovery-AUAjqSpV.js} +6 -6
  19. package/dist/{gate-discovery-cMbt8Ct2.js.map → gate-discovery-AUAjqSpV.js.map} +1 -1
  20. package/dist/{get-copilot-usage-DOFJWJaQ.js → get-copilot-usage-Ds09xSmH.js} +2 -2
  21. package/dist/{get-copilot-usage-DOFJWJaQ.js.map → get-copilot-usage-Ds09xSmH.js.map} +1 -1
  22. package/dist/{internal-artifact-open-CZGO831M.js → internal-artifact-open-CDqPfegE.js} +2 -2
  23. package/dist/{internal-artifact-open-CZGO831M.js.map → internal-artifact-open-CDqPfegE.js.map} +1 -1
  24. package/dist/{internal-plan-review-6gkcOAjT.js → internal-plan-review-CH9qTHoZ.js} +3 -3
  25. package/dist/{internal-plan-review-6gkcOAjT.js.map → internal-plan-review-CH9qTHoZ.js.map} +1 -1
  26. package/dist/{internal-prompt-submit-C0XOPgcP.js → internal-prompt-submit-Bve1s4z_.js} +5 -5
  27. package/dist/{internal-prompt-submit-C0XOPgcP.js.map → internal-prompt-submit-Bve1s4z_.js.map} +1 -1
  28. package/dist/{internal-session-bind-DtSBTkQe.js → internal-session-bind-Cc8bMXHK.js} +2 -2
  29. package/dist/{internal-session-bind-DtSBTkQe.js.map → internal-session-bind-Cc8bMXHK.js.map} +1 -1
  30. package/dist/{internal-stop-hook-CBcE2Js8.js → internal-stop-hook-B1MIwmTR.js} +6 -6
  31. package/dist/{internal-stop-hook-CBcE2Js8.js.map → internal-stop-hook-B1MIwmTR.js.map} +1 -1
  32. package/dist/{internal-stop-review-_1Mqz7eT.js → internal-stop-review-CWE7_QVv.js} +2 -2
  33. package/dist/{internal-stop-review-_1Mqz7eT.js.map → internal-stop-review-CWE7_QVv.js.map} +1 -1
  34. package/dist/{lifecycle-DjC9tC1A.js → lifecycle-0XrazT05.js} +2 -2
  35. package/dist/{lifecycle-DjC9tC1A.js.map → lifecycle-0XrazT05.js.map} +1 -1
  36. package/dist/lifecycle-2M0IThRr.js +2 -0
  37. package/dist/{lifecycle-Bd1Fyf4B.js → lifecycle-AgNOtFRv.js} +3 -3
  38. package/dist/{lifecycle-Bd1Fyf4B.js.map → lifecycle-AgNOtFRv.js.map} +1 -1
  39. package/dist/lifecycle-C8kFsAj-.js +2 -0
  40. package/dist/main.js +14 -14
  41. package/dist/{models-Cv6gprpy.js → models-BFQUp0ov.js} +35 -30
  42. package/dist/models-BFQUp0ov.js.map +1 -0
  43. package/dist/{orchestration-B6qidQAd.js → orchestration-B_Q3ncXI.js} +3 -3
  44. package/dist/{orchestration-B6qidQAd.js.map → orchestration-B_Q3ncXI.js.map} +1 -1
  45. package/dist/paths-BbHtQAOs.js +2 -0
  46. package/dist/{paths-BXrbboAS.js → paths-Bg1_DWhi.js} +3 -3
  47. package/dist/{paths-BXrbboAS.js.map → paths-Bg1_DWhi.js.map} +1 -1
  48. package/dist/{peer-mcp-personas-B22ncnbQ.js → peer-mcp-personas-pWP3Eyt7.js} +235 -108
  49. package/dist/peer-mcp-personas-pWP3Eyt7.js.map +1 -0
  50. package/dist/{plan-review-hook-Bo4y1r3j.js → plan-review-hook-BKOcW5s4.js} +3 -3
  51. package/dist/{plan-review-hook-Bo4y1r3j.js.map → plan-review-hook-BKOcW5s4.js.map} +1 -1
  52. package/dist/{prompt-submit-hook-BFRFLSk5.js → prompt-submit-hook-F7Zih_au.js} +2 -2
  53. package/dist/{prompt-submit-hook-BFRFLSk5.js.map → prompt-submit-hook-F7Zih_au.js.map} +1 -1
  54. package/dist/{provision-DSpLQHC3.js → provision-CsYUVdMT.js} +5 -5
  55. package/dist/{provision-DSpLQHC3.js.map → provision-CsYUVdMT.js.map} +1 -1
  56. package/dist/{serve-D9tBVVoK.js → serve--c9n9hk4.js} +11 -11
  57. package/dist/{serve-D9tBVVoK.js.map → serve--c9n9hk4.js.map} +1 -1
  58. package/dist/{server-setup-BM9Smfek.js → server-setup-BmyWS4WU.js} +559 -158
  59. package/dist/server-setup-BmyWS4WU.js.map +1 -0
  60. package/dist/{start-D7Hx2T_T.js → start-CXnLBouJ.js} +3 -3
  61. package/dist/{start-D7Hx2T_T.js.map → start-CXnLBouJ.js.map} +1 -1
  62. package/dist/{stop-gate-hook-Bmwla_2u.js → stop-gate-hook-BqpumJtl.js} +3 -3
  63. package/dist/{stop-gate-hook-Bmwla_2u.js.map → stop-gate-hook-BqpumJtl.js.map} +1 -1
  64. package/dist/{stop-gate-policy-CoMKWSsS.js → stop-gate-policy-C0XOBZhB.js} +3 -3
  65. package/dist/{stop-gate-policy-CoMKWSsS.js.map → stop-gate-policy-C0XOBZhB.js.map} +1 -1
  66. package/dist/{token-C8Uh7aUe.js → token-iaSGp76k.js} +356 -147
  67. package/dist/token-iaSGp76k.js.map +1 -0
  68. package/package.json +2 -2
  69. package/dist/engine-D8dlcSW6.js +0 -2
  70. package/dist/exec-DTO2oin0.js.map +0 -1
  71. package/dist/lifecycle-CRTWEbiP.js +0 -2
  72. package/dist/lifecycle-DUPXAOQS.js +0 -2
  73. package/dist/models-Cv6gprpy.js.map +0 -1
  74. package/dist/paths-Dz1WyRJG.js +0 -2
  75. package/dist/peer-mcp-personas-B22ncnbQ.js.map +0 -1
  76. package/dist/server-setup-BM9Smfek.js.map +0 -1
  77. package/dist/token-C8Uh7aUe.js.map +0 -1
@@ -1,13 +1,13 @@
1
1
  import { t as getPackageVersion } from "./version-_Q1WpsQp.js";
2
- import { t as PATHS } from "./paths-BXrbboAS.js";
3
- import { C as copilotHeaders, E as githubAgentHeaders, O as state, S as copilotBaseUrl, T as githubAgentGraphQLHeaders, _ as withTransientRetry, b as GITHUB_API_BASE_URL, d as resolveModel, f as sleep$2, g as fetchWithTransientRetry, h as isAllowedCopilotHost, i as tryRefreshAndRetry, v as HTTPError, w as copilotVersion, x as GITHUB_GRAPHQL_URL } from "./token-C8Uh7aUe.js";
4
- import { a as resolveExecutable, c as runManagedExeCapture, i as parseIntEnv, r as parseBoolEnv } from "./exec-DTO2oin0.js";
5
- import { i as registerExitHandlers$1, n as getInstanceUuid, r as recordWorkerRepo, t as WorktreeRegistry } from "./lifecycle-DjC9tC1A.js";
2
+ import { t as PATHS } from "./paths-Bg1_DWhi.js";
3
+ import { A as state, C as GITHUB_GRAPHQL_URL, D as githubAgentGraphQLHeaders, E as copilotVersion, O as githubAgentHeaders, S as GITHUB_API_BASE_URL, T as copilotHeaders, b as sanitizeTransportText, d as resolveModel, f as sleep$2, g as HTTPError, h as isAllowedCopilotHost, i as tryRefreshAndRetry, v as classifyTransportError, w as copilotBaseUrl, x as withTransientRetry, y as fetchWithTransientRetry } from "./token-iaSGp76k.js";
4
+ import { a as resolveExecutable, c as runManagedExeCapture, i as parseIntEnv, l as spawnTaskkillBestEffort, r as parseBoolEnv } from "./exec-y8C_MU8A.js";
5
+ import { i as registerExitHandlers$1, n as getInstanceUuid, r as recordWorkerRepo, t as WorktreeRegistry } from "./lifecycle-0XrazT05.js";
6
6
  import { t as MCP_WORKSPACE_HEADER } from "./mcp-workspace-header-CGJbNeHb.js";
7
7
  import { n as ArtifactError, r as applyInsecureTls, t as ArtifactClient } from "./client-CQMfroGV.js";
8
- import { n as isPidAlive, r as registerColbertExitHandlers, s as trackChild, t as getColbertInstanceUuid } from "./lifecycle-Bd1Fyf4B.js";
9
- import { h as runGateChecks, m as sealedGateIds, p as resolveSealedGate } from "./stop-gate-hook-Bmwla_2u.js";
10
- import { t as liveExec } from "./orchestration-B6qidQAd.js";
8
+ import { n as isPidAlive, r as registerColbertExitHandlers, s as trackChild, t as getColbertInstanceUuid } from "./lifecycle-AgNOtFRv.js";
9
+ import { h as runGateChecks, m as sealedGateIds, p as resolveSealedGate } from "./stop-gate-hook-BqpumJtl.js";
10
+ import { t as liveExec } from "./orchestration-B_Q3ncXI.js";
11
11
  import { createRequire } from "node:module";
12
12
  import consola from "consola";
13
13
  import { chmodSync, closeSync, constants, cpSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
@@ -3966,6 +3966,7 @@ async function readCappedText(response) {
3966
3966
  text += decoder.decode();
3967
3967
  } catch (err) {
3968
3968
  consola.debug("first-mate capi: capped read interrupted:", err);
3969
+ await reader.cancel().catch(() => void 0);
3969
3970
  }
3970
3971
  return text.length > MAX_LOG_BYTES ? text.slice(0, MAX_LOG_BYTES) : text;
3971
3972
  }
@@ -4511,13 +4512,45 @@ function currentFenceToken() {
4511
4512
  function sleep$1(ms) {
4512
4513
  return new Promise((resolve) => setTimeout(resolve, ms));
4513
4514
  }
4515
+ /**
4516
+ * Backoff for a transient Windows rename failure.
4517
+ *
4518
+ * On Windows `fs.rename` over an existing destination transiently fails with
4519
+ * EPERM / EBUSY / EACCES when anything else holds the target open for even a
4520
+ * moment — antivirus, the search indexer, a backup agent, an editor. Nothing is
4521
+ * wrong; the handle closes microseconds later.
4522
+ *
4523
+ * This matters here more than most places: this function is the durable write
4524
+ * for mission ledgers and decisions. Without a retry, a single AV scan landing
4525
+ * on the wrong millisecond throws out of a state write, and the caller sees a
4526
+ * mission-tracking failure it cannot act on. Observed in the test suite as an
4527
+ * EPERM on `octo__alpha.json`.
4528
+ *
4529
+ * Same delays as `renameWithRetry` in `~/lib/claude-md-injection`, which
4530
+ * documents the underlying Windows behavior at length.
4531
+ */
4532
+ const RENAME_RETRY_DELAYS_MS = [
4533
+ 50,
4534
+ 200,
4535
+ 500
4536
+ ];
4514
4537
  async function writeJsonSecure(target, value) {
4515
4538
  await fs$1.mkdir(path.dirname(target), { recursive: true });
4516
4539
  const tmp = `${target}.tmp.${process.pid}.${randomBytes(4).toString("hex")}`;
4517
4540
  try {
4518
4541
  await fs$1.writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`, { mode: 384 });
4519
4542
  await fs$1.chmod(tmp, 384).catch(() => {});
4520
- await fs$1.rename(tmp, target);
4543
+ let lastErr;
4544
+ let renamed = false;
4545
+ for (let attempt = 0; attempt <= RENAME_RETRY_DELAYS_MS.length; attempt++) try {
4546
+ await fs$1.rename(tmp, target);
4547
+ renamed = true;
4548
+ break;
4549
+ } catch (err) {
4550
+ lastErr = err;
4551
+ if (attempt < RENAME_RETRY_DELAYS_MS.length) await sleep$1(RENAME_RETRY_DELAYS_MS[attempt]);
4552
+ }
4553
+ if (!renamed) throw lastErr;
4521
4554
  await fs$1.chmod(target, 384).catch(() => {});
4522
4555
  } catch (err) {
4523
4556
  await fs$1.unlink(tmp).catch(() => {});
@@ -9776,6 +9809,35 @@ function parseRepoSlug(value) {
9776
9809
  repo: parts[1].trim()
9777
9810
  };
9778
9811
  }
9812
+ /**
9813
+ * Repositories `scaffold_repo` is permitted to write to.
9814
+ *
9815
+ * `parseRepoSlug` validates SHAPE only, so before this gate any `owner/name`
9816
+ * the agent token could reach was writable. The tool's own description says it
9817
+ * "is not for arbitrary third-party repositories" — that was prose in a model-
9818
+ * facing string, not enforcement.
9819
+ *
9820
+ * Why it matters here specifically: `--browse` ingests arbitrary web content,
9821
+ * and that content reaches a model whose tool surface (under `--agents`, with
9822
+ * the second write-scoped token) includes creating branches, committing files,
9823
+ * and opening PRs. A fetched page that talks a model into naming a different
9824
+ * repo is the realistic version of that risk, and nothing downstream would
9825
+ * have caught it: the branch+PR flow and the human merge gate bound the BLAST
9826
+ * RADIUS of a write, but neither constrains WHICH repo it lands in.
9827
+ *
9828
+ * Configured with `GH_ROUTER_FM_SCAFFOLD_REPOS` as a comma-separated list of
9829
+ * `owner/name` entries; `owner/*` allows a whole org. Matching is
9830
+ * case-insensitive (GitHub logins are). Unset means DENY-ALL rather than
9831
+ * allow-all: a default-open gate is not a gate, and the operator who wants
9832
+ * scaffolding is the one who knows which repos they own. The error names the
9833
+ * env var so the honest use case is one copy-paste away.
9834
+ */
9835
+ function assertScaffoldRepoAllowed(repo) {
9836
+ const patterns = (process.env.GH_ROUTER_FM_SCAFFOLD_REPOS ?? "").split(",").map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0);
9837
+ const slug = `${repo.owner}/${repo.repo}`.toLowerCase();
9838
+ if (patterns.some((pattern) => pattern === slug || pattern === `${repo.owner.toLowerCase()}/*`)) return;
9839
+ throw new ScaffoldHelperError("repo-not-allowed", `scaffold_repo refused ${slug}: it is not in the allowlist. This tool creates branches, commits files, and opens pull requests, so it is restricted to repositories the operator has named. Set GH_ROUTER_FM_SCAFFOLD_REPOS to a comma-separated list of owner/name entries (or owner/* for a whole org) to permit it.` + (patterns.length === 0 ? " It is currently unset, so every repository is denied." : ""));
9840
+ }
9779
9841
  function normalizeBranchRef(value) {
9780
9842
  const trimmed = value.trim();
9781
9843
  const withoutRefsPrefix = trimmed.startsWith("refs/heads/") ? trimmed.slice(11) : trimmed.startsWith("heads/") ? trimmed.slice(6) : trimmed;
@@ -10673,7 +10735,7 @@ function createFirstMateTools(depsOverride = {}) {
10673
10735
  repos
10674
10736
  });
10675
10737
  }),
10676
- tool("scaffold_repo", "Seeds first-mate and agentic-dev convention files into a GitHub repository by creating a scaffold branch, committing deterministic files, and opening a pull request; it does not write directly to the default branch. Inputs name the owner/name repo, optional base ref, handling mode, and optional detection overrides for stack, OS, package manager, commands, and UI evidence. Returns the pull request plus committed, preserved, and per-file report data, or a no-op note when nothing needs seeding. Use when preparing an owned repository for the first-mate cloud-agent workflow. It is not for arbitrary third-party repositories, normal feature work, or repeated runs unless the operator intentionally wants missing or enhanced convention files.", objectSchema({
10738
+ tool("scaffold_repo", "Seeds first-mate and agentic-dev convention files into a GitHub repository by creating a scaffold branch, committing deterministic files, and opening a pull request; it does not write directly to the default branch. Inputs name the owner/name repo, optional base ref, handling mode, and optional detection overrides for stack, OS, package manager, commands, and UI evidence. Returns the pull request plus committed, preserved, and per-file report data, or a no-op note when nothing needs seeding. Use when preparing an owned repository for the first-mate cloud-agent workflow. Repositories must be allowlisted by the operator via GH_ROUTER_FM_SCAFFOLD_REPOS (unset denies every repository), so a repo outside that list is refused rather than written to. It is not for arbitrary third-party repositories, normal feature work, or repeated runs unless the operator intentionally wants missing or enhanced convention files.", objectSchema({
10677
10739
  repo: stringProp("Repository as an owner/name string."),
10678
10740
  mode: enumProp([
10679
10741
  "add-missing-only",
@@ -10685,6 +10747,7 @@ function createFirstMateTools(depsOverride = {}) {
10685
10747
  }, ["repo"]), async (args, signal) => {
10686
10748
  const input = parseScaffoldRepoArgs(args);
10687
10749
  const repo = parseRepoSlug(input.repo);
10750
+ assertScaffoldRepoAllowed(repo);
10688
10751
  const repository = input.base_ref === void 0 ? await getRepositoryDetails(repo, signal) : { defaultBranch: normalizeBranchRef(input.base_ref) };
10689
10752
  const baseBranch = repository.defaultBranch;
10690
10753
  const desiredFiles = buildScaffoldFiles(await detectScaffoldOptions({
@@ -13318,14 +13381,7 @@ function tokenize(text) {
13318
13381
  function killChild(child) {
13319
13382
  if (!child.pid || child.killed) return;
13320
13383
  if (process.platform === "win32") {
13321
- try {
13322
- execFile("taskkill", [
13323
- "/T",
13324
- "/F",
13325
- "/PID",
13326
- String(child.pid)
13327
- ], () => {});
13328
- } catch {}
13384
+ spawnTaskkillBestEffort(child.pid);
13329
13385
  return;
13330
13386
  }
13331
13387
  try {
@@ -18367,7 +18423,7 @@ function logAudit$1(record) {
18367
18423
  try {
18368
18424
  const fs = await import("node:fs/promises");
18369
18425
  const path = await import("node:path");
18370
- const { PATHS } = await import("./paths-Dz1WyRJG.js");
18426
+ const { PATHS } = await import("./paths-BbHtQAOs.js");
18371
18427
  const dir = path.join(PATHS.APP_DIR, "browser-mcp");
18372
18428
  await fs.mkdir(dir, { recursive: true });
18373
18429
  const line = JSON.stringify({
@@ -19183,7 +19239,10 @@ async function readResponseBodyCapped(response, routePath, capBytes = MAX_RESPON
19183
19239
  chunks.push(value);
19184
19240
  }
19185
19241
  } catch (err) {
19186
- if (!capped) consola.warn(`readResponseBodyCapped: read error at ${routePath}:`, err);
19242
+ if (!capped) {
19243
+ consola.warn(`readResponseBodyCapped: read error at ${routePath}:`, err);
19244
+ await reader.cancel().catch(() => void 0);
19245
+ }
19187
19246
  }
19188
19247
  if (capped) {
19189
19248
  consola.warn(`Non-streaming upstream response at ${routePath} exceeded ${capBytes} bytes (10 MiB cap); dropping body to prevent OOM. Check upstream health.`);
@@ -27204,10 +27263,8 @@ function relayAnthropicStream(body, opts) {
27204
27263
  safeClose(controller);
27205
27264
  return;
27206
27265
  }
27207
- const errName = error instanceof Error ? error.name : "Error";
27208
- const errMessage = error instanceof Error ? error.message : String(error);
27209
- consola.error(`Upstream stream interrupted at ${opts.routePath}: bytes=${bytesRelayed} errType=${errName} message=${JSON.stringify(errMessage)}`);
27210
- const event = buildAnthropicErrorEvent(errName, errMessage);
27266
+ const { errName, errMessage, transport } = logStreamError(opts.routePath, error, bytesRelayed);
27267
+ const event = buildAnthropicErrorEvent(errName, errMessage, transport);
27211
27268
  try {
27212
27269
  controller.enqueue(ENCODER$1.encode(event));
27213
27270
  } catch (enqueueError) {
@@ -27272,12 +27329,13 @@ async function readIteratorWithTimeout(iterator, timeoutMs) {
27272
27329
  * event: error
27273
27330
  * data: {"type":"error","error":{"type":"...","message":"..."}}
27274
27331
  */
27275
- function buildAnthropicErrorEvent(errName, errMessage) {
27332
+ function buildAnthropicErrorEvent(errName, errMessage, transportDetails) {
27333
+ const details = transportDetails ?? classifyNamedStreamError(errName, errMessage);
27276
27334
  const payload = {
27277
27335
  type: "error",
27278
27336
  error: {
27279
- type: classifyStreamError(errName),
27280
- message: `Upstream stream interrupted: ${errName}: ${errMessage}`
27337
+ type: classifyStreamError(details),
27338
+ message: formatStreamErrorMessage(details)
27281
27339
  }
27282
27340
  };
27283
27341
  return `event: error\ndata: ${JSON.stringify(payload)}\n\n`;
@@ -27287,24 +27345,42 @@ function buildAnthropicErrorEvent(errName, errMessage) {
27287
27345
  * followed by the `data: [DONE]` terminator that OpenAI clients expect.
27288
27346
  */
27289
27347
  function buildOpenAIErrorEvent(errName, errMessage) {
27348
+ const details = classifyNamedStreamError(errName, errMessage);
27290
27349
  const payload = { error: {
27291
- type: classifyStreamError(errName),
27292
- message: `Upstream stream interrupted: ${errName}: ${errMessage}`
27350
+ type: classifyStreamError(details),
27351
+ message: formatStreamErrorMessage(details)
27293
27352
  } };
27294
27353
  return `data: ${JSON.stringify(payload)}\n\ndata: [DONE]\n\n`;
27295
27354
  }
27296
- function classifyStreamError(errName) {
27297
- if (errName === "AbortError") return "timeout_error";
27298
- if (errName === "InactivityTimeout") return "timeout_error";
27355
+ function classifyNamedStreamError(errName, errMessage) {
27356
+ const error = Object.assign(new Error(errMessage), { name: errName });
27357
+ return classifyTransportError(error);
27358
+ }
27359
+ function classifyStreamError(details) {
27360
+ if (details.name === "AbortError" || details.name === "InactivityTimeout" || details.name === "TimeoutError" || details.name === "timeout_error") return "timeout_error";
27361
+ if (details.classification === "transient") return "overloaded_error";
27299
27362
  return "api_error";
27300
27363
  }
27301
- function logStreamError(routePath, error) {
27302
- const errName = error instanceof Error ? error.name : "Error";
27303
- const errMessage = error instanceof Error ? error.message : String(error);
27304
- consola.error(`Upstream stream interrupted at ${routePath}: errType=${errName} message=${JSON.stringify(errMessage)}`);
27364
+ function formatStreamErrorMessage(details) {
27365
+ const code = details.causeCode ?? details.code;
27366
+ const suffix = code ? ` (${sanitizeTransportText(code)})` : "";
27367
+ const diagnostic = `${sanitizeTransportText(details.name)}: ${sanitizeTransportText(details.message)}${suffix}`;
27368
+ if (details.classification === "transient") return `Upstream stream interrupted by a transient transport failure; retry the request. ${diagnostic}`;
27369
+ if (details.classification === "deterministic") return `Upstream stream interrupted by a connectivity or TLS configuration failure. ${diagnostic}`;
27370
+ return `Upstream stream interrupted: ${diagnostic}`;
27371
+ }
27372
+ function logStreamError(routePath, error, bytesRelayed) {
27373
+ const transport = classifyTransportError(error);
27374
+ const errName = transport.name;
27375
+ const errMessage = transport.message;
27376
+ const byteField = bytesRelayed === void 0 ? "" : ` bytes=${Math.max(0, bytesRelayed)}`;
27377
+ const codeField = transport.code ? ` code=${JSON.stringify(transport.code)}` : "";
27378
+ const causeCodeField = transport.causeCode ? ` causeCode=${JSON.stringify(transport.causeCode)}` : "";
27379
+ consola.error("Upstream stream interrupted", `routePath=${JSON.stringify(routePath)}${byteField} classification=${transport.classification} errType=${errName}${codeField}${causeCodeField} message=${JSON.stringify(errMessage)}`);
27305
27380
  return {
27306
27381
  errName,
27307
- errMessage
27382
+ errMessage,
27383
+ transport
27308
27384
  };
27309
27385
  }
27310
27386
  //#endregion
@@ -27656,10 +27732,11 @@ async function runAdvisor(conversation, advisorModel, advisorEffort, signal) {
27656
27732
  * against edge cases that would otherwise emit a malformed block —
27657
27733
  * spec violation in either direction is a 400.
27658
27734
  */
27659
- function toClientServerToolUseId(id, fallbackIndex) {
27660
- const suffix = id.startsWith("toolu_") ? id.slice(6) : id;
27661
- if (/^[a-zA-Z0-9_]+$/.test(suffix)) return `srvtoolu_${suffix}`;
27662
- return `srvtoolu_advisor_${fallbackIndex}`;
27735
+ function toClientServerToolUseId(id, _fallbackIndex) {
27736
+ if (!id.startsWith("toolu_")) throw new Error("advisor tool_use id is not round-trippable");
27737
+ const suffix = id.slice(6);
27738
+ if (!/^[a-zA-Z0-9_]+$/.test(suffix)) throw new Error("advisor tool_use id is not round-trippable");
27739
+ return `srvtoolu_${suffix}`;
27663
27740
  }
27664
27741
  /**
27665
27742
  * Build an SSE event line in the canonical Anthropic shape:
@@ -27695,6 +27772,7 @@ function buildAdvisorStream(opts) {
27695
27772
  let messageStartForwarded = false;
27696
27773
  let nextSyntheticIndex = 0;
27697
27774
  let turnsRun;
27775
+ let pendingMessageDelta = null;
27698
27776
  const safeEnqueue = (bytes) => {
27699
27777
  try {
27700
27778
  controller.enqueue(bytes);
@@ -27708,9 +27786,42 @@ function buildAdvisorStream(opts) {
27708
27786
  }
27709
27787
  };
27710
27788
  const safeEnqueueEvent = (type, data) => safeEnqueue(ENCODER.encode(sseEvent(type, data)));
27789
+ const captureMessageDelta = (payload) => {
27790
+ const delta = payload.delta && typeof payload.delta === "object" ? payload.delta : {};
27791
+ const usage = payload.usage && typeof payload.usage === "object" ? payload.usage : {};
27792
+ if (!pendingMessageDelta) pendingMessageDelta = {
27793
+ stopReason: delta.stop_reason ?? null,
27794
+ stopSequence: delta.stop_sequence ?? null,
27795
+ usage: {}
27796
+ };
27797
+ else {
27798
+ if (delta.stop_reason !== void 0) pendingMessageDelta.stopReason = delta.stop_reason;
27799
+ if (delta.stop_sequence !== void 0) pendingMessageDelta.stopSequence = delta.stop_sequence;
27800
+ }
27801
+ for (const [key, value] of Object.entries(usage)) if (typeof value === "number" && Number.isFinite(value)) pendingMessageDelta.usage[key] = (pendingMessageDelta.usage[key] ?? 0) + value;
27802
+ };
27803
+ const emitTerminal = (forcedStopReason) => {
27804
+ if (pendingMessageDelta || forcedStopReason) {
27805
+ const terminal = pendingMessageDelta ?? {
27806
+ stopReason: null,
27807
+ stopSequence: null,
27808
+ usage: {}
27809
+ };
27810
+ if (!safeEnqueueEvent("message_delta", {
27811
+ type: "message_delta",
27812
+ delta: {
27813
+ stop_reason: forcedStopReason ?? terminal.stopReason,
27814
+ stop_sequence: terminal.stopSequence
27815
+ },
27816
+ usage: terminal.usage
27817
+ })) return false;
27818
+ }
27819
+ return safeEnqueueEvent("message_stop", { type: "message_stop" });
27820
+ };
27711
27821
  async function processOneTurn(response) {
27712
27822
  const capturedBlocks = [];
27713
- let advisorToolUse = null;
27823
+ const advisorToolUses = [];
27824
+ let clientToolUseCount = 0;
27714
27825
  const indexToBlock = /* @__PURE__ */ new Map();
27715
27826
  for await (const ev of events(response)) {
27716
27827
  if (!ev.event || !ev.data) continue;
@@ -27720,7 +27831,8 @@ function buildAdvisorStream(opts) {
27720
27831
  } catch {
27721
27832
  if (!safeEnqueue(ENCODER.encode(`event: ${ev.event}\ndata: ${ev.data}\n\n`))) return {
27722
27833
  capturedBlocks,
27723
- advisorToolUse
27834
+ advisorToolUses,
27835
+ clientToolUseCount
27724
27836
  };
27725
27837
  continue;
27726
27838
  }
@@ -27729,7 +27841,8 @@ function buildAdvisorStream(opts) {
27729
27841
  if (!messageStartForwarded) {
27730
27842
  if (!safeEnqueueEvent(ev.event, payload)) return {
27731
27843
  capturedBlocks,
27732
- advisorToolUse
27844
+ advisorToolUses,
27845
+ clientToolUseCount
27733
27846
  };
27734
27847
  messageStartForwarded = true;
27735
27848
  }
@@ -27741,12 +27854,13 @@ function buildAdvisorStream(opts) {
27741
27854
  const myIndex = nextSyntheticIndex++;
27742
27855
  if (block.type === "tool_use" && block.name === "__anthropic_advisor") {
27743
27856
  const id = typeof block.id === "string" ? block.id : `toolu_advisor_${myIndex}`;
27744
- advisorToolUse = {
27857
+ const advisorToolUse = {
27745
27858
  index: myIndex,
27746
27859
  id,
27747
27860
  clientId: toClientServerToolUseId(id, myIndex),
27748
27861
  inputJson: ""
27749
27862
  };
27863
+ advisorToolUses.push(advisorToolUse);
27750
27864
  const translated = {
27751
27865
  ...payload,
27752
27866
  index: myIndex,
@@ -27759,7 +27873,8 @@ function buildAdvisorStream(opts) {
27759
27873
  };
27760
27874
  if (!safeEnqueueEvent(ev.event, translated)) return {
27761
27875
  capturedBlocks,
27762
- advisorToolUse
27876
+ advisorToolUses,
27877
+ clientToolUseCount
27763
27878
  };
27764
27879
  const captured = {
27765
27880
  block: {
@@ -27774,13 +27889,15 @@ function buildAdvisorStream(opts) {
27774
27889
  capturedBlocks.push(captured);
27775
27890
  indexToBlock.set(upstreamIndex, captured);
27776
27891
  } else {
27892
+ if (block.type === "tool_use") clientToolUseCount++;
27777
27893
  const reindexed = {
27778
27894
  ...payload,
27779
27895
  index: myIndex
27780
27896
  };
27781
27897
  if (!safeEnqueueEvent(ev.event, reindexed)) return {
27782
27898
  capturedBlocks,
27783
- advisorToolUse
27899
+ advisorToolUses,
27900
+ clientToolUseCount
27784
27901
  };
27785
27902
  const captured = {
27786
27903
  block: { ...block },
@@ -27803,7 +27920,8 @@ function buildAdvisorStream(opts) {
27803
27920
  };
27804
27921
  if (!safeEnqueueEvent(ev.event, reindexed)) return {
27805
27922
  capturedBlocks,
27806
- advisorToolUse
27923
+ advisorToolUses,
27924
+ clientToolUseCount
27807
27925
  };
27808
27926
  if (captured && delta) {
27809
27927
  if (delta.type === "text_delta" && typeof delta.text === "string") captured.block.text = (captured.block.text ?? "") + delta.text;
@@ -27817,7 +27935,8 @@ function buildAdvisorStream(opts) {
27817
27935
  }
27818
27936
  } else if (!safeEnqueueEvent(ev.event, payload)) return {
27819
27937
  capturedBlocks,
27820
- advisorToolUse
27938
+ advisorToolUses,
27939
+ clientToolUseCount
27821
27940
  };
27822
27941
  continue;
27823
27942
  }
@@ -27830,7 +27949,8 @@ function buildAdvisorStream(opts) {
27830
27949
  };
27831
27950
  if (!safeEnqueueEvent(ev.event, reindexed)) return {
27832
27951
  capturedBlocks,
27833
- advisorToolUse
27952
+ advisorToolUses,
27953
+ clientToolUseCount
27834
27954
  };
27835
27955
  if (captured) {
27836
27956
  if (captured.block.type === "tool_use" && captured.partialJson.length > 0) try {
@@ -27839,38 +27959,28 @@ function buildAdvisorStream(opts) {
27839
27959
  consola.warn(`advisor: malformed input_json_delta for tool_use id=${captured.block.id ?? "?"} name=${captured.block.name ?? "?"} partialJson.length=${captured.partialJson.length} parseError=${err instanceof Error ? err.message : String(err)}`);
27840
27960
  captured.block.input = {};
27841
27961
  }
27842
- if (captured.block.type === "text" && (typeof captured.block.text !== "string" || captured.block.text.length === 0)) captured.dropFromReplay = true;
27843
27962
  }
27844
27963
  continue;
27845
27964
  }
27846
27965
  case "message_delta":
27847
- if (!safeEnqueueEvent(ev.event, payload)) return {
27848
- capturedBlocks,
27849
- advisorToolUse
27850
- };
27966
+ captureMessageDelta(payload);
27851
27967
  continue;
27852
- case "message_stop":
27853
- if (advisorToolUse) return {
27854
- capturedBlocks,
27855
- advisorToolUse
27856
- };
27857
- if (!safeEnqueueEvent(ev.event, payload)) return {
27858
- capturedBlocks,
27859
- advisorToolUse
27860
- };
27861
- return {
27862
- capturedBlocks,
27863
- advisorToolUse
27864
- };
27968
+ case "message_stop": return {
27969
+ capturedBlocks,
27970
+ advisorToolUses,
27971
+ clientToolUseCount
27972
+ };
27865
27973
  default: if (!safeEnqueueEvent(ev.event, payload)) return {
27866
27974
  capturedBlocks,
27867
- advisorToolUse
27975
+ advisorToolUses,
27976
+ clientToolUseCount
27868
27977
  };
27869
27978
  }
27870
27979
  }
27871
27980
  return {
27872
27981
  capturedBlocks,
27873
- advisorToolUse
27982
+ advisorToolUses,
27983
+ clientToolUseCount
27874
27984
  };
27875
27985
  }
27876
27986
  try {
@@ -27878,13 +27988,16 @@ function buildAdvisorStream(opts) {
27878
27988
  for (turnsRun = 0; turnsRun < 16; turnsRun++) {
27879
27989
  if (aborter.signal.aborted) return;
27880
27990
  if (conversation === null) return;
27881
- const { capturedBlocks, advisorToolUse } = await processOneTurn(response);
27882
- if (!advisorToolUse) return;
27991
+ const { capturedBlocks, advisorToolUses, clientToolUseCount } = await processOneTurn(response);
27992
+ if (advisorToolUses.length === 0) {
27993
+ emitTerminal();
27994
+ return;
27995
+ }
27883
27996
  if (aborter.signal.aborted) return;
27884
27997
  if (conversation === null) return;
27885
27998
  const assistantTurn = {
27886
27999
  role: "assistant",
27887
- content: capturedBlocks.filter((c) => !c.dropFromReplay).map((c) => {
28000
+ content: capturedBlocks.map((c) => {
27888
28001
  if (c.advisorReplay) {
27889
28002
  const input = typeof c.block.input === "object" && c.block.input !== null ? c.block.input : {};
27890
28003
  return {
@@ -27898,41 +28011,55 @@ function buildAdvisorStream(opts) {
27898
28011
  })
27899
28012
  };
27900
28013
  conversation.push(assistantTurn);
27901
- let advisorText;
27902
- try {
27903
- advisorText = await runAdvisor(conversation, advisorModel, advisorEffort, aborter.signal);
27904
- } catch (err) {
27905
- if (aborter.signal.aborted) return;
27906
- const msg = err instanceof Error ? err.message : String(err);
27907
- consola.warn(`Advisor model call failed: ${msg}`);
27908
- advisorText = `[Advisor unavailable: ${msg}. Continuing without external review — proceed with caution and consider self-checking against your primary-source evidence.]`;
27909
- }
28014
+ const advisorConversation = conversation;
28015
+ const advisorTexts = await Promise.all(advisorToolUses.map(async () => {
28016
+ try {
28017
+ return await runAdvisor(advisorConversation, advisorModel, advisorEffort, aborter.signal);
28018
+ } catch (err) {
28019
+ if (aborter.signal.aborted) throw err;
28020
+ const msg = err instanceof Error ? err.message : String(err);
28021
+ consola.warn(`Advisor model call failed: ${msg}`);
28022
+ return `[Advisor unavailable: ${msg}. Continuing without external review — proceed with caution and consider self-checking against your primary-source evidence.]`;
28023
+ }
28024
+ })).catch((err) => {
28025
+ if (aborter.signal.aborted) return null;
28026
+ throw err;
28027
+ });
28028
+ if (!advisorTexts) return;
27910
28029
  if (aborter.signal.aborted) return;
27911
28030
  if (conversation === null) return;
27912
- const resultIndex = nextSyntheticIndex++;
27913
- if (!safeEnqueueEvent("content_block_start", {
27914
- type: "content_block_start",
27915
- index: resultIndex,
27916
- content_block: {
27917
- type: "advisor_tool_result",
27918
- tool_use_id: advisorToolUse.clientId,
27919
- content: {
27920
- type: "advisor_result",
27921
- text: advisorText
28031
+ for (let index = 0; index < advisorToolUses.length; index++) {
28032
+ const advisorToolUse = advisorToolUses[index];
28033
+ const advisorText = advisorTexts[index];
28034
+ const resultIndex = nextSyntheticIndex++;
28035
+ if (!safeEnqueueEvent("content_block_start", {
28036
+ type: "content_block_start",
28037
+ index: resultIndex,
28038
+ content_block: {
28039
+ type: "advisor_tool_result",
28040
+ tool_use_id: advisorToolUse.clientId,
28041
+ content: {
28042
+ type: "advisor_result",
28043
+ text: advisorText
28044
+ }
27922
28045
  }
27923
- }
27924
- })) return;
27925
- if (!safeEnqueueEvent("content_block_stop", {
27926
- type: "content_block_stop",
27927
- index: resultIndex
27928
- })) return;
28046
+ })) return;
28047
+ if (!safeEnqueueEvent("content_block_stop", {
28048
+ type: "content_block_stop",
28049
+ index: resultIndex
28050
+ })) return;
28051
+ }
28052
+ if (clientToolUseCount > 0) {
28053
+ emitTerminal("tool_use");
28054
+ return;
28055
+ }
27929
28056
  conversation.push({
27930
28057
  role: "user",
27931
- content: [{
28058
+ content: advisorToolUses.map((advisorToolUse, index) => ({
27932
28059
  type: "tool_result",
27933
28060
  tool_use_id: advisorToolUse.id,
27934
- content: advisorText
27935
- }]
28061
+ content: advisorTexts[index]
28062
+ }))
27936
28063
  });
27937
28064
  if (aborter.signal.aborted) return;
27938
28065
  response = await createMessages(JSON.stringify({
@@ -27963,7 +28090,7 @@ function buildAdvisorStream(opts) {
27963
28090
  type: "content_block_stop",
27964
28091
  index: finalIndex
27965
28092
  });
27966
- safeEnqueueEvent("message_stop", { type: "message_stop" });
28093
+ emitTerminal("end_turn");
27967
28094
  } catch (err) {
27968
28095
  if (aborter.signal.aborted) return;
27969
28096
  const msg = err instanceof Error ? err.message : String(err);
@@ -33284,7 +33411,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
33284
33411
  toolNameHttp: "explore",
33285
33412
  group: "workers",
33286
33413
  capability: "worker",
33287
- description: "Runs as the background `worker-explore` agent. Dispatch via the Agent tool (subagent_type: worker-explore) so the turn is never blocked; the result arrives as a completion notification. Read-only investigation by an autonomous worker (Pi runtime; default model `gemini-3.6-flash` at high reasoning, override via the `model` arg with any Copilot-catalog model that advertises `tool_calls`). It has read, glob, grep, semantic-first code search, web search, fetch_url, advisor, update_plan, and read-only toolbelt tools, and it returns a single text answer. Use for bounded research, repo discovery, dependency investigation, or multi-file reading that would otherwise consume the lead context window. Not for implementation, test authoring, or verification of a concrete diff; use implement, test, or review for those scopes. Brief the investigation goal and constraints, not step-by-step tool semantics.",
33414
+ description: "Runs as the background `worker-explore` agent. Dispatch via the Agent tool (subagent_type: worker-explore) so the turn is never blocked; the result arrives as a completion notification. Read-only investigation by an autonomous worker (Pi runtime; default model `gemini-3.6-flash` at high reasoning, override via the `model` arg with any Copilot-catalog model that advertises `tool_calls`). It has read, glob, grep, semantic-first code search, web search, fetch_url, advisor, update_plan, and read-only toolbelt tools, and it returns a single text answer. Use for bounded research, repo discovery, dependency investigation, or multi-file reading that would otherwise consume the lead context window. Not for implementation, test authoring, or verification of a concrete diff; use implement, test, or review for those scopes. Brief the investigation goal and constraints, not step-by-step tool semantics. Strictly read-only: it changes nothing on disk, and its returned text is the only artifact it produces — route to `implement` or `test` when a file actually needs to change. If the result is too large to relay it is truncated to a preview and the FULL text is written to a file, whose absolute path is in the returned text; read that file rather than re-running the worker.",
33288
33415
  inputSchema: {
33289
33416
  type: "object",
33290
33417
  required: ["prompt"],
@@ -33325,7 +33452,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
33325
33452
  toolNameHttp: "implement",
33326
33453
  group: "workers",
33327
33454
  capability: "worker",
33328
- description: "Runs as the background `worker-implement` agent. Dispatch via the Agent tool (subagent_type: worker-implement) so the turn is never blocked; the result arrives as a completion notification. Delegates a scoped coding task to an autonomous worker (Pi runtime; default model `gpt-5.6-sol` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the explore read-only tools plus edit, write, bash, and codex_review, and it returns its final text with any changed files or worktree diff. Use for bounded implementation work that may take a while or benefits from isolated worker context. Not for pure research, planning, review, or independent test authoring; use explore, plan, review, or test for those scopes. ALWAYS runs in an isolated git worktree and returns the diff via a saved patch file (a `--stat` summary + a bounded preview + the patch path; a small diff is inlined in full) — it never edits your working tree, and it HARD-ERRORS if the workspace is not a git repository. For in-place edits, use the native `implementer` subagent.",
33455
+ description: "Runs as the background `worker-implement` agent. Dispatch via the Agent tool (subagent_type: worker-implement) so the turn is never blocked; the result arrives as a completion notification. Delegates a scoped coding task to an autonomous worker (Pi runtime; default model `gpt-5.6-sol` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the explore read-only tools plus edit, write, bash, and codex_review, and it returns its final text with any changed files or worktree diff. Use for bounded implementation work that may take a while or benefits from isolated worker context. Not for pure research, planning, review, or independent test authoring; use explore, plan, review, or test for those scopes. ALWAYS runs in an isolated git worktree and returns the diff via a saved patch file (a `--stat` summary + a bounded preview + the patch path; a small diff is inlined in full) — it never edits your working tree, and it HARD-ERRORS if the workspace is not a git repository. For in-place edits, use the native `implementer` subagent. If the result is too large to relay it is truncated to a preview and the FULL text is written to a file, whose absolute path is in the returned text; read that file rather than re-running the worker.",
33329
33456
  inputSchema: {
33330
33457
  type: "object",
33331
33458
  required: ["prompt"],
@@ -33370,7 +33497,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
33370
33497
  toolNameHttp: "review",
33371
33498
  group: "workers",
33372
33499
  capability: "worker",
33373
- description: "Runs as the background `worker-review` agent. Dispatch via the Agent tool (subagent_type: worker-review) so the turn is never blocked; the result arrives as a completion notification. Read-only code review by an autonomous worker (Pi runtime; default model `gemini-3.1-pro-preview`, default thinking xhigh clamped to high for that model, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read-only toolset as explore and verifies claims against surrounding repository context before returning severity-ranked findings with `file:line` citations. Use for reviewing a change, diff, or correctness claim when the reviewer should read the code itself rather than trusting a pasted artifact. Not for architecture critique, implementation, or test authoring; use codex_critic or gemini_critic for design review, implement for edits, and test for independent test creation.",
33500
+ description: "Runs as the background `worker-review` agent. Dispatch via the Agent tool (subagent_type: worker-review) so the turn is never blocked; the result arrives as a completion notification. Read-only code review by an autonomous worker (Pi runtime; default model `gemini-3.1-pro-preview`, default thinking xhigh clamped to high for that model, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read-only toolset as explore and verifies claims against surrounding repository context before returning severity-ranked findings with `file:line` citations. Use for reviewing a change, diff, or correctness claim when the reviewer should read the code itself rather than trusting a pasted artifact. Not for architecture critique, implementation, or test authoring; use codex_critic or gemini_critic for design review, implement for edits, and test for independent test creation. Strictly read-only: it changes nothing on disk, and its returned text is the only artifact it produces — route to `implement` or `test` when a file actually needs to change. If the result is too large to relay it is truncated to a preview and the FULL text is written to a file, whose absolute path is in the returned text; read that file rather than re-running the worker.",
33374
33501
  inputSchema: {
33375
33502
  type: "object",
33376
33503
  required: ["prompt"],
@@ -33411,7 +33538,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
33411
33538
  toolNameHttp: "plan",
33412
33539
  group: "workers",
33413
33540
  capability: "worker",
33414
- description: "Runs as the background `worker-plan` agent. Dispatch via the Agent tool (subagent_type: worker-plan) so the turn is never blocked; the result arrives as a completion notification. Read-only implementation planning by an autonomous worker (Pi runtime; default model `claude-opus-5` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read-only toolset as explore and returns a concrete, ordered implementation plan covering files, approach, risks, and how acceptance criteria will be verified. Use before coding when the task needs repo-grounded sequencing or acceptance criteria translated into implementation steps. Not for editing files, running an implementation, writing tests, or adversarial review; use implement, test, or review for those scopes.",
33541
+ description: "Runs as the background `worker-plan` agent. Dispatch via the Agent tool (subagent_type: worker-plan) so the turn is never blocked; the result arrives as a completion notification. Read-only implementation planning by an autonomous worker (Pi runtime; default model `claude-opus-5` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read-only toolset as explore and returns a concrete, ordered implementation plan covering files, approach, risks, and how acceptance criteria will be verified. Use before coding when the task needs repo-grounded sequencing or acceptance criteria translated into implementation steps. Not for editing files, running an implementation, writing tests, or adversarial review; use implement, test, or review for those scopes. Strictly read-only: it changes nothing on disk, and its returned text is the only artifact it produces — route to `implement` or `test` when a file actually needs to change. If the result is too large to relay it is truncated to a preview and the FULL text is written to a file, whose absolute path is in the returned text; read that file rather than re-running the worker.",
33415
33542
  inputSchema: {
33416
33543
  type: "object",
33417
33544
  required: ["prompt"],
@@ -33452,7 +33579,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
33452
33579
  toolNameHttp: "test",
33453
33580
  group: "workers",
33454
33581
  capability: "worker",
33455
- description: "Runs as the background `worker-test` agent. Dispatch via the Agent tool (subagent_type: worker-test) so the turn is never blocked; the result arrives as a completion notification. Independent adversarial test authoring by an autonomous worker (Pi runtime; default model `gpt-5.6-sol` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read/write toolset as implement and writes tests that try to break the implementation through edge cases, error paths, and acceptance criteria, then runs them and reports pass/fail. Use when a separate test author should challenge an implementation without modifying the production code to make tests pass. Not for implementing fixes, broad research, or code review; use implement, explore, or review for those scopes. ALWAYS runs in an isolated git worktree and returns the test diff via a saved patch file (a `--stat` summary + a bounded preview + the patch path; a small diff is inlined in full) — it never edits your working tree, and it HARD-ERRORS if the workspace is not a git repository. For in-place test authoring, use the native `implementer` subagent.",
33582
+ description: "Runs as the background `worker-test` agent. Dispatch via the Agent tool (subagent_type: worker-test) so the turn is never blocked; the result arrives as a completion notification. Independent adversarial test authoring by an autonomous worker (Pi runtime; default model `gpt-5.6-sol` at xhigh reasoning, override via `model` with any Copilot-catalog model that advertises `tool_calls`). It has the same read/write toolset as implement and writes tests that try to break the implementation through edge cases, error paths, and acceptance criteria, then runs them and reports pass/fail. Use when a separate test author should challenge an implementation without modifying the production code to make tests pass. Not for implementing fixes, broad research, or code review; use implement, explore, or review for those scopes. ALWAYS runs in an isolated git worktree and returns the test diff via a saved patch file (a `--stat` summary + a bounded preview + the patch path; a small diff is inlined in full) — it never edits your working tree, and it HARD-ERRORS if the workspace is not a git repository. For in-place test authoring, use the native `implementer` subagent. If the result is too large to relay it is truncated to a preview and the FULL text is written to a file, whose absolute path is in the returned text; read that file rather than re-running the worker.",
33456
33583
  inputSchema: {
33457
33584
  type: "object",
33458
33585
  required: ["prompt"],
@@ -33699,7 +33826,7 @@ const NON_PERSONA_MCP_TOOLS = Object.freeze([
33699
33826
  toolNameHttp: "browse",
33700
33827
  group: "workers",
33701
33828
  capability: "browse_agent",
33702
- description: "Runs as the background `worker-browse` agent. Dispatch via the Agent tool (subagent_type: worker-browse) so the turn is never blocked; the result arrives as a completion notification. A Pi-driven autonomous browser worker (default model `gpt-5.4-mini`) drives a real browser to accomplish `task`, keeps raw DOM and page snapshots inside its own context, and returns a single text result. Use for delegated multi-step web tasks such as comparing prices, logging into a dashboard, or summarizing pages when the lead does not need to steer each click. Not for direct in-context browser control, screenshots, or precise element interactions; use the `browser` MCP tools for those. Pass `sessionId` to continue a prior browse session, or omit it for a fresh isolated session; multiple calls run as parallel sessions on the shared browser.",
33829
+ description: "Runs as the background `worker-browse` agent. Dispatch via the Agent tool (subagent_type: worker-browse) so the turn is never blocked; the result arrives as a completion notification. A Pi-driven autonomous browser worker (default model `gpt-5.4-mini`) drives a real browser to accomplish `task`, keeps raw DOM and page snapshots inside its own context, and returns a single text result. Use for delegated multi-step web tasks such as comparing prices, logging into a dashboard, or summarizing pages when the lead does not need to steer each click. Not for direct in-context browser control, screenshots, or precise element interactions; use the `browser` MCP tools for those. Pass `sessionId` to continue a prior browse session, or omit it for a fresh isolated session; multiple calls run as parallel sessions on the shared browser. If the result is too large to relay it is truncated to a preview and the FULL text is written to a file, whose absolute path is in the returned text; read that file rather than re-running the worker.",
33703
33830
  inputSchema: {
33704
33831
  type: "object",
33705
33832
  required: ["task"],
@@ -34160,4 +34287,4 @@ function enumerateInjectedMcpToolNames(groupKeys, opts = {}) {
34160
34287
  //#endregion
34161
34288
  export { reviewerModel as $, searchWeb as A, DEFAULT_CODEX_MODEL_FALLBACKS as At, readIteratorWithTimeout as B, buildToolbeltAwareness as C, CONDENSED_OPERATING_SEQUENCE as Ct, TOOLBELT_TOOLS$1 as D, toolbeltPathOverride as Dt, vscodeRipgrepPath as E, collapsePathKeys as Et, isAdvisorRequested as F, pickClaudeDefault as Ft, artifactToolsEnabled as G, handleMcpDelete as H, buildAnthropicErrorEvent as I, withOneMSuffix as It, browserCompoundToolsEnabled as J, brainstormModel as K, buildOpenAIErrorEvent as L, withInstallLock as Lt, ADVISOR_TOOL_INSTRUCTIONS as M, UPSTREAM_FETCH_TIMEOUT_MS as Mt, buildAdvisorStream as N, UPSTREAM_INACTIVITY_TIMEOUT_MS as Nt, assetFor as O, DEFAULT_CLAUDE_MODEL_FALLBACKS as Ot, injectAdvisorTool as P, generateRandomPort as Pt, nativeSubagentModel as Q, isControllerClosedError as R, availableToolCommands as S, warmTreeSitterPool as St, toolbeltSkipSet as T, shouldUseInsecureTls as Tt, handleMcpPost as U, relayAnthropicStream as V, agentToolsEnabled as W, fleetToolsEnabled as X, browserToolsEnabled as Y, geminiAvailable as Z, appendPlanReminder as _, hasSupportedBrowserInstalled as _t, buildPeerAwarenessSnippet as a, countTokens as at, runWorkerAgent as b, extractTarGzMember as bt, personasFor as c, assembleResponsesPayload as ct, EXPLORE_DEFAULT_MODEL as d, createResponses as dt, scoutModel as et, EXPLORE_DEFAULT_THINKING as f, createChatCompletions as ft, TEST_DEFAULT_MODEL as g, provisionBrowserAssets as gt, REVIEW_DEFAULT_MODEL as h, parseJsonOrDiagnose as ht, buildAgentPrompt as i, shimDefaultsToXhigh as it, ADVISOR_INTERNAL_TOOL_NAME as j, DEFAULT_PORT as jt, satisfiesMinVersion as k, DEFAULT_CODEX_MODEL as kt, BROWSE_DEFAULT_MODEL as l, resolveMcpToolTimeoutMs as lt, PLAN_DEFAULT_MODEL as m, readResponseBodyCapped as mt, MCP_GROUPS as n, standInToolEnabled as nt, buildPeerAwarenessSummary as o, createMessages as ot, IMPLEMENT_DEFAULT_MODEL as p, MAX_RESPONSE_BODY_BYTES as pt, browseAgentEnabled as q, assertMcpToolSurfaceConsistent as r, workerToolsEnabled as rt, enumerateInjectedMcpToolNames as s, getTokenCount as st, GROUP_META as t, scribeModel as tt, DEFAULT_MODEL as u, pickEndpoint as ut, resolveModeDefaults as v, colbertDegradedWarning as vt, toolbeltEnabled as w, DEFINITION_OF_GREATNESS as wt, buildEnv as x, extractZipMember as xt, resolveWorkerRunOpts as y, provisionAndIndexColbert as yt, logStreamError as z };
34162
34289
 
34163
- //# sourceMappingURL=peer-mcp-personas-B22ncnbQ.js.map
34290
+ //# sourceMappingURL=peer-mcp-personas-pWP3Eyt7.js.map