@cortexkit/opencode-magic-context 0.42.3 → 0.42.5

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 (134) hide show
  1. package/README.md +3 -1
  2. package/dist/{announcement-3c1vertn.js → announcement-8mgn61fw.js} +1 -1
  3. package/dist/{conflict-warning-hook-aedp084d.js → conflict-warning-hook-jyj54gbe.js} +4 -4
  4. package/dist/{derive-budgets-s2pgnnm4.js → derive-budgets-v1fkhjjr.js} +2 -2
  5. package/dist/features/magic-context/context-authority.d.ts +13 -0
  6. package/dist/features/magic-context/context-authority.d.ts.map +1 -1
  7. package/dist/features/magic-context/dreamer/classify.d.ts +3 -1
  8. package/dist/features/magic-context/dreamer/classify.d.ts.map +1 -1
  9. package/dist/features/magic-context/dreamer/curate-category-rotation.d.ts +26 -0
  10. package/dist/features/magic-context/dreamer/curate-category-rotation.d.ts.map +1 -0
  11. package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts +7 -5
  12. package/dist/features/magic-context/dreamer/storage-task-schedule.d.ts.map +1 -1
  13. package/dist/features/magic-context/dreamer/task-executor.d.ts +6 -2
  14. package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
  15. package/dist/features/magic-context/dreamer/task-gates.d.ts +1 -0
  16. package/dist/features/magic-context/dreamer/task-gates.d.ts.map +1 -1
  17. package/dist/features/magic-context/dreamer/task-prompts.d.ts +3 -0
  18. package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
  19. package/dist/features/magic-context/dreamer/task-registry.d.ts +9 -0
  20. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
  21. package/dist/features/magic-context/dreamer/task-scheduler.d.ts +5 -1
  22. package/dist/features/magic-context/dreamer/task-scheduler.d.ts.map +1 -1
  23. package/dist/features/magic-context/memory/embedding-local.d.ts +11 -0
  24. package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
  25. package/dist/features/magic-context/mural/compress-cues.d.ts +3 -1
  26. package/dist/features/magic-context/mural/compress-cues.d.ts.map +1 -1
  27. package/dist/features/magic-context/transform-decision-log.d.ts +4 -0
  28. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  29. package/dist/hooks/magic-context/apply-operations.d.ts +4 -1
  30. package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/caveman-cleanup.d.ts +4 -0
  32. package/dist/hooks/magic-context/caveman-cleanup.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/compartment-runner-historian.d.ts +5 -2
  34. package/dist/hooks/magic-context/compartment-runner-historian.d.ts.map +1 -1
  35. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts +2 -2
  36. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/compartment-runner-types.d.ts +61 -2
  38. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/compartment-runner.d.ts +2 -2
  40. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/dropped-token-estimate.d.ts +20 -0
  42. package/dist/hooks/magic-context/dropped-token-estimate.d.ts.map +1 -0
  43. package/dist/hooks/magic-context/heuristic-cleanup.d.ts +2 -0
  44. package/dist/hooks/magic-context/heuristic-cleanup.d.ts.map +1 -1
  45. package/dist/hooks/magic-context/hook.d.ts +2 -2
  46. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/module-transport.d.ts +4 -1
  48. package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
  49. package/dist/hooks/magic-context/rust-mode-transform.d.ts +2 -0
  50. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  51. package/dist/hooks/magic-context/tail-hygiene-walk.d.ts.map +1 -1
  52. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +3 -0
  53. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  54. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +8 -0
  55. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  56. package/dist/hooks/magic-context/transform.d.ts +21 -0
  57. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  58. package/dist/{index-sf6x1ga9.js → index-1ar7b3e9.js} +3 -3
  59. package/dist/{index-wde5446v.js → index-3wbd8sdq.js} +225 -67
  60. package/dist/{index-3fe78beq.js → index-4ftb5hcq.js} +9 -1
  61. package/dist/{index-may8skc8.js → index-4wwr6cz0.js} +18 -1
  62. package/dist/{index-ecz14qke.js → index-d8mgqezq.js} +2 -2
  63. package/dist/{index-xdtge3y2.js → index-f9gem5cr.js} +2 -2
  64. package/dist/{index-z8552w7e.js → index-jkrqhc7y.js} +1 -1
  65. package/dist/{index-3wzdwt6p.js → index-ntbmt6rq.js} +1 -1
  66. package/dist/{index-gynz8qdc.js → index-p474rw9p.js} +3 -3
  67. package/dist/{index-dkv2dn46.js → index-qp20p2py.js} +1 -1
  68. package/dist/index.d.ts +4 -1
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +1625 -148
  71. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  72. package/dist/plugin/rpc-handlers.d.ts +18 -0
  73. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  74. package/dist/plugin/rust-tool-backends.d.ts +3 -1
  75. package/dist/plugin/rust-tool-backends.d.ts.map +1 -1
  76. package/dist/{recomp-orchestrator-447vycpt.js → recomp-orchestrator-k20sfpm2.js} +6 -6
  77. package/dist/{safe-notification-target-q9z81zt3.js → safe-notification-target-fepvcbsj.js} +1 -1
  78. package/dist/{send-session-notification-2mzgd3zf.js → send-session-notification-xnypkxpx.js} +3 -3
  79. package/dist/shared/harness.d.ts +2 -1
  80. package/dist/shared/harness.d.ts.map +1 -1
  81. package/dist/shared/model-suggestion-retry.d.ts +5 -1
  82. package/dist/shared/model-suggestion-retry.d.ts.map +1 -1
  83. package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
  84. package/dist/shared/rpc-types.d.ts +13 -0
  85. package/dist/shared/rpc-types.d.ts.map +1 -1
  86. package/dist/shared/status-detail-text.d.ts.map +1 -1
  87. package/dist/shared/status-summary.d.ts.map +1 -1
  88. package/dist/shared/user-facing-codes.d.ts +10 -0
  89. package/dist/shared/user-facing-codes.d.ts.map +1 -1
  90. package/dist/{storage-meta-session-fkmfhswa.js → storage-meta-session-x3j0q9qy.js} +3 -3
  91. package/dist/{task-config-hnv93r7p.js → task-config-cv8k9y8r.js} +1 -1
  92. package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
  93. package/dist/tools/ctx-note/tools.d.ts.map +1 -1
  94. package/dist/v2/fold/markers.d.ts +7 -0
  95. package/dist/v2/fold/markers.d.ts.map +1 -0
  96. package/dist/v2/fold/owner.d.ts +40 -0
  97. package/dist/v2/fold/owner.d.ts.map +1 -0
  98. package/dist/v2/fold/restore.d.ts +11 -0
  99. package/dist/v2/fold/restore.d.ts.map +1 -0
  100. package/dist/v2/hidden-completion.d.ts +20 -0
  101. package/dist/v2/hidden-completion.d.ts.map +1 -0
  102. package/dist/v2/hooks/channel2.d.ts +8 -0
  103. package/dist/v2/hooks/channel2.d.ts.map +1 -0
  104. package/dist/v2/hooks/context.d.ts +7 -0
  105. package/dist/v2/hooks/context.d.ts.map +1 -0
  106. package/dist/v2/hooks/dream-trigger.d.ts +19 -0
  107. package/dist/v2/hooks/dream-trigger.d.ts.map +1 -0
  108. package/dist/v2/hooks/payload.d.ts +12 -0
  109. package/dist/v2/hooks/payload.d.ts.map +1 -0
  110. package/dist/v2/hooks/refusal.d.ts +7 -0
  111. package/dist/v2/hooks/refusal.d.ts.map +1 -0
  112. package/dist/v2/hooks/store.d.ts +6 -0
  113. package/dist/v2/hooks/store.d.ts.map +1 -0
  114. package/dist/v2/hooks/types.d.ts +90 -0
  115. package/dist/v2/hooks/types.d.ts.map +1 -0
  116. package/dist/v2/hooks/update-check.d.ts +10 -0
  117. package/dist/v2/hooks/update-check.d.ts.map +1 -0
  118. package/dist/v2/server.d.ts +3 -1
  119. package/dist/v2/server.d.ts.map +1 -1
  120. package/dist/v2/server.js +116641 -4
  121. package/dist/v2/store-reader.d.ts +2 -0
  122. package/dist/v2/store-reader.d.ts.map +1 -1
  123. package/index.js +1 -0
  124. package/package.json +5 -4
  125. package/src/features/magic-context/dreamer/task-registry.ts +29 -0
  126. package/src/shared/harness.ts +2 -1
  127. package/src/shared/model-suggestion-retry.ts +66 -14
  128. package/src/shared/prompt-surface-runtime.ts +5 -1
  129. package/src/shared/rpc-types.ts +13 -0
  130. package/src/shared/status-detail-text.test.ts +26 -0
  131. package/src/shared/status-detail-text.ts +11 -0
  132. package/src/shared/status-summary.ts +2 -0
  133. package/src/shared/user-facing-codes.test.ts +1 -1
  134. package/src/shared/user-facing-codes.ts +10 -0
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  sessionLog,
6
6
  getLoggerDiagnostics,
7
7
  flushLogger
8
- } from "./index-dkv2dn46.js";
8
+ } from "./index-qp20p2py.js";
9
9
  import {
10
10
  withContentLanguageDirective,
11
11
  buildPrimaryLanguageDirective,
@@ -71,6 +71,7 @@ import {
71
71
  checksumAuthoritySeedRows,
72
72
  prepareAuthority,
73
73
  drainAuthority,
74
+ getMemoryMirrorStatus,
74
75
  applyMirroredNoteCompileFields,
75
76
  drainMirrorPages,
76
77
  pullMemoryMirrorOnce,
@@ -191,6 +192,7 @@ import {
191
192
  isToolPartWithOutput,
192
193
  isFilePart,
193
194
  buildFileSourceContent,
195
+ assertExecutableToolInput,
194
196
  createDroppedInputToolExecuteBeforeHook,
195
197
  isEditTool,
196
198
  partHasCompletedResult,
@@ -359,6 +361,7 @@ import {
359
361
  replaceSourceContent,
360
362
  getSourceContents,
361
363
  createChildSessionWithFence,
364
+ HiddenCompletionRefusal,
362
365
  detectThinkingBindingMismatch,
363
366
  isFable51ThinkingBindingModel,
364
367
  detectOverflow,
@@ -472,6 +475,7 @@ import {
472
475
  verificationFileExists,
473
476
  normalizeVerificationFiles,
474
477
  recordChildInvocation,
478
+ createV1HiddenCompletionExecutor,
475
479
  USER_MEMORY_CANDIDATE_TTL_MS,
476
480
  insertUserMemoryCandidates,
477
481
  getUserMemoryCandidates,
@@ -522,6 +526,7 @@ import {
522
526
  mustMaterialize,
523
527
  trimMemoriesToBudgetV2,
524
528
  renderMemoryBlockV2,
529
+ materializeM0,
525
530
  prepareCachedM0M1Replay,
526
531
  hasCompleteCachedM0M1,
527
532
  injectM0M1,
@@ -542,7 +547,7 @@ import {
542
547
  setRecompTerminal2,
543
548
  runManagedRecomp2,
544
549
  runManagedUpgrade2
545
- } from "./index-wde5446v.js";
550
+ } from "./index-3wbd8sdq.js";
546
551
  import {
547
552
  stripJsonComments,
548
553
  isPrototypePollutionKey,
@@ -568,7 +573,7 @@ import {
568
573
  deriveHistorianChunkTokens2,
569
574
  resolveKnownHistorianContextLimit2,
570
575
  resolveHistorianContextLimit2
571
- } from "./index-xdtge3y2.js";
576
+ } from "./index-f9gem5cr.js";
572
577
  import {
573
578
  resolveOpenCodeDbPath,
574
579
  openCodeDbPathExists,
@@ -589,7 +594,7 @@ import {
589
594
  assistantAwaitingTools,
590
595
  getMessageTimesFromOpenCodeDb,
591
596
  findLastAssistantModelFromOpenCodeDb
592
- } from "./index-z8552w7e.js";
597
+ } from "./index-jkrqhc7y.js";
593
598
  import {
594
599
  getErrorMessage,
595
600
  describeError,
@@ -598,13 +603,13 @@ import {
598
603
  clearIgnoredMessages2,
599
604
  observeIgnoredNotificationEvent2,
600
605
  sendStatusNotification2
601
- } from "./index-gynz8qdc.js";
606
+ } from "./index-p474rw9p.js";
602
607
  import {
603
608
  detectConflicts,
604
609
  resolveCompactionForBoot,
605
610
  sendConflictWarning2,
606
611
  cleanupConflictWarnings2
607
- } from "./index-ecz14qke.js";
612
+ } from "./index-d8mgqezq.js";
608
613
  import {
609
614
  resolveHistorianModel2,
610
615
  resolveOpenCodeAgentOverrides2,
@@ -612,6 +617,7 @@ import {
612
617
  } from "./index-7k55qm8a.js";
613
618
  import {
614
619
  CANONICAL_DREAM_TASKS,
620
+ DREAM_TASK_CAPABILITIES,
615
621
  formatDreamTaskBacklogs,
616
622
  processedDreamTaskItems,
617
623
  leaseKindFor,
@@ -620,7 +626,7 @@ import {
620
626
  compareTaskOrder,
621
627
  buildDreamTaskRuntimeConfigs2,
622
628
  userMemoryCollectionEnabled2
623
- } from "./index-may8skc8.js";
629
+ } from "./index-4wwr6cz0.js";
624
630
  import {
625
631
  logSlowWriteTransaction,
626
632
  getOrCreateSessionMeta2,
@@ -630,7 +636,7 @@ import {
630
636
  retryPendingSessionCleanups2,
631
637
  retryPendingRustSessionCleanupsForProject2,
632
638
  clearSession2
633
- } from "./index-sf6x1ga9.js";
639
+ } from "./index-1ar7b3e9.js";
634
640
  import {
635
641
  registerNotificationSink2,
636
642
  pushNotification2,
@@ -646,7 +652,7 @@ import {
646
652
  ANNOUNCEMENT_FOOTER2,
647
653
  markAnnouncementSeen2,
648
654
  shouldShowAnnouncement2
649
- } from "./index-3wzdwt6p.js";
655
+ } from "./index-ntbmt6rq.js";
650
656
  import {
651
657
  resolvePromptContext2
652
658
  } from "./index-fmsr7v69.js";
@@ -656,12 +662,13 @@ import {
656
662
  modelRefLookupOrder
657
663
  } from "./index-avwt563y.js";
658
664
  import {
665
+ setHarness,
659
666
  getHarness,
660
667
  getDataDir,
661
668
  getOpenCodeStorageDir,
662
669
  getMagicContextStorageResolution,
663
670
  getMagicContextStorageDir
664
- } from "./index-3fe78beq.js";
671
+ } from "./index-4ftb5hcq.js";
665
672
  import {
666
673
  __toESM,
667
674
  __commonJS
@@ -10774,9 +10781,11 @@ function buildCuratePrompt(args) {
10774
10781
 
10775
10782
  **Project:** ${args.projectPath}
10776
10783
 
10784
+ This run covers the whole of the \`${args.category}\` category (the other categories run in later windows).
10785
+
10777
10786
  The memories below are assumed ACCURATE (a separate verify task keeps them true). Your job is pool QUALITY: remove duplicates, tighten wording, and consolidate redundant entries that waste the ~6000-token injection budget. Explain each action in one line first. Do NOT mint new facts (that is the historian's job).
10778
10787
 
10779
- Work ALL THREE phases below in order (A → B → C) over the whole pool. Do NOT stop after consolidating — a run that only merges and never improves or archives is incomplete.
10788
+ Work ALL THREE phases below in order (A → B → C) over this category. Do NOT stop after consolidating — a run that only merges and never improves or archives is incomplete.
10780
10789
 
10781
10790
  ### Phase A — Consolidate duplicates
10782
10791
  Group by category, then merge near-identical / superset-subset / same-fact-different-angle clusters into one canonical memory with \`ctx_memory(action="merge", ids=[...], content="...", category="...")\`. Preserve every unique detail; terse present tense; paths/keys verbatim. Every id in a merge MUST share the same category — the system rejects cross-category merges. If two similar memories sit in different categories they are NOT duplicates; do not archive either as a consolidation. One fact per memory.
@@ -10996,6 +11005,7 @@ function buildDreamTaskPrompt(task, args) {
10996
11005
  case "curate":
10997
11006
  return buildCuratePrompt({
10998
11007
  projectPath: args.projectPath,
11008
+ category: args.curate?.category ?? "PROJECT_RULES",
10999
11009
  memories: args.curate?.memories ?? []
11000
11010
  });
11001
11011
  case "maintain-docs":
@@ -12174,7 +12184,7 @@ var SERIAL_LANE_MAX_WAITERS = 16;
12174
12184
  var SERIAL_LANE_MAX_WAITERS_PER_SESSION = 8;
12175
12185
  var SERIAL_LANE_MIN_REMAINING_MS = 25;
12176
12186
  var CANONICAL_ROOT_CACHE_MAX_ENTRIES = 256;
12177
- function getDefaultConnectionFile() {
12187
+ function getDefaultSubcConnectionFile() {
12178
12188
  return join5(getDataDir(), "cortexkit", "run", "subc-connection.json");
12179
12189
  }
12180
12190
  function errorChainSome(error, predicate) {
@@ -12289,7 +12299,7 @@ class SubcModuleTransport {
12289
12299
  return capabilities;
12290
12300
  }
12291
12301
  constructor(connectionFile, moduleId = DEFAULT_MODULE_ID, requestTimeoutMs = MODULE_SEND_TIMEOUT_MS, routeSessionPrefix = "") {
12292
- this.connectionFile = connectionFile ?? getDefaultConnectionFile();
12302
+ this.connectionFile = connectionFile;
12293
12303
  this.moduleId = moduleId;
12294
12304
  this.requestTimeoutMs = requestTimeoutMs;
12295
12305
  this.routeSessionPrefix = routeSessionPrefix;
@@ -12567,8 +12577,8 @@ class SubcModuleTransport {
12567
12577
  }
12568
12578
  async authorityStatus(args) {
12569
12579
  this.authorityProjectRoot = args.project;
12570
- const { projectRoot, ...body } = args;
12571
- const response = await this.authorityRequest(args.project, projectRoot ?? this.bindRootForAuthority(), "authority.status", body);
12580
+ const { projectRoot, sessionId, ...body } = args;
12581
+ const response = await this.authorityRequest(sessionId ?? args.project, projectRoot ?? this.bindRootForAuthority(), "authority.status", body);
12572
12582
  return { authority: response.authority ?? null };
12573
12583
  }
12574
12584
  async authorityPrepare(args) {
@@ -13560,6 +13570,7 @@ function toRow(r) {
13560
13570
  lastStatus: r.last_status ?? null,
13561
13571
  lastError: r.last_error,
13562
13572
  retryCount: r.retry_count ?? 0,
13573
+ taskStateJson: r.last_checked_commit ?? null,
13563
13574
  lastCheckedCommit: r.last_checked_commit ?? null,
13564
13575
  lastBroadRunAt: r.last_broad_run_at ?? null,
13565
13576
  retrospectiveWatermarkMs: r.retrospective_watermark_ms ?? null
@@ -13603,7 +13614,12 @@ function writeTaskScheduleState(db, row) {
13603
13614
  retry_count = excluded.retry_count,
13604
13615
  last_checked_commit = COALESCE(excluded.last_checked_commit, task_schedule_state.last_checked_commit),
13605
13616
  ${broadCycleUpdate},
13606
- retrospective_watermark_ms = COALESCE(excluded.retrospective_watermark_ms, task_schedule_state.retrospective_watermark_ms)`).run(row.projectPath, row.task, row.lastRunAt, row.nextDueAt, row.schedule, row.lastStatus, row.lastError, row.retryCount, row.lastCheckedCommit ?? null, row.lastBroadRunAt ?? null, row.retrospectiveWatermarkMs ?? null);
13617
+ retrospective_watermark_ms = COALESCE(excluded.retrospective_watermark_ms, task_schedule_state.retrospective_watermark_ms)`).run(row.projectPath, row.task, row.lastRunAt, row.nextDueAt, row.schedule, row.lastStatus, row.lastError, row.retryCount, row.taskStateJson ?? row.lastCheckedCommit ?? null, row.lastBroadRunAt ?? null, row.retrospectiveWatermarkMs ?? null);
13618
+ }
13619
+ function writeTaskStateJson(db, projectPath, task, taskStateJson) {
13620
+ db.prepare(`INSERT INTO task_schedule_state (project_path, task, last_checked_commit)
13621
+ VALUES (?, ?, ?)
13622
+ ON CONFLICT(project_path, task) DO UPDATE SET last_checked_commit = excluded.last_checked_commit`).run(projectPath, task, taskStateJson);
13607
13623
  }
13608
13624
  function isRetrospectiveWindowProcessed(db, projectPath, windowKey) {
13609
13625
  const row = db.prepare("SELECT 1 AS one FROM retrospective_processed_windows WHERE project_path = ? AND window_key = ?").get(projectPath, windowKey);
@@ -14041,6 +14057,8 @@ function isTimeoutClassError(error) {
14041
14057
  }
14042
14058
  async function compressOneChunk(args, chunk, sliceMs, signal) {
14043
14059
  let agentSessionId = null;
14060
+ let handle = null;
14061
+ const executor = args.hiddenCompletionExecutor ?? createV1HiddenCompletionExecutor(args.client, args.db, args.sessionDirectory);
14044
14062
  let promptSettled = false;
14045
14063
  const startedAt = Date.now();
14046
14064
  try {
@@ -14048,19 +14066,22 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
14048
14066
  projectPath: args.projectIdentity,
14049
14067
  memories: chunk.map(toPromptMemory)
14050
14068
  });
14051
- const createResponse = await createChildSessionWithFence({
14052
- client: args.client,
14053
- db: args.db,
14069
+ handle = await executor.open({
14054
14070
  parentSessionId: args.parentSessionId,
14071
+ agent: DREAMER_CLASSIFIER_AGENT,
14072
+ kind: "dreamer-task",
14073
+ system: COMPRESS_CUES_SYSTEM_PROMPT,
14074
+ model: args.model,
14075
+ configuredModels: [...args.model ? [args.model] : [], ...args.fallbackModels ?? []],
14076
+ timeoutMs: sliceMs,
14055
14077
  title: "magic-context-dream-compress-cues",
14056
- directory: args.sessionDirectory
14078
+ directory: args.sessionDirectory,
14079
+ metadata: { task: "compress-cues" }
14057
14080
  });
14058
- const created = normalizeSDKResponse(createResponse, null, {
14059
- preferResponseOnMissingData: true
14060
- });
14061
- agentSessionId = typeof created?.id === "string" ? created.id : null;
14081
+ agentSessionId = handle.id || null;
14062
14082
  if (!agentSessionId)
14063
14083
  throw new Error("Could not create compress-cues session.");
14084
+ const opened = handle;
14064
14085
  const run = await promptSyncWithValidatedOutputRetry(args.client, {
14065
14086
  path: { id: agentSessionId },
14066
14087
  query: { directory: args.sessionDirectory },
@@ -14071,24 +14092,18 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
14071
14092
  parts: [{ type: "text", text: prompt, synthetic: true }]
14072
14093
  }
14073
14094
  }, {
14095
+ transport: Object.assign((request) => executor.attempt(opened, request), { childSessionId: opened.childSessionId }),
14074
14096
  timeoutMs: sliceMs,
14075
14097
  signal,
14076
14098
  fallbackModels: args.fallbackModels,
14077
14099
  callContext: "dreamer:compress-cues",
14078
- fetchOutput: async () => {
14079
- const messagesResponse = await args.client.session.messages({
14080
- path: { id: agentSessionId },
14081
- query: { directory: args.sessionDirectory, limit: 50 }
14082
- });
14083
- return normalizeSDKResponse(messagesResponse, [], {
14084
- preferResponseOnMissingData: true
14085
- });
14086
- },
14087
- validateOutput: (messages) => {
14088
- if (hasLengthCappedOutput(messages)) {
14100
+ fetchOutput: () => executor.collect(opened, 50),
14101
+ validateOutput: (completion) => {
14102
+ const messages = completion.messages ?? [];
14103
+ if (completion.lengthCapped) {
14089
14104
  throw new Error("compress-cues returned length-capped output");
14090
14105
  }
14091
- const text = extractLatestAssistantText(messages);
14106
+ const text = completion.text;
14092
14107
  if (!text)
14093
14108
  throw new Error("compress-cues returned no output");
14094
14109
  try {
@@ -14103,11 +14118,25 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
14103
14118
  }
14104
14119
  });
14105
14120
  promptSettled = true;
14121
+ if (args.hiddenCompletionExecutor && args.parentSessionId) {
14122
+ recordChildInvocation({
14123
+ db: args.db,
14124
+ parentSessionId: args.parentSessionId,
14125
+ harness: executor.capabilities.harness,
14126
+ subagent: "dreamer",
14127
+ task: "compress-cues",
14128
+ startedAt,
14129
+ status: "completed",
14130
+ tokens: run.output.usage,
14131
+ providerId: run.output.providerId,
14132
+ modelId: run.output.modelId
14133
+ });
14134
+ }
14106
14135
  return args.moduleRoute ? await applyCuesThroughModule(args, chunk, run.validated, signal) : applyCues(args, chunk, run.validated);
14107
14136
  } catch (error) {
14108
14137
  const desc = describeError(error);
14109
14138
  log(`[dreamer] compress-cues chunk failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
14110
- if (signal.aborted || error instanceof DreamerProviderOutputFailureError)
14139
+ if (signal.aborted || error instanceof HiddenCompletionRefusal || error instanceof DreamerProviderOutputFailureError)
14111
14140
  throw error;
14112
14141
  return {
14113
14142
  compressed: 0,
@@ -14119,10 +14148,7 @@ async function compressOneChunk(args, chunk, sliceMs, signal) {
14119
14148
  }
14120
14149
  };
14121
14150
  } finally {
14122
- await teardownChildSession({
14123
- client: args.client,
14124
- sessionId: agentSessionId,
14125
- sessionDirectory: args.sessionDirectory,
14151
+ await executor.close(handle, {
14126
14152
  promptSettled,
14127
14153
  privacySensitive: true,
14128
14154
  context: "[dreamer] compress-cues",
@@ -14777,6 +14803,8 @@ async function runClassify(args) {
14777
14803
  }
14778
14804
  async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
14779
14805
  let agentSessionId = null;
14806
+ let handle = null;
14807
+ const executor = args.hiddenCompletionExecutor ?? createV1HiddenCompletionExecutor(args.client, args.db, args.sessionDirectory);
14780
14808
  let promptSettled = false;
14781
14809
  const startedAt = Date.now();
14782
14810
  const moduleRoute = isModuleRoute(args);
@@ -14791,19 +14819,22 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
14791
14819
  recordInvocation(args, startedAt, { status: "completed" });
14792
14820
  return run;
14793
14821
  }
14794
- const createResponse = await createChildSessionWithFence({
14795
- client: args.client,
14796
- db: args.db,
14822
+ handle = await executor.open({
14797
14823
  parentSessionId: args.parentSessionId,
14824
+ agent: DREAMER_CLASSIFIER_AGENT,
14825
+ kind: "dreamer-task",
14826
+ system: withContentLanguageDirective(CLASSIFY_SYSTEM_PROMPT, args.language),
14827
+ model: args.model,
14828
+ configuredModels: [...args.model ? [args.model] : [], ...args.fallbackModels ?? []],
14829
+ timeoutMs: sliceMs,
14798
14830
  title: "magic-context-dream-classify",
14799
- directory: args.sessionDirectory
14831
+ directory: args.sessionDirectory,
14832
+ metadata: { task: "classify-memories" }
14800
14833
  });
14801
- const created = normalizeSDKResponse(createResponse, null, {
14802
- preferResponseOnMissingData: true
14803
- });
14804
- agentSessionId = typeof created?.id === "string" ? created.id : null;
14834
+ agentSessionId = handle.id || null;
14805
14835
  if (!agentSessionId)
14806
14836
  throw new Error("Could not create classify session.");
14837
+ const opened = handle;
14807
14838
  const run = await promptSyncWithValidatedOutputRetry(args.client, {
14808
14839
  path: { id: agentSessionId },
14809
14840
  query: { directory: args.sessionDirectory },
@@ -14814,24 +14845,18 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
14814
14845
  parts: [{ type: "text", text: prompt, synthetic: true }]
14815
14846
  }
14816
14847
  }, {
14848
+ transport: Object.assign((request) => executor.attempt(opened, request), { childSessionId: opened.childSessionId }),
14817
14849
  timeoutMs: sliceMs,
14818
14850
  signal,
14819
14851
  fallbackModels: args.fallbackModels,
14820
14852
  callContext: "dreamer:classify-memories",
14821
- fetchOutput: async () => {
14822
- const messagesResponse = await args.client.session.messages({
14823
- path: { id: agentSessionId },
14824
- query: { directory: args.sessionDirectory, limit: 50 }
14825
- });
14826
- return normalizeSDKResponse(messagesResponse, [], {
14827
- preferResponseOnMissingData: true
14828
- });
14829
- },
14830
- validateOutput: (messages) => {
14831
- if (hasLengthCappedOutput(messages)) {
14853
+ fetchOutput: () => executor.collect(opened, 50),
14854
+ validateOutput: (completion) => {
14855
+ const messages = completion.messages ?? [];
14856
+ if (completion.lengthCapped) {
14832
14857
  throw new Error("classify returned length-capped output");
14833
14858
  }
14834
- const text = extractLatestAssistantText(messages);
14859
+ const text = completion.text;
14835
14860
  if (!text)
14836
14861
  throw new Error("classify returned no output");
14837
14862
  try {
@@ -14846,21 +14871,22 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
14846
14871
  }
14847
14872
  });
14848
14873
  promptSettled = true;
14849
- recordInvocation(args, startedAt, { status: "completed", messages: run.output });
14874
+ recordInvocation(args, startedAt, {
14875
+ status: "completed",
14876
+ messages: run.output.messages,
14877
+ completion: run.output
14878
+ });
14850
14879
  return applyClassifications(args, chunk.map((candidate) => candidate.contextMemory), run.validated);
14851
14880
  } catch (error) {
14852
14881
  const failure = moduleRoute ? new ClassifyModuleFailureError("module", error) : error;
14853
14882
  const desc = describeError(failure);
14854
14883
  log(`[dreamer] classify chunk failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
14855
14884
  recordInvocation(args, startedAt, { status: "failed", error: failure });
14856
- if (moduleRoute || signal.aborted || failure instanceof DreamerProviderOutputFailureError || getPromptFailureDetail(failure)?.failureClass !== "parse_failed" && getPromptFailureDetail(failure) !== null)
14885
+ if (moduleRoute || failure instanceof HiddenCompletionRefusal || signal.aborted || failure instanceof DreamerProviderOutputFailureError || getPromptFailureDetail(failure)?.failureClass !== "parse_failed" && getPromptFailureDetail(failure) !== null)
14857
14886
  throw failure;
14858
14887
  return { classified: 0, changed: 0 };
14859
14888
  } finally {
14860
- await teardownChildSession({
14861
- client: args.client,
14862
- sessionId: agentSessionId,
14863
- sessionDirectory: args.sessionDirectory,
14889
+ await executor.close(handle, {
14864
14890
  promptSettled,
14865
14891
  privacySensitive: true,
14866
14892
  context: "[dreamer] classify",
@@ -15014,16 +15040,119 @@ function recordInvocation(args, startedAt, params) {
15014
15040
  recordChildInvocation({
15015
15041
  db: args.db,
15016
15042
  parentSessionId: args.parentSessionId,
15017
- harness: "opencode",
15043
+ harness: args.hiddenCompletionExecutor?.capabilities.harness ?? "opencode",
15018
15044
  subagent: "dreamer",
15019
15045
  task: "classify-memories",
15020
15046
  startedAt,
15021
15047
  status: params.status,
15022
15048
  messages: params.messages,
15049
+ ...params.completion && !params.completion.messages ? {
15050
+ tokens: params.completion.usage,
15051
+ providerId: params.completion.providerId,
15052
+ modelId: params.completion.modelId
15053
+ } : {},
15023
15054
  error: params.error
15024
15055
  });
15025
15056
  }
15026
15057
 
15058
+ // src/features/magic-context/dreamer/curate-category-rotation.ts
15059
+ var CURATE_MEMORY_CATEGORIES = [
15060
+ "PROJECT_RULES",
15061
+ "ARCHITECTURE",
15062
+ "CONSTRAINTS",
15063
+ "CONFIG_VALUES",
15064
+ "NAMING"
15065
+ ];
15066
+ var LEGACY_CURATE_CATEGORY_BUCKETS = {
15067
+ ARCHITECTURE_DECISIONS: "ARCHITECTURE",
15068
+ CONFIG_DEFAULTS: "CONFIG_VALUES",
15069
+ ENVIRONMENT: "CONFIG_VALUES",
15070
+ KNOWN_ISSUES: "CONSTRAINTS",
15071
+ USER_DIRECTIVES: "PROJECT_RULES",
15072
+ USER_PREFERENCES: "PROJECT_RULES",
15073
+ WORKFLOW_RULES: "PROJECT_RULES"
15074
+ };
15075
+ function curateCategoryForMemoryCategory(category) {
15076
+ return isCurateMemoryCategory(category) ? category : LEGACY_CURATE_CATEGORY_BUCKETS[category] ?? null;
15077
+ }
15078
+ function isCurateMemoryCategory(value) {
15079
+ return CURATE_MEMORY_CATEGORIES.includes(value);
15080
+ }
15081
+ function parseTaskState(raw) {
15082
+ if (!raw)
15083
+ return {};
15084
+ try {
15085
+ const parsed = JSON.parse(raw);
15086
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
15087
+ } catch {
15088
+ return {};
15089
+ }
15090
+ }
15091
+ function normalizedCursor(value) {
15092
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value % CURATE_MEMORY_CATEGORIES.length : 0;
15093
+ }
15094
+ function readState(db, projectIdentity) {
15095
+ return parseTaskState(getTaskScheduleState(db, projectIdentity, "curate")?.taskStateJson);
15096
+ }
15097
+ function categoryStartIndex(state, populated) {
15098
+ const active = state.curate?.activeCategory;
15099
+ if (isCurateMemoryCategory(active)) {
15100
+ const activeIndex = CURATE_MEMORY_CATEGORIES.indexOf(active);
15101
+ return populated.has(active) ? activeIndex : (activeIndex + 1) % CURATE_MEMORY_CATEGORIES.length;
15102
+ }
15103
+ return normalizedCursor(state.curate?.cursor);
15104
+ }
15105
+ function peekCurateCategoryScope(db, projectIdentity, memories) {
15106
+ const populated = new Set(memories.map((memory) => curateCategoryForMemoryCategory(memory.category)).filter((category) => category !== null));
15107
+ const start = categoryStartIndex(readState(db, projectIdentity), populated);
15108
+ for (let offset = 0;offset < CURATE_MEMORY_CATEGORIES.length; offset += 1) {
15109
+ const category = CURATE_MEMORY_CATEGORIES[(start + offset) % CURATE_MEMORY_CATEGORIES.length];
15110
+ const scoped = memories.filter((memory) => curateCategoryForMemoryCategory(memory.category) === category);
15111
+ if (scoped.length > 0)
15112
+ return { category, memories: scoped };
15113
+ }
15114
+ return null;
15115
+ }
15116
+ function beginCurateCategoryRun(db, projectIdentity, memories) {
15117
+ const scope = peekCurateCategoryScope(db, projectIdentity, memories);
15118
+ if (!scope)
15119
+ return null;
15120
+ const state = readState(db, projectIdentity);
15121
+ writeTaskStateJson(db, projectIdentity, "curate", JSON.stringify({
15122
+ ...state,
15123
+ curate: {
15124
+ cursor: normalizedCursor(state.curate?.cursor),
15125
+ activeCategory: scope.category
15126
+ }
15127
+ }));
15128
+ return scope;
15129
+ }
15130
+ function curateTaskStateAfterSuccess(db, projectIdentity, category) {
15131
+ const state = readState(db, projectIdentity);
15132
+ return JSON.stringify({
15133
+ ...state,
15134
+ curate: {
15135
+ cursor: (CURATE_MEMORY_CATEGORIES.indexOf(category) + 1) % CURATE_MEMORY_CATEGORIES.length
15136
+ }
15137
+ });
15138
+ }
15139
+ function getActiveCurateCategory(db, projectIdentity) {
15140
+ const active = readState(db, projectIdentity).curate?.activeCategory;
15141
+ return isCurateMemoryCategory(active) ? active : null;
15142
+ }
15143
+ function getCurateCategoryScopeRefusal(args) {
15144
+ if (args.requestedCategory && args.requestedCategory !== args.scope) {
15145
+ return `Error: Curate scope is ${args.scope}; ${args.action} cannot target category ${args.requestedCategory}.`;
15146
+ }
15147
+ for (const id of args.ids ?? []) {
15148
+ const category = args.categoryForId(id);
15149
+ if (category && category !== args.scope) {
15150
+ return `Error: Curate scope is ${args.scope}; memory ID ${id} is outside the scoped category.`;
15151
+ }
15152
+ }
15153
+ return null;
15154
+ }
15155
+
15027
15156
  // src/features/magic-context/dreamer/memory-claim-safety.ts
15028
15157
  var POLICY_SENTENCE_START = /(?:^|[.!?]\s+|\n\s*)(?:[-*]\s+|\d+[.)]\s+)?(?:you\s+|we\s+)?(?:must(?:\s+not)?|never|always|do\s+not|don't|shall\s+not)\b/i;
15029
15158
  var ACTOR_POLICY = /\b(?:you|we|agents?|masons?|workers?|operators?|users?|maintainers?)\s+(?:must(?:\s+not)?|should(?:\s+not)?|need\s+to|shall(?:\s+not)?|cannot|can't|may\s+not)\b/i;
@@ -18316,12 +18445,13 @@ function countActiveMemories(db, projectPath) {
18316
18445
  }
18317
18446
  function countLiveMemories(db, projectPath, options = {}) {
18318
18447
  const unclassified = options.unclassifiedOnly && hasMemoryClassifiedAtColumn(db);
18319
- const row = db.prepare(`SELECT COUNT(*) AS cnt
18320
- FROM memories
18321
- WHERE project_path = ?
18322
- AND status IN ('active','permanent')
18323
- AND (expires_at IS NULL OR expires_at > ?)
18324
- ${unclassified ? "AND classified_at IS NULL" : ""}`).get(projectPath, Date.now());
18448
+ const sql = `SELECT COUNT(*) AS cnt
18449
+ FROM memories
18450
+ WHERE project_path = ?
18451
+ AND status IN ('active','permanent')
18452
+ AND (expires_at IS NULL OR expires_at > ?)
18453
+ ${unclassified ? "AND classified_at IS NULL" : ""}`;
18454
+ const row = options.category ? db.prepare(`${sql} AND category = ?`).get(projectPath, Date.now(), options.category) : db.prepare(sql).get(projectPath, Date.now());
18325
18455
  return row?.cnt ?? 0;
18326
18456
  }
18327
18457
  function countUnmappedActiveMemories(db, projectPath) {
@@ -18432,8 +18562,13 @@ function getDreamTaskBacklog(db, projectPath, task, options = {}) {
18432
18562
  return { pending, total };
18433
18563
  }
18434
18564
  case "curate": {
18435
- const total = countLiveMemories(db, projectPath);
18436
- return { pending: total, total };
18565
+ const categories = db.prepare(`SELECT category FROM memories
18566
+ WHERE project_path = ?
18567
+ AND status IN ('active','permanent')
18568
+ AND (expires_at IS NULL OR expires_at > ?)`).all(projectPath, Date.now());
18569
+ const scope = peekCurateCategoryScope(db, projectPath, categories);
18570
+ const total = scope?.memories.length ?? 0;
18571
+ return scope ? { pending: total, total, category: scope.category } : { pending: 0, total: 0 };
18437
18572
  }
18438
18573
  case "compress-cues": {
18439
18574
  const total = countLiveMemories(db, projectPath);
@@ -19156,7 +19291,7 @@ function dreamRunFailureDetail(error) {
19156
19291
  }
19157
19292
  const described = describeError(error);
19158
19293
  const message = described.brief;
19159
- const providerFailure = error instanceof Error && error.name === "DreamerProviderOutputFailureError";
19294
+ const providerFailure = error instanceof HiddenCompletionRefusal || error instanceof Error && error.name === "DreamerProviderOutputFailureError";
19160
19295
  return {
19161
19296
  failure_class: providerFailure ? "provider_error" : /no models?|model chain is empty/i.test(message) ? "no_models" : "unknown",
19162
19297
  model_attempted: null,
@@ -19246,13 +19381,20 @@ function formatCurateMemoryOperations(actions) {
19246
19381
  const noun = actions.length === 1 ? "operation" : "operations";
19247
19382
  return `curate: ${actions.length} memory ${noun} applied${actionDetail ? ` (${actionDetail})` : ""}`;
19248
19383
  }
19384
+ function requireDreamClient(client) {
19385
+ if (!client)
19386
+ throw new HiddenCompletionRefusal("hidden_tools_unsupported", "This dream task requires the child-session tool transport", true);
19387
+ return client;
19388
+ }
19249
19389
  function createDreamTaskExecutor(deps) {
19250
19390
  let parentSessionIdPromise;
19251
19391
  const resolveParentSessionId = () => {
19392
+ if (deps.hiddenCompletionExecutor)
19393
+ return Promise.resolve(deps.parentSessionId);
19252
19394
  if (!parentSessionIdPromise) {
19253
19395
  parentSessionIdPromise = (async () => {
19254
19396
  try {
19255
- const listResponse = await deps.client.session.list({
19397
+ const listResponse = await requireDreamClient(deps.client).session.list({
19256
19398
  query: { directory: deps.sessionDirectory }
19257
19399
  });
19258
19400
  const sessions = normalizeSDKResponse(listResponse, [], { preferResponseOnMissingData: true });
@@ -19278,6 +19420,7 @@ function createDreamTaskExecutor(deps) {
19278
19420
  processed: Math.max(0, processed),
19279
19421
  total: backlogAtStart.pending,
19280
19422
  startedAt,
19423
+ ...backlogAtStart.category ? { category: backlogAtStart.category } : {},
19281
19424
  ...refused === undefined ? {} : { refused: Math.max(0, refused) }
19282
19425
  });
19283
19426
  };
@@ -19330,7 +19473,8 @@ function createDreamTaskExecutor(deps) {
19330
19473
  totalAtStart: backlogAtStart.total,
19331
19474
  pendingAtEnd: end.pending,
19332
19475
  totalAtEnd: end.total,
19333
- processed
19476
+ processed,
19477
+ ...backlogAtStart.category ? { category: backlogAtStart.category } : {}
19334
19478
  };
19335
19479
  return value;
19336
19480
  })()
@@ -19366,6 +19510,9 @@ function createDreamTaskExecutor(deps) {
19366
19510
  return writtenIds.length || deletedIds.length || archivedIds.length || mergedIds.length ? changes : null;
19367
19511
  }
19368
19512
  try {
19513
+ if (deps.hiddenCompletionExecutor?.capabilities.tools === false && DREAM_TASK_CAPABILITIES[config.task].requiresTools) {
19514
+ throw new HiddenCompletionRefusal("hidden_tools_unsupported", `${config.task} requires tools; opencode2 hidden completions have no tool loop`, true);
19515
+ }
19369
19516
  if (config.task === "compress-cues") {
19370
19517
  if (deps.mural?.enabled !== true) {
19371
19518
  log("[dreamer] compress-cues: skipped (mural is not enabled)");
@@ -19375,6 +19522,7 @@ function createDreamTaskExecutor(deps) {
19375
19522
  const result = await runCompressCues({
19376
19523
  db,
19377
19524
  client: deps.client,
19525
+ hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
19378
19526
  projectIdentity,
19379
19527
  parentSessionId: parent,
19380
19528
  sessionDirectory: deps.sessionDirectory,
@@ -19399,7 +19547,7 @@ function createDreamTaskExecutor(deps) {
19399
19547
  if (config.task === "review-user-memories") {
19400
19548
  const result = await reviewUserMemories({
19401
19549
  db,
19402
- client: deps.client,
19550
+ client: requireDreamClient(deps.client),
19403
19551
  parentSessionId: parent,
19404
19552
  sessionDirectory: deps.sessionDirectory,
19405
19553
  holderId,
@@ -19418,7 +19566,7 @@ function createDreamTaskExecutor(deps) {
19418
19566
  if (config.task === "map-memories") {
19419
19567
  const result = await mapMemories({
19420
19568
  db,
19421
- client: deps.client,
19569
+ client: requireDreamClient(deps.client),
19422
19570
  projectIdentity,
19423
19571
  parentSessionId: parent,
19424
19572
  sessionDirectory: deps.sessionDirectory,
@@ -19455,7 +19603,7 @@ function createDreamTaskExecutor(deps) {
19455
19603
  const memoryBefore = getMemoryCountsByStatus(db, projectIdentity);
19456
19604
  const result = await runVerify({
19457
19605
  db,
19458
- client: deps.client,
19606
+ client: requireDreamClient(deps.client),
19459
19607
  projectIdentity,
19460
19608
  parentSessionId: parent,
19461
19609
  sessionDirectory: deps.sessionDirectory,
@@ -19513,6 +19661,7 @@ function createDreamTaskExecutor(deps) {
19513
19661
  const result = await runClassify({
19514
19662
  db,
19515
19663
  client: deps.client,
19664
+ hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
19516
19665
  projectIdentity,
19517
19666
  parentSessionId: parent,
19518
19667
  sessionDirectory: deps.sessionDirectory,
@@ -19538,7 +19687,7 @@ function createDreamTaskExecutor(deps) {
19538
19687
  if (config.task === "promote-primers") {
19539
19688
  const result = await promotePrimers({
19540
19689
  db,
19541
- client: deps.client,
19690
+ client: requireDreamClient(deps.client),
19542
19691
  projectIdentity,
19543
19692
  sessionDirectory: deps.sessionDirectory,
19544
19693
  holderId,
@@ -19555,7 +19704,7 @@ function createDreamTaskExecutor(deps) {
19555
19704
  if (config.task === "refresh-primers") {
19556
19705
  const result = await refreshPrimers({
19557
19706
  db,
19558
- client: deps.client,
19707
+ client: requireDreamClient(deps.client),
19559
19708
  projectIdentity,
19560
19709
  parentSessionId: parent,
19561
19710
  sessionDirectory: deps.sessionDirectory,
@@ -19576,7 +19725,7 @@ function createDreamTaskExecutor(deps) {
19576
19725
  if (config.task === "evaluate-smart-notes") {
19577
19726
  const result = await evaluateSmartNotes({
19578
19727
  db,
19579
- client: deps.client,
19728
+ client: requireDreamClient(deps.client),
19580
19729
  projectIdentity,
19581
19730
  parentSessionId: parent,
19582
19731
  sessionDirectory: deps.sessionDirectory,
@@ -19743,7 +19892,7 @@ async function runRetrospectiveTask(config, ctx, helpers) {
19743
19892
  let promptSettled = false;
19744
19893
  try {
19745
19894
  const createResponse = await createChildSessionWithFence({
19746
- client: deps.client,
19895
+ client: requireDreamClient(deps.client),
19747
19896
  db,
19748
19897
  parentSessionId: parent ?? undefined,
19749
19898
  title: "magic-context-dream-retrospective",
@@ -19757,7 +19906,7 @@ async function runRetrospectiveTask(config, ctx, helpers) {
19757
19906
  const runChildTurn = async (system, userText) => {
19758
19907
  const remainingMs = Math.max(0, deadline - Date.now());
19759
19908
  promptSettled = false;
19760
- const run = await promptSyncWithValidatedOutputRetry(deps.client, {
19909
+ const run = await promptSyncWithValidatedOutputRetry(requireDreamClient(deps.client), {
19761
19910
  path: { id: sessionId },
19762
19911
  query: { directory: deps.sessionDirectory },
19763
19912
  body: {
@@ -19772,7 +19921,7 @@ async function runRetrospectiveTask(config, ctx, helpers) {
19772
19921
  fallbackModels: config.fallbackModels,
19773
19922
  callContext: "dreamer:retrospective",
19774
19923
  fetchOutput: async () => {
19775
- const messagesResponse = await deps.client.session.messages({
19924
+ const messagesResponse = await requireDreamClient(deps.client).session.messages({
19776
19925
  path: { id: sessionId },
19777
19926
  query: { directory: deps.sessionDirectory, limit: 50 }
19778
19927
  });
@@ -19897,7 +20046,7 @@ async function runRetrospectiveTask(config, ctx, helpers) {
19897
20046
  } finally {
19898
20047
  heartbeat.stop();
19899
20048
  await teardownChildSession({
19900
- client: deps.client,
20049
+ client: requireDreamClient(deps.client),
19901
20050
  sessionId: childSessionId,
19902
20051
  sessionDirectory: deps.sessionDirectory,
19903
20052
  promptSettled,
@@ -19931,6 +20080,7 @@ async function runAgenticTask(config, ctx, helpers) {
19931
20080
  let expiredArchived = 0;
19932
20081
  try {
19933
20082
  let curateMemories;
20083
+ let curateCategory;
19934
20084
  if (task === "curate") {
19935
20085
  expiredArchived = await archiveExpiredMemories({
19936
20086
  db,
@@ -19942,10 +20092,12 @@ async function runAgenticTask(config, ctx, helpers) {
19942
20092
  });
19943
20093
  if (leaseLost)
19944
20094
  throw new Error("Dream lease lost during expired-memory archive");
19945
- curateMemories = loadActiveMemoryPromptMemories(db, projectIdentity);
19946
- log(`[dreamer] curate pool: in_scope=${curateMemories.length} expired_archived=${expiredArchived}`);
19947
- if (curateMemories.length === 0 && expiredArchived > 0) {
19948
- const progress = formatExpiredArchiveProgress(expiredArchived);
20095
+ const scope = beginCurateCategoryRun(db, projectIdentity, loadActiveMemoryPromptMemories(db, projectIdentity));
20096
+ curateMemories = scope?.memories ?? [];
20097
+ curateCategory = scope?.category;
20098
+ log(`[dreamer] curate pool: category=${curateCategory ?? "none"} in_scope=${curateMemories.length} expired_archived=${expiredArchived}`);
20099
+ if (curateMemories.length === 0) {
20100
+ const progress = expiredArchived > 0 ? formatExpiredArchiveProgress(expiredArchived) : "curate: no populated project-memory category";
19949
20101
  helpers.recordRun("completed", null, {
19950
20102
  memoryChanges: helpers.computeMemoryDelta(memoryBefore),
19951
20103
  progress
@@ -19957,10 +20109,10 @@ async function runAgenticTask(config, ctx, helpers) {
19957
20109
  projectPath: projectIdentity,
19958
20110
  lastDreamAt: lastRunAt ? String(lastRunAt) : null,
19959
20111
  existingDocs,
19960
- curate: curateMemories ? { memories: curateMemories } : undefined
20112
+ curate: curateMemories && curateCategory ? { category: curateCategory, memories: curateMemories } : undefined
19961
20113
  });
19962
20114
  const createResponse = await createChildSessionWithFence({
19963
- client: deps.client,
20115
+ client: requireDreamClient(deps.client),
19964
20116
  db,
19965
20117
  parentSessionId: parent ?? undefined,
19966
20118
  title: `magic-context-dream-${task}`,
@@ -19974,7 +20126,7 @@ async function runAgenticTask(config, ctx, helpers) {
19974
20126
  throw new Error("Dreamer could not create its child session.");
19975
20127
  const sessionId = childSessionId;
19976
20128
  const remainingMs = Math.max(0, deadline - Date.now());
19977
- const run = await promptSyncWithValidatedOutputRetry(deps.client, {
20129
+ const run = await promptSyncWithValidatedOutputRetry(requireDreamClient(deps.client), {
19978
20130
  path: { id: sessionId },
19979
20131
  query: { directory: docsDir },
19980
20132
  body: {
@@ -19989,7 +20141,7 @@ async function runAgenticTask(config, ctx, helpers) {
19989
20141
  fallbackModels: config.fallbackModels,
19990
20142
  callContext: `dreamer:${task}`,
19991
20143
  fetchOutput: async () => {
19992
- const messagesResponse = await deps.client.session.messages({
20144
+ const messagesResponse = await requireDreamClient(deps.client).session.messages({
19993
20145
  path: { id: sessionId },
19994
20146
  query: {
19995
20147
  directory: docsDir,
@@ -20049,22 +20201,40 @@ async function runAgenticTask(config, ctx, helpers) {
20049
20201
  }
20050
20202
  }
20051
20203
  const curateOutput = task === "curate" ? run.validated : undefined;
20204
+ const curateScopeProgress = task === "curate" && curateCategory && curateMemories ? `curate: ${curateCategory} (${curateMemories.length})` : null;
20052
20205
  const progress = [
20206
+ curateScopeProgress,
20053
20207
  expiredArchived > 0 ? formatExpiredArchiveProgress(expiredArchived) : null,
20054
20208
  curateOutput && curateOutput.memoryOperations.completedActions.length > 0 ? formatCurateMemoryOperations(curateOutput.memoryOperations.completedActions) : null,
20055
20209
  curateRefused > 0 ? `curate: refused ${curateRefused} unsafe mutation(s)` : null
20056
20210
  ].filter((value) => Boolean(value)).join("; ");
20211
+ const curateCount = task === "curate" && curateCategory ? loadActiveMemoryPromptMemories(db, projectIdentity).filter((memory) => curateCategoryForMemoryCategory(memory.category) === curateCategory).length : undefined;
20212
+ const curateBacklog = curateCount !== undefined && curateCategory ? {
20213
+ pending: curateCount,
20214
+ total: curateCount,
20215
+ category: curateCategory
20216
+ } : undefined;
20057
20217
  helpers.recordRun("completed", null, {
20058
20218
  memoryChanges: helpers.computeMemoryDelta(memoryBefore),
20059
- progress: progress || null
20219
+ progress: progress || null,
20220
+ backlogAfter: curateBacklog
20060
20221
  });
20061
- return { status: "completed", ...progress ? { detail: progress } : {} };
20222
+ return {
20223
+ status: "completed",
20224
+ ...progress ? { detail: progress } : {},
20225
+ ...curateBacklog ? { backlog: curateBacklog } : {},
20226
+ ...curateCategory ? {
20227
+ schedulePatch: {
20228
+ taskStateJson: curateTaskStateAfterSuccess(db, projectIdentity, curateCategory)
20229
+ }
20230
+ } : {}
20231
+ };
20062
20232
  } finally {
20063
20233
  heartbeat.stop();
20064
20234
  if (childSessionId)
20065
20235
  takeCurateSafetyRefusalCount(childSessionId);
20066
20236
  await teardownChildSession({
20067
- client: deps.client,
20237
+ client: requireDreamClient(deps.client),
20068
20238
  sessionId: childSessionId,
20069
20239
  sessionDirectory: docsDir,
20070
20240
  promptSettled,
@@ -20133,6 +20303,7 @@ function advanceAfterRun(db, projectIdentity, due, finishedAt, status, error, sc
20133
20303
  lastStatus: status,
20134
20304
  lastError: error,
20135
20305
  retryCount: 0,
20306
+ taskStateJson: schedulePatch?.taskStateJson,
20136
20307
  retrospectiveWatermarkMs: schedulePatch?.retrospectiveWatermarkMs
20137
20308
  });
20138
20309
  }
@@ -20225,7 +20396,7 @@ async function runDomainGroup(deps, group, cb) {
20225
20396
  const finishedAt = Date.now();
20226
20397
  if (outcome.status === "completed") {
20227
20398
  advanceAfterRun(db, projectIdentity, due, finishedAt, "completed", null, outcome.schedulePatch);
20228
- cb?.onRan?.(due.config.task, outcome.detail);
20399
+ cb?.onRan?.(due.config.task, outcome.detail, outcome.backlog);
20229
20400
  } else if (outcome.transient) {
20230
20401
  recordTransientFailure(db, projectIdentity, due, finishedAt, outcome.error ?? null);
20231
20402
  cb?.onFailed?.(due.config.task, outcome.failureDetail ?? outcome.error);
@@ -20292,6 +20463,7 @@ async function runManualDream(deps) {
20292
20463
  return result;
20293
20464
  }
20294
20465
  const groups = new Map;
20466
+ const runLocalBacklogs = {};
20295
20467
  for (const d of gated) {
20296
20468
  const kind = leaseKindFor(d.config.task);
20297
20469
  const arr = groups.get(kind) ?? [];
@@ -20301,10 +20473,12 @@ async function runManualDream(deps) {
20301
20473
  await Promise.all([...groups.values()].map((group) => runDomainGroup({ ...deps, executor: deps.executor }, group, {
20302
20474
  forceGate,
20303
20475
  leaseWaitMs: MANUAL_RUN_LEASE_WAIT_MS,
20304
- onRan: (t, detail) => {
20476
+ onRan: (t, detail, backlog) => {
20305
20477
  result.ran.push(t);
20306
20478
  if (detail)
20307
20479
  result.details?.push(detail);
20480
+ if (backlog)
20481
+ runLocalBacklogs[t] = backlog;
20308
20482
  },
20309
20483
  onFailed: (task, error) => {
20310
20484
  result.failed.push(task);
@@ -20313,7 +20487,10 @@ async function runManualDream(deps) {
20313
20487
  },
20314
20488
  onBusy: (t) => result.deferredBusy.push(t)
20315
20489
  })));
20316
- result.backlogAfter = getDreamTaskBacklogs(deps.db, deps.projectIdentity, selectedTaskNames);
20490
+ result.backlogAfter = {
20491
+ ...getDreamTaskBacklogs(deps.db, deps.projectIdentity, selectedTaskNames),
20492
+ ...runLocalBacklogs
20493
+ };
20317
20494
  return result;
20318
20495
  }
20319
20496
  async function runDueTasksForProject(deps) {
@@ -24972,6 +25149,10 @@ function statusSummaryFromDetail(detail) {
24972
25149
  if ((detail.loggerDiagnostics?.swallowedWriteCount ?? 0) > 0) {
24973
25150
  warnings.push("status_log_unavailable");
24974
25151
  }
25152
+ if (detail.memoryMirror?.stalled)
25153
+ warnings.push("memory_mirror_stalled");
25154
+ if (detail.memoryAuthorityMismatch)
25155
+ warnings.push("memory_authority_mismatch");
24975
25156
  return {
24976
25157
  inputTokens: detail.inputTokens,
24977
25158
  usableContextTokens: detail.contextLimit,
@@ -25108,6 +25289,9 @@ function formatStatusDiagnosticsMarkdown(detail) {
25108
25289
  `- **${formatCacheTtlDisplay({ value: detail.cacheTtl, source: detail.cacheTtlSource ?? "session", modelKey: detail.cacheTtlModelKey })}**; ${formatCacheLane(detail)}`,
25109
25290
  `- **Historian:** ${[historianState, ...historianDetails].join("; ")}`,
25110
25291
  ...detail.hostBackendsModuleSide ? [`- ${RUST_MODE_HOST_PATHS_LINE}`] : [],
25292
+ ...detail.memoryMirror ? [
25293
+ `- **Memory mirror:** cursor ${formatCount2(detail.memoryMirror.cursor)} / ${detail.memoryMirror.feedHead === null ? "unknown" : formatCount2(detail.memoryMirror.feedHead)}; ${formatCount2(detail.memoryMirror.liveRows)} live rows; ${detail.memoryMirror.stalled ? `stalled (${detail.memoryMirror.code})` : "advancing or caught up"}`
25294
+ ] : [],
25111
25295
  `- **Memory:** ${formatCount2(detail.memoryCount)} active; ${formatCount2(detail.memoryBlockCount)} injected`,
25112
25296
  `- **Tags:** ${formatCount2(detail.activeTags)} active, ${formatCount2(detail.droppedTags)} dropped; ${formatCount2(detail.pendingOpsCount)} pending drops`,
25113
25297
  `- **Execute threshold:** ${detail.executeThreshold.toFixed(1)}%${detail.executeThresholdClamped ? " (clamped)" : ""}`
@@ -25118,6 +25302,12 @@ function formatStatusDiagnosticsMarkdown(detail) {
25118
25302
  if (detail.lastTransformError) {
25119
25303
  lines.push(`- **Warning:** ${renderUserFacingFailure("transform_update_failed")}`);
25120
25304
  }
25305
+ if (detail.memoryMirror?.stalled) {
25306
+ lines.push(`- **Warning:** ${renderUserFacingFailure("memory_mirror_stalled")}`);
25307
+ }
25308
+ if (detail.memoryAuthorityMismatch) {
25309
+ lines.push(`- **Warning:** ${renderUserFacingFailure("memory_authority_mismatch")}`);
25310
+ }
25121
25311
  return lines.join(`
25122
25312
  `);
25123
25313
  }
@@ -29005,9 +29195,16 @@ function buildSidebarSnapshotRpcResponse(db, sessionId, directory, liveSessionSt
29005
29195
  }
29006
29196
  function buildStatusDetail(db, sessionId, directory, modelKey, config, liveSessionState, injectionBudgetTokens, moduleStatus, compactionEnabled = true) {
29007
29197
  const base = buildSidebarSnapshot(db, sessionId, directory, liveSessionState, injectionBudgetTokens, config, moduleStatus, compactionEnabled);
29198
+ const rustMode = config?.transform_mode === "rust";
29199
+ const projectIdentity = rustMode ? resolveProjectIdentity(directory) : null;
29200
+ const moduleMemoryAuthority = moduleStatus?.authority?.memories;
29201
+ const moduleMemoryState = moduleMemoryAuthority?.state;
29202
+ const moduleFeedHead = moduleStatus?.memory_mirror?.feed_head;
29008
29203
  const detail = {
29009
29204
  ...base,
29010
- hostBackendsModuleSide: config?.transform_mode === "rust",
29205
+ hostBackendsModuleSide: rustMode,
29206
+ memoryMirror: rustMode ? getMemoryMirrorStatus(db, moduleFeedHead) : undefined,
29207
+ memoryAuthorityMismatch: rustMode && moduleStatus?.authority !== undefined && projectIdentity !== null && getAuthorityManagedMarker(db, projectIdentity) !== null && (moduleMemoryState === "TS" || moduleMemoryAuthority === null),
29011
29208
  activeProfile: typeof config?.profile === "string" ? config.profile : null,
29012
29209
  tagCounter: 0,
29013
29210
  activeTags: 0,
@@ -29461,9 +29658,9 @@ function registerRpcHandlers(rpcServer, args) {
29461
29658
  return { count: buildCompartmentCount(db, sessionId, moduleStatus) };
29462
29659
  });
29463
29660
  const buildManagedCtx = async (db) => {
29464
- const { deriveHistorianChunkTokens, resolveHistorianContextLimit } = await import("./derive-budgets-s2pgnnm4.js");
29661
+ const { deriveHistorianChunkTokens, resolveHistorianContextLimit } = await import("./derive-budgets-v1fkhjjr.js");
29465
29662
  const { resolveHistorianModel } = await import("./model-resolution-dxatzjde.js");
29466
- const { userMemoryCollectionEnabled } = await import("./task-config-hnv93r7p.js");
29663
+ const { userMemoryCollectionEnabled } = await import("./task-config-cv8k9y8r.js");
29467
29664
  const DEFAULT_HISTORIAN_TIMEOUT_MS = 600000;
29468
29665
  const historianModel = resolveHistorianModel(config, "opencode");
29469
29666
  return {
@@ -29494,8 +29691,8 @@ function registerRpcHandlers(rpcServer, args) {
29494
29691
  const db = getDb();
29495
29692
  if (!db)
29496
29693
  return { ok: false, error: "db unavailable" };
29497
- const { runManagedRecomp } = await import("./recomp-orchestrator-447vycpt.js");
29498
- const { sendIgnoredMessage } = await import("./send-session-notification-2mzgd3zf.js");
29694
+ const { runManagedRecomp } = await import("./recomp-orchestrator-k20sfpm2.js");
29695
+ const { sendIgnoredMessage } = await import("./send-session-notification-xnypkxpx.js");
29499
29696
  log(`[rpc] recomp requested for session ${sessionId}`);
29500
29697
  const ctx = await buildManagedCtx(db);
29501
29698
  runManagedRecomp(ctx, sessionId).then((message) => {
@@ -29513,8 +29710,8 @@ function registerRpcHandlers(rpcServer, args) {
29513
29710
  const db = getDb();
29514
29711
  if (!db)
29515
29712
  return { ok: false, error: "db unavailable" };
29516
- const { runManagedUpgrade } = await import("./recomp-orchestrator-447vycpt.js");
29517
- const { sendIgnoredMessage } = await import("./send-session-notification-2mzgd3zf.js");
29713
+ const { runManagedUpgrade } = await import("./recomp-orchestrator-k20sfpm2.js");
29714
+ const { sendIgnoredMessage } = await import("./send-session-notification-xnypkxpx.js");
29518
29715
  log(`[rpc] session-upgrade requested for session ${sessionId}`);
29519
29716
  const ctx = await buildManagedCtx(db);
29520
29717
  runManagedUpgrade(ctx, sessionId).then((message) => {
@@ -29530,7 +29727,7 @@ function registerRpcHandlers(rpcServer, args) {
29530
29727
  if (!db)
29531
29728
  return { ok: false, error: "db unavailable" };
29532
29729
  try {
29533
- const { updateSessionMeta } = await import("./storage-meta-session-fkmfhswa.js");
29730
+ const { updateSessionMeta } = await import("./storage-meta-session-x3j0q9qy.js");
29534
29731
  updateSessionMeta(db, sessionId, { upgradeRemindedAt: Date.now() });
29535
29732
  return { ok: true };
29536
29733
  } catch (error) {
@@ -30179,7 +30376,8 @@ function applyCavemanCleanup(sessionId, db, targets, tags, config) {
30179
30376
  compressedToLite: 0,
30180
30377
  compressedToFull: 0,
30181
30378
  compressedToUltra: 0,
30182
- mutatedTextTags: 0
30379
+ mutatedTextTags: 0,
30380
+ textReductions: []
30183
30381
  };
30184
30382
  if (!config.enabled)
30185
30383
  return result;
@@ -30219,9 +30417,15 @@ function applyCavemanCleanup(sessionId, db, targets, tags, config) {
30219
30417
  const target = targets.get(tag.tagNumber);
30220
30418
  if (!target)
30221
30419
  continue;
30420
+ const priorContent = target.getContent?.();
30222
30421
  const didMutate = target.setContent(compressed);
30223
- if (didMutate)
30422
+ if (didMutate) {
30224
30423
  result.mutatedTextTags += 1;
30424
+ result.textReductions.push({
30425
+ tagNumber: tag.tagNumber,
30426
+ removedCharacters: Math.max(0, (priorContent?.length ?? originalText.length) - compressed.length)
30427
+ });
30428
+ }
30225
30429
  updateCavemanDepth(db, sessionId, tag.tagNumber, targetDepth);
30226
30430
  if (targetDepth === DEPTH_LITE)
30227
30431
  result.compressedToLite += 1;
@@ -32018,6 +32222,73 @@ function dropStaleReduceCalls(messages, frozenIds, options = {}) {
32018
32222
  return { didDrop, newlyStrippedIds };
32019
32223
  }
32020
32224
 
32225
+ // src/hooks/magic-context/dropped-token-estimate.ts
32226
+ var TAG_QUERY_CHUNK_SIZE = 900;
32227
+ var ESTIMATED_CHARACTERS_PER_TOKEN = 3.5;
32228
+ function estimateCharacters(characters) {
32229
+ return Math.ceil(Math.max(0, characters) / ESTIMATED_CHARACTERS_PER_TOKEN);
32230
+ }
32231
+ function persistedCountOrByteEstimate(count, bytes) {
32232
+ return typeof count === "number" && Number.isFinite(count) ? Math.max(0, count) : estimateCharacters(bytes);
32233
+ }
32234
+ function loadPersistedTagTokenCounts(db, sessionId, tagNumbers) {
32235
+ const countsByTag = new Map;
32236
+ for (let offset = 0;offset < tagNumbers.length; offset += TAG_QUERY_CHUNK_SIZE) {
32237
+ const chunk = tagNumbers.slice(offset, offset + TAG_QUERY_CHUNK_SIZE);
32238
+ const placeholders = chunk.map(() => "?").join(",");
32239
+ const rows = db.prepare(`SELECT tag_number AS tagNumber,
32240
+ type,
32241
+ byte_size AS byteSize,
32242
+ input_byte_size AS inputByteSize,
32243
+ reasoning_byte_size AS reasoningByteSize,
32244
+ token_count AS tokenCount,
32245
+ input_token_count AS inputTokenCount,
32246
+ reasoning_token_count AS reasoningTokenCount
32247
+ FROM tags
32248
+ WHERE session_id = ? AND tag_number IN (${placeholders})`).all(sessionId, ...chunk);
32249
+ for (const row of rows)
32250
+ countsByTag.set(row.tagNumber, row);
32251
+ }
32252
+ return countsByTag;
32253
+ }
32254
+ function estimateDroppedTokensFromTagReductions(db, sessionId, reductions) {
32255
+ if (reductions.length === 0)
32256
+ return 0;
32257
+ const structuralByTag = new Map;
32258
+ const partialCharactersByTag = new Map;
32259
+ for (const reduction of reductions) {
32260
+ if (reduction.mode === "partial") {
32261
+ partialCharactersByTag.set(reduction.tagNumber, (partialCharactersByTag.get(reduction.tagNumber) ?? 0) + Math.max(0, reduction.removedCharacters));
32262
+ continue;
32263
+ }
32264
+ const prior = structuralByTag.get(reduction.tagNumber);
32265
+ if (!prior || reduction.mode === "full") {
32266
+ structuralByTag.set(reduction.tagNumber, reduction);
32267
+ }
32268
+ }
32269
+ const tagNumbers = [...new Set([...structuralByTag.keys(), ...partialCharactersByTag.keys()])];
32270
+ const countsByTag = loadPersistedTagTokenCounts(db, sessionId, tagNumbers);
32271
+ let total = 0;
32272
+ for (const [tagNumber, reduction] of structuralByTag) {
32273
+ const row = countsByTag.get(tagNumber);
32274
+ if (!row)
32275
+ continue;
32276
+ total += persistedCountOrByteEstimate(row.tokenCount, row.byteSize);
32277
+ if (reduction.mode === "full") {
32278
+ total += persistedCountOrByteEstimate(row.reasoningTokenCount, row.reasoningByteSize);
32279
+ if (row.type === "tool") {
32280
+ total += persistedCountOrByteEstimate(row.inputTokenCount, row.inputByteSize);
32281
+ }
32282
+ }
32283
+ }
32284
+ for (const [tagNumber, removedCharacters] of partialCharactersByTag) {
32285
+ if (structuralByTag.has(tagNumber) || !countsByTag.has(tagNumber))
32286
+ continue;
32287
+ total += estimateCharacters(removedCharacters);
32288
+ }
32289
+ return Math.max(0, Math.round(total));
32290
+ }
32291
+
32021
32292
  // src/hooks/magic-context/fold-execution-gate.ts
32022
32293
  function foldExecutesThisPass(foldDue, materialized) {
32023
32294
  return foldDue && materialized;
@@ -32088,6 +32359,7 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
32088
32359
  let emergencyReclaimedTokens = 0;
32089
32360
  let deduplicatedTools = 0;
32090
32361
  let droppedInjections = 0;
32362
+ const droppedTokenReductions = [];
32091
32363
  if (config.emergency) {
32092
32364
  const emergency = config.emergency;
32093
32365
  const priorInputSample = getEmergencyInputSample(db, sessionId);
@@ -32123,6 +32395,10 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
32123
32395
  updateTagDropMode(db, sessionId, tag.tagNumber, skeleton ? "truncated" : "full");
32124
32396
  droppedTools++;
32125
32397
  emergencyDroppedTools++;
32398
+ droppedTokenReductions.push({
32399
+ tagNumber: tag.tagNumber,
32400
+ mode: result === "removed" ? "full" : "truncated"
32401
+ });
32126
32402
  emergencyReclaimedTokens += estimateEmergencyDropReclaimTokens(tag);
32127
32403
  }
32128
32404
  }
@@ -32157,12 +32433,18 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
32157
32433
  const strippedSource = stripTagPrefix(stripped);
32158
32434
  if (strippedSource.trim().length === 0) {
32159
32435
  const dropResult = target.drop?.() ?? "absent";
32160
- const didReplace = dropResult === "absent" ? target.setContent(`[dropped §${tag.tagNumber}§]`) : false;
32436
+ const replacement = `[dropped §${tag.tagNumber}§]`;
32437
+ const didReplace = dropResult === "absent" ? target.setContent(replacement) : false;
32161
32438
  if (dropResult === "removed" || dropResult === "absent") {
32162
32439
  replaceSourceContent(db, sessionId, tag.tagNumber, "");
32163
32440
  updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
32164
32441
  if (dropResult === "removed" || didReplace) {
32165
32442
  droppedInjections++;
32443
+ droppedTokenReductions.push(dropResult === "removed" ? { tagNumber: tag.tagNumber, mode: "full" } : {
32444
+ tagNumber: tag.tagNumber,
32445
+ mode: "partial",
32446
+ removedCharacters: Math.max(0, content.length - replacement.length)
32447
+ });
32166
32448
  }
32167
32449
  }
32168
32450
  } else {
@@ -32170,6 +32452,11 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
32170
32452
  if (didSet) {
32171
32453
  replaceSourceContent(db, sessionId, tag.tagNumber, strippedSource);
32172
32454
  droppedInjections++;
32455
+ droppedTokenReductions.push({
32456
+ tagNumber: tag.tagNumber,
32457
+ mode: "partial",
32458
+ removedCharacters: Math.max(0, content.length - stripped.length)
32459
+ });
32173
32460
  }
32174
32461
  }
32175
32462
  }
@@ -32209,6 +32496,10 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
32209
32496
  updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
32210
32497
  if (result === "removed" || result === "truncated") {
32211
32498
  deduplicatedTools++;
32499
+ droppedTokenReductions.push({
32500
+ tagNumber: tag.tagNumber,
32501
+ mode: result === "removed" ? "full" : "truncated"
32502
+ });
32212
32503
  }
32213
32504
  }
32214
32505
  }
@@ -32227,6 +32518,10 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
32227
32518
  });
32228
32519
  compressedTextTags = cavemanResult.compressedToLite + cavemanResult.compressedToFull + cavemanResult.compressedToUltra;
32229
32520
  mutatedTextTags = cavemanResult.mutatedTextTags;
32521
+ droppedTokenReductions.push(...cavemanResult.textReductions.map((reduction) => ({
32522
+ ...reduction,
32523
+ mode: "partial"
32524
+ })));
32230
32525
  }
32231
32526
  return {
32232
32527
  droppedTools,
@@ -32235,7 +32530,8 @@ function applyHeuristicCleanup(sessionId, db, targets, messageTagNumbers, config
32235
32530
  emergencyDroppedTools,
32236
32531
  emergencyReclaimedTokens,
32237
32532
  compressedTextTags,
32238
- mutatedTextTags
32533
+ mutatedTextTags,
32534
+ droppedTokenReductions
32239
32535
  };
32240
32536
  }
32241
32537
  function extractToolInfo(part) {
@@ -32475,7 +32771,7 @@ var RECENT_TOOL_SKELETON_WINDOW = 20;
32475
32771
  function buildReplacementContent(tagId) {
32476
32772
  return `[dropped §${tagId}§]`;
32477
32773
  }
32478
- function applyPendingOperations(sessionId, db, targets, protectedTagIds, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set) {
32774
+ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set, onTagReduced) {
32479
32775
  let didMutateMessage = false;
32480
32776
  let admitted = false;
32481
32777
  let startedAt = 0;
@@ -32484,6 +32780,7 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
32484
32780
  admitted = true;
32485
32781
  startedAt = performance.now();
32486
32782
  const tags = preloadedTags ?? getTagsBySession(db, sessionId);
32783
+ const tagById = new Map(tags.map((tag) => [tag.tagNumber, tag]));
32487
32784
  const tagStatusById = new Map(tags.map((tag) => [tag.tagNumber, tag.status]));
32488
32785
  const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
32489
32786
  const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
@@ -32516,6 +32813,7 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
32516
32813
  continue;
32517
32814
  }
32518
32815
  didMutateMessage = true;
32816
+ onTagReduced?.({ tagNumber: pendingOp.tagId, mode: "edit_marker" });
32519
32817
  updateTagDropMode(db, sessionId, pendingOp.tagId, "edit_marker");
32520
32818
  shouldPersistDrop = true;
32521
32819
  } else if (skeletonWindow.has(pendingOp.tagId)) {
@@ -32525,6 +32823,7 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
32525
32823
  }
32526
32824
  if (truncResult === "truncated") {
32527
32825
  didMutateMessage = true;
32826
+ onTagReduced?.({ tagNumber: pendingOp.tagId, mode: "truncated" });
32528
32827
  }
32529
32828
  updateTagDropMode(db, sessionId, pendingOp.tagId, "truncated");
32530
32829
  shouldPersistDrop = true;
@@ -32535,14 +32834,24 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
32535
32834
  }
32536
32835
  if (dropResult === "removed") {
32537
32836
  didMutateMessage = true;
32837
+ onTagReduced?.({ tagNumber: pendingOp.tagId, mode: "full" });
32538
32838
  }
32539
32839
  updateTagDropMode(db, sessionId, pendingOp.tagId, "full");
32540
32840
  shouldPersistDrop = true;
32541
32841
  }
32542
32842
  } else if (target) {
32543
- const changed = target.setContent(buildReplacementContent(pendingOp.tagId));
32544
- if (changed)
32843
+ const replacement = buildReplacementContent(pendingOp.tagId);
32844
+ const priorContent = target.getContent?.();
32845
+ const changed = target.setContent(replacement);
32846
+ if (changed) {
32545
32847
  didMutateMessage = true;
32848
+ const originalCharacters = typeof priorContent === "string" ? priorContent.length : tagById.get(pendingOp.tagId)?.byteSize ?? replacement.length;
32849
+ onTagReduced?.({
32850
+ tagNumber: pendingOp.tagId,
32851
+ mode: "partial",
32852
+ removedCharacters: Math.max(0, originalCharacters - replacement.length)
32853
+ });
32854
+ }
32546
32855
  shouldPersistDrop = true;
32547
32856
  } else if (!synthetic) {
32548
32857
  shouldPersistDrop = true;
@@ -33530,6 +33839,10 @@ function clearPendingCompactionMarkerAfterSuccessfulDrain(args) {
33530
33839
  sessionLog(args.sessionId, "compaction-marker drain: CAS-clear failed but no pending blob remains; another drain already cleared it");
33531
33840
  return "cas-lost-already-cleared";
33532
33841
  }
33842
+ var defaultCompactionMarkerStrategy = {
33843
+ applyDeferred: applyDeferredCompactionMarker,
33844
+ reconcile: reconcileMarkerRepresentation
33845
+ };
33533
33846
  async function abortSessionFailClosed(client, sessionId) {
33534
33847
  if (typeof client.session?.abort !== "function") {
33535
33848
  throw new Error("OpenCode session.abort is unavailable");
@@ -33753,7 +34066,7 @@ async function runPostTransformPhase(args) {
33753
34066
  let heuristicOrReasoningDidMutate = false;
33754
34067
  let droppedCount = 0;
33755
34068
  let droppedTokens = 0;
33756
- const tokensBeforeReductions = isCacheBustingPass || shouldApplyPendingOps ? estimateTokens(JSON.stringify(args.messages)) : 0;
34069
+ const droppedTokenReductions = [];
33757
34070
  let emergencyReclaimedTokens = 0;
33758
34071
  let emergency = false;
33759
34072
  let m0M1InjectedThisPass = false;
@@ -33775,7 +34088,7 @@ async function runPostTransformPhase(args) {
33775
34088
  const applyReason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : foldExecutedThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : `scheduler_execute (scheduler=${args.schedulerDecision})`;
33776
34089
  sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${formatPendingOpsDepth()}, context=${args.contextUsage.percentage.toFixed(1)}%`);
33777
34090
  const tApply = performance.now();
33778
- pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.contextUsage.percentage >= 95 ? newestCtxReduceTagNumbers(getTagsBySession(args.db, args.sessionId)) : args.protectedTagIds, undefined, pendingOps);
34091
+ pendingOpsDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.contextUsage.percentage >= 95 ? newestCtxReduceTagNumbers(getTagsBySession(args.db, args.sessionId)) : args.protectedTagIds, undefined, pendingOps, [], new Set, (reduction) => droppedTokenReductions.push(reduction));
33779
34092
  if (pendingOpsDidMutate) {
33780
34093
  rideSignals.agentDrop = true;
33781
34094
  isCacheBustingPass = hasReclaimRide(rideSignals);
@@ -33828,7 +34141,11 @@ async function runPostTransformPhase(args) {
33828
34141
  emergencyDroppedTools: cleanup.emergencyDroppedTools,
33829
34142
  emergencyReclaimedTokens: cleanup.emergencyReclaimedTokens,
33830
34143
  compressedTextTags: cleanup.compressedTextTags + ridingCleanup.compressedTextTags,
33831
- mutatedTextTags: cleanup.mutatedTextTags + ridingCleanup.mutatedTextTags
34144
+ mutatedTextTags: cleanup.mutatedTextTags + ridingCleanup.mutatedTextTags,
34145
+ droppedTokenReductions: [
34146
+ ...cleanup.droppedTokenReductions,
34147
+ ...ridingCleanup.droppedTokenReductions
34148
+ ]
33832
34149
  };
33833
34150
  routineCleanupApplied = true;
33834
34151
  }
@@ -33840,6 +34157,7 @@ async function runPostTransformPhase(args) {
33840
34157
  droppedCount += cleanup.droppedTools + cleanup.deduplicatedTools + cleanup.droppedInjections + cleanup.mutatedTextTags;
33841
34158
  emergency ||= cleanup.emergencyDroppedTools > 0;
33842
34159
  emergencyReclaimedTokens += cleanup.emergencyReclaimedTokens;
34160
+ droppedTokenReductions.push(...cleanup.droppedTokenReductions);
33843
34161
  const t7 = performance.now();
33844
34162
  const clearedReasoning = routineCleanupApplied && canUseEmptySentinels ? clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge) : 0;
33845
34163
  if (routineCleanupApplied && canUseEmptySentinels) {
@@ -33927,7 +34245,7 @@ async function runPostTransformPhase(args) {
33927
34245
  }
33928
34246
  autoReclaimTargetCount = syntheticPendingOps.length;
33929
34247
  if (syntheticPendingOps.length > 0) {
33930
- autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTagIds, undefined, [], syntheticPendingOps, editMarkerTagIds);
34248
+ autoReclaimDidMutate = applyPendingOperations(args.sessionId, args.db, args.targets, args.protectedTagIds, undefined, [], syntheticPendingOps, editMarkerTagIds, (reduction) => droppedTokenReductions.push(reduction));
33931
34249
  if (autoReclaimDidMutate) {
33932
34250
  droppedCount += syntheticPendingOps.length;
33933
34251
  autoReclaimDidMutateThisPass = true;
@@ -33965,7 +34283,7 @@ async function runPostTransformPhase(args) {
33965
34283
  updateSessionMeta2(args.db, args.sessionId, { lastTransformError: getErrorMessage(error) });
33966
34284
  }
33967
34285
  if (isCacheBustingPass) {
33968
- droppedTokens = Math.max(0, tokensBeforeReductions - estimateTokens(JSON.stringify(args.messages)));
34286
+ droppedTokens = estimateDroppedTokensFromTagReductions(args.db, args.sessionId, droppedTokenReductions);
33969
34287
  }
33970
34288
  const replaySnapshot = !compactionOff ? loadPostprocessReplaySnapshot(args.db, args.sessionId) : undefined;
33971
34289
  if (canUseEmptySentinels && !compactionOff && replaySnapshot) {
@@ -34131,7 +34449,7 @@ async function runPostTransformPhase(args) {
34131
34449
  suppressV12HistoryDrain = true;
34132
34450
  sessionLog(args.sessionId, `compaction-marker drain: pending ordinal ${pending.ordinal} is newer than consumed boundary ${args.pendingCompartmentInjection?.compartmentEndMessage ?? "<none>"}; preserving deferred history refresh signal`);
34133
34451
  } else {
34134
- const outcome = applyDeferredCompactionMarker(args.db, args.sessionId, pending, args.sessionDirectory);
34452
+ const outcome = (args.compactionMarkerStrategy ?? defaultCompactionMarkerStrategy).applyDeferred(args.db, args.sessionId, pending, args.sessionDirectory);
34135
34453
  switch (outcome.kind) {
34136
34454
  case "applied":
34137
34455
  case "already-current":
@@ -34156,7 +34474,7 @@ async function runPostTransformPhase(args) {
34156
34474
  }
34157
34475
  }
34158
34476
  if (!compactionOff) {
34159
- reconcileMarkerRepresentation(args.messages, persistedCompactionMarkerState, {
34477
+ (args.compactionMarkerStrategy ?? defaultCompactionMarkerStrategy).reconcile(args.messages, persistedCompactionMarkerState, {
34160
34478
  db: args.db,
34161
34479
  sessionId: args.sessionId,
34162
34480
  tagger: args.tagger,
@@ -34848,6 +35166,10 @@ function responseValue(response) {
34848
35166
  throw new Error("module transform returned a non-object response");
34849
35167
  }
34850
35168
  function mirrorProjectionKey(response) {
35169
+ const memoryMirrorHead = response.memory_mirror_head;
35170
+ if (typeof memoryMirrorHead === "number" && Number.isSafeInteger(memoryMirrorHead) && memoryMirrorHead >= 0) {
35171
+ return JSON.stringify(["memory-feed", memoryMirrorHead]);
35172
+ }
34851
35173
  const rowVersion = response.row_version;
34852
35174
  if (typeof rowVersion !== "number" || !Number.isSafeInteger(rowVersion) || rowVersion < 0) {
34853
35175
  return null;
@@ -36940,7 +37262,7 @@ async function runCompartmentPhaseImpl(args) {
36940
37262
  sessionLog(args.sessionId, `transform: skipping compartment start, no eligible history before protected tail (beyond ${lastObservedCompartmentEnd})`);
36941
37263
  updateSessionMeta2(args.db, args.sessionId, { compartmentInProgress: false });
36942
37264
  compartmentInProgress = false;
36943
- } else if (!args.client) {
37265
+ } else if (!args.client && !args.hiddenCompletionExecutor) {
36944
37266
  sessionLog(args.sessionId, "transform: cannot start compartment agent without client");
36945
37267
  updateSessionMeta2(args.db, args.sessionId, { compartmentInProgress: false });
36946
37268
  compartmentInProgress = false;
@@ -36948,6 +37270,8 @@ async function runCompartmentPhaseImpl(args) {
36948
37270
  sessionLog(args.sessionId, "transform: compartmentInProgress flag set, starting agent");
36949
37271
  startCompartmentAgent({
36950
37272
  client: args.client,
37273
+ hiddenCompletionExecutor: args.hiddenCompletionExecutor,
37274
+ compactionMarkerStrategy: args.compactionMarkerStrategy,
36951
37275
  db: args.db,
36952
37276
  sessionId: args.sessionId,
36953
37277
  historianChunkTokens: args.historianChunkTokens,
@@ -36976,10 +37300,12 @@ async function runCompartmentPhaseImpl(args) {
36976
37300
  let awaitedCompartmentRun = false;
36977
37301
  if (historianRunnable && args.canRunCompartments && !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE) {
36978
37302
  let activeRun = getActiveCompartmentRun(args.sessionId);
36979
- if (!activeRun && hasEligibleHistoryForCompartment() && args.client) {
37303
+ if (!activeRun && hasEligibleHistoryForCompartment() && (args.client || args.hiddenCompletionExecutor)) {
36980
37304
  sessionLog(args.sessionId, `transform: 95% reached (${args.contextUsage.percentage.toFixed(1)}%), force-starting compartment agent and blocking`);
36981
37305
  startCompartmentAgent({
36982
37306
  client: args.client,
37307
+ hiddenCompletionExecutor: args.hiddenCompletionExecutor,
37308
+ compactionMarkerStrategy: args.compactionMarkerStrategy,
36983
37309
  db: args.db,
36984
37310
  sessionId: args.sessionId,
36985
37311
  historianChunkTokens: args.historianChunkTokens,
@@ -37214,7 +37540,16 @@ function scheduleTsAuthorityRecovery(args) {
37214
37540
  }
37215
37541
  });
37216
37542
  }
37543
+ function resolveTransformHostSeams(deps) {
37544
+ return {
37545
+ hostRawMessages: deps.hostRawMessages ?? readRawSessionMessages,
37546
+ hostProtectedTailBoundary: deps.hostProtectedTailBoundary ?? resolveOpenCodeProtectedTailBoundary,
37547
+ hostModelFallback: deps.hostModelFallback ?? findLastAssistantModelFromOpenCodeDb,
37548
+ hostRefuse: deps.hostRefuse ?? abortSessionFailClosed
37549
+ };
37550
+ }
37217
37551
  function createTransform(deps) {
37552
+ const host = resolveTransformHostSeams(deps);
37218
37553
  const loadedSessions = new Set;
37219
37554
  const rustModeTransform = deps.transformMode === "rust" && deps.rustModeModuleClient ? createRustModeTransform(deps, {
37220
37555
  moduleClient: deps.rustModeModuleClient,
@@ -37250,7 +37585,7 @@ function createTransform(deps) {
37250
37585
  logTransformTiming(sessionId, "findSessionId", startTime, `messages=${messages.length}`);
37251
37586
  const db = deps.db;
37252
37587
  if (deps.client !== undefined) {
37253
- scheduleReconciliation(db, sessionId, readRawSessionMessages);
37588
+ scheduleReconciliation(db, sessionId, host.hostRawMessages);
37254
37589
  }
37255
37590
  const tUserMsg = performance.now();
37256
37591
  const currentTurnId = findLastUserMessageId(messages);
@@ -37353,7 +37688,7 @@ function createTransform(deps) {
37353
37688
  }
37354
37689
  const compartmentDirectory = sessionDirectory;
37355
37690
  const historianRunnable = deps.historianRunnable !== false;
37356
- const canRunCompartments = fullFeatureMode && !compactionOff && historianRunnable && deps.client !== undefined && compartmentDirectory.length > 0;
37691
+ const canRunCompartments = fullFeatureMode && !compactionOff && historianRunnable && (deps.client !== undefined || deps.hiddenCompletionExecutor !== undefined) && compartmentDirectory.length > 0;
37357
37692
  const fallbackModelId = deps.getFallbackModelId?.(sessionId);
37358
37693
  const tModelDetect = performance.now();
37359
37694
  const persistedUsageBeforeResets = contextUsagePassSnapshot(sessionMeta).persistedUsage;
@@ -37458,7 +37793,7 @@ function createTransform(deps) {
37458
37793
  }
37459
37794
  let modelForBudget = deps.liveModelBySession?.get(sessionId);
37460
37795
  if (!modelForBudget) {
37461
- const recovered = findLastAssistantModelFromOpenCodeDb(sessionId);
37796
+ const recovered = host.hostModelFallback(sessionId);
37462
37797
  if (recovered) {
37463
37798
  modelForBudget = recovered;
37464
37799
  deps.liveModelBySession?.set(sessionId, recovered);
@@ -37514,7 +37849,7 @@ function createTransform(deps) {
37514
37849
  if (!canRunCompartments)
37515
37850
  return null;
37516
37851
  if (_boundarySnapshotCache === undefined || emergencyTailScale) {
37517
- const snapshot = resolveOpenCodeProtectedTailBoundary({
37852
+ const snapshot = host.hostProtectedTailBoundary({
37518
37853
  db,
37519
37854
  sessionId: resolvedSessionId,
37520
37855
  mode: "transform-force",
@@ -37546,7 +37881,7 @@ function createTransform(deps) {
37546
37881
  boundarySnapshot = getRunnableBoundaryForCompartment(scale);
37547
37882
  }
37548
37883
  if (false) {}
37549
- if (!canRunCompartments || !deps.client || !boundarySnapshot || !hasRunnableCompartmentWindow(boundarySnapshot)) {
37884
+ if (!canRunCompartments || !deps.client && !deps.hiddenCompletionExecutor || !boundarySnapshot || !hasRunnableCompartmentWindow(boundarySnapshot)) {
37550
37885
  return false;
37551
37886
  }
37552
37887
  if (getActiveCompartmentRun(sessionId)) {
@@ -37555,6 +37890,8 @@ function createTransform(deps) {
37555
37890
  updateSessionMeta2(db, sessionId, { compartmentInProgress: true });
37556
37891
  startCompartmentAgent({
37557
37892
  client: deps.client,
37893
+ hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
37894
+ compactionMarkerStrategy: deps.compactionMarkerStrategy,
37558
37895
  db,
37559
37896
  sessionId,
37560
37897
  historianChunkTokens: deps.getHistorianChunkTokens?.() ?? 20000,
@@ -37761,6 +38098,8 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
37761
38098
  const rawGetNotifParams = deps.getNotificationParams;
37762
38099
  const tCompartmentPhase = performance.now();
37763
38100
  const compartmentPhase = await runCompartmentPhase({
38101
+ hiddenCompletionExecutor: deps.hiddenCompletionExecutor,
38102
+ compactionMarkerStrategy: deps.compactionMarkerStrategy,
37764
38103
  canRunCompartments,
37765
38104
  fullFeatureMode,
37766
38105
  compactionOff,
@@ -37871,6 +38210,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
37871
38210
  const protectedCutoff = protectionWindow.cutoff;
37872
38211
  const tPostProcess = performance.now();
37873
38212
  const postTransformResult = await runPostTransformPhase({
38213
+ compactionMarkerStrategy: deps.compactionMarkerStrategy ?? defaultCompactionMarkerStrategy,
37874
38214
  sessionId,
37875
38215
  db,
37876
38216
  messages,
@@ -37988,7 +38328,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
37988
38328
  throw new EmergencyFailClosedError(`Emergency recovery notification was ${notification}`);
37989
38329
  }
37990
38330
  try {
37991
- await abortSessionFailClosed(deps.client, sessionId);
38331
+ await host.hostRefuse(deps.client, sessionId);
37992
38332
  } catch (error) {
37993
38333
  sessionLog(sessionId, "transform: emergency fail-closed abort failed; refusing to return a sendable prompt:", getErrorMessage(error));
37994
38334
  throw new EmergencyFailClosedError("Emergency recovery abort failed", {
@@ -39785,7 +40125,7 @@ function createMagicContextHook(deps) {
39785
40125
  };
39786
40126
  const rustMemorySyncRequestedSessions = new Set;
39787
40127
  const authorityRecoveryModuleClient = deps.rustModeModuleClient ?? (() => {
39788
- const transport = new SubcModuleTransport(deps.config.subc?.connection_file);
40128
+ const transport = new SubcModuleTransport(deps.config.subc?.connection_file ?? getDefaultSubcConnectionFile());
39789
40129
  const client = {
39790
40130
  call: (args) => transport.call(args),
39791
40131
  stateSyncCapabilities: (args) => transport.stateSyncCapabilities(args),
@@ -39839,13 +40179,14 @@ function createMagicContextHook(deps) {
39839
40179
  const syncModuleNotes = () => syncModuleDomain("notes");
39840
40180
  const syncModuleMemories = () => syncModuleDomain("memories");
39841
40181
  const rustToolBackends = deps.config.transform_mode === "rust" && rustModeModuleClient ? {
39842
- authorityState: async ({ projectPath, projectRoot, domain }) => {
40182
+ authorityState: async ({ projectPath, projectRoot, sessionId, domain }) => {
39843
40183
  if (!rustModeModuleClient.authorityStatus)
39844
40184
  return null;
39845
40185
  const result = await rustModeModuleClient.authorityStatus({
39846
40186
  context_store_uuid: ensureContextStoreUuid(db),
39847
40187
  project: projectPath,
39848
40188
  projectRoot,
40189
+ sessionId,
39849
40190
  domain
39850
40191
  });
39851
40192
  return result.authority?.state ?? null;
@@ -39930,7 +40271,8 @@ function createMagicContextHook(deps) {
39930
40271
  content,
39931
40272
  category,
39932
40273
  ids,
39933
- reason
40274
+ reason,
40275
+ limit
39934
40276
  }) => {
39935
40277
  const response = await rustModeModuleClient.call({
39936
40278
  sessionId,
@@ -39945,6 +40287,7 @@ function createMagicContextHook(deps) {
39945
40287
  category,
39946
40288
  ids,
39947
40289
  reason,
40290
+ limit,
39948
40291
  memory_project: memoryProject
39949
40292
  }
39950
40293
  }
@@ -41070,6 +41413,9 @@ function memoryAuthorityRefusal(args) {
41070
41413
  const isMutation = args.action !== undefined && ["write", "update", "archive", "merge"].includes(args.action);
41071
41414
  return renderCapabilityRefusal(isMutation ? "memory_write" : "memory_access");
41072
41415
  }
41416
+ function memoryAuthorityMismatchRefusal() {
41417
+ return renderUserFacingFailure("memory_authority_mismatch");
41418
+ }
41073
41419
  function moduleMemoryText(response, args) {
41074
41420
  let value = response;
41075
41421
  if (value !== null && typeof value === "object" && "result" in value) {
@@ -41332,6 +41678,24 @@ function createCtxMemoryTool(deps) {
41332
41678
  return "Error: Could not resolve project identity for memory action.";
41333
41679
  }
41334
41680
  await deps.ensureProjectRegistered?.(toolContext.directory, deps.db);
41681
+ const activeCurateCategory = toolContext.agent === DREAMER_AGENT ? getActiveCurateCategory(deps.db, projectPath) : null;
41682
+ if (activeCurateCategory) {
41683
+ const scopeRefusal = getCurateCategoryScopeRefusal({
41684
+ scope: activeCurateCategory,
41685
+ action: args.action,
41686
+ requestedCategory: args.category,
41687
+ ids: [
41688
+ ...args.ids ?? [],
41689
+ ...Number.isInteger(args.superseded_by) ? [args.superseded_by] : []
41690
+ ],
41691
+ categoryForId: (id) => {
41692
+ const category = getMemoryById(deps.db, id)?.category;
41693
+ return category ? curateCategoryForMemoryCategory(category) : null;
41694
+ }
41695
+ });
41696
+ if (scopeRefusal)
41697
+ return scopeRefusal;
41698
+ }
41335
41699
  const curatePreflight = toolContext.agent === DREAMER_AGENT ? preflightCurateMutation({
41336
41700
  db: deps.db,
41337
41701
  params: args,
@@ -41339,13 +41703,14 @@ function createCtxMemoryTool(deps) {
41339
41703
  }) : { skip: null, successor: null };
41340
41704
  if (curatePreflight.skip)
41341
41705
  return curatePreflight.skip;
41342
- if (args.action !== "list") {
41706
+ {
41343
41707
  const marker = getAuthorityManagedMarker(deps.db, projectPath);
41344
41708
  let authorityState = null;
41345
41709
  try {
41346
41710
  authorityState = await deps.rustToolBackends?.authorityState?.({
41347
41711
  projectPath,
41348
41712
  projectRoot: toolContext.directory,
41713
+ sessionId: toolContext.sessionID,
41349
41714
  domain: "memories"
41350
41715
  }) ?? null;
41351
41716
  } catch (error) {
@@ -41382,7 +41747,8 @@ function createCtxMemoryTool(deps) {
41382
41747
  content: moduleArgs.content,
41383
41748
  category: moduleArgs.category,
41384
41749
  ids: moduleArgs.ids,
41385
- reason: moduleArgs.reason
41750
+ reason: moduleArgs.reason,
41751
+ limit: moduleArgs.action === "list" ? normalizeLimit2(moduleArgs.limit) : undefined
41386
41752
  }), moduleArgs);
41387
41753
  return text ?? memoryAuthorityRefusal(args);
41388
41754
  } catch (error) {
@@ -41393,6 +41759,9 @@ function createCtxMemoryTool(deps) {
41393
41759
  return memoryAuthorityRefusal(args);
41394
41760
  }
41395
41761
  }
41762
+ if (marker && (authorityState === null || authorityState === "TS")) {
41763
+ return memoryAuthorityMismatchRefusal();
41764
+ }
41396
41765
  if (marker || authorityState === "PREPARING" || authorityState === "DRAINING") {
41397
41766
  return memoryAuthorityRefusal(args);
41398
41767
  }
@@ -41461,7 +41830,8 @@ function createCtxMemoryTool(deps) {
41461
41830
  if (args.action === "list") {
41462
41831
  const limit = normalizeLimit2(args.limit);
41463
41832
  const category = normalizeCategory(args.category);
41464
- const memories = filterByCategory(getMemoriesByProject(deps.db, projectPath), category).slice(0, limit);
41833
+ const allMemories = getMemoriesByProject(deps.db, projectPath);
41834
+ const memories = (activeCurateCategory ? allMemories.filter((memory) => curateCategoryForMemoryCategory(memory.category) === activeCurateCategory) : filterByCategory(allMemories, category)).slice(0, limit);
41465
41835
  return formatMemoryList(memories);
41466
41836
  }
41467
41837
  if (args.action === "get") {
@@ -42417,6 +42787,7 @@ function createCtxNoteTool(deps) {
42417
42787
  notesAuthority = await deps.rustToolBackends.authorityState({
42418
42788
  projectPath: projectIdentity,
42419
42789
  projectRoot: toolContext.directory,
42790
+ sessionId,
42420
42791
  domain: "notes"
42421
42792
  });
42422
42793
  } catch (error) {
@@ -43383,6 +43754,1111 @@ function json(body, status = 200) {
43383
43754
  });
43384
43755
  }
43385
43756
 
43757
+ // src/v2/fold/markers.ts
43758
+ var v2CompactionMarkerStrategy = {
43759
+ setPending: () => {},
43760
+ publish: () => false,
43761
+ applyDeferred: () => ({ kind: "already-current" }),
43762
+ reconcile: () => false
43763
+ };
43764
+
43765
+ // src/v2/fold/owner.ts
43766
+ import { createHash as createHash15 } from "node:crypto";
43767
+ var foldDigest = (value) => createHash15("sha256").update(value).digest("hex");
43768
+
43769
+ class FoldOwner {
43770
+ storage;
43771
+ pending = new Map;
43772
+ constructor(storage) {
43773
+ this.storage = storage;
43774
+ }
43775
+ async serial(sessionID, operation) {
43776
+ const previous = this.pending.get(sessionID) ?? Promise.resolve();
43777
+ const next = previous.catch(() => {}).then(operation);
43778
+ this.pending.set(sessionID, next);
43779
+ try {
43780
+ return await next;
43781
+ } finally {
43782
+ if (this.pending.get(sessionID) === next)
43783
+ this.pending.delete(sessionID);
43784
+ }
43785
+ }
43786
+ key(sessionID) {
43787
+ return `fold/v1/${sessionID}`;
43788
+ }
43789
+ async read(sessionID) {
43790
+ return await this.storage.get(this.key(sessionID));
43791
+ }
43792
+ async supply(args) {
43793
+ return this.serial(args.sessionID, async () => {
43794
+ const previous = await this.read(args.sessionID);
43795
+ const same = previous && (args.runningCut !== undefined ? previous.cutSeq === args.runningCut : previous.cutSeq === undefined && previous.watermark === args.watermark);
43796
+ if (same)
43797
+ return previous;
43798
+ const submitted = args.materialize();
43799
+ const next = {
43800
+ watermark: args.watermark,
43801
+ cutSeq: args.runningCut,
43802
+ submitted,
43803
+ submittedSha: foldDigest(submitted)
43804
+ };
43805
+ await this.storage.set(this.key(args.sessionID), next);
43806
+ return next;
43807
+ });
43808
+ }
43809
+ async observe(args) {
43810
+ return this.serial(args.sessionID, async () => {
43811
+ let state = await this.read(args.sessionID);
43812
+ const renderedSha = foldDigest(JSON.stringify(args.rendered));
43813
+ if (!state) {
43814
+ args.onHard("boot_recovery");
43815
+ state = {
43816
+ watermark: args.cutSeq,
43817
+ submitted: args.summary,
43818
+ submittedSha: foldDigest(args.summary),
43819
+ reason: "boot_recovery"
43820
+ };
43821
+ }
43822
+ const reason = args.cutSeq < state.watermark ? "host_cut_before_watermark" : state.submittedSha !== foldDigest(args.summary) || state.renderedSha && state.renderedSha !== renderedSha ? "host_rerender" : undefined;
43823
+ if (reason && state.rejectedSha !== renderedSha) {
43824
+ args.onHard(reason);
43825
+ state.reason = reason;
43826
+ state.rejectedSha = renderedSha;
43827
+ }
43828
+ if (state.cutSeq === undefined && args.cutSeq >= state.watermark)
43829
+ state.cutSeq = args.cutSeq;
43830
+ if (!state.rendered && reason !== "host_cut_before_watermark") {
43831
+ state.rendered = structuredClone(args.rendered);
43832
+ state.renderedSha = renderedSha;
43833
+ state.renderedSummary = args.summary;
43834
+ }
43835
+ await this.storage.set(this.key(args.sessionID), state);
43836
+ return state;
43837
+ });
43838
+ }
43839
+ }
43840
+
43841
+ // src/v2/fold/restore.ts
43842
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
43843
+ var imageMimes = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
43844
+ function attachmentParts(files) {
43845
+ const seen = new Map;
43846
+ return files.flatMap((file) => {
43847
+ if (imageMimes.has(file.mime) && file.source.type === "inline" && file.mention?.text) {
43848
+ const key = JSON.stringify([
43849
+ file.mime,
43850
+ file.name ?? null,
43851
+ file.description ?? null,
43852
+ file.mention.text
43853
+ ]);
43854
+ const payloads = seen.get(key) ?? new Set;
43855
+ if (payloads.has(file.data))
43856
+ return [];
43857
+ payloads.add(file.data);
43858
+ seen.set(key, payloads);
43859
+ }
43860
+ const uri = file.source.type === "uri" ? file.source.uri : undefined;
43861
+ const location = uri?.startsWith("file:") ? fileURLToPath2(uri) : undefined;
43862
+ if (file.mime === "text/plain" || file.mime === "application/x-directory") {
43863
+ const directory = file.mime === "application/x-directory";
43864
+ return [
43865
+ {
43866
+ type: "text",
43867
+ text: `
43868
+
43869
+ ${[
43870
+ directory ? `Attached directory: ${location ?? file.name ?? uri ?? "directory"}` : `Attached file: ${file.name ?? uri ?? "inline attachment"}`,
43871
+ file.description === undefined ? undefined : `Description: ${file.description}`,
43872
+ directory && !file.data.length ? undefined : "",
43873
+ directory && !file.data.length ? undefined : Buffer.from(file.data, "base64").toString("utf8")
43874
+ ].filter((line) => line !== undefined).join(`
43875
+ `)}`,
43876
+ metadata: {
43877
+ attachment: {
43878
+ source: file.source,
43879
+ name: file.name,
43880
+ description: file.description
43881
+ }
43882
+ }
43883
+ }
43884
+ ];
43885
+ }
43886
+ if (!imageMimes.has(file.mime) && file.mime !== "application/pdf")
43887
+ return [];
43888
+ return [
43889
+ ...location ? [{ type: "text", text: `Attached file: ${location}` }] : [],
43890
+ {
43891
+ type: "media",
43892
+ mediaType: file.mime,
43893
+ data: file.data,
43894
+ filename: file.name,
43895
+ metadata: file.description === undefined ? undefined : { description: file.description }
43896
+ }
43897
+ ];
43898
+ });
43899
+ }
43900
+ function restoreRow(row, model) {
43901
+ const data = row.data;
43902
+ const make = (role, content, metadata = data.metadata) => ({
43903
+ id: row.id,
43904
+ role,
43905
+ content,
43906
+ ...metadata === undefined ? {} : { metadata }
43907
+ });
43908
+ if (row.type === "user") {
43909
+ const skills = data.skills ?? [];
43910
+ const content = [
43911
+ ...skills.flatMap((skill) => skill.text === undefined ? [] : [{ type: "text", text: skill.text }]),
43912
+ ...data.text ? [{ type: "text", text: data.text }] : [],
43913
+ ...attachmentParts(data.files ?? [])
43914
+ ];
43915
+ return content.length ? [
43916
+ make("user", content, {
43917
+ ...data.metadata ?? {},
43918
+ ...data.agents?.length ? { agents: data.agents } : {}
43919
+ })
43920
+ ] : [];
43921
+ }
43922
+ if (["synthetic", "skill", "system"].includes(row.type))
43923
+ return [
43924
+ make(row.type === "system" ? "system" : "user", [
43925
+ { type: "text", text: data.text ?? "" }
43926
+ ])
43927
+ ];
43928
+ if (row.type === "location-switched")
43929
+ return [
43930
+ make("user", [
43931
+ {
43932
+ type: "text",
43933
+ text: `The working directory has been changed to ${data.location.directory}.`
43934
+ }
43935
+ ])
43936
+ ];
43937
+ if (row.type === "shell")
43938
+ return data.metadata?.background === true ? [] : [
43939
+ make("user", [
43940
+ {
43941
+ type: "text",
43942
+ text: `The following shell command was executed by the user:
43943
+
43944
+ Command:
43945
+ ${data.command}
43946
+
43947
+ Output:
43948
+ ${data.output?.output ?? ""}`
43949
+ }
43950
+ ])
43951
+ ];
43952
+ if (row.type !== "assistant")
43953
+ return [];
43954
+ const previousModel = data.model;
43955
+ const sameProvider = previousModel?.providerID === model.providerID;
43956
+ const sameModel = sameProvider && previousModel?.id === model.id;
43957
+ const reuse = sameModel && data.error === undefined;
43958
+ const metadata = (state) => state === undefined ? undefined : { [model.providerID]: state };
43959
+ const content = [];
43960
+ const results = [];
43961
+ for (const part of data.content ?? []) {
43962
+ if (part.type === "text") {
43963
+ if (part.text !== "")
43964
+ content.push({
43965
+ type: "text",
43966
+ text: part.text,
43967
+ providerMetadata: reuse ? metadata(part.state) : undefined
43968
+ });
43969
+ continue;
43970
+ }
43971
+ if (part.type === "reasoning") {
43972
+ if (part.text !== "" || reuse && part.state !== undefined)
43973
+ content.push({
43974
+ type: reuse || data.error === undefined ? "reasoning" : "text",
43975
+ text: part.text,
43976
+ providerMetadata: reuse ? metadata(part.state) : undefined
43977
+ });
43978
+ continue;
43979
+ }
43980
+ const state = part.state;
43981
+ const completed = state.status === "completed" || state.status === "error";
43982
+ const toolReuse = reuse || sameModel && part.executed === true && completed;
43983
+ let input = state.input;
43984
+ if (state.status === "streaming" && typeof input === "string") {
43985
+ try {
43986
+ input = JSON.parse(input);
43987
+ } catch {}
43988
+ }
43989
+ content.push({
43990
+ type: "tool-call",
43991
+ id: part.id,
43992
+ name: part.name,
43993
+ input,
43994
+ providerExecuted: part.executed,
43995
+ providerMetadata: toolReuse ? metadata(part.providerState) : undefined
43996
+ });
43997
+ if (!completed)
43998
+ continue;
43999
+ const toolContent = state.content ?? [];
44000
+ const single = toolContent.length === 1 ? toolContent[0] : undefined;
44001
+ const result = {
44002
+ type: "tool-result",
44003
+ id: part.id,
44004
+ name: part.name,
44005
+ providerExecuted: part.executed,
44006
+ providerMetadata: toolReuse ? metadata(part.providerResultState ?? part.providerState) : sameProvider ? metadata(part.providerResultState) : undefined,
44007
+ result: state.status === "error" ? { error: state.error, content: toolContent } : single?.type === "text" ? { type: "text", value: single.text } : { type: "content", value: toolContent },
44008
+ ...state.status === "error" ? { resultType: "error" } : {}
44009
+ };
44010
+ if (part.executed === true)
44011
+ content.push(result);
44012
+ else
44013
+ results.push({ role: "tool", content: [result] });
44014
+ }
44015
+ return [...content.length ? [make("assistant", content)] : [], ...results];
44016
+ }
44017
+
44018
+ // src/v2/hidden-completion.ts
44019
+ function meter(system, prompt, text) {
44020
+ return {
44021
+ input: estimateTokens(system) + estimateTokens(prompt),
44022
+ output: estimateTokens(text),
44023
+ cacheRead: 0,
44024
+ cacheWrite: 0
44025
+ };
44026
+ }
44027
+ async function createV2HiddenCompletionExecutor(host, currentModel) {
44028
+ const runs = new WeakMap;
44029
+ const pending = new Map;
44030
+ const modelKey = (model) => `${model.providerID}/${model.modelID}`;
44031
+ const requireModel = async (sessionID) => {
44032
+ const model = sessionID ? await currentModel(sessionID) : null;
44033
+ if (!model)
44034
+ throw new HiddenCompletionRefusal("hidden_model_unsupported", "Hidden completion requires an existing session with a resolved current model", true);
44035
+ return model;
44036
+ };
44037
+ const refuseModel = (requested, actual, terminal = false) => {
44038
+ throw new HiddenCompletionRefusal("hidden_model_unsupported", `Hidden completion model ${requested} is unavailable on opencode2; use the session model ${actual} in historian.model or dreaming task model configuration, or unset the configured model`, terminal);
44039
+ };
44040
+ await host.hook("generate", async (draft) => {
44041
+ const last = draft.messages.at(-1);
44042
+ if (last?.role !== "user" || last.content.length !== 1)
44043
+ return;
44044
+ const part = last.content[0];
44045
+ if (part?.type !== "text" || typeof part.text !== "string")
44046
+ return;
44047
+ const attempt = pending.get(part.text);
44048
+ if (!attempt || draft.sessionID !== attempt.run.identity.parentSessionId)
44049
+ return;
44050
+ const actual = `${draft.model.providerID}/${draft.model.id}`;
44051
+ if (modelKey(attempt.model) !== actual)
44052
+ refuseModel(modelKey(attempt.model), actual);
44053
+ if (attempt.request.signal?.aborted)
44054
+ throw new Error("Hidden completion prompt aborted");
44055
+ const body = attempt.request.body;
44056
+ if (typeof body.variant === "string" && body.variant !== draft.model.variant) {
44057
+ refuseModel(`${actual} (${body.variant})`, `${actual} (${draft.model.variant ?? "default variant"})`);
44058
+ }
44059
+ const parts = body.parts;
44060
+ if (!Array.isArray(parts) || parts.some((item) => item.type !== "text" || typeof item.text !== "string")) {
44061
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Hidden completion accepts text-only calibrated prompts", true);
44062
+ }
44063
+ draft.system = [
44064
+ {
44065
+ type: "text",
44066
+ text: typeof body.system === "string" ? body.system : attempt.run.identity.system
44067
+ }
44068
+ ];
44069
+ draft.messages = [
44070
+ { role: "user", content: parts.map((item) => ({ type: "text", text: item.text })) }
44071
+ ];
44072
+ draft.tools = {};
44073
+ if (attempt.run.identity.maxOutputTokens !== undefined)
44074
+ draft.options.maxOutputTokens = attempt.run.identity.maxOutputTokens;
44075
+ attempt.shaped = true;
44076
+ });
44077
+ return {
44078
+ capabilities: { tools: false, harness: "opencode2" },
44079
+ async open(identity) {
44080
+ const model = await requireModel(identity.parentSessionId);
44081
+ const configured = (identity.configuredModels ?? (identity.model ? [identity.model] : [])).map(toModelEntry).filter((entry) => entry !== undefined);
44082
+ if (configured.length && !configured.some((entry) => entry.model === modelKey(model))) {
44083
+ refuseModel(configured.map((entry) => entry.model).join(", "), modelKey(model), true);
44084
+ }
44085
+ const handle = { id: `mc:hidden:${crypto.randomUUID()}` };
44086
+ runs.set(handle, { identity });
44087
+ return handle;
44088
+ },
44089
+ async attempt(handle, request) {
44090
+ const run = runs.get(handle);
44091
+ if (!run)
44092
+ throw new Error("Unknown hidden completion run");
44093
+ const sessionID = run.identity.parentSessionId;
44094
+ const actual = await requireModel(sessionID);
44095
+ if (sessionID === undefined)
44096
+ throw new Error("Hidden completion session id missing");
44097
+ const requested = request.body.model ?? actual;
44098
+ if (modelKey(requested) !== modelKey(actual))
44099
+ refuseModel(modelKey(requested), modelKey(actual));
44100
+ if (request.signal?.aborted)
44101
+ throw new Error("Hidden completion prompt aborted");
44102
+ const marker = `${handle.id}:${crypto.randomUUID()}`;
44103
+ const state = { run, request, model: actual, shaped: false };
44104
+ pending.set(marker, state);
44105
+ try {
44106
+ const generation = host.generate({ sessionID, prompt: marker }, { signal: request.signal });
44107
+ const result = await new Promise((resolve, reject) => {
44108
+ const abort = () => reject(new Error("Hidden completion prompt aborted"));
44109
+ request.signal?.addEventListener("abort", abort, { once: true });
44110
+ generation.then(resolve, reject).finally(() => {
44111
+ request.signal?.removeEventListener("abort", abort);
44112
+ pending.delete(marker);
44113
+ });
44114
+ if (request.signal?.aborted)
44115
+ abort();
44116
+ });
44117
+ if (!state.shaped)
44118
+ throw new HiddenCompletionRefusal("hidden_prompt_unrecognized", "Host did not dispatch the hidden generate hook", true);
44119
+ const prompt = request.body.parts.map((part) => part.text).join(`
44120
+ `);
44121
+ const system = typeof request.body.system === "string" ? request.body.system : run.identity.system;
44122
+ const usage = meter(system, prompt, result.text);
44123
+ usage.input += run.usage?.input ?? 0;
44124
+ usage.output += run.usage?.output ?? 0;
44125
+ run.usage = usage;
44126
+ run.completion = {
44127
+ text: result.text,
44128
+ usage,
44129
+ lengthCapped: false,
44130
+ providerId: actual.providerID,
44131
+ modelId: actual.modelID
44132
+ };
44133
+ } finally {
44134
+ if (!request.signal?.aborted)
44135
+ pending.delete(marker);
44136
+ }
44137
+ },
44138
+ async collect(handle) {
44139
+ const completion = runs.get(handle)?.completion;
44140
+ if (!completion)
44141
+ throw new Error("Hidden completion has no settled output");
44142
+ return completion;
44143
+ },
44144
+ async close() {}
44145
+ };
44146
+ }
44147
+
44148
+ // src/v2/store-reader.ts
44149
+ import { join as join11 } from "node:path";
44150
+ function sourceDatabaseFilename(channel, env = process.env) {
44151
+ return env.OPENCODE_DB ?? (["latest", "dev", "beta", "next", "prod"].includes(channel) || env.OPENCODE_DISABLE_CHANNEL_DB === "1" || env.OPENCODE_DISABLE_CHANNEL_DB === "true" ? "opencode.db" : `opencode-${channel.replace(/[^a-zA-Z0-9._-]/g, "")}.db`);
44152
+ }
44153
+ function gaDatabasePath(dataHome, channel = "latest", env = process.env) {
44154
+ const filename = sourceDatabaseFilename(channel, env);
44155
+ return filename === ":memory:" ? filename : join11(dataHome, "opencode", filename);
44156
+ }
44157
+ function decode(row) {
44158
+ const data = JSON.parse(row.data);
44159
+ if (!data || typeof data !== "object" || Array.isArray(data)) {
44160
+ throw new Error(`Invalid session_message data at seq ${row.seq}`);
44161
+ }
44162
+ if (row.type === "idle" && !["succeeded", "failed", "interrupted"].includes(String(data.outcome))) {
44163
+ throw new Error(`Invalid idle outcome at seq ${row.seq}`);
44164
+ }
44165
+ return { ...row, data };
44166
+ }
44167
+
44168
+ class V2StoreReader {
44169
+ db;
44170
+ constructor(path) {
44171
+ this.db = new Database(path, { readonly: true, fileMustExist: true });
44172
+ }
44173
+ close() {
44174
+ this.db.close();
44175
+ }
44176
+ page(sessionID, options = {}) {
44177
+ const limit = options.limit ?? 100;
44178
+ if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e4)
44179
+ throw new Error("Invalid page limit");
44180
+ const after = options.after ?? -1;
44181
+ if (!Number.isSafeInteger(after))
44182
+ throw new Error("Invalid seq cursor");
44183
+ const rows = this.db.prepare(`SELECT id, session_id, type, seq, data FROM session_message
44184
+ WHERE session_id = ? AND seq > ? ${options.type ? "AND type = ?" : ""}
44185
+ ORDER BY seq ASC LIMIT ?`).all(...options.type ? [sessionID, after, options.type, limit] : [sessionID, after, limit]).map(decode);
44186
+ return { rows, cursor: rows.at(-1)?.seq };
44187
+ }
44188
+ latestCompaction(sessionID) {
44189
+ const row = this.db.prepare(`SELECT id, session_id, type, seq, data FROM session_message
44190
+ WHERE session_id = ? AND type = 'compaction' AND json_extract(data, '$.status') = 'completed'
44191
+ ORDER BY seq DESC LIMIT 1`).get(sessionID);
44192
+ return row ? decode(row) : undefined;
44193
+ }
44194
+ idleRows(sessionID, after = -1) {
44195
+ return this.all(sessionID, after, "idle");
44196
+ }
44197
+ window(sessionID) {
44198
+ return this.db.transaction(() => {
44199
+ const cut = this.latestCompaction(sessionID);
44200
+ return this.all(sessionID, cut ? cut.seq - 1 : -1);
44201
+ })();
44202
+ }
44203
+ history(sessionID) {
44204
+ return this.all(sessionID, -1);
44205
+ }
44206
+ all(sessionID, after, type) {
44207
+ const rows = [];
44208
+ for (;; ) {
44209
+ const page = this.page(sessionID, { after, type });
44210
+ rows.push(...page.rows);
44211
+ if (page.rows.length < 100 || page.cursor === undefined)
44212
+ return rows;
44213
+ after = page.cursor;
44214
+ }
44215
+ }
44216
+ }
44217
+
44218
+ // src/v2/hooks/channel2.ts
44219
+ import { randomBytes as randomBytes2 } from "node:crypto";
44220
+ async function deliverSynthetic(context, sessionID, text) {
44221
+ const id = `msg_${randomBytes2(12).toString("hex")}`;
44222
+ await context.storage.set(`synthetic/${sessionID}/${id}`, { id });
44223
+ await context.session.synthetic({ sessionID, id, text, delivery: "steer" });
44224
+ return id;
44225
+ }
44226
+ async function isAdmittedSynthetic(context, sessionID, id) {
44227
+ const record = await context.storage.get(`synthetic/${sessionID}/${id}`);
44228
+ return record !== null && typeof record === "object" && "id" in record && record.id === id;
44229
+ }
44230
+ async function deliverPendingChannel2(context, db, sessionID, baseline) {
44231
+ if (getChannel2NudgeState(db, sessionID) !== "pending")
44232
+ return;
44233
+ const evaluation = evaluateChannel2(baseline);
44234
+ if (!evaluation.evaluable || !evaluation.shouldTrigger)
44235
+ return;
44236
+ const token = randomBytes2(16).toString("hex");
44237
+ if (!claimChannel2NudgeState(db, sessionID, token))
44238
+ return;
44239
+ try {
44240
+ await deliverSynthetic(context, sessionID, buildChannel2Reminder(evaluation.reclaimableTokens, reclaimableToolOutputCount(baseline?.baselineParts ?? [])));
44241
+ } catch (error) {
44242
+ casChannel2NudgeClaim(db, sessionID, "pending", token);
44243
+ throw error;
44244
+ }
44245
+ casChannel2NudgeClaim(db, sessionID, "delivered", token);
44246
+ }
44247
+
44248
+ // src/v2/hooks/dream-trigger.ts
44249
+ function startDreamTrigger(context, args) {
44250
+ const controller = new AbortController;
44251
+ const done = (async () => {
44252
+ try {
44253
+ for await (const value of context.event.subscribe({ signal: controller.signal })) {
44254
+ if (controller.signal.aborted)
44255
+ break;
44256
+ const event = value;
44257
+ if (event.type !== "session.execution.succeeded" || !event.data?.sessionID)
44258
+ continue;
44259
+ const db = openDatabase();
44260
+ if (!db)
44261
+ continue;
44262
+ try {
44263
+ await runDueTasksForProject({
44264
+ db,
44265
+ projectIdentity: args.projectIdentity(),
44266
+ tasks: buildDreamTaskRuntimeConfigs2(args.config, "opencode", args.language, args.mural?.model),
44267
+ executor: createDreamTaskExecutor({
44268
+ hiddenCompletionExecutor: args.executor,
44269
+ parentSessionId: event.data.sessionID,
44270
+ sessionDirectory: context.location.directory,
44271
+ openOpenCodeDb: () => null,
44272
+ language: args.language,
44273
+ mural: args.mural
44274
+ })
44275
+ });
44276
+ } catch (error) {
44277
+ console.warn("[magic-context] v2 dream scheduling failed", error);
44278
+ }
44279
+ }
44280
+ } catch (error) {
44281
+ if (!controller.signal.aborted)
44282
+ console.warn("[magic-context] v2 dream event subscription failed", error);
44283
+ }
44284
+ })();
44285
+ return {
44286
+ async dispose() {
44287
+ controller.abort();
44288
+ await done;
44289
+ }
44290
+ };
44291
+ }
44292
+
44293
+ // src/v2/hooks/payload.ts
44294
+ var HEAD_IDS = ["__magic_context_v2_m0__", "__magic_context_v2_m1__"];
44295
+ function adaptPayload(draft, admittedIDs = new Set) {
44296
+ const existingHeads = new Map(draft.messages.filter((m) => HEAD_IDS.some((id) => m.id === id)).map((m) => [m.id, m]));
44297
+ const source = draft.messages.filter((m) => !existingHeads.has(m.id));
44298
+ const results = new Map;
44299
+ for (const message of source) {
44300
+ for (const part of message.content) {
44301
+ if (part.type === "tool-result" && typeof part.id === "string") {
44302
+ const queue = results.get(part.id) ?? [];
44303
+ queue.push({ part, message });
44304
+ results.set(part.id, queue);
44305
+ }
44306
+ }
44307
+ }
44308
+ const paired = new Set;
44309
+ const bridges = new Map;
44310
+ const originals = new Map;
44311
+ const nativeTool = (call, result) => {
44312
+ const value = result?.part.result?.value;
44313
+ const output = typeof value === "string" ? value : value === undefined ? "" : JSON.stringify(value);
44314
+ const part = {
44315
+ type: "tool",
44316
+ callID: call?.id ?? result?.part.id,
44317
+ tool: call?.name ?? result?.part.name,
44318
+ state: {
44319
+ input: structuredClone(call?.input ?? {}),
44320
+ status: result ? "completed" : "running",
44321
+ ...result ? { output } : {}
44322
+ }
44323
+ };
44324
+ bridges.set(part, { call, result: result?.part, resultMessage: result?.message, output });
44325
+ if (result)
44326
+ paired.add(result.part);
44327
+ return part;
44328
+ };
44329
+ const callParts = new Map;
44330
+ for (const message of source) {
44331
+ for (const part of message.content) {
44332
+ if (part.type === "tool-call")
44333
+ callParts.set(part, nativeTool(part, results.get(String(part.id))?.shift()));
44334
+ }
44335
+ }
44336
+ const messages = [];
44337
+ for (const message of source) {
44338
+ const parts = [];
44339
+ for (const content of message.content) {
44340
+ if (paired.has(content))
44341
+ continue;
44342
+ const part = callParts.get(content) ?? (content.type === "tool-result" ? nativeTool(undefined, { part: content, message }) : structuredClone(content));
44343
+ if (message.id && admittedIDs.has(message.id))
44344
+ part.synthetic = true;
44345
+ parts.push(part);
44346
+ }
44347
+ if (!parts.length && message.content.length)
44348
+ continue;
44349
+ const mapped = {
44350
+ info: {
44351
+ id: message.id,
44352
+ sessionID: draft.sessionID,
44353
+ role: message.role,
44354
+ ...{
44355
+ providerID: draft.model.providerID,
44356
+ modelID: draft.model.id,
44357
+ agent: draft.agent,
44358
+ tools: draft.tools
44359
+ }
44360
+ },
44361
+ parts
44362
+ };
44363
+ originals.set(mapped, message);
44364
+ messages.push(mapped);
44365
+ }
44366
+ return {
44367
+ messages,
44368
+ commit() {
44369
+ let head = 0;
44370
+ const rendered = [];
44371
+ for (const message of messages) {
44372
+ const original = originals.get(message);
44373
+ const id = message.info.syntheticHead ? HEAD_IDS[head++] : original?.id;
44374
+ const content = [];
44375
+ const following = [];
44376
+ for (const candidate of message.parts) {
44377
+ const part = candidate;
44378
+ const bridge = bridges.get(part);
44379
+ if (!bridge) {
44380
+ const { synthetic: _synthetic, ...clean } = part;
44381
+ content.push(clean);
44382
+ continue;
44383
+ }
44384
+ const state = part.state;
44385
+ if (bridge.call)
44386
+ content.push({ ...bridge.call, input: state.input });
44387
+ if (bridge.result && bridge.resultMessage) {
44388
+ const result = {
44389
+ ...bridge.result,
44390
+ result: state.output === bridge.output ? bridge.result.result : { type: "text", value: state.output }
44391
+ };
44392
+ if (bridge.resultMessage === original)
44393
+ content.push(result);
44394
+ else
44395
+ following.push({ ...bridge.resultMessage, content: [result] });
44396
+ }
44397
+ }
44398
+ if (content.length || !original?.content.length) {
44399
+ const value = {
44400
+ ...original,
44401
+ id,
44402
+ role: message.info.role ?? "user",
44403
+ content
44404
+ };
44405
+ const existing = id ? existingHeads.get(id) : undefined;
44406
+ rendered.push(existing ? Object.assign(existing, { content }) : value);
44407
+ }
44408
+ rendered.push(...following);
44409
+ }
44410
+ draft.messages.splice(0, draft.messages.length, ...rendered);
44411
+ }
44412
+ };
44413
+ }
44414
+
44415
+ // src/v2/hooks/refusal.ts
44416
+ class V2ContextRefusal extends Error {
44417
+ constructor(message = "Context full — /ctx-flush or /clear to continue.", options) {
44418
+ super(message, options);
44419
+ this.name = "V2ContextRefusal";
44420
+ }
44421
+ }
44422
+ async function interruptBeforeProvider(session, sessionID) {
44423
+ let timer;
44424
+ try {
44425
+ const result = await Promise.race([
44426
+ session.interrupt({ sessionID }),
44427
+ new Promise((_, reject) => {
44428
+ timer = setTimeout(() => reject(new Error("interrupt exceeded 2000 ms")), 2000);
44429
+ })
44430
+ ]);
44431
+ if (result.interrupted !== true)
44432
+ throw new Error("interrupt arrived after the turn became idle");
44433
+ } catch (cause) {
44434
+ throw new V2ContextRefusal(undefined, { cause });
44435
+ } finally {
44436
+ clearTimeout(timer);
44437
+ }
44438
+ }
44439
+
44440
+ // src/v2/hooks/store.ts
44441
+ var isRawRow = (row) => ["user", "synthetic", "assistant", "skill", "shell", "system"].includes(row.type);
44442
+ function rawMessages(rows, history = rows) {
44443
+ const ordinals = new Map(history.filter(isRawRow).map((row, index) => [row.id, index + 1]));
44444
+ return rows.filter(isRawRow).map((row) => ({
44445
+ id: row.id,
44446
+ ordinal: ordinals.get(row.id),
44447
+ role: row.type === "assistant" ? "assistant" : "user",
44448
+ createdAt: row.data.time?.created,
44449
+ parts: row.type === "assistant" ? (row.data.content ?? []).map((part) => {
44450
+ if (part.type !== "tool")
44451
+ return { ...part };
44452
+ const state = part.state;
44453
+ const content = state.content;
44454
+ return {
44455
+ type: "tool",
44456
+ tool: part.name,
44457
+ callID: part.id,
44458
+ state: {
44459
+ ...state,
44460
+ output: content?.filter((p) => p.type === "text").map((p) => p.text).join(`
44461
+ `) ?? ""
44462
+ }
44463
+ };
44464
+ }) : [{ type: "text", text: row.data.text ?? "" }]
44465
+ }));
44466
+ }
44467
+
44468
+ // src/v2/hooks/context.ts
44469
+ function createHostSeams(context, read, liveModels) {
44470
+ return {
44471
+ hostRawMessages: read,
44472
+ hostProtectedTailBoundary: (args) => resolveOpenCodeProtectedTailBoundary({
44473
+ ...args,
44474
+ cacheNamespace: `opencode2:${args.sessionId}`
44475
+ }),
44476
+ hostModelFallback: (sessionID) => liveModels.get(sessionID) ?? null,
44477
+ hostRefuse: (_client, sessionID) => interruptBeforeProvider(context.session, sessionID)
44478
+ };
44479
+ }
44480
+ async function registerContext(context) {
44481
+ const directory = context.location.directory;
44482
+ const config = loadPluginConfigDetailed(directory).config;
44483
+ if (!config.enabled || !isCompactionEnabled(config))
44484
+ return;
44485
+ const folds = new FoldOwner(context.storage);
44486
+ const limits = new Map;
44487
+ const queriedModels = new Set;
44488
+ const liveModels = new Map;
44489
+ const hostGenerate = context.session.generate?.bind(context.session);
44490
+ const hiddenCompletionExecutor = hostGenerate ? await createV2HiddenCompletionExecutor({
44491
+ hook: (name, callback) => context.session.hook(name, callback),
44492
+ generate: (input, options) => hostGenerate(input, options)
44493
+ }, (sessionID) => liveModels.get(sessionID) ?? null) : undefined;
44494
+ const dreamTrigger = hiddenCompletionExecutor && config.dreamer && !config.dreamer.disable ? startDreamTrigger(context, {
44495
+ config: config.dreamer,
44496
+ executor: hiddenCompletionExecutor,
44497
+ projectIdentity: () => resolveProjectIdentity(directory) ?? directory,
44498
+ language: config.language,
44499
+ mural: config.mural
44500
+ }) : undefined;
44501
+ const historianModels = resolveHistorianModel2(config, "opencode");
44502
+ const usage = new Map;
44503
+ const channel1 = new Map;
44504
+ const variants = new Map;
44505
+ const agents = new Map;
44506
+ const historyRefreshSessions = new Set;
44507
+ const pendingMaterializationSessions = new Set;
44508
+ const lastHeuristicsTurnId = new Map;
44509
+ const rawProviders = new Map;
44510
+ let passDuties;
44511
+ let toolDuties;
44512
+ await context.tool.hook("execute.before", (draft) => assertExecutableToolInput(draft.input));
44513
+ await context.tool.hook("execute.after", async (draft) => {
44514
+ if (!db || draft.status !== "completed")
44515
+ return;
44516
+ try {
44517
+ toolDuties ??= createToolExecuteAfterHook({ db, channel1StateBySession: channel1 });
44518
+ const content = draft.result?.content;
44519
+ const text = typeof content === "string" ? content : Array.isArray(content) ? content.filter((part) => part.type === "text").map((part) => part.text).join(`
44520
+ `) : "";
44521
+ const output = { output: text };
44522
+ await toolDuties({ ...draft, args: draft.input }, output);
44523
+ if (draft.result && output.output !== text) {
44524
+ if (typeof content === "string")
44525
+ draft.result.content = output.output;
44526
+ else if (Array.isArray(content) && output.output.startsWith(text))
44527
+ content.push({ type: "text", text: output.output.slice(text.length) });
44528
+ }
44529
+ const baseline = channel1.get(draft.sessionID);
44530
+ await deliverPendingChannel2(context, db, draft.sessionID, baseline);
44531
+ } catch (error) {
44532
+ console.warn("[magic-context] v2 Channel 2 delivery deferred", error);
44533
+ }
44534
+ });
44535
+ const read = (sessionID) => {
44536
+ const reader = new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"));
44537
+ try {
44538
+ return rawMessages(reader.history(sessionID));
44539
+ } finally {
44540
+ reader.close();
44541
+ }
44542
+ };
44543
+ const pagedRead = Object.assign(read, {
44544
+ readPage: (sessionID, after, limit, watermark) => read(sessionID).filter((m) => m.ordinal > after && m.ordinal <= watermark).slice(0, limit),
44545
+ getCount: (sessionID) => read(sessionID).length
44546
+ });
44547
+ let transform;
44548
+ let db;
44549
+ const refuseIfUnsafe = async (draft) => {
44550
+ let unsafe = false;
44551
+ try {
44552
+ db ??= openDatabase();
44553
+ if (!db || !isDatabasePersisted(db))
44554
+ throw new Error("context storage is not durable");
44555
+ getOrCreateSessionMeta2(db, draft.sessionID);
44556
+ const reader = new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"));
44557
+ try {
44558
+ const latest = reader.history(draft.sessionID).filter((row) => row.type === "assistant").at(-1);
44559
+ const tokens = latest?.data.tokens;
44560
+ const modelKey = `${draft.model.providerID}/${draft.model.id}`;
44561
+ if (!queriedModels.has(modelKey)) {
44562
+ const catalog = await context.catalog.model.list({
44563
+ location: context.location
44564
+ });
44565
+ for (const model of catalog.data)
44566
+ limits.set(`${model.providerID}/${model.id}`, model.limit.context);
44567
+ queriedModels.add(modelKey);
44568
+ }
44569
+ const limit = limits.get(modelKey);
44570
+ if (tokens && limit && Number.isFinite(limit) && limit > 0) {
44571
+ const inputTokens = tokens.input + tokens.cache.read + tokens.cache.write;
44572
+ unsafe = inputTokens / limit >= 0.95;
44573
+ const completed = latest?.data.time?.completed;
44574
+ if (typeof completed === "number")
44575
+ updateSessionMeta2(db, draft.sessionID, { lastResponseTime: completed });
44576
+ usage.set(draft.sessionID, {
44577
+ usage: { inputTokens, percentage: inputTokens / limit * 100 },
44578
+ hasUsageTokens: true,
44579
+ updatedAt: Date.now()
44580
+ });
44581
+ }
44582
+ } finally {
44583
+ reader.close();
44584
+ }
44585
+ } catch {
44586
+ unsafe = true;
44587
+ }
44588
+ if (unsafe)
44589
+ await interruptBeforeProvider(context.session, draft.sessionID);
44590
+ return unsafe;
44591
+ };
44592
+ const materialize = (draft) => {
44593
+ db ??= openDatabase();
44594
+ if (!db || !isDatabasePersisted(db))
44595
+ throw new Error("context storage is not durable");
44596
+ const state = getOrCreateSessionMeta2(db, draft.sessionID);
44597
+ return materializeM0({
44598
+ db,
44599
+ sessionId: draft.sessionID,
44600
+ state,
44601
+ projectPath: resolveProjectIdentity(directory) ?? directory,
44602
+ projectDirectory: directory,
44603
+ memoryEnabled: config.memory.enabled,
44604
+ memoryInjectionBudgetTokens: config.memory.injection_budget_tokens,
44605
+ hardSignals: {
44606
+ systemHash: foldDigest(JSON.stringify(draft.system)),
44607
+ toolSetHash: "",
44608
+ modelKey: `${draft.model.providerID}/${draft.model.id}`,
44609
+ cacheExpired: false,
44610
+ lastResponseTime: state.lastResponseTime
44611
+ }
44612
+ }).m0Text;
44613
+ };
44614
+ await context.session.hook("compaction", async (draft) => {
44615
+ const reader = new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"));
44616
+ try {
44617
+ const rows = reader.history(draft.sessionID);
44618
+ const ids = new Set(draft.messages.map((message) => message.id));
44619
+ const watermark = Math.max(-1, ...rows.filter((row) => ids.has(row.id)).map((row) => row.seq));
44620
+ const running = rows.filter((row) => row.type === "compaction" && row.data.status === "running").at(-1);
44621
+ const fold = await folds.supply({
44622
+ sessionID: draft.sessionID,
44623
+ watermark,
44624
+ runningCut: running?.seq,
44625
+ materialize: () => materialize(draft)
44626
+ });
44627
+ draft.result = { summary: fold.submitted };
44628
+ } catch (cause) {
44629
+ await interruptBeforeProvider(context.session, draft.sessionID);
44630
+ throw new V2ContextRefusal("Magic Context could not preserve the host checkpoint.", {
44631
+ cause
44632
+ });
44633
+ } finally {
44634
+ reader.close();
44635
+ }
44636
+ });
44637
+ await context.session.hook("context", async (draft) => {
44638
+ let postFold = false;
44639
+ try {
44640
+ if (await refuseIfUnsafe(draft))
44641
+ return;
44642
+ if (!db)
44643
+ return;
44644
+ const storage = db;
44645
+ updateSessionMeta2(db, draft.sessionID, {
44646
+ systemPromptHash: foldDigest(JSON.stringify(draft.system))
44647
+ });
44648
+ await preloadTokenizer();
44649
+ passDuties ??= createChatMessageHook({
44650
+ db,
44651
+ liveModelBySession: liveModels,
44652
+ variantBySession: variants,
44653
+ agentBySession: agents,
44654
+ historyRefreshSessions,
44655
+ pendingMaterializationSessions,
44656
+ lastHeuristicsTurnId,
44657
+ systemPromptRefreshSessions: new Set,
44658
+ cacheTtlConfig: config.cache_ttl,
44659
+ upgradeReminder: (sessionID) => maybeSendUpgradeReminder({
44660
+ db: storage,
44661
+ client: undefined,
44662
+ getNotificationParams: () => ({}),
44663
+ sendStatusNotification: async (_client, id, text) => {
44664
+ pushNotification2("toast", { message: text, variant: "info" }, id);
44665
+ return "queued";
44666
+ }
44667
+ }, sessionID)
44668
+ });
44669
+ await passDuties({
44670
+ sessionID: draft.sessionID,
44671
+ agent: draft.agent,
44672
+ variant: draft.model.variant,
44673
+ model: { providerID: draft.model.providerID, modelID: draft.model.id }
44674
+ });
44675
+ if (!rawProviders.has(draft.sessionID))
44676
+ rawProviders.set(draft.sessionID, setRawMessageProvider(draft.sessionID, {
44677
+ readMessages: () => read(draft.sessionID)
44678
+ }));
44679
+ transform ??= createTransform({
44680
+ db,
44681
+ tagger: createTagger(),
44682
+ scheduler: createScheduler({
44683
+ executeThresholdPercentage: config.execute_threshold_percentage
44684
+ }),
44685
+ contextUsageMap: usage,
44686
+ protectedTokens: config.protected_tokens,
44687
+ protectedTokenTierOverrides: getProtectedTokensTierOverrides(config),
44688
+ executeThresholdPercentage: config.execute_threshold_percentage,
44689
+ liveModelBySession: liveModels,
44690
+ channel1StateBySession: channel1,
44691
+ historyRefreshSessions,
44692
+ pendingMaterializationSessions,
44693
+ lastHeuristicsTurnId,
44694
+ variantBySession: variants,
44695
+ clearReasoningAge: config.clear_reasoning_age,
44696
+ directory,
44697
+ projectPath: directory,
44698
+ hiddenCompletionExecutor,
44699
+ historianRunnable: hiddenCompletionExecutor !== undefined && config.historian?.disable !== true,
44700
+ historianModel: historianModels.primary,
44701
+ fallbackModels: historianModels.fallbacks,
44702
+ historianTimeoutMs: config.historian_timeout_ms,
44703
+ historianMaxOutputTokens: config.historian?.maxTokens,
44704
+ historianTwoPass: config.historian?.two_pass,
44705
+ compactionMarkerStrategy: v2CompactionMarkerStrategy,
44706
+ memoryConfig: {
44707
+ enabled: config.memory.enabled,
44708
+ injectionBudgetTokens: config.memory.injection_budget_tokens,
44709
+ autoPromote: config.memory.auto_promote
44710
+ },
44711
+ ...createHostSeams(context, pagedRead, liveModels)
44712
+ });
44713
+ const admitted = new Set;
44714
+ for (const message of draft.messages) {
44715
+ if (message.id && await isAdmittedSynthetic(context, draft.sessionID, message.id))
44716
+ admitted.add(message.id);
44717
+ }
44718
+ const reader = new V2StoreReader(gaDatabasePath(getDataDir(), process.env.OPENCODE_CHANNEL ?? "latest"));
44719
+ let checkpoint;
44720
+ let submitted;
44721
+ try {
44722
+ const cut = reader.latestCompaction(draft.sessionID);
44723
+ const incoming = cut && draft.messages.find((message) => message.id === cut.id);
44724
+ postFold = cut !== undefined;
44725
+ if (cut && !incoming)
44726
+ throw new Error("The host checkpoint disappeared from the context draft");
44727
+ if (cut && incoming) {
44728
+ const identity = await folds.observe({
44729
+ sessionID: draft.sessionID,
44730
+ cutSeq: cut.seq,
44731
+ summary: cut.data.summary ?? "",
44732
+ rendered: incoming,
44733
+ onHard: (reason) => {
44734
+ console.warn(`[magic-context] HARD reason=${reason} session=${draft.sessionID}`);
44735
+ materialize(draft);
44736
+ pendingMaterializationSessions.add(draft.sessionID);
44737
+ }
44738
+ });
44739
+ checkpoint = structuredClone(identity.rendered ?? incoming);
44740
+ submitted = identity.rendered ? identity.renderedSummary ?? identity.submitted : cut.data.summary ?? "";
44741
+ const all = reader.history(draft.sessionID);
44742
+ const boundaryID = db.prepare("SELECT cached_m0_last_baseline_end_message_id AS id FROM session_meta WHERE session_id = ?").get(draft.sessionID)?.id;
44743
+ const boundary = all.find((row) => row.id === boundaryID)?.seq ?? -1;
44744
+ const present = new Set(draft.messages.map((message) => message.id));
44745
+ const restored = all.filter((row) => row.seq > boundary && row.seq <= cut.seq && !present.has(row.id)).flatMap((row) => restoreRow(row, draft.model));
44746
+ draft.messages.splice(0, draft.messages.length, ...restored, ...draft.messages.filter((message) => message !== incoming));
44747
+ }
44748
+ } finally {
44749
+ reader.close();
44750
+ }
44751
+ const mapped = adaptPayload(draft, admitted);
44752
+ await transform({}, mapped);
44753
+ mapped.commit();
44754
+ if (checkpoint && submitted !== undefined) {
44755
+ const head = draft.messages.find((message) => message.id === HEAD_IDS[0]);
44756
+ const baseline = head?.content.find((part) => part.type === "text")?.text;
44757
+ if (typeof baseline === "string") {
44758
+ for (const part of checkpoint.content)
44759
+ if (part.type === "text" && typeof part.text === "string") {
44760
+ part.text = part.text.replace(`<summary>
44761
+ ${submitted}
44762
+ </summary>`, `<summary>
44763
+ ${baseline}
44764
+ </summary>`);
44765
+ }
44766
+ const volatile = draft.messages.find((message) => message.id === HEAD_IDS[1]);
44767
+ if (volatile && head)
44768
+ volatile.content.push(...head.content.filter((part) => part.type !== "text"));
44769
+ draft.messages.splice(0, draft.messages.length, checkpoint, ...draft.messages.filter((message) => message !== head));
44770
+ }
44771
+ }
44772
+ } catch (error) {
44773
+ if (error instanceof V2ContextRefusal)
44774
+ throw error;
44775
+ if (postFold) {
44776
+ await interruptBeforeProvider(context.session, draft.sessionID);
44777
+ throw new V2ContextRefusal("Magic Context could not restore the unarchived host history.", { cause: error });
44778
+ }
44779
+ console.warn("[magic-context] v2 context unavailable", error);
44780
+ }
44781
+ });
44782
+ return {
44783
+ async dispose() {
44784
+ await dreamTrigger?.dispose();
44785
+ for (const release of rawProviders.values())
44786
+ release();
44787
+ rawProviders.clear();
44788
+ }
44789
+ };
44790
+ }
44791
+
44792
+ // src/v2/hooks/update-check.ts
44793
+ import { existsSync as existsSync13, readFileSync as readFileSync7 } from "node:fs";
44794
+ import { dirname as dirname8, join as join12 } from "node:path";
44795
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
44796
+ function packageInfo() {
44797
+ let directory = dirname8(fileURLToPath3(import.meta.url));
44798
+ for (;; ) {
44799
+ try {
44800
+ const pkg = JSON.parse(readFileSync7(join12(directory, "package.json"), "utf8"));
44801
+ if (pkg.name === "@cortexkit/opencode-magic-context" && typeof pkg.version === "string") {
44802
+ return {
44803
+ version: pkg.version,
44804
+ development: existsSync13(join12(directory, "src/v2/server.ts"))
44805
+ };
44806
+ }
44807
+ } catch {}
44808
+ const parent = dirname8(directory);
44809
+ if (parent === directory)
44810
+ throw new Error("Magic Context package manifest is unavailable");
44811
+ directory = parent;
44812
+ }
44813
+ }
44814
+ function startUpdateChecks(context, check = (signal) => {
44815
+ return packageInfo().development ? Promise.resolve(null) : getLatestVersion("latest", { signal });
44816
+ }) {
44817
+ const controller = new AbortController;
44818
+ const done = (async () => {
44819
+ try {
44820
+ for await (const _event of context.event.subscribe({ signal: controller.signal })) {
44821
+ if (controller.signal.aborted)
44822
+ break;
44823
+ const last = await context.storage.get("version-check-at");
44824
+ if (typeof last === "number" && Date.now() - last < 60 * 60 * 1000)
44825
+ continue;
44826
+ await context.storage.set("version-check-at", Date.now());
44827
+ const latest = await check(controller.signal);
44828
+ const comparison = latest ? compareSemverCore(latest, packageInfo().version) : null;
44829
+ if (!controller.signal.aborted && comparison !== null && comparison > 0) {
44830
+ pushNotification2("toast", {
44831
+ message: `Magic Context ${latest} is available. Update the plugin to install it.`,
44832
+ variant: "info"
44833
+ });
44834
+ }
44835
+ }
44836
+ } catch (error) {
44837
+ if (!controller.signal.aborted)
44838
+ console.warn("[magic-context] v2 update check unavailable", error);
44839
+ }
44840
+ })();
44841
+ return {
44842
+ done,
44843
+ async dispose() {
44844
+ controller.abort();
44845
+ await done;
44846
+ }
44847
+ };
44848
+ }
44849
+
44850
+ // src/v2/server.ts
44851
+ async function setup(context) {
44852
+ setHarness("opencode2");
44853
+ const duties = await registerContext(context);
44854
+ const checks = loadPluginConfigDetailed(context.location.directory).config.auto_update === false ? undefined : startUpdateChecks(context);
44855
+ console.info("[magic-context] @cortexkit/opencode-magic-context v2 setup");
44856
+ return async () => {
44857
+ await checks?.dispose();
44858
+ await duties?.dispose();
44859
+ };
44860
+ }
44861
+
43386
44862
  // src/index.ts
43387
44863
  var BOOT_SERVER_DEADLINE_MS = 15000;
43388
44864
  var RESOLVED_CONFIG_TIMEOUT_MS = 2000;
@@ -43435,7 +44911,7 @@ var server = async (ctx) => {
43435
44911
  if (hasBannerEntries)
43436
44912
  setTimeout(async () => {
43437
44913
  try {
43438
- const { sendStatusNotification } = await import("./send-session-notification-2mzgd3zf.js");
44914
+ const { sendStatusNotification } = await import("./send-session-notification-xnypkxpx.js");
43439
44915
  const clientWithSessions = ctx.client;
43440
44916
  const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
43441
44917
  const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
@@ -43452,7 +44928,7 @@ var server = async (ctx) => {
43452
44928
  log(`[magic-context] opencode_db_missing path=${openCodeDbResolution.path} source=${openCodeDbResolution.source}`);
43453
44929
  setTimeout(async () => {
43454
44930
  try {
43455
- const { sendStatusNotification } = await import("./send-session-notification-2mzgd3zf.js");
44931
+ const { sendStatusNotification } = await import("./send-session-notification-xnypkxpx.js");
43456
44932
  const clientWithSessions = ctx.client;
43457
44933
  const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
43458
44934
  const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
@@ -43484,9 +44960,9 @@ var server = async (ctx) => {
43484
44960
  }
43485
44961
  conflictMs = performance.now() - conflictStartedAt;
43486
44962
  const liveSessionState = createLiveSessionState();
43487
- const rustModeModuleTransport = pluginConfig.transform_mode === "rust" ? new SubcModuleTransport(pluginConfig.subc?.connection_file) : undefined;
44963
+ const rustModeModuleTransport = pluginConfig.transform_mode === "rust" ? new SubcModuleTransport(pluginConfig.subc?.connection_file ?? getDefaultSubcConnectionFile()) : undefined;
43488
44964
  const rustModeModuleClient = rustModeModuleTransport;
43489
- const sessionCleanupModuleClient = pluginConfig.enabled ? rustModeModuleTransport ?? new SubcModuleTransport(pluginConfig.subc?.connection_file) : undefined;
44965
+ const sessionCleanupModuleClient = pluginConfig.enabled ? rustModeModuleTransport ?? new SubcModuleTransport(pluginConfig.subc?.connection_file ?? getDefaultSubcConnectionFile()) : undefined;
43490
44966
  const hooksPhase = await runBootPhaseWithinBudget(bootBudget, "hooks", () => createSessionHooksAsync({
43491
44967
  ctx,
43492
44968
  pluginConfig,
@@ -43698,12 +45174,12 @@ var server = async (ctx) => {
43698
45174
  {
43699
45175
  const fence = getSchemaFenceRejection();
43700
45176
  if (fence) {
43701
- import("./conflict-warning-hook-aedp084d.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
45177
+ import("./conflict-warning-hook-jyj54gbe.js").then(({ sendSchemaFenceWarning }) => sendSchemaFenceWarning(ctx.client, ctx.directory, fence));
43702
45178
  }
43703
45179
  }
43704
45180
  const serverUrl = ctx.serverUrl;
43705
45181
  const serverUrlStr = serverUrl instanceof URL ? serverUrl.toString().replace(/\/$/, "") : typeof serverUrl === "string" ? serverUrl.replace(/\/$/, "") : undefined;
43706
- import("./send-session-notification-2mzgd3zf.js").then(({ setNotificationServerUrl }) => {
45182
+ import("./send-session-notification-xnypkxpx.js").then(({ setNotificationServerUrl }) => {
43707
45183
  setNotificationServerUrl(serverUrlStr);
43708
45184
  });
43709
45185
  if (conflictResult?.hasConflict) {
@@ -43717,7 +45193,7 @@ var server = async (ctx) => {
43717
45193
  }
43718
45194
  if (pluginConfig.enabled && !conflictResult?.hasConflict) {
43719
45195
  setTimeout(() => {
43720
- import("./announcement-3c1vertn.js").then(({
45196
+ import("./announcement-8mgn61fw.js").then(({
43721
45197
  shouldShowAnnouncement,
43722
45198
  ANNOUNCEMENT_VERSION,
43723
45199
  ANNOUNCEMENT_FEATURES,
@@ -43726,7 +45202,7 @@ var server = async (ctx) => {
43726
45202
  }) => {
43727
45203
  if (!shouldShowAnnouncement())
43728
45204
  return;
43729
- return import("./conflict-warning-hook-aedp084d.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER, markAnnouncementSeen));
45205
+ return import("./conflict-warning-hook-jyj54gbe.js").then(({ sendStartupAnnouncement }) => sendStartupAnnouncement(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION, ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER, markAnnouncementSeen));
43730
45206
  }).catch(() => {});
43731
45207
  }, 8000);
43732
45208
  }
@@ -43882,7 +45358,8 @@ var server = async (ctx) => {
43882
45358
  };
43883
45359
  var plugin = {
43884
45360
  id: "opencode-magic-context",
43885
- server
45361
+ server,
45362
+ setup
43886
45363
  };
43887
45364
  var src_default = plugin;
43888
45365
  export {