@cortexkit/pi-magic-context 0.44.2 → 0.44.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -38,8 +38,10 @@ import {
38
38
  formatWindowDerivationLine,
39
39
  isSaneLimit,
40
40
  resolveOutputReserve,
41
+ getSdkWindowGeometry,
41
42
  getSdkContextLimit,
42
43
  getSdkOutputLimit,
44
+ getSdkInputLimit,
43
45
  cortexKitUserConfigBasePath,
44
46
  cortexKitProjectConfigBasePath,
45
47
  migrateMagicContextConfigLocations,
@@ -58,6 +60,7 @@ import {
58
60
  isFailClosedBlockingError,
59
61
  shouldBypassFailClosedBlock,
60
62
  createFailClosedController,
63
+ setHomeProjectPermission,
61
64
  ProjectIdentityError,
62
65
  resolveProjectIdentityStrict,
63
66
  isUserHomeDirectory,
@@ -301,6 +304,7 @@ import {
301
304
  readPiSessionMessages,
302
305
  readPiSessionMessagePage,
303
306
  findLastModelKeyFromBranch,
307
+ iterateEntriesToRawMessageRange,
304
308
  convertEntriesToRawMessages,
305
309
  convertEntriesToRawMessagePage,
306
310
  computeCueContentHash,
@@ -399,6 +403,9 @@ import {
399
403
  MEMORY_RENDER_FORMAT_EPOCH,
400
404
  encodeCachedM0UpgradeIdentity,
401
405
  decodeCachedM0UpgradeIdentity,
406
+ renderBudgetIdentityChanged,
407
+ renderedBudgetSnapshot,
408
+ renderedBudgetShrinkReason,
402
409
  DEFAULT_HISTORY_BUDGET_TOKENS,
403
410
  renderCompartmentAtTier,
404
411
  renderDecayedCompartments,
@@ -423,8 +430,10 @@ import {
423
430
  registerTodoStateLifecycle,
424
431
  syncCtxMemoryToolEnabled,
425
432
  registerMagicContextTools
426
- } from "./index-esnhck8v.js";
433
+ } from "./index-5am7amy4.js";
427
434
  import {
435
+ Database,
436
+ withSqliteBackgroundWriter,
428
437
  CTX_REDUCE_KEEP,
429
438
  newestCtxReduceTagNumbers,
430
439
  textMentionsRecentCommit,
@@ -500,7 +509,6 @@ import {
500
509
  recordOpenCodeDbReadFailure,
501
510
  clearOpenCodeDbReadFailure,
502
511
  claimOpenCodeDbDiagnosticOnce,
503
- Database,
504
512
  closeQuietly,
505
513
  RAW_SUMMARY_TEXT_MAX_CHARS,
506
514
  completedToolArcCrossesBoundary,
@@ -511,6 +519,7 @@ import {
511
519
  buildTrueRawTokenIndex,
512
520
  computeRawRangeFingerprint,
513
521
  invalidateTrueRawTokenCache,
522
+ hasUserAnswerMetadata,
514
523
  DreamTokenBudgetExceeded,
515
524
  TOKEN_BUDGET_FINALIZE_MESSAGE,
516
525
  TOKEN_BUDGET_TOOL_REFUSAL,
@@ -543,7 +552,7 @@ import {
543
552
  getRawSessionTagKeysThrough2,
544
553
  getLegacyProtectedTailStartOrdinal2,
545
554
  readSessionChunk2
546
- } from "./index-gsff513e.js";
555
+ } from "./index-npagr1cy.js";
547
556
  import {
548
557
  pushNotification2
549
558
  } from "./index-b3eqj1g6.js";
@@ -1071,7 +1080,7 @@ async function reconcileSessionIndex(db, sessionId, readMessages) {
1071
1080
  const messages = readMessages.readPage ? readMessages.readPage(sessionId, cursor, RECONCILIATION_BATCH_SIZE, finalWatermark) : (fallbackSnapshot ?? []).filter((message) => message.ordinal > cursor && message.ordinal <= pageEnd);
1072
1081
  const retainedMessages = fallbackSnapshot ?? messages;
1073
1082
  heapHolder.activeReconcilerBuffers.set(sessionId, retainedMessages);
1074
- indexMessagesAfterOrdinal(db, sessionId, messages, cursor, pageEnd);
1083
+ withSqliteBackgroundWriter(() => indexMessagesAfterOrdinal(db, sessionId, messages, cursor, pageEnd));
1075
1084
  const nextCursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
1076
1085
  if (nextCursor <= cursor)
1077
1086
  break;
@@ -1097,6 +1106,8 @@ function scheduleReconciliation(db, sessionId, readMessages) {
1097
1106
  defer(() => {
1098
1107
  reconcileSessionIndex(db, sessionId, readMessages).catch((error) => {
1099
1108
  logIndexingError(sessionId, "reconciliation", error);
1109
+ if (isDatabaseLockedError(error))
1110
+ setTimeout(() => scheduleReconciliation(db, sessionId, readMessages), 1000).unref();
1100
1111
  }).finally(() => {
1101
1112
  heapHolder.reconciliationScheduledSessions.delete(sessionId);
1102
1113
  });
@@ -1126,7 +1137,7 @@ function scheduleIncrementalIndex(db, sessionId, messageId, messageSource) {
1126
1137
  return;
1127
1138
  }
1128
1139
  const wasReconciled = heapHolder.reconciledSessions.delete(sessionId);
1129
- indexSingleMessage(db, sessionId, message);
1140
+ withSqliteBackgroundWriter(() => indexSingleMessage(db, sessionId, message));
1130
1141
  const finalWatermark = getLastIndexedOrdinal(db, sessionId);
1131
1142
  if (wasReconciled && isMessageIndexReconciledThrough(db, sessionId, finalWatermark)) {
1132
1143
  heapHolder.reconciledSessions.add(sessionId);
@@ -1135,6 +1146,8 @@ function scheduleIncrementalIndex(db, sessionId, messageId, messageSource) {
1135
1146
  }).catch((error) => {
1136
1147
  heapHolder.reconciledSessions.delete(sessionId);
1137
1148
  logIndexingError(sessionId, `incremental index for ${messageId}`, error);
1149
+ if (isDatabaseLockedError(error))
1150
+ setTimeout(() => scheduleIncrementalIndex(db, sessionId, messageId, messageSource), 1000).unref();
1138
1151
  }).finally(() => {
1139
1152
  heapHolder.pendingIncrementalKeys.delete(schedulingKey);
1140
1153
  });
@@ -1750,7 +1763,7 @@ function countFailures(db) {
1750
1763
  function classifyBackfillError(error) {
1751
1764
  if (error instanceof ProjectIdentityError) {
1752
1765
  return {
1753
- errorClass: error.errorClass === "dubious_ownership" || error.errorClass === "home_project_disabled" || error.errorClass === "git_identity_unavailable" ? "unknown" : error.errorClass,
1766
+ errorClass: error.errorClass === "dubious_ownership" || error.errorClass === "home_project_disabled" || error.errorClass === "git_identity_unavailable" || error.errorClass === "no_commits" ? "unknown" : error.errorClass,
1754
1767
  errorMessage: error.message
1755
1768
  };
1756
1769
  }
@@ -1989,6 +2002,21 @@ function resolveKnownHistorianContextLimit(historianModelOverride) {
1989
2002
  const limit = getSdkContextLimit(providerID, modelID, undefined, { reservation: "none" });
1990
2003
  return typeof limit === "number" && limit > 0 ? limit : undefined;
1991
2004
  }
2005
+ function resolveHistorianProducerLimits(modelKey) {
2006
+ if (!modelKey?.includes("/"))
2007
+ return {};
2008
+ const [provider, ...parts] = modelKey.split("/");
2009
+ const model = parts.join("/");
2010
+ if (!provider || !model)
2011
+ return {};
2012
+ const input = getSdkInputLimit(provider, model);
2013
+ const window = getSdkWindowGeometry(provider, model)?.derivation.window;
2014
+ const context = window ?? (input === undefined ? resolveKnownHistorianContextLimit(modelKey) : undefined);
2015
+ return {
2016
+ ...context !== undefined ? { context } : {},
2017
+ ...input !== undefined ? { input } : {}
2018
+ };
2019
+ }
1992
2020
  function resolveHistorianContextLimit(historianModelOverride) {
1993
2021
  if (typeof historianModelOverride === "string" && historianModelOverride.includes("/")) {
1994
2022
  return resolveKnownHistorianContextLimit(historianModelOverride) ?? DEFAULT_HISTORIAN_CONTEXT_FALLBACK;
@@ -4185,6 +4213,27 @@ function forgetHistorianOutputCap(sessionId) {
4185
4213
  historianCaps.delete(sessionId);
4186
4214
  }
4187
4215
 
4216
+ // ../plugin/src/shared/run-token-log.ts
4217
+ function count(value) {
4218
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
4219
+ }
4220
+ function runTokenLog(tokens, maxTokens, finish) {
4221
+ const usage = tokens && typeof tokens === "object" ? tokens : {};
4222
+ const cache = usage.cache && typeof usage.cache === "object" ? usage.cache : {};
4223
+ return {
4224
+ input: count(usage.input ?? usage.input_tokens),
4225
+ output: count(usage.output ?? usage.output_tokens),
4226
+ reasoning: count(usage.reasoning ?? usage.reasoning_tokens),
4227
+ cache_read: count(usage.cacheRead ?? usage.cache_read ?? usage.cached_input_tokens ?? cache.read),
4228
+ cache_write: count(usage.cacheWrite ?? usage.cache_write ?? usage.cache_write_tokens ?? cache.write),
4229
+ max_tokens: count(maxTokens),
4230
+ finish_reason: typeof finish === "string" ? finish : null
4231
+ };
4232
+ }
4233
+ function formatRunTokenLog(tokens) {
4234
+ return `tokens=${JSON.stringify(tokens)}`;
4235
+ }
4236
+
4188
4237
  // ../plugin/src/hooks/magic-context/historian-prompt.generated.ts
4189
4238
  var COMPARTMENT_AGENT_SYSTEM_PROMPT = `# Historian
4190
4239
 
@@ -5347,11 +5396,14 @@ function clampProducerAtomChars(text, maxChars, marker) {
5347
5396
  const tailChars = Math.floor(keptChars / 2);
5348
5397
  return `${text.slice(0, headChars)}${marker}${text.slice(text.length - tailChars)}`;
5349
5398
  }
5350
- function producerInputTokenLimit(contextLimitTokens, maxOutputTokens) {
5351
- if (typeof contextLimitTokens !== "number" || !Number.isFinite(contextLimitTokens) || contextLimitTokens <= 0 || !Number.isFinite(maxOutputTokens) || maxOutputTokens < 0) {
5399
+ function producerInputTokenLimit(contextLimitTokens, maxOutputTokens, inputLimitTokens) {
5400
+ if (!Number.isFinite(maxOutputTokens) || maxOutputTokens < 0)
5352
5401
  return;
5353
- }
5354
- const usableInputTokens = Math.floor(contextLimitTokens - maxOutputTokens);
5402
+ const shared = typeof contextLimitTokens === "number" && Number.isFinite(contextLimitTokens) && contextLimitTokens > 0 ? contextLimitTokens - maxOutputTokens : undefined;
5403
+ const input = typeof inputLimitTokens === "number" && Number.isFinite(inputLimitTokens) && inputLimitTokens > 0 ? inputLimitTokens : undefined;
5404
+ if (shared === undefined && input === undefined)
5405
+ return;
5406
+ const usableInputTokens = Math.floor(Math.min(shared ?? Infinity, input ?? Infinity));
5355
5407
  if (usableInputTokens <= 0)
5356
5408
  return;
5357
5409
  const limit = Math.floor(usableInputTokens * (1 - PRODUCER_WINDOW_REFUSAL_MARGIN));
@@ -5363,15 +5415,15 @@ function historianProducerReserve(window, configuredOutput, catalogOutput) {
5363
5415
  return window === undefined ? 0 : catalogOutputReserve(window, catalogOutput);
5364
5416
  }
5365
5417
  function producerWindowFailureReason(input) {
5366
- const { producerSourceTokens, contextLimitTokens, maxOutputTokens } = input;
5367
- const producerInputLimitTokens = producerInputTokenLimit(contextLimitTokens, maxOutputTokens);
5368
- if (producerInputLimitTokens === undefined || typeof contextLimitTokens !== "number" || !Number.isFinite(producerSourceTokens) || producerSourceTokens <= 0) {
5418
+ const { producerSourceTokens, contextLimitTokens, inputLimitTokens, maxOutputTokens } = input;
5419
+ const producerInputLimitTokens = producerInputTokenLimit(contextLimitTokens, maxOutputTokens, inputLimitTokens);
5420
+ if (producerInputLimitTokens === undefined || !Number.isFinite(producerSourceTokens) || producerSourceTokens <= 0) {
5369
5421
  return null;
5370
5422
  }
5371
- const usableInputTokens = Math.max(0, Math.floor(contextLimitTokens - maxOutputTokens));
5423
+ const usableInputTokens = Math.floor(Math.min(contextLimitTokens === undefined ? Infinity : Math.max(0, contextLimitTokens - maxOutputTokens), inputLimitTokens ?? Infinity));
5372
5424
  if (producerSourceTokens <= producerInputLimitTokens)
5373
5425
  return null;
5374
- return `producer_source_exceeds_window producer_source_tokens=${Math.round(producerSourceTokens)} usable_input_tokens=${usableInputTokens} producer_input_limit_tokens=${producerInputLimitTokens} context_limit_tokens=${Math.round(contextLimitTokens)} max_output_tokens=${Math.round(maxOutputTokens)} estimator_margin=${PRODUCER_WINDOW_REFUSAL_MARGIN}`;
5426
+ return `producer_source_exceeds_window producer_source_tokens=${Math.round(producerSourceTokens)} usable_input_tokens=${usableInputTokens} producer_input_limit_tokens=${producerInputLimitTokens} context_limit_tokens=${contextLimitTokens === undefined ? "unknown" : Math.round(contextLimitTokens)} max_output_tokens=${Math.round(maxOutputTokens)} estimator_margin=${PRODUCER_WINDOW_REFUSAL_MARGIN}`;
5375
5427
  }
5376
5428
  function splitMarkerPair() {
5377
5429
  return `
@@ -5380,7 +5432,7 @@ ${HISTORIAN_TRUNCATION_MARKER}
5380
5432
  `;
5381
5433
  }
5382
5434
  function fitAtomicHistorianSourceToProducerWindow(args) {
5383
- const producerInputLimitTokens = producerInputTokenLimit(args.contextLimitTokens, args.maxOutputTokens);
5435
+ const producerInputLimitTokens = producerInputTokenLimit(args.contextLimitTokens, args.maxOutputTokens, args.inputLimitTokens);
5384
5436
  const originalTokens = estimateTokens(args.text);
5385
5437
  if (producerInputLimitTokens === undefined || originalTokens < producerInputLimitTokens || producerInputLimitTokens <= 0) {
5386
5438
  return { text: args.text, producerInputLimitTokens, removedTokens: 0 };
@@ -5414,7 +5466,7 @@ function fitAtomicHistorianSourceToProducerWindow(args) {
5414
5466
  };
5415
5467
  }
5416
5468
  function producerPromptFailureReason(input) {
5417
- const limit = producerInputTokenLimit(input.contextLimitTokens, input.maxOutputTokens);
5469
+ const limit = producerInputTokenLimit(input.contextLimitTokens, input.maxOutputTokens, input.inputLimitTokens);
5418
5470
  const tokens = providerMass({ prose: input.sourceLocal, system: input.systemLocal, tools: input.toolsLocal }, calibrationForModelKey(input.modelKey), true);
5419
5471
  if (limit === undefined)
5420
5472
  return null;
@@ -5525,12 +5577,15 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
5525
5577
  throw new Error(`Historian host recorded an assistant error${finish}: ${describeAssistantFailure(assistantFailure.error)}`);
5526
5578
  }
5527
5579
  const text = extractLatestAssistantText(messages);
5580
+ const latest = Array.isArray(messages) ? messages.filter((message) => isRecord(message) && isRecord(message.info) && message.info.role === "assistant").sort((left, right) => historianMessageCreatedAt(right) - historianMessageCreatedAt(left))[0] : undefined;
5581
+ const info = latest && isRecord(latest.info) ? latest.info : {};
5528
5582
  return {
5529
5583
  messages,
5530
5584
  text,
5531
5585
  reasoning: text ? null : extractLatestHistorianReasoning(messages),
5532
5586
  lengthCapped: hasLengthCappedOutput(messages),
5533
- usage: sumTokensFromChildMessages(messages)
5587
+ usage: sumTokensFromChildMessages(messages),
5588
+ tokenLog: runTokenLog(info.tokens, undefined, info.finish ?? info.finish_reason ?? info.finishReason)
5534
5589
  };
5535
5590
  },
5536
5591
  async close(handle, settlement) {
@@ -5549,8 +5604,8 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
5549
5604
  }
5550
5605
  };
5551
5606
  }
5552
- function historianReasoningBudgetDiagnostic(outputTokens) {
5553
- return `historian ran out of output budget while reasoning (length-capped at ${outputTokens} tokens, no text) — set historian.maxTokens or route historian.model to a low-reasoning lane/variant`;
5607
+ function historianReasoningBudgetDiagnostic(outputTokens, tokens) {
5608
+ return `historian ran out of output budget while reasoning (length-capped at ${outputTokens} tokens, no text${tokens ? `; ${formatRunTokenLog(tokens)}` : ""}) — set historian.maxTokens or route historian.model to a low-reasoning lane/variant`;
5554
5609
  }
5555
5610
  async function runValidatedHistorianPass(args) {
5556
5611
  const firstRun = await runHistorianPrompt({
@@ -5739,8 +5794,10 @@ async function runHistorianPrompt(args) {
5739
5794
  const modelKey = selected ? `${selected.providerID}/${selected.modelID}` : undefined;
5740
5795
  const system = withContentLanguageDirective(agentId === HISTORIAN_EDITOR_AGENT ? HISTORIAN_EDITOR_SYSTEM_PROMPT : COMPARTMENT_AGENT_SYSTEM_PROMPT, args.language);
5741
5796
  const contextLimitTokens = selected ? getSdkContextLimit(selected.providerID, selected.modelID, undefined, { reservation: "none" }) : undefined;
5742
- const reserve = historianProducerReserve(contextLimitTokens, args.maxOutputTokens, selected ? getSdkOutputLimit(selected.providerID, selected.modelID) : undefined);
5743
- if (contextLimitTokens !== undefined && producerInputTokenLimit(contextLimitTokens, reserve) === undefined && modelKey && !unknownProducerWindows.has(modelKey)) {
5797
+ const producerLimits = selected ? resolveHistorianProducerLimits(modelKey) : {};
5798
+ const producerContext = producerLimits.context ?? (producerLimits.input === undefined ? contextLimitTokens : undefined);
5799
+ const reserve = historianProducerReserve(producerContext, args.maxOutputTokens, selected ? getSdkOutputLimit(selected.providerID, selected.modelID) : undefined);
5800
+ if (contextLimitTokens !== undefined && producerInputTokenLimit(producerContext, reserve, producerLimits.input) === undefined && modelKey && !unknownProducerWindows.has(modelKey)) {
5744
5801
  unknownProducerWindows.add(modelKey);
5745
5802
  sessionLog(parentSessionId, `producer window inconsistent for ${modelKey}: window=${contextLimitTokens} reserve=${reserve}; sending unguarded`);
5746
5803
  }
@@ -5749,7 +5806,8 @@ async function runHistorianPrompt(args) {
5749
5806
  systemLocal: estimateTokens(system),
5750
5807
  toolsLocal: 0,
5751
5808
  modelKey,
5752
- contextLimitTokens,
5809
+ contextLimitTokens: producerContext,
5810
+ inputLimitTokens: producerLimits.input,
5753
5811
  maxOutputTokens: reserve
5754
5812
  });
5755
5813
  if (failure)
@@ -5783,9 +5841,15 @@ async function runHistorianPrompt(args) {
5783
5841
  }
5784
5842
  completion = await executor.collect(handle, 50);
5785
5843
  const lengthCapped = completion.lengthCapped;
5844
+ const tokens = {
5845
+ ...runTokenLog(undefined, args.maxOutputTokens),
5846
+ ...completion.tokenLog,
5847
+ max_tokens: args.maxOutputTokens ?? null
5848
+ };
5849
+ sessionLog(parentSessionId, `historian response_chars=${(completion.text ?? completion.reasoning ?? "").length} ${formatRunTokenLog(tokens)}`);
5786
5850
  const textResult = completion.text;
5787
5851
  const reasoningResult = textResult ? null : completion.reasoning;
5788
- const emptyError = !textResult && reasoningResult && lengthCapped ? historianReasoningBudgetDiagnostic(completion.usage.output) : !textResult && !reasoningResult ? "Historian returned no assistant output." : !textResult ? "Historian returned reasoning but no assistant text." : lengthCapped ? "Historian returned length-capped output." : null;
5852
+ const emptyError = !textResult && reasoningResult && lengthCapped ? historianReasoningBudgetDiagnostic(completion.usage.output, tokens) : !textResult && !reasoningResult ? "Historian returned no assistant output." : !textResult ? "Historian returned reasoning but no assistant text." : lengthCapped ? `Historian returned length-capped output. ${formatRunTokenLog(tokens)}` : null;
5789
5853
  const invocationId = recordInvocation({
5790
5854
  status: emptyError ? "empty" : "completed",
5791
5855
  messages: completion.messages,
@@ -6159,7 +6223,7 @@ function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisiti
6159
6223
  }
6160
6224
  };
6161
6225
  beat();
6162
- const timer = lost ? undefined : setInterval(beat, intervalMs);
6226
+ const timer = lost ? undefined : setInterval(() => withSqliteBackgroundWriter(beat), intervalMs);
6163
6227
  return {
6164
6228
  stop: () => {
6165
6229
  if (timer)
@@ -6878,8 +6942,10 @@ async function runHiddenSingleShotPrompt(args) {
6878
6942
  callContext: args.callContext,
6879
6943
  fetchOutput: () => args.executor.collect(handle, 50),
6880
6944
  validateOutput: (completion) => {
6945
+ const tokens = completion.tokenLog ?? runTokenLog(undefined);
6946
+ sessionLog(args.parentSessionId ?? "dreamer", `${args.callContext} response_chars=${(completion.text ?? completion.reasoning ?? "").length} ${formatRunTokenLog(tokens)}`);
6881
6947
  if (completion.lengthCapped) {
6882
- throw new Error(completion.reasoning && !completion.text ? `${args.callContext} ran out of output budget while reasoning (length-capped at ${completion.usage.output} tokens, no text) — set dreamer.maxTokens or use a low-reasoning model` : `${args.callContext} returned length-capped output`);
6948
+ throw new Error(completion.reasoning && !completion.text ? `${args.callContext} ran out of output budget while reasoning (length-capped at ${completion.usage.output} tokens, no text; ${formatRunTokenLog(tokens)}) — set dreamer.maxTokens or use a low-reasoning model` : `${args.callContext} returned length-capped output; ${formatRunTokenLog(tokens)}`);
6883
6949
  }
6884
6950
  const text = completion.text;
6885
6951
  if (!text && !args.allowEmpty)
@@ -7714,8 +7780,10 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
7714
7780
  fetchOutput: () => executor.collect(opened, 50),
7715
7781
  validateOutput: (completion) => {
7716
7782
  const messages = completion.messages ?? [];
7783
+ const tokens = completion.tokenLog ?? runTokenLog(undefined);
7784
+ sessionLog(args.parentSessionId ?? "dreamer", `dreamer:classify response_chars=${(completion.text ?? completion.reasoning ?? "").length} ${formatRunTokenLog(tokens)}`);
7717
7785
  if (completion.lengthCapped) {
7718
- throw new Error(completion.reasoning && !completion.text ? `classify ran out of output budget while reasoning (length-capped at ${completion.usage.output} tokens, no text) — set dreamer.maxTokens or use a low-reasoning model` : "classify returned length-capped output");
7786
+ throw new Error(completion.reasoning && !completion.text ? `classify ran out of output budget while reasoning (length-capped at ${completion.usage.output} tokens, no text; ${formatRunTokenLog(tokens)}) — set dreamer.maxTokens or use a low-reasoning model` : `classify returned length-capped output; ${formatRunTokenLog(tokens)}`);
7719
7787
  }
7720
7788
  const text = completion.text;
7721
7789
  if (!text)
@@ -10339,6 +10407,11 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
10339
10407
  let agentSessionId = null;
10340
10408
  let promptSettled = false;
10341
10409
  const startedAt = Date.now();
10410
+ let budgetFinalized = false;
10411
+ const onBudgetUpdate = (state) => {
10412
+ budgetFinalized ||= state.finalizeFired;
10413
+ args.onBudgetUpdate?.(state);
10414
+ };
10342
10415
  try {
10343
10416
  const prompt = buildMapMemoriesPrompt(args.projectIdentity, batch);
10344
10417
  if (args.hiddenCompletionExecutor) {
@@ -10351,7 +10424,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
10351
10424
  prompt,
10352
10425
  title: "magic-context-dream-map-memories",
10353
10426
  callContext: "dreamer:map-memories",
10354
- metadata: { tokenBudget: args.tokenBudget, onBudgetUpdate: args.onBudgetUpdate },
10427
+ metadata: { tokenBudget: args.tokenBudget, onBudgetUpdate },
10355
10428
  model: args.model,
10356
10429
  fallbackModels: args.fallbackModels,
10357
10430
  timeoutMs: sliceMs,
@@ -10362,9 +10435,12 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
10362
10435
  status: "completed",
10363
10436
  messages: run.completion.messages ?? []
10364
10437
  });
10365
- const outcome = await applyParsedBatchMappings(args, batch, run.validated);
10438
+ const outcome = await applyParsedBatchMappings(args, batch, run.validated, budgetFinalized);
10366
10439
  const returnedIds = new Set(run.validated.map((entry) => entry.id));
10367
- return { ...outcome, requeue: batch.filter((memory) => !returnedIds.has(memory.id)) };
10440
+ return {
10441
+ ...outcome,
10442
+ requeue: budgetFinalized ? [] : batch.filter((memory) => !returnedIds.has(memory.id))
10443
+ };
10368
10444
  }
10369
10445
  const client = args.client;
10370
10446
  if (!client)
@@ -10394,7 +10470,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
10394
10470
  }, {
10395
10471
  transport: createPromptAsyncTransport(client, agentSessionId, {
10396
10472
  tokenBudget: args.tokenBudget,
10397
- onBudgetUpdate: args.onBudgetUpdate
10473
+ onBudgetUpdate
10398
10474
  }),
10399
10475
  timeoutMs: sliceMs,
10400
10476
  signal,
@@ -10421,11 +10497,11 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
10421
10497
  });
10422
10498
  promptSettled = true;
10423
10499
  recordInvocation2(args, startedAt, { status: "completed", messages: run.output });
10424
- const outcome = await applyParsedBatchMappings(args, batch, run.validated);
10500
+ const outcome = await applyParsedBatchMappings(args, batch, run.validated, budgetFinalized);
10425
10501
  const returnedIds = new Set(run.validated.filter((entry) => batch.some((memory) => memory.id === entry.id)).map((entry) => entry.id));
10426
10502
  return {
10427
10503
  ...outcome,
10428
- requeue: batch.filter((memory) => !returnedIds.has(memory.id))
10504
+ requeue: budgetFinalized ? [] : batch.filter((memory) => !returnedIds.has(memory.id))
10429
10505
  };
10430
10506
  } catch (error) {
10431
10507
  const desc = describeError(error);
@@ -10460,7 +10536,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
10460
10536
  });
10461
10537
  }
10462
10538
  }
10463
- async function applyParsedBatchMappings(args, batch, parsed) {
10539
+ async function applyParsedBatchMappings(args, batch, parsed, budgetFinalized = false) {
10464
10540
  const batchIds = new Set(batch.map((memory) => memory.id));
10465
10541
  const valid = parsed.filter((entry) => batchIds.has(entry.id));
10466
10542
  const unknown = parsed.filter((entry) => !batchIds.has(entry.id));
@@ -10468,9 +10544,12 @@ async function applyParsedBatchMappings(args, batch, parsed) {
10468
10544
  log(`[dreamer] map-memories warning: dropping ${unknown.length} unknown mapping entr${unknown.length === 1 ? "y" : "ies"} outside the current batch (${unknown.map((entry) => entry.id).join(", ")})`);
10469
10545
  }
10470
10546
  assertNoDuplicateManifestIds(valid.map((entry) => entry.id), "mappings");
10471
- if (valid.length * 2 < batch.length) {
10547
+ if (!budgetFinalized && valid.length * 2 < batch.length) {
10472
10548
  throw new Error(`mappings manifest covers ${valid.length}/${batch.length} batch ids after filtering unknown entries; rejecting mostly-wrong manifest`);
10473
10549
  }
10550
+ if (budgetFinalized && valid.length < batch.length) {
10551
+ log(`[dreamer] map-memories: accepted partial manifest after token budget: ${valid.length}/${batch.length}`);
10552
+ }
10474
10553
  if (valid.length === 0)
10475
10554
  return { mapped: 0, independent: 0 };
10476
10555
  const planned = [];
@@ -12247,6 +12326,11 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
12247
12326
  let agentSessionId = null;
12248
12327
  let promptSettled = false;
12249
12328
  const startedAt = Date.now();
12329
+ let budgetFinalized = false;
12330
+ const onBudgetUpdate = (state) => {
12331
+ budgetFinalized ||= state.finalizeFired;
12332
+ args.onBudgetUpdate?.(state);
12333
+ };
12250
12334
  try {
12251
12335
  const headAtPrompt = await readGitHead(args.sessionDirectory);
12252
12336
  const evidence = !args.forceBroad && batch.every((m) => m.verifiedAt) ? await buildVerifyDiffEvidence(args.sessionDirectory, batch) : null;
@@ -12261,7 +12345,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
12261
12345
  prompt,
12262
12346
  title: "magic-context-dream-verify",
12263
12347
  callContext: "dreamer:verify",
12264
- metadata: { tokenBudget: args.tokenBudget, onBudgetUpdate: args.onBudgetUpdate },
12348
+ metadata: { tokenBudget: args.tokenBudget, onBudgetUpdate },
12265
12349
  model: args.model,
12266
12350
  fallbackModels: args.fallbackModels,
12267
12351
  language: args.language,
@@ -12278,7 +12362,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
12278
12362
  status: "completed",
12279
12363
  messages: run.completion.messages ?? []
12280
12364
  });
12281
- return applyParsedVerifyManifest(args, batch, run.validated, evidence?.head ?? headAtPrompt);
12365
+ return applyParsedVerifyManifest(args, batch, run.validated, evidence?.head ?? headAtPrompt, budgetFinalized);
12282
12366
  }
12283
12367
  const client = args.client;
12284
12368
  if (!client)
@@ -12308,7 +12392,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
12308
12392
  }, {
12309
12393
  transport: createPromptAsyncTransport(client, agentSessionId, {
12310
12394
  tokenBudget: args.tokenBudget,
12311
- onBudgetUpdate: args.onBudgetUpdate
12395
+ onBudgetUpdate
12312
12396
  }),
12313
12397
  timeoutMs: sliceMs,
12314
12398
  signal,
@@ -12338,7 +12422,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
12338
12422
  });
12339
12423
  promptSettled = true;
12340
12424
  recordInvocation4(args, startedAt, { status: "completed", messages: run.output });
12341
- return await applyParsedVerifyManifest(args, batch, run.validated, evidence?.head ?? headAtPrompt);
12425
+ return await applyParsedVerifyManifest(args, batch, run.validated, evidence?.head ?? headAtPrompt, budgetFinalized);
12342
12426
  } catch (error) {
12343
12427
  const desc = describeError(error);
12344
12428
  const providerFailure = error instanceof DreamerProviderOutputFailureError ? error : undefined;
@@ -12384,7 +12468,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
12384
12468
  });
12385
12469
  }
12386
12470
  }
12387
- async function applyParsedVerifyManifest(args, batch, parsed, headAtPrompt) {
12471
+ async function applyParsedVerifyManifest(args, batch, parsed, headAtPrompt, budgetFinalized = false) {
12388
12472
  const batchIds = new Set(batch.map((m) => m.id));
12389
12473
  const batchById = new Map(batch.map((memory) => [memory.id, memory]));
12390
12474
  const valid = {
@@ -12404,9 +12488,12 @@ async function applyParsedVerifyManifest(args, batch, parsed, headAtPrompt) {
12404
12488
  }
12405
12489
  const validIds = [...valid.verified, ...valid.updated, ...valid.archived, ...valid.skipped].map((entry) => entry.id);
12406
12490
  assertNoDuplicateManifestIds(validIds, "verify");
12407
- if (validIds.length * 2 < batch.length) {
12491
+ if (!budgetFinalized && validIds.length * 2 < batch.length) {
12408
12492
  throw new Error(`verify manifest covers ${validIds.length}/${batch.length} batch ids after filtering unknown entries; rejecting mostly-wrong manifest`);
12409
12493
  }
12494
+ if (budgetFinalized && validIds.length < batch.length) {
12495
+ log(`[dreamer] verify: accepted partial manifest after token budget: ${validIds.length}/${batch.length}`);
12496
+ }
12410
12497
  if (validIds.length === 0) {
12411
12498
  return { verified: 0, updated: 0, archived: 0, skipped: 0, refused: 0 };
12412
12499
  }
@@ -14433,6 +14520,205 @@ function clearDreamerTickFailure(db) {
14433
14520
  db.prepare("DELETE FROM schema_migrations_meta WHERE key = ?").run(DREAMER_TICK_FAILURE_KEY);
14434
14521
  }
14435
14522
 
14523
+ // ../plugin/src/hooks/magic-context/lkg-persist.ts
14524
+ import { createHash as createHash11 } from "node:crypto";
14525
+ function parseStringArray(value) {
14526
+ if (typeof value !== "string")
14527
+ return null;
14528
+ let parsed;
14529
+ try {
14530
+ parsed = JSON.parse(value);
14531
+ } catch {
14532
+ return null;
14533
+ }
14534
+ if (!Array.isArray(parsed))
14535
+ return null;
14536
+ const result = [];
14537
+ for (const entry of parsed) {
14538
+ if (typeof entry !== "string" || entry.length === 0)
14539
+ return null;
14540
+ result.push(entry);
14541
+ }
14542
+ return result;
14543
+ }
14544
+ function parseNullableString(value) {
14545
+ if (value === null || value === undefined)
14546
+ return null;
14547
+ return typeof value === "string" ? value : undefined;
14548
+ }
14549
+ function parseNullableInteger(value) {
14550
+ if (value === null || value === undefined)
14551
+ return;
14552
+ return typeof value === "number" && Number.isSafeInteger(value) ? value : undefined;
14553
+ }
14554
+ function parsePersistedLkgSlot(row) {
14555
+ if (!row || typeof row !== "object")
14556
+ return;
14557
+ const record = row;
14558
+ const jsonPrefix = record.json_prefix;
14559
+ const lastInputMessageId = record.last_input_message_id;
14560
+ const capturedAt = record.captured_at;
14561
+ let inputIdsRaw = record.input_id_seq;
14562
+ let piOutputEntryIds;
14563
+ if (typeof inputIdsRaw === "string") {
14564
+ try {
14565
+ const metadata = JSON.parse(inputIdsRaw);
14566
+ if (metadata && !Array.isArray(metadata) && metadata.version === 1 && Array.isArray(metadata.piOutputEntryIds)) {
14567
+ if (!metadata.piOutputEntryIds.every((id) => id === null || typeof id === "string" && id.length > 0))
14568
+ return;
14569
+ piOutputEntryIds = metadata.piOutputEntryIds;
14570
+ inputIdsRaw = JSON.stringify(metadata.inputIds);
14571
+ }
14572
+ } catch {
14573
+ return;
14574
+ }
14575
+ }
14576
+ const inputIdSeq = parseStringArray(inputIdsRaw);
14577
+ const inputContentDigests = parseStringArray(record.input_content_digests);
14578
+ const modelKey = parseNullableString(record.model_key);
14579
+ const providerKey = parseNullableString(record.provider_key);
14580
+ if (typeof jsonPrefix !== "string" || typeof lastInputMessageId !== "string" || lastInputMessageId.length === 0 || typeof capturedAt !== "number" || !Number.isFinite(capturedAt) || inputIdSeq === null || inputContentDigests === null || inputContentDigests.length !== inputIdSeq.length || modelKey === undefined || providerKey === undefined) {
14581
+ return;
14582
+ }
14583
+ if (piOutputEntryIds) {
14584
+ try {
14585
+ const output = JSON.parse(jsonPrefix);
14586
+ const inputs = new Set(inputIdSeq);
14587
+ if (!Array.isArray(output) || output.length !== piOutputEntryIds.length || piOutputEntryIds.some((id) => id !== null && !inputs.has(id)))
14588
+ return;
14589
+ } catch {
14590
+ return;
14591
+ }
14592
+ }
14593
+ let inputContentSignatures;
14594
+ if (record.input_content_signatures !== null && record.input_content_signatures !== undefined) {
14595
+ const parsed = parseStringArray(record.input_content_signatures);
14596
+ if (parsed === null || parsed.length !== inputIdSeq.length)
14597
+ return;
14598
+ inputContentSignatures = parsed;
14599
+ }
14600
+ const slot = {
14601
+ jsonPrefix,
14602
+ inputIdSeq,
14603
+ inputContentDigests,
14604
+ lastInputMessageId,
14605
+ modelKey,
14606
+ providerKey,
14607
+ capturedAt
14608
+ };
14609
+ if (inputContentSignatures)
14610
+ slot.inputContentSignatures = inputContentSignatures;
14611
+ if (piOutputEntryIds)
14612
+ slot.piOutputEntryIds = piOutputEntryIds;
14613
+ const rowVersion = parseNullableInteger(record.row_version);
14614
+ if (rowVersion !== undefined)
14615
+ slot.rowVersion = rowVersion;
14616
+ const captureSequence = parseNullableInteger(record.capture_sequence);
14617
+ if (captureSequence !== undefined)
14618
+ slot.captureSequence = captureSequence;
14619
+ return slot;
14620
+ }
14621
+ var persistedFingerprints = new WeakMap;
14622
+ function saveLkgSlotToDb(db, sessionId, slot) {
14623
+ const fingerprint = createHash11("sha256").update(JSON.stringify([
14624
+ slot.jsonPrefix,
14625
+ slot.inputIdSeq,
14626
+ slot.inputContentDigests,
14627
+ slot.inputContentSignatures,
14628
+ slot.piOutputEntryIds,
14629
+ slot.lastInputMessageId,
14630
+ slot.modelKey,
14631
+ slot.providerKey,
14632
+ slot.rowVersion,
14633
+ slot.captureSequence
14634
+ ])).digest("hex");
14635
+ let saved = persistedFingerprints.get(db);
14636
+ if (saved?.get(sessionId) === fingerprint)
14637
+ return true;
14638
+ try {
14639
+ db.prepare(`INSERT INTO lkg_slots (
14640
+ session_id, json_prefix, input_id_seq, input_content_digests,
14641
+ input_content_signatures, last_input_message_id, model_key, provider_key,
14642
+ captured_at, row_version, capture_sequence
14643
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
14644
+ ON CONFLICT(session_id) DO UPDATE SET
14645
+ json_prefix = excluded.json_prefix,
14646
+ input_id_seq = excluded.input_id_seq,
14647
+ input_content_digests = excluded.input_content_digests,
14648
+ input_content_signatures = excluded.input_content_signatures,
14649
+ last_input_message_id = excluded.last_input_message_id,
14650
+ model_key = excluded.model_key,
14651
+ provider_key = excluded.provider_key,
14652
+ captured_at = excluded.captured_at,
14653
+ row_version = excluded.row_version,
14654
+ capture_sequence = excluded.capture_sequence`).run(sessionId, slot.jsonPrefix, JSON.stringify(slot.piOutputEntryIds ? {
14655
+ version: 1,
14656
+ inputIds: slot.inputIdSeq,
14657
+ piOutputEntryIds: slot.piOutputEntryIds
14658
+ } : slot.inputIdSeq), JSON.stringify(slot.inputContentDigests), slot.inputContentSignatures ? JSON.stringify(slot.inputContentSignatures) : null, slot.lastInputMessageId, slot.modelKey, slot.providerKey, slot.capturedAt, slot.rowVersion ?? null, slot.captureSequence ?? null);
14659
+ if (!saved) {
14660
+ saved = new Map;
14661
+ persistedFingerprints.set(db, saved);
14662
+ }
14663
+ if (saved.size >= 1000) {
14664
+ const oldest = saved.keys().next().value;
14665
+ if (oldest !== undefined)
14666
+ saved.delete(oldest);
14667
+ }
14668
+ saved.set(sessionId, fingerprint);
14669
+ return true;
14670
+ } catch (error) {
14671
+ sessionLog(sessionId, "LKG snapshot persistence failed (in-memory slot retained):", error);
14672
+ return false;
14673
+ }
14674
+ }
14675
+ function clearPersistedLkgSlot(db, sessionId) {
14676
+ try {
14677
+ db.prepare("DELETE FROM lkg_slots WHERE session_id = ?").run(sessionId);
14678
+ persistedFingerprints.get(db)?.delete(sessionId);
14679
+ } catch (error) {
14680
+ sessionLog(sessionId, "LKG snapshot durable clear failed:", error);
14681
+ }
14682
+ }
14683
+ function loadPersistedLkgSlot(db, sessionId) {
14684
+ let row;
14685
+ try {
14686
+ row = db.prepare("SELECT * FROM lkg_slots WHERE session_id = ?").get(sessionId);
14687
+ } catch (error) {
14688
+ sessionLog(sessionId, "LKG snapshot durable load failed:", error);
14689
+ return;
14690
+ }
14691
+ if (!row)
14692
+ return;
14693
+ const slot = parsePersistedLkgSlot(row);
14694
+ if (!slot) {
14695
+ clearPersistedLkgSlot(db, sessionId);
14696
+ return;
14697
+ }
14698
+ return slot;
14699
+ }
14700
+ function pruneStaleLkgSlots(db, now = Date.now()) {
14701
+ const previousTimeout = db.prepare("PRAGMA busy_timeout").get();
14702
+ try {
14703
+ db.exec("PRAGMA busy_timeout = 0");
14704
+ const result = db.prepare(`DELETE FROM lkg_slots WHERE captured_at < ? AND NOT EXISTS (
14705
+ SELECT 1 FROM session_projects sp
14706
+ WHERE sp.session_id = lkg_slots.session_id AND sp.updated_at >= ?
14707
+ )`).run(now - 7 * 24 * 60 * 60 * 1000, now - 7 * 24 * 60 * 60 * 1000);
14708
+ if (result.changes)
14709
+ persistedFingerprints.delete(db);
14710
+ return result.changes;
14711
+ } finally {
14712
+ db.exec(`PRAGMA busy_timeout = ${Number(previousTimeout.timeout) || 0}`);
14713
+ }
14714
+ }
14715
+ function createDbLkgPersistence(db) {
14716
+ return {
14717
+ load: (sessionId) => loadPersistedLkgSlot(db, sessionId),
14718
+ clear: (sessionId) => clearPersistedLkgSlot(db, sessionId)
14719
+ };
14720
+ }
14721
+
14436
14722
  // ../plugin/src/plugin/dream-timer.ts
14437
14723
  var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
14438
14724
  var GIT_COMMIT_BACKLOG_DRAIN_MAX_MS = 5 * 60 * 1000;
@@ -14595,6 +14881,11 @@ function persistTickOutcome(db, failure) {
14595
14881
  }
14596
14882
  }
14597
14883
  async function runMessageHistoryMaintenance(db) {
14884
+ try {
14885
+ pruneStaleLkgSlots(db);
14886
+ } catch (error) {
14887
+ log("[magic-context] LKG pruning deferred:", error);
14888
+ }
14598
14889
  const cleanup = retryPendingSessionCleanups(db);
14599
14890
  if (cleanup.cleared > 0 || cleanup.failedSessionIds.length > 0) {
14600
14891
  log(`[message-index] pending session cleanup: cleared=${cleanup.cleared} failed=${cleanup.failedSessionIds.length}`);
@@ -15492,6 +15783,15 @@ class PiSubagentRunner {
15492
15783
  if (settled)
15493
15784
  return;
15494
15785
  settled = true;
15786
+ if (accountingMessages.length > 0 && /historian|dreamer|classify/i.test(options.agent)) {
15787
+ const last = [...accountingMessages].reverse().find((message) => message !== null && typeof message === "object" && message.role === "assistant");
15788
+ const responseChars = result.ok ? result.assistantText.length : last?.content?.filter((part) => typeof part === "object" && part !== null && part.type === "text" && typeof part.text === "string").reduce((sum, part) => sum + part.text.length, 0) ?? 0;
15789
+ const tokenDetails = formatRunTokenLog(runTokenLog(last?.usage, options.maxOutputTokens, last?.stopReason));
15790
+ if (!result.ok && result.reason === "truncated") {
15791
+ result = { ...result, error: `${result.error}; ${tokenDetails}` };
15792
+ }
15793
+ sessionLog(options.accountingSessionId ?? "subagent", `${options.agent} response_chars=${responseChars} ${tokenDetails}`);
15794
+ }
15495
15795
  const outcome = budget ? {
15496
15796
  ...result,
15497
15797
  meta: { ...result.meta, tokenBudget: budget.snapshot() }
@@ -16599,6 +16899,9 @@ function createPiPrimerRawProviderFactory(deps = {}) {
16599
16899
  readMessages() {
16600
16900
  throw new Error("Pi primer history requires bounded pages");
16601
16901
  },
16902
+ iterateMessageRange(from, to) {
16903
+ return iterateEntriesToRawMessageRange(summaryEntries(path), from - 1, Number.MAX_SAFE_INTEGER, to);
16904
+ },
16602
16905
  readMessagePage(after, limit, watermark) {
16603
16906
  return convertEntriesToRawMessagePage(summaryEntries(path), after, Math.min(50, limit), watermark);
16604
16907
  }
@@ -17944,6 +18247,12 @@ function resolveTokensMatchWithKey(tokensConfig, modelKey) {
17944
18247
  }
17945
18248
  return;
17946
18249
  }
18250
+ function historyBudgetPolicyIdentity(historyBudgetPercentage, executeThresholdPercentage, modelKey, executeThresholdTokens) {
18251
+ if (!historyBudgetPercentage)
18252
+ return "pdefault";
18253
+ const threshold = resolveExecuteThresholdDetail(executeThresholdPercentage ?? 65, modelKey, 65, { tokensConfig: executeThresholdTokens, contextLimit: Number.MAX_SAFE_INTEGER });
18254
+ return `p${historyBudgetPercentage}:${threshold.mode}:${threshold.absoluteTokens ?? threshold.percentage}`;
18255
+ }
17947
18256
 
17948
18257
  // ../plugin/src/features/magic-context/scheduler.ts
17949
18258
  var TTL_PATTERN = /^(\d+)([smh])$/;
@@ -20545,10 +20854,10 @@ function advanceToolReclaimWatermarkToCurrentMax(db, sessionId) {
20545
20854
  }
20546
20855
 
20547
20856
  // ../plugin/src/shared/tag-transcript.ts
20548
- import { createHash as createHash11 } from "node:crypto";
20857
+ import { createHash as createHash12 } from "node:crypto";
20549
20858
  var TEXT_TAG_IDENTITY_MARKER = ":mc-text-v1:";
20550
20859
  function textIdentityDigest(value) {
20551
- return createHash11("sha256").update(value).digest("hex");
20860
+ return createHash12("sha256").update(value).digest("hex");
20552
20861
  }
20553
20862
  function buildContentDerivedTextIds(messageId, parts) {
20554
20863
  const sources = parts.filter((part) => part.kind === "text").map((part) => stripTagPrefix(part.getText() ?? ""));
@@ -21235,7 +21544,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
21235
21544
  }
21236
21545
  return any ? "truncated" : "absent";
21237
21546
  },
21238
- canDrop: complete,
21547
+ canDrop: () => complete() && !occurrences.some((occ) => occ.part.hasUserAnswer?.()),
21239
21548
  requiresToolArcSkeleton,
21240
21549
  readInput() {
21241
21550
  for (const occ of occurrences) {
@@ -21287,6 +21596,7 @@ function buildToolTarget(part, message, tagId) {
21287
21596
  return setToolContentOrText(part, `[dropped §${tagId}§]`) ? "truncated" : "absent";
21288
21597
  },
21289
21598
  cannotRemove: () => part.setToolInput !== undefined,
21599
+ ...part.hasUserAnswer?.() ? { canDrop: () => false } : {},
21290
21600
  inputStringBytes() {
21291
21601
  return part.setToolInput ? toolInputStringBytes(part.getToolInput?.() ?? null) : 0;
21292
21602
  },
@@ -23812,8 +24122,10 @@ async function runHistorianSubagentWithTransientRetriesGuarded(args) {
23812
24122
  try {
23813
24123
  const key = piModelRefToCanonical(args.options.model ?? "");
23814
24124
  const window = args.resolveContextLimit?.(key) ?? resolveKnownHistorianContextLimit(key);
23815
- const reserve = historianProducerReserve(window, args.options.maxOutputTokens, args.resolveOutputLimit?.(key));
23816
- if (window !== undefined && producerInputTokenLimit(window, reserve) === undefined && !loggedInconsistentWindows.has(key)) {
24125
+ const limits = args.resolveContextLimit ? { context: window, input: undefined } : resolveHistorianProducerLimits(key);
24126
+ const context = limits.context ?? (limits.input === undefined ? window : undefined);
24127
+ const reserve = historianProducerReserve(context, args.options.maxOutputTokens, args.resolveOutputLimit?.(key));
24128
+ if (window !== undefined && producerInputTokenLimit(context, reserve, limits.input) === undefined && !loggedInconsistentWindows.has(key)) {
23817
24129
  loggedInconsistentWindows.add(key);
23818
24130
  sessionLog(args.sessionId, `producer window inconsistent for ${key}: window=${window} reserve=${reserve}; sending unguarded`);
23819
24131
  }
@@ -23822,7 +24134,8 @@ async function runHistorianSubagentWithTransientRetriesGuarded(args) {
23822
24134
  systemLocal: estimateTokens(args.options.systemPrompt),
23823
24135
  toolsLocal: 0,
23824
24136
  modelKey: key,
23825
- contextLimitTokens: window,
24137
+ contextLimitTokens: context,
24138
+ inputLimitTokens: limits.input,
23826
24139
  maxOutputTokens: reserve
23827
24140
  });
23828
24141
  if (failure)
@@ -24964,6 +25277,8 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
24964
25277
  if (!matched)
24965
25278
  continue;
24966
25279
  const target = targets.get(tag.tagNumber);
25280
+ if (target?.canDrop?.() === false)
25281
+ continue;
24967
25282
  const { result, mode } = applyNewToolDrop(target, { inWindow: false });
24968
25283
  if (result === "incomplete")
24969
25284
  continue;
@@ -25048,6 +25363,8 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
25048
25363
  for (let i = 0;i < group.length - 1; i++) {
25049
25364
  const tag = group[i];
25050
25365
  const target = targets.get(tag.tagNumber);
25366
+ if (target?.canDrop?.() === false)
25367
+ continue;
25051
25368
  const { result, mode } = applyNewToolDrop(target, {
25052
25369
  inWindow: false
25053
25370
  });
@@ -26091,7 +26408,7 @@ var EMPTY_PI_HARD_SIGNALS = {
26091
26408
  lastResponseTime: 0
26092
26409
  };
26093
26410
  function renderBudgetIdentityPi(state) {
26094
- return `m${state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS}-h${state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS}`;
26411
+ return `m${state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS}-h${state.historyBudgetPolicyIdentity ?? state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS}`;
26095
26412
  }
26096
26413
  function piMaterializeMismatch(reason, signal, cached, current) {
26097
26414
  return { value: true, reason, mismatch: { signal, cached, current } };
@@ -26226,7 +26543,8 @@ function getCachedMarkers(db, state, compartmentsForNormalization, metaOverride,
26226
26543
  modelKey: meta.cachedM0ModelKey ?? "",
26227
26544
  projectIdentity: meta.cachedM0ProjectIdentity ?? null,
26228
26545
  muralEnabled: cachedUpgradeIdentity.muralEnabled ?? false,
26229
- renderBudgetIdentity: cachedUpgradeIdentity.renderBudgetIdentity ?? ""
26546
+ renderBudgetIdentity: cachedUpgradeIdentity.renderBudgetIdentity ?? "",
26547
+ renderedBudgets: cachedUpgradeIdentity.renderedBudgets
26230
26548
  };
26231
26549
  }
26232
26550
  function lastBaselineEndMessageId(compartments) {
@@ -26261,7 +26579,8 @@ function readCurrentMarkersFromCompartments(db, state, compartments, projectDocs
26261
26579
  modelKey: piModelRefToCanonical((state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey),
26262
26580
  projectIdentity: state.projectIdentity,
26263
26581
  muralEnabled: state.muralEnabled === true,
26264
- renderBudgetIdentity: renderBudgetIdentityPi(state)
26582
+ renderBudgetIdentity: renderBudgetIdentityPi(state),
26583
+ renderedBudgets: renderedBudgetSnapshot(state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS, state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS)
26265
26584
  };
26266
26585
  }
26267
26586
  function mustMaterializePi(state, db, currentCompartmentsOverride, passSnapshot) {
@@ -26283,10 +26602,14 @@ function mustMaterializePi(state, db, currentCompartmentsOverride, passSnapshot)
26283
26602
  return piMaterializeMismatch("compartment_render_epoch", "compartmentRenderEpoch", cached.compartmentRenderEpoch, current.compartmentRenderEpoch);
26284
26603
  }
26285
26604
  if (cached.muralEnabled !== current.muralEnabled) {
26286
- return piMaterializeMismatch("render_config", "muralEnabled", cached.muralEnabled, current.muralEnabled);
26605
+ return piMaterializeMismatch(`render_config:mural(${cached.muralEnabled}→${current.muralEnabled})`, "muralEnabled", cached.muralEnabled, current.muralEnabled);
26287
26606
  }
26288
- if (cached.renderBudgetIdentity !== current.renderBudgetIdentity) {
26289
- return piMaterializeMismatch("render_config", "renderBudgetIdentity", cached.renderBudgetIdentity, current.renderBudgetIdentity);
26607
+ if (renderBudgetIdentityChanged(cached.renderBudgetIdentity, current.renderBudgetIdentity)) {
26608
+ return piMaterializeMismatch(`render_config:budget(${cached.renderBudgetIdentity}→${current.renderBudgetIdentity})`, "renderBudgetIdentity", cached.renderBudgetIdentity, current.renderBudgetIdentity);
26609
+ }
26610
+ const budgetShrinkReason = renderedBudgetShrinkReason(cached.renderedBudgets, current.renderedBudgets);
26611
+ if (budgetShrinkReason) {
26612
+ return piMaterializeMismatch(budgetShrinkReason, "renderedBudgets", cached.renderedBudgets ?? null, current.renderedBudgets ?? null);
26290
26613
  }
26291
26614
  const hard = state.hardSignals ?? EMPTY_PI_HARD_SIGNALS;
26292
26615
  const canonicalHardModelKey = piModelRefToCanonical(hard.modelKey);
@@ -26428,7 +26751,8 @@ function readFrozenM0InputsPi(state, db, docs = readProjectDocsForPiM0(state), m
26428
26751
  modelKey: piModelRefToCanonical((state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey),
26429
26752
  projectIdentity: state.projectIdentity,
26430
26753
  muralEnabled: state.memoryEnabled !== false && state.muralEnabled === true,
26431
- renderBudgetIdentity: renderBudgetIdentityPi(state)
26754
+ renderBudgetIdentity: renderBudgetIdentityPi(state),
26755
+ renderedBudgets: renderedBudgetSnapshot(state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS, state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS)
26432
26756
  };
26433
26757
  return { docs, markers, compartments, memories, userProfile, workspace };
26434
26758
  });
@@ -26518,7 +26842,7 @@ function materializeM0Pi(state, db, passSnapshot) {
26518
26842
  projectDocsHash: snapshotMarkers.projectDocsHash,
26519
26843
  materializedAt: snapshotMarkers.materializedAt,
26520
26844
  sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
26521
- upgradeState: encodeCachedM0UpgradeIdentity(snapshotMarkers.upgradeState, snapshotMarkers.compartmentRenderEpoch, snapshotMarkers.muralEnabled, snapshotMarkers.renderBudgetIdentity, snapshotMarkers.memoryRenderEpoch),
26845
+ upgradeState: encodeCachedM0UpgradeIdentity(snapshotMarkers.upgradeState, snapshotMarkers.compartmentRenderEpoch, snapshotMarkers.muralEnabled, snapshotMarkers.renderBudgetIdentity, snapshotMarkers.memoryRenderEpoch, snapshotMarkers.renderedBudgets ?? null),
26522
26846
  systemHash: snapshotMarkers.systemHash,
26523
26847
  modelKey: snapshotMarkers.modelKey,
26524
26848
  projectIdentity: snapshotMarkers.projectIdentity
@@ -26778,7 +27102,8 @@ function markersFromCachedPiRow(row, compartmentsForNormalization) {
26778
27102
  modelKey: row.cached_m0_model_key ?? "",
26779
27103
  projectIdentity: row.cached_m0_project_identity ?? null,
26780
27104
  muralEnabled: cachedUpgradeIdentity.muralEnabled ?? false,
26781
- renderBudgetIdentity: cachedUpgradeIdentity.renderBudgetIdentity ?? ""
27105
+ renderBudgetIdentity: cachedUpgradeIdentity.renderBudgetIdentity ?? "",
27106
+ renderedBudgets: cachedUpgradeIdentity.renderedBudgets
26782
27107
  };
26783
27108
  }
26784
27109
  function cachedPiRowMatchesSnapshot(args) {
@@ -27559,162 +27884,6 @@ function registerPiGuardedContext(pi, handler) {
27559
27884
  });
27560
27885
  }
27561
27886
 
27562
- // ../plugin/src/hooks/magic-context/lkg-persist.ts
27563
- function parseStringArray(value) {
27564
- if (typeof value !== "string")
27565
- return null;
27566
- let parsed;
27567
- try {
27568
- parsed = JSON.parse(value);
27569
- } catch {
27570
- return null;
27571
- }
27572
- if (!Array.isArray(parsed))
27573
- return null;
27574
- const result = [];
27575
- for (const entry of parsed) {
27576
- if (typeof entry !== "string" || entry.length === 0)
27577
- return null;
27578
- result.push(entry);
27579
- }
27580
- return result;
27581
- }
27582
- function parseNullableString(value) {
27583
- if (value === null || value === undefined)
27584
- return null;
27585
- return typeof value === "string" ? value : undefined;
27586
- }
27587
- function parseNullableInteger(value) {
27588
- if (value === null || value === undefined)
27589
- return;
27590
- return typeof value === "number" && Number.isSafeInteger(value) ? value : undefined;
27591
- }
27592
- function parsePersistedLkgSlot(row) {
27593
- if (!row || typeof row !== "object")
27594
- return;
27595
- const record = row;
27596
- const jsonPrefix = record.json_prefix;
27597
- const lastInputMessageId = record.last_input_message_id;
27598
- const capturedAt = record.captured_at;
27599
- let inputIdsRaw = record.input_id_seq;
27600
- let piOutputEntryIds;
27601
- if (typeof inputIdsRaw === "string") {
27602
- try {
27603
- const metadata = JSON.parse(inputIdsRaw);
27604
- if (metadata && !Array.isArray(metadata) && metadata.version === 1 && Array.isArray(metadata.piOutputEntryIds)) {
27605
- if (!metadata.piOutputEntryIds.every((id) => id === null || typeof id === "string" && id.length > 0))
27606
- return;
27607
- piOutputEntryIds = metadata.piOutputEntryIds;
27608
- inputIdsRaw = JSON.stringify(metadata.inputIds);
27609
- }
27610
- } catch {
27611
- return;
27612
- }
27613
- }
27614
- const inputIdSeq = parseStringArray(inputIdsRaw);
27615
- const inputContentDigests = parseStringArray(record.input_content_digests);
27616
- const modelKey = parseNullableString(record.model_key);
27617
- const providerKey = parseNullableString(record.provider_key);
27618
- if (typeof jsonPrefix !== "string" || typeof lastInputMessageId !== "string" || lastInputMessageId.length === 0 || typeof capturedAt !== "number" || !Number.isFinite(capturedAt) || inputIdSeq === null || inputContentDigests === null || inputContentDigests.length !== inputIdSeq.length || modelKey === undefined || providerKey === undefined) {
27619
- return;
27620
- }
27621
- if (piOutputEntryIds) {
27622
- try {
27623
- const output = JSON.parse(jsonPrefix);
27624
- const inputs = new Set(inputIdSeq);
27625
- if (!Array.isArray(output) || output.length !== piOutputEntryIds.length || piOutputEntryIds.some((id) => id !== null && !inputs.has(id)))
27626
- return;
27627
- } catch {
27628
- return;
27629
- }
27630
- }
27631
- let inputContentSignatures;
27632
- if (record.input_content_signatures !== null && record.input_content_signatures !== undefined) {
27633
- const parsed = parseStringArray(record.input_content_signatures);
27634
- if (parsed === null || parsed.length !== inputIdSeq.length)
27635
- return;
27636
- inputContentSignatures = parsed;
27637
- }
27638
- const slot = {
27639
- jsonPrefix,
27640
- inputIdSeq,
27641
- inputContentDigests,
27642
- lastInputMessageId,
27643
- modelKey,
27644
- providerKey,
27645
- capturedAt
27646
- };
27647
- if (inputContentSignatures)
27648
- slot.inputContentSignatures = inputContentSignatures;
27649
- if (piOutputEntryIds)
27650
- slot.piOutputEntryIds = piOutputEntryIds;
27651
- const rowVersion = parseNullableInteger(record.row_version);
27652
- if (rowVersion !== undefined)
27653
- slot.rowVersion = rowVersion;
27654
- const captureSequence = parseNullableInteger(record.capture_sequence);
27655
- if (captureSequence !== undefined)
27656
- slot.captureSequence = captureSequence;
27657
- return slot;
27658
- }
27659
- function saveLkgSlotToDb(db, sessionId, slot) {
27660
- try {
27661
- db.prepare(`INSERT INTO lkg_slots (
27662
- session_id, json_prefix, input_id_seq, input_content_digests,
27663
- input_content_signatures, last_input_message_id, model_key, provider_key,
27664
- captured_at, row_version, capture_sequence
27665
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
27666
- ON CONFLICT(session_id) DO UPDATE SET
27667
- json_prefix = excluded.json_prefix,
27668
- input_id_seq = excluded.input_id_seq,
27669
- input_content_digests = excluded.input_content_digests,
27670
- input_content_signatures = excluded.input_content_signatures,
27671
- last_input_message_id = excluded.last_input_message_id,
27672
- model_key = excluded.model_key,
27673
- provider_key = excluded.provider_key,
27674
- captured_at = excluded.captured_at,
27675
- row_version = excluded.row_version,
27676
- capture_sequence = excluded.capture_sequence`).run(sessionId, slot.jsonPrefix, JSON.stringify(slot.piOutputEntryIds ? {
27677
- version: 1,
27678
- inputIds: slot.inputIdSeq,
27679
- piOutputEntryIds: slot.piOutputEntryIds
27680
- } : slot.inputIdSeq), JSON.stringify(slot.inputContentDigests), slot.inputContentSignatures ? JSON.stringify(slot.inputContentSignatures) : null, slot.lastInputMessageId, slot.modelKey, slot.providerKey, slot.capturedAt, slot.rowVersion ?? null, slot.captureSequence ?? null);
27681
- return true;
27682
- } catch (error) {
27683
- sessionLog(sessionId, "LKG snapshot persistence failed (in-memory slot retained):", error);
27684
- return false;
27685
- }
27686
- }
27687
- function clearPersistedLkgSlot(db, sessionId) {
27688
- try {
27689
- db.prepare("DELETE FROM lkg_slots WHERE session_id = ?").run(sessionId);
27690
- } catch (error) {
27691
- sessionLog(sessionId, "LKG snapshot durable clear failed:", error);
27692
- }
27693
- }
27694
- function loadPersistedLkgSlot(db, sessionId) {
27695
- let row;
27696
- try {
27697
- row = db.prepare("SELECT * FROM lkg_slots WHERE session_id = ?").get(sessionId);
27698
- } catch (error) {
27699
- sessionLog(sessionId, "LKG snapshot durable load failed:", error);
27700
- return;
27701
- }
27702
- if (!row)
27703
- return;
27704
- const slot = parsePersistedLkgSlot(row);
27705
- if (!slot) {
27706
- clearPersistedLkgSlot(db, sessionId);
27707
- return;
27708
- }
27709
- return slot;
27710
- }
27711
- function createDbLkgPersistence(db) {
27712
- return {
27713
- load: (sessionId) => loadPersistedLkgSlot(db, sessionId),
27714
- clear: (sessionId) => clearPersistedLkgSlot(db, sessionId)
27715
- };
27716
- }
27717
-
27718
27887
  // ../plugin/src/hooks/magic-context/openai-compat-adjacency.ts
27719
27888
  function assertOpenAiCompatAdjacency(messages) {
27720
27889
  const violations = [];
@@ -29350,7 +29519,7 @@ function replayStrippedInlineThinkingPi(args) {
29350
29519
  }
29351
29520
 
29352
29521
  // src/served-array-ledger.ts
29353
- import { createHash as createHash12 } from "node:crypto";
29522
+ import { createHash as createHash13 } from "node:crypto";
29354
29523
  import * as fs2 from "node:fs";
29355
29524
  import * as path6 from "node:path";
29356
29525
  var PI_SERVED_ARRAY_TAIL_MESSAGES = 40;
@@ -29365,7 +29534,7 @@ var flushTimer = null;
29365
29534
  var swallowedWriteCount = 0;
29366
29535
  var lastWriteError = null;
29367
29536
  function sha256(value) {
29368
- return createHash12("sha256").update(value).digest("hex");
29537
+ return createHash13("sha256").update(value).digest("hex");
29369
29538
  }
29370
29539
  function safeSessionFileStem(sessionId) {
29371
29540
  const readable = sessionId.replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 96);
@@ -29673,7 +29842,7 @@ function stripPiProcessedImages(args) {
29673
29842
  }
29674
29843
 
29675
29844
  // src/system-prompt.ts
29676
- import { createHash as createHash13 } from "node:crypto";
29845
+ import { createHash as createHash14 } from "node:crypto";
29677
29846
  var MAGIC_CONTEXT_MARKER = "## Magic Context";
29678
29847
  var stickyDateBySession = new Map;
29679
29848
  function buildMagicContextBlock(opts) {
@@ -29704,7 +29873,7 @@ function processSystemPromptForCache(args) {
29704
29873
  const liveDate = dateMatch ? dateMatch[0] : null;
29705
29874
  const stickyDate = stickyDateBySession.get(sessionId);
29706
29875
  const stableCandidate = liveDate && stickyDate && liveDate !== stickyDate ? systemPrompt.replace(DATE_PATTERN, stickyDate) : systemPrompt;
29707
- const stableCandidateHash = createHash13("md5").update(promptSurfaceHashMaterial(stableCandidate, args.promptSurfacePreset)).digest("hex");
29876
+ const stableCandidateHash = createHash14("md5").update(promptSurfaceHashMaterial(stableCandidate, args.promptSurfacePreset)).digest("hex");
29708
29877
  const contentOrPresetChanged = !isFirstHash && stableCandidateHash !== previousHash;
29709
29878
  const dateMayAdvance = isCacheBusting || contentOrPresetChanged;
29710
29879
  if (liveDate && !stickyDate) {
@@ -29718,7 +29887,7 @@ function processSystemPromptForCache(args) {
29718
29887
  sessionLog(sessionId, `system prompt date frozen: real=${liveDate}, using=${stickyDate} (cache-stable pass)`);
29719
29888
  }
29720
29889
  }
29721
- const currentHash = createHash13("md5").update(promptSurfaceHashMaterial(frozenPrompt, args.promptSurfacePreset)).digest("hex");
29890
+ const currentHash = createHash14("md5").update(promptSurfaceHashMaterial(frozenPrompt, args.promptSurfacePreset)).digest("hex");
29722
29891
  const hashChanged = !isFirstHash && currentHash !== previousHash;
29723
29892
  if (hashChanged) {
29724
29893
  sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${frozenPrompt.length})`);
@@ -30331,6 +30500,9 @@ function createPiToolResultPart(working, messageIndex, partIndex, markDirty) {
30331
30500
  inputTokenCount: 0
30332
30501
  };
30333
30502
  },
30503
+ hasUserAnswer() {
30504
+ return hasUserAnswerMetadata(working[messageIndex].details);
30505
+ },
30334
30506
  replaceWithSentinel(sentinelText) {
30335
30507
  const current = working[messageIndex].content;
30336
30508
  const newContent = current.slice();
@@ -31639,6 +31811,7 @@ function registerPiContextHandler(pi, baseOptions) {
31639
31811
  injection: options.injection ? {
31640
31812
  ...options.injection,
31641
31813
  memoryEnabled: options.injection.memoryEnabled,
31814
+ historyBudgetPolicyIdentity: historyBudgetPolicyIdentity(options.historian?.historyBudgetPercentage, options.historian?.executeThresholdPercentage, liveModelBySession.get(sessionId), options.historian?.executeThresholdTokens),
31642
31815
  historyBudgetTokens: resolveHistoryBudgetTokensForPi({
31643
31816
  historyBudgetPercentage: options.historian?.historyBudgetPercentage,
31644
31817
  usagePercentage,
@@ -32514,6 +32687,7 @@ async function runCompactionOffPipeline(args) {
32514
32687
  injectDocs: args.injection.injectDocs,
32515
32688
  injectionBudgetTokens: args.injection.injectionBudgetTokens,
32516
32689
  historyBudgetTokens: args.injection.historyBudgetTokens,
32690
+ historyBudgetPolicyIdentity: args.injection.historyBudgetPolicyIdentity,
32517
32691
  muralEnabled: args.injection.muralEnabled === true,
32518
32692
  compactionOff: true
32519
32693
  }, args.db, args.messages, args.entryIds, false, args.injectionPassSnapshot);
@@ -32632,6 +32806,7 @@ async function runPipeline(args) {
32632
32806
  injectDocs: args.injection.injectDocs,
32633
32807
  injectionBudgetTokens: args.injection.injectionBudgetTokens,
32634
32808
  historyBudgetTokens: args.injection.historyBudgetTokens,
32809
+ historyBudgetPolicyIdentity: args.injection.historyBudgetPolicyIdentity,
32635
32810
  hardSignals: piHardSignals,
32636
32811
  muralEnabled: args.injection.muralEnabled === true,
32637
32812
  freezePrefixForPass: true,
@@ -35816,7 +35991,7 @@ function buildStatusView(source, options) {
35816
35991
  // package.json
35817
35992
  var package_default = {
35818
35993
  name: "@cortexkit/pi-magic-context",
35819
- version: "0.44.2",
35994
+ version: "0.44.4",
35820
35995
  type: "module",
35821
35996
  description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
35822
35997
  main: "dist/index.js",
@@ -35864,7 +36039,6 @@ var package_default = {
35864
36039
  "comment-json": "^5.0.0",
35865
36040
  "onnxruntime-web": "1.26.0-dev.20260416-b7804b056c",
35866
36041
  "quickjs-emscripten": "^0.32.0",
35867
- typebox: "^1.3.1",
35868
36042
  zod: "^4.1.8"
35869
36043
  },
35870
36044
  optionalDependencies: {
@@ -35884,11 +36058,13 @@ var package_default = {
35884
36058
  "pi-ai-086": "npm:@earendil-works/pi-ai@0.86.0",
35885
36059
  "pi-coding-agent-086": "npm:@earendil-works/pi-coding-agent@0.86.0",
35886
36060
  "pi-coding-agent-087": "npm:@earendil-works/pi-coding-agent@0.87.1",
36061
+ typebox: "^1.3.1",
35887
36062
  typescript: "^5.8.0"
35888
36063
  },
35889
36064
  peerDependencies: {
35890
- "@earendil-works/pi-coding-agent": ">=0.80.2",
35891
- "@earendil-works/pi-tui": ">=0.80.2"
36065
+ "@earendil-works/pi-coding-agent": "*",
36066
+ "@earendil-works/pi-tui": "*",
36067
+ typebox: "*"
35892
36068
  },
35893
36069
  peerDependenciesMeta: {
35894
36070
  "@earendil-works/pi-coding-agent": {
@@ -35896,6 +36072,9 @@ var package_default = {
35896
36072
  },
35897
36073
  "@earendil-works/pi-tui": {
35898
36074
  optional: true
36075
+ },
36076
+ typebox: {
36077
+ optional: true
35899
36078
  }
35900
36079
  },
35901
36080
  exports: {
@@ -37557,6 +37736,7 @@ async function src_default(pi) {
37557
37736
  const bootProjectDir = process.cwd();
37558
37737
  ensureConfigLocationsMigrated(bootProjectDir);
37559
37738
  const bootConfig = loadPiConfig({ cwd: bootProjectDir });
37739
+ setHomeProjectPermission(bootConfig.config.allow_home_project);
37560
37740
  if (!bootConfig.config.enabled) {
37561
37741
  info("plugin DISABLED via config (enabled: false) — skipping registration");
37562
37742
  return;