github-router 0.3.270 → 0.3.273

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 (38) hide show
  1. package/dist/{attribution-settings-of5gJM5a.js → attribution-settings-4nEQq_tn.js} +3 -3
  2. package/dist/{attribution-settings-of5gJM5a.js.map → attribution-settings-4nEQq_tn.js.map} +1 -1
  3. package/dist/{auth-DIFbHOu0.js → auth-3so8RT91.js} +2 -2
  4. package/dist/{auth-DIFbHOu0.js.map → auth-3so8RT91.js.map} +1 -1
  5. package/dist/browser-ext/manifest.json +1 -1
  6. package/dist/{check-usage-DfnrR-d_.js → check-usage-goXyc3qS.js} +3 -3
  7. package/dist/{check-usage-DfnrR-d_.js.map → check-usage-goXyc3qS.js.map} +1 -1
  8. package/dist/{claude-BlzCUbVq.js → claude-BNZD-bQN.js} +7 -7
  9. package/dist/{claude-BlzCUbVq.js.map → claude-BNZD-bQN.js.map} +1 -1
  10. package/dist/{codex-BaFcXOyg.js → codex-C_MA9uy5.js} +5 -5
  11. package/dist/{codex-BaFcXOyg.js.map → codex-C_MA9uy5.js.map} +1 -1
  12. package/dist/engine-CHN8j6BV.js +2 -0
  13. package/dist/{gate-discovery-AUAjqSpV.js → gate-discovery-DvA4xObh.js} +2 -2
  14. package/dist/{gate-discovery-AUAjqSpV.js.map → gate-discovery-DvA4xObh.js.map} +1 -1
  15. package/dist/{get-copilot-usage-Ds09xSmH.js → get-copilot-usage-nZXbvSi8.js} +2 -2
  16. package/dist/{get-copilot-usage-Ds09xSmH.js.map → get-copilot-usage-nZXbvSi8.js.map} +1 -1
  17. package/dist/{internal-stop-hook-B1MIwmTR.js → internal-stop-hook-WVgnwt5U.js} +2 -2
  18. package/dist/{internal-stop-hook-B1MIwmTR.js.map → internal-stop-hook-WVgnwt5U.js.map} +1 -1
  19. package/dist/main.js +8 -8
  20. package/dist/{models-BFQUp0ov.js → models-BmGGH6pP.js} +2 -2
  21. package/dist/{models-BFQUp0ov.js.map → models-BmGGH6pP.js.map} +1 -1
  22. package/dist/{peer-mcp-personas-pWP3Eyt7.js → peer-mcp-personas-DAZU1OfN.js} +331 -20
  23. package/dist/peer-mcp-personas-DAZU1OfN.js.map +1 -0
  24. package/dist/{provision-CsYUVdMT.js → provision-C3UIA1Tf.js} +2 -2
  25. package/dist/{provision-CsYUVdMT.js.map → provision-C3UIA1Tf.js.map} +1 -1
  26. package/dist/{serve--c9n9hk4.js → serve-DPgawWWq.js} +6 -6
  27. package/dist/{serve--c9n9hk4.js.map → serve-DPgawWWq.js.map} +1 -1
  28. package/dist/{server-setup-BmyWS4WU.js → server-setup-I5KYkuxE.js} +570 -121
  29. package/dist/server-setup-I5KYkuxE.js.map +1 -0
  30. package/dist/{start-CXnLBouJ.js → start-CWWqjjwm.js} +3 -3
  31. package/dist/{start-CXnLBouJ.js.map → start-CWWqjjwm.js.map} +1 -1
  32. package/dist/{token-iaSGp76k.js → token-Bz7iN8US.js} +74 -6
  33. package/dist/token-Bz7iN8US.js.map +1 -0
  34. package/package.json +2 -1
  35. package/dist/engine-mwIgHJoi.js +0 -2
  36. package/dist/peer-mcp-personas-pWP3Eyt7.js.map +0 -1
  37. package/dist/server-setup-BmyWS4WU.js.map +0 -1
  38. package/dist/token-iaSGp76k.js.map +0 -1
@@ -1,11 +1,11 @@
1
1
  import { t as getPackageVersion } from "./version-_Q1WpsQp.js";
2
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";
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-Bz7iN8US.js";
4
4
  import { a as resolveExecutable, c as runManagedExeCapture, i as parseIntEnv, l as spawnTaskkillBestEffort, r as parseBoolEnv } from "./exec-y8C_MU8A.js";
5
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-AgNOtFRv.js";
8
+ import { n as isPidAlive$1, r as registerColbertExitHandlers, s as trackChild, t as getColbertInstanceUuid } from "./lifecycle-AgNOtFRv.js";
9
9
  import { h as runGateChecks, m as sealedGateIds, p as resolveSealedGate } from "./stop-gate-hook-BqpumJtl.js";
10
10
  import { t as liveExec } from "./orchestration-B_Q3ncXI.js";
11
11
  import { createRequire } from "node:module";
@@ -272,6 +272,12 @@ function envInt$1(key, fallback) {
272
272
  }
273
273
  const UPSTREAM_FETCH_TIMEOUT_MS = envInt$1("UPSTREAM_FETCH_TIMEOUT_MS", 0);
274
274
  const UPSTREAM_INACTIVITY_TIMEOUT_MS = envInt$1("UPSTREAM_INACTIVITY_TIMEOUT_MS", 3e5);
275
+ function upstreamAllowH2() {
276
+ return process.env.GH_ROUTER_UPSTREAM_ALLOW_H2 === "1";
277
+ }
278
+ function upstreamMaxConnections() {
279
+ return envInt$1("GH_ROUTER_UPSTREAM_MAX_CONNECTIONS", 256);
280
+ }
275
281
  //#endregion
276
282
  //#region src/lib/toolbelt/path-inject.ts
277
283
  /**
@@ -4966,19 +4972,19 @@ function resolveTierModel(tier) {
4966
4972
  }
4967
4973
  //#endregion
4968
4974
  //#region src/lib/first-mate/classifier.ts
4969
- function isRecord$1(value) {
4975
+ function isRecord$2(value) {
4970
4976
  return typeof value === "object" && value !== null && !Array.isArray(value);
4971
4977
  }
4972
4978
  function firstMessageContent$1(value) {
4973
- if (!isRecord$1(value) || !Array.isArray(value.choices)) return null;
4979
+ if (!isRecord$2(value) || !Array.isArray(value.choices)) return null;
4974
4980
  const first = value.choices[0];
4975
- if (!isRecord$1(first) || !isRecord$1(first.message)) return null;
4981
+ if (!isRecord$2(first) || !isRecord$2(first.message)) return null;
4976
4982
  return typeof first.message.content === "string" ? first.message.content : null;
4977
4983
  }
4978
4984
  function parseJsonObject(value) {
4979
4985
  try {
4980
4986
  const parsed = JSON.parse(value);
4981
- return isRecord$1(parsed) ? parsed : null;
4987
+ return isRecord$2(parsed) ? parsed : null;
4982
4988
  } catch {
4983
4989
  return null;
4984
4990
  }
@@ -5048,7 +5054,7 @@ async function classifyPlanReady(logExcerpt) {
5048
5054
  schemaHint: "{\"planReady\":boolean,\"planExcerpt\":\"<=1200 chars from the completed plan, or empty\",\"confidence\":number}",
5049
5055
  maxTokens: 500,
5050
5056
  validate(value) {
5051
- if (!isRecord$1(value)) return null;
5057
+ if (!isRecord$2(value)) return null;
5052
5058
  const planReady = booleanValue$1(value.planReady);
5053
5059
  const planExcerpt = stringValue$1(value.planExcerpt);
5054
5060
  if (planReady === null || planExcerpt === null) return null;
@@ -5065,7 +5071,7 @@ async function classifyQuestionAnswerable(question, acceptanceCriteria) {
5065
5071
  user: `Acceptance criteria:\n${acceptanceCriteria}\n\nAgent question:\n${question}`,
5066
5072
  schemaHint: "{\"answerable\":boolean,\"answer\":\"present only when answerable\",\"confidence\":number}",
5067
5073
  validate(value) {
5068
- if (!isRecord$1(value)) return null;
5074
+ if (!isRecord$2(value)) return null;
5069
5075
  const answerable = booleanValue$1(value.answerable);
5070
5076
  if (answerable === null) return null;
5071
5077
  const answer = stringValue$1(value.answer);
@@ -5083,7 +5089,7 @@ async function classifyFixAddressed(failureSummary, latestLogExcerpt) {
5083
5089
  user: `Failure summary:\n${failureSummary}\n\nLatest log excerpt:\n${latestLogExcerpt}`,
5084
5090
  schemaHint: "{\"addressed\":boolean,\"confidence\":number}",
5085
5091
  validate(value) {
5086
- if (!isRecord$1(value)) return null;
5092
+ if (!isRecord$2(value)) return null;
5087
5093
  const addressed = booleanValue$1(value.addressed);
5088
5094
  return addressed === null ? null : { addressed };
5089
5095
  }
@@ -5095,7 +5101,7 @@ async function classifyStuck(logExcerpt) {
5095
5101
  user: `Log excerpt:\n${logExcerpt}`,
5096
5102
  schemaHint: "{\"stuck\":boolean,\"confidence\":number}",
5097
5103
  validate(value) {
5098
- if (!isRecord$1(value)) return null;
5104
+ if (!isRecord$2(value)) return null;
5099
5105
  const stuck = booleanValue$1(value.stuck);
5100
5106
  return stuck === null ? null : { stuck };
5101
5107
  }
@@ -9975,6 +9981,40 @@ const WIN_RENAME_TRANSIENT = /* @__PURE__ */ new Set([
9975
9981
  "EBUSY"
9976
9982
  ]);
9977
9983
  /**
9984
+ * Owner pid embedded in a `.draining.<pid>.<rand>` or `.claim.<pid>.<rand>`
9985
+ * segment. A file can carry both (a claimed orphan keeps the drain segment), so
9986
+ * the LAST match is the current owner.
9987
+ */
9988
+ const OWNER_SEGMENT_RE = /\.(?:draining|claim)\.(\d+)\./g;
9989
+ /**
9990
+ * Claims held by a live drainer in THIS process, across instances. Per-instance
9991
+ * `inflight` cannot see a peer instance's claim, and both share our pid, so pid
9992
+ * liveness cannot separate them either. A claim abandoned on a read error is
9993
+ * never added here, which is what keeps it replayable (R3 #4).
9994
+ */
9995
+ const heldClaims = /* @__PURE__ */ new Set();
9996
+ function ownerPidOf(name) {
9997
+ let pid;
9998
+ for (const match of name.matchAll(OWNER_SEGMENT_RE)) pid = Number(match[1]);
9999
+ return pid !== void 0 && Number.isInteger(pid) && pid > 0 ? pid : void 0;
10000
+ }
10001
+ /**
10002
+ * `process.kill(pid, 0)` probes existence without signalling; `EPERM` means the
10003
+ * process exists but is owned by another user (still alive). Mirrors the copies
10004
+ * in `lib/paths.ts`, `lib/colbert/lifecycle.ts`, and `lib/worker-agent/
10005
+ * lifecycle.ts` — kept local so first-mate takes no dependency on those modules.
10006
+ */
10007
+ function isPidAlive(pid) {
10008
+ if (!Number.isInteger(pid) || pid <= 0) return false;
10009
+ try {
10010
+ process.kill(pid, 0);
10011
+ return true;
10012
+ } catch (err) {
10013
+ if (err.code === "EPERM") return true;
10014
+ return false;
10015
+ }
10016
+ }
10017
+ /**
9978
10018
  * Atomically claim `from` by renaming it to the process-unique `to`.
9979
10019
  * Returns `true` if THIS caller won the claim, `false` if a peer already took it
9980
10020
  * (source gone). Retries transient Windows sharing violations so two concurrent
@@ -10070,6 +10110,9 @@ var AnswerInbox = class {
10070
10110
  if (!name.startsWith(`${base}.draining.`)) continue;
10071
10111
  const orphan = path.join(dir, name);
10072
10112
  if (this.inflight.has(orphan)) continue;
10113
+ if (heldClaims.has(orphan)) continue;
10114
+ const owner = ownerPidOf(name);
10115
+ if (owner !== void 0 && owner !== process.pid && isPidAlive(owner)) continue;
10073
10116
  const claim = `${orphan}.claim.${process.pid}.${randomBytes(4).toString("hex")}`;
10074
10117
  if (!await claimByRename(orphan, claim)) continue;
10075
10118
  try {
@@ -10086,11 +10129,15 @@ var AnswerInbox = class {
10086
10129
  } catch (err) {
10087
10130
  if (err.code !== "ENOENT") consola.warn(`first-mate: deferring unreadable inbox claim ${target} for retry:`, err);
10088
10131
  }
10089
- for (const p of claimed) this.inflight.add(p);
10132
+ for (const p of claimed) {
10133
+ this.inflight.add(p);
10134
+ heldClaims.add(p);
10135
+ }
10090
10136
  const ack = async () => {
10091
10137
  for (const p of claimed) {
10092
10138
  await fs$1.unlink(p).catch(() => {});
10093
10139
  this.inflight.delete(p);
10140
+ heldClaims.delete(p);
10094
10141
  }
10095
10142
  };
10096
10143
  return {
@@ -11499,7 +11546,7 @@ function parsePackageJson(text) {
11499
11546
  if (text === void 0) return void 0;
11500
11547
  try {
11501
11548
  const parsed = JSON.parse(text);
11502
- if (!isRecord(parsed)) return void 0;
11549
+ if (!isRecord$1(parsed)) return void 0;
11503
11550
  return {
11504
11551
  scripts: stringRecord(parsed.scripts),
11505
11552
  dependencies: stringRecord(parsed.dependencies),
@@ -11699,11 +11746,11 @@ function buildScaffoldPrBody(reports) {
11699
11746
  "No factory protocol files are seeded; orchestration remains external to the repository."
11700
11747
  ].join("\n");
11701
11748
  }
11702
- function isRecord(value) {
11749
+ function isRecord$1(value) {
11703
11750
  return typeof value === "object" && value !== null && !Array.isArray(value);
11704
11751
  }
11705
11752
  function stringRecord(value) {
11706
- if (!isRecord(value)) return {};
11753
+ if (!isRecord$1(value)) return {};
11707
11754
  const result = {};
11708
11755
  for (const [key, entry] of Object.entries(value)) if (typeof entry === "string") result[key] = entry;
11709
11756
  return result;
@@ -15779,7 +15826,7 @@ async function freshnessVerdict(workspace) {
15779
15826
  };
15780
15827
  if (meta.status === "building") {
15781
15828
  const pid = typeof meta.buildPid === "number" ? meta.buildPid : 0;
15782
- if (isInitInFlight(workspace) || pid > 0 && isPidAlive(pid)) return {
15829
+ if (isInitInFlight(workspace) || pid > 0 && isPidAlive$1(pid)) return {
15783
15830
  verdict: "building",
15784
15831
  meta
15785
15832
  };
@@ -27358,7 +27405,6 @@ function classifyNamedStreamError(errName, errMessage) {
27358
27405
  }
27359
27406
  function classifyStreamError(details) {
27360
27407
  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";
27362
27408
  return "api_error";
27363
27409
  }
27364
27410
  function formatStreamErrorMessage(details) {
@@ -27384,6 +27430,255 @@ function logStreamError(routePath, error, bytesRelayed) {
27384
27430
  };
27385
27431
  }
27386
27432
  //#endregion
27433
+ //#region src/lib/thinking-history-repair.ts
27434
+ const THINKING_INTEGRITY_ERROR_RES = [/messages\.(\d+)\.content\.(\d+):\s*`thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified/, /messages\.(\d+)\.content\.(\d+):\s*Invalid `signature` in `thinking` block/];
27435
+ const MAX_REMEMBERED_REPAIRS = 1e3;
27436
+ const OMITTED_THINKING_PLACEHOLDER = "[prior reasoning omitted]";
27437
+ const repairSalt = randomBytes(32);
27438
+ const rememberedRepairs = /* @__PURE__ */ new Set();
27439
+ function declined(reason, detail = {}) {
27440
+ return {
27441
+ ok: false,
27442
+ decline: {
27443
+ reason,
27444
+ ...detail
27445
+ }
27446
+ };
27447
+ }
27448
+ /** Render a decline as a single log-safe `key=value` line. */
27449
+ function formatThinkingRepairDecline(decline) {
27450
+ return Object.entries(decline).filter(([, value]) => value !== void 0).map(([key, value]) => `${key}=${String(value)}`).join(" ");
27451
+ }
27452
+ function isRecord(value) {
27453
+ return typeof value === "object" && value !== null;
27454
+ }
27455
+ /** Count signed blocks without hashing — used only to explain a decline. */
27456
+ function countSignedBlocks(content) {
27457
+ return content.filter((block) => isRecord(block) && (block.type === "thinking" || block.type === "redacted_thinking")).length;
27458
+ }
27459
+ function signedBlockFingerprint(_messageIndex, content) {
27460
+ const hash = createHash("sha256");
27461
+ hash.update(repairSalt);
27462
+ let signedBlocks = 0;
27463
+ for (let index = 0; index < content.length; index++) {
27464
+ const block = content[index];
27465
+ if (!isRecord(block)) continue;
27466
+ if (block.type !== "thinking" && block.type !== "redacted_thinking") continue;
27467
+ signedBlocks++;
27468
+ hash.update(String(index));
27469
+ hash.update(String(block.type));
27470
+ if (typeof block.signature === "string") hash.update(block.signature);
27471
+ if (typeof block.data === "string") hash.update(block.data);
27472
+ }
27473
+ return signedBlocks > 0 ? hash.digest("hex") : void 0;
27474
+ }
27475
+ function repairAtArrayIndex(parsed, messageIndex) {
27476
+ if (!Array.isArray(parsed.messages)) return declined("no-messages-array", { messageIndex });
27477
+ const messages = [...parsed.messages];
27478
+ const detail = {
27479
+ messageIndex,
27480
+ messageCount: messages.length
27481
+ };
27482
+ const message = messages[messageIndex];
27483
+ if (!isRecord(message)) return declined("message-missing", detail);
27484
+ if (message.role !== "assistant") return declined("message-not-assistant", {
27485
+ ...detail,
27486
+ roleAtIndex: typeof message.role === "string" ? message.role : "unknown"
27487
+ });
27488
+ if (!Array.isArray(message.content)) return declined("content-not-array", {
27489
+ ...detail,
27490
+ roleAtIndex: "assistant"
27491
+ });
27492
+ const shape = {
27493
+ ...detail,
27494
+ roleAtIndex: "assistant",
27495
+ blocksAtIndex: message.content.length,
27496
+ signedBlocksAtIndex: countSignedBlocks(message.content)
27497
+ };
27498
+ const fingerprint = signedBlockFingerprint(messageIndex, message.content);
27499
+ if (!fingerprint) return declined("no-signed-blocks", shape);
27500
+ const repairedContent = message.content.filter((block) => !isRecord(block) || block.type !== "thinking" && block.type !== "redacted_thinking");
27501
+ const removedBlocks = message.content.length - repairedContent.length;
27502
+ if (removedBlocks === 0) return declined("no-blocks-removed", shape);
27503
+ if (repairedContent.length === 0) repairedContent.push({
27504
+ type: "text",
27505
+ text: OMITTED_THINKING_PLACEHOLDER
27506
+ });
27507
+ messages[messageIndex] = {
27508
+ ...message,
27509
+ content: repairedContent
27510
+ };
27511
+ parsed.messages = messages;
27512
+ return {
27513
+ ok: true,
27514
+ repair: {
27515
+ body: JSON.stringify(parsed),
27516
+ fingerprint,
27517
+ messageIndex,
27518
+ removedBlocks
27519
+ }
27520
+ };
27521
+ }
27522
+ /** Roles in order, for a decline log. Roles only, so it carries no content. */
27523
+ function roleSequenceOf(messages) {
27524
+ return messages.map((message) => isRecord(message) && typeof message.role === "string" ? message.role : "unknown").join(",");
27525
+ }
27526
+ /** Elements upstream would not count as a conversation turn. */
27527
+ function isHoistedElement(message) {
27528
+ if (!isRecord(message)) return false;
27529
+ return message.role !== "user" && message.role !== "assistant";
27530
+ }
27531
+ /**
27532
+ * Translate an upstream-reported message index into an index in THIS array,
27533
+ * skipping elements upstream would not have counted.
27534
+ *
27535
+ * Anthropic's Messages schema has no in-array `system` role, yet clients do
27536
+ * send one, and upstream evidently accepts it and drops it before validating —
27537
+ * which shifts every index after it. Returns undefined when nothing is hoisted
27538
+ * (the mapping would be the identity) or when the target does not exist.
27539
+ */
27540
+ function hoistAdjustedIndex(messages, reportedIndex) {
27541
+ let retained = 0;
27542
+ for (let index = 0; index < messages.length; index++) {
27543
+ if (isHoistedElement(messages[index])) continue;
27544
+ if (retained === reportedIndex) return index === reportedIndex ? void 0 : index;
27545
+ retained++;
27546
+ }
27547
+ }
27548
+ /** True when `content[contentIndex]` is a signed thinking block. */
27549
+ function hasSignedBlockAt(content, contentIndex) {
27550
+ if (!Array.isArray(content)) return false;
27551
+ const block = content[contentIndex];
27552
+ if (!isRecord(block)) return false;
27553
+ return block.type === "thinking" || block.type === "redacted_thinking";
27554
+ }
27555
+ /**
27556
+ * Resolve the message upstream named, then repair it.
27557
+ *
27558
+ * DIRECT INDEX FIRST, hoist-adjusted index only as a fallback. The ordering is
27559
+ * the whole safety argument: every request that repairs correctly today takes
27560
+ * the direct path untouched, and the adjusted path runs only where the code
27561
+ * would otherwise have declined outright. Mapping first would REGRESS a working
27562
+ * case — with `[user, system, assistant]` and upstream naming `messages.2`, the
27563
+ * direct lookup repairs the assistant turn correctly while a retained-role
27564
+ * mapping yields only `[user, assistant]` and runs off the end.
27565
+ *
27566
+ * The fallback is self-validating rather than trusted: it is accepted only if
27567
+ * the block upstream actually named is a signed thinking block at the adjusted
27568
+ * position. If the index shift has some other cause, that check fails and the
27569
+ * original decline stands, so a wrong hypothesis fails closed instead of
27570
+ * stripping blocks from an innocent turn.
27571
+ */
27572
+ /** True when `index` names an assistant carrying the block upstream reported. */
27573
+ function namesReportedBlock(messages, index, contentIndex) {
27574
+ const message = messages[index];
27575
+ if (!isRecord(message) || message.role !== "assistant") return false;
27576
+ return hasSignedBlockAt(message.content, contentIndex);
27577
+ }
27578
+ /**
27579
+ * Resolve the message upstream named, then repair it.
27580
+ *
27581
+ * When nothing is hoisted, this array and upstream's are indexed alike, so the
27582
+ * reported index is used directly — the identity case, and the overwhelming
27583
+ * majority of traffic, whose behaviour is unchanged.
27584
+ *
27585
+ * When something IS hoisted, the two arrays provably disagree and the reported
27586
+ * index alone cannot say which turn was meant. Both the raw index and the
27587
+ * hoist-adjusted one can land on a signed assistant, and picking the raw one
27588
+ * blind would strip a healthy turn while leaving the corrupt one in place. So
27589
+ * the block index upstream reported is used as the tiebreak: whichever
27590
+ * candidate actually carries a signed block THERE is the one repaired. If both
27591
+ * do, the request is genuinely ambiguous and we decline — the client sees the
27592
+ * same 400 it would have seen anyway, with no innocent turn rewritten.
27593
+ */
27594
+ function repairMessageAt(parsed, messageIndex, contentIndex) {
27595
+ if (!Array.isArray(parsed.messages)) return repairAtArrayIndex(parsed, messageIndex);
27596
+ const messages = parsed.messages;
27597
+ const hoistedCount = messages.filter((m) => isHoistedElement(m)).length;
27598
+ const mapped = hoistedCount === 0 ? void 0 : hoistAdjustedIndex(messages, messageIndex);
27599
+ const annotate = (outcome, extra = {}) => outcome.ok ? outcome : declined(outcome.decline.reason, {
27600
+ ...outcome.decline,
27601
+ hoistedCount,
27602
+ roleSequence: roleSequenceOf(messages),
27603
+ ...extra
27604
+ });
27605
+ if (hoistedCount === 0 || contentIndex === void 0 || mapped === void 0) return annotate(repairAtArrayIndex(parsed, messageIndex));
27606
+ const directNames = namesReportedBlock(messages, messageIndex, contentIndex);
27607
+ const mappedNames = namesReportedBlock(messages, mapped, contentIndex);
27608
+ if (directNames && mappedNames) return declined("ambiguous-index", {
27609
+ messageIndex,
27610
+ messageCount: messages.length,
27611
+ hoistedCount,
27612
+ roleSequence: roleSequenceOf(messages),
27613
+ mappedIndex: mapped
27614
+ });
27615
+ if (mappedNames) return annotate(repairAtArrayIndex(parsed, mapped), { mappedIndex: mapped });
27616
+ return annotate(repairAtArrayIndex(parsed, messageIndex), { mappedIndex: mapped });
27617
+ }
27618
+ /**
27619
+ * Build a one-shot repair only for Copilot's known signed-thinking integrity
27620
+ * rejections. The upstream error is the oracle: valid omitted-display thinking
27621
+ * also has an empty `thinking` string, so request shape alone cannot identify a
27622
+ * corrupt signature safely.
27623
+ *
27624
+ * Returns a discriminated outcome so a caller can report WHY a repair was not
27625
+ * applied; a silent decline is what made the original incident undiagnosable.
27626
+ */
27627
+ function repairRejectedThinkingHistory(rawBody, upstreamErrorText) {
27628
+ const match = THINKING_INTEGRITY_ERROR_RES.map((pattern) => pattern.exec(upstreamErrorText)).find((candidate) => candidate !== null);
27629
+ if (!match) return declined("error-not-recognized");
27630
+ const messageIndex = Number(match[1]);
27631
+ if (!Number.isSafeInteger(messageIndex) || messageIndex < 0) return declined("message-index-invalid", { messageIndex });
27632
+ const parsedContentIndex = Number(match[2]);
27633
+ const contentIndex = Number.isSafeInteger(parsedContentIndex) && parsedContentIndex >= 0 ? parsedContentIndex : void 0;
27634
+ let parsed;
27635
+ try {
27636
+ parsed = JSON.parse(rawBody);
27637
+ } catch {
27638
+ return declined("body-not-json", { messageIndex });
27639
+ }
27640
+ return repairMessageAt(parsed, messageIndex, contentIndex);
27641
+ }
27642
+ /**
27643
+ * Reapply a repair already proven successful in this process. Only salted
27644
+ * digests are retained; no message, thinking, signature, or tool content is
27645
+ * stored.
27646
+ */
27647
+ function repairKnownThinkingHistory(rawBody) {
27648
+ if (rememberedRepairs.size === 0) return void 0;
27649
+ let parsed;
27650
+ try {
27651
+ parsed = JSON.parse(rawBody);
27652
+ } catch {
27653
+ return;
27654
+ }
27655
+ if (!Array.isArray(parsed.messages)) return void 0;
27656
+ let repaired;
27657
+ let totalRemovedBlocks = 0;
27658
+ for (let index = parsed.messages.length - 1; index >= 0; index--) {
27659
+ const message = parsed.messages[index];
27660
+ if (!isRecord(message) || !Array.isArray(message.content)) continue;
27661
+ const fingerprint = signedBlockFingerprint(index, message.content);
27662
+ if (!fingerprint || !rememberedRepairs.has(fingerprint)) continue;
27663
+ const attempt = repairAtArrayIndex(parsed, index);
27664
+ if (!attempt.ok) continue;
27665
+ totalRemovedBlocks += attempt.repair.removedBlocks;
27666
+ repaired = {
27667
+ ...attempt.repair,
27668
+ removedBlocks: totalRemovedBlocks
27669
+ };
27670
+ }
27671
+ return repaired;
27672
+ }
27673
+ function rememberThinkingHistoryRepair(fingerprint) {
27674
+ if (rememberedRepairs.has(fingerprint)) return;
27675
+ if (rememberedRepairs.size >= MAX_REMEMBERED_REPAIRS) {
27676
+ const oldest = rememberedRepairs.values().next().value;
27677
+ if (typeof oldest === "string") rememberedRepairs.delete(oldest);
27678
+ }
27679
+ rememberedRepairs.add(fingerprint);
27680
+ }
27681
+ //#endregion
27387
27682
  //#region src/services/advisor/advisor.ts
27388
27683
  /**
27389
27684
  * Phase I: ADVISOR proxy-side translation.
@@ -28062,11 +28357,27 @@ function buildAdvisorStream(opts) {
28062
28357
  }))
28063
28358
  });
28064
28359
  if (aborter.signal.aborted) return;
28065
- response = await createMessages(JSON.stringify({
28360
+ let continuationSend = JSON.stringify({
28066
28361
  ...opts.baseBody,
28067
28362
  messages: conversation,
28068
28363
  stream: true
28069
- }), opts.requestHeaders, aborter.signal, true);
28364
+ });
28365
+ const knownRepair = repairKnownThinkingHistory(continuationSend);
28366
+ if (knownRepair) continuationSend = knownRepair.body;
28367
+ try {
28368
+ response = await createMessages(continuationSend, opts.requestHeaders, aborter.signal, true);
28369
+ } catch (continuationError) {
28370
+ if (!(continuationError instanceof HTTPError)) throw continuationError;
28371
+ const errorBody = await continuationError.response.clone().text().catch(() => "");
28372
+ const outcome = repairRejectedThinkingHistory(continuationSend, errorBody);
28373
+ if (!outcome.ok) {
28374
+ consola.warn(`Advisor continuation thinking-history repair declined: ${formatThinkingRepairDecline(outcome.decline)}`);
28375
+ throw continuationError;
28376
+ }
28377
+ consola.warn(`Advisor continuation: retrying without rejected thinking blocks: message=${outcome.repair.messageIndex} removed_blocks=${outcome.repair.removedBlocks}`);
28378
+ response = await createMessages(outcome.repair.body, opts.requestHeaders, aborter.signal, true);
28379
+ rememberThinkingHistoryRepair(outcome.repair.fingerprint);
28380
+ }
28070
28381
  }
28071
28382
  if (aborter.signal.aborted) return;
28072
28383
  const finalIndex = nextSyntheticIndex++;
@@ -34285,6 +34596,6 @@ function enumerateInjectedMcpToolNames(groupKeys, opts = {}) {
34285
34596
  return [...new Set(names)];
34286
34597
  }
34287
34598
  //#endregion
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 };
34599
+ export { browserToolsEnabled as $, searchWeb as A, collapsePathKeys as At, buildAnthropicErrorEvent as B, upstreamAllowH2 as Bt, buildToolbeltAwareness as C, provisionAndIndexColbert as Ct, TOOLBELT_TOOLS$1 as D, CONDENSED_OPERATING_SEQUENCE as Dt, vscodeRipgrepPath as E, warmTreeSitterPool as Et, isAdvisorRequested as F, DEFAULT_PORT as Ft, relayAnthropicStream as G, isControllerClosedError as H, withOneMSuffix as Ht, formatThinkingRepairDecline as I, UPSTREAM_FETCH_TIMEOUT_MS as It, agentToolsEnabled as J, handleMcpDelete as K, rememberThinkingHistoryRepair as L, UPSTREAM_INACTIVITY_TIMEOUT_MS as Lt, ADVISOR_TOOL_INSTRUCTIONS as M, DEFAULT_CLAUDE_MODEL_FALLBACKS as Mt, buildAdvisorStream as N, DEFAULT_CODEX_MODEL as Nt, assetFor as O, DEFINITION_OF_GREATNESS as Ot, injectAdvisorTool as P, DEFAULT_CODEX_MODEL_FALLBACKS as Pt, browserCompoundToolsEnabled as Q, repairKnownThinkingHistory as R, generateRandomPort as Rt, availableToolCommands as S, colbertDegradedWarning as St, toolbeltSkipSet as T, extractZipMember as Tt, logStreamError as U, withInstallLock as Ut, buildOpenAIErrorEvent as V, upstreamMaxConnections as Vt, readIteratorWithTimeout as W, brainstormModel as X, artifactToolsEnabled as Y, browseAgentEnabled as Z, appendPlanReminder as _, MAX_RESPONSE_BODY_BYTES as _t, buildPeerAwarenessSnippet as a, scribeModel as at, runWorkerAgent as b, provisionBrowserAssets as bt, personasFor as c, shimDefaultsToXhigh as ct, EXPLORE_DEFAULT_MODEL as d, getTokenCount as dt, fleetToolsEnabled as et, EXPLORE_DEFAULT_THINKING as f, assembleResponsesPayload as ft, TEST_DEFAULT_MODEL as g, createChatCompletions as gt, REVIEW_DEFAULT_MODEL as h, createResponses as ht, buildAgentPrompt as i, scoutModel as it, ADVISOR_INTERNAL_TOOL_NAME as j, toolbeltPathOverride as jt, satisfiesMinVersion as k, shouldUseInsecureTls as kt, BROWSE_DEFAULT_MODEL as l, countTokens as lt, PLAN_DEFAULT_MODEL as m, pickEndpoint as mt, MCP_GROUPS as n, nativeSubagentModel as nt, buildPeerAwarenessSummary as o, standInToolEnabled as ot, IMPLEMENT_DEFAULT_MODEL as p, resolveMcpToolTimeoutMs as pt, handleMcpPost as q, assertMcpToolSurfaceConsistent as r, reviewerModel as rt, enumerateInjectedMcpToolNames as s, workerToolsEnabled as st, GROUP_META as t, geminiAvailable as tt, DEFAULT_MODEL as u, createMessages as ut, resolveModeDefaults as v, readResponseBodyCapped as vt, toolbeltEnabled as w, extractTarGzMember as wt, buildEnv as x, hasSupportedBrowserInstalled as xt, resolveWorkerRunOpts as y, parseJsonOrDiagnose as yt, repairRejectedThinkingHistory as z, pickClaudeDefault as zt };
34289
34600
 
34290
- //# sourceMappingURL=peer-mcp-personas-pWP3Eyt7.js.map
34601
+ //# sourceMappingURL=peer-mcp-personas-DAZU1OfN.js.map