@cortexkit/opencode-magic-context 0.49.2 → 0.49.3

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 (114) hide show
  1. package/README.md +2 -38
  2. package/dist/auto-search-worker.js +3 -3
  3. package/dist/compaction-marker-candidates-dd638ypn.js +19 -0
  4. package/dist/compaction-marker-candidates-worker.js +24 -0
  5. package/dist/{conflict-warning-hook-asnt6hfc.js → conflict-warning-hook-ae8nmv7c.js} +5 -4
  6. package/dist/{context-tfyhtdcs.js → context-9tbxh883.js} +63 -29
  7. package/dist/{embedding-backfill-wyc3ykyf.js → embedding-backfill-aj488s8x.js} +5 -5
  8. package/dist/features/magic-context/compaction-marker-candidates-worker.d.ts +2 -0
  9. package/dist/features/magic-context/compaction-marker-candidates-worker.d.ts.map +1 -0
  10. package/dist/features/magic-context/compaction-marker-candidates.d.ts +47 -0
  11. package/dist/features/magic-context/compaction-marker-candidates.d.ts.map +1 -0
  12. package/dist/features/magic-context/compaction-marker.d.ts +12 -0
  13. package/dist/features/magic-context/compaction-marker.d.ts.map +1 -1
  14. package/dist/features/magic-context/memory/project-identity.d.ts +5 -1
  15. package/dist/features/magic-context/memory/project-identity.d.ts.map +1 -1
  16. package/dist/features/magic-context/message-index-async.d.ts +3 -0
  17. package/dist/features/magic-context/message-index-async.d.ts.map +1 -1
  18. package/dist/features/magic-context/message-index.d.ts.map +1 -1
  19. package/dist/features/magic-context/storage-clone.d.ts +2 -0
  20. package/dist/features/magic-context/storage-clone.d.ts.map +1 -1
  21. package/dist/features/magic-context/storage-tags.d.ts +1 -1
  22. package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/compaction-marker-manager.d.ts +3 -0
  24. package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  26. package/dist/hooks/magic-context/history-boundary-repair.d.ts +11 -2
  27. package/dist/hooks/magic-context/history-boundary-repair.d.ts.map +1 -1
  28. package/dist/hooks/magic-context/protected-tail-boundary.d.ts +4 -3
  29. package/dist/hooks/magic-context/protected-tail-boundary.d.ts.map +1 -1
  30. package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts +10 -0
  31. package/dist/hooks/magic-context/raw-ordinal-warmup.d.ts.map +1 -1
  32. package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  34. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  35. package/dist/{index-sfhndpcb.js → index-3wckxwfp.js} +39 -39
  36. package/dist/{index-gzky5rva.js → index-41gqa557.js} +4 -2
  37. package/dist/{index-r2zcs71c.js → index-7ndnvw7a.js} +1 -1
  38. package/dist/{index-sv0bb7vg.js → index-7zg9dvx0.js} +35 -4
  39. package/dist/{index-xgrwmj82.js → index-bhk710rw.js} +1 -1
  40. package/dist/{index-fg00p1cg.js → index-c0b01zrc.js} +2 -2
  41. package/dist/{index-rafsaxac.js → index-fjtgekd4.js} +2 -2
  42. package/dist/{index-fdtkt5r1.js → index-fst3t0d9.js} +9 -9
  43. package/dist/{index-6tfxmc4n.js → index-je2na55n.js} +4 -4
  44. package/dist/{index-h5zfkjyk.js → index-jpm52v9x.js} +6 -24
  45. package/dist/{index-s7fc0fkn.js → index-m4p77myp.js} +1 -1
  46. package/dist/{index-xnanvj3w.js → index-mgy5dwcw.js} +607 -579
  47. package/dist/{index-0pjvpfkf.js → index-qvr78ej6.js} +1 -1
  48. package/dist/{index-zfzdpeq2.js → index-s4ztdn8v.js} +1311 -1271
  49. package/dist/index-v0p37hm2.js +22 -0
  50. package/dist/{index-eypn4ba6.js → index-w9pe0nx1.js} +3 -3
  51. package/dist/{index-p0n5ryq8.js → index-ws3gcy5m.js} +19 -9
  52. package/dist/{index-att4bfan.js → index-xfbfrngb.js} +1 -1
  53. package/dist/{index-nydv6g8r.js → index-yqps2zsv.js} +44 -6
  54. package/dist/index-yxawqmdd.js +212 -0
  55. package/dist/{index-zg8yq4ya.js → index-znzgze2v.js} +3 -3
  56. package/dist/index.js +38 -35
  57. package/dist/{message-index-bounded-hqktkhdy.js → message-index-bounded-pv6ct15d.js} +18 -17
  58. package/dist/message-index-jqa7qd0s.js +60 -0
  59. package/dist/migration-worker.js +3 -3
  60. package/dist/{project-embedding-registry-0gv3h6y8.js → project-embedding-registry-fcmszatg.js} +4 -4
  61. package/dist/raw-ordinal-warmup-worker.js +22 -5
  62. package/dist/{read-session-chunk-5mh0bh8y.js → read-session-chunk-cwgjwjd0.js} +7 -6
  63. package/dist/{read-session-raw-8sjbc9h0.js → read-session-raw-z38cn0as.js} +2 -1
  64. package/dist/{recomp-orchestrator-kpkhkjhq.js → recomp-orchestrator-txcc802e.js} +19 -17
  65. package/dist/{search-p9w39qv4.js → search-v1t47s2q.js} +14 -13
  66. package/dist/{send-session-notification-xffh3bbe.js → send-session-notification-yp9m5g4p.js} +4 -3
  67. package/dist/shared/tag-owner-id.d.ts +1 -0
  68. package/dist/shared/tag-owner-id.d.ts.map +1 -1
  69. package/dist/{storage-tags-k0pda32s.js → storage-tags-0ssbmzg9.js} +2 -2
  70. package/dist/{transform-postprocess-phase-481j5a7z.js → transform-postprocess-phase-113rwew1.js} +19 -17
  71. package/dist/v2/auto-search-worker.js +3 -3
  72. package/dist/v2/compaction-marker-candidates-1s21e2fz.js +18 -0
  73. package/dist/v2/compaction-marker-candidates-worker.js +24 -0
  74. package/dist/v2/{context-gsdtha5v.js → context-p1xf3w5q.js} +115 -44
  75. package/dist/v2/{embedding-backfill-dbvjbcmm.js → embedding-backfill-9hbkfvnz.js} +5 -5
  76. package/dist/v2/{message-index-bounded-p6v0n8qh.js → message-index-bounded-c0810p5w.js} +17 -16
  77. package/dist/v2/message-index-h8ssgq3q.js +59 -0
  78. package/dist/v2/migration-worker.js +3 -3
  79. package/dist/v2/{project-embedding-registry-nyq7z8y6.js → project-embedding-registry-42th7k1z.js} +4 -4
  80. package/dist/v2/raw-ordinal-warmup-worker.js +22 -5
  81. package/dist/v2/{read-session-chunk-fhyfe4qa.js → read-session-chunk-n86v9xfg.js} +6 -5
  82. package/dist/v2/{read-session-raw-j8dvp7f4.js → read-session-raw-3b3ehga4.js} +2 -1
  83. package/dist/v2/{recomp-orchestrator-5xy7w136.js → recomp-orchestrator-v168jwgg.js} +16 -14
  84. package/dist/v2/{search-j7bakcwa.js → search-048v8y02.js} +13 -12
  85. package/dist/v2/{send-session-notification-f6v698r5.js → send-session-notification-a4h2azxa.js} +2 -1
  86. package/dist/v2/{server-bgzy0phk.js → server-3bc6k4k4.js} +62 -33
  87. package/dist/v2/{server-7h861yms.js → server-3dqjhchy.js} +5 -18
  88. package/dist/v2/{server-c7n2ftng.js → server-4n2tknpc.js} +34 -3
  89. package/dist/v2/server-51779zs2.js +19 -0
  90. package/dist/v2/{server-kh958yj8.js → server-5zrpr764.js} +1 -1
  91. package/dist/v2/{server-6tcrjfw8.js → server-8pqnnmf9.js} +1 -1
  92. package/dist/v2/server-9290a1mb.js +212 -0
  93. package/dist/v2/{server-7vkj6zhb.js → server-9a6v0wth.js} +3 -3
  94. package/dist/v2/{server-1fszbabv.js → server-cjz51jm2.js} +2 -2
  95. package/dist/v2/{server-7spkq1y6.js → server-cxxjb33r.js} +2286 -2246
  96. package/dist/v2/{server-mqvtz7wz.js → server-hetyb88z.js} +9 -9
  97. package/dist/v2/{server-4c7jt8gq.js → server-pcygfdbs.js} +44 -6
  98. package/dist/v2/{server-8xmq9h3f.js → server-q6j5dasr.js} +4 -2
  99. package/dist/v2/{server-zbxjj2mz.js → server-rygvffsf.js} +2 -2
  100. package/dist/v2/server.js +4 -4
  101. package/dist/v2/{storage-tags-5yxrvkaf.js → storage-tags-3a4cavqb.js} +2 -2
  102. package/dist/v2/{wrapup-orchestrator-yem5422s.js → wrapup-orchestrator-zcyf8ymw.js} +14 -12
  103. package/dist/{wrapup-orchestrator-xvrr27ws.js → wrapup-orchestrator-5aa2q4v3.js} +20 -18
  104. package/package.json +3 -3
  105. package/src/config/latch-permanence-guard.test.ts +6 -1
  106. package/src/shared/sqlite-writer-diagnostics.test.ts +21 -10
  107. package/src/shared/tag-owner-id.ts +13 -0
  108. package/src/shared/tag-transcript.test.ts +6 -1
  109. package/src/shared/tag-transcript.ts +2 -1
  110. package/src/shared/windows-hidden-spawns.test.ts +60 -4
  111. /package/dist/{index-69vas84q.js → index-e6xnpach.js} +0 -0
  112. /package/dist/{index-p1hnwfd8.js → index-gcdb3rqw.js} +0 -0
  113. /package/dist/v2/{index-69vas84q.js → index-e6xnpach.js} +0 -0
  114. /package/dist/v2/{server-s2st631p.js → server-8wcf79fe.js} +0 -0
@@ -53,7 +53,7 @@ import {
53
53
  storedPathBelongsToIdentity,
54
54
  beginBootQuietPeriod,
55
55
  scheduleAfterBootQuiet
56
- } from "./index-gzky5rva.js";
56
+ } from "./index-41gqa557.js";
57
57
  import {
58
58
  recordSessionProjectIdentity,
59
59
  hasRecordedSessionProjectIdentity,
@@ -80,7 +80,7 @@ import {
80
80
  drainCommitBacklogForProject2,
81
81
  embedSessionCompartmentChunks2,
82
82
  getEmbeddingCoverageStatus2
83
- } from "./index-fg00p1cg.js";
83
+ } from "./index-c0b01zrc.js";
84
84
  import {
85
85
  hasTrustedAbsoluteWall,
86
86
  applyProvenInputFloor,
@@ -142,7 +142,7 @@ import {
142
142
  getDroppedTagsByNumbers2,
143
143
  getMaxDroppedTagNumber2,
144
144
  getTagById2
145
- } from "./index-nydv6g8r.js";
145
+ } from "./index-yqps2zsv.js";
146
146
  import {
147
147
  observeTemporalDecisions
148
148
  } from "./index-1bt88epp.js";
@@ -164,7 +164,7 @@ import {
164
164
  extractInMemoryMessageViews2,
165
165
  buildInMemoryTailRawMessages2,
166
166
  runSessionWarmupWorker
167
- } from "./index-h5zfkjyk.js";
167
+ } from "./index-jpm52v9x.js";
168
168
  import {
169
169
  openCodeDbExists,
170
170
  withReadOnlySessionDb,
@@ -172,7 +172,7 @@ import {
172
172
  latestPersistedMessageForRecovery,
173
173
  latestRealUserTurnIdFromOpenCodeDb,
174
174
  findLastAssistantModelFromOpenCodeDb
175
- } from "./index-0pjvpfkf.js";
175
+ } from "./index-qvr78ej6.js";
176
176
  import {
177
177
  expandToolPart,
178
178
  estimateTrueRawMessageTokens,
@@ -284,7 +284,7 @@ import {
284
284
  readRawSessionMessageById2,
285
285
  readSessionChunk2,
286
286
  readRawSessionSeedTail2
287
- } from "./index-sv0bb7vg.js";
287
+ } from "./index-7zg9dvx0.js";
288
288
  import {
289
289
  getMeasuredToolDefinitionTokens
290
290
  } from "./index-h2wc01qk.js";
@@ -315,7 +315,7 @@ import {
315
315
  runSqliteOptimize,
316
316
  openDatabase,
317
317
  openCurrentDatabase
318
- } from "./index-zg8yq4ya.js";
318
+ } from "./index-znzgze2v.js";
319
319
  import {
320
320
  registerOwnRpcServerInstance,
321
321
  rpcPortDir,
@@ -337,7 +337,7 @@ import {
337
337
  resolveStoredPathWorkspaceIdentity,
338
338
  storedPathBelongsToWorkspace,
339
339
  computeWorkspaceEpochFingerprint
340
- } from "./index-att4bfan.js";
340
+ } from "./index-xfbfrngb.js";
341
341
  import {
342
342
  V2_MEMORY_CATEGORIES,
343
343
  CATEGORY_PRIORITY
@@ -466,12 +466,13 @@ import {
466
466
  dismissUserMemory,
467
467
  getMuralIdentity,
468
468
  getMural,
469
+ getOpenCodeDbPath,
470
+ prepareCompactionMarkerCandidates,
471
+ removeMcOwnedCompactionMarkers,
469
472
  readCoordinateGeneration,
470
473
  readCoordinateRebaseNotice,
471
474
  formatCoordinateRebaseNotice,
472
475
  rebaseSessionCoordinatesAsync,
473
- getOpenCodeDbPath,
474
- removeMcOwnedCompactionMarkers,
475
476
  MARKER_SUMMARY_TEXT,
476
477
  markerUpdateDefinitelyDidNotCut,
477
478
  buildMagicContextSection,
@@ -508,7 +509,7 @@ import {
508
509
  snapRangeToCompartments,
509
510
  getActiveCompartmentRun,
510
511
  startCompartmentAgent
511
- } from "./index-zfzdpeq2.js";
512
+ } from "./index-s4ztdn8v.js";
512
513
  import {
513
514
  SubcClient,
514
515
  connectionFileExists,
@@ -528,16 +529,16 @@ import {
528
529
  prepareLkgCaptureFence,
529
530
  certifyCommittedLkgCapture,
530
531
  markLkgRecoveryDirty,
531
- getMessageIndexSourceIdentity,
532
- isMessageIndexSourceCurrent,
533
- getLastIndexedOrdinal,
534
- getMessageIndexReconciliationStartOrdinal,
535
- isMessageIndexReconciledThrough,
536
- clearIndexedMessages,
537
- indexSingleMessage,
538
- indexMessagesAfterOrdinal,
539
- sweepOrphanedOpenCodeMessageIndexes
540
- } from "./index-sfhndpcb.js";
532
+ getMessageIndexSourceIdentity2,
533
+ isMessageIndexSourceCurrent2,
534
+ getLastIndexedOrdinal2,
535
+ getMessageIndexReconciliationStartOrdinal2,
536
+ isMessageIndexReconciledThrough2,
537
+ clearIndexedMessages2,
538
+ indexSingleMessage2,
539
+ indexMessagesAfterOrdinal2,
540
+ sweepOrphanedOpenCodeMessageIndexes2
541
+ } from "./index-3wckxwfp.js";
541
542
  import {
542
543
  renderUserFacingFailure,
543
544
  userFacingFailureCode,
@@ -581,7 +582,7 @@ import {
581
582
  readGitFileChangeTimesSince,
582
583
  verificationFileExists,
583
584
  normalizeVerificationFiles
584
- } from "./index-rafsaxac.js";
585
+ } from "./index-fjtgekd4.js";
585
586
  import {
586
587
  registerNotificationSink2,
587
588
  pushNotification2,
@@ -599,7 +600,7 @@ import {
599
600
  } from "./index-4dhv7mqz.js";
600
601
  import {
601
602
  cosineSimilarity
602
- } from "./index-r2zcs71c.js";
603
+ } from "./index-7ndnvw7a.js";
603
604
  import {
604
605
  computeCueContentHash,
605
606
  hasMuralCueColumns,
@@ -645,17 +646,17 @@ import {
645
646
  resolveMemoriesByIdsForSearch2,
646
647
  unifiedSearch2,
647
648
  formatSearchResults2
648
- } from "./index-fdtkt5r1.js";
649
+ } from "./index-fst3t0d9.js";
649
650
  import {
650
651
  flushIgnoredMessages2,
651
652
  clearIgnoredMessages2,
652
653
  observeIgnoredNotificationEvent2,
653
654
  sendStatusNotification2
654
- } from "./index-xgrwmj82.js";
655
+ } from "./index-bhk710rw.js";
655
656
  import {
656
657
  setRecompStarting2,
657
658
  setRecompTerminal2
658
- } from "./index-eypn4ba6.js";
659
+ } from "./index-w9pe0nx1.js";
659
660
  import {
660
661
  searchMessageHistoryOffThread,
661
662
  findSessionId,
@@ -705,7 +706,7 @@ import {
705
706
  abortSessionFailClosed2,
706
707
  evaluateEmergencyFailClosed2,
707
708
  runPostTransformPhase2
708
- } from "./index-p0n5ryq8.js";
709
+ } from "./index-ws3gcy5m.js";
709
710
  import {
710
711
  ANNOUNCEMENT_VERSION2,
711
712
  ANNOUNCEMENT_FEATURES2,
@@ -4967,7 +4968,7 @@ function getAsyncModule() {
4967
4968
  await beforeModuleLoad();
4968
4969
  const [{ default: singlefileAsyncifyVariant }, { newQuickJSAsyncWASMModuleFromVariant }] = await importPluginModule(() => Promise.all([
4969
4970
  import("./index-e7vx3byk.js").then((m)=>__toESM(m.default,1)),
4970
- import("./index-69vas84q.js")
4971
+ import("./index-e6xnpach.js")
4971
4972
  ]));
4972
4973
  const module = await newQuickJSAsyncWASMModuleFromVariant(singlefileAsyncifyVariant);
4973
4974
  return module;
@@ -10834,174 +10835,506 @@ function clearDreamerTickFailure(db) {
10834
10835
  db.prepare("DELETE FROM schema_migrations_meta WHERE key = ?").run(DREAMER_TICK_FAILURE_KEY);
10835
10836
  }
10836
10837
 
10837
- // src/plugin/dream-timer.ts
10838
- var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
10839
- var GIT_COMMIT_BACKLOG_DRAIN_MAX_MS = 5 * 60 * 1000;
10840
- var BOOT_PROJECT_JITTER_SLOT_MS = 1000;
10841
- var activeTimer = null;
10842
- var tickInFlight = false;
10843
- var startupTickTimer = null;
10844
- var startupTimers = new Map;
10845
- var startupJitters = new Map;
10846
- var nextStartupJitterSlot = 0;
10847
- function directoryStillExists(directory) {
10848
- try {
10849
- return statSync2(directory).isDirectory();
10850
- } catch {
10838
+ // src/features/magic-context/message-index-async.ts
10839
+ var indexCancellations = new Map;
10840
+ var sessionEpochs = new Map;
10841
+ var workerMeasurements = new WeakMap;
10842
+ function isDatabaseLockedError(error) {
10843
+ if (!error || typeof error !== "object")
10851
10844
  return false;
10845
+ const e = error;
10846
+ if (typeof e.code === "string") {
10847
+ if (e.code === "SQLITE_BUSY" || e.code === "SQLITE_LOCKED")
10848
+ return true;
10852
10849
  }
10853
- }
10854
- function openTimerDatabaseOrNull(context) {
10855
- let db;
10856
- try {
10857
- db = openCurrentDatabase();
10858
- } catch (error) {
10859
- log2(`[dreamer] storage fatal; skipping ${context}: ${getErrorMessage(error)}`);
10860
- return null;
10861
- }
10862
- if (!db) {
10863
- log2(`[dreamer] storage unavailable; skipping ${context} (the cache schema is newer than this binary supports — restart/upgrade OpenCode/Pi/Magic Context to recover)`);
10864
- return null;
10850
+ if (typeof e.message === "string") {
10851
+ if (/database is locked/i.test(e.message))
10852
+ return true;
10853
+ if (/sqlite_(busy|locked)/i.test(e.message))
10854
+ return true;
10865
10855
  }
10866
- return db;
10856
+ return false;
10867
10857
  }
10868
- var refusedEmptyIdentityDirectories = new Set;
10869
- function logEmptyIdentityRefusalOnce(directory) {
10870
- if (refusedEmptyIdentityDirectories.has(directory))
10871
- return;
10872
- refusedEmptyIdentityDirectories.add(directory);
10873
- log2(`[dreamer] not registering ${directory}: it has no project identity, so no project-scoped work runs for it`);
10858
+ var INCREMENTAL_DEBOUNCE_MS = 100;
10859
+ var RECONCILIATION_BATCH_SIZE = 100;
10860
+
10861
+ class MagicContextMessageIndexHeapHolder {
10862
+ reconciledSessions = new Set;
10863
+ reconciliationScheduledSessions = new Set;
10864
+ clearAndReindexScheduledSessions = new Map;
10865
+ sessionLocks = new Map;
10866
+ incrementalTimers = new Map;
10867
+ pendingIncrementalKeys = new Set;
10868
+ completedIncrementalKeys = new Set;
10869
+ activeReconcilerBuffers = new Map;
10874
10870
  }
10875
- var registeredProjects = new Map;
10876
- function stopDreamScheduleTimerIfIdle() {
10877
- if (registeredProjects.size !== 0)
10878
- return;
10879
- const stopped = activeTimer !== null || startupTickTimer !== null;
10880
- if (activeTimer) {
10881
- clearInterval(activeTimer);
10882
- activeTimer = null;
10883
- }
10884
- if (startupTickTimer) {
10885
- clearTimeout(startupTickTimer);
10886
- startupTickTimer = null;
10871
+ var heapHolder = new MagicContextMessageIndexHeapHolder;
10872
+ function clearCompletedIncrementalKeys(sessionId) {
10873
+ const prefix = `${sessionId}\x00`;
10874
+ for (const key of heapHolder.completedIncrementalKeys) {
10875
+ if (key.startsWith(prefix))
10876
+ heapHolder.completedIncrementalKeys.delete(key);
10887
10877
  }
10888
- startupJitters.clear();
10889
- nextStartupJitterSlot = 0;
10890
- if (stopped)
10891
- log2("[dreamer] stopped dream schedule timer (no projects left)");
10892
10878
  }
10893
- async function startDreamScheduleTimer(args) {
10894
- if (!isUsableProjectIdentity(args.projectIdentity)) {
10895
- logEmptyIdentityRefusalOnce(args.directory);
10879
+ var PREPARE_RETRY_MS = 60000;
10880
+ async function sourceReady(source, sessionId) {
10881
+ const prepare = source?.prepare;
10882
+ return typeof prepare === "function" ? prepare(sessionId) : true;
10883
+ }
10884
+ function defer(fn) {
10885
+ const immediate = globalThis.setImmediate;
10886
+ if (typeof immediate === "function") {
10887
+ immediate(fn);
10896
10888
  return;
10897
10889
  }
10898
- beginBootQuietPeriod();
10899
- const db = openTimerDatabaseOrNull("schedule timer registration");
10900
- if (!db)
10890
+ setTimeout(fn, 0);
10891
+ }
10892
+ function yieldToEventLoop() {
10893
+ return new Promise((resolve) => defer(resolve));
10894
+ }
10895
+ function runWithSessionLock(sessionId, operation) {
10896
+ const previous = heapHolder.sessionLocks.get(sessionId) ?? Promise.resolve();
10897
+ const run = previous.catch(() => {
10901
10898
  return;
10902
- const dreamingEnabled = Boolean(args.dreamerConfig && args.dreamerConfig.disable !== true);
10903
- const embeddingSweepEnabled = args.memoryEnabled === true;
10904
- const commitIndexingEnabled = args.gitCommitIndexing?.enabled === true;
10905
- const previousRegistration = registeredProjects.get(args.directory);
10906
- const isNewRegistration = previousRegistration === undefined;
10907
- if (previousRegistration && previousRegistration !== args) {
10908
- const pendingStartup = startupTimers.get(args.directory);
10909
- if (pendingStartup) {
10910
- clearTimeout(pendingStartup);
10911
- startupTimers.delete(args.directory);
10899
+ }).then(async () => {
10900
+ await operation();
10901
+ });
10902
+ heapHolder.sessionLocks.set(sessionId, run);
10903
+ run.finally(() => {
10904
+ if (heapHolder.sessionLocks.get(sessionId) === run) {
10905
+ heapHolder.sessionLocks.delete(sessionId);
10912
10906
  }
10907
+ }).catch(() => {
10908
+ return;
10909
+ });
10910
+ return run;
10911
+ }
10912
+ function logIndexingError(sessionId, action, error) {
10913
+ if (isDatabaseLockedError(error)) {
10914
+ sessionLog2(sessionId, `message FTS async ${action} skipped (database busy; will retry on next reconciliation)`);
10915
+ return;
10913
10916
  }
10914
- registeredProjects.set(args.directory, args);
10915
- if (isNewRegistration) {
10916
- log2(`[dreamer] registered project ${args.projectIdentity} (dreaming=${dreamingEnabled} embeddings=${embeddingSweepEnabled} commits=${commitIndexingEnabled}; total=${registeredProjects.size})`);
10917
- }
10918
- if (!activeTimer) {
10919
- log2(`[dreamer] started independent schedule timer (every ${DREAM_TIMER_INTERVAL_MS / 60000}m)`);
10920
- startupTickTimer = scheduleAfterBootQuiet(() => {
10921
- startupTickTimer = null;
10922
- runTick("startup");
10923
- });
10924
- const timer = setInterval(() => runTick("interval"), DREAM_TIMER_INTERVAL_MS);
10925
- if (typeof timer === "object" && "unref" in timer) {
10926
- timer.unref();
10927
- }
10928
- activeTimer = timer;
10929
- } else if (isNewRegistration || previousRegistration !== args) {
10930
- scheduleInitialProjectRun(args, db);
10917
+ sessionLog2(sessionId, `message FTS async ${action} failed: ${error instanceof Error ? error.message : String(error)}`);
10918
+ log2(`[message-index-async] ${action} failed for ${sessionId}:`, error);
10919
+ }
10920
+ function serializedMessageBytes(messages) {
10921
+ try {
10922
+ return Buffer.byteLength(JSON.stringify(messages));
10923
+ } catch {
10924
+ return 0;
10931
10925
  }
10932
- return () => {
10933
- if (registeredProjects.get(args.directory) !== args) {
10934
- stopDreamScheduleTimerIfIdle();
10935
- return;
10936
- }
10937
- registeredProjects.delete(args.directory);
10938
- const startupTimer = startupTimers.get(args.directory);
10939
- if (startupTimer) {
10940
- clearTimeout(startupTimer);
10941
- startupTimers.delete(args.directory);
10942
- }
10943
- log2(`[dreamer] unregistered project ${args.projectIdentity} (remaining=${registeredProjects.size})`);
10944
- stopDreamScheduleTimerIfIdle();
10945
- };
10946
10926
  }
10947
- var tickStages = {
10948
- runMessageHistoryMaintenance,
10949
- runProjectMaintenance
10950
- };
10951
- function runTick(origin) {
10952
- if (tickInFlight)
10953
- return;
10954
- tickInFlight = true;
10955
- log2(`[dreamer] timer tick (${origin}) — projects=${registeredProjects.size}`);
10956
- (async () => {
10927
+ async function reconcileSessionIndex(db, sessionId, readMessages) {
10928
+ if (!await sourceReady(readMessages, sessionId))
10929
+ return false;
10930
+ await runWithSessionLock(sessionId, async () => {
10931
+ if (heapHolder.reconciledSessions.has(sessionId))
10932
+ return;
10933
+ let fallbackSnapshot = null;
10957
10934
  try {
10958
- const db = openTimerDatabaseOrNull("maintenance tick");
10959
- if (!db)
10960
- return;
10961
- let failure = null;
10962
- const noteFailure = (stage, error) => {
10963
- failure ??= { at: Date.now(), stage, message: getErrorMessage(error) };
10964
- };
10965
- try {
10966
- await tickStages.runMessageHistoryMaintenance(db);
10967
- } catch (error) {
10968
- log2("[magic-context] timer-triggered message-history maintenance failed:", error);
10969
- noteFailure("message-history maintenance", error);
10970
- }
10971
- for (const reg of registeredProjects.values()) {
10972
- try {
10973
- if (origin === "startup") {
10974
- scheduleInitialProjectRun(reg, db);
10975
- } else {
10976
- await tickStages.runProjectMaintenance(reg, origin, db);
10977
- }
10978
- } catch (error) {
10979
- log2(`[magic-context] timer-triggered maintenance failed for ${reg.projectIdentity}:`, error);
10980
- noteFailure(`project ${reg.projectIdentity}`, error);
10935
+ const fullReader = typeof readMessages === "function" ? readMessages : null;
10936
+ const finalWatermark = readMessages.getCount ? readMessages.getCount(sessionId) : (fallbackSnapshot = fullReader?.(sessionId) ?? []).length;
10937
+ let cursor = getMessageIndexReconciliationStartOrdinal2(db, sessionId);
10938
+ let after;
10939
+ while (cursor < finalWatermark) {
10940
+ const pageEnd = Math.min(finalWatermark, cursor + RECONCILIATION_BATCH_SIZE);
10941
+ const messages = readMessages.readPage ? readMessages.readPage(sessionId, cursor, RECONCILIATION_BATCH_SIZE, finalWatermark, after) : (fallbackSnapshot ?? []).filter((message) => message.ordinal > cursor && message.ordinal <= pageEnd);
10942
+ const retainedMessages = fallbackSnapshot ?? messages;
10943
+ heapHolder.activeReconcilerBuffers.set(sessionId, retainedMessages);
10944
+ withSqliteBackgroundWriter2(() => indexMessagesAfterOrdinal2(db, sessionId, messages, cursor, pageEnd));
10945
+ const nextCursor = getMessageIndexReconciliationStartOrdinal2(db, sessionId);
10946
+ if (nextCursor <= cursor)
10947
+ break;
10948
+ cursor = nextCursor;
10949
+ const last = messages.at(-1);
10950
+ after = last?.ordinal === cursor && typeof last.createdAt === "number" ? { timeCreated: last.createdAt, id: last.id } : undefined;
10951
+ if (cursor < finalWatermark) {
10952
+ await yieldToEventLoop();
10981
10953
  }
10982
10954
  }
10983
- persistTickOutcome(db, failure);
10984
- if (origin === "startup")
10985
- return;
10986
- runSqliteOptimize(db);
10987
- } catch (error) {
10988
- log2("[magic-context] timer-triggered maintenance check failed:", error);
10955
+ if (isMessageIndexReconciledThrough2(db, sessionId, finalWatermark)) {
10956
+ heapHolder.reconciledSessions.add(sessionId);
10957
+ }
10989
10958
  } finally {
10990
- tickInFlight = false;
10959
+ heapHolder.activeReconcilerBuffers.delete(sessionId);
10991
10960
  }
10992
- })();
10961
+ });
10962
+ return true;
10993
10963
  }
10994
- function persistTickOutcome(db, failure) {
10995
- try {
10996
- if (failure)
10997
- recordDreamerTickFailure(db, failure);
10998
- else
10999
- clearDreamerTickFailure(db);
11000
- } catch (error) {
11001
- log2("[dreamer] could not persist the outcome of this tick:", error);
10964
+ function scheduleReconciliation(db, sessionId, readMessages) {
10965
+ if (heapHolder.reconciledSessions.has(sessionId) || heapHolder.reconciliationScheduledSessions.has(sessionId)) {
10966
+ return;
11002
10967
  }
11003
- }
11004
- async function runMessageHistoryMaintenance(db) {
10968
+ heapHolder.reconciliationScheduledSessions.add(sessionId);
10969
+ scheduleAfterBootQuiet(() => {
10970
+ defer(() => {
10971
+ reconcileSessionIndex(db, sessionId, readMessages).then((ran) => {
10972
+ if (ran)
10973
+ return;
10974
+ setTimeout(() => {
10975
+ heapHolder.reconciliationScheduledSessions.delete(sessionId);
10976
+ scheduleReconciliation(db, sessionId, readMessages);
10977
+ }, PREPARE_RETRY_MS).unref?.();
10978
+ }).catch((error) => {
10979
+ logIndexingError(sessionId, "reconciliation", error);
10980
+ if (isDatabaseLockedError(error))
10981
+ setTimeout(() => scheduleReconciliation(db, sessionId, readMessages), 1000).unref();
10982
+ }).finally(() => {
10983
+ heapHolder.reconciliationScheduledSessions.delete(sessionId);
10984
+ });
10985
+ });
10986
+ });
10987
+ }
10988
+ function scheduleIncrementalIndex(db, sessionId, messageId, messageSource) {
10989
+ const schedulingKey = `${sessionId}\x00${messageId}`;
10990
+ const epoch = sessionEpochs.get(sessionId) ?? 0;
10991
+ if (heapHolder.pendingIncrementalKeys.has(schedulingKey))
10992
+ return;
10993
+ const activeTimer = heapHolder.incrementalTimers.get(schedulingKey);
10994
+ if (activeTimer)
10995
+ clearTimeout(activeTimer);
10996
+ const timer = setTimeout(() => {
10997
+ heapHolder.incrementalTimers.delete(schedulingKey);
10998
+ heapHolder.pendingIncrementalKeys.add(schedulingKey);
10999
+ const indexMessage = async () => {
11000
+ if ((sessionEpochs.get(sessionId) ?? 0) !== epoch || !heapHolder.pendingIncrementalKeys.has(schedulingKey))
11001
+ return;
11002
+ const message = typeof messageSource === "function" ? messageSource(sessionId, messageId) : messageSource;
11003
+ if (!message)
11004
+ return;
11005
+ const revisionKey = `${schedulingKey}\x00${getMessageIndexSourceIdentity2(message)}`;
11006
+ if (heapHolder.completedIncrementalKeys.has(revisionKey))
11007
+ return;
11008
+ const currentWatermark = getLastIndexedOrdinal2(db, sessionId);
11009
+ if (message.ordinal <= currentWatermark && isMessageIndexSourceCurrent2(db, sessionId, message)) {
11010
+ heapHolder.completedIncrementalKeys.add(revisionKey);
11011
+ return;
11012
+ }
11013
+ const wasReconciled = heapHolder.reconciledSessions.delete(sessionId);
11014
+ await indexSingleMessageOffThread(db, sessionId, message);
11015
+ if ((sessionEpochs.get(sessionId) ?? 0) !== epoch || !heapHolder.pendingIncrementalKeys.has(schedulingKey))
11016
+ return;
11017
+ const finalWatermark = getLastIndexedOrdinal2(db, sessionId);
11018
+ if (wasReconciled && isMessageIndexReconciledThrough2(db, sessionId, finalWatermark)) {
11019
+ heapHolder.reconciledSessions.add(sessionId);
11020
+ }
11021
+ heapHolder.completedIncrementalKeys.add(revisionKey);
11022
+ };
11023
+ sourceReady(messageSource, sessionId).then((ready) => {
11024
+ if ((sessionEpochs.get(sessionId) ?? 0) !== epoch)
11025
+ return;
11026
+ if (ready)
11027
+ return runWithSessionLock(sessionId, indexMessage);
11028
+ setTimeout(() => scheduleIncrementalIndex(db, sessionId, messageId, messageSource), PREPARE_RETRY_MS).unref?.();
11029
+ }).catch((error) => {
11030
+ if ((sessionEpochs.get(sessionId) ?? 0) !== epoch)
11031
+ return;
11032
+ heapHolder.reconciledSessions.delete(sessionId);
11033
+ logIndexingError(sessionId, `incremental index for ${messageId}`, error);
11034
+ if (isDatabaseLockedError(error))
11035
+ setTimeout(() => scheduleIncrementalIndex(db, sessionId, messageId, messageSource), 1000).unref();
11036
+ }).finally(() => {
11037
+ if ((sessionEpochs.get(sessionId) ?? 0) === epoch)
11038
+ heapHolder.pendingIncrementalKeys.delete(schedulingKey);
11039
+ });
11040
+ }, INCREMENTAL_DEBOUNCE_MS);
11041
+ heapHolder.incrementalTimers.set(schedulingKey, timer);
11042
+ }
11043
+ async function indexSingleMessageOffThread(db, sessionId, message) {
11044
+ const path = getSqliteDatabasePath2(db);
11045
+ if (!path)
11046
+ return withSqliteBackgroundWriter2(() => indexSingleMessage2(db, sessionId, message));
11047
+ const cancellation = new Int32Array(new SharedArrayBuffer(4));
11048
+ const active = indexCancellations.get(sessionId) ?? new Set;
11049
+ active.add(cancellation);
11050
+ indexCancellations.set(sessionId, active);
11051
+ const result = await runSessionWarmupWorker({
11052
+ path,
11053
+ sessionId,
11054
+ indexMessage: message,
11055
+ harness: getHarness2(),
11056
+ indexCancellation: cancellation.buffer,
11057
+ ...indexCoordinationInput2()
11058
+ }, {}).finally(() => {
11059
+ active.delete(cancellation);
11060
+ if (active.size === 0)
11061
+ indexCancellations.delete(sessionId);
11062
+ });
11063
+ if (!("inserted" in result))
11064
+ throw new Error("failure" in result ? result.detail : "unexpected indexing worker reply");
11065
+ if (result.measurements) {
11066
+ const sessions = workerMeasurements.get(db) ?? new Map;
11067
+ sessions.set(sessionId, result.measurements);
11068
+ workerMeasurements.set(db, sessions);
11069
+ if (result.measurements.skipped)
11070
+ log2(`[magic-context] incremental FTS skipped oversized source ${message.id} (${result.measurements.sourceBytes} bytes); identity and progress persisted`);
11071
+ }
11072
+ return result.inserted;
11073
+ }
11074
+ async function sweepOrphanedOpenCodeMessageIndexesOffThread(db, openSource, options = {}) {
11075
+ const path = getSqliteDatabasePath2(db);
11076
+ if (!path || getHarness2() !== "opencode")
11077
+ return sweepOrphanedOpenCodeMessageIndexes2(db, openSource, options);
11078
+ let source = null;
11079
+ let sourcePath = null;
11080
+ try {
11081
+ source = openSource();
11082
+ if (source)
11083
+ sourcePath = getSqliteDatabasePath2(source);
11084
+ } catch {} finally {
11085
+ if (sourcePath)
11086
+ source?.close();
11087
+ }
11088
+ if (!sourcePath)
11089
+ return sweepOrphanedOpenCodeMessageIndexes2(db, () => source, options);
11090
+ const reply = await runSessionWarmupWorker({
11091
+ path,
11092
+ sessionId: "",
11093
+ harness: getHarness2(),
11094
+ orphanSweep: { sourcePath, options }
11095
+ }, {});
11096
+ if (!("orphanSweep" in reply))
11097
+ throw new Error("message history orphan sweep worker failed");
11098
+ return reply.orphanSweep;
11099
+ }
11100
+ function scheduleClearAndReindex(db, sessionId, readMessages) {
11101
+ heapHolder.reconciledSessions.delete(sessionId);
11102
+ heapHolder.reconciliationScheduledSessions.delete(sessionId);
11103
+ clearCompletedIncrementalKeys(sessionId);
11104
+ const existing = heapHolder.clearAndReindexScheduledSessions.get(sessionId);
11105
+ if (existing) {
11106
+ existing.source = readMessages;
11107
+ return;
11108
+ }
11109
+ const pending = { source: readMessages };
11110
+ heapHolder.clearAndReindexScheduledSessions.set(sessionId, pending);
11111
+ scheduleAfterBootQuiet(() => {
11112
+ defer(() => {
11113
+ let cleared = false;
11114
+ runWithSessionLock(sessionId, () => {
11115
+ if (heapHolder.clearAndReindexScheduledSessions.get(sessionId) !== pending)
11116
+ return;
11117
+ heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
11118
+ heapHolder.reconciledSessions.delete(sessionId);
11119
+ clearCompletedIncrementalKeys(sessionId);
11120
+ clearIndexedMessages2(db, sessionId);
11121
+ cleared = true;
11122
+ }).then(() => cleared ? reconcileSessionIndex(db, sessionId, pending.source) : undefined).catch((error) => {
11123
+ heapHolder.reconciledSessions.delete(sessionId);
11124
+ if (heapHolder.clearAndReindexScheduledSessions.get(sessionId) === pending)
11125
+ heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
11126
+ logIndexingError(sessionId, "clear and reindex", error);
11127
+ });
11128
+ });
11129
+ });
11130
+ }
11131
+ function getMessageIndexQueueHeapStats() {
11132
+ return {
11133
+ queueLength: heapHolder.reconciliationScheduledSessions.size + heapHolder.incrementalTimers.size + heapHolder.pendingIncrementalKeys.size,
11134
+ reconciliationScheduled: heapHolder.reconciliationScheduledSessions.size,
11135
+ incrementalTimers: heapHolder.incrementalTimers.size,
11136
+ pendingIncremental: heapHolder.pendingIncrementalKeys.size,
11137
+ activeSessionLocks: heapHolder.sessionLocks.size,
11138
+ completedIncrementalKeys: heapHolder.completedIncrementalKeys.size,
11139
+ activeBufferMessages: [...heapHolder.activeReconcilerBuffers.values()].reduce((sum, messages) => sum + messages.length, 0),
11140
+ activeBufferBytes: [...heapHolder.activeReconcilerBuffers.values()].reduce((sum, messages) => sum + serializedMessageBytes(messages), 0)
11141
+ };
11142
+ }
11143
+ function clearSessionTracking(sessionId) {
11144
+ sessionEpochs.set(sessionId, (sessionEpochs.get(sessionId) ?? 0) + 1);
11145
+ for (const cancellation of indexCancellations.get(sessionId) ?? [])
11146
+ Atomics.store(cancellation, 0, 1);
11147
+ heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
11148
+ heapHolder.reconciledSessions.delete(sessionId);
11149
+ heapHolder.reconciliationScheduledSessions.delete(sessionId);
11150
+ heapHolder.sessionLocks.delete(sessionId);
11151
+ heapHolder.activeReconcilerBuffers.delete(sessionId);
11152
+ const prefix = `${sessionId}\x00`;
11153
+ for (const [key, timer] of heapHolder.incrementalTimers) {
11154
+ if (key.startsWith(prefix)) {
11155
+ clearTimeout(timer);
11156
+ heapHolder.incrementalTimers.delete(key);
11157
+ }
11158
+ }
11159
+ for (const key of heapHolder.pendingIncrementalKeys) {
11160
+ if (key.startsWith(prefix)) {
11161
+ heapHolder.pendingIncrementalKeys.delete(key);
11162
+ }
11163
+ }
11164
+ for (const key of heapHolder.completedIncrementalKeys) {
11165
+ if (key.startsWith(prefix))
11166
+ heapHolder.completedIncrementalKeys.delete(key);
11167
+ }
11168
+ }
11169
+
11170
+ // src/plugin/dream-timer.ts
11171
+ var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
11172
+ var GIT_COMMIT_BACKLOG_DRAIN_MAX_MS = 5 * 60 * 1000;
11173
+ var BOOT_PROJECT_JITTER_SLOT_MS = 1000;
11174
+ var activeTimer = null;
11175
+ var tickInFlight = false;
11176
+ var startupTickTimer = null;
11177
+ var startupTimers = new Map;
11178
+ var startupJitters = new Map;
11179
+ var nextStartupJitterSlot = 0;
11180
+ function directoryStillExists(directory) {
11181
+ try {
11182
+ return statSync2(directory).isDirectory();
11183
+ } catch {
11184
+ return false;
11185
+ }
11186
+ }
11187
+ function openTimerDatabaseOrNull(context) {
11188
+ let db;
11189
+ try {
11190
+ db = openCurrentDatabase();
11191
+ } catch (error) {
11192
+ log2(`[dreamer] storage fatal; skipping ${context}: ${getErrorMessage(error)}`);
11193
+ return null;
11194
+ }
11195
+ if (!db) {
11196
+ log2(`[dreamer] storage unavailable; skipping ${context} (the cache schema is newer than this binary supports — restart/upgrade OpenCode/Pi/Magic Context to recover)`);
11197
+ return null;
11198
+ }
11199
+ return db;
11200
+ }
11201
+ var refusedEmptyIdentityDirectories = new Set;
11202
+ function logEmptyIdentityRefusalOnce(directory) {
11203
+ if (refusedEmptyIdentityDirectories.has(directory))
11204
+ return;
11205
+ refusedEmptyIdentityDirectories.add(directory);
11206
+ log2(`[dreamer] not registering ${directory}: it has no project identity, so no project-scoped work runs for it`);
11207
+ }
11208
+ var registeredProjects = new Map;
11209
+ function stopDreamScheduleTimerIfIdle() {
11210
+ if (registeredProjects.size !== 0)
11211
+ return;
11212
+ const stopped = activeTimer !== null || startupTickTimer !== null;
11213
+ if (activeTimer) {
11214
+ clearInterval(activeTimer);
11215
+ activeTimer = null;
11216
+ }
11217
+ if (startupTickTimer) {
11218
+ clearTimeout(startupTickTimer);
11219
+ startupTickTimer = null;
11220
+ }
11221
+ startupJitters.clear();
11222
+ nextStartupJitterSlot = 0;
11223
+ if (stopped)
11224
+ log2("[dreamer] stopped dream schedule timer (no projects left)");
11225
+ }
11226
+ async function startDreamScheduleTimer(args) {
11227
+ if (!isUsableProjectIdentity(args.projectIdentity)) {
11228
+ logEmptyIdentityRefusalOnce(args.directory);
11229
+ return;
11230
+ }
11231
+ beginBootQuietPeriod();
11232
+ const db = openTimerDatabaseOrNull("schedule timer registration");
11233
+ if (!db)
11234
+ return;
11235
+ const dreamingEnabled = Boolean(args.dreamerConfig && args.dreamerConfig.disable !== true);
11236
+ const embeddingSweepEnabled = args.memoryEnabled === true;
11237
+ const commitIndexingEnabled = args.gitCommitIndexing?.enabled === true;
11238
+ const previousRegistration = registeredProjects.get(args.directory);
11239
+ const isNewRegistration = previousRegistration === undefined;
11240
+ if (previousRegistration && previousRegistration !== args) {
11241
+ const pendingStartup = startupTimers.get(args.directory);
11242
+ if (pendingStartup) {
11243
+ clearTimeout(pendingStartup);
11244
+ startupTimers.delete(args.directory);
11245
+ }
11246
+ }
11247
+ registeredProjects.set(args.directory, args);
11248
+ if (isNewRegistration) {
11249
+ log2(`[dreamer] registered project ${args.projectIdentity} (dreaming=${dreamingEnabled} embeddings=${embeddingSweepEnabled} commits=${commitIndexingEnabled}; total=${registeredProjects.size})`);
11250
+ }
11251
+ if (!activeTimer) {
11252
+ log2(`[dreamer] started independent schedule timer (every ${DREAM_TIMER_INTERVAL_MS / 60000}m)`);
11253
+ startupTickTimer = scheduleAfterBootQuiet(() => {
11254
+ startupTickTimer = null;
11255
+ runTick("startup");
11256
+ });
11257
+ const timer = setInterval(() => runTick("interval"), DREAM_TIMER_INTERVAL_MS);
11258
+ if (typeof timer === "object" && "unref" in timer) {
11259
+ timer.unref();
11260
+ }
11261
+ activeTimer = timer;
11262
+ } else if (isNewRegistration || previousRegistration !== args) {
11263
+ scheduleInitialProjectRun(args, db);
11264
+ }
11265
+ return () => {
11266
+ if (registeredProjects.get(args.directory) !== args) {
11267
+ stopDreamScheduleTimerIfIdle();
11268
+ return;
11269
+ }
11270
+ registeredProjects.delete(args.directory);
11271
+ const startupTimer = startupTimers.get(args.directory);
11272
+ if (startupTimer) {
11273
+ clearTimeout(startupTimer);
11274
+ startupTimers.delete(args.directory);
11275
+ }
11276
+ log2(`[dreamer] unregistered project ${args.projectIdentity} (remaining=${registeredProjects.size})`);
11277
+ stopDreamScheduleTimerIfIdle();
11278
+ };
11279
+ }
11280
+ var tickStages = {
11281
+ runMessageHistoryMaintenance,
11282
+ runProjectMaintenance
11283
+ };
11284
+ function runTick(origin) {
11285
+ if (tickInFlight)
11286
+ return;
11287
+ tickInFlight = true;
11288
+ log2(`[dreamer] timer tick (${origin}) — projects=${registeredProjects.size}`);
11289
+ (async () => {
11290
+ try {
11291
+ const db = openTimerDatabaseOrNull("maintenance tick");
11292
+ if (!db)
11293
+ return;
11294
+ let failure = null;
11295
+ const noteFailure = (stage, error) => {
11296
+ failure ??= { at: Date.now(), stage, message: getErrorMessage(error) };
11297
+ };
11298
+ try {
11299
+ await tickStages.runMessageHistoryMaintenance(db);
11300
+ } catch (error) {
11301
+ log2("[magic-context] timer-triggered message-history maintenance failed:", error);
11302
+ noteFailure("message-history maintenance", error);
11303
+ }
11304
+ for (const reg of registeredProjects.values()) {
11305
+ try {
11306
+ if (origin === "startup") {
11307
+ scheduleInitialProjectRun(reg, db);
11308
+ } else {
11309
+ await tickStages.runProjectMaintenance(reg, origin, db);
11310
+ }
11311
+ } catch (error) {
11312
+ log2(`[magic-context] timer-triggered maintenance failed for ${reg.projectIdentity}:`, error);
11313
+ noteFailure(`project ${reg.projectIdentity}`, error);
11314
+ }
11315
+ }
11316
+ persistTickOutcome(db, failure);
11317
+ if (origin === "startup")
11318
+ return;
11319
+ runSqliteOptimize(db);
11320
+ } catch (error) {
11321
+ log2("[magic-context] timer-triggered maintenance check failed:", error);
11322
+ } finally {
11323
+ tickInFlight = false;
11324
+ }
11325
+ })();
11326
+ }
11327
+ function persistTickOutcome(db, failure) {
11328
+ try {
11329
+ if (failure)
11330
+ recordDreamerTickFailure(db, failure);
11331
+ else
11332
+ clearDreamerTickFailure(db);
11333
+ } catch (error) {
11334
+ log2("[dreamer] could not persist the outcome of this tick:", error);
11335
+ }
11336
+ }
11337
+ async function runMessageHistoryMaintenance(db) {
11005
11338
  try {
11006
11339
  await drainStaleLkgSlots(db);
11007
11340
  } catch (error) {
@@ -11026,7 +11359,7 @@ async function runMessageHistoryMaintenance(db) {
11026
11359
  log2(`[message-index] pending Rust session cleanup: cleared=${rustCleanup.cleared} failed=${rustCleanup.failedSessionIds.length}`);
11027
11360
  }
11028
11361
  }
11029
- const sweep = sweepOrphanedOpenCodeMessageIndexes(db, openOpenCodeDb);
11362
+ const sweep = await sweepOrphanedOpenCodeMessageIndexesOffThread(db, openOpenCodeDb);
11030
11363
  if (sweep.reason)
11031
11364
  log2(`[message-index] orphan sweep parked: ${sweep.reason}`);
11032
11365
  if (sweep.deleted > 0) {
@@ -11991,419 +12324,113 @@ function createScheduler(config) {
11991
12324
  if (contextUsage.percentage >= threshold) {
11992
12325
  return "execute";
11993
12326
  }
11994
- let ttlMs;
11995
- try {
11996
- ttlMs = parseCacheTtl(sessionMeta.cacheTtl);
11997
- } catch (error) {
11998
- if (sessionId) {
11999
- sessionLog2(sessionId, `invalid cache_ttl "${sessionMeta.cacheTtl}"; falling back to default 5m`, error);
12000
- } else {
12001
- log2(`[magic-context] invalid cache_ttl "${sessionMeta.cacheTtl}"; falling back to default 5m`, error);
12002
- }
12003
- ttlMs = parseCacheTtl("5m");
12004
- }
12005
- const elapsedTime = currentTime - sessionMeta.lastResponseTime;
12006
- if (elapsedTime > ttlMs) {
12007
- return "execute";
12008
- }
12009
- return "defer";
12010
- }
12011
- };
12012
- }
12013
- function computeHardCacheExpired(cacheTtl, lastResponseTime, now, onInvalid) {
12014
- let ttlMs;
12015
- try {
12016
- ttlMs = parseCacheTtl(cacheTtl);
12017
- } catch (error) {
12018
- onInvalid?.(error);
12019
- ttlMs = 5 * 60 * 1000;
12020
- }
12021
- return lastResponseTime > 0 && now - lastResponseTime > ttlMs;
12022
- }
12023
-
12024
- // src/features/magic-context/storage-unavailable-reason.ts
12025
- function describeStorageUnavailability(fallbackCause) {
12026
- const migration = getMigrationOnOpenRefusal();
12027
- const blockingProcesses = migration?.blockingProcesses ?? migration?.serverPids.map((pid) => ({ kind: "process", pid })) ?? [];
12028
- if (migration && (blockingProcesses.length > 0 || migration.unreadableFile)) {
12029
- return {
12030
- kind: "migration_guard",
12031
- persistedVersion: migration.persistedVersion,
12032
- supportedVersion: migration.supportedVersion,
12033
- blockingProcesses,
12034
- ...migration.unreadableFile ? { unreadableFile: migration.unreadableFile } : {},
12035
- ...migration.unreadableArm ? { unreadableArm: migration.unreadableArm } : {}
12036
- };
12037
- }
12038
- const fence = getSchemaFenceRejection();
12039
- if (fence) {
12040
- return {
12041
- kind: "schema_fence",
12042
- persistedVersion: fence.persistedVersion,
12043
- supportedVersion: fence.supportedVersion
12044
- };
12045
- }
12046
- return { kind: "storage_failure", cause: fallbackCause };
12047
- }
12048
-
12049
- // src/plugin/rpc-handlers.ts
12050
- import { randomUUID as randomUUID3 } from "node:crypto";
12051
- import { once } from "node:events";
12052
- import { rmSync as rmSync2 } from "node:fs";
12053
- import { join as join5 } from "node:path";
12054
-
12055
- // src/features/magic-context/memory/memory-diagnostics.ts
12056
- function emptyMemoryImportanceHistogram() {
12057
- return {
12058
- total: 0,
12059
- unclassified: 0,
12060
- bands: {
12061
- "0-19": 0,
12062
- "20-39": 0,
12063
- "40-59": 0,
12064
- "60-79": 0,
12065
- "80-100": 0
12066
- }
12067
- };
12068
- }
12069
- function readHistogramRow(db, projectPath, classifiedColumn) {
12070
- const unclassified = classifiedColumn ? "SUM(CASE WHEN classified_at IS NULL THEN 1 ELSE 0 END)" : "COUNT(*)";
12071
- return db.prepare(`SELECT COUNT(*) AS total,
12072
- ${unclassified} AS unclassified,
12073
- SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 0 AND 19 THEN 1 ELSE 0 END) AS band_0_19,
12074
- SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 20 AND 39 THEN 1 ELSE 0 END) AS band_20_39,
12075
- SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 40 AND 59 THEN 1 ELSE 0 END) AS band_40_59,
12076
- SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 60 AND 79 THEN 1 ELSE 0 END) AS band_60_79,
12077
- SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 80 AND 100 THEN 1 ELSE 0 END) AS band_80_100
12078
- FROM memories
12079
- WHERE project_path = ? AND status = 'active'`).get(projectPath);
12080
- }
12081
- function getActiveMemoryImportanceHistogram(db, projectPath) {
12082
- let row;
12083
- try {
12084
- row = readHistogramRow(db, projectPath, true);
12085
- } catch (error) {
12086
- if (!String(error).includes("no such column: classified_at"))
12087
- throw error;
12088
- row = readHistogramRow(db, projectPath, false);
12089
- }
12090
- return {
12091
- total: Number(row.total ?? 0),
12092
- unclassified: Number(row.unclassified ?? 0),
12093
- bands: {
12094
- "0-19": Number(row.band_0_19 ?? 0),
12095
- "20-39": Number(row.band_20_39 ?? 0),
12096
- "40-59": Number(row.band_40_59 ?? 0),
12097
- "60-79": Number(row.band_60_79 ?? 0),
12098
- "80-100": Number(row.band_80_100 ?? 0)
12099
- }
12100
- };
12101
- }
12102
-
12103
- // src/features/magic-context/message-index-async.ts
12104
- var indexCancellations = new Map;
12105
- var sessionEpochs = new Map;
12106
- var workerMeasurements = new WeakMap;
12107
- function isDatabaseLockedError(error) {
12108
- if (!error || typeof error !== "object")
12109
- return false;
12110
- const e = error;
12111
- if (typeof e.code === "string") {
12112
- if (e.code === "SQLITE_BUSY" || e.code === "SQLITE_LOCKED")
12113
- return true;
12114
- }
12115
- if (typeof e.message === "string") {
12116
- if (/database is locked/i.test(e.message))
12117
- return true;
12118
- if (/sqlite_(busy|locked)/i.test(e.message))
12119
- return true;
12120
- }
12121
- return false;
12122
- }
12123
- var INCREMENTAL_DEBOUNCE_MS = 100;
12124
- var RECONCILIATION_BATCH_SIZE = 100;
12125
-
12126
- class MagicContextMessageIndexHeapHolder {
12127
- reconciledSessions = new Set;
12128
- reconciliationScheduledSessions = new Set;
12129
- clearAndReindexScheduledSessions = new Map;
12130
- sessionLocks = new Map;
12131
- incrementalTimers = new Map;
12132
- pendingIncrementalKeys = new Set;
12133
- completedIncrementalKeys = new Set;
12134
- activeReconcilerBuffers = new Map;
12135
- }
12136
- var heapHolder = new MagicContextMessageIndexHeapHolder;
12137
- function clearCompletedIncrementalKeys(sessionId) {
12138
- const prefix = `${sessionId}\x00`;
12139
- for (const key of heapHolder.completedIncrementalKeys) {
12140
- if (key.startsWith(prefix))
12141
- heapHolder.completedIncrementalKeys.delete(key);
12142
- }
12143
- }
12144
- var PREPARE_RETRY_MS = 60000;
12145
- async function sourceReady(source, sessionId) {
12146
- const prepare = source?.prepare;
12147
- return typeof prepare === "function" ? prepare(sessionId) : true;
12148
- }
12149
- function defer(fn) {
12150
- const immediate = globalThis.setImmediate;
12151
- if (typeof immediate === "function") {
12152
- immediate(fn);
12153
- return;
12154
- }
12155
- setTimeout(fn, 0);
12156
- }
12157
- function yieldToEventLoop() {
12158
- return new Promise((resolve) => defer(resolve));
12159
- }
12160
- function runWithSessionLock(sessionId, operation) {
12161
- const previous = heapHolder.sessionLocks.get(sessionId) ?? Promise.resolve();
12162
- const run = previous.catch(() => {
12163
- return;
12164
- }).then(async () => {
12165
- await operation();
12166
- });
12167
- heapHolder.sessionLocks.set(sessionId, run);
12168
- run.finally(() => {
12169
- if (heapHolder.sessionLocks.get(sessionId) === run) {
12170
- heapHolder.sessionLocks.delete(sessionId);
12171
- }
12172
- }).catch(() => {
12173
- return;
12174
- });
12175
- return run;
12176
- }
12177
- function logIndexingError(sessionId, action, error) {
12178
- if (isDatabaseLockedError(error)) {
12179
- sessionLog2(sessionId, `message FTS async ${action} skipped (database busy; will retry on next reconciliation)`);
12180
- return;
12181
- }
12182
- sessionLog2(sessionId, `message FTS async ${action} failed: ${error instanceof Error ? error.message : String(error)}`);
12183
- log2(`[message-index-async] ${action} failed for ${sessionId}:`, error);
12184
- }
12185
- function serializedMessageBytes(messages) {
12186
- try {
12187
- return Buffer.byteLength(JSON.stringify(messages));
12188
- } catch {
12189
- return 0;
12190
- }
12191
- }
12192
- async function reconcileSessionIndex(db, sessionId, readMessages) {
12193
- if (!await sourceReady(readMessages, sessionId))
12194
- return false;
12195
- await runWithSessionLock(sessionId, async () => {
12196
- if (heapHolder.reconciledSessions.has(sessionId))
12197
- return;
12198
- let fallbackSnapshot = null;
12199
- try {
12200
- const fullReader = typeof readMessages === "function" ? readMessages : null;
12201
- const finalWatermark = readMessages.getCount ? readMessages.getCount(sessionId) : (fallbackSnapshot = fullReader?.(sessionId) ?? []).length;
12202
- let cursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
12203
- let after;
12204
- while (cursor < finalWatermark) {
12205
- const pageEnd = Math.min(finalWatermark, cursor + RECONCILIATION_BATCH_SIZE);
12206
- const messages = readMessages.readPage ? readMessages.readPage(sessionId, cursor, RECONCILIATION_BATCH_SIZE, finalWatermark, after) : (fallbackSnapshot ?? []).filter((message) => message.ordinal > cursor && message.ordinal <= pageEnd);
12207
- const retainedMessages = fallbackSnapshot ?? messages;
12208
- heapHolder.activeReconcilerBuffers.set(sessionId, retainedMessages);
12209
- withSqliteBackgroundWriter2(() => indexMessagesAfterOrdinal(db, sessionId, messages, cursor, pageEnd));
12210
- const nextCursor = getMessageIndexReconciliationStartOrdinal(db, sessionId);
12211
- if (nextCursor <= cursor)
12212
- break;
12213
- cursor = nextCursor;
12214
- const last = messages.at(-1);
12215
- after = last?.ordinal === cursor && typeof last.createdAt === "number" ? { timeCreated: last.createdAt, id: last.id } : undefined;
12216
- if (cursor < finalWatermark) {
12217
- await yieldToEventLoop();
12327
+ let ttlMs;
12328
+ try {
12329
+ ttlMs = parseCacheTtl(sessionMeta.cacheTtl);
12330
+ } catch (error) {
12331
+ if (sessionId) {
12332
+ sessionLog2(sessionId, `invalid cache_ttl "${sessionMeta.cacheTtl}"; falling back to default 5m`, error);
12333
+ } else {
12334
+ log2(`[magic-context] invalid cache_ttl "${sessionMeta.cacheTtl}"; falling back to default 5m`, error);
12218
12335
  }
12336
+ ttlMs = parseCacheTtl("5m");
12219
12337
  }
12220
- if (isMessageIndexReconciledThrough(db, sessionId, finalWatermark)) {
12221
- heapHolder.reconciledSessions.add(sessionId);
12338
+ const elapsedTime = currentTime - sessionMeta.lastResponseTime;
12339
+ if (elapsedTime > ttlMs) {
12340
+ return "execute";
12222
12341
  }
12223
- } finally {
12224
- heapHolder.activeReconcilerBuffers.delete(sessionId);
12342
+ return "defer";
12225
12343
  }
12226
- });
12227
- return true;
12344
+ };
12228
12345
  }
12229
- function scheduleReconciliation(db, sessionId, readMessages) {
12230
- if (heapHolder.reconciledSessions.has(sessionId) || heapHolder.reconciliationScheduledSessions.has(sessionId)) {
12231
- return;
12346
+ function computeHardCacheExpired(cacheTtl, lastResponseTime, now, onInvalid) {
12347
+ let ttlMs;
12348
+ try {
12349
+ ttlMs = parseCacheTtl(cacheTtl);
12350
+ } catch (error) {
12351
+ onInvalid?.(error);
12352
+ ttlMs = 5 * 60 * 1000;
12232
12353
  }
12233
- heapHolder.reconciliationScheduledSessions.add(sessionId);
12234
- scheduleAfterBootQuiet(() => {
12235
- defer(() => {
12236
- reconcileSessionIndex(db, sessionId, readMessages).then((ran) => {
12237
- if (ran)
12238
- return;
12239
- setTimeout(() => {
12240
- heapHolder.reconciliationScheduledSessions.delete(sessionId);
12241
- scheduleReconciliation(db, sessionId, readMessages);
12242
- }, PREPARE_RETRY_MS).unref?.();
12243
- }).catch((error) => {
12244
- logIndexingError(sessionId, "reconciliation", error);
12245
- if (isDatabaseLockedError(error))
12246
- setTimeout(() => scheduleReconciliation(db, sessionId, readMessages), 1000).unref();
12247
- }).finally(() => {
12248
- heapHolder.reconciliationScheduledSessions.delete(sessionId);
12249
- });
12250
- });
12251
- });
12354
+ return lastResponseTime > 0 && now - lastResponseTime > ttlMs;
12252
12355
  }
12253
- function scheduleIncrementalIndex(db, sessionId, messageId, messageSource) {
12254
- const schedulingKey = `${sessionId}\x00${messageId}`;
12255
- const epoch = sessionEpochs.get(sessionId) ?? 0;
12256
- if (heapHolder.pendingIncrementalKeys.has(schedulingKey))
12257
- return;
12258
- const activeTimer = heapHolder.incrementalTimers.get(schedulingKey);
12259
- if (activeTimer)
12260
- clearTimeout(activeTimer);
12261
- const timer = setTimeout(() => {
12262
- heapHolder.incrementalTimers.delete(schedulingKey);
12263
- heapHolder.pendingIncrementalKeys.add(schedulingKey);
12264
- const indexMessage = async () => {
12265
- if ((sessionEpochs.get(sessionId) ?? 0) !== epoch || !heapHolder.pendingIncrementalKeys.has(schedulingKey))
12266
- return;
12267
- const message = typeof messageSource === "function" ? messageSource(sessionId, messageId) : messageSource;
12268
- if (!message)
12269
- return;
12270
- const revisionKey = `${schedulingKey}\x00${getMessageIndexSourceIdentity(message)}`;
12271
- if (heapHolder.completedIncrementalKeys.has(revisionKey))
12272
- return;
12273
- const currentWatermark = getLastIndexedOrdinal(db, sessionId);
12274
- if (message.ordinal <= currentWatermark && isMessageIndexSourceCurrent(db, sessionId, message)) {
12275
- heapHolder.completedIncrementalKeys.add(revisionKey);
12276
- return;
12277
- }
12278
- const wasReconciled = heapHolder.reconciledSessions.delete(sessionId);
12279
- await indexSingleMessageOffThread(db, sessionId, message);
12280
- if ((sessionEpochs.get(sessionId) ?? 0) !== epoch || !heapHolder.pendingIncrementalKeys.has(schedulingKey))
12281
- return;
12282
- const finalWatermark = getLastIndexedOrdinal(db, sessionId);
12283
- if (wasReconciled && isMessageIndexReconciledThrough(db, sessionId, finalWatermark)) {
12284
- heapHolder.reconciledSessions.add(sessionId);
12285
- }
12286
- heapHolder.completedIncrementalKeys.add(revisionKey);
12356
+
12357
+ // src/features/magic-context/storage-unavailable-reason.ts
12358
+ function describeStorageUnavailability(fallbackCause) {
12359
+ const migration = getMigrationOnOpenRefusal();
12360
+ const blockingProcesses = migration?.blockingProcesses ?? migration?.serverPids.map((pid) => ({ kind: "process", pid })) ?? [];
12361
+ if (migration && (blockingProcesses.length > 0 || migration.unreadableFile)) {
12362
+ return {
12363
+ kind: "migration_guard",
12364
+ persistedVersion: migration.persistedVersion,
12365
+ supportedVersion: migration.supportedVersion,
12366
+ blockingProcesses,
12367
+ ...migration.unreadableFile ? { unreadableFile: migration.unreadableFile } : {},
12368
+ ...migration.unreadableArm ? { unreadableArm: migration.unreadableArm } : {}
12287
12369
  };
12288
- sourceReady(messageSource, sessionId).then((ready) => {
12289
- if ((sessionEpochs.get(sessionId) ?? 0) !== epoch)
12290
- return;
12291
- if (ready)
12292
- return runWithSessionLock(sessionId, indexMessage);
12293
- setTimeout(() => scheduleIncrementalIndex(db, sessionId, messageId, messageSource), PREPARE_RETRY_MS).unref?.();
12294
- }).catch((error) => {
12295
- if ((sessionEpochs.get(sessionId) ?? 0) !== epoch)
12296
- return;
12297
- heapHolder.reconciledSessions.delete(sessionId);
12298
- logIndexingError(sessionId, `incremental index for ${messageId}`, error);
12299
- if (isDatabaseLockedError(error))
12300
- setTimeout(() => scheduleIncrementalIndex(db, sessionId, messageId, messageSource), 1000).unref();
12301
- }).finally(() => {
12302
- if ((sessionEpochs.get(sessionId) ?? 0) === epoch)
12303
- heapHolder.pendingIncrementalKeys.delete(schedulingKey);
12304
- });
12305
- }, INCREMENTAL_DEBOUNCE_MS);
12306
- heapHolder.incrementalTimers.set(schedulingKey, timer);
12307
- }
12308
- async function indexSingleMessageOffThread(db, sessionId, message) {
12309
- const path = getSqliteDatabasePath2(db);
12310
- if (!path)
12311
- return withSqliteBackgroundWriter2(() => indexSingleMessage(db, sessionId, message));
12312
- const cancellation = new Int32Array(new SharedArrayBuffer(4));
12313
- const active = indexCancellations.get(sessionId) ?? new Set;
12314
- active.add(cancellation);
12315
- indexCancellations.set(sessionId, active);
12316
- const result = await runSessionWarmupWorker({
12317
- path,
12318
- sessionId,
12319
- indexMessage: message,
12320
- harness: getHarness2(),
12321
- indexCancellation: cancellation.buffer,
12322
- ...indexCoordinationInput2()
12323
- }, {}).finally(() => {
12324
- active.delete(cancellation);
12325
- if (active.size === 0)
12326
- indexCancellations.delete(sessionId);
12327
- });
12328
- if (!("inserted" in result))
12329
- throw new Error("failure" in result ? result.detail : "unexpected indexing worker reply");
12330
- if (result.measurements) {
12331
- const sessions = workerMeasurements.get(db) ?? new Map;
12332
- sessions.set(sessionId, result.measurements);
12333
- workerMeasurements.set(db, sessions);
12334
- if (result.measurements.skipped)
12335
- log2(`[magic-context] incremental FTS skipped oversized source ${message.id} (${result.measurements.sourceBytes} bytes); identity and progress persisted`);
12336
12370
  }
12337
- return result.inserted;
12338
- }
12339
- function scheduleClearAndReindex(db, sessionId, readMessages) {
12340
- heapHolder.reconciledSessions.delete(sessionId);
12341
- heapHolder.reconciliationScheduledSessions.delete(sessionId);
12342
- clearCompletedIncrementalKeys(sessionId);
12343
- const existing = heapHolder.clearAndReindexScheduledSessions.get(sessionId);
12344
- if (existing) {
12345
- existing.source = readMessages;
12346
- return;
12371
+ const fence = getSchemaFenceRejection();
12372
+ if (fence) {
12373
+ return {
12374
+ kind: "schema_fence",
12375
+ persistedVersion: fence.persistedVersion,
12376
+ supportedVersion: fence.supportedVersion
12377
+ };
12347
12378
  }
12348
- const pending = { source: readMessages };
12349
- heapHolder.clearAndReindexScheduledSessions.set(sessionId, pending);
12350
- scheduleAfterBootQuiet(() => {
12351
- defer(() => {
12352
- let cleared = false;
12353
- runWithSessionLock(sessionId, () => {
12354
- if (heapHolder.clearAndReindexScheduledSessions.get(sessionId) !== pending)
12355
- return;
12356
- heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
12357
- heapHolder.reconciledSessions.delete(sessionId);
12358
- clearCompletedIncrementalKeys(sessionId);
12359
- clearIndexedMessages(db, sessionId);
12360
- cleared = true;
12361
- }).then(() => cleared ? reconcileSessionIndex(db, sessionId, pending.source) : undefined).catch((error) => {
12362
- heapHolder.reconciledSessions.delete(sessionId);
12363
- if (heapHolder.clearAndReindexScheduledSessions.get(sessionId) === pending)
12364
- heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
12365
- logIndexingError(sessionId, "clear and reindex", error);
12366
- });
12367
- });
12368
- });
12379
+ return { kind: "storage_failure", cause: fallbackCause };
12369
12380
  }
12370
- function getMessageIndexQueueHeapStats() {
12381
+
12382
+ // src/plugin/rpc-handlers.ts
12383
+ import { randomUUID as randomUUID3 } from "node:crypto";
12384
+ import { once } from "node:events";
12385
+ import { rmSync as rmSync2 } from "node:fs";
12386
+ import { join as join5 } from "node:path";
12387
+
12388
+ // src/features/magic-context/memory/memory-diagnostics.ts
12389
+ function emptyMemoryImportanceHistogram() {
12371
12390
  return {
12372
- queueLength: heapHolder.reconciliationScheduledSessions.size + heapHolder.incrementalTimers.size + heapHolder.pendingIncrementalKeys.size,
12373
- reconciliationScheduled: heapHolder.reconciliationScheduledSessions.size,
12374
- incrementalTimers: heapHolder.incrementalTimers.size,
12375
- pendingIncremental: heapHolder.pendingIncrementalKeys.size,
12376
- activeSessionLocks: heapHolder.sessionLocks.size,
12377
- completedIncrementalKeys: heapHolder.completedIncrementalKeys.size,
12378
- activeBufferMessages: [...heapHolder.activeReconcilerBuffers.values()].reduce((sum, messages) => sum + messages.length, 0),
12379
- activeBufferBytes: [...heapHolder.activeReconcilerBuffers.values()].reduce((sum, messages) => sum + serializedMessageBytes(messages), 0)
12391
+ total: 0,
12392
+ unclassified: 0,
12393
+ bands: {
12394
+ "0-19": 0,
12395
+ "20-39": 0,
12396
+ "40-59": 0,
12397
+ "60-79": 0,
12398
+ "80-100": 0
12399
+ }
12380
12400
  };
12381
12401
  }
12382
- function clearSessionTracking(sessionId) {
12383
- sessionEpochs.set(sessionId, (sessionEpochs.get(sessionId) ?? 0) + 1);
12384
- for (const cancellation of indexCancellations.get(sessionId) ?? [])
12385
- Atomics.store(cancellation, 0, 1);
12386
- heapHolder.clearAndReindexScheduledSessions.delete(sessionId);
12387
- heapHolder.reconciledSessions.delete(sessionId);
12388
- heapHolder.reconciliationScheduledSessions.delete(sessionId);
12389
- heapHolder.sessionLocks.delete(sessionId);
12390
- heapHolder.activeReconcilerBuffers.delete(sessionId);
12391
- const prefix = `${sessionId}\x00`;
12392
- for (const [key, timer] of heapHolder.incrementalTimers) {
12393
- if (key.startsWith(prefix)) {
12394
- clearTimeout(timer);
12395
- heapHolder.incrementalTimers.delete(key);
12396
- }
12402
+ function readHistogramRow(db, projectPath, classifiedColumn) {
12403
+ const unclassified = classifiedColumn ? "SUM(CASE WHEN classified_at IS NULL THEN 1 ELSE 0 END)" : "COUNT(*)";
12404
+ return db.prepare(`SELECT COUNT(*) AS total,
12405
+ ${unclassified} AS unclassified,
12406
+ SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 0 AND 19 THEN 1 ELSE 0 END) AS band_0_19,
12407
+ SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 20 AND 39 THEN 1 ELSE 0 END) AS band_20_39,
12408
+ SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 40 AND 59 THEN 1 ELSE 0 END) AS band_40_59,
12409
+ SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 60 AND 79 THEN 1 ELSE 0 END) AS band_60_79,
12410
+ SUM(CASE WHEN COALESCE(importance, 50) BETWEEN 80 AND 100 THEN 1 ELSE 0 END) AS band_80_100
12411
+ FROM memories
12412
+ WHERE project_path = ? AND status = 'active'`).get(projectPath);
12413
+ }
12414
+ function getActiveMemoryImportanceHistogram(db, projectPath) {
12415
+ let row;
12416
+ try {
12417
+ row = readHistogramRow(db, projectPath, true);
12418
+ } catch (error) {
12419
+ if (!String(error).includes("no such column: classified_at"))
12420
+ throw error;
12421
+ row = readHistogramRow(db, projectPath, false);
12397
12422
  }
12398
- for (const key of heapHolder.pendingIncrementalKeys) {
12399
- if (key.startsWith(prefix)) {
12400
- heapHolder.pendingIncrementalKeys.delete(key);
12423
+ return {
12424
+ total: Number(row.total ?? 0),
12425
+ unclassified: Number(row.unclassified ?? 0),
12426
+ bands: {
12427
+ "0-19": Number(row.band_0_19 ?? 0),
12428
+ "20-39": Number(row.band_20_39 ?? 0),
12429
+ "40-59": Number(row.band_40_59 ?? 0),
12430
+ "60-79": Number(row.band_60_79 ?? 0),
12431
+ "80-100": Number(row.band_80_100 ?? 0)
12401
12432
  }
12402
- }
12403
- for (const key of heapHolder.completedIncrementalKeys) {
12404
- if (key.startsWith(prefix))
12405
- heapHolder.completedIncrementalKeys.delete(key);
12406
- }
12433
+ };
12407
12434
  }
12408
12435
 
12409
12436
  // src/features/magic-context/session-cache-ttl.ts
@@ -15679,8 +15706,8 @@ function registerRpcHandlers(rpcServer, args) {
15679
15706
  const db = readDatabase();
15680
15707
  if (!db)
15681
15708
  return { ok: false, error: "db unavailable" };
15682
- const { runManagedRecomp } = await importPluginModule(() => import("./recomp-orchestrator-kpkhkjhq.js"));
15683
- const { sendIgnoredMessage } = await importPluginModule(() => import("./send-session-notification-xffh3bbe.js"));
15709
+ const { runManagedRecomp } = await importPluginModule(() => import("./recomp-orchestrator-txcc802e.js"));
15710
+ const { sendIgnoredMessage } = await importPluginModule(() => import("./send-session-notification-yp9m5g4p.js"));
15684
15711
  log2(`[rpc] recomp requested for session ${sessionId}`);
15685
15712
  if (!args.client && !args.hiddenCompletionExecutor) {
15686
15713
  return {
@@ -15749,7 +15776,7 @@ function registerRpcHandlers(rpcServer, args) {
15749
15776
  const db = readDatabase();
15750
15777
  if (!db)
15751
15778
  return { ok: false, error: "db unavailable" };
15752
- const { runManagedWrapup } = await importPluginModule(() => import("./wrapup-orchestrator-xvrr27ws.js"));
15779
+ const { runManagedWrapup } = await importPluginModule(() => import("./wrapup-orchestrator-5aa2q4v3.js"));
15753
15780
  const model = liveSessionState.liveModelBySession.get(sessionId);
15754
15781
  const contextLimit = model ? resolveContextLimit(model.providerID, model.modelID, { db, sessionID: sessionId }) : 128000;
15755
15782
  const ctx = {
@@ -21769,7 +21796,8 @@ function createRustModeTransform(deps, options) {
21769
21796
  }
21770
21797
  pendingWireCache.nativeOutput = moduleMessages;
21771
21798
  if (!replayedFrozenRepresentation) {
21772
- if (materializedBoundary && !deps.compactionOff) {
21799
+ if ((materializedBoundary || getPendingCompactionMarkerState(deps.db, sessionId) !== null) && !deps.compactionOff) {
21800
+ await prepareCompactionMarkerCandidates(sessionId);
21773
21801
  try {
21774
21802
  await withAsyncPrivilegedWriter2(deps.db, () => {
21775
21803
  return;
@@ -26719,7 +26747,7 @@ function singleLine(value) {
26719
26747
  // src/tools/ctx-note/tools.ts
26720
26748
  function captureAnchorOrdinal(db, sessionId) {
26721
26749
  try {
26722
- const ordinal = getLastIndexedOrdinal(db, sessionId);
26750
+ const ordinal = getLastIndexedOrdinal2(db, sessionId);
26723
26751
  return ordinal > 0 ? ordinal : null;
26724
26752
  } catch {
26725
26753
  return null;
@@ -27822,4 +27850,4 @@ function applyHiddenSubagentTemperature(input, output, log) {
27822
27850
  output.temperature = temperature;
27823
27851
  }
27824
27852
 
27825
- export { openOpenCodeDb, DREAMER_SYSTEM_PROMPT, runSessionProjectBackfill, SMART_NOTE_COMPILER_SYSTEM_PROMPT, createLiveSessionState, RETROSPECTIVE_MAX_USER_MESSAGE_CHARS, RETROSPECTIVE_MESSAGE_TRUNCATION_MARKER, OpenCodeRetrospectiveRawProvider, createDreamTaskExecutor, runManualDream, runDueTasksForProject, startDreamScheduleTimer, ensureProjectRegisteredFromOpenCodeDirectory, recordOpenCodeProvenInputFloor, resolveOpenCodeProvenInputFloor, resolveContextWindowGeometry, resolveContextLimit, resolveExecuteThresholdDetail, resolveModelKey, resolveSessionId, createScheduler, describeStorageUnavailability, scheduleClearAndReindex, resolveSessionCacheTtl, runEmbedHistoryDrain, pauseEmbedHistoryDrain, formatEmbedStatusText, getSessionProperties, getSessionCreatedInfo, getMessageUpdatedAssistantInfo, getMessageUpdatedInfo, getSessionErrorInfo, getMessageRemovedInfo, summarizeManualDream, createMagicContextCommandHandler, getLiveNotificationParams, createChatMessageHook, createEventHook, createCommandExecuteBeforeHook, createToolExecuteAfterHook, recordHiddenVariantWarning, buildStatusDetail, isDebugRpcEnabled, registerRpcHandlers, clearTransformDecisionSession, scheduleOpenCodeTransformDecisionWrite, maybeDeliverChannel2, armLatestThinkingRecovery, armBindingRecoverySafely, armLatestThinkingRecoveryFromError, lkgReplayLimit, measureLkgReplay, STORAGE_BUSY_MESSAGE, StorageBusyRefusalError, bindSystemDateRequestIdentity, bindSystemDateOutput, registerSystemDateRefresh, rustWrapupHistorianFields, UnmanagedOverWindowError, UnresolvedHistoryBoundaryError, clearMessageTokensCache, createTransform, createSubcModuleClient, createModuleToolBackends, createRustRefusalRecovery, createSystemPromptHashHandler, tryMessagesTransformLkgReplay, createMessagesTransformHandler, primaryOnlyToolIds, subagentToolRefusal, guardSubagentTools, hideSubagentTools, createCtxExpandTools, CTX_MEMORY_LIST_TOOL_NAME, CTX_MEMORY_ACTIONS, createCtxMemoryTools, createCtxMemoryListTools, CTX_NOTE_DESCRIPTION, withoutSmartNoteText, createCtxNoteTools, createCtxReduceTools, createCtxSearchTools, parameterDescriptionsFor, applyJsonSchemaParameterDescriptions, MagicContextRpcServer, subagentTemperature, applyHiddenSubagentTemperature };
27853
+ export { openOpenCodeDb, DREAMER_SYSTEM_PROMPT, runSessionProjectBackfill, SMART_NOTE_COMPILER_SYSTEM_PROMPT, createLiveSessionState, RETROSPECTIVE_MAX_USER_MESSAGE_CHARS, RETROSPECTIVE_MESSAGE_TRUNCATION_MARKER, OpenCodeRetrospectiveRawProvider, createDreamTaskExecutor, runManualDream, runDueTasksForProject, scheduleClearAndReindex, startDreamScheduleTimer, ensureProjectRegisteredFromOpenCodeDirectory, recordOpenCodeProvenInputFloor, resolveOpenCodeProvenInputFloor, resolveContextWindowGeometry, resolveContextLimit, resolveExecuteThresholdDetail, resolveModelKey, resolveSessionId, createScheduler, describeStorageUnavailability, resolveSessionCacheTtl, runEmbedHistoryDrain, pauseEmbedHistoryDrain, formatEmbedStatusText, getSessionProperties, getSessionCreatedInfo, getMessageUpdatedAssistantInfo, getMessageUpdatedInfo, getSessionErrorInfo, getMessageRemovedInfo, summarizeManualDream, createMagicContextCommandHandler, getLiveNotificationParams, createChatMessageHook, createEventHook, createCommandExecuteBeforeHook, createToolExecuteAfterHook, recordHiddenVariantWarning, buildStatusDetail, isDebugRpcEnabled, registerRpcHandlers, clearTransformDecisionSession, scheduleOpenCodeTransformDecisionWrite, maybeDeliverChannel2, armLatestThinkingRecovery, armBindingRecoverySafely, armLatestThinkingRecoveryFromError, lkgReplayLimit, measureLkgReplay, STORAGE_BUSY_MESSAGE, StorageBusyRefusalError, bindSystemDateRequestIdentity, bindSystemDateOutput, registerSystemDateRefresh, rustWrapupHistorianFields, UnmanagedOverWindowError, UnresolvedHistoryBoundaryError, clearMessageTokensCache, createTransform, createSubcModuleClient, createModuleToolBackends, createRustRefusalRecovery, createSystemPromptHashHandler, tryMessagesTransformLkgReplay, createMessagesTransformHandler, primaryOnlyToolIds, subagentToolRefusal, guardSubagentTools, hideSubagentTools, createCtxExpandTools, CTX_MEMORY_LIST_TOOL_NAME, CTX_MEMORY_ACTIONS, createCtxMemoryTools, createCtxMemoryListTools, CTX_NOTE_DESCRIPTION, withoutSmartNoteText, createCtxNoteTools, createCtxReduceTools, createCtxSearchTools, parameterDescriptionsFor, applyJsonSchemaParameterDescriptions, MagicContextRpcServer, subagentTemperature, applyHiddenSubagentTemperature };