@cortexkit/opencode-magic-context 0.36.0 → 0.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/config/index.d.ts.map +1 -1
  2. package/dist/{conflict-warning-hook-dw9fs934.js → conflict-warning-hook-mt0ttc4x.js} +2 -2
  3. package/dist/features/magic-context/context-authority.d.ts +12 -0
  4. package/dist/features/magic-context/context-authority.d.ts.map +1 -1
  5. package/dist/features/magic-context/dreamer/classify.d.ts +2 -0
  6. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  7. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts +2 -0
  8. package/dist/features/magic-context/dreamer/evaluate-smart-notes.d.ts.map +1 -1
  9. package/dist/features/magic-context/dreamer/lease.d.ts +10 -3
  10. package/dist/features/magic-context/dreamer/lease.d.ts.map +1 -1
  11. package/dist/features/magic-context/dreamer/map-memories.d.ts +2 -0
  12. package/dist/features/magic-context/dreamer/map-memories.d.ts.map +1 -1
  13. package/dist/features/magic-context/dreamer/module-apply.d.ts +5 -0
  14. package/dist/features/magic-context/dreamer/module-apply.d.ts.map +1 -1
  15. package/dist/features/magic-context/dreamer/promote-primers.d.ts +2 -0
  16. package/dist/features/magic-context/dreamer/promote-primers.d.ts.map +1 -1
  17. package/dist/features/magic-context/dreamer/refresh-primers.d.ts +2 -0
  18. package/dist/features/magic-context/dreamer/refresh-primers.d.ts.map +1 -1
  19. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  20. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +5 -2
  21. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  22. package/dist/features/magic-context/dreamer/verify.d.ts +2 -0
  23. package/dist/features/magic-context/dreamer/verify.d.ts.map +1 -1
  24. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  25. package/dist/features/magic-context/mural/compress-cues.d.ts +2 -0
  26. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  27. package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
  28. package/dist/features/magic-context/schema-fence-probe.d.ts +1 -0
  29. package/dist/features/magic-context/schema-fence-probe.d.ts.map +1 -1
  30. package/dist/features/magic-context/smart-notes/condition-compiler.d.ts +1 -0
  31. package/dist/features/magic-context/smart-notes/condition-compiler.d.ts.map +1 -1
  32. package/dist/features/magic-context/storage-clone.d.ts +6 -0
  33. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  34. package/dist/features/magic-context/storage-db.d.ts +1 -1
  35. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  36. package/dist/features/magic-context/storage-identity-merge.d.ts.map +1 -1
  37. package/dist/features/magic-context/storage-tags.d.ts +2 -0
  38. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  39. package/dist/features/magic-context/storage.d.ts +1 -1
  40. package/dist/features/magic-context/storage.d.ts.map +1 -1
  41. package/dist/features/magic-context/user-memory/review-user-memories.d.ts +2 -0
  42. package/dist/features/magic-context/user-memory/review-user-memories.d.ts.map +1 -1
  43. package/dist/hooks/magic-context/child-session-spawn.d.ts +1 -0
  44. package/dist/hooks/magic-context/child-session-spawn.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
  46. package/dist/hooks/magic-context/compaction-off-transition.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/compartment-render-epoch.d.ts +5 -3
  48. package/dist/hooks/magic-context/compartment-render-epoch.d.ts.map +1 -1
  49. package/dist/hooks/magic-context/embed-session-state.d.ts +1 -1
  50. package/dist/hooks/magic-context/embed-session-state.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  52. package/dist/hooks/magic-context/inject-compartments.d.ts +8 -0
  53. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/lkg-replay.d.ts +5 -2
  55. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  56. package/dist/hooks/magic-context/module-state-sync.d.ts +1 -0
  57. package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
  58. package/dist/hooks/magic-context/module-transport.d.ts +20 -3
  59. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  60. package/dist/hooks/magic-context/read-session-formatting.d.ts +1 -0
  61. package/dist/hooks/magic-context/read-session-formatting.d.ts.map +1 -1
  62. package/dist/hooks/magic-context/rust-mode-transform.d.ts +3 -0
  63. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  64. package/dist/hooks/magic-context/strip-content.d.ts +6 -1
  65. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  66. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  67. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +1 -0
  68. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  69. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  70. package/dist/{index-3nfgbsp4.js → index-1skzp4dc.js} +347 -44
  71. package/dist/{index-z8v31d85.js → index-3zqcdwqr.js} +137 -10
  72. package/dist/{index-0c9dmw9m.js → index-8mtsfhyg.js} +33 -3
  73. package/dist/{index-37rt2bka.js → index-zp6x6s6a.js} +1 -1
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +820 -548
  76. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  77. package/dist/plugin/rust-tool-backends.d.ts +4 -0
  78. package/dist/plugin/rust-tool-backends.d.ts.map +1 -1
  79. package/dist/{recomp-orchestrator-7wbbvf87.js → recomp-orchestrator-a0g9b52q.js} +3 -3
  80. package/dist/shared/conflict-fixer.d.ts.map +1 -1
  81. package/dist/shared/jsonc-edit.d.ts +18 -0
  82. package/dist/shared/jsonc-edit.d.ts.map +1 -0
  83. package/dist/shared/jsonc-parser.d.ts +11 -1
  84. package/dist/shared/jsonc-parser.d.ts.map +1 -1
  85. package/dist/shared/prompt-surface.d.ts +5 -3
  86. package/dist/shared/prompt-surface.d.ts.map +1 -1
  87. package/dist/shared/rpc-utils.d.ts +16 -0
  88. package/dist/shared/rpc-utils.d.ts.map +1 -1
  89. package/dist/shared/tui-preferences.d.ts +9 -0
  90. package/dist/shared/tui-preferences.d.ts.map +1 -1
  91. package/dist/{storage-meta-session-kh5egr11.js → storage-meta-session-df9tstzr.js} +1 -1
  92. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  93. package/package.json +2 -1
  94. package/src/config/index.test.ts +23 -0
  95. package/src/config/index.ts +41 -9
  96. package/src/config/schema/magic-context.test.ts +2 -1
  97. package/src/config/schema/magic-context.ts +3 -3
  98. package/src/shared/conflict-fixer.test.ts +174 -0
  99. package/src/shared/conflict-fixer.ts +66 -70
  100. package/src/shared/jsonc-edit.ts +295 -0
  101. package/src/shared/jsonc-parser.test.ts +33 -0
  102. package/src/shared/jsonc-parser.ts +54 -2
  103. package/src/shared/prompt-surface.test.ts +53 -2
  104. package/src/shared/prompt-surface.ts +20 -9
  105. package/src/shared/rpc-utils.test.ts +36 -0
  106. package/src/shared/rpc-utils.ts +71 -0
  107. package/src/shared/tui-preferences.test.ts +52 -2
  108. package/src/shared/tui-preferences.ts +42 -17
package/dist/index.js CHANGED
@@ -60,6 +60,7 @@ import {
60
60
  appendAutoSearchHintDecision,
61
61
  applyDeferredCompactionMarker,
62
62
  applyMirrorPage,
63
+ applyMirroredNoteCompileFields,
63
64
  applyStrippedPlaceholderDelta,
64
65
  archiveMemory,
65
66
  backfillTagTokenCounts,
@@ -80,6 +81,7 @@ import {
80
81
  clearEmergencyDropSample,
81
82
  clearEmergencyRecovery,
82
83
  clearHistorianFailureState,
84
+ clearHookInitFailure,
83
85
  clearInjectionCache,
84
86
  clearMemoryVerifications,
85
87
  clearNoteNudgeTriggerAndCooldown,
@@ -99,6 +101,7 @@ import {
99
101
  countEmbeddedCommits,
100
102
  countPrimerCandidatesForProject,
101
103
  createChildSessionWithFence,
104
+ createFailClosedController,
102
105
  createPrimer,
103
106
  createPromptSurfaceGuidanceEpochCache,
104
107
  createPromptSurfaceRuntime,
@@ -153,6 +156,7 @@ import {
153
156
  getHistorianFailureState,
154
157
  getLastCompartmentEndMessage,
155
158
  getLastCompartmentEndMessageId,
159
+ getLastHookInitFailure,
156
160
  getLastNudgeLevel,
157
161
  getLastNudgeUndropped,
158
162
  getLatestIndexedCommitTimeMs,
@@ -235,6 +239,7 @@ import {
235
239
  isDatabasePersisted,
236
240
  isEmbeddingEnabled,
237
241
  isEmergencyRecoveryArmed,
242
+ isFailClosedBlockingError,
238
243
  isPidAlive,
239
244
  isProviderOverflowReconfirmed,
240
245
  lkgContentDigest,
@@ -274,6 +279,7 @@ import {
274
279
  prepareCompartmentInjection,
275
280
  primerOccurrenceKey,
276
281
  primerOccurrenceUtcDay,
282
+ promptSurfaceConfigIdentity,
277
283
  promptSurfaceHashMaterial,
278
284
  promptSyncWithValidatedOutputRetry,
279
285
  pruneAutoSearchHintDecisions,
@@ -291,6 +297,7 @@ import {
291
297
  recordDetectedContextLimit,
292
298
  recordEmbeddingMeasurement,
293
299
  recordHighPressureNoEligibleHead,
300
+ recordHookInitFailure,
294
301
  recordMemoryMapping,
295
302
  recordMemoryVerifications,
296
303
  recordMuralCueRejection,
@@ -320,6 +327,7 @@ import {
320
327
  resetLastNudgeCycleIfTailShrank,
321
328
  resetNoteNudgeCooldownOnly,
322
329
  resetProtectedTailNoEligibleHead,
330
+ resolveAgentNameFromMessages,
323
331
  resolveCompactionModeRecord,
324
332
  resolveGitTopLevel,
325
333
  resolveLegacyConfigSources,
@@ -365,6 +373,7 @@ import {
365
373
  setRecompTerminal,
366
374
  setSessionWorkMetrics,
367
375
  setSqlitePragmaConfig,
376
+ shouldBypassFailClosedBlock,
368
377
  shouldKeepSubagents,
369
378
  snapRangeToCompartments,
370
379
  sourceNameForMemory,
@@ -391,7 +400,7 @@ import {
391
400
  upsertCommits,
392
401
  verificationFileExists,
393
402
  withContentLanguageDirective
394
- } from "./index-3nfgbsp4.js";
403
+ } from "./index-1skzp4dc.js";
395
404
  import {
396
405
  deriveHistorianChunkTokens,
397
406
  deriveTriggerBudget,
@@ -455,6 +464,7 @@ import {
455
464
  markSessionCleanupPending,
456
465
  normalizeText,
457
466
  partHasCompletedResult,
467
+ preloadTokenizer,
458
468
  prependTag,
459
469
  primeInMemoryTailRawMessageCache,
460
470
  primeTailRawMessageCache,
@@ -472,7 +482,7 @@ import {
472
482
  textMentionsRecentCommit,
473
483
  updateSessionMeta,
474
484
  withRawSessionMessageCache
475
- } from "./index-z8v31d85.js";
485
+ } from "./index-3zqcdwqr.js";
476
486
  import {
477
487
  Database,
478
488
  closeQuietly,
@@ -486,12 +496,13 @@ import {
486
496
  cleanupConflictWarnings,
487
497
  detectConflicts,
488
498
  sendConflictWarning
489
- } from "./index-37rt2bka.js";
499
+ } from "./index-zp6x6s6a.js";
490
500
  import {
491
501
  detectConfigFile,
502
+ isPrototypePollutionKey,
492
503
  parseJsonc,
493
504
  stripJsonComments
494
- } from "./index-0c9dmw9m.js";
505
+ } from "./index-8mtsfhyg.js";
495
506
  import {
496
507
  ANNOUNCEMENT_FEATURES,
497
508
  ANNOUNCEMENT_FOOTER,
@@ -9515,10 +9526,15 @@ function loadConfigFileDetailed(configPath, source) {
9515
9526
  configPath,
9516
9527
  isProjectConfig: source === "project"
9517
9528
  });
9529
+ const rejectedKeyPaths = [];
9530
+ const config = parseJsonc(substituted.text, {
9531
+ onRejectedKey: (path) => rejectedKeyPaths.push(path.join("."))
9532
+ });
9533
+ const unsafeKeyWarnings = rejectedKeyPaths.map((path) => `Ignored unsafe config key "${path}" (security: prototype-pollution keys are not allowed).`);
9518
9534
  return {
9519
- config: parseJsonc(substituted.text),
9520
- warnings: substituted.warnings.map((w) => `${configPath}: ${w}`),
9521
- outcome: substituted.warnings.length > 0 ? "substitution-failure" : "ok",
9535
+ config,
9536
+ warnings: [...substituted.warnings, ...unsafeKeyWarnings].map((warning) => `${configPath}: ${warning}`),
9537
+ outcome: rejectedKeyPaths.length > 0 ? "schema-recovery" : substituted.warnings.length > 0 ? "substitution-failure" : "ok",
9522
9538
  source
9523
9539
  };
9524
9540
  } catch (error) {
@@ -9532,18 +9548,35 @@ function loadConfigFileDetailed(configPath, source) {
9532
9548
  };
9533
9549
  }
9534
9550
  }
9551
+ function defineOwnConfigValue(target, key, value) {
9552
+ Object.defineProperty(target, key, {
9553
+ value,
9554
+ enumerable: true,
9555
+ configurable: true,
9556
+ writable: true
9557
+ });
9558
+ }
9535
9559
  function deepMergeRawConfig(base, override) {
9536
- const result = { ...base };
9560
+ const result = {};
9561
+ for (const key of Object.keys(base)) {
9562
+ if (isPrototypePollutionKey(key))
9563
+ continue;
9564
+ defineOwnConfigValue(result, key, base[key]);
9565
+ }
9537
9566
  for (const key of Object.keys(override)) {
9538
- const baseVal = base[key];
9567
+ if (isPrototypePollutionKey(key))
9568
+ continue;
9569
+ const baseVal = Object.hasOwn(base, key) ? base[key] : undefined;
9539
9570
  const overrideVal = override[key];
9571
+ let mergedValue;
9540
9572
  if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) && overrideVal !== null && typeof overrideVal === "object" && !Array.isArray(overrideVal)) {
9541
- result[key] = deepMergeRawConfig(baseVal, overrideVal);
9573
+ mergedValue = deepMergeRawConfig(baseVal, overrideVal);
9542
9574
  } else if (key === "disabled_hooks" && Array.isArray(baseVal) && Array.isArray(overrideVal)) {
9543
- result[key] = [...new Set([...baseVal, ...overrideVal])];
9575
+ mergedValue = [...new Set([...baseVal, ...overrideVal])];
9544
9576
  } else {
9545
- result[key] = overrideVal;
9577
+ mergedValue = overrideVal;
9546
9578
  }
9579
+ defineOwnConfigValue(result, key, mergedValue);
9547
9580
  }
9548
9581
  return result;
9549
9582
  }
@@ -10157,171 +10190,6 @@ function buildDreamTaskPrompt(task, args) {
10157
10190
  }
10158
10191
  }
10159
10192
 
10160
- // src/features/magic-context/fail-closed-block.ts
10161
- var FAIL_CLOSED_DOCTOR_COMMAND = "npx @cortexkit/magic-context@latest doctor";
10162
- var FAIL_CLOSED_REPROBE_EVERY_N = 5;
10163
-
10164
- class FailClosedBlockingError extends Error {
10165
- code = "FAIL_CLOSED_BLOCKING";
10166
- reason;
10167
- constructor(message, reason, options) {
10168
- super(message, options);
10169
- this.name = "FailClosedBlockingError";
10170
- this.reason = reason;
10171
- }
10172
- }
10173
- var OPENCODE_INTERNAL_AGENT_NAMES = new Set(["title", "summary", "compaction"]);
10174
- function isMagicContextHiddenAgentName(agent) {
10175
- if (agent === "sidekick" || agent === "smart-note-compiler" || agent.startsWith("smart-note-")) {
10176
- return true;
10177
- }
10178
- if (agent === "historian" || agent.startsWith("historian-"))
10179
- return true;
10180
- if (agent === "dreamer" || agent.startsWith("dreamer-"))
10181
- return true;
10182
- return false;
10183
- }
10184
- var MAX_FORMATTED_BLOCKING_PROCESSES = 8;
10185
- function formatFailClosedBlockingProcesses(processes) {
10186
- const uniqueProcesses = new Map;
10187
- for (const process2 of processes) {
10188
- if (!process2.harness.trim() || !Number.isInteger(process2.pid) || process2.pid <= 0)
10189
- continue;
10190
- uniqueProcesses.set(`${process2.harness}\x00${process2.pid}`, {
10191
- harness: process2.harness.trim(),
10192
- pid: process2.pid
10193
- });
10194
- }
10195
- const entries = [...uniqueProcesses.values()];
10196
- const visible = entries.slice(0, MAX_FORMATTED_BLOCKING_PROCESSES);
10197
- const rendered = visible.map(({ harness, pid }) => `${harness} (PID ${pid})`);
10198
- const omitted = entries.length - visible.length;
10199
- if (omitted > 0)
10200
- rendered.push(`${omitted} more blocking process(es)`);
10201
- if (rendered.length === 0)
10202
- return "a live harness process";
10203
- if (rendered.length === 1)
10204
- return rendered[0];
10205
- const last = rendered.pop();
10206
- return `${rendered.join(", ")}, and ${last}`;
10207
- }
10208
- function formatFailClosedBlockingMessage(reason) {
10209
- if (reason.kind === "migration_guard") {
10210
- if (reason.unreadableFile) {
10211
- const arm = reason.unreadableArm ?? "io";
10212
- const recovery = arm === "io" ? `If no OpenCode server is running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop OpenCode before deleting it.`;
10213
- return [
10214
- `Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live OpenCode server cannot be proven.`,
10215
- recovery,
10216
- `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10217
- ].join(" ");
10218
- }
10219
- return [
10220
- `Magic Context cannot migrate the shared database because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
10221
- "Restart the blocking process (it will pick up the new build and migrate on start), or shut it down and retry.",
10222
- `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10223
- ].join(" ");
10224
- }
10225
- if (reason.kind === "schema_fence") {
10226
- return [
10227
- `Magic Context cannot operate: this Magic Context build is older than the database; upgrade/restart this harness (upstream migration lane v${reason.persistedVersion}, build supports through v${reason.supportedVersion}).`,
10228
- `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10229
- ].join(" ");
10230
- }
10231
- const cause = reason.cause.trim().length > 0 ? reason.cause.trim() : "unknown storage error";
10232
- return [
10233
- `Magic Context cannot operate: persistent storage failed (${cause}).`,
10234
- "The plugin will not silently degrade to native compaction while enabled.",
10235
- `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
10236
- ].join(" ");
10237
- }
10238
- function createFailClosedBlockingError(reason, options) {
10239
- return new FailClosedBlockingError(formatFailClosedBlockingMessage(reason), reason, options);
10240
- }
10241
- function isFailClosedBlockingError(error) {
10242
- return error instanceof FailClosedBlockingError || typeof error === "object" && error !== null && error.name === "FailClosedBlockingError" && error.code === "FAIL_CLOSED_BLOCKING";
10243
- }
10244
- function shouldBypassFailClosedBlock(input) {
10245
- if (input.isPiSubagentEnv === true)
10246
- return true;
10247
- if (input.isInternalChildSession === true)
10248
- return true;
10249
- const agent = typeof input.agent === "string" ? input.agent.trim() : "";
10250
- if (agent.length === 0)
10251
- return false;
10252
- if (OPENCODE_INTERNAL_AGENT_NAMES.has(agent))
10253
- return true;
10254
- if (isMagicContextHiddenAgentName(agent))
10255
- return true;
10256
- return false;
10257
- }
10258
- function resolveAgentNameFromMessages(messages) {
10259
- for (let i = messages.length - 1;i >= 0; i -= 1) {
10260
- const info = messages[i]?.info;
10261
- if (!info || typeof info !== "object")
10262
- continue;
10263
- const agent = info.agent;
10264
- if (typeof agent === "string" && agent.length > 0)
10265
- return agent;
10266
- }
10267
- return;
10268
- }
10269
- function createFailClosedController(options) {
10270
- const reprobeEveryN = Math.max(1, options?.reprobeEveryN ?? FAIL_CLOSED_REPROBE_EVERY_N);
10271
- let reason = null;
10272
- let blockedPassCount = 0;
10273
- return {
10274
- arm(next) {
10275
- reason = next;
10276
- blockedPassCount = 0;
10277
- },
10278
- clear() {
10279
- reason = null;
10280
- blockedPassCount = 0;
10281
- },
10282
- isArmed() {
10283
- return reason !== null;
10284
- },
10285
- getReason() {
10286
- return reason;
10287
- },
10288
- async enforce(input) {
10289
- if (!reason)
10290
- return;
10291
- if (!input.blockingEnabled)
10292
- return;
10293
- if (input.exempt)
10294
- return;
10295
- blockedPassCount += 1;
10296
- const shouldReprobe = typeof input.tryReopen === "function" && (blockedPassCount === 1 || blockedPassCount % reprobeEveryN === 0);
10297
- if (shouldReprobe) {
10298
- try {
10299
- const healed = await input.tryReopen?.();
10300
- if (healed) {
10301
- reason = null;
10302
- blockedPassCount = 0;
10303
- return;
10304
- }
10305
- } catch {}
10306
- }
10307
- const blockedReason = reason;
10308
- if (!blockedReason)
10309
- return;
10310
- throw createFailClosedBlockingError(blockedReason);
10311
- }
10312
- };
10313
- }
10314
- var lastHookInitFailure = null;
10315
- function recordHookInitFailure(failure) {
10316
- lastHookInitFailure = failure;
10317
- }
10318
- function clearHookInitFailure() {
10319
- lastHookInitFailure = null;
10320
- }
10321
- function getLastHookInitFailure() {
10322
- return lastHookInitFailure;
10323
- }
10324
-
10325
10193
  // src/features/magic-context/session-project-backfill.ts
10326
10194
  import { randomUUID } from "node:crypto";
10327
10195
  import { existsSync as existsSync4 } from "node:fs";
@@ -11576,7 +11444,9 @@ var CONNECT_BACKOFF_MAX_MS = 30000;
11576
11444
  var HANDSHAKE_TIMEOUT_MS = 2000;
11577
11445
  var MODULE_SEND_TIMEOUT_MS = 15000;
11578
11446
  var TRANSFORM_SEND_TIMEOUT_MS = 5000;
11447
+ var MAX_WRAPUP_REQUEST_BUDGET_MS = 3800000;
11579
11448
  var SERIAL_LANE_MAX_WAITERS = 16;
11449
+ var SERIAL_LANE_MAX_WAITERS_PER_SESSION = 8;
11580
11450
  var SERIAL_LANE_MIN_REMAINING_MS = 25;
11581
11451
  var CANONICAL_ROOT_CACHE_MAX_ENTRIES = 256;
11582
11452
  function getDefaultConnectionFile() {
@@ -11627,6 +11497,9 @@ function isConnectionFailure(error) {
11627
11497
  ].includes(code) || /\bclient closed\b|\bconnection closed\b|\bclosed the connection\b/i.test(message);
11628
11498
  });
11629
11499
  }
11500
+ function isModuleTransportGenerationChangedResult(value) {
11501
+ return isRecord(value) && value.transport_status === "connection_generation_changed" && typeof value.previous_generation === "number" && typeof value.current_generation === "number";
11502
+ }
11630
11503
 
11631
11504
  class SubcModuleTransport {
11632
11505
  connectionFile;
@@ -11635,10 +11508,13 @@ class SubcModuleTransport {
11635
11508
  routeSessionPrefix;
11636
11509
  client = null;
11637
11510
  routes = new Map;
11511
+ routeOpenings = new Map;
11638
11512
  canonicalRootCache = new Map;
11639
- activeSession = null;
11513
+ sessionLanes = new Map;
11514
+ queuedLaneWaiters = 0;
11515
+ wrapupSessions = new Map;
11640
11516
  nextProbeMs = 0;
11641
- laneReleaseCallbacks = [];
11517
+ connectionPromise = null;
11642
11518
  authorityProjectRoot = "";
11643
11519
  authorityBindRoot = "";
11644
11520
  backoffMs = CONNECT_BACKOFF_INITIAL_MS;
@@ -11684,6 +11560,11 @@ class SubcModuleTransport {
11684
11560
  laneTimeoutError() {
11685
11561
  return this.deadlineError("while queued");
11686
11562
  }
11563
+ connectionChangedError(detail) {
11564
+ const error = new Error(detail);
11565
+ error.code = "ECONNRESET";
11566
+ return error;
11567
+ }
11687
11568
  async beforeDeadline(operation, deadlineMs, detail) {
11688
11569
  const remainingMs = deadlineMs - Date.now();
11689
11570
  if (remainingMs <= 0)
@@ -11701,22 +11582,30 @@ class SubcModuleTransport {
11701
11582
  clearTimeout(timer);
11702
11583
  }
11703
11584
  }
11704
- laneRelease() {
11585
+ cleanupLane(sessionId, lane) {
11586
+ if (!lane.active && lane.waiters.length === 0 && this.sessionLanes.get(sessionId) === lane) {
11587
+ this.sessionLanes.delete(sessionId);
11588
+ }
11589
+ }
11590
+ laneRelease(sessionId, lane) {
11705
11591
  let released = false;
11706
11592
  return () => {
11707
11593
  if (released)
11708
11594
  return;
11709
11595
  released = true;
11710
- this.activeSession = null;
11711
- this.dispatchNextLaneWaiter();
11596
+ lane.active = false;
11597
+ this.dispatchNextLaneWaiter(sessionId, lane);
11712
11598
  };
11713
11599
  }
11714
- dispatchNextLaneWaiter() {
11715
- if (this.activeSession !== null)
11600
+ dispatchNextLaneWaiter(sessionId, lane) {
11601
+ if (lane.active)
11716
11602
  return;
11717
- while (this.laneReleaseCallbacks.length > 0) {
11718
- const waiter = this.laneReleaseCallbacks.shift();
11719
- if (!waiter || waiter.settled)
11603
+ while (lane.waiters.length > 0) {
11604
+ const waiter = lane.waiters.shift();
11605
+ if (!waiter)
11606
+ continue;
11607
+ this.queuedLaneWaiters = Math.max(0, this.queuedLaneWaiters - 1);
11608
+ if (waiter.settled)
11720
11609
  continue;
11721
11610
  waiter.settled = true;
11722
11611
  clearTimeout(waiter.timer);
@@ -11729,10 +11618,16 @@ class SubcModuleTransport {
11729
11618
  waiter.reject(this.laneTimeoutError());
11730
11619
  continue;
11731
11620
  }
11732
- this.activeSession = waiter.sessionId;
11733
- waiter.resolve(this.laneRelease());
11621
+ lane.active = true;
11622
+ waiter.resolve(this.laneRelease(sessionId, lane));
11734
11623
  return;
11735
11624
  }
11625
+ this.cleanupLane(sessionId, lane);
11626
+ }
11627
+ queueFullError() {
11628
+ const error = new Error("module transport queue is full");
11629
+ error.code = "EBUSY";
11630
+ return error;
11736
11631
  }
11737
11632
  acquireCorrectnessLane(sessionId, signal, deadlineMs) {
11738
11633
  if (signal?.aborted) {
@@ -11741,14 +11636,14 @@ class SubcModuleTransport {
11741
11636
  if (deadlineMs - Date.now() < SERIAL_LANE_MIN_REMAINING_MS) {
11742
11637
  return Promise.reject(this.laneTimeoutError());
11743
11638
  }
11744
- if (this.activeSession === null && this.laneReleaseCallbacks.length === 0) {
11745
- this.activeSession = sessionId;
11746
- return Promise.resolve(this.laneRelease());
11639
+ const lane = this.sessionLanes.get(sessionId) ?? { active: false, waiters: [] };
11640
+ this.sessionLanes.set(sessionId, lane);
11641
+ if (!lane.active && lane.waiters.length === 0) {
11642
+ lane.active = true;
11643
+ return Promise.resolve(this.laneRelease(sessionId, lane));
11747
11644
  }
11748
- if (this.laneReleaseCallbacks.length >= SERIAL_LANE_MAX_WAITERS) {
11749
- const error = new Error("module transport queue is full");
11750
- error.code = "EBUSY";
11751
- return Promise.reject(error);
11645
+ if (this.queuedLaneWaiters >= SERIAL_LANE_MAX_WAITERS || lane.waiters.length >= SERIAL_LANE_MAX_WAITERS_PER_SESSION) {
11646
+ return Promise.reject(this.queueFullError());
11752
11647
  }
11753
11648
  return new Promise((resolve3, reject) => {
11754
11649
  const waiter = {};
@@ -11758,14 +11653,14 @@ class SubcModuleTransport {
11758
11653
  waiter.settled = true;
11759
11654
  clearTimeout(waiter.timer);
11760
11655
  signal?.removeEventListener("abort", waiter.onAbort);
11761
- const index = this.laneReleaseCallbacks.indexOf(waiter);
11762
- if (index >= 0)
11763
- this.laneReleaseCallbacks.splice(index, 1);
11656
+ const index = lane.waiters.indexOf(waiter);
11657
+ if (index >= 0) {
11658
+ lane.waiters.splice(index, 1);
11659
+ this.queuedLaneWaiters = Math.max(0, this.queuedLaneWaiters - 1);
11660
+ }
11764
11661
  reject(error);
11765
- if (this.activeSession === null)
11766
- this.dispatchNextLaneWaiter();
11662
+ this.cleanupLane(sessionId, lane);
11767
11663
  };
11768
- waiter.sessionId = sessionId;
11769
11664
  waiter.signal = signal;
11770
11665
  waiter.deadlineMs = deadlineMs;
11771
11666
  waiter.resolve = resolve3;
@@ -11774,17 +11669,40 @@ class SubcModuleTransport {
11774
11669
  waiter.onAbort = () => removeAndReject(signal?.reason ?? new Error("module transport call aborted"));
11775
11670
  waiter.timer = setTimeout(() => removeAndReject(this.laneTimeoutError()), Math.max(0, deadlineMs - Date.now()));
11776
11671
  signal?.addEventListener("abort", waiter.onAbort, { once: true });
11777
- this.laneReleaseCallbacks.push(waiter);
11672
+ lane.waiters.push(waiter);
11673
+ this.queuedLaneWaiters += 1;
11778
11674
  });
11779
11675
  }
11780
11676
  async call(args) {
11781
- const attemptTimeoutMs = args.timeoutMs ?? (args.method === "transform" ? Math.min(this.requestTimeoutMs, TRANSFORM_SEND_TIMEOUT_MS) : this.requestTimeoutMs);
11677
+ const wrapupInFlight = (this.wrapupSessions.get(args.sessionId) ?? 0) > 0;
11678
+ const attemptTimeoutMs = args.timeoutMs ?? (args.method === "session.wrapup" || args.method === "session.status" && wrapupInFlight ? MAX_WRAPUP_REQUEST_BUDGET_MS : args.method === "transform" ? Math.min(this.requestTimeoutMs, TRANSFORM_SEND_TIMEOUT_MS) : this.requestTimeoutMs);
11679
+ const tracksWrapup = args.method === "session.wrapup";
11680
+ if (tracksWrapup) {
11681
+ this.wrapupSessions.set(args.sessionId, (this.wrapupSessions.get(args.sessionId) ?? 0) + 1);
11682
+ }
11683
+ const finishWrapupTracking = () => {
11684
+ if (!tracksWrapup)
11685
+ return;
11686
+ const remaining = (this.wrapupSessions.get(args.sessionId) ?? 1) - 1;
11687
+ if (remaining > 0)
11688
+ this.wrapupSessions.set(args.sessionId, remaining);
11689
+ else
11690
+ this.wrapupSessions.delete(args.sessionId);
11691
+ };
11782
11692
  const laneDeadlineMs = Date.now() + attemptTimeoutMs;
11783
- const releaseLane = await this.acquireCorrectnessLane(args.sessionId, args.signal, laneDeadlineMs);
11784
- const onAbort = () => this.invalidateConnection();
11693
+ let releaseLane;
11694
+ try {
11695
+ releaseLane = await this.acquireCorrectnessLane(args.sessionId, args.signal, laneDeadlineMs);
11696
+ } catch (error) {
11697
+ finishWrapupTracking();
11698
+ throw error;
11699
+ }
11700
+ let activeAttemptClient = null;
11701
+ const onAbort = () => this.invalidateConnection(activeAttemptClient ?? this.client);
11785
11702
  args.signal?.addEventListener("abort", onAbort, { once: true });
11786
11703
  try {
11787
11704
  for (let attempt = 0;attempt < 2; attempt += 1) {
11705
+ activeAttemptClient = null;
11788
11706
  let ensuredRoute = null;
11789
11707
  try {
11790
11708
  if (args.signal?.aborted) {
@@ -11792,22 +11710,35 @@ class SubcModuleTransport {
11792
11710
  }
11793
11711
  const attemptDeadlineMs = Date.now() + attemptTimeoutMs;
11794
11712
  ensuredRoute = await this.ensureRoute(args.sessionId, args.projectRoot, attemptDeadlineMs);
11713
+ activeAttemptClient = ensuredRoute.client;
11795
11714
  if (args.signal?.aborted) {
11796
11715
  throw args.signal.reason ?? new Error("module transport call aborted");
11797
11716
  }
11798
- return await this.beforeDeadline(ensuredRoute.client.request(ensuredRoute.route, args.body, {
11717
+ const response = await this.beforeDeadline(ensuredRoute.client.request(ensuredRoute.route, args.body, {
11799
11718
  priority: Priority.Background,
11800
11719
  admissionClass: AdmissionClass.Normal,
11801
11720
  timeoutMs: Math.max(1, attemptDeadlineMs - Date.now())
11802
11721
  }), attemptDeadlineMs, "waiting for the module response");
11722
+ if (this.client !== ensuredRoute.client || this.connectionGeneration !== ensuredRoute.generation) {
11723
+ throw this.connectionChangedError("subc connection changed while awaiting the module response");
11724
+ }
11725
+ return response;
11803
11726
  } catch (error) {
11804
11727
  if (isConnectionFailure(error)) {
11728
+ const previousGeneration = ensuredRoute?.generation ?? this.connectionGeneration;
11805
11729
  if (ensuredRoute) {
11806
11730
  this.dropRoute(ensuredRoute.routeKey, ensuredRoute.route);
11807
11731
  this.invalidateConnection(ensuredRoute.client);
11808
11732
  } else {
11809
11733
  this.invalidateConnection();
11810
11734
  }
11735
+ if (args.generationSensitive && !args.signal?.aborted) {
11736
+ return {
11737
+ transport_status: "connection_generation_changed",
11738
+ previous_generation: previousGeneration,
11739
+ current_generation: this.connectionGeneration
11740
+ };
11741
+ }
11811
11742
  if (attempt === 0 && !args.signal?.aborted)
11812
11743
  continue;
11813
11744
  }
@@ -11817,6 +11748,7 @@ class SubcModuleTransport {
11817
11748
  throw new Error("module transport route retry exhausted");
11818
11749
  } finally {
11819
11750
  args.signal?.removeEventListener("abort", onAbort);
11751
+ finishWrapupTracking();
11820
11752
  releaseLane();
11821
11753
  }
11822
11754
  }
@@ -11907,7 +11839,7 @@ class SubcModuleTransport {
11907
11839
  });
11908
11840
  }
11909
11841
  }
11910
- if (routes.length === 0 && this.activeSession === sessionId) {
11842
+ if (routes.length === 0 && this.sessionLanes.get(sessionId)?.active) {
11911
11843
  this.invalidateConnection(client);
11912
11844
  }
11913
11845
  }
@@ -11922,23 +11854,36 @@ class SubcModuleTransport {
11922
11854
  }
11923
11855
  if (existing)
11924
11856
  this.routes.delete(routeKey);
11925
- const target = { kind: "tool_provider", module_id: this.moduleId };
11926
- const identity = {
11927
- project_root: projectRoot,
11928
- harness: getHarness(),
11929
- session: `${this.routeSessionPrefix}${sessionId}`
11930
- };
11931
- const route = await this.beforeDeadline(client.routeOpen(target, identity), deadlineMs, "opening the module route");
11932
- if (this.client !== client || generation !== this.connectionGeneration) {
11933
- await client.closeRoute(route).catch(() => {
11934
- return;
11935
- });
11936
- const error = new Error("subc connection changed while opening module route");
11937
- error.code = "ECONNRESET";
11938
- throw error;
11857
+ const opening = this.routeOpenings.get(routeKey);
11858
+ if (opening?.client === client && opening.generation === generation) {
11859
+ return await opening.promise;
11860
+ }
11861
+ const promise = (async () => {
11862
+ const target = { kind: "tool_provider", module_id: this.moduleId };
11863
+ const identity = {
11864
+ project_root: projectRoot,
11865
+ harness: getHarness(),
11866
+ session: `${this.routeSessionPrefix}${sessionId}`
11867
+ };
11868
+ const route = await this.beforeDeadline(client.routeOpen(target, identity), deadlineMs, "opening the module route");
11869
+ if (this.client !== client || generation !== this.connectionGeneration) {
11870
+ await client.closeRoute(route).catch(() => {
11871
+ return;
11872
+ });
11873
+ throw this.connectionChangedError("subc connection changed while opening module route");
11874
+ }
11875
+ this.routes.set(routeKey, { route, generation });
11876
+ return { client, route, routeKey, generation };
11877
+ })();
11878
+ const routeOpening = { client, generation, promise };
11879
+ this.routeOpenings.set(routeKey, routeOpening);
11880
+ try {
11881
+ return await promise;
11882
+ } finally {
11883
+ if (this.routeOpenings.get(routeKey) === routeOpening) {
11884
+ this.routeOpenings.delete(routeKey);
11885
+ }
11939
11886
  }
11940
- this.routes.set(routeKey, { route, generation });
11941
- return { client, route, routeKey, generation };
11942
11887
  }
11943
11888
  dropRoute(routeKey, route) {
11944
11889
  const existing = this.routes.get(routeKey);
@@ -11966,9 +11911,17 @@ class SubcModuleTransport {
11966
11911
  }
11967
11912
  return resolved;
11968
11913
  }
11914
+ connectClient() {
11915
+ return SubcClient.connect({
11916
+ connectionFile: this.connectionFile,
11917
+ handshakeTimeoutMs: HANDSHAKE_TIMEOUT_MS
11918
+ });
11919
+ }
11969
11920
  async ensureConnected() {
11970
11921
  if (this.client)
11971
11922
  return this.client;
11923
+ if (this.connectionPromise)
11924
+ return await this.connectionPromise;
11972
11925
  const now = Date.now();
11973
11926
  if (now < this.nextProbeMs) {
11974
11927
  const error = new Error(`subc connection backoff active until ${this.nextProbeMs}`);
@@ -11976,38 +11929,44 @@ class SubcModuleTransport {
11976
11929
  throw error;
11977
11930
  }
11978
11931
  const generation = this.connectionGeneration;
11979
- let candidate = null;
11980
- try {
11981
- candidate = await SubcClient.connect({
11982
- connectionFile: this.connectionFile,
11983
- handshakeTimeoutMs: HANDSHAKE_TIMEOUT_MS
11984
- });
11985
- if (generation !== this.connectionGeneration) {
11986
- candidate.close();
11987
- const error = new Error("subc connection attempt was superseded");
11988
- error.code = "ECONNRESET";
11932
+ const connecting = (async () => {
11933
+ let candidate = null;
11934
+ try {
11935
+ candidate = await this.connectClient();
11936
+ if (generation !== this.connectionGeneration) {
11937
+ candidate.close();
11938
+ throw this.connectionChangedError("subc connection attempt was superseded");
11939
+ }
11940
+ this.client = candidate;
11941
+ this.routes.clear();
11942
+ this.backoffMs = CONNECT_BACKOFF_INITIAL_MS;
11943
+ this.nextProbeMs = 0;
11944
+ return candidate;
11945
+ } catch (error) {
11946
+ candidate?.close();
11947
+ if (generation === this.connectionGeneration)
11948
+ this.invalidateConnection();
11949
+ this.nextProbeMs = Date.now() + this.backoffMs;
11950
+ this.backoffMs = Math.min(this.backoffMs * 2, CONNECT_BACKOFF_MAX_MS);
11989
11951
  throw error;
11990
11952
  }
11991
- this.client = candidate;
11992
- this.routes.clear();
11993
- this.backoffMs = CONNECT_BACKOFF_INITIAL_MS;
11994
- this.nextProbeMs = 0;
11995
- return candidate;
11996
- } catch (error) {
11997
- candidate?.close();
11998
- this.invalidateConnection();
11999
- this.nextProbeMs = Date.now() + this.backoffMs;
12000
- this.backoffMs = Math.min(this.backoffMs * 2, CONNECT_BACKOFF_MAX_MS);
12001
- throw error;
11953
+ })();
11954
+ this.connectionPromise = connecting;
11955
+ try {
11956
+ return await connecting;
11957
+ } finally {
11958
+ if (this.connectionPromise === connecting)
11959
+ this.connectionPromise = null;
12002
11960
  }
12003
11961
  }
12004
11962
  invalidateConnection(client = this.client) {
12005
- if (client && this.client && client !== this.client)
11963
+ if (client && this.client !== client)
12006
11964
  return;
12007
11965
  this.connectionGeneration += 1;
12008
11966
  this.invalidateStateSyncCapabilities();
12009
11967
  this.client = null;
12010
11968
  this.routes.clear();
11969
+ this.routeOpenings.clear();
12011
11970
  client?.close();
12012
11971
  }
12013
11972
  }
@@ -12062,13 +12021,15 @@ function rowKeys(leaseKey) {
12062
12021
  return {
12063
12022
  holder: "dreaming_lease_holder",
12064
12023
  heartbeat: "dreaming_lease_heartbeat",
12065
- expiry: "dreaming_lease_expiry"
12024
+ expiry: "dreaming_lease_expiry",
12025
+ generation: "dreaming_lease_generation"
12066
12026
  };
12067
12027
  }
12068
12028
  return {
12069
12029
  holder: `lease:${leaseKey}:holder`,
12070
12030
  heartbeat: `lease:${leaseKey}:heartbeat`,
12071
- expiry: `lease:${leaseKey}:expiry`
12031
+ expiry: `lease:${leaseKey}:expiry`,
12032
+ generation: `lease:${leaseKey}:generation`
12072
12033
  };
12073
12034
  }
12074
12035
  function getLeaseExpiry(db, keys) {
@@ -12086,6 +12047,13 @@ function isLeaseActive(db, leaseKey = DREAMING_LEASE_KEY) {
12086
12047
  function getLeaseHolder(db, leaseKey = DREAMING_LEASE_KEY) {
12087
12048
  return getDreamState(db, rowKeys(leaseKey).holder);
12088
12049
  }
12050
+ function getLeaseGeneration(db, leaseKey = DREAMING_LEASE_KEY) {
12051
+ const value = getDreamState(db, rowKeys(leaseKey).generation);
12052
+ if (!value)
12053
+ return null;
12054
+ const generation = Number(value);
12055
+ return Number.isSafeInteger(generation) && generation > 0 ? generation : null;
12056
+ }
12089
12057
  function peekLeaseHolderAndExpiry(db, expectedHolder, leaseKey = DREAMING_LEASE_KEY) {
12090
12058
  const keys = rowKeys(leaseKey);
12091
12059
  const holder = getDreamState(db, keys.holder);
@@ -12097,6 +12065,9 @@ function peekLeaseHolderAndExpiry(db, expectedHolder, leaseKey = DREAMING_LEASE_
12097
12065
  const expiry = Number(expiryStr);
12098
12066
  return Number.isFinite(expiry) && expiry >= Date.now();
12099
12067
  }
12068
+ function leaseOwnershipMatches(db, expectedHolder, expectedGeneration, leaseKey = DREAMING_LEASE_KEY) {
12069
+ return getLeaseGeneration(db, leaseKey) === expectedGeneration && peekLeaseHolderAndExpiry(db, expectedHolder, leaseKey);
12070
+ }
12100
12071
  function runImmediate(db, body) {
12101
12072
  db.exec("BEGIN IMMEDIATE");
12102
12073
  let committed = false;
@@ -12113,26 +12084,30 @@ function runImmediate(db, body) {
12113
12084
  }
12114
12085
  }
12115
12086
  }
12116
- function acquireLease(db, holderId, leaseKey = DREAMING_LEASE_KEY) {
12087
+ function acquireLeaseWithAcquisition(db, holderId, leaseKey = DREAMING_LEASE_KEY) {
12117
12088
  const keys = rowKeys(leaseKey);
12118
12089
  return runImmediate(db, () => {
12119
- if (isLeaseActive(db, leaseKey)) {
12120
- const existingHolder = getLeaseHolder(db, leaseKey);
12121
- if (existingHolder && existingHolder !== holderId) {
12122
- return false;
12123
- }
12090
+ const existingHolder = getLeaseHolder(db, leaseKey);
12091
+ if (isLeaseActive(db, leaseKey) && existingHolder && existingHolder !== holderId) {
12092
+ return null;
12124
12093
  }
12125
12094
  const now = Date.now();
12095
+ const priorGeneration = getLeaseGeneration(db, leaseKey) ?? 0;
12096
+ const generation = existingHolder === holderId ? Math.max(1, priorGeneration) : priorGeneration + 1;
12126
12097
  setDreamState(db, keys.holder, holderId);
12127
12098
  setDreamState(db, keys.heartbeat, String(now));
12128
12099
  setDreamState(db, keys.expiry, String(now + LEASE_DURATION_MS));
12129
- return true;
12100
+ setDreamState(db, keys.generation, String(generation));
12101
+ return { acquiredAt: now, generation };
12130
12102
  });
12131
12103
  }
12132
- function renewLease(db, holderId, leaseKey = DREAMING_LEASE_KEY) {
12104
+ function acquireLease(db, holderId, leaseKey = DREAMING_LEASE_KEY) {
12105
+ return acquireLeaseWithAcquisition(db, holderId, leaseKey) !== null;
12106
+ }
12107
+ function renewLease(db, holderId, leaseKey = DREAMING_LEASE_KEY, expectedGeneration) {
12133
12108
  const keys = rowKeys(leaseKey);
12134
12109
  return runImmediate(db, () => {
12135
- if (getLeaseHolder(db, leaseKey) !== holderId || !isLeaseActive(db, leaseKey)) {
12110
+ if (getLeaseHolder(db, leaseKey) !== holderId || !isLeaseActive(db, leaseKey) || expectedGeneration !== undefined && getLeaseGeneration(db, leaseKey) !== expectedGeneration) {
12136
12111
  return false;
12137
12112
  }
12138
12113
  const now = Date.now();
@@ -12150,9 +12125,12 @@ function runLeaseGuardedWrite(db, holderId, leaseKey, fn) {
12150
12125
  });
12151
12126
  }
12152
12127
  var LEASE_HEARTBEAT_INTERVAL_MS = 60 * 1000;
12153
- function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalMs = LEASE_HEARTBEAT_INTERVAL_MS) {
12128
+ function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisition = LEASE_HEARTBEAT_INTERVAL_MS) {
12129
+ const intervalMs = typeof intervalOrAcquisition === "number" ? intervalOrAcquisition : LEASE_HEARTBEAT_INTERVAL_MS;
12130
+ const acquisition = typeof intervalOrAcquisition === "number" ? undefined : intervalOrAcquisition;
12154
12131
  let lost = false;
12155
- let lastConfirmedAt = Date.now();
12132
+ let expectedGeneration = acquisition?.generation ?? getLeaseGeneration(db, leaseKey);
12133
+ let lastConfirmedAt = acquisition?.acquiredAt ?? Date.now();
12156
12134
  const declareLost = (reason) => {
12157
12135
  if (lost)
12158
12136
  return;
@@ -12163,15 +12141,25 @@ function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalMs = LEASE_
12163
12141
  if (lost)
12164
12142
  return;
12165
12143
  try {
12166
- if (renewLease(db, holderId, leaseKey)) {
12144
+ if (renewLease(db, holderId, leaseKey, expectedGeneration === null ? undefined : expectedGeneration)) {
12167
12145
  lastConfirmedAt = Date.now();
12168
12146
  return;
12169
12147
  }
12148
+ if (expectedGeneration !== null && getLeaseGeneration(db, leaseKey) !== expectedGeneration) {
12149
+ declareLost("lease generation changed — another holder acquired it");
12150
+ return;
12151
+ }
12170
12152
  if (Date.now() - lastConfirmedAt > LEASE_DURATION_MS) {
12171
12153
  declareLost("lease lapsed past TTL — another holder may have run");
12172
12154
  return;
12173
12155
  }
12174
- if (acquireLease(db, holderId, leaseKey)) {
12156
+ const reacquired = acquireLeaseWithAcquisition(db, holderId, leaseKey);
12157
+ if (reacquired) {
12158
+ if (expectedGeneration !== null && reacquired.generation !== expectedGeneration) {
12159
+ declareLost("lease generation changed during reacquisition");
12160
+ return;
12161
+ }
12162
+ expectedGeneration = reacquired.generation;
12175
12163
  lastConfirmedAt = Date.now();
12176
12164
  return;
12177
12165
  }
@@ -12678,7 +12666,7 @@ var DREAMER_DOCS_AGENT = "dreamer-docs";
12678
12666
  var DREAMER_REVIEWER_AGENT = "dreamer-reviewer";
12679
12667
 
12680
12668
  // src/features/magic-context/mural/compress-cues.ts
12681
- import { createHash as createHash2 } from "node:crypto";
12669
+ import { createHash as createHash3 } from "node:crypto";
12682
12670
 
12683
12671
  // src/features/magic-context/dreamer/manifest-parser.ts
12684
12672
  function extractCompleteManifestBody(text, rootName) {
@@ -12714,6 +12702,16 @@ function assertManifestCoversExactly(ids, expectedIds, rootName) {
12714
12702
  }
12715
12703
 
12716
12704
  // src/features/magic-context/dreamer/module-apply.ts
12705
+ class DreamerModuleBusyError extends Error {
12706
+ state;
12707
+ transient = true;
12708
+ constructor(state) {
12709
+ super(`Rust memory authority is ${state}; dreamer mutation deferred until authority settles.`);
12710
+ this.state = state;
12711
+ this.name = "DreamerModuleBusyError";
12712
+ }
12713
+ }
12714
+
12717
12715
  class DreamerModuleFailureError extends Error {
12718
12716
  transient = true;
12719
12717
  constructor(operation, cause) {
@@ -12735,9 +12733,12 @@ async function resolveDreamerModuleRoute(args) {
12735
12733
  projectRoot: args.projectRoot,
12736
12734
  domain: "memories"
12737
12735
  });
12738
- if (result.authority?.state !== "MODULE")
12736
+ const authority = result.authority;
12737
+ if (authority?.state === "DRAINING")
12738
+ throw new DreamerModuleBusyError(authority.state);
12739
+ if (authority?.state !== "MODULE")
12739
12740
  return;
12740
- const generation = result.authority.generation;
12741
+ const generation = authority.generation;
12741
12742
  if (typeof generation !== "number")
12742
12743
  throw new Error("Rust authority status omitted generation");
12743
12744
  return {
@@ -12771,6 +12772,68 @@ function getModuleMemoryIdentities(db, projectIdentity, contextIds) {
12771
12772
  ] : []));
12772
12773
  }
12773
12774
 
12775
+ // src/features/magic-context/dreamer/provider-output-failure.ts
12776
+ import { createHash as createHash2 } from "node:crypto";
12777
+ var MAX_NEAR_ZERO_OUTPUT_TOKENS = 32;
12778
+
12779
+ class DreamerProviderOutputFailureError extends Error {
12780
+ fingerprint;
12781
+ outputTokens;
12782
+ reasoningTokens;
12783
+ transient = true;
12784
+ constructor(fingerprint, outputTokens, reasoningTokens, responseText) {
12785
+ const preview = responseText.trim().replace(/\s+/g, " ").slice(0, 160);
12786
+ super(`dreamer provider-outage completion (output_tokens=${outputTokens}, reasoning_tokens=${reasoningTokens}): ${JSON.stringify(preview)}`);
12787
+ this.fingerprint = fingerprint;
12788
+ this.outputTokens = outputTokens;
12789
+ this.reasoningTokens = reasoningTokens;
12790
+ this.name = "DreamerProviderOutputFailureError";
12791
+ }
12792
+ }
12793
+ function finiteTokenCount(value) {
12794
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
12795
+ }
12796
+ function completionShape(value) {
12797
+ if (!isRecord(value))
12798
+ return null;
12799
+ const info = isRecord(value.info) ? value.info : value;
12800
+ if (info.role !== "assistant")
12801
+ return null;
12802
+ const time = isRecord(info.time) ? info.time : null;
12803
+ const tokens = isRecord(info.tokens) ? info.tokens : null;
12804
+ return {
12805
+ createdAt: typeof time?.created === "number" ? time.created : 0,
12806
+ finish: typeof info.finish === "string" ? info.finish : typeof info.finish_reason === "string" ? info.finish_reason : typeof info.finishReason === "string" ? info.finishReason : null,
12807
+ error: info.error,
12808
+ outputTokens: finiteTokenCount(tokens?.output),
12809
+ reasoningTokens: finiteTokenCount(tokens?.reasoning)
12810
+ };
12811
+ }
12812
+ function latestAssistantCompletion(messages) {
12813
+ if (!Array.isArray(messages))
12814
+ return null;
12815
+ let latest = null;
12816
+ for (const message of messages) {
12817
+ const completion = completionShape(message);
12818
+ if (completion && (!latest || completion.createdAt >= latest.createdAt))
12819
+ latest = completion;
12820
+ }
12821
+ return latest;
12822
+ }
12823
+ function providerOutputFailureFromInvalidManifest(messages, responseText) {
12824
+ const completion = latestAssistantCompletion(messages);
12825
+ if (completion?.finish?.toLowerCase() !== "stop")
12826
+ return null;
12827
+ if (completion.error != null || completion.outputTokens === null || completion.outputTokens > MAX_NEAR_ZERO_OUTPUT_TOKENS || completion.reasoningTokens !== 0) {
12828
+ return null;
12829
+ }
12830
+ const normalized = responseText.trim().replace(/\s+/g, " ").toLowerCase();
12831
+ if (!normalized)
12832
+ return null;
12833
+ const fingerprint = createHash2("sha256").update(normalized).digest("hex").slice(0, 16);
12834
+ return new DreamerProviderOutputFailureError(fingerprint, completion.outputTokens, completion.reasoningTokens, responseText);
12835
+ }
12836
+
12774
12837
  // src/features/magic-context/mural/compress-cues-prompt.ts
12775
12838
  var CUE_BUDGET_HIGH = 90;
12776
12839
  var CUE_BUDGET_LOW = 50;
@@ -12943,7 +13006,7 @@ async function runCompressCues(args) {
12943
13006
  chunks.push(candidates.slice(i, i + COMPRESS_CUES_CHUNK_SIZE));
12944
13007
  }
12945
13008
  const abortController = new AbortController;
12946
- const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
13009
+ const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
12947
13010
  try {
12948
13011
  let consecutiveTimeouts = 0;
12949
13012
  let timeoutStreakElapsedMs = [];
@@ -13038,7 +13101,14 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
13038
13101
  const text = extractLatestAssistantText(messages);
13039
13102
  if (!text)
13040
13103
  throw new Error("compress-cues returned no output");
13041
- parseCuesManifest(text);
13104
+ try {
13105
+ parseCuesManifest(text);
13106
+ } catch (error) {
13107
+ const providerFailure = providerOutputFailureFromInvalidManifest(messages, text);
13108
+ if (providerFailure)
13109
+ throw providerFailure;
13110
+ throw error;
13111
+ }
13042
13112
  return text;
13043
13113
  }
13044
13114
  });
@@ -13046,7 +13116,7 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
13046
13116
  } catch (error) {
13047
13117
  const desc = describeError(error);
13048
13118
  log(`[dreamer] compress-cues chunk failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
13049
- if (signal.aborted)
13119
+ if (signal.aborted || error instanceof DreamerProviderOutputFailureError)
13050
13120
  throw error;
13051
13121
  return {
13052
13122
  compressed: 0,
@@ -13154,7 +13224,7 @@ async function applyCuesThroughModule(args, chunk, manifestText, signal) {
13154
13224
  log(`[dreamer] compress-cues: skipped cue for memory ${entry.id} (${failure.reason}; rejection ${rejectionCount}/${CUE_REJECTION_LATCH_THRESHOLD})`);
13155
13225
  }
13156
13226
  }
13157
- const commandId = `mural-cues:${route.moduleCommandId}:${createHash2("sha256").update(chunk.map((candidate) => candidate.memory.id).join(",")).digest("hex").slice(0, 24)}`;
13227
+ const commandId = `mural-cues:${route.moduleCommandId}:${createHash3("sha256").update(chunk.map((candidate) => candidate.memory.id).join(",")).digest("hex").slice(0, 24)}`;
13158
13228
  let response;
13159
13229
  try {
13160
13230
  response = await route.moduleClient.call({
@@ -13291,7 +13361,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
13291
13361
  const heartbeat = startLeaseHeartbeat(args.db, args.holderId, leaseKey, (reason) => {
13292
13362
  log(`[dreamer] user-memories: lease lost (${reason}) — aborting`);
13293
13363
  abortController.abort();
13294
- });
13364
+ }, args.leaseAcquisition);
13295
13365
  try {
13296
13366
  const createResponse = await createChildSessionWithFence({
13297
13367
  client: args.client,
@@ -13414,7 +13484,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
13414
13484
  }
13415
13485
 
13416
13486
  // src/features/magic-context/dreamer/classify.ts
13417
- import { createHash as createHash3 } from "node:crypto";
13487
+ import { createHash as createHash4 } from "node:crypto";
13418
13488
 
13419
13489
  // src/plugin/rust-tool-backends.ts
13420
13490
  function toolCallIdFromContext(context) {
@@ -13816,7 +13886,7 @@ async function runClassify(args) {
13816
13886
  chunks.push(toClassify.slice(i, i + CLASSIFY_CHUNK_SIZE));
13817
13887
  }
13818
13888
  const abortController = new AbortController;
13819
- const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
13889
+ const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
13820
13890
  try {
13821
13891
  for (let i = 0;i < chunks.length; i += 1) {
13822
13892
  const remainingMs = Math.max(0, args.deadline - Date.now());
@@ -13896,7 +13966,14 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
13896
13966
  const text = extractLatestAssistantText(messages);
13897
13967
  if (!text)
13898
13968
  throw new Error("classify returned no output");
13899
- parseClassifyManifest(text);
13969
+ try {
13970
+ parseClassifyManifest(text);
13971
+ } catch (error) {
13972
+ const providerFailure = providerOutputFailureFromInvalidManifest(messages, text);
13973
+ if (providerFailure)
13974
+ throw providerFailure;
13975
+ throw error;
13976
+ }
13900
13977
  return text;
13901
13978
  }
13902
13979
  });
@@ -13907,7 +13984,7 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
13907
13984
  const desc = describeError(failure);
13908
13985
  log(`[dreamer] classify chunk failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
13909
13986
  recordInvocation(args, startedAt, { status: "failed", error: failure });
13910
- if (moduleRoute || signal.aborted)
13987
+ if (moduleRoute || signal.aborted || failure instanceof DreamerProviderOutputFailureError)
13911
13988
  throw failure;
13912
13989
  return { classified: 0, changed: 0 };
13913
13990
  } finally {
@@ -13936,7 +14013,7 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
13936
14013
  v: 1,
13937
14014
  session_id: args.moduleSessionId,
13938
14015
  task: "classify",
13939
- command_id: `classify:${args.moduleCommandId ?? Date.now()}:${createHash3("sha256").update(chunk.map((candidate) => candidate.id).join(",")).digest("hex").slice(0, 24)}`,
14016
+ command_id: `classify:${args.moduleCommandId ?? Date.now()}:${createHash4("sha256").update(chunk.map((candidate) => candidate.id).join(",")).digest("hex").slice(0, 24)}`,
13940
14017
  authority_generation: args.moduleAuthorityGeneration,
13941
14018
  payload: {
13942
14019
  prompt_body: prompt,
@@ -14632,7 +14709,7 @@ function throwIfAborted2(signal) {
14632
14709
  }
14633
14710
 
14634
14711
  // src/features/magic-context/smart-notes/compiler.ts
14635
- import { createHash as createHash4 } from "node:crypto";
14712
+ import { createHash as createHash5 } from "node:crypto";
14636
14713
 
14637
14714
  // src/features/magic-context/smart-notes/sandbox-runner.ts
14638
14715
  var asyncModulePromise = null;
@@ -15026,7 +15103,7 @@ function manifestAdvisoryWarnings(code, manifest) {
15026
15103
  return warnings;
15027
15104
  }
15028
15105
  function hashCheck(surfaceCondition, compiledCheck, manifest, checkCron) {
15029
- return createHash4("sha256").update(surfaceCondition ?? "").update("\x00").update(compiledCheck).update("\x00").update(JSON.stringify(manifest)).update("\x00").update(checkCron).digest("hex");
15106
+ return createHash5("sha256").update(surfaceCondition ?? "").update("\x00").update(compiledCheck).update("\x00").update(JSON.stringify(manifest)).update("\x00").update(checkCron).digest("hex");
15030
15107
  }
15031
15108
  function extractJsonObject(output) {
15032
15109
  const fenced = output.match(/```(?:json)?\s*([\s\S]*?)```/i);
@@ -15414,7 +15491,7 @@ async function evaluateSmartNotes(args) {
15414
15491
  leaseAbortController.abort(new Error("Dream lease lost during smart notes"));
15415
15492
  log("[dreamer] smart notes: lease lost — aborting");
15416
15493
  args.onLeaseLost?.("smart notes");
15417
- });
15494
+ }, args.leaseAcquisition);
15418
15495
  let surfaced = 0;
15419
15496
  let didWork = false;
15420
15497
  try {
@@ -15855,7 +15932,7 @@ function enforceMaintainDocsProtectedRegions(args) {
15855
15932
  }
15856
15933
 
15857
15934
  // src/features/magic-context/dreamer/map-memories.ts
15858
- import { createHash as createHash5 } from "node:crypto";
15935
+ import { createHash as createHash6 } from "node:crypto";
15859
15936
 
15860
15937
  // src/features/magic-context/dreamer/map-memories-prompt.ts
15861
15938
  import { existsSync as existsSync8, statSync as statSync2 } from "node:fs";
@@ -15972,7 +16049,7 @@ async function mapMemories(args) {
15972
16049
  }
15973
16050
  result.remaining = inputs.length;
15974
16051
  const abortController = new AbortController;
15975
- const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
16052
+ const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
15976
16053
  try {
15977
16054
  for (let i = 0;i < batches.length; i += 1) {
15978
16055
  const remainingMs = Math.max(0, args.deadline - Date.now());
@@ -16116,7 +16193,7 @@ async function applyBatchMappings(args, batch, manifestText) {
16116
16193
  memory_project: args.projectIdentity,
16117
16194
  context_store_uuid: args.moduleRoute.moduleContextStoreUuid,
16118
16195
  authority_generation: args.moduleRoute.moduleAuthorityGeneration,
16119
- command_id: `${args.moduleRoute.moduleCommandId}:${createHash5("sha256").update(rows.map((row) => row.memory_id).join(",")).digest("hex").slice(0, 16)}`,
16196
+ command_id: `${args.moduleRoute.moduleCommandId}:${createHash6("sha256").update(rows.map((row) => row.memory_id).join(",")).digest("hex").slice(0, 16)}`,
16120
16197
  rows
16121
16198
  }
16122
16199
  }
@@ -16341,7 +16418,7 @@ async function promotePrimers(args) {
16341
16418
  const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => {
16342
16419
  leaseLost = true;
16343
16420
  log("[dreamer] primers: lease lost during promote-primers — aborting");
16344
- });
16421
+ }, args.leaseAcquisition);
16345
16422
  try {
16346
16423
  assertLeaseHeld("prune start");
16347
16424
  result.pruned = pruneExpiredPrimerCandidatesForProject(args.db, args.projectIdentity, Date.now(), PRIMER_CANDIDATE_TTL_MS);
@@ -16573,7 +16650,7 @@ async function refreshPrimers(args) {
16573
16650
  if (primers.length === 0)
16574
16651
  return result;
16575
16652
  const abortController = new AbortController;
16576
- const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
16653
+ const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
16577
16654
  try {
16578
16655
  for (let i = 0;i < primers.length; i += 1) {
16579
16656
  const primer = primers[i];
@@ -17060,68 +17137,6 @@ function evaluateTaskGate(task, ctx) {
17060
17137
  // src/features/magic-context/dreamer/verify.ts
17061
17138
  import { createHash as createHash7 } from "node:crypto";
17062
17139
 
17063
- // src/features/magic-context/dreamer/provider-output-failure.ts
17064
- import { createHash as createHash6 } from "node:crypto";
17065
- var MAX_NEAR_ZERO_OUTPUT_TOKENS = 32;
17066
-
17067
- class DreamerProviderOutputFailureError extends Error {
17068
- fingerprint;
17069
- outputTokens;
17070
- reasoningTokens;
17071
- transient = true;
17072
- constructor(fingerprint, outputTokens, reasoningTokens, responseText) {
17073
- const preview = responseText.trim().replace(/\s+/g, " ").slice(0, 160);
17074
- super(`verify provider-outage completion (output_tokens=${outputTokens}, reasoning_tokens=${reasoningTokens}): ${JSON.stringify(preview)}`);
17075
- this.fingerprint = fingerprint;
17076
- this.outputTokens = outputTokens;
17077
- this.reasoningTokens = reasoningTokens;
17078
- this.name = "DreamerProviderOutputFailureError";
17079
- }
17080
- }
17081
- function finiteTokenCount(value) {
17082
- return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
17083
- }
17084
- function completionShape(value) {
17085
- if (!isRecord(value))
17086
- return null;
17087
- const info = isRecord(value.info) ? value.info : value;
17088
- if (info.role !== "assistant")
17089
- return null;
17090
- const time = isRecord(info.time) ? info.time : null;
17091
- const tokens = isRecord(info.tokens) ? info.tokens : null;
17092
- return {
17093
- createdAt: typeof time?.created === "number" ? time.created : 0,
17094
- finish: typeof info.finish === "string" ? info.finish : typeof info.finish_reason === "string" ? info.finish_reason : typeof info.finishReason === "string" ? info.finishReason : null,
17095
- error: info.error,
17096
- outputTokens: finiteTokenCount(tokens?.output),
17097
- reasoningTokens: finiteTokenCount(tokens?.reasoning)
17098
- };
17099
- }
17100
- function latestAssistantCompletion(messages) {
17101
- if (!Array.isArray(messages))
17102
- return null;
17103
- let latest = null;
17104
- for (const message of messages) {
17105
- const completion = completionShape(message);
17106
- if (completion && (!latest || completion.createdAt >= latest.createdAt))
17107
- latest = completion;
17108
- }
17109
- return latest;
17110
- }
17111
- function providerOutputFailureFromInvalidManifest(messages, responseText) {
17112
- const completion = latestAssistantCompletion(messages);
17113
- if (completion?.finish?.toLowerCase() !== "stop")
17114
- return null;
17115
- if (completion.error != null || completion.outputTokens === null || completion.outputTokens > MAX_NEAR_ZERO_OUTPUT_TOKENS || completion.reasoningTokens !== 0) {
17116
- return null;
17117
- }
17118
- const normalized = responseText.trim().replace(/\s+/g, " ").toLowerCase();
17119
- if (!normalized)
17120
- return null;
17121
- const fingerprint = createHash6("sha256").update(normalized).digest("hex").slice(0, 16);
17122
- return new DreamerProviderOutputFailureError(fingerprint, completion.outputTokens, completion.reasoningTokens, responseText);
17123
- }
17124
-
17125
17140
  // src/features/magic-context/dreamer/verify-gate.ts
17126
17141
  import path4 from "node:path";
17127
17142
  function minOf(values) {
@@ -17366,7 +17381,7 @@ async function runVerify(args) {
17366
17381
  batches.push(gate.inScope.slice(i, i + VERIFY_BATCH_SIZE));
17367
17382
  }
17368
17383
  const abortController = new AbortController;
17369
- const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort());
17384
+ const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
17370
17385
  let consecutiveProviderFailures = 0;
17371
17386
  let priorProviderFailureFingerprint = null;
17372
17387
  let lastProviderFailure = null;
@@ -17702,6 +17717,9 @@ function createDreamTaskExecutor(deps) {
17702
17717
  return async (config, ctx) => {
17703
17718
  const { db, projectIdentity, holderId, leaseKey } = ctx;
17704
17719
  const startedAt = Date.now();
17720
+ const leaseAcquisition = ctx.leaseAcquisition ?? acquireLeaseWithAcquisition(db, holderId, leaseKey) ?? (() => {
17721
+ throw new Error("Dream lease unavailable during executor setup");
17722
+ })();
17705
17723
  const deadline = startedAt + config.timeoutMinutes * 60 * 1000;
17706
17724
  const backlogAtStart = getDreamTaskBacklog(db, projectIdentity, config.task);
17707
17725
  const reportProgress = (processed) => {
@@ -17719,7 +17737,7 @@ function createDreamTaskExecutor(deps) {
17719
17737
  };
17720
17738
  const parent = await resolveParentSessionId();
17721
17739
  let moduleRoute;
17722
- if (config.task === "map-memories" || config.task === "compress-cues" || config.task === "verify" || config.task === "verify-broad" || config.task === "retrospective") {
17740
+ if (config.task === "map-memories" || config.task === "compress-cues" || config.task === "classify-memories" || config.task === "verify" || config.task === "verify-broad" || config.task === "retrospective") {
17723
17741
  try {
17724
17742
  moduleRoute = await resolveDreamerModuleRoute({
17725
17743
  db,
@@ -17733,6 +17751,9 @@ function createDreamTaskExecutor(deps) {
17733
17751
  throw new DreamerModuleFailureError("authority.status", error);
17734
17752
  }
17735
17753
  }
17754
+ if (!leaseOwnershipMatches(db, holderId, leaseAcquisition.generation, leaseKey)) {
17755
+ throw new Error("Dream lease lost during executor setup");
17756
+ }
17736
17757
  const recordRun = (status, error, extra) => {
17737
17758
  try {
17738
17759
  insertDreamRun(db, {
@@ -17805,6 +17826,7 @@ function createDreamTaskExecutor(deps) {
17805
17826
  holderId,
17806
17827
  leaseKey,
17807
17828
  deadline,
17829
+ leaseAcquisition,
17808
17830
  model: config.model ?? deps.mural.model ?? deps.dreamerModel,
17809
17831
  fallbackModels: config.fallbackModels,
17810
17832
  moduleRoute,
@@ -17828,6 +17850,7 @@ function createDreamTaskExecutor(deps) {
17828
17850
  holderId,
17829
17851
  leaseKey,
17830
17852
  deadline,
17853
+ leaseAcquisition,
17831
17854
  promotionThreshold: config.promotionThreshold ?? 3,
17832
17855
  model: config.model,
17833
17856
  fallbackModels: config.fallbackModels,
@@ -17847,6 +17870,7 @@ function createDreamTaskExecutor(deps) {
17847
17870
  holderId,
17848
17871
  leaseKey,
17849
17872
  deadline,
17873
+ leaseAcquisition,
17850
17874
  model: config.model,
17851
17875
  fallbackModels: config.fallbackModels,
17852
17876
  moduleRoute,
@@ -17872,6 +17896,7 @@ function createDreamTaskExecutor(deps) {
17872
17896
  holderId,
17873
17897
  leaseKey,
17874
17898
  deadline,
17899
+ leaseAcquisition,
17875
17900
  forceBroad: config.task === "verify-broad",
17876
17901
  model: config.model,
17877
17902
  fallbackModels: config.fallbackModels,
@@ -17905,40 +17930,15 @@ function createDreamTaskExecutor(deps) {
17905
17930
  }
17906
17931
  if (config.task === "classify-memories") {
17907
17932
  let moduleArgs;
17908
- const moduleTransport = deps.transformMode === "ts" ? undefined : deps.moduleClient;
17909
- if (moduleTransport?.authorityStatus) {
17910
- const contextStoreUuid = getContextStoreUuid(db);
17911
- if (!contextStoreUuid) {
17912
- throw new Error("Rust classify requires a context store identity");
17913
- }
17914
- let authority;
17915
- try {
17916
- authority = await moduleTransport.authorityStatus({
17917
- context_store_uuid: contextStoreUuid,
17918
- project: projectIdentity,
17919
- projectRoot: deps.sessionDirectory,
17920
- domain: "memories"
17921
- });
17922
- } catch (error) {
17923
- throw new ClassifyModuleFailureError("authority.status", error);
17924
- }
17925
- if (authority.authority?.state === "MODULE") {
17926
- const generation = authority.authority.generation;
17927
- if (typeof generation !== "number") {
17928
- throw new ClassifyModuleFailureError("authority.status", new Error("response omitted generation"));
17929
- }
17930
- const moduleClient = {
17931
- call: (callArgs) => moduleTransport.call(callArgs)
17932
- };
17933
- moduleArgs = {
17934
- moduleClient,
17935
- moduleSessionId: projectIdentity,
17936
- moduleProjectRoot: deps.sessionDirectory,
17937
- moduleContextStoreUuid: contextStoreUuid,
17938
- moduleAuthorityGeneration: generation,
17939
- moduleCommandId: `${startedAt}:${holderId}`
17940
- };
17941
- }
17933
+ if (moduleRoute) {
17934
+ moduleArgs = {
17935
+ moduleClient: moduleRoute.moduleClient,
17936
+ moduleSessionId: moduleRoute.moduleSessionId,
17937
+ moduleProjectRoot: moduleRoute.moduleProjectRoot,
17938
+ moduleContextStoreUuid: moduleRoute.moduleContextStoreUuid,
17939
+ moduleAuthorityGeneration: moduleRoute.moduleAuthorityGeneration,
17940
+ moduleCommandId: moduleRoute.moduleCommandId
17941
+ };
17942
17942
  }
17943
17943
  const result = await runClassify({
17944
17944
  db,
@@ -17949,6 +17949,7 @@ function createDreamTaskExecutor(deps) {
17949
17949
  holderId,
17950
17950
  leaseKey,
17951
17951
  deadline,
17952
+ leaseAcquisition,
17952
17953
  model: config.model,
17953
17954
  fallbackModels: config.fallbackModels,
17954
17955
  ...moduleArgs,
@@ -17972,6 +17973,7 @@ function createDreamTaskExecutor(deps) {
17972
17973
  holderId,
17973
17974
  leaseKey,
17974
17975
  deadline,
17976
+ leaseAcquisition,
17975
17977
  promotionThreshold: config.promotionThreshold ?? 2,
17976
17978
  ensureProjectRegistered: deps.ensureProjectRegistered
17977
17979
  });
@@ -17989,6 +17991,7 @@ function createDreamTaskExecutor(deps) {
17989
17991
  holderId,
17990
17992
  leaseKey,
17991
17993
  deadline,
17994
+ leaseAcquisition,
17992
17995
  model: config.model,
17993
17996
  fallbackModels: config.fallbackModels,
17994
17997
  language: config.language ?? deps.language,
@@ -18009,6 +18012,7 @@ function createDreamTaskExecutor(deps) {
18009
18012
  holderId,
18010
18013
  leaseKey,
18011
18014
  deadline,
18015
+ leaseAcquisition,
18012
18016
  model: config.model,
18013
18017
  fallbackModels: config.fallbackModels,
18014
18018
  retinaHandoff: deps.retinaHandoff
@@ -18154,7 +18158,7 @@ async function runRetrospectiveTask(config, ctx, helpers) {
18154
18158
  const heartbeat = startLeaseHeartbeat(db, holderId, leaseKey, () => {
18155
18159
  leaseLost = true;
18156
18160
  abortController.abort();
18157
- });
18161
+ }, ctx.leaseAcquisition);
18158
18162
  let childSessionId = null;
18159
18163
  try {
18160
18164
  const createResponse = await createChildSessionWithFence({
@@ -18344,7 +18348,7 @@ async function runAgenticTask(config, ctx, helpers) {
18344
18348
  const heartbeat = startLeaseHeartbeat(db, holderId, leaseKey, () => {
18345
18349
  leaseLost = true;
18346
18350
  abortController.abort();
18347
- });
18351
+ }, ctx.leaseAcquisition);
18348
18352
  let childSessionId = null;
18349
18353
  try {
18350
18354
  const createResponse = await createChildSessionWithFence({
@@ -18527,15 +18531,15 @@ async function runDomainGroup(deps, group, cb) {
18527
18531
  const { db, projectIdentity, executor } = deps;
18528
18532
  const leaseKey = leaseKeyFor(group[0].config.task, projectIdentity);
18529
18533
  const holderId = crypto.randomUUID();
18530
- let acquired = acquireLease(db, holderId, leaseKey);
18531
- if (!acquired && cb?.leaseWaitMs) {
18534
+ let acquisition = acquireLeaseWithAcquisition(db, holderId, leaseKey);
18535
+ if (!acquisition && cb?.leaseWaitMs) {
18532
18536
  const deadline = Date.now() + cb.leaseWaitMs;
18533
- while (!acquired && Date.now() < deadline) {
18537
+ while (!acquisition && Date.now() < deadline) {
18534
18538
  await new Promise((resolve3) => setTimeout(resolve3, LEASE_WAIT_POLL_MS));
18535
- acquired = acquireLease(db, holderId, leaseKey);
18539
+ acquisition = acquireLeaseWithAcquisition(db, holderId, leaseKey);
18536
18540
  }
18537
18541
  }
18538
- if (!acquired) {
18542
+ if (!acquisition) {
18539
18543
  log(`[dreamer] domain lease busy (${leaseKey}) — deferring ${group.length} task(s)`);
18540
18544
  for (const due of group)
18541
18545
  cb?.onBusy?.(due.config.task);
@@ -18543,7 +18547,7 @@ async function runDomainGroup(deps, group, cb) {
18543
18547
  }
18544
18548
  try {
18545
18549
  for (const due of [...group].sort((a, b) => compareTaskOrder(a.config.task, b.config.task))) {
18546
- if (!peekLeaseHolderAndExpiry(db, holderId, leaseKey)) {
18550
+ if (!leaseOwnershipMatches(db, holderId, acquisition.generation, leaseKey)) {
18547
18551
  log(`[dreamer] domain lease lost (${leaseKey}) — stopping remaining task(s)`);
18548
18552
  break;
18549
18553
  }
@@ -18562,7 +18566,13 @@ async function runDomainGroup(deps, group, cb) {
18562
18566
  }
18563
18567
  let outcome;
18564
18568
  try {
18565
- outcome = await executor(due.config, { db, projectIdentity, holderId, leaseKey });
18569
+ outcome = await executor(due.config, {
18570
+ db,
18571
+ projectIdentity,
18572
+ holderId,
18573
+ leaseKey,
18574
+ leaseAcquisition: acquisition
18575
+ });
18566
18576
  } catch (error) {
18567
18577
  outcome = { status: "failed", transient: true, error: String(error) };
18568
18578
  }
@@ -21087,14 +21097,15 @@ function createMagicContextCommandHandler(deps) {
21087
21097
  const isSessionUpgradeCommand = (command) => command === "ctx-session-upgrade";
21088
21098
  const isEmbedCommand = (command) => command === "ctx-embed";
21089
21099
  const rustMode = deps.transformMode === "rust" && deps.rustModeModuleClient;
21090
- const callRust = async (method, body) => {
21100
+ const callRust = async (method, body, timeoutMs) => {
21091
21101
  if (!rustMode)
21092
21102
  throw new Error("Rust module client is unavailable");
21093
21103
  return moduleResponseValue(await rustMode.call({
21094
21104
  sessionId: body.session_id,
21095
21105
  projectRoot: deps.projectRoot ?? process.cwd(),
21096
21106
  method,
21097
- body
21107
+ body,
21108
+ ...timeoutMs === undefined ? {} : { timeoutMs }
21098
21109
  }));
21099
21110
  };
21100
21111
  return {
@@ -21239,7 +21250,7 @@ Starting wrapup…`, {});
21239
21250
  session_id: sessionId,
21240
21251
  keep,
21241
21252
  command_id: rustCommandId("wrapup")
21242
- });
21253
+ }, MAX_WRAPUP_REQUEST_BUDGET_MS);
21243
21254
  result = formatRustOperationMessage("wrapup", value);
21244
21255
  } catch (error) {
21245
21256
  result = `## Magic Wrapup — Failed
@@ -21638,6 +21649,13 @@ var sessionLocks = new Map;
21638
21649
  var incrementalTimers = new Map;
21639
21650
  var pendingIncrementalKeys = new Set;
21640
21651
  var completedIncrementalKeys = new Set;
21652
+ function clearCompletedIncrementalKeys(sessionId) {
21653
+ const prefix = `${sessionId}\x00`;
21654
+ for (const key of completedIncrementalKeys) {
21655
+ if (key.startsWith(prefix))
21656
+ completedIncrementalKeys.delete(key);
21657
+ }
21658
+ }
21641
21659
  function defer(fn) {
21642
21660
  const immediate = globalThis.setImmediate;
21643
21661
  if (typeof immediate === "function") {
@@ -21752,14 +21770,12 @@ function scheduleIncrementalIndex(db, sessionId, messageId, messageSource) {
21752
21770
  function scheduleClearAndReindex(db, sessionId, readMessages) {
21753
21771
  reconciledSessions.delete(sessionId);
21754
21772
  reconciliationScheduledSessions.delete(sessionId);
21755
- const prefix = `${sessionId}\x00`;
21756
- for (const key of completedIncrementalKeys) {
21757
- if (key.startsWith(prefix))
21758
- completedIncrementalKeys.delete(key);
21759
- }
21773
+ clearCompletedIncrementalKeys(sessionId);
21760
21774
  scheduleAfterBootQuiet(() => {
21761
21775
  defer(() => {
21762
21776
  runWithSessionLock(sessionId, () => {
21777
+ reconciledSessions.delete(sessionId);
21778
+ clearCompletedIncrementalKeys(sessionId);
21763
21779
  clearIndexedMessages(db, sessionId);
21764
21780
  }).then(() => reconcileSessionIndex(db, sessionId, readMessages)).catch((error) => {
21765
21781
  reconciledSessions.delete(sessionId);
@@ -22789,16 +22805,8 @@ function reconcileCompactionMode(args) {
22789
22805
  notice: COMPACTION_ON_WRAPUP_SUGGESTION
22790
22806
  };
22791
22807
  }
22792
- if (stored === "off_notice_pending") {
22793
- const markerCleanup2 = cleanupOffMarkers(sessionId);
22794
- return {
22795
- ...NO_TRANSITION,
22796
- recordToWrite: markerCleanup2.verified ? "off" : "off_cleanup_pending",
22797
- notice: COMPACTION_OFF_FLIP_NOTICE,
22798
- markerCleanup: markerCleanup2
22799
- };
22800
- }
22801
- if (!args.compactionOff) {
22808
+ const completingOffNotice = stored === "off_notice_pending";
22809
+ if (!args.compactionOff && !completingOffNotice) {
22802
22810
  if (stored === null || resolveCompactionModeRecord(stored) === "on") {
22803
22811
  return stored === null ? { ...NO_TRANSITION, recordToWrite: "on" } : NO_TRANSITION;
22804
22812
  }
@@ -22834,6 +22842,9 @@ function reconcileCompactionMode(args) {
22834
22842
  markerCleanup: markerCleanup2
22835
22843
  };
22836
22844
  }
22845
+ if (!completingOffNotice) {
22846
+ setCompactionModeRecord(db, sessionId, "off_notice_pending");
22847
+ }
22837
22848
  let clearedSomething = false;
22838
22849
  const markerCleanup = cleanupOffMarkers(sessionId);
22839
22850
  if (markerCleanup.removedRows > 0)
@@ -22871,10 +22882,8 @@ function reconcileCompactionMode(args) {
22871
22882
  loggedUnverifiedMarkerCleanupRetry = true;
22872
22883
  sessionLog(sessionId, "compaction-off transition could not verify complete marker cleanup; durable cleanup retry will run on the next pass");
22873
22884
  }
22874
- const notice = clearedSomething ? COMPACTION_OFF_FLIP_NOTICE : null;
22875
- if (notice) {
22876
- setCompactionModeRecord(db, sessionId, "off_notice_pending");
22877
- } else if (!markerCleanup.verified) {
22885
+ const notice = clearedSomething || completingOffNotice ? COMPACTION_OFF_FLIP_NOTICE : null;
22886
+ if (!notice && !markerCleanup.verified) {
22878
22887
  setCompactionModeRecord(db, sessionId, "off_cleanup_pending");
22879
22888
  }
22880
22889
  return {
@@ -23703,6 +23712,22 @@ function partIsAnthropicThinking(part) {
23703
23712
  const type = part.type;
23704
23713
  return type === "thinking" || type === "reasoning" || type === "redacted_thinking";
23705
23714
  }
23715
+ function partEndsAnthropicAssistantRun(part) {
23716
+ if (!part || typeof part !== "object")
23717
+ return false;
23718
+ const value = part;
23719
+ if (value.type !== "tool" || value.providerExecuted === true || !value.state || typeof value.state !== "object") {
23720
+ return false;
23721
+ }
23722
+ const status = value.state.status;
23723
+ return status === "completed" || status === "error";
23724
+ }
23725
+ function partIsOpenCodeStepMetadata(part) {
23726
+ if (!part || typeof part !== "object")
23727
+ return false;
23728
+ const type = part.type;
23729
+ return type === "step-start" || type === "step-finish";
23730
+ }
23706
23731
  function validateAnthropicReasoningRuns(messages) {
23707
23732
  let index = 0;
23708
23733
  while (index < messages.length) {
@@ -23718,7 +23743,10 @@ function validateAnthropicReasoningRuns(messages) {
23718
23743
  thinkingBlocks += 1;
23719
23744
  if (thinkingBlocks > 1 || sawOtherContent)
23720
23745
  return false;
23721
- } else {
23746
+ } else if (partEndsAnthropicAssistantRun(part)) {
23747
+ thinkingBlocks = 0;
23748
+ sawOtherContent = false;
23749
+ } else if (!partIsOpenCodeStepMetadata(part)) {
23722
23750
  sawOtherContent = true;
23723
23751
  }
23724
23752
  }
@@ -24366,23 +24394,68 @@ function encodeOpenCodeMessagesToCk(messages) {
24366
24394
 
24367
24395
  // src/hooks/magic-context/module-state-sync.ts
24368
24396
  async function mirrorModuleCompartments(args) {
24369
- const row = args.db.prepare("SELECT COALESCE(MAX(sequence), -1) AS max_sequence FROM compartments WHERE session_id = ?").get(args.sessionId);
24370
- const afterSequence = row?.max_sequence ?? -1;
24371
- const published = await args.reader.getCompartmentsAfter(args.sessionId, afterSequence);
24372
- if (!Number.isFinite(published.max_sequence) || published.max_sequence <= afterSequence) {
24373
- return afterSequence;
24374
- }
24375
- const insert = args.db.prepare("INSERT INTO compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, p1, p2, p3, p4, importance, episode_type, legacy, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(session_id, sequence) DO NOTHING");
24376
- const now = Date.now();
24377
- args.db.transaction(() => {
24397
+ const authoritative = [];
24398
+ let afterSequence = -1;
24399
+ let maxSequence = null;
24400
+ for (;; ) {
24401
+ const published = await args.reader.getCompartmentsAfter(args.sessionId, afterSequence);
24402
+ if (!Number.isSafeInteger(published.max_sequence) || published.max_sequence < -1 || maxSequence !== null && published.max_sequence !== maxSequence) {
24403
+ throw new Error("module compartment mirror changed while its authoritative set was read");
24404
+ }
24405
+ maxSequence ??= published.max_sequence;
24406
+ let pageAdvanced = false;
24378
24407
  for (const compartment of published.compartments) {
24379
- if (!Number.isFinite(compartment.sequence) || compartment.sequence <= afterSequence || typeof compartment.start_message_id !== "string" || typeof compartment.end_message_id !== "string" || typeof compartment.title !== "string" || typeof compartment.content !== "string") {
24380
- continue;
24408
+ if (!Number.isSafeInteger(compartment.sequence) || compartment.sequence <= afterSequence || compartment.sequence > maxSequence || !Number.isSafeInteger(compartment.start_message) || !Number.isSafeInteger(compartment.end_message) || typeof compartment.start_message_id !== "string" || typeof compartment.end_message_id !== "string" || typeof compartment.title !== "string" || typeof compartment.content !== "string") {
24409
+ throw new Error("module compartment mirror returned an invalid authoritative row");
24381
24410
  }
24382
- insert.run(args.sessionId, compartment.sequence, compartment.start_message, compartment.end_message, compartment.start_message_id, compartment.end_message_id, compartment.title, compartment.content, compartment.p1 ?? null, compartment.p2 ?? null, compartment.p3 ?? null, compartment.p4 ?? null, compartment.importance ?? 50, compartment.episode_type ?? null, compartment.legacy ?? (compartment.p1 ? 0 : 1), compartment.created_at ?? now, getHarness());
24411
+ authoritative.push(compartment);
24412
+ afterSequence = compartment.sequence;
24413
+ pageAdvanced = true;
24414
+ }
24415
+ if (afterSequence >= maxSequence)
24416
+ break;
24417
+ if (!pageAdvanced) {
24418
+ throw new Error("module compartment mirror returned an incomplete authoritative set");
24419
+ }
24420
+ }
24421
+ const local = args.db.prepare("SELECT sequence, end_message FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(args.sessionId);
24422
+ let firstDifference = 0;
24423
+ while (firstDifference < local.length && firstDifference < authoritative.length && local[firstDifference]?.sequence === authoritative[firstDifference]?.sequence && local[firstDifference]?.end_message === authoritative[firstDifference]?.end_message) {
24424
+ firstDifference += 1;
24425
+ }
24426
+ const localDifference = local[firstDifference]?.sequence;
24427
+ const authoritativeDifference = authoritative[firstDifference]?.sequence;
24428
+ const divergentSequence = localDifference === undefined ? authoritativeDifference : authoritativeDifference === undefined ? localDifference : Math.min(localDifference, authoritativeDifference);
24429
+ const upsert = args.db.prepare(`INSERT INTO compartments
24430
+ (session_id, sequence, start_message, end_message, start_message_id, end_message_id,
24431
+ title, content, p1, p2, p3, p4, importance, episode_type, legacy, created_at, harness)
24432
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
24433
+ ON CONFLICT(session_id, sequence) DO UPDATE SET
24434
+ start_message = excluded.start_message,
24435
+ end_message = excluded.end_message,
24436
+ start_message_id = excluded.start_message_id,
24437
+ end_message_id = excluded.end_message_id,
24438
+ title = excluded.title,
24439
+ content = excluded.content,
24440
+ p1 = excluded.p1,
24441
+ p2 = excluded.p2,
24442
+ p3 = excluded.p3,
24443
+ p4 = excluded.p4,
24444
+ importance = excluded.importance,
24445
+ episode_type = excluded.episode_type,
24446
+ legacy = excluded.legacy,
24447
+ created_at = excluded.created_at,
24448
+ harness = excluded.harness`);
24449
+ const now = Date.now();
24450
+ args.db.transaction(() => {
24451
+ if (divergentSequence !== undefined) {
24452
+ args.db.prepare("DELETE FROM compartments WHERE session_id = ? AND sequence >= ?").run(args.sessionId, divergentSequence);
24453
+ }
24454
+ for (const compartment of authoritative) {
24455
+ upsert.run(args.sessionId, compartment.sequence, compartment.start_message, compartment.end_message, compartment.start_message_id, compartment.end_message_id, compartment.title, compartment.content, compartment.p1 ?? null, compartment.p2 ?? null, compartment.p3 ?? null, compartment.p4 ?? null, compartment.importance ?? 50, compartment.episode_type ?? null, compartment.legacy ?? (compartment.p1 ? 0 : 1), compartment.created_at ?? now, getHarness());
24383
24456
  }
24384
24457
  })();
24385
- return published.max_sequence;
24458
+ return maxSequence;
24386
24459
  }
24387
24460
  function stableHash(value) {
24388
24461
  return createHmac("sha256", "magic-context-shadow-watermark").update(value).digest("hex");
@@ -25002,7 +25075,7 @@ async function buildModuleStateSyncPayload(args) {
25002
25075
  workspace,
25003
25076
  nowMs: args.pass.nowMs
25004
25077
  }) : [];
25005
- const userProfile = includeUserProfile && profileChanged ? getActiveUserMemories(args.pass.db).map((memory) => memory.content) : [];
25078
+ const userProfile = includeUserProfile ? getActiveUserMemories(args.pass.db).map((memory) => memory.content) : [];
25006
25079
  const memoryMutations = memoryMutationsChanged && args.pass.projectPath ? getMemoryMutationsForRenderByProjects(args.pass.db, workspace.expandedIdentities, acked.memory_mutation_id, renderedMemoryIds).map((row) => ({
25007
25080
  id: row.id,
25008
25081
  project_path: row.projectPath,
@@ -25147,63 +25220,74 @@ function readAuthoritySeqMismatch(error) {
25147
25220
  async function syncModuleState(args) {
25148
25221
  let force = args.force;
25149
25222
  const adoption = args.options?.authoritySeqAdoption ?? { used: false };
25150
- let stateSyncDeltas = args.options?.stateSyncDeltas ?? args.client.getCachedStateSyncCapabilities?.()?.state_sync_deltas;
25151
- if (stateSyncDeltas === undefined && args.client.stateSyncCapabilities) {
25152
- try {
25153
- stateSyncDeltas = (await args.client.stateSyncCapabilities({
25154
- sessionId: args.pass.sessionId,
25155
- projectRoot: args.projectRoot
25156
- })).state_sync_deltas === true;
25157
- } catch {
25158
- stateSyncDeltas = false;
25159
- }
25160
- }
25161
- for (;; ) {
25162
- const payload = await buildModuleStateSyncPayload({
25163
- state: args.state,
25164
- pass: args.pass,
25165
- force,
25166
- options: { ...args.options, stateSyncDeltas }
25167
- });
25168
- if (payload === null)
25169
- return { status: "no_change" };
25170
- if (payload === "m0_mutation" || payload === "mismatch" || payload === "unresolved" || payload === "seed_budget") {
25171
- throw new Error(`module state sync ${payload}`);
25172
- }
25173
- try {
25174
- const batches = payload.wireBatches ?? [payload];
25175
- for (const batch of batches) {
25176
- const response = await args.client.call({
25223
+ const resolveStateSyncDeltas = async (afterGenerationChange = false) => {
25224
+ let capability = afterGenerationChange ? undefined : args.options?.stateSyncDeltas;
25225
+ capability ??= args.client.getCachedStateSyncCapabilities?.()?.state_sync_deltas;
25226
+ if (capability === undefined && args.client.stateSyncCapabilities) {
25227
+ try {
25228
+ capability = (await args.client.stateSyncCapabilities({
25177
25229
  sessionId: args.pass.sessionId,
25178
- projectRoot: args.projectRoot,
25179
- method: "state_sync",
25180
- body: {
25181
- method: batch.method,
25182
- ...batch.params
25230
+ projectRoot: args.projectRoot
25231
+ })).state_sync_deltas;
25232
+ } catch {
25233
+ capability = false;
25234
+ }
25235
+ }
25236
+ return capability === true;
25237
+ };
25238
+ let stateSyncDeltas = await resolveStateSyncDeltas();
25239
+ syncLoop:
25240
+ for (;; ) {
25241
+ const payload = await buildModuleStateSyncPayload({
25242
+ state: args.state,
25243
+ pass: args.pass,
25244
+ force,
25245
+ options: { ...args.options, stateSyncDeltas }
25246
+ });
25247
+ if (payload === null)
25248
+ return { status: "no_change" };
25249
+ if (payload === "m0_mutation" || payload === "mismatch" || payload === "unresolved" || payload === "seed_budget") {
25250
+ throw new Error(`module state sync ${payload}`);
25251
+ }
25252
+ try {
25253
+ const batches = payload.wireBatches ?? [payload];
25254
+ for (const batch of batches) {
25255
+ const response = await args.client.call({
25256
+ sessionId: args.pass.sessionId,
25257
+ projectRoot: args.projectRoot,
25258
+ method: "state_sync",
25259
+ body: {
25260
+ method: batch.method,
25261
+ ...batch.params
25262
+ },
25263
+ generationSensitive: stateSyncDeltas
25264
+ });
25265
+ if (isModuleTransportGenerationChangedResult(response)) {
25266
+ stateSyncDeltas = await resolveStateSyncDeltas(true);
25267
+ continue syncLoop;
25268
+ }
25269
+ if (args.options?.authority === true && responseMemoriesSkipped(response) && !args.state.authorityMemorySyncSkipLogged) {
25270
+ args.state.authorityMemorySyncSkipLogged = true;
25271
+ sessionLog(args.pass.sessionId, "authority state sync skipped module-owned memory sections");
25183
25272
  }
25184
- });
25185
- if (args.options?.authority === true && responseMemoriesSkipped(response) && !args.state.authorityMemorySyncSkipLogged) {
25186
- args.state.authorityMemorySyncSkipLogged = true;
25187
- sessionLog(args.pass.sessionId, "authority state sync skipped module-owned memory sections");
25188
25273
  }
25274
+ } catch (error) {
25275
+ if (isHistorianCompartmentSyncBusy(error)) {
25276
+ return { status: "retry_busy" };
25277
+ }
25278
+ const durableSeq = args.options?.authority ? readAuthoritySeqMismatch(error) : null;
25279
+ if (durableSeq === null || adoption.used)
25280
+ throw error;
25281
+ adoption.used = true;
25282
+ args.state.lastAckedSeq = durableSeq;
25283
+ args.state.lastAckedWatermarks = null;
25284
+ force = true;
25285
+ continue;
25189
25286
  }
25190
- } catch (error) {
25191
- if (isHistorianCompartmentSyncBusy(error)) {
25192
- return { status: "retry_busy" };
25193
- }
25194
- const durableSeq = args.options?.authority ? readAuthoritySeqMismatch(error) : null;
25195
- if (durableSeq === null || adoption.used)
25196
- throw error;
25197
- adoption.used = true;
25198
- args.state.lastAckedSeq = durableSeq;
25199
- args.state.lastAckedWatermarks = null;
25200
- force = true;
25201
- continue;
25287
+ args.state.lastAckedWatermarks = payload.watermarks;
25288
+ args.state.lastAckedSeq += 1;
25289
+ return { status: "acked", watermarks: payload.watermarks };
25202
25290
  }
25203
- args.state.lastAckedWatermarks = payload.watermarks;
25204
- args.state.lastAckedSeq += 1;
25205
- return { status: "acked", watermarks: payload.watermarks };
25206
- }
25207
25291
  }
25208
25292
 
25209
25293
  // src/hooks/magic-context/raw-fallback-context-limit.ts
@@ -27700,7 +27784,7 @@ var REASONING_IGNORED_PART_TYPES = new Set([
27700
27784
  "compaction"
27701
27785
  ]);
27702
27786
  var REASONING_PART_TYPES = new Set(["reasoning", "thinking", "redacted_thinking"]);
27703
- function stripReasoningFromMergedAssistants(messages, providerID) {
27787
+ function stripReasoningFromMergedAssistants(messages, providerID, options) {
27704
27788
  if (providerID !== "anthropic")
27705
27789
  return 0;
27706
27790
  let stripped = 0;
@@ -27716,6 +27800,10 @@ function stripReasoningFromMergedAssistants(messages, providerID) {
27716
27800
  const firstInRun = prevRole !== "assistant";
27717
27801
  if (firstInRun)
27718
27802
  keptReasoningInRun = false;
27803
+ if (message === options?.mutationExemptMessage) {
27804
+ prevRole = role;
27805
+ continue;
27806
+ }
27719
27807
  let keepIndex = -1;
27720
27808
  if (firstInRun && !keptReasoningInRun) {
27721
27809
  for (let i = 0;i < message.parts.length; i++) {
@@ -28810,11 +28898,21 @@ function finalizeMessageRepresentation(messages, resolvedProviderID, options) {
28810
28898
  clearedParts = stripClearedReasoning(targetedMessages);
28811
28899
  }
28812
28900
  }
28813
- const mergedReasoningParts = stripReasoningFromMergedAssistants(messages, resolvedProviderID);
28901
+ const mergedReasoningParts = stripReasoningFromMergedAssistants(messages, resolvedProviderID, {
28902
+ mutationExemptMessage: options?.reasoningMutationExemptMessage
28903
+ });
28814
28904
  return { clearedParts, mergedReasoningParts };
28815
28905
  }
28816
28906
  async function runPostTransformPhase(args) {
28817
28907
  const compactionOff = args.compactionOff === true;
28908
+ let reasoningMutationExemptMessage;
28909
+ for (let index = args.messages.length - 1;index >= 0; index -= 1) {
28910
+ const message = args.messages[index];
28911
+ if (message.info.role !== "assistant")
28912
+ continue;
28913
+ reasoningMutationExemptMessage = message;
28914
+ break;
28915
+ }
28818
28916
  const pendingMaterializationAtPassStart = args.pendingMaterializationSessions.has(args.sessionId);
28819
28917
  const deferredMaterializationAtPassStart = args.deferredMaterializationSessions.has(args.sessionId);
28820
28918
  const isExplicitFlush = pendingMaterializationAtPassStart;
@@ -28833,6 +28931,10 @@ async function runPostTransformPhase(args) {
28833
28931
  state: args.sessionMeta,
28834
28932
  projectPath: args.m0M1.projectPath,
28835
28933
  projectDirectory: args.m0M1.projectDirectory,
28934
+ injectDocs: args.m0M1.injectDocs,
28935
+ muralEnabled: args.m0M1.muralEnabled,
28936
+ memoryInjectionBudgetTokens: args.m0M1.memoryInjectionBudgetTokens,
28937
+ historyBudgetTokens: args.m0M1.historyBudgetTokens,
28836
28938
  hardSignals: args.m0M1.hardSignals
28837
28939
  }).value : false;
28838
28940
  const bypassCompartmentGate = forceMaterialization || m0HardFoldThisPass;
@@ -29361,7 +29463,8 @@ async function runPostTransformPhase(args) {
29361
29463
  const tFinalRepresentation = performance.now();
29362
29464
  const finalRepresentation = finalizeMessageRepresentation(args.messages, args.resolvedProviderID, {
29363
29465
  prependedMessageCount,
29364
- reasoningMutatedMessages
29466
+ reasoningMutatedMessages,
29467
+ reasoningMutationExemptMessage
29365
29468
  });
29366
29469
  sessionLog(args.sessionId, `final representation: clearedParts=${finalRepresentation.clearedParts} mergedReasoningParts=${finalRepresentation.mergedReasoningParts}`);
29367
29470
  logTransformTiming(args.sessionId, "finalizeMessageRepresentation", tFinalRepresentation, `clearedParts=${finalRepresentation.clearedParts} mergedReasoningParts=${finalRepresentation.mergedReasoningParts}`);
@@ -29403,6 +29506,15 @@ var RUST_PARK_RETRY_INTERVAL = 5;
29403
29506
  var RUST_EMERGENCY_WALL_PCT = 95;
29404
29507
  var RUST_PARK_PROBE_PRESSURE_BYPASS_PCT = 90;
29405
29508
  var RUST_SEND_TIMEOUT_MS = 15000;
29509
+ var RAW_FALLBACK_BYTES_PER_CONTEXT_TOKEN = 4;
29510
+ function rawFallbackSerializedBytes(messages) {
29511
+ try {
29512
+ const serialized = JSON.stringify(messages);
29513
+ return typeof serialized === "string" ? Buffer.byteLength(serialized) : null;
29514
+ } catch {
29515
+ return null;
29516
+ }
29517
+ }
29406
29518
  function isRecord3(value) {
29407
29519
  return value !== null && typeof value === "object";
29408
29520
  }
@@ -29635,6 +29747,19 @@ function responseValue(response) {
29635
29747
  return response;
29636
29748
  throw new Error("module transform returned a non-object response");
29637
29749
  }
29750
+ function mirrorRustRenderedMemoryIds(args) {
29751
+ if (!("rendered_memory_ids" in args.response))
29752
+ return;
29753
+ const rawIds = args.response.rendered_memory_ids;
29754
+ if (!Array.isArray(rawIds) || rawIds.some((id) => typeof id !== "number" || !Number.isSafeInteger(id) || id <= 0)) {
29755
+ throw new Error("module transform returned an invalid rendered-memory manifest");
29756
+ }
29757
+ const serialized = JSON.stringify(rawIds);
29758
+ args.db.prepare(`UPDATE session_meta
29759
+ SET memory_block_ids = ?, memory_block_count = ?
29760
+ WHERE session_id = ?
29761
+ AND (COALESCE(memory_block_ids, '') <> ? OR COALESCE(memory_block_count, -1) <> ?)`).run(serialized, rawIds.length, args.sessionId, serialized, rawIds.length);
29762
+ }
29638
29763
  function noteDeliveryPassIds(response) {
29639
29764
  if (!Array.isArray(response.note_deliveries))
29640
29765
  return [];
@@ -29983,8 +30108,10 @@ function buildTransformBody(args) {
29983
30108
  model_key: args.modelKey,
29984
30109
  provider_id: args.providerId,
29985
30110
  tool_present: args.passInputs.tool_present === true,
30111
+ ...typeof args.passInputs.todo_tool_present === "boolean" ? { todo_tool_present: args.passInputs.todo_tool_present } : {},
29986
30112
  prompt_surface_preset: args.passInputs.prompt_surface_preset ?? "full",
29987
30113
  prompt_surface_model_key: args.passInputs.prompt_surface_model_key,
30114
+ prompt_surface_config_identity: args.passInputs.prompt_surface_config_identity,
29988
30115
  prompt_surface_tool_descriptions: args.passInputs.prompt_surface_tool_descriptions ?? {},
29989
30116
  effective_execute_threshold: args.passInputs.effective_execute_threshold,
29990
30117
  history_budget_tokens: args.passInputs.history_budget_tokens,
@@ -30007,6 +30134,7 @@ function createRustModeTransform(deps, options) {
30007
30134
  const states = new Map;
30008
30135
  const wireCaches = new Map;
30009
30136
  const scheduleLkgCapture = options.scheduleLkgCapture ?? ((capture) => setImmediate(capture));
30137
+ const rawFallbackEstimator = options.rawFallbackEstimatorForTests ?? estimateFinalWireInputTokens;
30010
30138
  const timeoutMs = Math.max(1, options.moduleTimeoutMs ?? RUST_SEND_TIMEOUT_MS);
30011
30139
  const logStage = (sessionId, stage, startedAt, timings, extra) => {
30012
30140
  const elapsed = Math.max(0, performance.now() - startedAt);
@@ -30229,23 +30357,22 @@ function createRustModeTransform(deps, options) {
30229
30357
  const serveRawFallback = (cause) => {
30230
30358
  const contextLimit = resolvedContextLimit ?? (overflowState && overflowState.detectedContextLimit > 0 ? overflowState.detectedContextLimit : undefined);
30231
30359
  if (contextLimit !== undefined) {
30360
+ let estimate;
30232
30361
  try {
30233
- const estimate = estimateFinalWireInputTokens({
30362
+ estimate = rawFallbackEstimator({
30234
30363
  messages,
30235
30364
  systemPromptTokens: sessionMeta.systemPromptTokens,
30236
30365
  providerID: model?.providerID,
30237
30366
  modelID: model?.modelID,
30238
30367
  agentName: deps.getNotificationParams?.(sessionId)?.agent
30239
30368
  });
30240
- if (estimate.tokens > contextLimit) {
30241
- sessionLog(sessionId, `raw_fallback_over_context_limit estimated=${estimate.tokens} limit=${contextLimit}`);
30242
- throw new RawFallbackContextLimitError(estimate.tokens, contextLimit, {
30243
- cause
30244
- });
30245
- }
30246
- } catch (error) {
30247
- if (error instanceof RawFallbackContextLimitError)
30248
- throw error;
30369
+ } catch {}
30370
+ const rawBytes = rawFallbackSerializedBytes(messages);
30371
+ const proxyTokens = rawBytes === null ? contextLimit + 1 : Math.ceil(rawBytes / RAW_FALLBACK_BYTES_PER_CONTEXT_TOKEN);
30372
+ const refusalTokens = Math.max(estimate?.tokens ?? 0, proxyTokens);
30373
+ if (refusalTokens > contextLimit) {
30374
+ sessionLog(sessionId, `raw_fallback_over_context_limit estimated=${estimate?.tokens ?? "unavailable"} ` + `proxy_bytes=${rawBytes ?? "unavailable"} proxy_tokens=${proxyTokens} limit=${contextLimit}`);
30375
+ throw new RawFallbackContextLimitError(refusalTokens, contextLimit, { cause });
30249
30376
  }
30250
30377
  }
30251
30378
  replaceMessagesInPlace(output, messages);
@@ -30319,7 +30446,9 @@ function createRustModeTransform(deps, options) {
30319
30446
  }
30320
30447
  const reduceAvailability = resolveCtxReduceAvailability(sessionId);
30321
30448
  resolveTodowriteAvailabilityFromMessages(sessionId, messages);
30449
+ const todoAvailability = resolveTodowriteAvailability(sessionId);
30322
30450
  const toolPresent = reduceAvailability.frozen && reduceAvailability.callable;
30451
+ const todoToolPresent = todoAvailability.frozen ? todoAvailability.callable : undefined;
30323
30452
  try {
30324
30453
  if (preflightError)
30325
30454
  throw preflightError;
@@ -30353,8 +30482,10 @@ function createRustModeTransform(deps, options) {
30353
30482
  system_prompt_hash: sessionMeta.systemPromptHash ?? "",
30354
30483
  upgrade_state: readUpgradeState(deps.db, sessionId),
30355
30484
  tool_present: toolPresent,
30485
+ todo_tool_present: todoToolPresent,
30356
30486
  prompt_surface_preset: promptSurface.preset,
30357
30487
  prompt_surface_model_key: modelKey,
30488
+ prompt_surface_config_identity: promptSurfaceConfigIdentity(deps.promptSurface),
30358
30489
  prompt_surface_tool_descriptions: deps.promptSurface?.tool_descriptions ?? {},
30359
30490
  protected_tags: deps.protectedTags ?? DEFAULT_PROTECTED_TAGS,
30360
30491
  temporal_awareness: deps.experimentalTemporalAwareness === true,
@@ -30755,6 +30886,9 @@ function createRustModeTransform(deps, options) {
30755
30886
  }
30756
30887
  logStage(sessionId, "apply", applyStartedAt, timings);
30757
30888
  const lkgSnapshotStartedAt = performance.now();
30889
+ if (cacheBustingPass) {
30890
+ dropSlot(sessionId, "lkg_cache_bust_pending_capture");
30891
+ }
30758
30892
  const capturePlan = prepareRustCapture(state, sessionId, messages, pendingWireCache.rawContentSnapshots, response, rowVersion);
30759
30893
  let captureMode = "async";
30760
30894
  const captureFailed = (mode, error) => {
@@ -30804,6 +30938,11 @@ function createRustModeTransform(deps, options) {
30804
30938
  }
30805
30939
  throw error;
30806
30940
  }
30941
+ try {
30942
+ mirrorRustRenderedMemoryIds({ db: deps.db, sessionId, response });
30943
+ } catch (error) {
30944
+ sessionLog(sessionId, "rust rendered-memory mirror write failed (ignored):", error);
30945
+ }
30807
30946
  if (deliveryPassIds.length > 0) {
30808
30947
  try {
30809
30948
  await sendNoteDeliveryDisposition("transform.ack");
@@ -31360,16 +31499,6 @@ function createTransform(deps) {
31360
31499
  sessionLog(sessionId, "transform skipped (internal magic-context child session)");
31361
31500
  return;
31362
31501
  }
31363
- if (deps.transformMode === "rust") {
31364
- if (!rustModeTransform) {
31365
- sessionLog(sessionId, "rust transform unavailable; using raw passthrough");
31366
- return;
31367
- }
31368
- await rustModeTransform.run(sessionId, messages, output, sessionMeta);
31369
- return;
31370
- }
31371
- const reducedMode = sessionMeta.isSubagent;
31372
- const fullFeatureMode = !reducedMode;
31373
31502
  const compactionOff = deps.compactionOff === true;
31374
31503
  try {
31375
31504
  const transition = reconcileCompactionMode({
@@ -31411,6 +31540,18 @@ function createTransform(deps) {
31411
31540
  passOutcome.record("compaction-mode-transition-failure");
31412
31541
  sessionLog(sessionId, "compaction mode transition failed (retrying next pass):", error);
31413
31542
  }
31543
+ if (deps.transformMode === "rust") {
31544
+ if (compactionOff)
31545
+ return;
31546
+ if (!rustModeTransform) {
31547
+ sessionLog(sessionId, "rust transform unavailable; using raw passthrough");
31548
+ return;
31549
+ }
31550
+ await rustModeTransform.run(sessionId, messages, output, sessionMeta);
31551
+ return;
31552
+ }
31553
+ const reducedMode = sessionMeta.isSubagent;
31554
+ const fullFeatureMode = !reducedMode;
31414
31555
  const ctxReduceAvailability = resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
31415
31556
  const ctxReduceCallable = ctxReduceAvailability.callable;
31416
31557
  const todowriteAvailability = resolveTodowriteAvailabilityFromMessages(sessionId, messages);
@@ -33488,37 +33629,49 @@ function createSystemPromptHashHandler(deps) {
33488
33629
  }
33489
33630
  const isCacheBusting = deps.systemPromptRefreshSessions.has(sessionId);
33490
33631
  const DATE_PATTERN = /Today's date: .+/;
33632
+ const DATE_PATTERN_ALL = /Today's date: .+/g;
33633
+ const liveSystemContent = output.system.join(`
33634
+ `);
33635
+ if (liveSystemContent.length === 0)
33636
+ return;
33637
+ const previousHash = sessionMetaEarly?.systemPromptHash ?? "";
33638
+ const hasPersistedHash = previousHash !== "" && previousHash !== "0";
33639
+ const dateElementIndexes = [];
33640
+ let currentDate;
33491
33641
  for (let i = 0;i < output.system.length; i++) {
33492
33642
  const match = output.system[i].match(DATE_PATTERN);
33493
33643
  if (!match)
33494
33644
  continue;
33495
- const currentDate = match[0];
33496
- const stickyDate = stickyDateBySession.get(sessionId);
33497
- if (!stickyDate) {
33645
+ dateElementIndexes.push(i);
33646
+ currentDate ??= match[0];
33647
+ }
33648
+ const stickyDate = stickyDateBySession.get(sessionId);
33649
+ const stableCandidate = currentDate && stickyDate && currentDate !== stickyDate ? liveSystemContent.replace(DATE_PATTERN_ALL, stickyDate) : liveSystemContent;
33650
+ const stableCandidateHash = createHash14("md5").update(promptSurfaceHashMaterial(stableCandidate, promptSurface.preset)).digest("hex");
33651
+ const contentOrPresetChanged = hasPersistedHash && stableCandidateHash !== previousHash;
33652
+ const dateMayAdvance = isCacheBusting || contentOrPresetChanged;
33653
+ if (currentDate && !stickyDate) {
33654
+ stickyDateBySession.set(sessionId, currentDate);
33655
+ } else if (currentDate && stickyDate && currentDate !== stickyDate) {
33656
+ if (dateMayAdvance) {
33498
33657
  stickyDateBySession.set(sessionId, currentDate);
33499
- } else if (currentDate !== stickyDate) {
33500
- if (isCacheBusting) {
33501
- stickyDateBySession.set(sessionId, currentDate);
33502
- sessionLog(sessionId, `system prompt date updated: ${stickyDate} → ${currentDate} (cache-busting pass)`);
33503
- } else {
33504
- output.system[i] = output.system[i].replace(DATE_PATTERN, stickyDate);
33505
- sessionLog(sessionId, `system prompt date frozen: real=${currentDate}, using=${stickyDate} (defer pass)`);
33658
+ sessionLog(sessionId, `system prompt date updated: ${stickyDate} → ${currentDate} (cache-busting pass)`);
33659
+ } else if (dateElementIndexes.length > 0) {
33660
+ for (const index of dateElementIndexes) {
33661
+ output.system[index] = output.system[index].replace(DATE_PATTERN_ALL, stickyDate);
33506
33662
  }
33663
+ sessionLog(sessionId, `system prompt date frozen: real=${currentDate}, using=${stickyDate} (defer pass)`);
33507
33664
  }
33508
- break;
33509
33665
  }
33510
33666
  const systemContent = output.system.join(`
33511
33667
  `);
33512
- if (systemContent.length === 0)
33513
- return;
33514
- if (!availability.frozen)
33668
+ if (!availability.frozen || !modelKey)
33515
33669
  return;
33516
33670
  const currentHash = createHash14("md5").update(promptSurfaceHashMaterial(systemContent, promptSurface.preset)).digest("hex");
33517
33671
  if (!sessionMetaEarly) {
33518
33672
  return;
33519
33673
  }
33520
33674
  const sessionMeta = sessionMetaEarly;
33521
- const previousHash = sessionMeta.systemPromptHash;
33522
33675
  if (previousHash !== "" && previousHash !== "0" && previousHash !== currentHash) {
33523
33676
  sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${systemContent.length}), triggering flush`);
33524
33677
  deps.historyRefreshSessions.add(sessionId);
@@ -33691,6 +33844,37 @@ function notifyMagicContextDisabled(client, reason) {
33691
33844
  log("[magic-context] failed to show disabled toast:", error);
33692
33845
  });
33693
33846
  }
33847
+ function moduleNoteRowId(response, depth = 0) {
33848
+ if (depth > 4 || response === null || response === undefined)
33849
+ return null;
33850
+ if (typeof response === "string") {
33851
+ const match = response.match(/\b(?:smart\s+)?note\s+#(\d+)/i);
33852
+ return match ? Number(match[1]) : null;
33853
+ }
33854
+ if (Array.isArray(response)) {
33855
+ for (const item of response) {
33856
+ const id = moduleNoteRowId(item, depth + 1);
33857
+ if (id !== null)
33858
+ return id;
33859
+ }
33860
+ return null;
33861
+ }
33862
+ if (typeof response !== "object")
33863
+ return null;
33864
+ const record = response;
33865
+ return moduleNoteRowId(record.result, depth + 1) ?? moduleNoteRowId(record.content, depth + 1) ?? moduleNoteRowId(record.text, depth + 1);
33866
+ }
33867
+ function moduleNoteResponseIsError(response, depth = 0) {
33868
+ if (depth > 4 || response === null || typeof response !== "object")
33869
+ return false;
33870
+ if (Array.isArray(response)) {
33871
+ return response.some((item) => moduleNoteResponseIsError(item, depth + 1));
33872
+ }
33873
+ const record = response;
33874
+ if (record.isError === true || record.ok === false || record.error !== undefined)
33875
+ return true;
33876
+ return moduleNoteResponseIsError(record.result, depth + 1);
33877
+ }
33694
33878
  function createMagicContextHook(deps) {
33695
33879
  const contextUsageMap = new Map;
33696
33880
  let db;
@@ -33965,6 +34149,7 @@ function createMagicContextHook(deps) {
33965
34149
  autoEmbedAttemptedBySession.add(sessionId);
33966
34150
  const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
33967
34151
  (async () => {
34152
+ let completedDrainWithWork = false;
33968
34153
  try {
33969
34154
  await new Promise((resolve3) => setTimeout(resolve3, 0));
33970
34155
  await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
@@ -33986,6 +34171,8 @@ function createMagicContextHook(deps) {
33986
34171
  });
33987
34172
  }
33988
34173
  const summary = await executeEmbedHistory(sessionId);
34174
+ const completedCoverage = getEmbeddingCoverageStatus(db, sessionProjectIdentity, sessionId);
34175
+ completedDrainWithWork = completedCoverage.session.total - completedCoverage.session.embedded <= 0;
33989
34176
  if (!isTuiConnected(sessionId)) {
33990
34177
  await sendIgnoredMessage(deps.client, sessionId, summary, {
33991
34178
  ...notifyParams
@@ -33993,6 +34180,9 @@ function createMagicContextHook(deps) {
33993
34180
  }
33994
34181
  } catch (error) {
33995
34182
  log("[magic-context] auto-embed drain failed:", error);
34183
+ } finally {
34184
+ if (!completedDrainWithWork)
34185
+ autoEmbedAttemptedBySession.delete(sessionId);
33996
34186
  }
33997
34187
  })();
33998
34188
  };
@@ -34082,6 +34272,10 @@ function createMagicContextHook(deps) {
34082
34272
  action,
34083
34273
  content,
34084
34274
  surfaceCondition,
34275
+ compiledProvider,
34276
+ compiledConfig,
34277
+ compiledAt,
34278
+ compileStatus,
34085
34279
  filter,
34086
34280
  limit,
34087
34281
  offset,
@@ -34107,6 +34301,22 @@ function createMagicContextHook(deps) {
34107
34301
  }
34108
34302
  });
34109
34303
  await syncModuleNotes();
34304
+ if (compileStatus && !moduleNoteResponseIsError(response)) {
34305
+ const moduleRowId = action === "write" ? moduleNoteRowId(response) : noteId ?? null;
34306
+ if (moduleRowId === null || !applyMirroredNoteCompileFields({
34307
+ db,
34308
+ moduleProject: memoryProject,
34309
+ moduleRowId,
34310
+ fields: {
34311
+ compiledProvider: compiledProvider ?? null,
34312
+ compiledConfig: compiledConfig ?? null,
34313
+ compiledAt: compiledAt ?? null,
34314
+ compileStatus
34315
+ }
34316
+ })) {
34317
+ throw new Error("Rust note was written but its host compilation metadata could not be mirrored");
34318
+ }
34319
+ }
34110
34320
  return response;
34111
34321
  },
34112
34322
  memory: async ({
@@ -35417,7 +35627,7 @@ function registerRpcHandlers(rpcServer, args) {
35417
35627
  const db = getDb();
35418
35628
  if (!db)
35419
35629
  return { ok: false, error: "db unavailable" };
35420
- const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-7wbbvf87.js");
35630
+ const { runManagedRecomp: runManagedRecomp2 } = await import("./recomp-orchestrator-a0g9b52q.js");
35421
35631
  const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-bgtf4853.js");
35422
35632
  log(`[rpc] recomp requested for session ${sessionId}`);
35423
35633
  const ctx = await buildManagedCtx(db);
@@ -35433,7 +35643,7 @@ function registerRpcHandlers(rpcServer, args) {
35433
35643
  const db = getDb();
35434
35644
  if (!db)
35435
35645
  return { ok: false, error: "db unavailable" };
35436
- const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-7wbbvf87.js");
35646
+ const { runManagedUpgrade: runManagedUpgrade2 } = await import("./recomp-orchestrator-a0g9b52q.js");
35437
35647
  const { sendIgnoredMessage: sendIgnoredMessage2 } = await import("./send-session-notification-bgtf4853.js");
35438
35648
  log(`[rpc] session-upgrade requested for session ${sessionId}`);
35439
35649
  const ctx = await buildManagedCtx(db);
@@ -35450,7 +35660,7 @@ function registerRpcHandlers(rpcServer, args) {
35450
35660
  if (!db)
35451
35661
  return { ok: false, error: "db unavailable" };
35452
35662
  try {
35453
- const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-kh5egr11.js");
35663
+ const { updateSessionMeta: updateSessionMeta2 } = await import("./storage-meta-session-df9tstzr.js");
35454
35664
  updateSessionMeta2(db, sessionId, { upgradeRemindedAt: Date.now() });
35455
35665
  return { ok: true };
35456
35666
  } catch (error) {
@@ -36428,6 +36638,16 @@ class ProviderError extends Error {
36428
36638
 
36429
36639
  // ../retina-local-fs/src/path-fence.ts
36430
36640
  async function resolveAndFenceProviderPath(configuredPath, options) {
36641
+ const { home, dataDirectory } = await resolveFenceRoots(options);
36642
+ const expanded = configuredPath.startsWith("~/") ? join6(home, configuredPath.slice(2)) : configuredPath === "~" ? home : configuredPath;
36643
+ const absolute = isAbsolute3(expanded) ? resolve3(expanded) : resolve3(options.cwd ?? process.cwd(), expanded);
36644
+ const canonical = await canonicalPath(absolute, options.allowMissing);
36645
+ if (isFencedPath(canonical, home, dataDirectory)) {
36646
+ throw new ProviderError("fenced_path", `Refusing fenced path: ${canonical}`);
36647
+ }
36648
+ return canonical;
36649
+ }
36650
+ async function resolveFenceRoots(options) {
36431
36651
  const configuredHomePath = resolve3(options.homeDirectory ?? process.env.HOME ?? homedir4());
36432
36652
  let home;
36433
36653
  try {
@@ -36435,13 +36655,9 @@ async function resolveAndFenceProviderPath(configuredPath, options) {
36435
36655
  } catch (error) {
36436
36656
  throw fsError(configuredHomePath, error);
36437
36657
  }
36438
- const expanded = configuredPath.startsWith("~/") ? join6(home, configuredPath.slice(2)) : configuredPath === "~" ? home : configuredPath;
36439
- const absolute = isAbsolute3(expanded) ? resolve3(expanded) : resolve3(options.cwd ?? process.cwd(), expanded);
36440
- const canonical = await canonicalPath(absolute, options.allowMissing);
36441
- if (isFencedPath(canonical, home)) {
36442
- throw new ProviderError("fenced_path", `Refusing fenced path: ${canonical}`);
36443
- }
36444
- return canonical;
36658
+ const configuredDataDirectory = resolve3(options.dataDirectory ?? process.env.XDG_DATA_HOME ?? join6(home, ".local", "share"));
36659
+ const dataDirectory = await canonicalPath(configuredDataDirectory, true);
36660
+ return { home, dataDirectory };
36445
36661
  }
36446
36662
  async function canonicalPath(path6, allowMissing) {
36447
36663
  try {
@@ -36481,9 +36697,8 @@ async function canonicalPath(path6, allowMissing) {
36481
36697
  }
36482
36698
  }
36483
36699
  }
36484
- function isFencedPath(canonicalPath2, homeDirectory) {
36485
- const home = resolve3(homeDirectory);
36486
- const cortexkitRoot = join6(home, ".local", "share", "cortexkit");
36700
+ function isFencedPath(canonicalPath2, homeDirectory, dataDirectory = process.env.XDG_DATA_HOME ?? join6(resolve3(homeDirectory), ".local", "share")) {
36701
+ const cortexkitRoot = join6(resolve3(dataDirectory), "cortexkit");
36487
36702
  const relativeToCortexkit = relative(cortexkitRoot, canonicalPath2);
36488
36703
  const insideCortexkit = relativeToCortexkit !== "" && relativeToCortexkit !== ".." && !relativeToCortexkit.startsWith(`..${sep}`) && !isAbsolute3(relativeToCortexkit);
36489
36704
  const parts = insideCortexkit ? relativeToCortexkit.split(sep) : [];
@@ -36492,10 +36707,11 @@ function isFencedPath(canonicalPath2, homeDirectory) {
36492
36707
  const catalogDirectoryCarveIn = pathParts.includes("catalog");
36493
36708
  const moduleBinCarveIn = parts.length >= 2 && parts[1] === "bin";
36494
36709
  const catalogJsonCarveIn = name.endsWith(".json") && name.includes("catalog");
36495
- if (catalogDirectoryCarveIn || moduleBinCarveIn || catalogJsonCarveIn) {
36710
+ const rootWithoutCarveIns = insideCortexkit && (parts[0] === "run" || parts[0] === "magic-context");
36711
+ if (!rootWithoutCarveIns && (catalogDirectoryCarveIn || moduleBinCarveIn || catalogJsonCarveIn)) {
36496
36712
  return false;
36497
36713
  }
36498
- const inFencedRoot = insideCortexkit && ["plexus", "claustrum", "staging"].includes(parts[0] ?? "");
36714
+ const inFencedRoot = insideCortexkit && ["plexus", "claustrum", "staging", "run", "magic-context"].includes(parts[0] ?? "");
36499
36715
  const fencedBasename = name.includes("binding-key") || name.endsWith(".handle");
36500
36716
  const plexusStore = insideCortexkit && parts[0] === "plexus" && name.startsWith("store.db");
36501
36717
  return inFencedRoot || fencedBasename || plexusStore;
@@ -36645,6 +36861,9 @@ function invalid(message) {
36645
36861
  var RETINA_LOCAL_FS_PROVIDER = "local-fs";
36646
36862
  var VALUE = String.raw`(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\S+)`;
36647
36863
  async function compileSurfaceCondition(surfaceCondition, options) {
36864
+ const plainReason = unsafeGrammarReason(surfaceCondition);
36865
+ if (plainReason)
36866
+ return { status: "plain", reason: plainReason };
36648
36867
  const parsed = parseCondition(surfaceCondition, options.projectPath);
36649
36868
  if (parsed === null)
36650
36869
  return { status: "plain" };
@@ -36726,23 +36945,27 @@ function parseCondition(surfaceCondition, projectPath) {
36726
36945
  return predicates.every((predicate) => predicate !== null) ? predicates : null;
36727
36946
  }
36728
36947
  function parseAtomicCondition(text, projectPath) {
36729
- const fileContains = text.match(new RegExp(`^(?:when\\s+)?file\\s+(${VALUE})\\s+(no longer contains|contains)\\s+(.+)$`, "i"));
36948
+ const fileContains = text.match(new RegExp(`^(?:when\\s+)?file\\s+(${VALUE})\\s+(no longer contains|contains)\\s+(${VALUE})$`, "i"));
36730
36949
  if (fileContains) {
36950
+ const path6 = unquote(fileContains[1]);
36731
36951
  const needle = unquote(fileContains[3].trim());
36732
- if (needle === null)
36952
+ if (path6 === null || needle === null)
36733
36953
  return null;
36734
36954
  return {
36735
36955
  kind: "file_contains",
36736
- path: unquote(fileContains[1]) ?? fileContains[1],
36956
+ path: path6,
36737
36957
  needle,
36738
36958
  ...fileContains[2].toLowerCase() === "no longer contains" ? { absent: true } : {}
36739
36959
  };
36740
36960
  }
36741
36961
  const commit = text.match(new RegExp(`^(?:when\\s+)?(?:repo(?:sitory)?\\s+)?(${VALUE})\\s+has\\s+a\\s+commit\\s+(?:after|newer than)\\s+([0-9a-f]{7,64})$`, "i"));
36742
36962
  if (commit) {
36963
+ const repoPath = unquote(commit[1]);
36964
+ if (repoPath === null)
36965
+ return null;
36743
36966
  return {
36744
36967
  kind: "git_commit_after",
36745
- repo_path: unquote(commit[1]) ?? commit[1],
36968
+ repo_path: repoPath,
36746
36969
  sha: commit[2]
36747
36970
  };
36748
36971
  }
@@ -36762,16 +36985,22 @@ function parseAtomicCondition(text, projectPath) {
36762
36985
  }
36763
36986
  const mtime = text.match(new RegExp(`^(?:when\\s+)?(?:file\\s+)?(${VALUE})\\s+(changes|is rebuilt|mtime moves)$`, "i"));
36764
36987
  if (mtime) {
36988
+ const path6 = unquote(mtime[1]);
36989
+ if (path6 === null)
36990
+ return null;
36765
36991
  return {
36766
36992
  kind: "mtime_after",
36767
- path: unquote(mtime[1]) ?? mtime[1]
36993
+ path: path6
36768
36994
  };
36769
36995
  }
36770
36996
  const pathExists = text.match(new RegExp(`^(?:when\\s+)?(?:path\\s+)?(${VALUE})\\s+(exists|is gone)$`, "i"));
36771
36997
  if (pathExists) {
36998
+ const path6 = unquote(pathExists[1]);
36999
+ if (path6 === null)
37000
+ return null;
36772
37001
  return {
36773
37002
  kind: "path_exists",
36774
- path: unquote(pathExists[1]) ?? pathExists[1],
37003
+ path: path6,
36775
37004
  ...pathExists[2].toLowerCase() === "is gone" ? { gone: true } : {}
36776
37005
  };
36777
37006
  }
@@ -36826,12 +37055,42 @@ function splitOrClauses(text) {
36826
37055
  clauses.push(text.slice(start).trim());
36827
37056
  return clauses.filter(Boolean);
36828
37057
  }
37058
+ function unsafeGrammarReason(value) {
37059
+ let quote = null;
37060
+ let escaped = false;
37061
+ for (const character of value) {
37062
+ if (escaped) {
37063
+ escaped = false;
37064
+ continue;
37065
+ }
37066
+ if (quote && character === "\\") {
37067
+ escaped = true;
37068
+ continue;
37069
+ }
37070
+ if (character === '"' || character === "'") {
37071
+ quote = quote === character ? null : quote === null ? character : quote;
37072
+ }
37073
+ }
37074
+ if (quote !== null)
37075
+ return "unbalanced quote; leaving condition dreamer-evaluated";
37076
+ if (/\bcontains\s+no(?:\s|$)/i.test(value)) {
37077
+ return "ambiguous negation after contains; leaving condition dreamer-evaluated";
37078
+ }
37079
+ const temporalSuffix = new RegExp(`\\bcontains\\s+${VALUE}\\s+(?:since|until|after|before|when|while|for|as\\s+of)\\b`, "i");
37080
+ if (temporalSuffix.test(value)) {
37081
+ return "temporal suffix after contains; leaving condition dreamer-evaluated";
37082
+ }
37083
+ return null;
37084
+ }
36829
37085
  function unquote(value) {
36830
- if (value.length < 2)
36831
- return value;
36832
37086
  const quote = value[0];
36833
- if (quote !== '"' && quote !== "'" || value.at(-1) !== quote)
37087
+ const final = value.at(-1);
37088
+ const startsQuoted = quote === '"' || quote === "'";
37089
+ const endsQuoted = final === '"' || final === "'";
37090
+ if (!startsQuoted && !endsQuoted)
36834
37091
  return value;
37092
+ if (!startsQuoted || final !== quote || value.length < 2)
37093
+ return null;
36835
37094
  if (quote === '"') {
36836
37095
  try {
36837
37096
  const parsed = JSON.parse(value);
@@ -37026,8 +37285,15 @@ function createCtxNoteTool(deps) {
37026
37285
  if (!rustNote || !projectIdentity) {
37027
37286
  return "Error: Rust notes authority is active, but this module transport does not support ctx_note.";
37028
37287
  }
37029
- if (action === "write" && args.surface_condition?.trim() && deps.rustToolBackends?.noteEvaluationAvailable?.(projectIdentity) !== true) {
37030
- return "Error: Smart-note evaluation is unavailable for this Rust-authority project; the note was not written.";
37288
+ const surfaceCondition = args.surface_condition?.trim();
37289
+ let compilation;
37290
+ if ((action === "write" || action === "update") && surfaceCondition) {
37291
+ if (deps.rustToolBackends?.noteEvaluationAvailable?.(projectIdentity) !== true) {
37292
+ return "Error: Smart-note evaluation is unavailable for this Rust-authority project; the note was not written.";
37293
+ }
37294
+ compilation = await compileSurfaceCondition(surfaceCondition, {
37295
+ projectPath: toolContext.directory
37296
+ });
37031
37297
  }
37032
37298
  const commandId = toolCallIdFromContext(toolContext);
37033
37299
  const request2 = {
@@ -37038,7 +37304,8 @@ function createCtxNoteTool(deps) {
37038
37304
  memoryProject: projectIdentity,
37039
37305
  action,
37040
37306
  content: args.content,
37041
- surfaceCondition: args.surface_condition,
37307
+ surfaceCondition,
37308
+ ...compilation ? conditionCompileStorageFields(compilation) : {},
37042
37309
  filter: args.filter,
37043
37310
  limit: args.limit,
37044
37311
  offset: args.offset,
@@ -37046,9 +37313,13 @@ function createCtxNoteTool(deps) {
37046
37313
  };
37047
37314
  try {
37048
37315
  const text = moduleNoteText(await rustNote(request2));
37049
- if (text !== null)
37050
- return text;
37051
- return "Error: Rust module returned an invalid ctx_note response.";
37316
+ if (text === null) {
37317
+ return "Error: Rust module returned an invalid ctx_note response.";
37318
+ }
37319
+ if (compilation && !text.startsWith("Error:")) {
37320
+ return text + conditionCompileReplySuffix(compilation);
37321
+ }
37322
+ return text;
37052
37323
  } catch (error) {
37053
37324
  if (isRustAuthorityDrainingError(error)) {
37054
37325
  return "Error: Rust notes authority is not ready; TypeScript fallback is disabled.";
@@ -38200,7 +38471,7 @@ var server = async (ctx) => {
38200
38471
  {
38201
38472
  const fence = getSchemaFenceRejection();
38202
38473
  if (fence) {
38203
- import("./conflict-warning-hook-dw9fs934.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
38474
+ import("./conflict-warning-hook-mt0ttc4x.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
38204
38475
  }
38205
38476
  }
38206
38477
  if (conflictResult?.hasConflict) {
@@ -38221,7 +38492,7 @@ var server = async (ctx) => {
38221
38492
  } = await import("./announcement-6c1g4es4.js");
38222
38493
  if (shouldShowAnnouncement2()) {
38223
38494
  setTimeout(() => {
38224
- import("./conflict-warning-hook-dw9fs934.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
38495
+ import("./conflict-warning-hook-mt0ttc4x.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
38225
38496
  }, 8000);
38226
38497
  }
38227
38498
  } catch {}
@@ -38273,6 +38544,7 @@ var server = async (ctx) => {
38273
38544
  await magicContextRuntime.magicContext?.["command.execute.before"]?.(input, output);
38274
38545
  },
38275
38546
  "chat.message": async (input, _output) => {
38547
+ await preloadTokenizer();
38276
38548
  const typed = input;
38277
38549
  const provId = typed.model?.providerID;
38278
38550
  const modId = typed.model?.modelID;