@cortexkit/opencode-magic-context 0.21.6 → 0.21.7

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 (56) hide show
  1. package/README.md +1 -1
  2. package/dist/config/agent-disable.d.ts +26 -0
  3. package/dist/config/agent-disable.d.ts.map +1 -0
  4. package/dist/config/index.d.ts.map +1 -1
  5. package/dist/config/schema/magic-context.d.ts +0 -6
  6. package/dist/config/schema/magic-context.d.ts.map +1 -1
  7. package/dist/features/magic-context/compartment-lease.d.ts +14 -0
  8. package/dist/features/magic-context/compartment-lease.d.ts.map +1 -0
  9. package/dist/features/magic-context/compartment-storage.d.ts +5 -1
  10. package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
  11. package/dist/features/magic-context/compression-depth-storage.d.ts +2 -1
  12. package/dist/features/magic-context/compression-depth-storage.d.ts.map +1 -1
  13. package/dist/features/magic-context/migrations.d.ts.map +1 -1
  14. package/dist/features/magic-context/storage-db.d.ts.map +1 -1
  15. package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
  16. package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
  17. package/dist/features/magic-context/storage.d.ts +1 -1
  18. package/dist/features/magic-context/storage.d.ts.map +1 -1
  19. package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -1
  20. package/dist/hooks/magic-context/compartment-runner-compressor.d.ts +4 -0
  21. package/dist/hooks/magic-context/compartment-runner-compressor.d.ts.map +1 -1
  22. package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
  23. package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
  24. package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
  25. package/dist/hooks/magic-context/compartment-runner-types.d.ts +2 -0
  26. package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
  27. package/dist/hooks/magic-context/compartment-runner.d.ts +5 -0
  28. package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
  29. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  30. package/dist/hooks/magic-context/transform-compartment-phase.d.ts +2 -2
  31. package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
  32. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +1 -0
  33. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  34. package/dist/hooks/magic-context/transform.d.ts +2 -0
  35. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +617 -173
  38. package/dist/plugin/conflict-warning-hook.d.ts +10 -0
  39. package/dist/plugin/conflict-warning-hook.d.ts.map +1 -1
  40. package/dist/plugin/dream-timer.d.ts.map +1 -1
  41. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  42. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  43. package/dist/plugin/tool-registry.d.ts.map +1 -1
  44. package/dist/shared/announcement.d.ts +55 -0
  45. package/dist/shared/announcement.d.ts.map +1 -0
  46. package/dist/shared/format-threshold.d.ts +24 -0
  47. package/dist/shared/format-threshold.d.ts.map +1 -0
  48. package/dist/tui/data/context-db.d.ts +14 -0
  49. package/dist/tui/data/context-db.d.ts.map +1 -1
  50. package/package.json +1 -1
  51. package/src/shared/announcement.test.ts +143 -0
  52. package/src/shared/announcement.ts +97 -0
  53. package/src/shared/format-threshold.ts +28 -0
  54. package/src/tui/data/context-db.ts +43 -0
  55. package/src/tui/index.tsx +68 -4
  56. package/src/tui/slots/sidebar-content.tsx +11 -2
package/dist/index.js CHANGED
@@ -14858,7 +14858,6 @@ var init_magic_context = __esm(() => {
14858
14858
  ];
14859
14859
  PiThinkingLevelSchema = exports_external.enum(["off", "minimal", "low", "medium", "high", "xhigh"]).optional();
14860
14860
  DreamerConfigSchema = AgentOverrideConfigSchema.merge(exports_external.object({
14861
- enabled: exports_external.boolean().default(false),
14862
14861
  schedule: exports_external.string().default("02:00-06:00"),
14863
14862
  max_runtime_minutes: exports_external.number().min(10).default(120),
14864
14863
  tasks: exports_external.array(DreamingTaskSchema).default(DEFAULT_DREAMER_TASKS),
@@ -14876,7 +14875,6 @@ var init_magic_context = __esm(() => {
14876
14875
  thinking_level: PiThinkingLevelSchema
14877
14876
  }));
14878
14877
  SidekickConfigSchema = AgentOverrideConfigSchema.extend({
14879
- enabled: exports_external.boolean().default(false),
14880
14878
  timeout_ms: exports_external.number().default(30000),
14881
14879
  system_prompt: exports_external.string().optional(),
14882
14880
  thinking_level: PiThinkingLevelSchema
@@ -156094,6 +156092,106 @@ var require_src2 = __commonJS((exports, module) => {
156094
156092
  };
156095
156093
  });
156096
156094
 
156095
+ // src/features/magic-context/compartment-lease.ts
156096
+ function acquireCompartmentLease(db, sessionId, holderId) {
156097
+ const acquiredAt = Date.now();
156098
+ const expiresAt = acquiredAt + COMPARTMENT_LEASE_TTL_MS;
156099
+ const result = db.prepare(`INSERT INTO compartment_state_lease (session_id, holder_id, acquired_at, expires_at)
156100
+ VALUES (?, ?, ?, ?)
156101
+ ON CONFLICT(session_id) DO UPDATE SET
156102
+ holder_id = excluded.holder_id,
156103
+ acquired_at = excluded.acquired_at,
156104
+ expires_at = excluded.expires_at
156105
+ WHERE compartment_state_lease.holder_id = excluded.holder_id
156106
+ OR compartment_state_lease.expires_at <= ?`).run(sessionId, holderId, acquiredAt, expiresAt, acquiredAt);
156107
+ if (result.changes !== 1) {
156108
+ return null;
156109
+ }
156110
+ return { sessionId, holderId, acquiredAt, expiresAt };
156111
+ }
156112
+ function renewCompartmentLease(db, sessionId, holderId) {
156113
+ const now = Date.now();
156114
+ const expiresAt = now + COMPARTMENT_LEASE_TTL_MS;
156115
+ const result = db.prepare(`UPDATE compartment_state_lease
156116
+ SET expires_at = ?, acquired_at = ?
156117
+ WHERE session_id = ? AND holder_id = ? AND expires_at > ?`).run(expiresAt, now, sessionId, holderId, now);
156118
+ return result.changes === 1;
156119
+ }
156120
+ function releaseCompartmentLease(db, sessionId, holderId) {
156121
+ db.prepare("DELETE FROM compartment_state_lease WHERE session_id = ? AND holder_id = ?").run(sessionId, holderId);
156122
+ }
156123
+ function isCompartmentLeaseHeld(db, sessionId, holderId) {
156124
+ const row = db.prepare("SELECT 1 FROM compartment_state_lease WHERE session_id = ? AND holder_id = ? AND expires_at > ?").get(sessionId, holderId, Date.now());
156125
+ return row != null;
156126
+ }
156127
+ var COMPARTMENT_LEASE_TTL_MS, COMPARTMENT_LEASE_RENEWAL_MS;
156128
+ var init_compartment_lease = __esm(() => {
156129
+ COMPARTMENT_LEASE_TTL_MS = 5 * 60 * 1000;
156130
+ COMPARTMENT_LEASE_RENEWAL_MS = 60 * 1000;
156131
+ });
156132
+
156133
+ // src/features/magic-context/compression-depth-storage.ts
156134
+ function getIncrementDepthStatement(db) {
156135
+ let stmt = incrementDepthStatements.get(db);
156136
+ if (!stmt) {
156137
+ stmt = db.prepare("INSERT INTO compression_depth (session_id, message_ordinal, depth, harness) VALUES (?, ?, 1, ?) ON CONFLICT(session_id, message_ordinal) DO UPDATE SET depth = depth + 1");
156138
+ incrementDepthStatements.set(db, stmt);
156139
+ }
156140
+ return stmt;
156141
+ }
156142
+ function getTotalDepthStatement(db) {
156143
+ let stmt = totalDepthStatements.get(db);
156144
+ if (!stmt) {
156145
+ stmt = db.prepare("SELECT COALESCE(SUM(depth), 0) AS total_depth FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?");
156146
+ totalDepthStatements.set(db, stmt);
156147
+ }
156148
+ return stmt;
156149
+ }
156150
+ function getClearDepthStatement(db) {
156151
+ let stmt = clearDepthStatements.get(db);
156152
+ if (!stmt) {
156153
+ stmt = db.prepare("DELETE FROM compression_depth WHERE session_id = ?");
156154
+ clearDepthStatements.set(db, stmt);
156155
+ }
156156
+ return stmt;
156157
+ }
156158
+ function incrementCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
156159
+ if (endOrdinal < startOrdinal) {
156160
+ return;
156161
+ }
156162
+ db.transaction(() => {
156163
+ const stmt = getIncrementDepthStatement(db);
156164
+ for (let ordinal = startOrdinal;ordinal <= endOrdinal; ordinal += 1) {
156165
+ stmt.run(sessionId, ordinal, getHarness());
156166
+ }
156167
+ })();
156168
+ }
156169
+ function getAverageCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
156170
+ if (endOrdinal < startOrdinal) {
156171
+ return 0;
156172
+ }
156173
+ const row = getTotalDepthStatement(db).get(sessionId, startOrdinal, endOrdinal);
156174
+ const totalDepth = typeof row?.total_depth === "number" ? row.total_depth : 0;
156175
+ const messageCount = endOrdinal - startOrdinal + 1;
156176
+ return totalDepth / messageCount;
156177
+ }
156178
+ function clearCompressionDepth(db, sessionId) {
156179
+ getClearDepthStatement(db).run(sessionId);
156180
+ }
156181
+ function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
156182
+ if (endOrdinal < startOrdinal) {
156183
+ return;
156184
+ }
156185
+ db.prepare("DELETE FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?").run(sessionId, startOrdinal, endOrdinal);
156186
+ }
156187
+ var incrementDepthStatements, totalDepthStatements, maxDepthStatements, clearDepthStatements;
156188
+ var init_compression_depth_storage = __esm(() => {
156189
+ incrementDepthStatements = new WeakMap;
156190
+ totalDepthStatements = new WeakMap;
156191
+ maxDepthStatements = new WeakMap;
156192
+ clearDepthStatements = new WeakMap;
156193
+ });
156194
+
156097
156195
  // src/features/magic-context/compartment-storage.ts
156098
156196
  function getInsertCompartmentStatement(db) {
156099
156197
  let stmt = insertCompartmentStatements.get(db);
@@ -156201,6 +156299,38 @@ function replaceAllCompartmentState(db, sessionId, compartments, facts) {
156201
156299
  db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
156202
156300
  })();
156203
156301
  }
156302
+ function replaceAllCompartmentStateAndBumpDepth(db, holderId, sessionId, compartments, facts, depthStartOrdinal, depthEndOrdinal) {
156303
+ const now = Date.now();
156304
+ db.exec("BEGIN IMMEDIATE");
156305
+ let finished = false;
156306
+ try {
156307
+ if (!isCompartmentLeaseHeld(db, sessionId, holderId)) {
156308
+ db.exec("ROLLBACK");
156309
+ finished = true;
156310
+ return false;
156311
+ }
156312
+ db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
156313
+ db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
156314
+ insertCompartmentRows(db, sessionId, compartments, now);
156315
+ insertFactRows(db, sessionId, facts, now);
156316
+ db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
156317
+ if (depthEndOrdinal >= depthStartOrdinal) {
156318
+ const stmt = getIncrementDepthStatement(db);
156319
+ for (let ordinal = depthStartOrdinal;ordinal <= depthEndOrdinal; ordinal += 1) {
156320
+ stmt.run(sessionId, ordinal, getHarness());
156321
+ }
156322
+ }
156323
+ db.exec("COMMIT");
156324
+ finished = true;
156325
+ return true;
156326
+ } finally {
156327
+ if (!finished) {
156328
+ try {
156329
+ db.exec("ROLLBACK");
156330
+ } catch {}
156331
+ }
156332
+ }
156333
+ }
156204
156334
  function buildCompartmentBlock(compartments, facts, memoryBlock, dateRanges) {
156205
156335
  const lines = [];
156206
156336
  if (memoryBlock) {
@@ -156268,12 +156398,37 @@ function getRecompStaging(db, sessionId) {
156268
156398
  lastEndMessage: lastEnd
156269
156399
  };
156270
156400
  }
156271
- function promoteRecompStaging(db, sessionId) {
156401
+ function promoteRecompStaging(db, sessionId, holderId) {
156272
156402
  const now = Date.now();
156273
- return db.transaction(() => {
156403
+ if (!holderId) {
156404
+ return db.transaction(() => {
156405
+ const staging = getRecompStaging(db, sessionId);
156406
+ if (!staging || staging.compartments.length === 0)
156407
+ return null;
156408
+ db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
156409
+ db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
156410
+ insertCompartmentRows(db, sessionId, staging.compartments, now);
156411
+ insertFactRows(db, sessionId, staging.facts, now);
156412
+ db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
156413
+ db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
156414
+ db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
156415
+ return { compartments: staging.compartments, facts: staging.facts };
156416
+ })();
156417
+ }
156418
+ db.exec("BEGIN IMMEDIATE");
156419
+ let finished = false;
156420
+ try {
156421
+ if (!isCompartmentLeaseHeld(db, sessionId, holderId)) {
156422
+ db.exec("ROLLBACK");
156423
+ finished = true;
156424
+ return null;
156425
+ }
156274
156426
  const staging = getRecompStaging(db, sessionId);
156275
- if (!staging || staging.compartments.length === 0)
156427
+ if (!staging || staging.compartments.length === 0) {
156428
+ db.exec("ROLLBACK");
156429
+ finished = true;
156276
156430
  return null;
156431
+ }
156277
156432
  db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
156278
156433
  db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
156279
156434
  insertCompartmentRows(db, sessionId, staging.compartments, now);
@@ -156281,8 +156436,16 @@ function promoteRecompStaging(db, sessionId) {
156281
156436
  db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
156282
156437
  db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
156283
156438
  db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
156439
+ db.exec("COMMIT");
156440
+ finished = true;
156284
156441
  return { compartments: staging.compartments, facts: staging.facts };
156285
- })();
156442
+ } finally {
156443
+ if (!finished) {
156444
+ try {
156445
+ db.exec("ROLLBACK");
156446
+ } catch {}
156447
+ }
156448
+ }
156286
156449
  }
156287
156450
  function invalidateAllMemoryBlockCaches(db) {
156288
156451
  try {
@@ -156336,6 +156499,8 @@ function escapeXmlContent(s) {
156336
156499
  }
156337
156500
  var insertCompartmentStatements, insertFactStatements;
156338
156501
  var init_compartment_storage = __esm(() => {
156502
+ init_compartment_lease();
156503
+ init_compression_depth_storage();
156339
156504
  insertCompartmentStatements = new WeakMap;
156340
156505
  insertFactStatements = new WeakMap;
156341
156506
  });
@@ -156911,6 +157076,7 @@ var init_conflict_detector = __esm(() => {
156911
157076
  var exports_conflict_warning_hook = {};
156912
157077
  __export(exports_conflict_warning_hook, {
156913
157078
  sendTuiSetupNotification: () => sendTuiSetupNotification,
157079
+ sendStartupAnnouncement: () => sendStartupAnnouncement,
156914
157080
  sendConflictWarning: () => sendConflictWarning,
156915
157081
  cleanupConflictWarnings: () => cleanupConflictWarnings
156916
157082
  });
@@ -157194,7 +157360,46 @@ async function sendTuiSetupNotification(client, directory, serverUrl) {
157194
157360
  } catch {}
157195
157361
  }, 1000);
157196
157362
  }
157197
- var CONFLICT_WARNING_MARKER = "⚠️ Magic Context is disabled due to conflicting configuration:", ENABLED_MARKER = "✨ Magic Context is now enabled", TUI_SETUP_MARKER = "\uD83D\uDCCA Magic Context sidebar configured", cachedDesktopStateByDir;
157363
+ async function sendStartupAnnouncement(client, directory, version2, features, footer, markSeen) {
157364
+ if (!version2 || features.length === 0)
157365
+ return;
157366
+ const { sessionId } = getDesktopState(directory);
157367
+ if (!sessionId) {
157368
+ return;
157369
+ }
157370
+ const bullets = features.map((line) => ` • ${line}`).join(`
157371
+ `);
157372
+ const sections = [`${ANNOUNCEMENT_MARKER} v${version2}:`, "", bullets];
157373
+ if (footer && footer.trim().length > 0) {
157374
+ sections.push("", footer);
157375
+ }
157376
+ const text = sections.join(`
157377
+ `);
157378
+ log(`[magic-context] sending startup announcement for v${version2} to session ${sessionId}`);
157379
+ try {
157380
+ const c = client;
157381
+ const promptInput = {
157382
+ path: { id: sessionId },
157383
+ body: {
157384
+ noReply: true,
157385
+ parts: [{ type: "text", text, ignored: true }]
157386
+ }
157387
+ };
157388
+ if (typeof c.session?.prompt === "function") {
157389
+ await Promise.resolve(c.session.prompt(promptInput));
157390
+ } else if (typeof c.session?.promptAsync === "function") {
157391
+ await c.session.promptAsync(promptInput);
157392
+ } else {
157393
+ log("[magic-context] announcement: session prompt API unavailable");
157394
+ return;
157395
+ }
157396
+ } catch (error51) {
157397
+ log(`[magic-context] announcement: failed to send: ${error51 instanceof Error ? error51.message : String(error51)}`);
157398
+ return;
157399
+ }
157400
+ markSeen(version2);
157401
+ }
157402
+ var CONFLICT_WARNING_MARKER = "⚠️ Magic Context is disabled due to conflicting configuration:", ENABLED_MARKER = "✨ Magic Context is now enabled", TUI_SETUP_MARKER = "\uD83D\uDCCA Magic Context sidebar configured", ANNOUNCEMENT_MARKER = "✨ Magic Context — what's new in", cachedDesktopStateByDir;
157198
157403
  var init_conflict_warning_hook = __esm(() => {
157199
157404
  init_conflict_detector();
157200
157405
  init_logger();
@@ -159519,68 +159724,6 @@ var init_storage_memory_fts = __esm(() => {
159519
159724
  searchStatements = new WeakMap;
159520
159725
  });
159521
159726
 
159522
- // src/features/magic-context/compression-depth-storage.ts
159523
- function getIncrementDepthStatement(db) {
159524
- let stmt = incrementDepthStatements.get(db);
159525
- if (!stmt) {
159526
- stmt = db.prepare("INSERT INTO compression_depth (session_id, message_ordinal, depth, harness) VALUES (?, ?, 1, ?) ON CONFLICT(session_id, message_ordinal) DO UPDATE SET depth = depth + 1");
159527
- incrementDepthStatements.set(db, stmt);
159528
- }
159529
- return stmt;
159530
- }
159531
- function getTotalDepthStatement(db) {
159532
- let stmt = totalDepthStatements.get(db);
159533
- if (!stmt) {
159534
- stmt = db.prepare("SELECT COALESCE(SUM(depth), 0) AS total_depth FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?");
159535
- totalDepthStatements.set(db, stmt);
159536
- }
159537
- return stmt;
159538
- }
159539
- function getClearDepthStatement(db) {
159540
- let stmt = clearDepthStatements.get(db);
159541
- if (!stmt) {
159542
- stmt = db.prepare("DELETE FROM compression_depth WHERE session_id = ?");
159543
- clearDepthStatements.set(db, stmt);
159544
- }
159545
- return stmt;
159546
- }
159547
- function incrementCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
159548
- if (endOrdinal < startOrdinal) {
159549
- return;
159550
- }
159551
- db.transaction(() => {
159552
- const stmt = getIncrementDepthStatement(db);
159553
- for (let ordinal = startOrdinal;ordinal <= endOrdinal; ordinal += 1) {
159554
- stmt.run(sessionId, ordinal, getHarness());
159555
- }
159556
- })();
159557
- }
159558
- function getAverageCompressionDepth(db, sessionId, startOrdinal, endOrdinal) {
159559
- if (endOrdinal < startOrdinal) {
159560
- return 0;
159561
- }
159562
- const row = getTotalDepthStatement(db).get(sessionId, startOrdinal, endOrdinal);
159563
- const totalDepth = typeof row?.total_depth === "number" ? row.total_depth : 0;
159564
- const messageCount = endOrdinal - startOrdinal + 1;
159565
- return totalDepth / messageCount;
159566
- }
159567
- function clearCompressionDepth(db, sessionId) {
159568
- getClearDepthStatement(db).run(sessionId);
159569
- }
159570
- function clearCompressionDepthRange(db, sessionId, startOrdinal, endOrdinal) {
159571
- if (endOrdinal < startOrdinal) {
159572
- return;
159573
- }
159574
- db.prepare("DELETE FROM compression_depth WHERE session_id = ? AND message_ordinal BETWEEN ? AND ?").run(sessionId, startOrdinal, endOrdinal);
159575
- }
159576
- var incrementDepthStatements, totalDepthStatements, maxDepthStatements, clearDepthStatements;
159577
- var init_compression_depth_storage = __esm(() => {
159578
- incrementDepthStatements = new WeakMap;
159579
- totalDepthStatements = new WeakMap;
159580
- maxDepthStatements = new WeakMap;
159581
- clearDepthStatements = new WeakMap;
159582
- });
159583
-
159584
159727
  // src/hooks/magic-context/read-session-db.ts
159585
159728
  import { join as join16 } from "node:path";
159586
159729
  function getOpenCodeDbPath2() {
@@ -160934,6 +161077,22 @@ var init_migrations = __esm(async () => {
160934
161077
  db.exec("ALTER TABLE session_meta ADD COLUMN pending_pi_compaction_marker_state TEXT");
160935
161078
  }
160936
161079
  }
161080
+ },
161081
+ {
161082
+ version: 19,
161083
+ description: "Add compartment state lease table",
161084
+ up: (db) => {
161085
+ db.exec(`
161086
+ CREATE TABLE IF NOT EXISTS compartment_state_lease (
161087
+ session_id TEXT PRIMARY KEY NOT NULL,
161088
+ holder_id TEXT NOT NULL,
161089
+ acquired_at INTEGER NOT NULL,
161090
+ expires_at INTEGER NOT NULL
161091
+ );
161092
+ CREATE INDEX IF NOT EXISTS idx_compartment_state_lease_expires
161093
+ ON compartment_state_lease(expires_at);
161094
+ `);
161095
+ }
160937
161096
  }
160938
161097
  ];
160939
161098
  });
@@ -161274,6 +161433,15 @@ function initializeDatabase(db) {
161274
161433
  );
161275
161434
  CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
161276
161435
 
161436
+ CREATE TABLE IF NOT EXISTS compartment_state_lease (
161437
+ session_id TEXT PRIMARY KEY NOT NULL,
161438
+ holder_id TEXT NOT NULL,
161439
+ acquired_at INTEGER NOT NULL,
161440
+ expires_at INTEGER NOT NULL
161441
+ );
161442
+ CREATE INDEX IF NOT EXISTS idx_compartment_state_lease_expires
161443
+ ON compartment_state_lease(expires_at);
161444
+
161277
161445
  CREATE TABLE IF NOT EXISTS compression_depth (
161278
161446
  session_id TEXT NOT NULL,
161279
161447
  message_ordinal INTEGER NOT NULL,
@@ -162406,6 +162574,7 @@ function clearSession(db, sessionId) {
162406
162574
  db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
162407
162575
  clearCompressionDepth(db, sessionId);
162408
162576
  db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
162577
+ db.prepare("DELETE FROM compartment_state_lease WHERE session_id = ?").run(sessionId);
162409
162578
  db.prepare("DELETE FROM notes WHERE session_id = ? AND type = 'session'").run(sessionId);
162410
162579
  db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
162411
162580
  db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
@@ -164543,6 +164712,12 @@ async function executePartialRecompInternal(deps, range) {
164543
164712
  getNotificationParams
164544
164713
  } = deps;
164545
164714
  const notifParams = () => getNotificationParams?.() ?? {};
164715
+ const holderId = deps.compartmentLeaseHolderId;
164716
+ if (!holderId) {
164717
+ return `## Magic Recomp — Failed
164718
+
164719
+ Could not acquire the compartment-state lease for this session.`;
164720
+ }
164546
164721
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
164547
164722
  try {
164548
164723
  let promoteFinal = function() {
@@ -164579,7 +164754,7 @@ async function executePartialRecompInternal(deps, range) {
164579
164754
  return null;
164580
164755
  }
164581
164756
  saveRecompStagingPass(db, sessionId, passCount + 1, merged, currentFacts);
164582
- const promoted = promoteRecompStaging(db, sessionId);
164757
+ const promoted = promoteRecompStaging(db, sessionId, holderId);
164583
164758
  if (!promoted) {
164584
164759
  log("[magic-context] partial recomp promote returned null");
164585
164760
  return null;
@@ -165349,6 +165524,10 @@ function cavemanLevelForDepth(outputDepth) {
165349
165524
  }
165350
165525
  async function runCompressionPassIfNeeded(deps) {
165351
165526
  const { db, sessionId, historyBudgetTokens } = deps;
165527
+ if (deps.historianRunnable === false) {
165528
+ sessionLog(sessionId, "compressor: skipped because historian.disable=true");
165529
+ return false;
165530
+ }
165352
165531
  const minCompartmentRatio = deps.minCompartmentRatio ?? DEFAULT_COMPRESSOR_MIN_COMPARTMENT_RATIO;
165353
165532
  const maxMergeDepth = deps.maxMergeDepth ?? DEFAULT_COMPRESSOR_MAX_MERGE_DEPTH;
165354
165533
  const compartments = getCompartments(db, sessionId);
@@ -165435,7 +165614,8 @@ ${c.content}
165435
165614
  originalStart: selectedCompartments[0].startMessage,
165436
165615
  originalEnd: selectedCompartments[selectedCompartments.length - 1].endMessage,
165437
165616
  facts,
165438
- logLabel: `depth-5 title-only collapse (${selectedCompartments.length} → ${selectedCompartments.length})`
165617
+ logLabel: `depth-5 title-only collapse (${selectedCompartments.length} → ${selectedCompartments.length})`,
165618
+ holderId: deps.compartmentLeaseHolderId
165439
165619
  });
165440
165620
  }
165441
165621
  try {
@@ -165465,7 +165645,8 @@ ${c.content}
165465
165645
  originalStart: selectedCompartments[0].startMessage,
165466
165646
  originalEnd: selectedCompartments[selectedCompartments.length - 1].endMessage,
165467
165647
  facts,
165468
- logLabel: `depth-${outputDepth} (${selectedCompartments.length} → ${finalCompressed.length})`
165648
+ logLabel: `depth-${outputDepth} (${selectedCompartments.length} → ${finalCompressed.length})`,
165649
+ holderId: deps.compartmentLeaseHolderId
165469
165650
  });
165470
165651
  } catch (error51) {
165471
165652
  sessionLog(sessionId, "compressor: unexpected error:", getErrorMessage(error51));
@@ -165590,7 +165771,8 @@ function finalizeCompression(args) {
165590
165771
  originalStart,
165591
165772
  originalEnd,
165592
165773
  facts,
165593
- logLabel
165774
+ logLabel,
165775
+ holderId
165594
165776
  } = args;
165595
165777
  const compressedStart = compressed[0].startMessage;
165596
165778
  const compressedEnd = compressed[compressed.length - 1].endMessage;
@@ -165641,8 +165823,16 @@ function finalizeCompression(args) {
165641
165823
  content: c.content
165642
165824
  }))
165643
165825
  ];
165644
- replaceAllCompartmentState(db, sessionId, allCompartments, facts.map((f) => ({ category: f.category, content: f.content })));
165645
- incrementCompressionDepth(db, sessionId, originalStart, originalEnd);
165826
+ const factInputs = facts.map((f) => ({ category: f.category, content: f.content }));
165827
+ const published = holderId ? replaceAllCompartmentStateAndBumpDepth(db, holderId, sessionId, allCompartments, factInputs, originalStart, originalEnd) : (() => {
165828
+ replaceAllCompartmentState(db, sessionId, allCompartments, factInputs);
165829
+ incrementCompressionDepth(db, sessionId, originalStart, originalEnd);
165830
+ return true;
165831
+ })();
165832
+ if (!published) {
165833
+ sessionLog(sessionId, "compressor: publish skipped because compartment lease is no longer held");
165834
+ return false;
165835
+ }
165646
165836
  sessionLog(sessionId, `compressor: completed ${logLabel}`);
165647
165837
  return true;
165648
165838
  }
@@ -165897,7 +166087,19 @@ No new compartments or facts were written. Check the historian model/output and
165897
166087
  const deferMarkerApplication = deps.preserveInjectionCacheUntilConsumed === true;
165898
166088
  const lastCompartmentEnd = lastNewEnd;
165899
166089
  const lastNewEndMessageId = newCompartments[newCompartments.length - 1]?.endMessageId;
165900
- db.transaction(() => {
166090
+ const holderId = deps.compartmentLeaseHolderId;
166091
+ if (!holderId) {
166092
+ sessionLog(sessionId, "historian publish skipped: missing compartment lease holder");
166093
+ return;
166094
+ }
166095
+ let published = false;
166096
+ db.exec("BEGIN IMMEDIATE");
166097
+ try {
166098
+ if (!isCompartmentLeaseHeld(db, sessionId, holderId)) {
166099
+ db.exec("ROLLBACK");
166100
+ sessionLog(sessionId, "historian publish skipped: compartment lease no longer held");
166101
+ return;
166102
+ }
165901
166103
  appendCompartments(db, sessionId, newCompartments);
165902
166104
  replaceSessionFacts(db, sessionId, validatedPass.facts ?? []);
165903
166105
  clearHistorianFailureState(db, sessionId);
@@ -165909,7 +166111,15 @@ No new compartments or facts were written. Check the historian model/output and
165909
166111
  publishedAt: Date.now()
165910
166112
  });
165911
166113
  }
165912
- })();
166114
+ db.exec("COMMIT");
166115
+ published = true;
166116
+ } finally {
166117
+ if (!published) {
166118
+ try {
166119
+ db.exec("ROLLBACK");
166120
+ } catch {}
166121
+ }
166122
+ }
165913
166123
  if (deps.preserveInjectionCacheUntilConsumed !== true) {
165914
166124
  clearInjectionCache(sessionId);
165915
166125
  }
@@ -165977,6 +166187,7 @@ var init_compartment_runner_incremental = __esm(async () => {
165977
166187
  init_compartment_storage();
165978
166188
  init_historian_state_file();
165979
166189
  init_historian_state_file();
166190
+ init_compartment_lease();
165980
166191
  init_memory();
165981
166192
  init_project_identity();
165982
166193
  init_storage_memory();
@@ -166013,6 +166224,12 @@ async function executeContextRecompInternal(deps) {
166013
166224
  getNotificationParams
166014
166225
  } = deps;
166015
166226
  const notifParams = () => getNotificationParams?.() ?? {};
166227
+ const holderId = deps.compartmentLeaseHolderId;
166228
+ if (!holderId) {
166229
+ return `## Magic Recomp — Skipped
166230
+
166231
+ Could not acquire the compartment-state lease for this session.`;
166232
+ }
166016
166233
  let currentStateFilePath;
166017
166234
  updateSessionMeta(db, sessionId, { compartmentInProgress: true });
166018
166235
  try {
@@ -166049,7 +166266,7 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
166049
166266
  if (mergedError)
166050
166267
  return null;
166051
166268
  saveRecompStagingPass(db, sessionId, passCount, candidateCompartments, candidateFacts);
166052
- const promoted2 = promoteRecompStaging(db, sessionId);
166269
+ const promoted2 = promoteRecompStaging(db, sessionId, holderId);
166053
166270
  if (!promoted2)
166054
166271
  return null;
166055
166272
  clearCompressionDepth(db, sessionId);
@@ -166200,10 +166417,12 @@ Recomp completed ${passCount} pass${passCount === 1 ? "" : "es"} but produced an
166200
166417
  Nothing was written.`;
166201
166418
  }
166202
166419
  saveRecompStagingPass(db, sessionId, passCount, candidateCompartments, candidateFacts);
166203
- const promoted = promoteRecompStaging(db, sessionId);
166420
+ const promoted = promoteRecompStaging(db, sessionId, holderId);
166204
166421
  if (!promoted) {
166205
- replaceAllCompartmentState(db, sessionId, candidateCompartments, candidateFacts);
166206
- clearRecompStaging(db, sessionId);
166422
+ sessionLog(sessionId, "recomp publish skipped: compartment lease no longer held");
166423
+ return `## Magic Recomp — Skipped
166424
+
166425
+ Another process acquired the compartment-state lease before recomp could publish. No state was written.`;
166207
166426
  }
166208
166427
  clearCompressionDepth(db, sessionId);
166209
166428
  if (deps.preserveInjectionCacheUntilConsumed !== true) {
@@ -166262,6 +166481,7 @@ var init_compartment_runner_recomp = __esm(async () => {
166262
166481
  init_project_identity();
166263
166482
  init_storage_memory();
166264
166483
  init_shared();
166484
+ init_logger();
166265
166485
  init_compartment_prompt();
166266
166486
  init_compartment_runner_state_xml();
166267
166487
  init_send_session_notification();
@@ -166286,6 +166506,7 @@ __export(exports_compartment_runner, {
166286
166506
  registerActiveCompartmentRun: () => registerActiveCompartmentRun,
166287
166507
  markActiveCompartmentRunPublished: () => markActiveCompartmentRunPublished,
166288
166508
  getActiveCompartmentRun: () => getActiveCompartmentRun,
166509
+ executeContextRecompWithResult: () => executeContextRecompWithResult,
166289
166510
  executeContextRecomp: () => executeContextRecomp
166290
166511
  });
166291
166512
  function getActiveCompartmentRun(sessionId) {
@@ -166319,30 +166540,59 @@ function withPublishedCallback(deps) {
166319
166540
  }
166320
166541
  };
166321
166542
  }
166543
+ function startLeaseRenewal(deps, holderId) {
166544
+ return setInterval(() => {
166545
+ if (!renewCompartmentLease(deps.db, deps.sessionId, holderId)) {
166546
+ sessionLog(deps.sessionId, "compartment lease renewal failed; publish will be skipped if holder is stale");
166547
+ }
166548
+ }, COMPARTMENT_LEASE_RENEWAL_MS);
166549
+ }
166322
166550
  function startCompartmentAgent(deps) {
166323
166551
  const existing = activeRuns.get(deps.sessionId);
166324
166552
  if (existing) {
166325
166553
  return;
166326
166554
  }
166327
- const runnerDeps = withPublishedCallback(deps);
166555
+ const holderId = crypto.randomUUID();
166556
+ const lease2 = acquireCompartmentLease(deps.db, deps.sessionId, holderId);
166557
+ if (!lease2) {
166558
+ sessionLog(deps.sessionId, "compartment agent skipped: compartment lease held by another process");
166559
+ return;
166560
+ }
166561
+ const renewal = startLeaseRenewal(deps, holderId);
166562
+ const runnerDeps = withPublishedCallback({ ...deps, compartmentLeaseHolderId: holderId });
166328
166563
  const promise2 = runCompartmentAgent(runnerDeps).catch((err) => {
166329
166564
  sessionLog(deps.sessionId, "compartment agent: unhandled rejection:", err);
166330
166565
  try {
166331
166566
  updateSessionMeta(deps.db, deps.sessionId, { compartmentInProgress: false });
166332
166567
  } catch {}
166333
166568
  }).finally(() => {
166569
+ clearInterval(renewal);
166570
+ releaseCompartmentLease(deps.db, deps.sessionId, holderId);
166334
166571
  if (activeRuns.get(deps.sessionId)?.promise === promise2) {
166335
166572
  activeRuns.delete(deps.sessionId);
166336
166573
  }
166337
166574
  });
166338
166575
  activeRuns.set(deps.sessionId, { promise: promise2, published: false });
166339
166576
  }
166340
- async function executeContextRecomp(deps, options = {}) {
166577
+ async function executeContextRecompWithResult(deps, options = {}) {
166341
166578
  const { sessionId } = deps;
166342
166579
  if (activeRuns.has(sessionId)) {
166343
- return "## Magic Recomp\n\nHistorian is already running for this session. Wait for it to finish, then try `/ctx-recomp` again.";
166580
+ return {
166581
+ message: "## Magic Recomp\n\nHistorian is already running for this session. Wait for it to finish, then try `/ctx-recomp` again.",
166582
+ published: false
166583
+ };
166584
+ }
166585
+ const holderId = crypto.randomUUID();
166586
+ const lease2 = acquireCompartmentLease(deps.db, sessionId, holderId);
166587
+ if (!lease2) {
166588
+ sessionLog(sessionId, "recomp skipped: compartment lease held by another process");
166589
+ return {
166590
+ message: "## Magic Recomp\n\nAnother process is already mutating compartment state for this session. Wait for it to finish, then try `/ctx-recomp` again.",
166591
+ published: false
166592
+ };
166344
166593
  }
166345
- const runnerDeps = withPublishedCallback(deps);
166594
+ const renewal = startLeaseRenewal(deps, holderId);
166595
+ const runnerDeps = withPublishedCallback({ ...deps, compartmentLeaseHolderId: holderId });
166346
166596
  const promise2 = options.range ? executePartialRecompInternal(runnerDeps, options.range) : executeContextRecompInternal(runnerDeps);
166347
166597
  const wrappedPromise = promise2.then(() => {
166348
166598
  return;
@@ -166351,15 +166601,25 @@ async function executeContextRecomp(deps, options = {}) {
166351
166601
  });
166352
166602
  activeRuns.set(sessionId, { promise: wrappedPromise, published: false });
166353
166603
  try {
166354
- return await promise2;
166604
+ const message = await promise2;
166605
+ return {
166606
+ message,
166607
+ published: activeRuns.get(sessionId)?.published === true
166608
+ };
166355
166609
  } finally {
166610
+ clearInterval(renewal);
166611
+ releaseCompartmentLease(deps.db, sessionId, holderId);
166356
166612
  if (activeRuns.get(sessionId)?.promise === wrappedPromise) {
166357
166613
  activeRuns.delete(sessionId);
166358
166614
  }
166359
166615
  }
166360
166616
  }
166617
+ async function executeContextRecomp(deps, options = {}) {
166618
+ return (await executeContextRecompWithResult(deps, options)).message;
166619
+ }
166361
166620
  var activeRuns;
166362
166621
  var init_compartment_runner = __esm(async () => {
166622
+ init_compartment_lease();
166363
166623
  init_logger();
166364
166624
  await __promiseAll([
166365
166625
  init_storage_meta(),
@@ -166371,13 +166631,65 @@ var init_compartment_runner = __esm(async () => {
166371
166631
  activeRuns = new Map;
166372
166632
  });
166373
166633
 
166634
+ // src/shared/announcement.ts
166635
+ var exports_announcement = {};
166636
+ __export(exports_announcement, {
166637
+ shouldShowAnnouncement: () => shouldShowAnnouncement,
166638
+ readLastAnnouncedVersion: () => readLastAnnouncedVersion,
166639
+ markAnnouncementSeen: () => markAnnouncementSeen,
166640
+ ANNOUNCEMENT_VERSION: () => ANNOUNCEMENT_VERSION,
166641
+ ANNOUNCEMENT_FOOTER: () => ANNOUNCEMENT_FOOTER,
166642
+ ANNOUNCEMENT_FEATURES: () => ANNOUNCEMENT_FEATURES
166643
+ });
166644
+ import * as fs2 from "node:fs";
166645
+ import * as path5 from "node:path";
166646
+ function getStateFilePath() {
166647
+ return path5.join(getMagicContextStorageDir(), STATE_FILENAME);
166648
+ }
166649
+ function readLastAnnouncedVersion() {
166650
+ try {
166651
+ const file2 = getStateFilePath();
166652
+ if (!fs2.existsSync(file2))
166653
+ return "";
166654
+ return fs2.readFileSync(file2, "utf-8").trim();
166655
+ } catch {
166656
+ return "";
166657
+ }
166658
+ }
166659
+ function markAnnouncementSeen(version2) {
166660
+ if (!version2)
166661
+ return;
166662
+ try {
166663
+ const dir = getMagicContextStorageDir();
166664
+ fs2.mkdirSync(dir, { recursive: true });
166665
+ fs2.writeFileSync(getStateFilePath(), version2);
166666
+ } catch {}
166667
+ }
166668
+ function shouldShowAnnouncement() {
166669
+ if (!ANNOUNCEMENT_VERSION || ANNOUNCEMENT_FEATURES.length === 0)
166670
+ return false;
166671
+ return readLastAnnouncedVersion() !== ANNOUNCEMENT_VERSION;
166672
+ }
166673
+ var ANNOUNCEMENT_VERSION = "0.21.7", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
166674
+ var init_announcement = __esm(() => {
166675
+ init_data_path();
166676
+ ANNOUNCEMENT_FEATURES = [
166677
+ "Pi parity sweep: 44 audit findings fixed, including a critical SHIP-BLOCKER where /ctx-flush did not drain the pending Pi compaction queue.",
166678
+ "Pi historian recovery fix: empty/no-op historian returns now clear emergency recovery so sessions cannot loop forever at 95%.",
166679
+ "trimPiMessagesToBoundary now sweeps non-contiguous tool-result orphans, fixing provider 400s after compaction in long Pi sessions.",
166680
+ "Hidden subagent tool isolation: historian, dreamer, and sidekick can no longer spawn subagents or run unsafe tools.",
166681
+ "TUI sidebar and /ctx-status header now show execute threshold inline: '47.5% / 65%' on the left, '475K / 1.0M' on the right.",
166682
+ "doctor --issue now caps GitHub issue bodies at ~60KB with a dedicated 'Recent errors' section so reports stay submittable."
166683
+ ];
166684
+ });
166685
+
166374
166686
  // src/shared/tui-config.ts
166375
166687
  var exports_tui_config = {};
166376
166688
  __export(exports_tui_config, {
166377
166689
  ensureTuiPluginEntry: () => ensureTuiPluginEntry
166378
166690
  });
166379
- import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
166380
- import { dirname as dirname9, join as join27 } from "node:path";
166691
+ import { existsSync as existsSync17, mkdirSync as mkdirSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
166692
+ import { dirname as dirname9, join as join28 } from "node:path";
166381
166693
  function isMagicContextEntry(entry) {
166382
166694
  if (!entry)
166383
166695
  return false;
@@ -166391,11 +166703,11 @@ function isMagicContextEntry(entry) {
166391
166703
  }
166392
166704
  function resolveTuiConfigPath() {
166393
166705
  const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
166394
- const jsoncPath = join27(configDir, "tui.jsonc");
166395
- const jsonPath = join27(configDir, "tui.json");
166396
- if (existsSync16(jsoncPath))
166706
+ const jsoncPath = join28(configDir, "tui.jsonc");
166707
+ const jsonPath = join28(configDir, "tui.json");
166708
+ if (existsSync17(jsoncPath))
166397
166709
  return jsoncPath;
166398
- if (existsSync16(jsonPath))
166710
+ if (existsSync17(jsonPath))
166399
166711
  return jsonPath;
166400
166712
  return jsonPath;
166401
166713
  }
@@ -166403,8 +166715,8 @@ function ensureTuiPluginEntry() {
166403
166715
  try {
166404
166716
  const configPath = resolveTuiConfigPath();
166405
166717
  let config2 = {};
166406
- if (existsSync16(configPath)) {
166407
- const raw = readFileSync15(configPath, "utf-8");
166718
+ if (existsSync17(configPath)) {
166719
+ const raw = readFileSync16(configPath, "utf-8");
166408
166720
  config2 = import_comment_json4.parse(raw) ?? {};
166409
166721
  }
166410
166722
  const plugins = Array.isArray(config2.plugin) ? config2.plugin.filter((p) => typeof p === "string") : [];
@@ -166423,8 +166735,8 @@ function ensureTuiPluginEntry() {
166423
166735
  plugins.push(PLUGIN_ENTRY);
166424
166736
  }
166425
166737
  config2.plugin = plugins;
166426
- mkdirSync9(dirname9(configPath), { recursive: true });
166427
- writeFileSync8(configPath, `${import_comment_json4.stringify(config2, null, 2)}
166738
+ mkdirSync10(dirname9(configPath), { recursive: true });
166739
+ writeFileSync9(configPath, `${import_comment_json4.stringify(config2, null, 2)}
166428
166740
  `);
166429
166741
  log(`[magic-context] updated TUI plugin entry in ${configPath}`);
166430
166742
  return true;
@@ -166468,11 +166780,69 @@ var SIDEKICK_ALLOWED_TOOLS = [
166468
166780
  ];
166469
166781
  // src/config/index.ts
166470
166782
  init_jsonc_parser();
166471
- init_magic_context();
166472
166783
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
166473
166784
  import { homedir as homedir2 } from "node:os";
166474
166785
  import { join } from "node:path";
166475
166786
 
166787
+ // src/config/agent-disable.ts
166788
+ function isDreamerRunnable(config) {
166789
+ return !!config.dreamer && config.dreamer.disable !== true;
166790
+ }
166791
+ function isSidekickRunnable(config) {
166792
+ return !!config.sidekick && config.sidekick.disable !== true;
166793
+ }
166794
+ function isHistorianRunnable(config) {
166795
+ return config.historian?.disable !== true;
166796
+ }
166797
+ function clonePlainObject(value) {
166798
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
166799
+ return;
166800
+ }
166801
+ return { ...value };
166802
+ }
166803
+ function migrateLegacyEnabledForAgent(args) {
166804
+ const agent = clonePlainObject(args.patched[args.agentName]);
166805
+ if (!agent || !("enabled" in agent))
166806
+ return;
166807
+ const enabled = agent.enabled;
166808
+ const disable = agent.disable;
166809
+ delete agent.enabled;
166810
+ if (args.agentName === "historian") {
166811
+ args.warnings.push('Removed invalid "historian.enabled" in-memory (run doctor to persist).');
166812
+ args.patched.historian = agent;
166813
+ return;
166814
+ }
166815
+ if (args.agentName === "dreamer") {
166816
+ if (disable !== true && enabled === false) {
166817
+ agent.disable = true;
166818
+ args.warnings.push('Migrated "dreamer.enabled=false" → "dreamer.disable=true" in-memory (run doctor to persist). This now also disables manual /ctx-dream; for manual-only remove disable and set schedule="".');
166819
+ }
166820
+ args.patched.dreamer = agent;
166821
+ return;
166822
+ }
166823
+ if (disable !== true && enabled === false) {
166824
+ agent.disable = true;
166825
+ args.warnings.push('Migrated "sidekick.enabled=false" → "sidekick.disable=true" in-memory (run doctor to persist).');
166826
+ }
166827
+ args.patched.sidekick = agent;
166828
+ }
166829
+ function migrateLegacyAgentEnabledInMemory(rawConfig, warnings) {
166830
+ const shouldPatch = ["dreamer", "sidekick", "historian"].some((key) => {
166831
+ const agent = rawConfig[key];
166832
+ return typeof agent === "object" && agent !== null && !Array.isArray(agent) && "enabled" in agent;
166833
+ });
166834
+ if (!shouldPatch)
166835
+ return rawConfig;
166836
+ const patched = { ...rawConfig };
166837
+ migrateLegacyEnabledForAgent({ patched, agentName: "dreamer", warnings });
166838
+ migrateLegacyEnabledForAgent({ patched, agentName: "sidekick", warnings });
166839
+ migrateLegacyEnabledForAgent({ patched, agentName: "historian", warnings });
166840
+ return patched;
166841
+ }
166842
+
166843
+ // src/config/index.ts
166844
+ init_magic_context();
166845
+
166476
166846
  // src/config/variable.ts
166477
166847
  init_jsonc_parser();
166478
166848
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
@@ -166716,7 +167086,8 @@ function migrateLegacyExperimental(rawConfig, warnings) {
166716
167086
  }
166717
167087
  function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
166718
167088
  const preMigrationWarnings = [];
166719
- const migrated = migrateLegacyExperimental(rawConfig, preMigrationWarnings);
167089
+ const migratedExperimental = migrateLegacyExperimental(rawConfig, preMigrationWarnings);
167090
+ const migrated = migrateLegacyAgentEnabledInMemory(migratedExperimental, preMigrationWarnings);
166720
167091
  const parsed = MagicContextConfigSchema.safeParse(migrated);
166721
167092
  const disabledHooks = Array.isArray(rawConfig.disabled_hooks) ? rawConfig.disabled_hooks.filter((value) => typeof value === "string") : undefined;
166722
167093
  const command = typeof rawConfig.command === "object" && rawConfig.command !== null ? rawConfig.command : undefined;
@@ -170119,7 +170490,7 @@ async function startDreamScheduleTimer(args) {
170119
170490
  const db = openDatabase();
170120
170491
  await args.ensureRegistered(args.directory, db);
170121
170492
  const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
170122
- const dreamingEnabled = Boolean(args.dreamerConfig?.enabled && args.dreamerConfig.schedule?.trim());
170493
+ const dreamingEnabled = Boolean(args.dreamerConfig && args.dreamerConfig.disable !== true && args.dreamerConfig.schedule?.trim());
170123
170494
  const embeddingSweepEnabled = snapshot?.enabled ?? false;
170124
170495
  const commitIndexingEnabled = snapshot?.gitCommitEnabled ?? false;
170125
170496
  if (!dreamingEnabled && !embeddingSweepEnabled && !commitIndexingEnabled) {
@@ -170175,7 +170546,7 @@ function runTick(origin) {
170175
170546
  })();
170176
170547
  }
170177
170548
  async function sweepProject(reg, origin, db = openDatabase(), gitCommitEnabled = getProjectEmbeddingSnapshot(reg.projectIdentity)?.gitCommitEnabled === true) {
170178
- const dreamingEnabled = Boolean(reg.dreamerConfig?.enabled && reg.dreamerConfig.schedule?.trim());
170549
+ const dreamingEnabled = Boolean(reg.dreamerConfig && reg.dreamerConfig.disable !== true && reg.dreamerConfig.schedule?.trim());
170179
170550
  if (gitCommitEnabled && reg.gitCommitIndexing) {
170180
170551
  await sweepGitCommits({
170181
170552
  directory: reg.directory,
@@ -170818,7 +171189,6 @@ function createTagger() {
170818
171189
  cleanup
170819
171190
  };
170820
171191
  }
170821
-
170822
171192
  // src/hooks/magic-context/hook.ts
170823
171193
  init_magic_context();
170824
171194
  init_project_identity();
@@ -172482,6 +172852,7 @@ init_temporal_awareness();
172482
172852
 
172483
172853
  // src/hooks/magic-context/transform-compartment-phase.ts
172484
172854
  init_magic_context();
172855
+ init_compartment_lease();
172485
172856
  init_compartment_storage();
172486
172857
  init_logger();
172487
172858
  await __promiseAll([
@@ -172513,11 +172884,12 @@ async function runCompartmentPhase(args) {
172513
172884
  let published = false;
172514
172885
  let justAwaitedPublication = false;
172515
172886
  let rebuiltHistoryThisPass = false;
172887
+ const historianRunnable = args.historianRunnable !== false;
172516
172888
  let lastCompartmentEnd = null;
172517
172889
  let rawMessageCount = null;
172518
172890
  let cachedProtectedTailStart = null;
172519
172891
  function hasNewRawHistoryForCompartment() {
172520
- if (!args.fullFeatureMode)
172892
+ if (!args.fullFeatureMode || !historianRunnable)
172521
172893
  return false;
172522
172894
  if (lastCompartmentEnd === null) {
172523
172895
  lastCompartmentEnd = getLastCompartmentEndMessage(args.db, args.resolvedSessionId);
@@ -172555,7 +172927,12 @@ async function runCompartmentPhase(args) {
172555
172927
  }
172556
172928
  return "completed";
172557
172929
  }
172558
- if (args.canRunCompartments && args.sessionMeta.compartmentInProgress && !getActiveCompartmentRun(args.sessionId)) {
172930
+ if (!historianRunnable && args.sessionMeta.compartmentInProgress) {
172931
+ sessionLog(args.sessionId, "transform: historian disabled; clearing stale compartmentInProgress flag");
172932
+ updateSessionMeta(args.db, args.sessionId, { compartmentInProgress: false });
172933
+ compartmentInProgress = false;
172934
+ }
172935
+ if (historianRunnable && args.canRunCompartments && args.sessionMeta.compartmentInProgress && !getActiveCompartmentRun(args.sessionId)) {
172559
172936
  if (!hasEligibleHistoryForCompartment()) {
172560
172937
  sessionLog(args.sessionId, `transform: skipping compartment start, no eligible history before protected tail (beyond ${lastCompartmentEnd ?? -1})`);
172561
172938
  updateSessionMeta(args.db, args.sessionId, { compartmentInProgress: false });
@@ -172591,7 +172968,7 @@ async function runCompartmentPhase(args) {
172591
172968
  }
172592
172969
  }
172593
172970
  let awaitedCompartmentRun = false;
172594
- if (args.canRunCompartments && !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE) {
172971
+ if (historianRunnable && args.canRunCompartments && !args.skipAwaitForThisPass && args.contextUsage.percentage >= BLOCK_UNTIL_DONE_PERCENTAGE) {
172595
172972
  let activeRun = getActiveCompartmentRun(args.sessionId);
172596
172973
  if (!activeRun && hasEligibleHistoryForCompartment() && args.client) {
172597
172974
  sessionLog(args.sessionId, `transform: 95% reached (${args.contextUsage.percentage.toFixed(1)}%), force-starting compartment agent and blocking`);
@@ -172635,19 +173012,41 @@ async function runCompartmentPhase(args) {
172635
173012
  }
172636
173013
  }
172637
173014
  }
172638
- if (args.safeForBackgroundCompression && !args.suppressBackgroundCompressionThisPass && args.historyBudgetTokens && args.historyBudgetTokens > 0 && args.client && !compartmentInProgress && !awaitedCompartmentRun && !isCompressorOnCooldown(args.sessionId, args.compressorCooldownMs ?? DEFAULT_COMPRESSOR_COOLDOWN_MS)) {
172639
- markCompressorRun(args.sessionId);
172640
- const compressorPromise = runCompressionPassIfNeeded({
172641
- client: args.client,
172642
- db: args.db,
172643
- sessionId: args.sessionId,
172644
- directory: args.compartmentDirectory,
172645
- historyBudgetTokens: args.historyBudgetTokens,
172646
- historianTimeoutMs: args.historianTimeoutMs,
172647
- fallbackModels: args.fallbackModels,
172648
- minCompartmentRatio: args.compressorMinCompartmentRatio,
172649
- maxMergeDepth: args.compressorMaxMergeDepth
172650
- }).then((compressed) => {
173015
+ if (historianRunnable && args.safeForBackgroundCompression && args.historyBudgetTokens && args.historyBudgetTokens > 0 && args.client && !compartmentInProgress && !awaitedCompartmentRun && !isCompressorOnCooldown(args.sessionId, args.compressorCooldownMs ?? DEFAULT_COMPRESSOR_COOLDOWN_MS)) {
173016
+ const client = args.client;
173017
+ const historyBudgetTokens = args.historyBudgetTokens;
173018
+ const holderId = crypto.randomUUID();
173019
+ const compressorPromise = (async () => {
173020
+ const lease2 = acquireCompartmentLease(args.db, args.sessionId, holderId);
173021
+ if (!lease2) {
173022
+ sessionLog(args.sessionId, "independent compressor skipped: compartment lease held by another process");
173023
+ return false;
173024
+ }
173025
+ markCompressorRun(args.sessionId);
173026
+ const renewal = setInterval(() => {
173027
+ if (!renewCompartmentLease(args.db, args.sessionId, holderId)) {
173028
+ sessionLog(args.sessionId, "independent compressor lease renewal failed; publish will be skipped if holder is stale");
173029
+ }
173030
+ }, COMPARTMENT_LEASE_RENEWAL_MS);
173031
+ try {
173032
+ return await runCompressionPassIfNeeded({
173033
+ client,
173034
+ db: args.db,
173035
+ sessionId: args.sessionId,
173036
+ directory: args.compartmentDirectory,
173037
+ historyBudgetTokens,
173038
+ historianTimeoutMs: args.historianTimeoutMs,
173039
+ fallbackModels: args.fallbackModels,
173040
+ minCompartmentRatio: args.compressorMinCompartmentRatio,
173041
+ maxMergeDepth: args.compressorMaxMergeDepth,
173042
+ historianRunnable,
173043
+ compartmentLeaseHolderId: holderId
173044
+ });
173045
+ } finally {
173046
+ clearInterval(renewal);
173047
+ releaseCompartmentLease(args.db, args.sessionId, holderId);
173048
+ }
173049
+ })().then((compressed) => {
172651
173050
  if (compressed) {
172652
173051
  markActiveCompartmentRunPublished(args.sessionId);
172653
173052
  published = true;
@@ -173897,6 +174296,7 @@ ${trimmedBody}…
173897
174296
  }
173898
174297
 
173899
174298
  // src/hooks/magic-context/auto-search-runner.ts
174299
+ init_read_session_formatting();
173900
174300
  var AUTO_SEARCH_TIMEOUT_MS = 3000;
173901
174301
  async function unifiedSearchWithTimeout(db, sessionId, projectPath, prompt, options, timeoutMs) {
173902
174302
  const controller = new AbortController;
@@ -173925,10 +174325,12 @@ function collectUserPromptParts(message) {
173925
174325
  let collected = "";
173926
174326
  for (const part of message.parts) {
173927
174327
  const p = part;
173928
- if (p.type === "text" && typeof p.text === "string") {
173929
- collected += (collected.length > 0 ? `
174328
+ if (p.type !== "text" || typeof p.text !== "string")
174329
+ continue;
174330
+ if (p.ignored === true)
174331
+ continue;
174332
+ collected += (collected.length > 0 ? `
173930
174333
  ` : "") + p.text;
173931
- }
173932
174334
  }
173933
174335
  return collected;
173934
174336
  }
@@ -173971,11 +174373,8 @@ function findLatestMeaningfulUserMessage(messages) {
173971
174373
  continue;
173972
174374
  if (typeof msg.info.id !== "string")
173973
174375
  continue;
173974
- for (const part of msg.parts) {
173975
- const p = part;
173976
- if (p.type === "text" && typeof p.text === "string" && p.text.trim().length > 0) {
173977
- return msg;
173978
- }
174376
+ if (hasMeaningfulUserText(msg.parts)) {
174377
+ return msg;
173979
174378
  }
173980
174379
  }
173981
174380
  return null;
@@ -174455,8 +174854,10 @@ function resetDegradedCacheCount(sessionId) {
174455
174854
  }
174456
174855
  async function runPostTransformPhase(args) {
174457
174856
  let didMutateFromPendingOperations = false;
174458
- const isExplicitFlush = args.pendingMaterializationSessions.has(args.sessionId);
174459
- const deferredMaterializationWasPending = args.deferredMaterializationSessions.has(args.sessionId);
174857
+ const pendingMaterializationAtPassStart = args.pendingMaterializationSessions.has(args.sessionId);
174858
+ const deferredMaterializationAtPassStart = args.deferredMaterializationSessions.has(args.sessionId);
174859
+ const isExplicitFlush = pendingMaterializationAtPassStart;
174860
+ const deferredMaterializationWasPending = deferredMaterializationAtPassStart;
174460
174861
  const alreadyRanThisTurn = args.currentTurnId !== null && args.lastHeuristicsTurnId.get(args.sessionId) === args.currentTurnId;
174461
174862
  const forceMaterialization = args.fullFeatureMode && args.contextUsage.percentage >= args.forceMaterializationPercentage;
174462
174863
  const activeCompartmentRun = args.canRunCompartments ? getActiveCompartmentRun(args.sessionId) : undefined;
@@ -174542,7 +174943,9 @@ async function runPostTransformPhase(args) {
174542
174943
  }
174543
174944
  }
174544
174945
  logTransformTiming(args.sessionId, "clearOldReasoning", t7);
174545
- args.pendingMaterializationSessions.delete(args.sessionId);
174946
+ if (pendingMaterializationAtPassStart) {
174947
+ args.pendingMaterializationSessions.delete(args.sessionId);
174948
+ }
174546
174949
  if (args.currentTurnId) {
174547
174950
  args.lastHeuristicsTurnId.set(args.sessionId, args.currentTurnId);
174548
174951
  }
@@ -174747,7 +175150,7 @@ async function runPostTransformPhase(args) {
174747
175150
  }
174748
175151
  }
174749
175152
  let suppressV12HistoryDrain = false;
174750
- if (historyWasConsumedThisPass && args.deferredHistoryRefreshSessions.has(args.sessionId)) {
175153
+ if (historyWasConsumedThisPass && args.deferredHistoryWasPendingAtPassStart) {
174751
175154
  const pending = getPendingCompactionMarkerState(args.db, args.sessionId);
174752
175155
  if (pending) {
174753
175156
  const outcome = applyDeferredCompactionMarker(args.db, args.sessionId, pending, args.sessionDirectory);
@@ -174764,11 +175167,11 @@ async function runPostTransformPhase(args) {
174764
175167
  }
174765
175168
  }
174766
175169
  }
174767
- const deferredHistoryDrainEligible = historyWasConsumedThisPass && !suppressV12HistoryDrain;
175170
+ const deferredHistoryDrainEligible = historyWasConsumedThisPass && args.deferredHistoryWasPendingAtPassStart && !suppressV12HistoryDrain;
174768
175171
  if (deferredHistoryDrainEligible) {
174769
175172
  args.deferredHistoryRefreshSessions.delete(args.sessionId);
174770
175173
  }
174771
- if (explicitMaterializedSuccessfully || deferredMaterializedSuccessfully) {
175174
+ if ((explicitMaterializedSuccessfully || deferredMaterializedSuccessfully) && deferredMaterializationAtPassStart) {
174772
175175
  args.deferredMaterializationSessions.delete(args.sessionId);
174773
175176
  }
174774
175177
  const workExecutedSuccessfully = explicitMaterializedSuccessfully || deferredMaterializedSuccessfully || heuristicsRanSuccessfully || pendingOpsRanSuccessfully;
@@ -174935,7 +175338,8 @@ function createTransform(deps) {
174935
175338
  } catch {}
174936
175339
  }
174937
175340
  const compartmentDirectory = sessionDirectory;
174938
- const canRunCompartments = fullFeatureMode && deps.client !== undefined && compartmentDirectory.length > 0;
175341
+ const historianRunnable = deps.historianRunnable !== false;
175342
+ const canRunCompartments = fullFeatureMode && historianRunnable && deps.client !== undefined && compartmentDirectory.length > 0;
174939
175343
  const fallbackModelId = deps.getFallbackModelId?.(sessionId);
174940
175344
  const tModelDetect = performance.now();
174941
175345
  if (deps.liveModelBySession) {
@@ -175027,6 +175431,7 @@ function createTransform(deps) {
175027
175431
  }
175028
175432
  sessionLog(sessionId, `[boundary-exec] base=${schedulerDecisionEarly} bypass=${bypassReason} midTurn=${midTurn} effective=${midTurnAdjustedSchedulerDecision} sideEffect=${sideEffect}`);
175029
175433
  const historyRefreshExplicitBeforePrepare = deps.historyRefreshSessions.has(sessionId);
175434
+ const deferredHistoryWasPendingAtPassStart = deferredHistoryRefreshSessions.has(sessionId);
175030
175435
  const earlyActiveRunBlocksMaterialization = (getActiveCompartmentRun(sessionId) !== undefined || sessionMeta.compartmentInProgress) && contextUsageEarly.percentage < FORCE_MATERIALIZE_PERCENTAGE;
175031
175436
  const canConsumeDeferredEarly = canConsumeDeferredOnThisPass({
175032
175437
  schedulerDecision: midTurnAdjustedSchedulerDecision,
@@ -175034,9 +175439,8 @@ function createTransform(deps) {
175034
175439
  justAwaitedPublication: false,
175035
175440
  activeRunBlocksMaterialization: earlyActiveRunBlocksMaterialization
175036
175441
  });
175037
- const consumingDeferredEarly = canConsumeDeferredEarly && deferredHistoryRefreshSessions.has(sessionId);
175442
+ const consumingDeferredEarly = canConsumeDeferredEarly && deferredHistoryWasPendingAtPassStart;
175038
175443
  const isCacheBusting = historyRefreshExplicitBeforePrepare || consumingDeferredEarly;
175039
- const historyBustThisPass = isCacheBusting;
175040
175444
  if (historianFailureState.failureCount === 0) {
175041
175445
  lastEmergencyNotificationCount.delete(sessionId);
175042
175446
  }
@@ -175230,6 +175634,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
175230
175634
  const compartmentPhase = await runCompartmentPhase({
175231
175635
  canRunCompartments,
175232
175636
  fullFeatureMode,
175637
+ historianRunnable,
175233
175638
  sessionMeta,
175234
175639
  contextUsage,
175235
175640
  client: deps.client,
@@ -175247,8 +175652,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
175247
175652
  projectPath: projectIdentity,
175248
175653
  injectionBudgetTokens: deps.memoryConfig?.injectionBudgetTokens,
175249
175654
  getNotificationParams: rawGetNotifParams ? () => rawGetNotifParams(sessionId) : undefined,
175250
- safeForBackgroundCompression: isCacheBusting || midTurnAdjustedSchedulerDecision === "execute",
175251
- suppressBackgroundCompressionThisPass: historyBustThisPass,
175655
+ safeForBackgroundCompression: historianRunnable && (isCacheBusting || midTurnAdjustedSchedulerDecision === "execute"),
175252
175656
  deferredHistoryRefreshSessions,
175253
175657
  skipAwaitForThisPass: skipCompartmentAwaitForThisPass,
175254
175658
  experimentalUserMemories: deps.experimentalUserMemories,
@@ -175297,6 +175701,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
175297
175701
  phaseJustAwaitedPublication: compartmentPhase.justAwaitedPublication,
175298
175702
  compartmentInProgress,
175299
175703
  historyRefreshExplicitBeforePrepare,
175704
+ deferredHistoryWasPendingAtPassStart,
175300
175705
  compartmentInjectionRebuiltFromDb: pendingCompartmentInjection?.rebuiltFromDb === true,
175301
175706
  rebuiltHistoryFromInitialPrepare,
175302
175707
  historyRebuiltThisPass,
@@ -176678,6 +177083,11 @@ function createMagicContextHook(deps) {
176678
177083
  return;
176679
177084
  };
176680
177085
  const ctxReduceEnabled = deps.config.ctx_reduce_enabled !== false;
177086
+ const dreamerRunnable = isDreamerRunnable(deps.config);
177087
+ const dreamerConfig = dreamerRunnable ? deps.config.dreamer : undefined;
177088
+ const historianRunnable = isHistorianRunnable(deps.config);
177089
+ const sidekickRunnable = isSidekickRunnable(deps.config);
177090
+ const sidekickConfig = sidekickRunnable ? deps.config.sidekick : undefined;
176681
177091
  const nudgerWithRecentReduce = ctxReduceEnabled ? createNudger({
176682
177092
  protected_tags: deps.config.protected_tags,
176683
177093
  nudge_interval_tokens: deps.config.nudge_interval_tokens ?? DEFAULT_NUDGE_INTERVAL_TOKENS,
@@ -176727,7 +177137,8 @@ function createMagicContextHook(deps) {
176727
177137
  return model ? `${model.providerID}/${model.modelID}` : undefined;
176728
177138
  },
176729
177139
  projectPath,
176730
- experimentalUserMemories: deps.config.dreamer?.user_memories?.enabled,
177140
+ historianRunnable,
177141
+ experimentalUserMemories: dreamerConfig?.user_memories?.enabled,
176731
177142
  experimentalTemporalAwareness: deps.config.experimental?.temporal_awareness === true,
176732
177143
  historianTwoPass: deps.config.historian?.two_pass === true,
176733
177144
  compressorMinCompartmentRatio: deps.config.compressor?.enabled === false ? undefined : deps.config.compressor?.min_compartment_ratio,
@@ -176766,7 +177177,7 @@ function createMagicContextHook(deps) {
176766
177177
  });
176767
177178
  const runDreamQueueInBackground = () => {
176768
177179
  const dreaming = deps.config.dreamer;
176769
- if (!dreaming?.enabled || !dreaming.schedule?.trim()) {
177180
+ if (!dreaming || dreaming.disable === true || !dreaming.schedule?.trim()) {
176770
177181
  return;
176771
177182
  }
176772
177183
  const now = Date.now();
@@ -176786,16 +177197,16 @@ function createMagicContextHook(deps) {
176786
177197
  tasks: dreaming.tasks,
176787
177198
  taskTimeoutMinutes: dreaming.task_timeout_minutes,
176788
177199
  maxRuntimeMinutes: dreaming.max_runtime_minutes,
176789
- experimentalUserMemories: deps.config.dreamer?.user_memories?.enabled ? {
177200
+ experimentalUserMemories: dreaming.user_memories?.enabled ? {
176790
177201
  enabled: true,
176791
- promotionThreshold: deps.config.dreamer.user_memories.promotion_threshold
177202
+ promotionThreshold: dreaming.user_memories.promotion_threshold
176792
177203
  } : undefined,
176793
- experimentalPinKeyFiles: deps.config.dreamer?.pin_key_files?.enabled ? {
177204
+ experimentalPinKeyFiles: dreaming.pin_key_files?.enabled ? {
176794
177205
  enabled: true,
176795
- token_budget: deps.config.dreamer.pin_key_files.token_budget,
176796
- min_reads: deps.config.dreamer.pin_key_files.min_reads
177206
+ token_budget: dreaming.pin_key_files.token_budget,
177207
+ min_reads: dreaming.pin_key_files.min_reads
176797
177208
  } : undefined,
176798
- fallbackModels: resolveFallbackChain(DREAMER_AGENT, deps.config.dreamer?.fallback_models),
177209
+ fallbackModels: resolveFallbackChain(DREAMER_AGENT, dreaming.fallback_models),
176799
177210
  projectIdentity: projectPath
176800
177211
  }).catch((error51) => {
176801
177212
  log("[dreamer] scheduled queue processing failed:", error51);
@@ -176824,7 +177235,7 @@ function createMagicContextHook(deps) {
176824
177235
  systemPromptRefreshSessions.add(sessionId);
176825
177236
  pendingMaterializationSessions.add(sessionId);
176826
177237
  },
176827
- executeRecomp: async (sessionId, options) => executeContextRecomp({
177238
+ executeRecomp: historianRunnable ? async (sessionId, options) => executeContextRecomp({
176828
177239
  client: deps.client,
176829
177240
  db,
176830
177241
  sessionId,
@@ -176848,34 +177259,34 @@ function createMagicContextHook(deps) {
176848
177259
  onDeferredMarkerPending: (sid) => {
176849
177260
  deferredHistoryRefreshSessions.add(sid);
176850
177261
  }
176851
- }, options),
177262
+ }, options) : undefined,
176852
177263
  sendNotification: async (sessionId, text, params) => {
176853
177264
  await sendIgnoredMessage(deps.client, sessionId, text, {
176854
177265
  ...getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
176855
177266
  ...params
176856
177267
  });
176857
177268
  },
176858
- sidekick: deps.config.sidekick?.enabled ? {
176859
- config: deps.config.sidekick,
177269
+ sidekick: sidekickConfig ? {
177270
+ config: sidekickConfig,
176860
177271
  projectPath,
176861
177272
  sessionDirectory: deps.directory,
176862
177273
  client: deps.client
176863
177274
  } : undefined,
176864
- dreamer: deps.config.dreamer ? {
176865
- config: deps.config.dreamer,
177275
+ dreamer: dreamerConfig ? {
177276
+ config: dreamerConfig,
176866
177277
  projectPath,
176867
177278
  client: deps.client,
176868
177279
  directory: deps.directory,
176869
- experimentalUserMemories: deps.config.dreamer?.user_memories?.enabled ? {
177280
+ experimentalUserMemories: dreamerConfig.user_memories?.enabled ? {
176870
177281
  enabled: true,
176871
- promotionThreshold: deps.config.dreamer.user_memories.promotion_threshold
177282
+ promotionThreshold: dreamerConfig.user_memories.promotion_threshold
176872
177283
  } : undefined,
176873
- experimentalPinKeyFiles: deps.config.dreamer?.pin_key_files?.enabled ? {
177284
+ experimentalPinKeyFiles: dreamerConfig.pin_key_files?.enabled ? {
176874
177285
  enabled: true,
176875
- token_budget: deps.config.dreamer.pin_key_files.token_budget,
176876
- min_reads: deps.config.dreamer.pin_key_files.min_reads
177286
+ token_budget: dreamerConfig.pin_key_files.token_budget,
177287
+ min_reads: dreamerConfig.pin_key_files.min_reads
176877
177288
  } : undefined,
176878
- fallbackModels: resolveFallbackChain(DREAMER_AGENT, deps.config.dreamer.fallback_models)
177289
+ fallbackModels: resolveFallbackChain(DREAMER_AGENT, dreamerConfig.fallback_models)
176879
177290
  } : undefined
176880
177291
  });
176881
177292
  const systemPromptHash = createSystemPromptHashHandler({
@@ -176883,7 +177294,7 @@ function createMagicContextHook(deps) {
176883
177294
  protectedTags: deps.config.protected_tags,
176884
177295
  ctxReduceEnabled,
176885
177296
  dropToolStructure: deps.config.drop_tool_structure ?? true,
176886
- dreamerEnabled: deps.config.dreamer?.enabled === true,
177297
+ dreamerEnabled: dreamerRunnable,
176887
177298
  injectDocs: deps.config.dreamer?.inject_docs !== false,
176888
177299
  directory: deps.directory,
176889
177300
  historyRefreshSessions,
@@ -177221,6 +177632,7 @@ function calibrateBuckets(input) {
177221
177632
  }
177222
177633
 
177223
177634
  // src/plugin/rpc-handlers.ts
177635
+ init_announcement();
177224
177636
  init_logger();
177225
177637
  init_rpc_notifications();
177226
177638
  function getDb() {
@@ -177643,6 +178055,23 @@ function registerRpcHandlers(rpcServer, args) {
177643
178055
  const notifications = drainNotifications(Number.isFinite(lastReceivedId) ? lastReceivedId : 0);
177644
178056
  return { messages: notifications };
177645
178057
  });
178058
+ rpcServer.handle("get-announcement", async () => {
178059
+ if (!shouldShowAnnouncement()) {
178060
+ return { show: false };
178061
+ }
178062
+ return {
178063
+ show: true,
178064
+ version: ANNOUNCEMENT_VERSION,
178065
+ features: [...ANNOUNCEMENT_FEATURES],
178066
+ footer: ANNOUNCEMENT_FOOTER
178067
+ };
178068
+ });
178069
+ rpcServer.handle("mark-announced", async () => {
178070
+ if (ANNOUNCEMENT_VERSION) {
178071
+ markAnnouncementSeen(ANNOUNCEMENT_VERSION);
178072
+ }
178073
+ return { ok: true };
178074
+ });
177646
178075
  }
177647
178076
 
177648
178077
  // src/plugin/tool-registry.ts
@@ -178586,7 +179015,7 @@ function createToolRegistry(args) {
178586
179015
  ...createCtxExpandTools(),
178587
179016
  ...createCtxNoteTools({
178588
179017
  db,
178589
- dreamerEnabled: pluginConfig.dreamer?.enabled === true,
179018
+ dreamerEnabled: isDreamerRunnable(pluginConfig),
178590
179019
  resolveProjectPath: resolveProjectPath2
178591
179020
  }),
178592
179021
  ...createCtxSearchTools({
@@ -178617,28 +179046,28 @@ init_models_dev_cache();
178617
179046
  // src/shared/rpc-server.ts
178618
179047
  init_logger();
178619
179048
  import {
178620
- mkdirSync as mkdirSync8,
179049
+ mkdirSync as mkdirSync9,
178621
179050
  readdirSync,
178622
- readFileSync as readFileSync14,
179051
+ readFileSync as readFileSync15,
178623
179052
  renameSync as renameSync2,
178624
179053
  unlinkSync as unlinkSync3,
178625
- writeFileSync as writeFileSync7
179054
+ writeFileSync as writeFileSync8
178626
179055
  } from "node:fs";
178627
179056
  import { createServer } from "node:http";
178628
179057
  import { dirname as dirname8 } from "node:path";
178629
179058
 
178630
179059
  // src/shared/rpc-utils.ts
178631
179060
  import { createHash as createHash10 } from "node:crypto";
178632
- import { join as join26 } from "node:path";
179061
+ import { join as join27 } from "node:path";
178633
179062
  function projectHash(directory) {
178634
179063
  const normalized = directory.replace(/\/+$/, "");
178635
179064
  return createHash10("sha256").update(normalized).digest("hex").slice(0, 16);
178636
179065
  }
178637
179066
  function rpcPortDir(storageDir, directory) {
178638
- return join26(storageDir, "rpc", projectHash(directory));
179067
+ return join27(storageDir, "rpc", projectHash(directory));
178639
179068
  }
178640
179069
  function rpcPortFilePath(storageDir, directory, pid = process.pid) {
178641
- return join26(rpcPortDir(storageDir, directory), `port-${pid}.json`);
179070
+ return join27(rpcPortDir(storageDir, directory), `port-${pid}.json`);
178642
179071
  }
178643
179072
  function isPidAlive(pid) {
178644
179073
  if (!Number.isInteger(pid) || pid <= 0)
@@ -178713,9 +179142,9 @@ class MagicContextRpcServer {
178713
179142
  try {
178714
179143
  this.warnIfOtherLiveInstance();
178715
179144
  const dir = dirname8(this.portFilePath);
178716
- mkdirSync8(dir, { recursive: true });
179145
+ mkdirSync9(dir, { recursive: true });
178717
179146
  const tmpPath = `${this.portFilePath}.tmp`;
178718
- writeFileSync7(tmpPath, JSON.stringify({
179147
+ writeFileSync8(tmpPath, JSON.stringify({
178719
179148
  port: this.port,
178720
179149
  pid: process.pid,
178721
179150
  started_at: this.startedAt
@@ -178735,7 +179164,7 @@ class MagicContextRpcServer {
178735
179164
  for (const entry of readdirSync(this.portDir)) {
178736
179165
  if (!entry.startsWith("port-") || !entry.endsWith(".json"))
178737
179166
  continue;
178738
- const record2 = parseRpcPortFile(readFileSync14(`${this.portDir}/${entry}`, "utf-8"));
179167
+ const record2 = parseRpcPortFile(readFileSync15(`${this.portDir}/${entry}`, "utf-8"));
178739
179168
  if (!record2 || record2.pid === process.pid || !isPidAlive(record2.pid))
178740
179169
  continue;
178741
179170
  log(`[rpc] another Magic Context RPC server is active for this project (pid ${record2.pid}, port ${record2.port}); starting separate instance on a new port`);
@@ -178860,18 +179289,19 @@ var plugin = async (ctx) => {
178860
179289
  });
178861
179290
  const storageDir = getMagicContextStorageDir();
178862
179291
  if (pluginConfig.enabled) {
179292
+ const dreamerRunnable = isDreamerRunnable(pluginConfig);
178863
179293
  const timerRegistration = {
178864
179294
  directory: ctx.directory,
178865
179295
  projectIdentity: resolveProjectIdentity(ctx.directory),
178866
179296
  client: ctx.client,
178867
- dreamerConfig: pluginConfig.dreamer,
179297
+ dreamerConfig: dreamerRunnable ? pluginConfig.dreamer : undefined,
178868
179298
  embeddingConfig: pluginConfig.embedding,
178869
179299
  memoryEnabled: pluginConfig.memory?.enabled === true,
178870
- experimentalUserMemories: pluginConfig.dreamer?.user_memories?.enabled ? {
179300
+ experimentalUserMemories: dreamerRunnable && pluginConfig.dreamer?.user_memories?.enabled ? {
178871
179301
  enabled: true,
178872
179302
  promotionThreshold: pluginConfig.dreamer.user_memories.promotion_threshold
178873
179303
  } : undefined,
178874
- experimentalPinKeyFiles: pluginConfig.dreamer?.pin_key_files?.enabled ? {
179304
+ experimentalPinKeyFiles: dreamerRunnable && pluginConfig.dreamer?.pin_key_files?.enabled ? {
178875
179305
  enabled: true,
178876
179306
  token_budget: pluginConfig.dreamer.pin_key_files.token_budget,
178877
179307
  min_reads: pluginConfig.dreamer.pin_key_files.min_reads
@@ -178915,6 +179345,22 @@ var plugin = async (ctx) => {
178915
179345
  }
178916
179346
  } catch {}
178917
179347
  }
179348
+ if (pluginConfig.enabled && !conflictResult?.hasConflict) {
179349
+ try {
179350
+ const {
179351
+ shouldShowAnnouncement: shouldShowAnnouncement2,
179352
+ ANNOUNCEMENT_VERSION: ANNOUNCEMENT_VERSION2,
179353
+ ANNOUNCEMENT_FEATURES: ANNOUNCEMENT_FEATURES2,
179354
+ ANNOUNCEMENT_FOOTER: ANNOUNCEMENT_FOOTER2,
179355
+ markAnnouncementSeen: markAnnouncementSeen2
179356
+ } = await Promise.resolve().then(() => (init_announcement(), exports_announcement));
179357
+ if (shouldShowAnnouncement2()) {
179358
+ setTimeout(() => {
179359
+ Promise.resolve().then(() => (init_conflict_warning_hook(), exports_conflict_warning_hook)).then(({ sendStartupAnnouncement: sendStartupAnnouncement2 }) => sendStartupAnnouncement2(ctx.client, ctx.directory, ANNOUNCEMENT_VERSION2, ANNOUNCEMENT_FEATURES2, ANNOUNCEMENT_FOOTER2, markAnnouncementSeen2)).catch(() => {});
179360
+ }, 8000);
179361
+ }
179362
+ } catch {}
179363
+ }
178918
179364
  let lastChatContext = null;
178919
179365
  return {
178920
179366
  tool: tools5,
@@ -178984,7 +179430,6 @@ var plugin = async (ctx) => {
178984
179430
  config2.command = commandConfig;
178985
179431
  const dreamerAgentOverrides = pluginConfig.dreamer ? (() => {
178986
179432
  const {
178987
- enabled: _enabled,
178988
179433
  schedule: _schedule,
178989
179434
  max_runtime_minutes: _max,
178990
179435
  tasks: _tasks,
@@ -178995,7 +179440,6 @@ var plugin = async (ctx) => {
178995
179440
  })() : undefined;
178996
179441
  const sidekickAgentOverrides = pluginConfig.sidekick ? (() => {
178997
179442
  const {
178998
- enabled: _enabled,
178999
179443
  timeout_ms: _timeoutMs,
179000
179444
  system_prompt: _systemPrompt,
179001
179445
  ...agentOverrides
@@ -179009,7 +179453,7 @@ var plugin = async (ctx) => {
179009
179453
  config2.agent = {
179010
179454
  ...config2.agent ?? {},
179011
179455
  [DREAMER_AGENT]: buildHiddenAgentConfig(DREAMER_AGENT, DREAMER_SYSTEM_PROMPT, DREAMER_ALLOWED_TOOLS, dreamerAgentOverrides),
179012
- [HISTORIAN_AGENT]: buildHiddenAgentConfig(HISTORIAN_AGENT, pluginConfig.dreamer?.user_memories?.enabled ? COMPARTMENT_AGENT_SYSTEM_PROMPT + USER_OBSERVATIONS_APPENDIX : COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_ALLOWED_TOOLS, historianAgentOverrides),
179456
+ [HISTORIAN_AGENT]: buildHiddenAgentConfig(HISTORIAN_AGENT, isDreamerRunnable(pluginConfig) && pluginConfig.dreamer?.user_memories?.enabled ? COMPARTMENT_AGENT_SYSTEM_PROMPT + USER_OBSERVATIONS_APPENDIX : COMPARTMENT_AGENT_SYSTEM_PROMPT, HISTORIAN_ALLOWED_TOOLS, historianAgentOverrides),
179013
179457
  [HISTORIAN_EDITOR_AGENT]: buildHiddenAgentConfig(HISTORIAN_EDITOR_AGENT, HISTORIAN_EDITOR_SYSTEM_PROMPT, HISTORIAN_ALLOWED_TOOLS, historianAgentOverrides),
179014
179458
  [SIDEKICK_AGENT]: buildHiddenAgentConfig(SIDEKICK_AGENT, SIDEKICK_SYSTEM_PROMPT, SIDEKICK_ALLOWED_TOOLS, sidekickAgentOverrides)
179015
179459
  };