@vanillagreen/pi-claude-bridge 4.0.1 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bundle/index.js CHANGED
@@ -36017,7 +36017,8 @@ async function listAccountConnectors(deps) {
36017
36017
  const { credentials, apiBase, signal } = deps;
36018
36018
  const fetchImpl = deps.fetchImpl ?? fetch;
36019
36019
  const url2 = connectorsListUrl(credentials.organizationUuid, apiBase);
36020
- const fail = (reason) => ({ ok: false, complete: false, reason: redactSecret(reason, credentials.accessToken) });
36020
+ const fail = (key, value, reason) => ({ ok: false, complete: false, reason: redactSecret(`${key}=${JSON.stringify(value)}
36021
+ ${reason}`, credentials.accessToken) });
36021
36022
  let response;
36022
36023
  try {
36023
36024
  response = await fetchImpl(url2, {
@@ -36031,32 +36032,32 @@ async function listAccountConnectors(deps) {
36031
36032
  signal
36032
36033
  });
36033
36034
  } catch (error51) {
36034
- return fail(`connector list request failed: ${errorText(error51)}`);
36035
+ return fail("connector-request", "transport", `connector list request failed: ${errorText(error51)}`);
36035
36036
  }
36036
36037
  let bodyText;
36037
36038
  try {
36038
36039
  bodyText = await response.text();
36039
36040
  } catch (error51) {
36040
- return fail(`connector list response unreadable: ${errorText(error51)}`);
36041
+ return fail("connector-response", "unreadable", `connector list response unreadable: ${errorText(error51)}`);
36041
36042
  }
36042
36043
  if (!response.ok) {
36043
- return fail(`connector list returned HTTP ${response.status}${apiErrorSuffix(bodyText)}`);
36044
+ return fail("connector-http", response.status, `connector list returned HTTP ${response.status}${apiErrorSuffix(bodyText)}`);
36044
36045
  }
36045
36046
  let parsed;
36046
36047
  try {
36047
36048
  parsed = JSON.parse(bodyText);
36048
36049
  } catch {
36049
- return fail("connector list returned a non-JSON body");
36050
+ return fail("connector-json", "invalid", "connector list returned a non-JSON body");
36050
36051
  }
36051
36052
  if (!Array.isArray(parsed?.results)) {
36052
- return fail("connector list response had no results array");
36053
+ return fail("connector-results", "not-array", "connector list response had no results array");
36053
36054
  }
36054
36055
  const connectors = [];
36055
36056
  for (const raw of parsed.results) {
36056
36057
  const entry = raw;
36057
36058
  const name = nonEmptyString(entry?.name);
36058
36059
  if (!name) {
36059
- return fail("connector list contained an entry with no name");
36060
+ return fail("connector-name", connectors.length, "connector list contained an entry with no name");
36060
36061
  }
36061
36062
  connectors.push({
36062
36063
  name,
@@ -36369,7 +36370,8 @@ function connectorWriteDenyOutput(toolName) {
36369
36370
  hookSpecificOutput: {
36370
36371
  hookEventName: "PreToolUse",
36371
36372
  permissionDecision: "deny",
36372
- permissionDecisionReason: `Connector write tool "${toolName}" is blocked in read-only connector mode. Connector writes must go through the host application's gated approval flow.`
36373
+ permissionDecisionReason: `connector-write-denied=${JSON.stringify(toolName)}
36374
+ Connector write tool "${toolName}" is blocked in read-only connector mode. Connector writes must go through the host application's gated approval flow.`
36373
36375
  }
36374
36376
  };
36375
36377
  }
@@ -36761,7 +36763,8 @@ var DRAIN_CAUSE_TEXT = {
36761
36763
  };
36762
36764
  function interruptedToolCallResult(cause) {
36763
36765
  return {
36764
- content: [{ type: "text", text: `Claude bridge: ${DRAIN_CAUSE_TEXT[cause]} before this tool call's result was delivered. The call did not complete and produced no output.` }],
36766
+ content: [{ type: "text", text: `tool-call-drain=${cause}
36767
+ Claude bridge: ${DRAIN_CAUSE_TEXT[cause]} before this tool call's result was delivered. The call did not complete and produced no output.` }],
36765
36768
  isError: true
36766
36769
  };
36767
36770
  }
@@ -36780,7 +36783,7 @@ function drainPendingToolCalls(queryCtx, cause) {
36780
36783
  }
36781
36784
  function strandedToolCallResult() {
36782
36785
  return {
36783
- content: [{ type: "text", text: "Claude bridge: this tool call was never forwarded to Pi before its turn ended, so it did not execute and no result can arrive. Re-run the tool." }],
36786
+ content: [{ type: "text", text: "tool-call-stranded=unforwarded\nClaude bridge: this tool call was never forwarded to Pi before its turn ended, so it did not execute and no result can arrive. Re-run the tool." }],
36784
36787
  isError: true
36785
36788
  };
36786
36789
  }
@@ -36856,6 +36859,22 @@ var QueryContext = class {
36856
36859
  // Query-scoped (fully isolated per query)
36857
36860
  activeQuery = null;
36858
36861
  currentPiStream = null;
36862
+ /** Pi replaced the history this query's Claude session was built from
36863
+ * (compaction, history navigation) while the query was still running.
36864
+ * Delivering further tool results into it would keep Claude Code on history
36865
+ * Pi no longer holds, so the next provider callback restarts the query from
36866
+ * Pi's new context. A query that ENDS while this is set persists its record
36867
+ * with needsRebuild, so the next turn rebuilds either way. */
36868
+ piHistoryReplaced = false;
36869
+ /** The handover this replacement asked for was refused, and the refusal is
36870
+ * already reported. Every later callback of the query re-reads
36871
+ * `piHistoryReplaced`, which stays set, so without this the same refusal
36872
+ * would be recorded once per remaining tool result. */
36873
+ reportedHistoryRestartDecline = false;
36874
+ /** The provider callback that observed `piHistoryReplaced`. The dying query's
36875
+ * own promise chain runs it, after teardown released the query state, and
36876
+ * feeds the replacement query's events into that callback's stream. */
36877
+ restartRequest = null;
36859
36878
  latestCursor = 0;
36860
36879
  pendingToolCalls = /* @__PURE__ */ new Map();
36861
36880
  pendingResults = /* @__PURE__ */ new Map();
@@ -36940,14 +36959,20 @@ var QueryContext = class {
36940
36959
  /** tool_use id → raw SDK tool name. */
36941
36960
  childExecutedToolCalls = /* @__PURE__ */ new Map();
36942
36961
  /**
36943
- * The same calls, for the connector-call audit trail (see connector-audit.ts).
36962
+ * Every call the CHILD executed that pi's messages cannot carry — a claude.ai
36963
+ * connector, or a foreign MCP tool the child loaded itself — keyed by tool_use
36964
+ * id. Nothing can rebuild these from pi's context, so a history handover is
36965
+ * refused while the map is non-empty. Connector entries also back the
36966
+ * connector-call audit trail (see connector-audit.ts).
36944
36967
  *
36945
36968
  * Query-scoped and deliberately NOT cleared by resetToolTracking: that runs at
36946
36969
  * every child message boundary, and a call issued in one child message is only
36947
36970
  * reconciled after that message ends. Clearing it there would make an abandoned
36948
36971
  * call unrecordable at teardown — which is the one case the trail exists for.
36972
+ * Fresh-query setup clears it instead, once teardown has flushed it: a reused
36973
+ * top-level context would otherwise answer for calls an earlier query made.
36949
36974
  */
36950
- connectorCallAudit = /* @__PURE__ */ new Map();
36975
+ childSideCalls = /* @__PURE__ */ new Map();
36951
36976
  /** Claude Code session id for this query, from the SDK's `system` init message.
36952
36977
  * Undefined until it arrives; the audit trail omits the field rather than
36953
36978
  * guessing. */
@@ -37004,7 +37029,7 @@ var QueryContext = class {
37004
37029
  turnSawStreamEvent = false;
37005
37030
  turnSawToolCall = false;
37006
37031
  get turnBlocks() {
37007
- if (!this.turnOutput) throw new Error("turnBlocks accessed before resetTurnState");
37032
+ if (!this.turnOutput) throw new Error("turn-state-uninitialized=turnBlocks\nturnBlocks accessed before resetTurnState");
37008
37033
  return this.turnOutput.content;
37009
37034
  }
37010
37035
  resetTurnState(model) {
@@ -37061,9 +37086,10 @@ var QueryContext = class {
37061
37086
  }
37062
37087
  if (id2 && isConnectorTool(rawName)) {
37063
37088
  this.childExecutedToolCalls.set(id2, rawName);
37064
- if (!this.connectorCallAudit.has(id2)) {
37065
- this.connectorCallAudit.set(id2, {
37089
+ if (!this.childSideCalls.has(id2)) {
37090
+ this.childSideCalls.set(id2, {
37066
37091
  name: rawName,
37092
+ kind: "connector",
37067
37093
  ...this.childSessionId ? { childSessionId: this.childSessionId } : {},
37068
37094
  recorded: false
37069
37095
  });
@@ -37071,6 +37097,20 @@ var QueryContext = class {
37071
37097
  }
37072
37098
  if (typeof streamIndex === "number") this.childExecutedStreamIndexes.add(streamIndex);
37073
37099
  }
37100
+ /** A foreign MCP tool the child loaded from filesystem settings and ran
37101
+ * itself. Pi never sees the call or its result, so it commits the turn the
37102
+ * same way a connector does and joins the same map: a rebuild from pi's
37103
+ * context would erase an account-visible operation the model could repeat. */
37104
+ noteForeignMcpToolCall(id2, rawName) {
37105
+ this.markOutputCommitted();
37106
+ if (!id2 || this.childSideCalls.has(id2)) return;
37107
+ this.childSideCalls.set(id2, {
37108
+ name: rawName,
37109
+ kind: "foreign-mcp",
37110
+ ...this.childSessionId ? { childSessionId: this.childSessionId } : {},
37111
+ recorded: false
37112
+ });
37113
+ }
37074
37114
  recordToolCall(id2, toolName, args = {}) {
37075
37115
  if (!id2) return;
37076
37116
  this.queryToolNames.set(id2, toolName);
@@ -37238,13 +37278,13 @@ function stackDepth() {
37238
37278
  }
37239
37279
  function pushContext() {
37240
37280
  const state = lane();
37241
- if (!state.current.activeQuery) throw new Error("pushContext() called with no active query");
37281
+ if (!state.current.activeQuery) throw new Error("query-stack-push=inactive\npushContext() called with no active query");
37242
37282
  state.stack.push(state.current);
37243
37283
  state.current = new QueryContext();
37244
37284
  }
37245
37285
  function popContext() {
37246
37286
  const state = lane();
37247
- if (state.stack.length === 0) throw new Error("popContext() called with empty stack");
37287
+ if (state.stack.length === 0) throw new Error("query-stack-pop=empty\npopContext() called with empty stack");
37248
37288
  const parent = state.stack[state.stack.length - 1];
37249
37289
  parent.deferredUserMessages.push(...state.current.deferredUserMessages);
37250
37290
  state.current = state.stack.pop();
@@ -37340,7 +37380,7 @@ function findUnpairedToolUses(messages) {
37340
37380
  }
37341
37381
  return missing;
37342
37382
  }
37343
- var LOST_TOOL_RESULT_TEXT = "Claude bridge: the result of this tool call was lost before the session was rebuilt (the turn was interrupted). Treat the call as failed \u2014 it may or may not have executed. Re-run the tool if its output is still needed.";
37383
+ var LOST_TOOL_RESULT_TEXT = "tool-result-lost=interrupted\nClaude bridge: the result of this tool call was lost before the session was rebuilt (the turn was interrupted). Treat the call as failed \u2014 it may or may not have executed. Re-run the tool if its output is still needed.";
37344
37384
  function insertLostToolResultPlaceholders(messages, missing) {
37345
37385
  const block = (id2) => ({ type: "tool_result", tool_use_id: id2, content: LOST_TOOL_RESULT_TEXT, is_error: true });
37346
37386
  const byAssistant = /* @__PURE__ */ new Map();
@@ -37527,7 +37567,8 @@ function reportToolResultMismatch(queryCtx, reason, cwd, opts = {}) {
37527
37567
  unmatchedResultIds: progress.unmatchedResultIds
37528
37568
  });
37529
37569
  safeNotify(
37530
- `Claude bridge: tool result delivery interrupted during ${reason}; delivered ${progress.deliveredCount}/${progress.expectedCount}, resolved ${progress.resolvedCount}/${progress.expectedCount}, waiting=${progress.waitingCount}, queued=${progress.queuedCount}, unmatched=${progress.unmatchedResultCount}${toolNameSummary.length ? `, tools=${toolNameSummary.join(", ")}` : ""}. ` + (queryCtx.detachedFromSharedSession ? `Detached one-shot query \u2014 shared Claude session record left untouched; ${diagGuidance()}.` : `Claude session will rebuild before the next turn; ${diagGuidance()}.`),
37570
+ `tool-result-mismatch=${JSON.stringify({ delivered: progress.deliveredCount, expected: progress.expectedCount, resolved: progress.resolvedCount, diagnostic: DEBUG ? diagLogPath() : "CLAUDE_BRIDGE_DEBUG=1" })}
37571
+ Claude bridge: tool result delivery interrupted during ${reason}; delivered ${progress.deliveredCount}/${progress.expectedCount}, resolved ${progress.resolvedCount}/${progress.expectedCount}, waiting=${progress.waitingCount}, queued=${progress.queuedCount}, unmatched=${progress.unmatchedResultCount}${toolNameSummary.length ? `, tools=${toolNameSummary.join(", ")}` : ""}. ` + (queryCtx.detachedFromSharedSession ? `Detached one-shot query \u2014 shared Claude session record left untouched; ${diagGuidance()}.` : `Claude session will rebuild before the next turn; ${diagGuidance()}.`),
37531
37572
  "error"
37532
37573
  );
37533
37574
  return true;
@@ -37587,10 +37628,10 @@ function appendConnectorCallAudit(data) {
37587
37628
  return delivered;
37588
37629
  }
37589
37630
  function recordConnectorCallResult(queryCtx, toolUseId, name, isError, byteSize) {
37590
- const pending = queryCtx.connectorCallAudit.get(toolUseId);
37631
+ const pending = queryCtx.childSideCalls.get(toolUseId);
37591
37632
  if (pending?.recorded) return false;
37592
37633
  const childSessionId = pending?.childSessionId ?? queryCtx.childSessionId;
37593
- queryCtx.connectorCallAudit.set(toolUseId, { ...pending, name, childSessionId, recorded: true });
37634
+ queryCtx.childSideCalls.set(toolUseId, { ...pending, kind: pending?.kind ?? "connector", name, childSessionId, recorded: true });
37594
37635
  return appendConnectorCallAudit({
37595
37636
  name,
37596
37637
  toolUseId,
@@ -37601,9 +37642,9 @@ function recordConnectorCallResult(queryCtx, toolUseId, name, isError, byteSize)
37601
37642
  }
37602
37643
  function flushConnectorCallAudit(queryCtx, reason) {
37603
37644
  let appended = 0;
37604
- for (const [toolUseId, state] of queryCtx.connectorCallAudit) {
37605
- if (state.recorded) continue;
37606
- queryCtx.connectorCallAudit.set(toolUseId, { ...state, recorded: true });
37645
+ for (const [toolUseId, state] of queryCtx.childSideCalls) {
37646
+ if (state.recorded || state.kind !== "connector") continue;
37647
+ queryCtx.childSideCalls.set(toolUseId, { ...state, recorded: true });
37607
37648
  const childSessionId = state.childSessionId ?? queryCtx.childSessionId;
37608
37649
  if (appendConnectorCallAudit({
37609
37650
  name: state.name,
@@ -37617,6 +37658,18 @@ function flushConnectorCallAudit(queryCtx, reason) {
37617
37658
  }
37618
37659
 
37619
37660
  // src/query-teardown.ts
37661
+ function closeSdkQuery(sdkQuery) {
37662
+ try {
37663
+ sdkQuery.close();
37664
+ } catch (error51) {
37665
+ debug("provider: closing the sdk query threw; continuing teardown:", error51);
37666
+ }
37667
+ }
37668
+ function abortSdkQuery(sdkQuery) {
37669
+ void sdkQuery.interrupt().catch(() => {
37670
+ });
37671
+ closeSdkQuery(sdkQuery);
37672
+ }
37620
37673
  function teardownQuery(queryCtx, sdkQuery, cause, cwd, isReentrant) {
37621
37674
  if (queryCtx.activeQuery !== sdkQuery) return false;
37622
37675
  reportToolResultMismatch(queryCtx, "query teardown", cwd, { forceRotate: cause !== "query-end" });
@@ -37687,7 +37740,9 @@ function claudeAuthSourceLabel(env = process.env) {
37687
37740
  return "Claude Code login";
37688
37741
  }
37689
37742
  function buildNativeProvider(piAi2, models, streamSimple, env = process.env, hasCredentials = () => hasClaudeCredentials(env)) {
37690
- if (!supportsNativeProvider(piAi2)) throw new Error(NATIVE_PROVIDER_UNSUPPORTED_MESSAGE);
37743
+ if (!supportsNativeProvider(piAi2)) {
37744
+ throw Object.assign(new Error(NATIVE_PROVIDER_UNSUPPORTED_MESSAGE), { code: "CLAUDE_BRIDGE_NATIVE_PROVIDER_UNSUPPORTED" });
37745
+ }
37691
37746
  const stamped = models.map((model) => ({ ...model, api: "claude-bridge", baseUrl: "claude-bridge", provider: PROVIDER_ID }));
37692
37747
  const streams = {
37693
37748
  stream: streamSimple,
@@ -53144,28 +53199,33 @@ function verifyWrittenSession(jsonlPath, expectedSessionId, expectedRecordCount)
53144
53199
  try {
53145
53200
  st2 = statSync3(jsonlPath);
53146
53201
  } catch (e) {
53147
- warnings.push(`file missing after save \u2014 path=${jsonlPath} err=${e.message}`);
53202
+ warnings.push(`session-file-missing=${jsonlPath}
53203
+ File missing after save: ${e.message}`);
53148
53204
  return warnings;
53149
53205
  }
53150
53206
  let summary;
53151
53207
  try {
53152
53208
  summary = summarizeJsonl(jsonlPath);
53153
53209
  } catch (e) {
53154
- warnings.push(`file unreadable \u2014 path=${jsonlPath} size=${st2.size} err=${e.message}`);
53210
+ warnings.push(`session-file-unreadable=${jsonlPath}
53211
+ File unreadable: size=${st2.size} error=${e.message}`);
53155
53212
  return warnings;
53156
53213
  }
53157
53214
  if (summary.count !== expectedRecordCount) {
53158
- warnings.push(`record count mismatch \u2014 expected=${expectedRecordCount} actual=${summary.count} path=${jsonlPath} bytes=${st2.size}`);
53215
+ warnings.push(`session-record-count=${summary.count} expected=${expectedRecordCount}
53216
+ Record count differs: path=${jsonlPath} bytes=${st2.size}`);
53159
53217
  return warnings;
53160
53218
  }
53161
53219
  try {
53162
53220
  const firstRec = JSON.parse(summary.firstLine ?? "");
53163
53221
  const lastRec = JSON.parse(summary.lastLine ?? "");
53164
53222
  if (firstRec.sessionId !== expectedSessionId || lastRec.sessionId !== expectedSessionId) {
53165
- warnings.push(`sessionId drift \u2014 expected=${expectedSessionId} first=${firstRec.sessionId} last=${lastRec.sessionId}`);
53223
+ warnings.push(`session-id-drift=${expectedSessionId} first=${firstRec.sessionId} last=${lastRec.sessionId}
53224
+ Session identity differs from the expected identity.`);
53166
53225
  }
53167
53226
  } catch (e) {
53168
- warnings.push(`malformed JSONL \u2014 path=${jsonlPath} err=${e.message}`);
53227
+ warnings.push(`session-json-invalid=${jsonlPath}
53228
+ Malformed JSONL: ${e.message}`);
53169
53229
  }
53170
53230
  return warnings;
53171
53231
  }
@@ -53481,12 +53541,14 @@ function canonicalize(p) {
53481
53541
  }
53482
53542
  }
53483
53543
  function shouldRestorePersistedBridgeEntry(persisted, currentPiSessionId, currentCwd) {
53484
- if (!persisted.piSessionId) return "missing piSessionId";
53544
+ if (!persisted.piSessionId) return "restore-session-missing=piSessionId\nMissing piSessionId.";
53485
53545
  if (currentPiSessionId && persisted.piSessionId !== currentPiSessionId) {
53486
- return `piSessionId mismatch (persisted=${persisted.piSessionId} current=${currentPiSessionId})`;
53546
+ return `restore-session-mismatch=${persisted.piSessionId} current=${currentPiSessionId}
53547
+ The persisted session differs from the active session.`;
53487
53548
  }
53488
53549
  if (currentCwd && canonicalize(persisted.cwd) !== canonicalize(currentCwd)) {
53489
- return `cwd mismatch (persisted=${persisted.cwd} current=${currentCwd})`;
53550
+ return `restore-cwd-mismatch=${persisted.cwd} current=${currentCwd}
53551
+ The persisted working directory differs from the active directory.`;
53490
53552
  }
53491
53553
  return void 0;
53492
53554
  }
@@ -53640,7 +53702,7 @@ function verifyWrittenSession2(jsonlPath, expectedSessionId, expectedRecordCount
53640
53702
  for (const msg of warnings) {
53641
53703
  debug(`WARNING session verify: ${msg}`);
53642
53704
  safeNotify(
53643
- `Session file issue: ${msg}
53705
+ `${msg}
53644
53706
  cwd=${displayPath(cwd)} realpath=${displayPath(safeRealpath(cwd))}
53645
53707
  Please copy and paste this message into a new issue at https://github.com/vanillagreencom/kendex/issues/new` + (DEBUG ? ` and attach ${DEBUG_LOG_PATH}` : ` (rerun with CLAUDE_BRIDGE_DEBUG=1 to capture a debug log)`),
53646
53708
  "warning"
@@ -54009,7 +54071,8 @@ function reapStaleQueuedResults(c) {
54009
54071
  diagDump("stale_queued_tool_results_parked", { count: stale.length, stale });
54010
54072
  appendIntegrityEntry("stale_queued_tool_results_parked", { count: stale.length, stale });
54011
54073
  safeNotify(
54012
- `Claude bridge: parked ${stale.length} early tool result(s) whose handler has not arrived (${names.slice(0, 6).join(", ")}${names.length > 6 ? ", \u2026" : ""}). A late handler can still consume them.`,
54074
+ `queued-results-parked=${JSON.stringify({ count: stale.length, tools: names })}
54075
+ Claude bridge: parked ${stale.length} early tool result(s) whose handler has not arrived (${names.slice(0, 6).join(", ")}${names.length > 6 ? ", \u2026" : ""}). A late handler can still consume them.`,
54013
54076
  "warning"
54014
54077
  );
54015
54078
  }
@@ -54106,7 +54169,7 @@ function processStreamEvent(message, customToolNameToPi, model, c = ctx()) {
54106
54169
  }
54107
54170
  if (event.content_block?.type === "tool_use" && !isPiDispatchable(event.content_block.name, customToolNameToPi)) {
54108
54171
  c.suppressedStreamIndexes.add(event.index);
54109
- if (isForeignMcpTool(event.content_block.name)) c.markOutputCommitted();
54172
+ if (isForeignMcpTool(event.content_block.name)) c.noteForeignMcpToolCall(event.content_block.id, event.content_block.name);
54110
54173
  debug(`processStreamEvent: non-dispatchable tool ${event.content_block.name} [${event.content_block.id}] \u2014 not mirrored as a Pi tool call`);
54111
54174
  return;
54112
54175
  }
@@ -54228,7 +54291,7 @@ function appendMissingToolUsesFromAssistant(assistantMsg, model, customToolNameT
54228
54291
  continue;
54229
54292
  }
54230
54293
  if (!isPiDispatchable(block.name, customToolNameToPi)) {
54231
- if (isForeignMcpTool(block.name)) c.markOutputCommitted();
54294
+ if (isForeignMcpTool(block.name)) c.noteForeignMcpToolCall(block.id, block.name);
54232
54295
  debug(`assistant message: non-dispatchable tool ${block.name} [${block.id}] \u2014 not mirrored as a Pi tool call`);
54233
54296
  continue;
54234
54297
  }
@@ -54326,7 +54389,7 @@ function processAssistantMessage(message, model, customToolNameToPi, c = ctx())
54326
54389
  continue;
54327
54390
  }
54328
54391
  if (!isPiDispatchable(block.name, customToolNameToPi)) {
54329
- if (isForeignMcpTool(block.name)) c.markOutputCommitted();
54392
+ if (isForeignMcpTool(block.name)) c.noteForeignMcpToolCall(block.id, block.name);
54330
54393
  debug(`processAssistantMessage fallback: non-dispatchable tool ${block.name} [${block.id}] \u2014 not mirrored as a Pi tool call`);
54331
54394
  continue;
54332
54395
  }
@@ -54456,6 +54519,52 @@ var BRIDGE_ACCOUNT_HOST = {
54456
54519
  probeProfile: probeClaudeAccountProfile
54457
54520
  };
54458
54521
 
54522
+ // src/billing-identity.ts
54523
+ var CLAUDE_BILLING_IDENTITY_SYMBOL = /* @__PURE__ */ Symbol.for("kendex.pi.claude-bridge.billing-identity.v1");
54524
+ var FIRST_PARTY = "firstParty";
54525
+ var BILLING_IDENTITY_LANES_SYMBOL = /* @__PURE__ */ Symbol.for("kendex.pi.claude-bridge.billing-identity-lanes.v1");
54526
+ function sharedBillingIdentityLanes() {
54527
+ const host = globalThis;
54528
+ let lanes = host[BILLING_IDENTITY_LANES_SYMBOL];
54529
+ if (!lanes) {
54530
+ lanes = /* @__PURE__ */ new Map();
54531
+ host[BILLING_IDENTITY_LANES_SYMBOL] = lanes;
54532
+ }
54533
+ return lanes;
54534
+ }
54535
+ function nonEmpty(value) {
54536
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
54537
+ }
54538
+ function loginEmailFrom(info) {
54539
+ if (info.apiProvider !== FIRST_PARTY) return void 0;
54540
+ if (nonEmpty(info.apiKeySource)) return void 0;
54541
+ return nonEmpty(info.email);
54542
+ }
54543
+ function makeBillingIdentityStore(lanes = /* @__PURE__ */ new Map()) {
54544
+ return {
54545
+ version: 1,
54546
+ currentLoginEmail: (sessionId) => lanes.get(sessionId)?.loginEmail,
54547
+ beginAttempt: (sessionId) => {
54548
+ const attempt = /* @__PURE__ */ Symbol("billing-identity-attempt");
54549
+ lanes.set(sessionId, { attempt });
54550
+ return (info) => {
54551
+ const current = lanes.get(sessionId);
54552
+ if (current?.attempt !== attempt) return;
54553
+ lanes.set(sessionId, { attempt, loginEmail: loginEmailFrom(info) });
54554
+ };
54555
+ },
54556
+ deleteLane: (sessionId) => lanes.delete(sessionId),
54557
+ clear: () => lanes.clear()
54558
+ };
54559
+ }
54560
+ var BRIDGE_BILLING_IDENTITY = makeBillingIdentityStore(sharedBillingIdentityLanes());
54561
+ function beginBillingIdentityAttempt() {
54562
+ return BRIDGE_BILLING_IDENTITY.beginAttempt(currentRequestLaneId());
54563
+ }
54564
+ function deleteBillingIdentityLane(sessionId) {
54565
+ BRIDGE_BILLING_IDENTITY.deleteLane(sessionId);
54566
+ }
54567
+
54459
54568
  // src/bridge-commands.ts
54460
54569
  var COMMANDS_REGISTERED_KEY = /* @__PURE__ */ Symbol.for("claude-bridge:commandsRegistered");
54461
54570
  function commandCwd(ctx2) {
@@ -54545,10 +54654,11 @@ function noteFastModeDisabledReason(message, bridgeConfig) {
54545
54654
  const text = FAST_MODE_DISABLED_REASON_TEXT[reason] ?? `unavailable (${reason})`;
54546
54655
  safeNotify(`Pi Claude: fast mode is enabled in settings but Claude Code declined it \u2014 ${text}.`, "warning");
54547
54656
  }
54548
- async function consumeQuery(sdkQuery, queryCtx, customToolNameToPi, model, bridgeConfig, wasAborted, account, router, attemptFailureBox) {
54657
+ async function consumeQuery(sdkQuery, queryCtx, customToolNameToPi, model, bridgeConfig, wasAborted, recordBillingIdentity, account, router, attemptFailureBox) {
54549
54658
  let capturedSessionId;
54550
54659
  let failure;
54551
54660
  let accountProbe;
54661
+ let accountInfoProbe;
54552
54662
  const holdFailure = (next) => {
54553
54663
  failure = next;
54554
54664
  if (attemptFailureBox) attemptFailureBox.failure = next;
@@ -54626,9 +54736,13 @@ async function consumeQuery(sdkQuery, queryCtx, customToolNameToPi, model, bridg
54626
54736
  capturedSessionId = message.session_id;
54627
54737
  queryCtx.childSessionId = capturedSessionId;
54628
54738
  noteFastModeDisabledReason(message, bridgeConfig);
54739
+ if (!accountInfoProbe) {
54740
+ accountInfoProbe = (async () => sdkQuery.accountInfo())();
54741
+ void accountInfoProbe.then((info) => recordBillingIdentity(info)).catch((error51) => debug("consumeQuery: billing identity probe rejected:", error51));
54742
+ }
54629
54743
  if (account && router && !accountProbe) {
54630
54744
  accountProbe = Promise.allSettled([
54631
- sdkQuery.accountInfo().then((info) => router.recordIdentity(account.profileId, {
54745
+ accountInfoProbe.then((info) => router.recordIdentity(account.profileId, {
54632
54746
  email: info.email,
54633
54747
  organization: info.organization,
54634
54748
  subscriptionType: info.subscriptionType
@@ -55215,6 +55329,27 @@ function applyProviderRegistration(trigger) {
55215
55329
  debug(`${trigger}: registerProvider threw; released stream guard for retry (kept primary):`, err);
55216
55330
  }
55217
55331
  }
55332
+ var HISTORY_REPLACED_PROMPT = "The conversation above was rewritten by Pi (compaction or history navigation). It is the complete current history, including the results of every tool call that has already run. Continue the turn from there, and do not repeat a tool call whose result is already above.";
55333
+ function restartContext(request) {
55334
+ return {
55335
+ ...request.context,
55336
+ messages: [...request.context.messages, { role: "user", content: HISTORY_REPLACED_PROMPT, timestamp: Date.now() }]
55337
+ };
55338
+ }
55339
+ function onPiHistoryReplaced(event) {
55340
+ const activeSession = getSharedSession();
55341
+ const queryCtx = ctx();
55342
+ const running = queryCtx.activeQuery !== null;
55343
+ const restarts = running && !queryCtx.detachedFromSharedSession;
55344
+ if (running) {
55345
+ if (restarts) queryCtx.piHistoryReplaced = true;
55346
+ reportToolResultMismatch(queryCtx, event, activeSession?.cwd ?? process.cwd(), { expectedInterruption: restarts });
55347
+ }
55348
+ if (activeSession) {
55349
+ debug(`${event}: marking needsRebuild on session ${activeSession.sessionId.slice(0, 8)}`);
55350
+ markSessionForRebuild({ forceRotate: restarts });
55351
+ }
55352
+ }
55218
55353
  function streamClaudeAgentSdk(model, context, options) {
55219
55354
  return runInRequestLane(options?.sessionId, () => streamClaudeAgentSdkInLane(model, context, options));
55220
55355
  }
@@ -55226,12 +55361,30 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55226
55361
  if (!ephemeralLane) return;
55227
55362
  deleteSharedSessionLane(laneId);
55228
55363
  deleteQueryLane(laneId);
55364
+ deleteBillingIdentityLane(laneId);
55229
55365
  };
55230
55366
  const lastMsgRole = context.messages[context.messages.length - 1]?.role;
55231
55367
  const cwd = options?.cwd ?? process.cwd();
55232
55368
  debug(`provider: streamClaudeAgentSdk called, activeQuery=${!!ctx().activeQuery}, lastMsgRole=${lastMsgRole}, isReentrant=${ctx().activeQuery !== null}`);
55233
55369
  if (ctx().activeQuery) {
55234
55370
  const queryCtx = ctx();
55371
+ if (queryCtx.piHistoryReplaced) {
55372
+ if (queryCtx.childSideCalls.size > 0) {
55373
+ if (!queryCtx.reportedHistoryRestartDecline) {
55374
+ queryCtx.reportedHistoryRestartDecline = true;
55375
+ const names = [...new Set([...queryCtx.childSideCalls.values()].map((call) => call.name))];
55376
+ debug(`provider: pi replaced this query's history, but ${queryCtx.childSideCalls.size} child-executed call(s) are absent from pi's context; not restarting (${names.join(", ")})`);
55377
+ appendIntegrityEntry("history_restart_declined", { reason: "child-executed calls pi's history cannot carry", count: queryCtx.childSideCalls.size, names });
55378
+ }
55379
+ } else {
55380
+ queryCtx.piHistoryReplaced = false;
55381
+ queryCtx.restartRequest = { model, context, options, stream };
55382
+ queryCtx.currentPiStream = null;
55383
+ debug(`provider: pi replaced this query's history; restarting from ${context.messages.length} message(s)`);
55384
+ abortSdkQuery(queryCtx.activeQuery);
55385
+ return stream;
55386
+ }
55387
+ }
55235
55388
  queryCtx.currentPiStream = stream;
55236
55389
  queryCtx.resetTurnState(model);
55237
55390
  queryCtx.callbackGeneration += 1;
@@ -55326,6 +55479,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55326
55479
  });
55327
55480
  return stream;
55328
55481
  }
55482
+ const recordBillingIdentity = beginBillingIdentityAttempt();
55329
55483
  if (!hasClaudeCredentials() && !resolveClaudeAccountRouter()) {
55330
55484
  try {
55331
55485
  applyProviderRegistration("pre-spawn");
@@ -55365,6 +55519,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55365
55519
  ctx().pendingToolCalls.clear();
55366
55520
  ctx().pendingResults.clear();
55367
55521
  ctx().reapedResults.clear();
55522
+ ctx().childSideCalls.clear();
55368
55523
  ctx().forwardedToolCallIds.clear();
55369
55524
  ctx().deadToolCallIds.clear();
55370
55525
  ctx().callbackGeneration = 0;
@@ -55373,6 +55528,8 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55373
55528
  ctx().resetToolTracking();
55374
55529
  ctx().latestCursor = 0;
55375
55530
  ctx().committedOutput = false;
55531
+ ctx().piHistoryReplaced = false;
55532
+ ctx().reportedHistoryRestartDecline = false;
55376
55533
  ctx().detachedFromSharedSession = isReentrant;
55377
55534
  const router = resolveClaudeAccountRouter();
55378
55535
  const rotationOptions = options;
@@ -55496,6 +55653,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55496
55653
  `prompt=${promptText.slice(0, 60)}${promptBlocks ? " [+images]" : ""}`
55497
55654
  );
55498
55655
  let wasAborted = false;
55656
+ let reentryStream = stream;
55499
55657
  let streamIdleTimedOut = false;
55500
55658
  let retryRequested = false;
55501
55659
  let retryFailure;
@@ -55505,7 +55663,9 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55505
55663
  const attemptFailure = {};
55506
55664
  const persistSession = (next) => {
55507
55665
  if (isReentrant || foreignContext) return;
55508
- setSharedSession(next && conversationFp ? { conversationFingerprint: conversationFp, ...next } : next);
55666
+ const restartPending = abortCtx.restartRequest !== null;
55667
+ const replaced = next && (abortCtx.piHistoryReplaced || restartPending) ? { ...next, needsRebuild: true, ...restartPending ? { forceRotate: true } : {} } : next;
55668
+ setSharedSession(replaced && conversationFp ? { conversationFingerprint: conversationFp, ...replaced } : replaced);
55509
55669
  };
55510
55670
  const markRebuildForThisQuery = (opts = {}) => {
55511
55671
  if (isReentrant || foreignContext) return;
@@ -55525,14 +55685,6 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55525
55685
  safeRouterCall("recordFailure", () => router.recordFailure(account.profileId, failure.kind, queryModel.id));
55526
55686
  accountFailureRecorded = true;
55527
55687
  };
55528
- const requestAbort = () => {
55529
- void sdkQuery.interrupt().catch(() => {
55530
- });
55531
- try {
55532
- sdkQuery.close();
55533
- } catch {
55534
- }
55535
- };
55536
55688
  const requestRotation = (failure) => {
55537
55689
  recordAttemptFailure(failure);
55538
55690
  const committed = abortCtx.committedOutput || attemptBuffer?.hasCommittedOutput === true;
@@ -55573,7 +55725,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55573
55725
  debug("provider: stream idle timeout", `model=${queryModel.id}`, `timeout=${timeoutMs}`, `idle=${idleMs}`);
55574
55726
  const idleFailure = { kind: "network", message: errorMessage };
55575
55727
  if (requestRotation(idleFailure)) {
55576
- requestAbort();
55728
+ abortSdkQuery(sdkQuery);
55577
55729
  return;
55578
55730
  }
55579
55731
  abortCtx.handledTerminalError = true;
@@ -55601,7 +55753,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55601
55753
  abortCtx.currentPiStream?.push({ type: "error", reason: "error", error: abortCtx.turnOutput });
55602
55754
  abortCtx.currentPiStream?.end();
55603
55755
  abortCtx.currentPiStream = null;
55604
- requestAbort();
55756
+ abortSdkQuery(sdkQuery);
55605
55757
  },
55606
55758
  timeoutMs: streamIdleTimeoutMs
55607
55759
  }) : null;
@@ -55619,7 +55771,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55619
55771
  const drained = drainPendingToolCalls(abortCtx, "abort");
55620
55772
  if (drained > 0) debug(`provider: abort drained ${drained} waiting MCP handler(s) as errors`);
55621
55773
  abortCtx.pendingResults.clear();
55622
- requestAbort();
55774
+ abortSdkQuery(sdkQuery);
55623
55775
  });
55624
55776
  if (options?.signal) {
55625
55777
  if (options.signal.aborted) onAbort();
@@ -55651,8 +55803,12 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55651
55803
  abortCtx.currentPiStream?.end();
55652
55804
  abortCtx.currentPiStream = null;
55653
55805
  };
55654
- consumeQuery(sdkQuery, abortCtx, customToolNameToPi, queryModel, bridgeConfig, () => wasAborted, account, router, attemptFailure).then(async ({ capturedSessionId, failure }) => {
55806
+ consumeQuery(sdkQuery, abortCtx, customToolNameToPi, queryModel, bridgeConfig, () => wasAborted, recordBillingIdentity, account, router, attemptFailure).then(async ({ capturedSessionId, failure }) => {
55655
55807
  debug(`provider: consumeQuery completed, stopReason=${abortCtx.turnOutput?.stopReason}, failure=${failure?.kind ?? "none"}, aborted=${wasAborted}`);
55808
+ if (abortCtx.restartRequest) {
55809
+ debug("provider: query ended for a history restart; leaving the outcome to the replacement query");
55810
+ return;
55811
+ }
55656
55812
  if (streamIdleTimedOut) {
55657
55813
  dropDeferredUserMessages("stream-idle-timeout-completion");
55658
55814
  debug(`provider: stream idle timeout ${retryRequested ? "queued account rotation" : "already surfaced"}; skipping normal completion`);
@@ -55704,7 +55860,8 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55704
55860
  abortCtx.activeQuery = contQuery;
55705
55861
  debug(`provider: continuation query, model=${queryModel.id}, resume=${resumeId.slice(0, 8)}, account=${account?.label ?? "legacy"}, prompt=${steerPreview}`);
55706
55862
  try {
55707
- const continuation = await consumeQuery(contQuery, abortCtx, customToolNameToPi, queryModel, bridgeConfig, () => wasAborted, account, router);
55863
+ const continuation = await consumeQuery(contQuery, abortCtx, customToolNameToPi, queryModel, bridgeConfig, () => wasAborted, recordBillingIdentity, account, router);
55864
+ if (abortCtx.restartRequest) break;
55708
55865
  if (continuation.failure) {
55709
55866
  recordAttemptFailure(continuation.failure);
55710
55867
  if (!abortCtx.handledTerminalError) surfaceFailure(continuation.failure);
@@ -55719,6 +55876,7 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55719
55876
  persistSession({ sessionId: sid, cursor: activeSession2?.cursor ?? 0, cwd, ...accountScope });
55720
55877
  }
55721
55878
  } catch (contError) {
55879
+ if (abortCtx.restartRequest) break;
55722
55880
  debug(`provider: continuation query error:`, contError);
55723
55881
  const continuationFailure = {
55724
55882
  kind: classifyClaudeFailure(contError),
@@ -55740,6 +55898,10 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55740
55898
  finalizeCurrentStream(abortCtx.turnOutput?.stopReason, abortCtx);
55741
55899
  }).catch((error51) => {
55742
55900
  debug(`provider: query error, model=${queryModel.id}, aborted=${Boolean(options?.signal?.aborted)}, error=`, error51);
55901
+ if (abortCtx.restartRequest) {
55902
+ debug("provider: query error while a history restart was pending; suppressed");
55903
+ return;
55904
+ }
55743
55905
  const suppressDuplicateError = abortCtx.handledTerminalError || streamIdleTimedOut && !retryRequested;
55744
55906
  if (wasAborted || options?.signal?.aborted) {
55745
55907
  markRebuildForThisQuery({ forceRotate: true });
@@ -55764,8 +55926,26 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55764
55926
  if (options?.signal) options.signal.removeEventListener("abort", onAbort);
55765
55927
  const cause = toolCallDrainCause({ wasAborted, signalAborted: options?.signal?.aborted, streamIdleTimedOut });
55766
55928
  teardownQuery(abortCtx, sdkQuery, cause, cwd, isReentrant);
55767
- sdkQuery.close();
55929
+ closeSdkQuery(sdkQuery);
55768
55930
  }).then(async () => {
55931
+ const restart = abortCtx.restartRequest;
55932
+ if (restart) {
55933
+ abortCtx.restartRequest = null;
55934
+ reentryStream = restart.stream;
55935
+ if (wasAborted || options?.signal?.aborted || restart.options?.signal?.aborted) {
55936
+ debug("provider: abort before the history restart \u2014 terminating the stream without restarting");
55937
+ abortCtx.resetTurnState(restart.model);
55938
+ abortCtx.turnOutput.stopReason = "aborted";
55939
+ abortCtx.turnOutput.errorMessage = "Operation aborted";
55940
+ reentryStream.push({ type: "error", reason: "aborted", error: abortCtx.turnOutput });
55941
+ reentryStream.end();
55942
+ return;
55943
+ }
55944
+ debug(`provider: restarting query on replaced history, ${restart.context.messages.length} pi message(s)`);
55945
+ for await (const event of streamClaudeAgentSdk(restart.model, restartContext(restart), restart.options)) reentryStream.push(event);
55946
+ reentryStream.end();
55947
+ return;
55948
+ }
55769
55949
  if (!retryRequested) return;
55770
55950
  if (wasAborted || options?.signal?.aborted) {
55771
55951
  debug("provider: abort after queued account retry \u2014 terminating stream without retrying");
@@ -55773,8 +55953,8 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55773
55953
  abortCtx.turnOutput.stopReason = "aborted";
55774
55954
  abortCtx.turnOutput.errorMessage = "Operation aborted";
55775
55955
  }
55776
- stream.push({ type: "error", reason: "aborted", error: abortCtx.turnOutput });
55777
- stream.end();
55956
+ reentryStream.push({ type: "error", reason: "aborted", error: abortCtx.turnOutput });
55957
+ reentryStream.end();
55778
55958
  return;
55779
55959
  }
55780
55960
  debug(`provider: starting account retry after ${retryFailure?.kind ?? "failure"}; excluded=${[...rotationState.excludedProfileIds].join(",")}`);
@@ -55782,16 +55962,22 @@ function streamClaudeAgentSdkInLane(model, context, options) {
55782
55962
  ...options ?? {},
55783
55963
  [ROTATION_STATE_KEY]: rotationState
55784
55964
  });
55785
- for await (const event of retryStream) stream.push(event);
55786
- stream.end();
55965
+ for await (const event of retryStream) reentryStream.push(event);
55966
+ reentryStream.end();
55787
55967
  }).catch((error51) => {
55788
- debug("provider: account retry pipeline failed:", error51);
55968
+ debug("provider: re-entry pipeline failed:", error51);
55969
+ const restart = abortCtx.restartRequest;
55970
+ if (restart) {
55971
+ abortCtx.restartRequest = null;
55972
+ reentryStream = restart.stream;
55973
+ abortCtx.resetTurnState(restart.model);
55974
+ }
55789
55975
  if (abortCtx.turnOutput) {
55790
55976
  abortCtx.turnOutput.stopReason = "error";
55791
55977
  abortCtx.turnOutput.errorMessage = error51 instanceof Error ? error51.message : String(error51);
55792
55978
  }
55793
- stream.push({ type: "error", reason: "error", error: abortCtx.turnOutput });
55794
- stream.end();
55979
+ reentryStream.push({ type: "error", reason: "error", error: abortCtx.turnOutput });
55980
+ reentryStream.end();
55795
55981
  }).finally(releaseEphemeralLane);
55796
55982
  return stream;
55797
55983
  }
@@ -55809,6 +55995,7 @@ function index_default(pi2) {
55809
55995
  if (claimPrimaryInstance()) {
55810
55996
  const host = globalThis;
55811
55997
  host[CLAUDE_BRIDGE_ACCOUNT_HOST_SYMBOL] = BRIDGE_ACCOUNT_HOST;
55998
+ host[CLAUDE_BILLING_IDENTITY_SYMBOL] = BRIDGE_BILLING_IDENTITY;
55812
55999
  }
55813
56000
  const clearSession = (event) => {
55814
56001
  const activeSession = getSharedSession();
@@ -55834,23 +56021,14 @@ function index_default(pi2) {
55834
56021
  });
55835
56022
  deleteSharedSessionLane(sessionId);
55836
56023
  deleteQueryLane(sessionId);
56024
+ deleteBillingIdentityLane(sessionId);
55837
56025
  });
55838
56026
  pi2.on("message_end", (event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => {
55839
56027
  const message = event.message;
55840
56028
  if (message?.role === "assistant" && message.provider === PROVIDER_ID) schedulePersistSharedSession(ctx2);
55841
56029
  }));
55842
- const markRebuild = (event) => {
55843
- const activeSession = getSharedSession();
55844
- if (ctx().activeQuery) {
55845
- reportToolResultMismatch(ctx(), event, activeSession?.cwd ?? process.cwd());
55846
- }
55847
- if (activeSession) {
55848
- debug(`${event}: marking needsRebuild on session ${activeSession.sessionId.slice(0, 8)}`);
55849
- markSessionForRebuild();
55850
- }
55851
- };
55852
- pi2.on("session_compact", (_event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => markRebuild("session_compact")));
55853
- pi2.on("session_tree", (_event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => markRebuild("session_tree")));
56030
+ pi2.on("session_compact", (_event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => onPiHistoryReplaced("session_compact")));
56031
+ pi2.on("session_tree", (_event, ctx2) => runInRequestLane(ctx2.sessionManager.getSessionId(), () => onPiHistoryReplaced("session_tree")));
55854
56032
  applyProviderRegistration("load");
55855
56033
  }
55856
56034
  export {
@@ -55864,6 +56042,7 @@ export {
55864
56042
  CONNECTOR_WRITE_TOOLS,
55865
56043
  DEFAULT_STREAM_IDLE_TIMEOUT_MS,
55866
56044
  DISALLOWED_BUILTIN_TOOLS,
56045
+ HISTORY_REPLACED_PROMPT,
55867
56046
  INTEGRITY_CUSTOM_TYPE,
55868
56047
  NATIVE_PROVIDER_UNSUPPORTED_MESSAGE,
55869
56048
  RetryEventBuffer,
@@ -55922,6 +56101,7 @@ export {
55922
56101
  mapToolName,
55923
56102
  normalizeRateLimitUtilization,
55924
56103
  noteChildExecutedToolResults,
56104
+ onPiHistoryReplaced,
55925
56105
  planDeferredUserReplay,
55926
56106
  planIncrementalPromptBatch,
55927
56107
  preflightClaudeExecutable,