@cortexkit/pi-magic-context 0.34.1 → 0.34.2

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.
@@ -8667,6 +8667,7 @@ import {
8667
8667
  mkdtempSync,
8668
8668
  readdirSync,
8669
8669
  readFileSync as readFileSync3,
8670
+ statSync as statSync3,
8670
8671
  unlinkSync as unlinkSync2
8671
8672
  } from "node:fs";
8672
8673
  import { basename as basename2, dirname as dirname2, join as join3 } from "node:path";
@@ -11641,6 +11642,15 @@ var MIGRATIONS = [
11641
11642
  ensureColumn(db, "session_meta", "detected_context_limit_provenance", "TEXT NOT NULL DEFAULT 'unknown'");
11642
11643
  }
11643
11644
  }
11645
+ },
11646
+ {
11647
+ version: 75,
11648
+ description: "persist mural cue validation rejection latches",
11649
+ up(db) {
11650
+ if (!tableExists2(db, "memories"))
11651
+ return;
11652
+ ensureColumn(db, "memories", "mural_cue_rejection_count", "INTEGER NOT NULL DEFAULT 0");
11653
+ }
11644
11654
  }
11645
11655
  ];
11646
11656
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -144676,7 +144686,7 @@ function getSchemaFenceRejection() {
144676
144686
  function getMigrationOnOpenRefusal() {
144677
144687
  return lastMigrationOnOpenRefusal;
144678
144688
  }
144679
- var LATEST_SUPPORTED_VERSION = 74;
144689
+ var LATEST_SUPPORTED_VERSION = 75;
144680
144690
  var PERMISSIONS_ENFORCEABLE = process.platform !== "win32";
144681
144691
  var defaultStoragePermissionFs = { chmodSync, mkdirSync: mkdirSync2 };
144682
144692
  var storagePermissionFs = defaultStoragePermissionFs;
@@ -144798,24 +144808,65 @@ function enforceSchemaFence(db, dbPath, latestSupportedVersion) {
144798
144808
  log(`[magic-context] storage fatal: refusing to open ${dbPath}; upstream migration lane v${persistedVersion} is newer than this binary supports (max v${latestSupportedVersion}). A pinned or stale plugin is likely sharing this database with a newer instance; update or unpin Magic Context with 'npx @cortexkit/magic-context@latest doctor --force', then restart.`);
144799
144809
  return false;
144800
144810
  }
144801
- function unreadableDiscovery(path2) {
144811
+ function unreadableDiscovery(path2, arm) {
144802
144812
  return {
144803
144813
  state: "unreadable",
144804
144814
  serverPids: [],
144805
144815
  staleFiles: [],
144806
- unreadableFile: path2
144816
+ unreadableFile: path2,
144817
+ unreadableArm: arm
144807
144818
  };
144808
144819
  }
144820
+ var RPC_DISCOVERY_PARSE_GRACE_MS = 10 * 60 * 1000;
144821
+ var defaultRpcDiscoveryFs = {
144822
+ readdirSync: (path2, options) => options?.withFileTypes ? readdirSync(path2, { withFileTypes: true }) : readdirSync(path2),
144823
+ readFileSync: (path2, encoding) => String(readFileSync3(path2, encoding)),
144824
+ statSync: (path2) => ({ mtimeMs: statSync3(path2).mtimeMs }),
144825
+ unlinkSync: (path2) => unlinkSync2(path2)
144826
+ };
144827
+ var rpcDiscoveryFs = defaultRpcDiscoveryFs;
144828
+ function invalidDiscoveryReason(raw) {
144829
+ const trimmed = raw.trim();
144830
+ if (trimmed.startsWith("{")) {
144831
+ try {
144832
+ const parsed = JSON.parse(trimmed);
144833
+ if ("pid" in parsed) {
144834
+ const pid = Number(parsed.pid);
144835
+ if (!Number.isInteger(pid) || pid <= 0)
144836
+ return "invalid-pid";
144837
+ }
144838
+ } catch {}
144839
+ }
144840
+ return "parse-invalid";
144841
+ }
144842
+ function classifyJunkDiscovery(portFile, raw, staleFiles) {
144843
+ let mtimeMs;
144844
+ try {
144845
+ mtimeMs = rpcDiscoveryFs.statSync(portFile).mtimeMs;
144846
+ } catch (error) {
144847
+ if (error.code === "ENOENT")
144848
+ return null;
144849
+ return unreadableDiscovery(portFile, "io");
144850
+ }
144851
+ const ageMs = Date.now() - mtimeMs;
144852
+ if (!Number.isFinite(ageMs) || ageMs < RPC_DISCOVERY_PARSE_GRACE_MS) {
144853
+ return unreadableDiscovery(portFile, "parse");
144854
+ }
144855
+ staleFiles.push(portFile);
144856
+ const reason = invalidDiscoveryReason(raw);
144857
+ log(`[magic-context] removing stale RPC discovery file ${portFile}: ${reason} record older than 10 minutes`);
144858
+ return null;
144859
+ }
144809
144860
  function inspectRpcServerDiscovery(storageDir) {
144810
144861
  const rpcRoot = join3(storageDir, "rpc");
144811
144862
  let projectEntries;
144812
144863
  try {
144813
- projectEntries = readdirSync(rpcRoot, { withFileTypes: true });
144864
+ projectEntries = rpcDiscoveryFs.readdirSync(rpcRoot, { withFileTypes: true });
144814
144865
  } catch (error) {
144815
144866
  if (error.code === "ENOENT") {
144816
144867
  return { state: "absent", serverPids: [], staleFiles: [] };
144817
144868
  }
144818
- return unreadableDiscovery(rpcRoot);
144869
+ return unreadableDiscovery(rpcRoot, "io");
144819
144870
  }
144820
144871
  const portFiles = [];
144821
144872
  for (const projectEntry of projectEntries) {
@@ -144824,9 +144875,11 @@ function inspectRpcServerDiscovery(storageDir) {
144824
144875
  const projectDir = join3(rpcRoot, projectEntry.name);
144825
144876
  let entries;
144826
144877
  try {
144827
- entries = readdirSync(projectDir);
144828
- } catch {
144829
- return unreadableDiscovery(projectDir);
144878
+ entries = rpcDiscoveryFs.readdirSync(projectDir);
144879
+ } catch (error) {
144880
+ if (error.code === "ENOENT")
144881
+ continue;
144882
+ return unreadableDiscovery(projectDir, "io");
144830
144883
  }
144831
144884
  for (const entry of entries) {
144832
144885
  if (entry === "port" || entry.startsWith("port-") && entry.endsWith(".json")) {
@@ -144842,15 +144895,21 @@ function inspectRpcServerDiscovery(storageDir) {
144842
144895
  for (const portFile of portFiles) {
144843
144896
  let raw;
144844
144897
  try {
144845
- raw = readFileSync3(portFile, "utf8");
144846
- } catch {
144847
- return unreadableDiscovery(portFile);
144898
+ raw = rpcDiscoveryFs.readFileSync(portFile, "utf8");
144899
+ } catch (error) {
144900
+ if (error.code === "ENOENT")
144901
+ continue;
144902
+ return unreadableDiscovery(portFile, "io");
144848
144903
  }
144849
144904
  const filename = basename2(portFile);
144850
144905
  const pidFromName = /^port-(\d+)/.exec(filename)?.[1];
144851
- const record = parseRpcPortFile(raw, pidFromName ? Number(pidFromName) : 0);
144906
+ const fallbackPid = pidFromName ? Number(pidFromName) : 0;
144907
+ const record = parseRpcPortFile(raw, fallbackPid);
144852
144908
  if (!record || !Number.isInteger(record.pid) || record.pid <= 0) {
144853
- return unreadableDiscovery(portFile);
144909
+ const junk = classifyJunkDiscovery(portFile, raw, staleFiles);
144910
+ if (junk)
144911
+ return junk;
144912
+ continue;
144854
144913
  }
144855
144914
  if (isPidAlive(record.pid) && isPidIdentityPlausible(record))
144856
144915
  pids.add(record.pid);
@@ -144859,9 +144918,9 @@ function inspectRpcServerDiscovery(storageDir) {
144859
144918
  }
144860
144919
  for (const staleFile of staleFiles) {
144861
144920
  try {
144862
- unlinkSync2(staleFile);
144921
+ rpcDiscoveryFs.unlinkSync(staleFile);
144863
144922
  } catch {
144864
- return unreadableDiscovery(staleFile);
144923
+ return unreadableDiscovery(staleFile, "io");
144865
144924
  }
144866
144925
  }
144867
144926
  const serverPids = [...pids].sort((a, b) => a - b);
@@ -144885,10 +144944,14 @@ function enforceMigrationOnOpenGuard(db, dbPath, dbDir, latestSupportedVersion)
144885
144944
  persistedVersion,
144886
144945
  supportedVersion: latestSupportedVersion,
144887
144946
  serverPids: discovery.serverPids,
144888
- ...discovery.unreadableFile ? { unreadableFile: discovery.unreadableFile } : {}
144947
+ ...discovery.unreadableFile ? { unreadableFile: discovery.unreadableFile } : {},
144948
+ ...discovery.unreadableArm ? { unreadableArm: discovery.unreadableArm } : {}
144889
144949
  };
144890
144950
  if (discovery.state === "unreadable") {
144891
- log(`[magic-context] storage fatal: refusing to migrate ${dbPath} from upstream migration v${persistedVersion} to v${latestSupportedVersion} because RPC discovery file ${discovery.unreadableFile ?? "<unknown>"} is unreadable or invalid, so the absence of a live OpenCode server cannot be proven. Restart OpenCode, remove or repair the named discovery file, then retry this process.`);
144951
+ const unreadableFile = discovery.unreadableFile ?? "<unknown>";
144952
+ const arm = discovery.unreadableArm ?? "io";
144953
+ const recovery = arm === "io" ? `If no OpenCode server is running, it is safe to delete ${unreadableFile} and retry.` : `Retry after the file is older than the ten-minute grace window, or stop OpenCode before deleting it.`;
144954
+ log(`[magic-context] storage fatal: refusing to migrate ${dbPath} from upstream migration v${persistedVersion} to v${latestSupportedVersion} because RPC discovery file ${unreadableFile} is uncertain (${arm} arm), so the absence of a live OpenCode server cannot be proven. ${recovery}`);
144892
144955
  } else {
144893
144956
  log(`[magic-context] storage fatal: refusing to migrate ${dbPath} from upstream migration v${persistedVersion} to v${latestSupportedVersion} while live OpenCode server PID(s) ${discovery.serverPids.join(", ")} may still use the old plugin build. Restart OpenCode, then retry this process.`);
144894
144957
  }
@@ -145182,6 +145245,7 @@ function initializeDatabase(db) {
145182
145245
  mural_cue TEXT,
145183
145246
  mural_cue_hash TEXT,
145184
145247
  mural_cue_at INTEGER,
145248
+ mural_cue_rejection_count INTEGER NOT NULL DEFAULT 0,
145185
145249
  UNIQUE(project_path, category, normalized_hash)
145186
145250
  );
145187
145251
 
@@ -146513,6 +146577,7 @@ function clearCachedM0M1(db, sessionId) {
146513
146577
 
146514
146578
  // ../plugin/src/features/magic-context/storage-meta-persisted.ts
146515
146579
  var emergencyRecoveryArmedSessions = new Set;
146580
+ var emergencyRecoveryArmedAtBySession = new Map;
146516
146581
  var providerOverflowReconfirmedSessions = new Set;
146517
146582
  var CAS_RETRY_LIMIT = 5;
146518
146583
  var AUTO_SEARCH_NO_HINT_REASONS = new Set([
@@ -147278,6 +147343,7 @@ function getOverflowState(db, sessionId, modelKey) {
147278
147343
  }
147279
147344
  function recordOverflowDetected(db, sessionId, reportedLimit, modelKey, origin = "provider_overflow", provenance = "unknown") {
147280
147345
  emergencyRecoveryArmedSessions.add(sessionId);
147346
+ emergencyRecoveryArmedAtBySession.set(sessionId, Date.now());
147281
147347
  db.transaction(() => {
147282
147348
  ensureSessionMetaRow(db, sessionId);
147283
147349
  const prior = db.prepare("SELECT needs_emergency_recovery FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -147301,6 +147367,7 @@ function clearEmergencyRecovery(db, sessionId) {
147301
147367
  }
147302
147368
  })();
147303
147369
  emergencyRecoveryArmedSessions.delete(sessionId);
147370
+ emergencyRecoveryArmedAtBySession.delete(sessionId);
147304
147371
  providerOverflowReconfirmedSessions.delete(sessionId);
147305
147372
  }
147306
147373
  function clearDetectedContextLimit(db, sessionId) {
@@ -149105,7 +149172,7 @@ function escapeXmlContent(s) {
149105
149172
  }
149106
149173
  // ../plugin/src/features/magic-context/project-docs-hash.ts
149107
149174
  import { createHash as createHash5 } from "node:crypto";
149108
- import { lstatSync, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
149175
+ import { lstatSync, readFileSync as readFileSync4, statSync as statSync4 } from "node:fs";
149109
149176
  import path2 from "node:path";
149110
149177
  var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
149111
149178
  var PROJECT_DOCS_DELIMITER = `
@@ -149136,7 +149203,7 @@ function fingerprintFile(filePath) {
149136
149203
  }
149137
149204
  function readDirectoryMtimeMs(projectDirectory) {
149138
149205
  try {
149139
- return statSync3(projectDirectory).mtimeMs;
149206
+ return statSync4(projectDirectory).mtimeMs;
149140
149207
  } catch {
149141
149208
  return 0;
149142
149209
  }
@@ -167494,7 +167561,7 @@ function loadPiConfigDetailed(opts = {}) {
167494
167561
  }
167495
167562
 
167496
167563
  // src/embedding-bootstrap.ts
167497
- import { statSync as statSync4 } from "node:fs";
167564
+ import { statSync as statSync5 } from "node:fs";
167498
167565
 
167499
167566
  // ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
167500
167567
  import { createHash as createHash8 } from "node:crypto";
@@ -173545,7 +173612,7 @@ function configCandidatePaths(directory, loadedPaths) {
173545
173612
  function configFingerprint(paths) {
173546
173613
  return paths.map((path3) => {
173547
173614
  try {
173548
- const stat2 = statSync4(path3);
173615
+ const stat2 = statSync5(path3);
173549
173616
  return `${path3}:${stat2.size}:${stat2.mtimeMs}`;
173550
173617
  } catch {
173551
173618
  return `${path3}:missing`;
@@ -178625,6 +178692,7 @@ function computeCueContentHash(content) {
178625
178692
  return createHash13("sha256").update(content).digest("hex");
178626
178693
  }
178627
178694
  var muralCueColumnCache = new WeakMap;
178695
+ var muralCueRejectionColumnCache = new WeakMap;
178628
178696
  function hasMuralCueColumns(db) {
178629
178697
  const cached2 = muralCueColumnCache.get(db);
178630
178698
  if (cached2 !== undefined)
@@ -178634,6 +178702,15 @@ function hasMuralCueColumns(db) {
178634
178702
  muralCueColumnCache.set(db, present);
178635
178703
  return present;
178636
178704
  }
178705
+ function hasMuralCueRejectionCountColumn(db) {
178706
+ const cached2 = muralCueRejectionColumnCache.get(db);
178707
+ if (cached2 !== undefined)
178708
+ return cached2;
178709
+ const columns = db.prepare("PRAGMA table_info(memories)").all();
178710
+ const present = columns.some((column) => column.name === "mural_cue_rejection_count");
178711
+ muralCueRejectionColumnCache.set(db, present);
178712
+ return present;
178713
+ }
178637
178714
  function getMuralCueState(db, memoryIds) {
178638
178715
  const out = new Map;
178639
178716
  if (!hasMuralCueColumns(db))
@@ -178642,9 +178719,14 @@ function getMuralCueState(db, memoryIds) {
178642
178719
  if (ids.length === 0)
178643
178720
  return out;
178644
178721
  const placeholders3 = ids.map(() => "?").join(", ");
178645
- const rows = db.prepare(`SELECT id, mural_cue, mural_cue_hash FROM memories WHERE id IN (${placeholders3})`).all(...ids);
178722
+ const rejectionCountColumn = hasMuralCueRejectionCountColumn(db) ? "COALESCE(mural_cue_rejection_count, 0) AS mural_cue_rejection_count" : "0 AS mural_cue_rejection_count";
178723
+ const rows = db.prepare(`SELECT id, mural_cue, mural_cue_hash, ${rejectionCountColumn} FROM memories WHERE id IN (${placeholders3})`).all(...ids);
178646
178724
  for (const row of rows) {
178647
- out.set(row.id, { cue: row.mural_cue ?? null, hash: row.mural_cue_hash ?? null });
178725
+ out.set(row.id, {
178726
+ cue: row.mural_cue ?? null,
178727
+ hash: row.mural_cue_hash ?? null,
178728
+ ...row.mural_cue_rejection_count > 0 ? { rejectionCount: row.mural_cue_rejection_count } : {}
178729
+ });
178648
178730
  }
178649
178731
  return out;
178650
178732
  }
@@ -178661,9 +178743,25 @@ function setMuralCue(db, projectPath, id, cue, contentHash) {
178661
178743
  if (!owned) {
178662
178744
  throw new Error(`Memory ${id} does not belong to project ${projectPath}`);
178663
178745
  }
178664
- db.prepare("UPDATE memories SET mural_cue = ?, mural_cue_hash = ?, mural_cue_at = ? WHERE id = ? AND project_path = ?").run(cue, contentHash, Date.now(), id, projectPath);
178746
+ const rejectionReset = hasMuralCueRejectionCountColumn(db) ? ", mural_cue_rejection_count = 0" : "";
178747
+ db.prepare(`UPDATE memories SET mural_cue = ?, mural_cue_hash = ?, mural_cue_at = ?${rejectionReset} WHERE id = ? AND project_path = ?`).run(cue, contentHash, Date.now(), id, projectPath);
178665
178748
  });
178666
178749
  }
178750
+ function recordMuralCueRejection(db, projectPath, id, contentHash) {
178751
+ if (!hasMuralCueColumns(db) || !hasMuralCueRejectionCountColumn(db))
178752
+ return 0;
178753
+ let count = 0;
178754
+ withPrivilegedWriter(db, () => {
178755
+ const owned = db.prepare("SELECT 1 FROM memories WHERE id = ? AND project_path = ?").get(id, projectPath);
178756
+ if (!owned) {
178757
+ throw new Error(`Memory ${id} does not belong to project ${projectPath}`);
178758
+ }
178759
+ const row = db.prepare("SELECT mural_cue_hash, mural_cue_rejection_count FROM memories WHERE id = ?").get(id);
178760
+ count = row?.mural_cue_hash === contentHash ? (row.mural_cue_rejection_count ?? 0) + 1 : 1;
178761
+ db.prepare("UPDATE memories SET mural_cue = NULL, mural_cue_hash = ?, mural_cue_at = ?, mural_cue_rejection_count = ? WHERE id = ? AND project_path = ?").run(contentHash, Date.now(), count, id, projectPath);
178762
+ });
178763
+ return count;
178764
+ }
178667
178765
 
178668
178766
  // ../plugin/src/features/magic-context/memory/visibility.ts
178669
178767
  var FOREIGN_VISIBLE_SQL = "status IN ('active','permanent') AND (expires_at IS NULL OR expires_at > :now_ms) AND shareable = 1 AND scope IN ('project','ecosystem','universe') AND category IN (SELECT value FROM json_each(:share_categories)) AND project_path IN (SELECT project_path FROM mc_workspace_members WHERE workspace_id = :workspace_id) AND project_path <> :reader_project";
@@ -179296,7 +179394,8 @@ function updateMemoryContent(db, id, content, normalizedHash) {
179296
179394
  db.prepare("UPDATE memories SET classified_at = NULL WHERE id = ?").run(id);
179297
179395
  }
179298
179396
  if (hasMuralCueColumns(db)) {
179299
- db.prepare("UPDATE memories SET mural_cue = NULL, mural_cue_hash = NULL, mural_cue_at = NULL WHERE id = ?").run(id);
179397
+ const rejectionReset = hasMuralCueRejectionCountColumn(db) ? ", mural_cue_rejection_count = 0" : "";
179398
+ db.prepare(`UPDATE memories SET mural_cue = NULL, mural_cue_hash = NULL, mural_cue_at = NULL${rejectionReset} WHERE id = ?`).run(id);
179300
179399
  }
179301
179400
  let stmt = deleteEmbeddingOnContentUpdateStatements.get(db);
179302
179401
  if (!stmt) {
@@ -179631,7 +179730,7 @@ function getMemoryVerifications(db, memoryIds) {
179631
179730
  }
179632
179731
  // ../plugin/src/features/magic-context/memory/verification-paths.ts
179633
179732
  import { execFile } from "node:child_process";
179634
- import { existsSync as existsSync8, realpathSync as realpathSync2, statSync as statSync5 } from "node:fs";
179733
+ import { existsSync as existsSync8, realpathSync as realpathSync2, statSync as statSync6 } from "node:fs";
179635
179734
  import path3 from "node:path";
179636
179735
  import { promisify } from "node:util";
179637
179736
  var execFileAsync = promisify(execFile);
@@ -179773,7 +179872,7 @@ async function normalizeVerificationFiles(args) {
179773
179872
  }
179774
179873
  if (existsSync8(candidate)) {
179775
179874
  try {
179776
- if (statSync5(candidate).isDirectory()) {
179875
+ if (statSync6(candidate).isDirectory()) {
179777
179876
  warnings.push(`Skipped verification path "${value}" because it is a directory.`);
179778
179877
  continue;
179779
179878
  }
@@ -184220,4 +184319,4 @@ function registerMagicContextTools(pi, opts) {
184220
184319
  }
184221
184320
  }
184222
184321
 
184223
- export { COMPACTION_ENABLED_PATH, isDreamerRunnable, isCompactionEnabled, migrateMagicContextConfigLocations, ProjectIdentityError, resolveProjectIdentityStrict, resolveProjectIdentity, resolveProjectIdentityForSession, beginBootQuietPeriod, scheduleAfterBootQuiet, Database, closeQuietly, isMidTurn, textMentionsRecentCommit, hasMeaningfulUserText, extractTexts, extractToolCallSummaries, estimateTokens, normalizeText, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isRecord, isEditTool, applyEditMarkerToInput, setRawMessageProvider, withRawMessageProvider, cleanUserText, withRawSessionMessageCache, readRawSessionMessages, primeTailRawMessageCache, getCachedAbsoluteMessageCount, primeInMemoryTailRawMessageCache, getRawSessionMessageCount, getRawSessionTagKeysThrough, getLegacyProtectedTailStartOrdinal, readSessionChunk, clearCompressionDepth, clearCompressionDepthRange, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes, recordSessionProjectIdentity, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, isCompartmentLeaseHeld, persistCachedM0, clearCachedM0M1, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, getCompartmentsByEndMessageId, appendCompartments, saveRecompStagingPass, getRecompStaging, clearRecompStaging, getRecompPartialRange, setRecompPartialRange, escapeXmlAttr, escapeXmlContent, getModuleNoteEvaluationBridge, getContextStoreUuid, parseCompartmentOutput, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, sourceNameForMemory, computeWorkspaceEpochFingerprint, bumpEpochsForWorkspaceMembers, readProjectDocsCanonical, copySessionStateForClone, getErrorMessage, describeError, setStoragePrivatePermissionEnforcement, stableStringify, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, applySqliteTuningPragmas, runSqliteOptimize, openDatabase, openDatabaseAsync, queueM0Mutation, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRender, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationId, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, loadProtectedTailMeta, markProtectedTailPolicyV3Seeded, recordProtectedTailPublicationFloor, recordProtectedTailNoEligibleHead, getWrapupInProgressState, isWrapupInProgress, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, reserveProtectedTailDrainTokens, clearEmergencyDrainLatch, recordHistorianDrainFailure, clearHistorianDrainFailure, rollbackProtectedTailDrainReservation, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getLastNudgeLevel, setLastNudgeLevel, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, setChannel2NudgeState, casChannel2NudgeState, getPersistedNoteNudge, setPersistedNoteNudgeTrigger, setPersistedNoteNudgeTriggerMessageId, getNoteNudgeAnchors, getAutoSearchHintDecisions, deliverNoteNudgeAtomic, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, getNoteLastReadAt, getHistorianFailureState, incrementHistorianFailure, clearHistorianFailureState, getOverflowState, recordOverflowDetected, clearEmergencyRecovery, clearDetectedContextLimit, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, getPendingPiCompactionMarkerState, setPendingPiCompactionMarkerState, clearPendingPiCompactionMarkerStateIf, getSessionsWithPendingPiMarker, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, setSessionWorkMetrics, getSessionWorkMetrics, getOrCreateSessionMeta, updateSessionMeta, advanceToolReclaimWatermark, retryPendingSessionCleanups, getNotes, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, insertPrimerCandidates, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, recordSubagentInvocation, getLatestHistorianInvocationId, updateTagByteSize, getActiveTagTokenAggregate, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, updateTagInputByteSize, updateTagTokenCount, getPersistedToolTagAccounting, getAllStatusTagTokenTotalsFlat, updateTagInputTokenCount, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, hasPiFallbackMessageTags, findAdoptableFallbackTags, hasPiFallbackToolOwnerTags, findPiFallbackToolOwnerTags, adoptPiFallbackToolOwnerTag, adoptPiFallbackMessageTag, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getTagsForPendingOperations, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, BoundedSessionMap, piModelRefToCanonical, resolveModelRefForPi, isSaneLimit, resolveLimit, getSdkContextLimit, normalizeTodoStateJson, buildSyntheticTodoPart, SYNTH_USER_ID_PREFIX, resolvePiStableId, isMidTurnPi, readPiSessionMessages, findLastModelKeyFromBranch, convertEntriesToRawMessages, withContentLanguageDirective, withMigrationLanguageDirective, buildPrimaryLanguageDirective, computeCueContentHash, hasMuralCueColumns, getMuralCueState, memoryNeedsCue, setMuralCue, invalidateMemory, computeNormalizedHash, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, insertMemory, getMemoryByHash, getMemoriesByProject, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getAllActiveMemoriesForMigration, getMemoryById, setMemoryClassification, archiveMemory, deleteMemory, getMemoryCount, getMemoryCountsByStatus, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, getOpenCodeDbPath2 as getOpenCodeDbPath, parseCron, nextOccurrence, nextDueAtMs, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, buildCanonicalChunkTextFromFts, buildCompartmentSummaryFallbackText, canonicalizeInMemoryChunkTextForEmbedding, chunkCanonicalText, chunkEmbeddingWindowsAreCurrent, replaceCompartmentChunkEmbeddings, cosineSimilarity, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, contentSha256, sweepStaleEmbeddingIdentitiesForProject, enqueueShadowEmbeddingItems, getProjectEmbeddingSnapshot, getProjectChunkEmbeddingModelId, getProjectEmbeddingMaxInputTokens, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, promoteSessionFactsDurable, embedPromotedFacts, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, indexCommitsForProject, embedUnembeddedCommits, loadPiConfig, ensureProjectRegisteredFromPiDirectory, resolveMuralWire, updateCompactionMarkerAfterPublication, COMPARTMENT_RENDER_EPOCH, encodeCachedM0UpgradeIdentity, decodeCachedM0UpgradeIdentity, DEFAULT_HISTORY_BUDGET_TOKENS, renderCompartmentAtTier, renderDecayedCompartments, extractM0Block, TEMPORAL_MARKER_PATTERN, temporalMarkerPrefix, clearInjectionCache, getVisibleMemoryIds, renderMemoryBlock, DEFAULT_MEMORY_BUDGET_TOKENS, DEFAULT_USER_PROFILE_BUDGET_TOKENS, trimMemoriesToBudgetV2, trimWorkspaceMemoriesToBudgetV2, trimUserMemoriesToBudget, renderMemoryBlockV2, stripMemoryMuralBlock, unifiedSearch, rememberTodowriteToolCallTodos, parseTodos, setTodoSnapshot, registerTodoOverlay, registerTodoStateLifecycle, registerMagicContextTools };
184322
+ export { COMPACTION_ENABLED_PATH, isDreamerRunnable, isCompactionEnabled, migrateMagicContextConfigLocations, ProjectIdentityError, resolveProjectIdentityStrict, resolveProjectIdentity, resolveProjectIdentityForSession, beginBootQuietPeriod, scheduleAfterBootQuiet, Database, closeQuietly, isMidTurn, textMentionsRecentCommit, hasMeaningfulUserText, extractTexts, extractToolCallSummaries, estimateTokens, normalizeText, stripPersistedAssistantText, byteSize, stripTagPrefix, peelLeadingMcTagNotation, prependTag, isRecord, isEditTool, applyEditMarkerToInput, setRawMessageProvider, withRawMessageProvider, cleanUserText, withRawSessionMessageCache, readRawSessionMessages, primeTailRawMessageCache, getCachedAbsoluteMessageCount, primeInMemoryTailRawMessageCache, getRawSessionMessageCount, getRawSessionTagKeysThrough, getLegacyProtectedTailStartOrdinal, readSessionChunk, clearCompressionDepth, clearCompressionDepthRange, getMessageIndexSourceIdentity, isMessageIndexSourceCurrent, getLastIndexedOrdinal, getMessageIndexReconciliationStartOrdinal, isMessageIndexReconciledThrough, indexSingleMessage, indexMessagesAfterOrdinal, sweepOrphanedOpenCodeMessageIndexes, recordSessionProjectIdentity, COMPARTMENT_LEASE_RENEWAL_MS, acquireCompartmentLease, renewCompartmentLease, releaseCompartmentLease, isCompartmentLeaseHeld, persistCachedM0, clearCachedM0M1, getCompartments, getLastCompartmentEndMessage, getLastCompartmentEndMessageId, getCompartmentsByEndMessageId, appendCompartments, saveRecompStagingPass, getRecompStaging, clearRecompStaging, getRecompPartialRange, setRecompPartialRange, escapeXmlAttr, escapeXmlContent, getModuleNoteEvaluationBridge, getContextStoreUuid, parseCompartmentOutput, resolveWorkspaceShareCategories, resolveWorkspaceIdentitySet, expandWorkspaceIdentitySetWithAliases, sourceNameForMemory, computeWorkspaceEpochFingerprint, bumpEpochsForWorkspaceMembers, readProjectDocsCanonical, copySessionStateForClone, getErrorMessage, describeError, setStoragePrivatePermissionEnforcement, stableStringify, getSchemaFenceRejection, getMigrationOnOpenRefusal, LATEST_SUPPORTED_VERSION, getDatabasePath, getPersistedSchemaVersion, setSqlitePragmaConfig, applySqliteTuningPragmas, runSqliteOptimize, openDatabase, openDatabaseAsync, queueM0Mutation, getMaxM0MutationId, queueMemoryMutation, getMemoryMutationsForRender, getMemoryMutationsForRenderByProjects, getMaxMemoryMutationId, getMaxMemoryMutationIdForProjects, MAX_EXECUTE_THRESHOLD, escalationBands, loadProtectedTailMeta, markProtectedTailPolicyV3Seeded, recordProtectedTailPublicationFloor, recordProtectedTailNoEligibleHead, getWrapupInProgressState, isWrapupInProgress, acquireWrapupInProgress, updateWrapupInProgress, releaseWrapupInProgress, resolveCompactionModeRecord, getCompactionModeRecord, setCompactionModeRecord, reserveProtectedTailDrainTokens, clearEmergencyDrainLatch, recordHistorianDrainFailure, clearHistorianDrainFailure, rollbackProtectedTailDrainReservation, clearPersistedReasoningWatermark, getEmergencyInputSample, setEmergencyDropSample, clearEmergencyDropSample, getLastNudgeUndropped, setLastNudgeUndropped, getLastNudgeLevel, setLastNudgeLevel, resetLastNudgeCycle, resetLastNudgeCycleIfTailShrank, getChannel2NudgeState, setChannel2NudgeState, casChannel2NudgeState, getPersistedNoteNudge, setPersistedNoteNudgeTrigger, setPersistedNoteNudgeTriggerMessageId, getNoteNudgeAnchors, getAutoSearchHintDecisions, deliverNoteNudgeAtomic, appendAutoSearchHintDecision, pruneNoteNudgeAnchors, pruneAutoSearchHintDecisions, getPersistedTodoSyntheticAnchor, setPersistedTodoSyntheticAnchor, clearPersistedTodoSyntheticAnchor, getNoteLastReadAt, getHistorianFailureState, incrementHistorianFailure, clearHistorianFailureState, getOverflowState, recordOverflowDetected, clearEmergencyRecovery, clearDetectedContextLimit, getStrippedPlaceholderIds, applyStrippedPlaceholderDelta, getProcessedImageStrippedIds, addProcessedImageStrippedIds, getPendingCompactionMarkerState, clearPendingCompactionMarkerStateIf, getPendingPiCompactionMarkerState, setPendingPiCompactionMarkerState, clearPendingPiCompactionMarkerStateIf, getSessionsWithPendingPiMarker, peekDeferredExecutePending, setDeferredExecutePendingIfAbsent, clearDeferredExecutePendingIfMatches, setSessionWorkMetrics, getSessionWorkMetrics, getOrCreateSessionMeta, updateSessionMeta, advanceToolReclaimWatermark, retryPendingSessionCleanups, getNotes, getSessionNotes, getPendingSmartNotes, getReadySmartNotes, markNoteReady, markNoteChecked, queuePendingOp, getPendingOps, clearPendingOps, removePendingOp, PRIMER_CANDIDATE_TTL_MS, PRIMER_CANDIDATE_MAX_AGE_MS, primerOccurrenceKey, primerOccurrenceUtcDay, insertPrimerCandidates, updatePrimerCandidateEmbedding, getPrimerCandidatesByIds, getPrimerCandidatesForPromotion, countPrimerCandidatesForProject, getActivePrimers, createPrimer, updatePrimerSupport, updatePrimerAnswer, GLOBAL_USER_PROFILE_PROJECT_PATH, getProjectState, bumpProjectUserProfileVersion, saveSourceContent, replaceSourceContent, getSourceContents, recordSubagentInvocation, getLatestHistorianInvocationId, updateTagByteSize, getActiveTagTokenAggregate, AGE_RECLAIM_MIN_TOKENS, getOldestActiveUnprotectedToolTags, getActiveToolTagsForAgeReclaim, getTriggerTagTokenUpperBound, updateTagInputByteSize, updateTagTokenCount, getPersistedToolTagAccounting, getAllStatusTagTokenTotalsFlat, updateTagInputTokenCount, tagTokenCountIsNull, backfillTagTokenCounts, insertTag, updateTagStatus, updateTagDropMode, updateCavemanDepth, hasPiFallbackMessageTags, findAdoptableFallbackTags, hasPiFallbackToolOwnerTags, findPiFallbackToolOwnerTags, adoptPiFallbackToolOwnerTag, adoptPiFallbackMessageTag, getMaxTagNumberBySession, getTagNumberByMessageId, deriveTagLoadFloor, getTagsBySession, getActiveTagsBySession, getTagsForPendingOperations, getTagsByNumbers, getMaxDroppedTagNumber, getToolTagNumberByOwner, getNullOwnerToolTag, adoptNullOwnerToolTag, BoundedSessionMap, piModelRefToCanonical, resolveModelRefForPi, isSaneLimit, resolveLimit, getSdkContextLimit, normalizeTodoStateJson, buildSyntheticTodoPart, SYNTH_USER_ID_PREFIX, resolvePiStableId, isMidTurnPi, readPiSessionMessages, findLastModelKeyFromBranch, convertEntriesToRawMessages, withContentLanguageDirective, withMigrationLanguageDirective, buildPrimaryLanguageDirective, computeCueContentHash, hasMuralCueColumns, getMuralCueState, memoryNeedsCue, setMuralCue, recordMuralCueRejection, invalidateMemory, computeNormalizedHash, hasMemoryShareableColumn, hasMemoryClassifiedAtColumn, getUnclassifiedMemoryIds, insertMemory, getMemoryByHash, getMemoriesByProject, getMemoriesByProjects, getMaxMemoryIdForProjects, readNewMemoriesForM1Union, getAllActiveMemoriesForMigration, getMemoryById, setMemoryClassification, archiveMemory, deleteMemory, getMemoryCount, getMemoryCountsByStatus, USER_MEMORY_CANDIDATE_TTL_MS, insertUserMemoryCandidates, getUserMemoryCandidates, deleteUserMemoryCandidates, pruneExpiredUserMemoryCandidates, insertUserMemory, getActiveUserMemories, updateUserMemoryContent, dismissUserMemory, getOpenCodeDbPath2 as getOpenCodeDbPath, parseCron, nextOccurrence, nextDueAtMs, DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE, DEFAULT_HISTORIAN_TIMEOUT_MS, buildCanonicalChunkTextFromFts, buildCompartmentSummaryFallbackText, canonicalizeInMemoryChunkTextForEmbedding, chunkCanonicalText, chunkEmbeddingWindowsAreCurrent, replaceCompartmentChunkEmbeddings, cosineSimilarity, GIT_SWEEP_LEASE_RENEWAL_MS, acquireGitSweepLease, renewGitSweepLease, markGitSweepSuccessAndRelease, parkGitSweepNonIndexable, releaseGitSweepLease, contentSha256, sweepStaleEmbeddingIdentitiesForProject, enqueueShadowEmbeddingItems, getProjectEmbeddingSnapshot, getProjectChunkEmbeddingModelId, getProjectEmbeddingMaxInputTokens, embedTextForProject, embedBatchForProject, embedItemsForProject, embedUnembeddedMemoriesForProject, drainCommitBacklogForProject, embedSessionCompartmentChunks, getEmbeddingCoverageStatus, promoteSessionFactsDurable, embedPromotedFacts, recordMemoryMapping, recordMemoryVerifications, getUnmappedMemoryIds, clearMemoryVerifications, getMemoryVerifications, resolveGitTopLevel, readGitHead, readGitChangedFilesSince, readGitFileChangeTimesSince, verificationFileExists, normalizeVerificationFiles, indexCommitsForProject, embedUnembeddedCommits, loadPiConfig, ensureProjectRegisteredFromPiDirectory, resolveMuralWire, updateCompactionMarkerAfterPublication, COMPARTMENT_RENDER_EPOCH, encodeCachedM0UpgradeIdentity, decodeCachedM0UpgradeIdentity, DEFAULT_HISTORY_BUDGET_TOKENS, renderCompartmentAtTier, renderDecayedCompartments, extractM0Block, TEMPORAL_MARKER_PATTERN, temporalMarkerPrefix, clearInjectionCache, getVisibleMemoryIds, renderMemoryBlock, DEFAULT_MEMORY_BUDGET_TOKENS, DEFAULT_USER_PROFILE_BUDGET_TOKENS, trimMemoriesToBudgetV2, trimWorkspaceMemoriesToBudgetV2, trimUserMemoriesToBudget, renderMemoryBlockV2, stripMemoryMuralBlock, unifiedSearch, rememberTodowriteToolCallTodos, parseTodos, setTodoSnapshot, registerTodoOverlay, registerTodoStateLifecycle, registerMagicContextTools };
package/dist/index.js CHANGED
@@ -270,6 +270,7 @@ import {
270
270
  recordHistorianDrainFailure,
271
271
  recordMemoryMapping,
272
272
  recordMemoryVerifications,
273
+ recordMuralCueRejection,
273
274
  recordOverflowDetected,
274
275
  recordProtectedTailNoEligibleHead,
275
276
  recordProtectedTailPublicationFloor,
@@ -362,7 +363,7 @@ import {
362
363
  withMigrationLanguageDirective,
363
364
  withRawMessageProvider,
364
365
  withRawSessionMessageCache
365
- } from "./index-ekzg3w5y.js";
366
+ } from "./index-fw42dv6t.js";
366
367
  import {
367
368
  pushNotification
368
369
  } from "./index-hw34xmzk.js";
@@ -583,6 +584,15 @@ function formatFailClosedBlockingProcesses(processes) {
583
584
  }
584
585
  function formatFailClosedBlockingMessage(reason) {
585
586
  if (reason.kind === "migration_guard") {
587
+ if (reason.unreadableFile) {
588
+ const arm = reason.unreadableArm ?? "io";
589
+ const recovery = arm === "io" ? `If no OpenCode server is running, it is safe to delete ${reason.unreadableFile} and retry.` : `The file may be a recent incomplete write; retry after the file is older than the ten-minute grace window, or stop OpenCode before deleting it.`;
590
+ return [
591
+ `Magic Context cannot migrate the shared database because RPC discovery file ${reason.unreadableFile} is uncertain (${arm} arm), so the absence of a live OpenCode server cannot be proven.`,
592
+ recovery,
593
+ `Recovery: ${FAIL_CLOSED_DOCTOR_COMMAND}`
594
+ ].join(" ");
595
+ }
586
596
  return [
587
597
  `Magic Context cannot migrate the shared database because ${formatFailClosedBlockingProcesses(reason.blockingProcesses)} may be running an older Magic Context build that would fail against the migrated database.`,
588
598
  "Restart the blocking process (it will pick up the new build and migrate on start), or shut it down and retry.",
@@ -3286,6 +3296,70 @@ function backoffMs(failureCount) {
3286
3296
  return minutes * 60 * 1000;
3287
3297
  }
3288
3298
 
3299
+ // ../plugin/src/features/magic-context/dreamer/storage-task-schedule.ts
3300
+ function toRow(r) {
3301
+ return {
3302
+ projectPath: r.project_path,
3303
+ task: r.task,
3304
+ lastRunAt: r.last_run_at,
3305
+ nextDueAt: r.next_due_at,
3306
+ schedule: r.schedule ?? null,
3307
+ lastStatus: r.last_status ?? null,
3308
+ lastError: r.last_error,
3309
+ retryCount: r.retry_count ?? 0,
3310
+ lastCheckedCommit: r.last_checked_commit ?? null,
3311
+ lastBroadRunAt: r.last_broad_run_at ?? null,
3312
+ retrospectiveWatermarkMs: r.retrospective_watermark_ms ?? null
3313
+ };
3314
+ }
3315
+ var SELECT_COLUMNS = "project_path, task, last_run_at, next_due_at, schedule, last_status, last_error, retry_count, last_checked_commit, last_broad_run_at, retrospective_watermark_ms";
3316
+ function getTaskScheduleState(db, projectPath, task) {
3317
+ const row = db.prepare(`SELECT ${SELECT_COLUMNS} FROM task_schedule_state WHERE project_path = ? AND task = ?`).get(projectPath, task);
3318
+ return row ? toRow(row) : null;
3319
+ }
3320
+ function getMostRecentTaskRunAt(db, projectPath) {
3321
+ const row = db.prepare("SELECT MAX(last_run_at) AS max_at FROM task_schedule_state WHERE project_path = ?").get(projectPath);
3322
+ const value = row?.max_at ?? null;
3323
+ return typeof value === "number" && value > 0 ? value : null;
3324
+ }
3325
+ function pruneNonCanonicalTaskRows(db, projectPath, canonicalTasks) {
3326
+ if (canonicalTasks.length === 0)
3327
+ return 0;
3328
+ const placeholders = canonicalTasks.map(() => "?").join(", ");
3329
+ const result = db.prepare(`DELETE FROM task_schedule_state WHERE project_path = ? AND task NOT IN (${placeholders})`).run(projectPath, ...canonicalTasks);
3330
+ return Number(result.changes ?? 0);
3331
+ }
3332
+ function deleteTaskScheduleRowsForProject(db, projectPath) {
3333
+ const result = db.prepare("DELETE FROM task_schedule_state WHERE project_path = ?").run(projectPath);
3334
+ return Number(result.changes ?? 0);
3335
+ }
3336
+ function seedTaskScheduleState(db, projectPath, task, nextDueAt, lastRunAt, schedule) {
3337
+ db.prepare("INSERT INTO task_schedule_state (project_path, task, last_run_at, next_due_at, schedule, last_status, last_error, retry_count) VALUES (?, ?, ?, ?, ?, NULL, NULL, 0) ON CONFLICT(project_path, task) DO NOTHING").run(projectPath, task, lastRunAt, nextDueAt, schedule);
3338
+ }
3339
+ function writeTaskScheduleState(db, row) {
3340
+ const broadCycleUpdate = row.lastBroadRunAt === undefined ? "last_broad_run_at = task_schedule_state.last_broad_run_at" : "last_broad_run_at = excluded.last_broad_run_at";
3341
+ db.prepare(`INSERT INTO task_schedule_state
3342
+ (project_path, task, last_run_at, next_due_at, schedule, last_status, last_error, retry_count, last_checked_commit, last_broad_run_at, retrospective_watermark_ms)
3343
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3344
+ ON CONFLICT(project_path, task) DO UPDATE SET
3345
+ last_run_at = excluded.last_run_at,
3346
+ next_due_at = excluded.next_due_at,
3347
+ schedule = excluded.schedule,
3348
+ last_status = excluded.last_status,
3349
+ last_error = excluded.last_error,
3350
+ retry_count = excluded.retry_count,
3351
+ last_checked_commit = COALESCE(excluded.last_checked_commit, task_schedule_state.last_checked_commit),
3352
+ ${broadCycleUpdate},
3353
+ retrospective_watermark_ms = COALESCE(excluded.retrospective_watermark_ms, task_schedule_state.retrospective_watermark_ms)`).run(row.projectPath, row.task, row.lastRunAt, row.nextDueAt, row.schedule, row.lastStatus, row.lastError, row.retryCount, row.lastCheckedCommit ?? null, row.lastBroadRunAt ?? null, row.retrospectiveWatermarkMs ?? null);
3354
+ }
3355
+ function isRetrospectiveWindowProcessed(db, projectPath, windowKey) {
3356
+ const row = db.prepare("SELECT 1 AS one FROM retrospective_processed_windows WHERE project_path = ? AND window_key = ?").get(projectPath, windowKey);
3357
+ return row != null;
3358
+ }
3359
+ function recordRetrospectiveWindowProcessed(db, projectPath, windowKey) {
3360
+ db.prepare("INSERT INTO retrospective_processed_windows (project_path, window_key, processed_at) VALUES (?, ?, ?) ON CONFLICT(project_path, window_key) DO NOTHING").run(projectPath, windowKey, Date.now());
3361
+ }
3362
+
3289
3363
  // ../plugin/src/features/magic-context/dreamer/task-gates.ts
3290
3364
  function countActiveMemories(db, projectPath) {
3291
3365
  const row = db.prepare("SELECT COUNT(*) AS cnt FROM memories WHERE project_path = ? AND status IN ('active','permanent')").get(projectPath);
@@ -3331,6 +3405,19 @@ function countUnverifiedMappedMemories(db, projectPath) {
3331
3405
  AND v.verified_at = 0`).get(projectPath);
3332
3406
  return row?.cnt ?? 0;
3333
3407
  }
3408
+ function countBroadCycleCandidates(db, projectPath, cycleStartAt) {
3409
+ const row = db.prepare(`SELECT COUNT(*) AS cnt
3410
+ FROM memories m
3411
+ WHERE m.project_path = ?
3412
+ AND m.status IN ('active','permanent')
3413
+ AND (
3414
+ SELECT MAX(v.verified_at)
3415
+ FROM memory_verifications v
3416
+ WHERE v.memory_id = m.id
3417
+ AND v.file_path <> ''
3418
+ ) < ?`).get(projectPath, cycleStartAt);
3419
+ return row?.cnt ?? 0;
3420
+ }
3334
3421
  function countCueCandidates(db, projectPath) {
3335
3422
  if (!hasMuralCueColumns(db))
3336
3423
  return countActiveMemories(db, projectPath);
@@ -3386,7 +3473,9 @@ function getDreamTaskBacklog(db, projectPath, task, options = {}) {
3386
3473
  }
3387
3474
  case "verify-broad": {
3388
3475
  const total = countMappedMemories(db, projectPath);
3389
- return { pending: total, total };
3476
+ const cycleStartAt = getTaskScheduleState(db, projectPath, "verify-broad")?.lastBroadRunAt;
3477
+ const pending = cycleStartAt == null ? total : countBroadCycleCandidates(db, projectPath, cycleStartAt);
3478
+ return { pending, total };
3390
3479
  }
3391
3480
  case "curate": {
3392
3481
  const total = countActiveMemories(db, projectPath);
@@ -3445,7 +3534,7 @@ function evaluateTaskGate(task, ctx) {
3445
3534
  case "verify":
3446
3535
  return countActiveMemories(db, project) > 0;
3447
3536
  case "verify-broad":
3448
- return countActiveMemories(db, project) > 0;
3537
+ return getTaskScheduleState(db, project, "verify-broad")?.lastBroadRunAt != null || countActiveMemories(db, project) > 0;
3449
3538
  case "curate":
3450
3539
  return countActiveMemories(db, project) > 0;
3451
3540
  case "compress-cues":
@@ -4370,7 +4459,7 @@ function hasBalancedParentheses(cue) {
4370
4459
  }
4371
4460
  return depth === 0;
4372
4461
  }
4373
- function validateCue(cue, importance) {
4462
+ function validateCue(cue, importance, ownId) {
4374
4463
  const trimmed = cue.trim();
4375
4464
  if (trimmed.length === 0)
4376
4465
  return { reason: "empty" };
@@ -4378,8 +4467,9 @@ function validateCue(cue, importance) {
4378
4467
  const length = [...trimmed].length;
4379
4468
  if (length > budget)
4380
4469
  return { reason: `over-budget ${length}>${budget}` };
4381
- if (/#\d+/.test(trimmed))
4470
+ if (ownId !== undefined && new RegExp(`#${ownId}\\b`).test(trimmed)) {
4382
4471
  return { reason: "leaked-id" };
4472
+ }
4383
4473
  if (!hasBalancedParentheses(trimmed))
4384
4474
  return { reason: "unbalanced-parens" };
4385
4475
  const markers = trimmed.split("⊘").length - 1;
@@ -4395,6 +4485,7 @@ function validateCue(cue, importance) {
4395
4485
  // ../plugin/src/features/magic-context/mural/compress-cues.ts
4396
4486
  var COMPRESS_CUES_CHUNK_SIZE = 40;
4397
4487
  var CHUNK_TIMEOUT_FLOOR_MS = 240000;
4488
+ var CUE_REJECTION_LATCH_THRESHOLD = 3;
4398
4489
  var CONSECUTIVE_TIMEOUT_LIMIT = 2;
4399
4490
  function toPromptMemory(candidate) {
4400
4491
  const memory = candidate.memory;
@@ -4405,6 +4496,38 @@ function toPromptMemory(candidate) {
4405
4496
  content: memory.content
4406
4497
  };
4407
4498
  }
4499
+ function stripOwnIdToken(value, ownId) {
4500
+ return value.replace(new RegExp(`#${ownId}\\b`, "g"), "");
4501
+ }
4502
+ function truncateCue(value, budget) {
4503
+ const trimmed = value.trim();
4504
+ const codepoints = [...trimmed];
4505
+ if (codepoints.length <= budget)
4506
+ return trimmed;
4507
+ const prefix = codepoints.slice(0, budget).join("");
4508
+ const boundary = prefix.search(/\s+\S*$/);
4509
+ return (boundary > 0 ? prefix.slice(0, boundary) : prefix).trim();
4510
+ }
4511
+ function sanitizeCue(value, candidate) {
4512
+ return truncateCue(stripOwnIdToken(value, candidate.memory.id), cueBudgetFor(candidate.memory.importance ?? 50));
4513
+ }
4514
+ function deterministicFallbackCue(candidate, lastCandidate) {
4515
+ const importance = candidate.memory.importance ?? 50;
4516
+ const budget = cueBudgetFor(importance);
4517
+ const sanitizedCandidate = sanitizeCue(lastCandidate, candidate);
4518
+ if (validateCue(sanitizedCandidate, importance, candidate.memory.id) === null) {
4519
+ return sanitizedCandidate;
4520
+ }
4521
+ const sourceSlice = sanitizeCue(candidate.memory.content, candidate);
4522
+ if (validateCue(sourceSlice, importance, candidate.memory.id) === null) {
4523
+ return sourceSlice;
4524
+ }
4525
+ const grammarSafe = truncateCue(sourceSlice.replaceAll("⊘", "").replace(/[()]/g, "").replace(/\b(?:must not|never|without|instead of|exclude|excludes)\b/gi, "").replace(/\s+/g, " "), budget);
4526
+ if (validateCue(grammarSafe, importance, candidate.memory.id) === null) {
4527
+ return grammarSafe;
4528
+ }
4529
+ return "memory";
4530
+ }
4408
4531
  function selectCandidates(db, projectIdentity) {
4409
4532
  const memories = getMemoriesByProject(db, projectIdentity, ["active", "permanent"]);
4410
4533
  const cueState = getMuralCueState(db, memories.map((memory) => memory.id));
@@ -4573,10 +4696,19 @@ function applyCues(args, chunk, manifestText) {
4573
4696
  const candidate = byId.get(entry.id);
4574
4697
  if (!candidate)
4575
4698
  throw new Error(`cues manifest contains unknown id ${entry.id}`);
4576
- const failure = validateCue(entry.cue, candidate.memory.importance ?? 50);
4699
+ const importance = candidate.memory.importance ?? 50;
4700
+ const failure = validateCue(entry.cue, importance, candidate.memory.id);
4577
4701
  if (failure) {
4702
+ const rejectionCount = recordMuralCueRejection(args.db, args.projectIdentity, entry.id, candidate.contentHash);
4703
+ if (rejectionCount >= CUE_REJECTION_LATCH_THRESHOLD) {
4704
+ const fallback = deterministicFallbackCue(candidate, entry.cue);
4705
+ setMuralCue(args.db, args.projectIdentity, entry.id, fallback, candidate.contentHash);
4706
+ compressed += 1;
4707
+ log(`[dreamer] compress-cues: fallback cue for memory ${entry.id} (${failure.reason}; ${rejectionCount} rejections; fallback)`);
4708
+ continue;
4709
+ }
4578
4710
  skipped += 1;
4579
- log(`[dreamer] compress-cues: skipped cue for memory ${entry.id} (${failure.reason})`);
4711
+ log(`[dreamer] compress-cues: skipped cue for memory ${entry.id} (${failure.reason}; rejection ${rejectionCount}/${CUE_REJECTION_LATCH_THRESHOLD})`);
4580
4712
  continue;
4581
4713
  }
4582
4714
  setMuralCue(args.db, args.projectIdentity, entry.id, entry.cue.trim(), candidate.contentHash);
@@ -8721,69 +8853,6 @@ function insertDreamRun(db, run) {
8721
8853
  getInsertDreamRunStatement(db).run(run.projectPath, run.startedAt, run.finishedAt, run.holderId, JSON.stringify(run.tasks), run.tasksSucceeded, run.tasksFailed, run.smartNotesSurfaced, run.smartNotesPending, run.memoryChanges ? JSON.stringify(run.memoryChanges) : null, run.parentSessionId ?? null);
8722
8854
  }
8723
8855
 
8724
- // ../plugin/src/features/magic-context/dreamer/storage-task-schedule.ts
8725
- function toRow(r) {
8726
- return {
8727
- projectPath: r.project_path,
8728
- task: r.task,
8729
- lastRunAt: r.last_run_at,
8730
- nextDueAt: r.next_due_at,
8731
- schedule: r.schedule ?? null,
8732
- lastStatus: r.last_status ?? null,
8733
- lastError: r.last_error,
8734
- retryCount: r.retry_count ?? 0,
8735
- lastCheckedCommit: r.last_checked_commit ?? null,
8736
- lastBroadRunAt: r.last_broad_run_at ?? null,
8737
- retrospectiveWatermarkMs: r.retrospective_watermark_ms ?? null
8738
- };
8739
- }
8740
- var SELECT_COLUMNS = "project_path, task, last_run_at, next_due_at, schedule, last_status, last_error, retry_count, last_checked_commit, last_broad_run_at, retrospective_watermark_ms";
8741
- function getTaskScheduleState(db, projectPath, task) {
8742
- const row = db.prepare(`SELECT ${SELECT_COLUMNS} FROM task_schedule_state WHERE project_path = ? AND task = ?`).get(projectPath, task);
8743
- return row ? toRow(row) : null;
8744
- }
8745
- function getMostRecentTaskRunAt(db, projectPath) {
8746
- const row = db.prepare("SELECT MAX(last_run_at) AS max_at FROM task_schedule_state WHERE project_path = ?").get(projectPath);
8747
- const value = row?.max_at ?? null;
8748
- return typeof value === "number" && value > 0 ? value : null;
8749
- }
8750
- function pruneNonCanonicalTaskRows(db, projectPath, canonicalTasks) {
8751
- if (canonicalTasks.length === 0)
8752
- return 0;
8753
- const placeholders = canonicalTasks.map(() => "?").join(", ");
8754
- const result = db.prepare(`DELETE FROM task_schedule_state WHERE project_path = ? AND task NOT IN (${placeholders})`).run(projectPath, ...canonicalTasks);
8755
- return Number(result.changes ?? 0);
8756
- }
8757
- function deleteTaskScheduleRowsForProject(db, projectPath) {
8758
- const result = db.prepare("DELETE FROM task_schedule_state WHERE project_path = ?").run(projectPath);
8759
- return Number(result.changes ?? 0);
8760
- }
8761
- function seedTaskScheduleState(db, projectPath, task, nextDueAt, lastRunAt, schedule) {
8762
- db.prepare("INSERT INTO task_schedule_state (project_path, task, last_run_at, next_due_at, schedule, last_status, last_error, retry_count) VALUES (?, ?, ?, ?, ?, NULL, NULL, 0) ON CONFLICT(project_path, task) DO NOTHING").run(projectPath, task, lastRunAt, nextDueAt, schedule);
8763
- }
8764
- function writeTaskScheduleState(db, row) {
8765
- db.prepare(`INSERT INTO task_schedule_state
8766
- (project_path, task, last_run_at, next_due_at, schedule, last_status, last_error, retry_count, last_checked_commit, last_broad_run_at, retrospective_watermark_ms)
8767
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
8768
- ON CONFLICT(project_path, task) DO UPDATE SET
8769
- last_run_at = excluded.last_run_at,
8770
- next_due_at = excluded.next_due_at,
8771
- schedule = excluded.schedule,
8772
- last_status = excluded.last_status,
8773
- last_error = excluded.last_error,
8774
- retry_count = excluded.retry_count,
8775
- last_checked_commit = COALESCE(excluded.last_checked_commit, task_schedule_state.last_checked_commit),
8776
- last_broad_run_at = COALESCE(excluded.last_broad_run_at, task_schedule_state.last_broad_run_at),
8777
- retrospective_watermark_ms = COALESCE(excluded.retrospective_watermark_ms, task_schedule_state.retrospective_watermark_ms)`).run(row.projectPath, row.task, row.lastRunAt, row.nextDueAt, row.schedule, row.lastStatus, row.lastError, row.retryCount, row.lastCheckedCommit ?? null, row.lastBroadRunAt ?? null, row.retrospectiveWatermarkMs ?? null);
8778
- }
8779
- function isRetrospectiveWindowProcessed(db, projectPath, windowKey) {
8780
- const row = db.prepare("SELECT 1 AS one FROM retrospective_processed_windows WHERE project_path = ? AND window_key = ?").get(projectPath, windowKey);
8781
- return row != null;
8782
- }
8783
- function recordRetrospectiveWindowProcessed(db, projectPath, windowKey) {
8784
- db.prepare("INSERT INTO retrospective_processed_windows (project_path, window_key, processed_at) VALUES (?, ?, ?) ON CONFLICT(project_path, window_key) DO NOTHING").run(projectPath, windowKey, Date.now());
8785
- }
8786
-
8787
8856
  // ../plugin/src/features/magic-context/dreamer/verify.ts
8788
8857
  import { createHash as createHash5 } from "node:crypto";
8789
8858
 
@@ -8792,6 +8861,30 @@ import path5 from "node:path";
8792
8861
  function minOf(values) {
8793
8862
  return values.reduce((acc, v) => v < acc ? v : acc, Number.POSITIVE_INFINITY);
8794
8863
  }
8864
+ function ensureBroadCycleStart(args) {
8865
+ const current = getTaskScheduleState(args.db, args.projectIdentity, "verify-broad");
8866
+ if (current?.lastBroadRunAt != null && current.lastBroadRunAt > 0) {
8867
+ return current.lastBroadRunAt;
8868
+ }
8869
+ if (!current)
8870
+ return args.runStartedAt;
8871
+ if (!args.holderId || !args.leaseKey) {
8872
+ throw new Error("verify-broad cycle opening requires the task lease");
8873
+ }
8874
+ return runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
8875
+ const latest = getTaskScheduleState(args.db, args.projectIdentity, "verify-broad");
8876
+ if (!latest)
8877
+ return args.runStartedAt;
8878
+ if (latest.lastBroadRunAt != null && latest.lastBroadRunAt > 0) {
8879
+ return latest.lastBroadRunAt;
8880
+ }
8881
+ writeTaskScheduleState(args.db, {
8882
+ ...latest,
8883
+ lastBroadRunAt: args.runStartedAt
8884
+ });
8885
+ return args.runStartedAt;
8886
+ });
8887
+ }
8795
8888
  async function partitionVerifyScope(args) {
8796
8889
  const runStartedAt = args.now ?? Date.now();
8797
8890
  const active = getMemoriesByProject(args.db, args.projectIdentity);
@@ -8803,6 +8896,29 @@ async function partitionVerifyScope(args) {
8803
8896
  content: m.content,
8804
8897
  mappedFiles: verById.get(m.id)?.files ?? []
8805
8898
  });
8899
+ if (args.forceBroad) {
8900
+ const broadCycleStartAt = ensureBroadCycleStart({
8901
+ db: args.db,
8902
+ projectIdentity: args.projectIdentity,
8903
+ holderId: args.holderId,
8904
+ leaseKey: args.leaseKey,
8905
+ runStartedAt
8906
+ });
8907
+ const broadCandidates = candidates.filter((m) => (verById.get(m.id)?.verifiedAt ?? 0) < broadCycleStartAt).sort((a, b) => {
8908
+ const verifiedAtA = verById.get(a.id)?.verifiedAt ?? 0;
8909
+ const verifiedAtB = verById.get(b.id)?.verifiedAt ?? 0;
8910
+ return verifiedAtA - verifiedAtB || a.id - b.id;
8911
+ });
8912
+ return {
8913
+ runStartedAt,
8914
+ mode: "broad",
8915
+ inScope: broadCandidates.map(toPrompt),
8916
+ inScopeIds: broadCandidates.map((m) => m.id),
8917
+ skippedIds: candidates.filter((m) => !broadCandidates.some((candidate) => candidate.id === m.id)).map((m) => m.id),
8918
+ broadCycleStartAt,
8919
+ reason: `broad cycle (${broadCandidates.length} remain; started ${broadCycleStartAt})`
8920
+ };
8921
+ }
8806
8922
  if (candidates.length === 0) {
8807
8923
  return {
8808
8924
  runStartedAt,
@@ -8813,16 +8929,6 @@ async function partitionVerifyScope(args) {
8813
8929
  reason: "no file-mapped memories in scope"
8814
8930
  };
8815
8931
  }
8816
- if (args.forceBroad) {
8817
- return {
8818
- runStartedAt,
8819
- mode: "broad",
8820
- inScope: candidates.map(toPrompt),
8821
- inScopeIds: candidates.map((m) => m.id),
8822
- skippedIds: [],
8823
- reason: "broad full-pool verification of file-mapped memories"
8824
- };
8825
- }
8826
8932
  const allInScope = (mode, reason) => ({
8827
8933
  runStartedAt,
8828
8934
  mode,
@@ -8941,7 +9047,25 @@ function parseVerifyManifest(text) {
8941
9047
 
8942
9048
  // ../plugin/src/features/magic-context/dreamer/verify.ts
8943
9049
  var VERIFY_BATCH_SIZE = 50;
9050
+ function closeBroadCycle(args, cycleStartAt) {
9051
+ if (!args.forceBroad || cycleStartAt === undefined)
9052
+ return;
9053
+ if (!getTaskScheduleState(args.db, args.projectIdentity, "verify-broad"))
9054
+ return;
9055
+ runLeaseGuardedWrite(args.db, args.holderId, args.leaseKey, () => {
9056
+ const current = getTaskScheduleState(args.db, args.projectIdentity, "verify-broad");
9057
+ if (current?.lastBroadRunAt !== cycleStartAt)
9058
+ return;
9059
+ if (!current)
9060
+ return;
9061
+ writeTaskScheduleState(args.db, {
9062
+ ...current,
9063
+ lastBroadRunAt: null
9064
+ });
9065
+ });
9066
+ }
8944
9067
  async function runVerify(args) {
9068
+ const runStartedAt = Date.now();
8945
9069
  const result = {
8946
9070
  verified: 0,
8947
9071
  updated: 0,
@@ -8956,14 +9080,20 @@ async function runVerify(args) {
8956
9080
  db: args.db,
8957
9081
  projectIdentity: args.projectIdentity,
8958
9082
  projectDirectory: args.sessionDirectory,
8959
- forceBroad: args.forceBroad
9083
+ forceBroad: args.forceBroad,
9084
+ now: runStartedAt,
9085
+ holderId: args.holderId,
9086
+ leaseKey: args.leaseKey
8960
9087
  });
8961
9088
  result.mode = gate.mode;
9089
+ result.broadCycleStartAt = gate.broadCycleStartAt;
8962
9090
  result.inScope = gate.inScope.length;
8963
9091
  result.remaining = gate.inScope.length;
8964
9092
  log(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"} gate: mode=${gate.mode} in_scope=${gate.inScope.length} skipped=${gate.skippedIds.length} reason=${gate.reason}`);
8965
- if (gate.inScope.length === 0)
9093
+ if (gate.inScope.length === 0) {
9094
+ closeBroadCycle(args, gate.broadCycleStartAt);
8966
9095
  return result;
9096
+ }
8967
9097
  const batches = [];
8968
9098
  for (let i = 0;i < gate.inScope.length; i += VERIFY_BATCH_SIZE) {
8969
9099
  batches.push(gate.inScope.slice(i, i + VERIFY_BATCH_SIZE));
@@ -8986,6 +9116,8 @@ async function runVerify(args) {
8986
9116
  args.onProgress?.(result.verified + result.updated + result.archived);
8987
9117
  }
8988
9118
  result.complete = result.remaining === 0;
9119
+ if (result.complete)
9120
+ closeBroadCycle(args, gate.broadCycleStartAt);
8989
9121
  log(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: verified=${result.verified} updated=${result.updated} archived=${result.archived} batches=${result.batches} remaining=${result.remaining} complete=${result.complete}`);
8990
9122
  return result;
8991
9123
  } finally {
@@ -9319,7 +9451,7 @@ function createDreamTaskExecutor(deps) {
9319
9451
  resultChars: 0,
9320
9452
  ...error ? { error } : {},
9321
9453
  backlog: (() => {
9322
- const end = getDreamTaskBacklog(db, projectIdentity, config.task);
9454
+ const end = extra?.backlogAfter ?? getDreamTaskBacklog(db, projectIdentity, config.task);
9323
9455
  const processed = processedDreamTaskItems(backlogAtStart.pending, end.pending);
9324
9456
  const value = {
9325
9457
  pendingAtStart: backlogAtStart.pending,
@@ -9454,19 +9586,31 @@ function createDreamTaskExecutor(deps) {
9454
9586
  fallbackModels: config.fallbackModels,
9455
9587
  language: config.language ?? deps.language,
9456
9588
  moduleRoute,
9457
- onProgress: (processed) => reportProgress(processed)
9589
+ onProgress: (processed2) => reportProgress(processed2)
9458
9590
  });
9591
+ const processed = result.verified + result.updated + result.archived;
9592
+ const broadProgress = config.task === "verify-broad" ? `verify-broad cycle ${result.broadCycleStartAt ?? "open"}: verified ${processed}, ${result.remaining} remain` : null;
9593
+ const backlogAfter = config.task === "verify-broad" ? { pending: result.remaining, total: backlogAtStart.total } : undefined;
9459
9594
  if (!result.complete) {
9595
+ if (broadProgress && processed > 0) {
9596
+ recordRun("completed", broadProgress, {
9597
+ memoryChanges: computeMemoryDelta(memoryBefore),
9598
+ backlogAfter
9599
+ });
9600
+ return { status: "completed", error: broadProgress };
9601
+ }
9460
9602
  const error = incompleteMessage(result.remaining);
9461
9603
  recordRun("failed", error, {
9462
- memoryChanges: computeMemoryDelta(memoryBefore)
9604
+ memoryChanges: computeMemoryDelta(memoryBefore),
9605
+ backlogAfter
9463
9606
  });
9464
9607
  return { status: "failed", transient: true, error };
9465
9608
  }
9466
- recordRun("completed", null, {
9467
- memoryChanges: computeMemoryDelta(memoryBefore)
9609
+ recordRun("completed", broadProgress, {
9610
+ memoryChanges: computeMemoryDelta(memoryBefore),
9611
+ backlogAfter
9468
9612
  });
9469
- return { status: "completed" };
9613
+ return broadProgress ? { status: "completed", error: broadProgress } : { status: "completed" };
9470
9614
  }
9471
9615
  if (config.task === "classify-memories") {
9472
9616
  let moduleArgs;
@@ -27539,7 +27683,7 @@ ${c.content}
27539
27683
  // package.json
27540
27684
  var package_default = {
27541
27685
  name: "@cortexkit/pi-magic-context",
27542
- version: "0.34.1",
27686
+ version: "0.34.2",
27543
27687
  type: "module",
27544
27688
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
27545
27689
  main: "dist/index.js",
@@ -5,7 +5,7 @@ import {
5
5
  registerMagicContextTools,
6
6
  resolveProjectIdentityForSession,
7
7
  setStoragePrivatePermissionEnforcement
8
- } from "./index-ekzg3w5y.js";
8
+ } from "./index-fw42dv6t.js";
9
9
  import {
10
10
  log,
11
11
  setHarness
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/pi-magic-context",
3
- "version": "0.34.1",
3
+ "version": "0.34.2",
4
4
  "type": "module",
5
5
  "description": "Pi coding agent extension for Magic Context — cross-session memory and context management",
6
6
  "main": "dist/index.js",