@cortexkit/pi-magic-context 0.21.2 → 0.21.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -141906,6 +141906,10 @@ function getLastCompartmentEndMessage(db, sessionId) {
141906
141906
  const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
141907
141907
  return row?.max_end ?? -1;
141908
141908
  }
141909
+ function getCompartmentsByEndMessageId(db, sessionId, endMessageId) {
141910
+ const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? AND end_message_id = ? ORDER BY sequence ASC").all(sessionId, endMessageId).filter(isCompartmentRow);
141911
+ return rows.map(toCompartment);
141912
+ }
141909
141913
  function appendCompartments(db, sessionId, compartments) {
141910
141914
  if (compartments.length === 0)
141911
141915
  return;
@@ -142015,7 +142019,7 @@ function promoteRecompStaging(db, sessionId) {
142015
142019
  insertFactRows(db, sessionId, staging.facts, now);
142016
142020
  db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
142017
142021
  db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
142018
- db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE session_id = ?").run(sessionId);
142022
+ db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
142019
142023
  return { compartments: staging.compartments, facts: staging.facts };
142020
142024
  })();
142021
142025
  }
@@ -142245,8 +142249,10 @@ function deleteOrphanProjectKeyFiles(db, now = Date.now()) {
142245
142249
  if (existsSync2(row.projectPath))
142246
142250
  continue;
142247
142251
  try {
142248
- db.prepare("DELETE FROM project_key_files WHERE project_path = ?").run(row.projectPath);
142249
- db.prepare("DELETE FROM project_key_files_version WHERE project_path = ?").run(row.projectPath);
142252
+ db.transaction(() => {
142253
+ db.prepare("DELETE FROM project_key_files WHERE project_path = ?").run(row.projectPath);
142254
+ db.prepare("DELETE FROM project_key_files_version WHERE project_path = ?").run(row.projectPath);
142255
+ })();
142250
142256
  deletedProjects++;
142251
142257
  } catch (error) {
142252
142258
  log(`[key-files] orphan GC failed for ${row.projectPath}:`, error);
@@ -142653,6 +142659,16 @@ var MIGRATIONS = [
142653
142659
  WHERE auto_search_hint_decisions IS NULL
142654
142660
  `);
142655
142661
  }
142662
+ },
142663
+ {
142664
+ version: 18,
142665
+ description: "Add pending_pi_compaction_marker_state column for Pi deferred marker drain",
142666
+ up: (db) => {
142667
+ const cols = db.prepare("PRAGMA table_info(session_meta)").all();
142668
+ if (!cols.some((c) => c.name === "pending_pi_compaction_marker_state")) {
142669
+ db.exec("ALTER TABLE session_meta ADD COLUMN pending_pi_compaction_marker_state TEXT");
142670
+ }
142671
+ }
142656
142672
  }
142657
142673
  ];
142658
142674
  function ensureMigrationsTable(db) {
@@ -142668,7 +142684,7 @@ function getCurrentVersion(db) {
142668
142684
  const row = db.prepare("SELECT MAX(version) as version FROM schema_migrations").get();
142669
142685
  return row?.version ?? 0;
142670
142686
  }
142671
- function isSiblingMigrationConflict(error, version) {
142687
+ function isSiblingMigrationConflict(db, error, version) {
142672
142688
  if (!(error instanceof Error))
142673
142689
  return false;
142674
142690
  const code = error.code;
@@ -142680,7 +142696,8 @@ function isSiblingMigrationConflict(error, version) {
142680
142696
  return false;
142681
142697
  if (!msg.toLowerCase().includes("version"))
142682
142698
  return false;
142683
- return true;
142699
+ const confirmed = db.prepare("SELECT 1 FROM schema_migrations WHERE version = ?").get(version);
142700
+ return confirmed != null;
142684
142701
  }
142685
142702
  function runMigrations(db) {
142686
142703
  ensureMigrationsTable(db);
@@ -142701,7 +142718,7 @@ function runMigrations(db) {
142701
142718
  log(`[migrations] applied v${migration.version}: ${migration.description}`);
142702
142719
  migrationIndex += 1;
142703
142720
  } catch (error) {
142704
- if (isSiblingMigrationConflict(error, migration.version)) {
142721
+ if (isSiblingMigrationConflict(db, error, migration.version)) {
142705
142722
  log(`[migrations] v${migration.version} already applied by sibling instance — resuming with re-read version`);
142706
142723
  const reReadVersion = getCurrentVersion(db);
142707
142724
  if (reReadVersion <= currentVersion) {
@@ -143298,6 +143315,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143298
143315
  -- Excluded from healNullTextColumns. Readers filter IS NOT NULL AND
143299
143316
  -- != empty-string defensively. Plan v6 section 3.
143300
143317
  pending_compaction_marker_state TEXT,
143318
+ -- pending_pi_compaction_marker_state: intentionally NULLABLE without a
143319
+ -- default. Absence of a deferred Pi-native marker is SQL NULL; presence
143320
+ -- is a valid JSON blob written via setPendingPiCompactionMarkerState.
143321
+ -- Excluded from healNullTextColumns.
143322
+ pending_pi_compaction_marker_state TEXT,
143301
143323
  -- deferred_execute_state: intentionally NULLABLE without a default.
143302
143324
  -- Absence is SQL NULL; presence is a JSON blob written via
143303
143325
  -- setDeferredExecutePendingIfAbsent. Excluded from healNullTextColumns.
@@ -143394,6 +143416,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143394
143416
  ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
143395
143417
  ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
143396
143418
  ensureColumn(db, "session_meta", "pending_compaction_marker_state", "TEXT");
143419
+ ensureColumn(db, "session_meta", "pending_pi_compaction_marker_state", "TEXT");
143397
143420
  ensureColumn(db, "session_meta", "deferred_execute_state", "TEXT");
143398
143421
  ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
143399
143422
  ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
@@ -144009,6 +144032,39 @@ function clearPendingCompactionMarkerStateIf(db, sessionId, expected) {
144009
144032
  WHERE session_id = ? AND pending_compaction_marker_state = ?`).run(sessionId, expectedBlob);
144010
144033
  return result.changes > 0;
144011
144034
  }
144035
+ function isPendingPiCompactionMarker(value) {
144036
+ return typeof value === "object" && value !== null && typeof value.firstKeptEntryId === "string" && typeof value.endMessageId === "string" && typeof value.ordinal === "number" && typeof value.tokensBefore === "number" && typeof value.summary === "string" && typeof value.publishedAt === "number";
144037
+ }
144038
+ function getPendingPiCompactionMarkerState(db, sessionId) {
144039
+ const row = db.prepare("SELECT pending_pi_compaction_marker_state FROM session_meta WHERE session_id = ?").get(sessionId);
144040
+ const raw = row?.pending_pi_compaction_marker_state;
144041
+ if (raw === null || raw === undefined || raw === "")
144042
+ return null;
144043
+ try {
144044
+ const parsed = JSON.parse(raw);
144045
+ if (isPendingPiCompactionMarker(parsed)) {
144046
+ return parsed;
144047
+ }
144048
+ } catch {}
144049
+ return null;
144050
+ }
144051
+ function setPendingPiCompactionMarkerState(db, sessionId, state) {
144052
+ ensureSessionMetaRow(db, sessionId);
144053
+ const blob = state ? stableStringify(state) : null;
144054
+ db.prepare("UPDATE session_meta SET pending_pi_compaction_marker_state = ? WHERE session_id = ?").run(blob, sessionId);
144055
+ }
144056
+ function clearPendingPiCompactionMarkerStateIf(db, sessionId, expected) {
144057
+ const expectedBlob = stableStringify(expected);
144058
+ const result = db.prepare(`UPDATE session_meta SET pending_pi_compaction_marker_state = NULL
144059
+ WHERE session_id = ? AND pending_pi_compaction_marker_state = ?`).run(sessionId, expectedBlob);
144060
+ return result.changes > 0;
144061
+ }
144062
+ function getSessionsWithPendingPiMarker(db) {
144063
+ const rows = db.prepare(`SELECT session_id FROM session_meta
144064
+ WHERE pending_pi_compaction_marker_state IS NOT NULL
144065
+ AND pending_pi_compaction_marker_state != ''`).all();
144066
+ return rows.map((r) => r.session_id);
144067
+ }
144012
144068
  function peekDeferredExecutePending(db, sessionId) {
144013
144069
  const row = db.prepare("SELECT deferred_execute_state FROM session_meta WHERE session_id = ?").get(sessionId);
144014
144070
  const raw = row?.deferred_execute_state;
@@ -144129,6 +144185,12 @@ function getNoteById(db, noteId) {
144129
144185
  const row = db.prepare("SELECT * FROM notes WHERE id = ?").get(noteId);
144130
144186
  return isNoteRow(row) ? toNote(row) : null;
144131
144187
  }
144188
+ function noteBelongsToScope(note, scope) {
144189
+ if (note.type === "session") {
144190
+ return note.sessionId === scope.sessionId;
144191
+ }
144192
+ return note.projectPath === scope.projectPath;
144193
+ }
144132
144194
  function buildStatusClause(status) {
144133
144195
  if (status === undefined) {
144134
144196
  return null;
@@ -144190,9 +144252,9 @@ function getPendingSmartNotes(db, projectPath) {
144190
144252
  function getReadySmartNotes(db, projectPath) {
144191
144253
  return getSmartNotes(db, projectPath, "ready");
144192
144254
  }
144193
- function updateNote(db, noteId, updates) {
144255
+ function updateNote(db, noteId, updates, scope) {
144194
144256
  const existing = getNoteById(db, noteId);
144195
- if (!existing) {
144257
+ if (!existing || !noteBelongsToScope(existing, scope)) {
144196
144258
  return null;
144197
144259
  }
144198
144260
  const now = Date.now();
@@ -144239,7 +144301,11 @@ function updateNote(db, noteId, updates) {
144239
144301
  const result = db.prepare(`UPDATE notes SET ${sets.join(", ")} WHERE id = ? RETURNING *`).get(...params);
144240
144302
  return isNoteRow(result) ? toNote(result) : null;
144241
144303
  }
144242
- function dismissNote(db, noteId) {
144304
+ function dismissNote(db, noteId, scope) {
144305
+ const existing = getNoteById(db, noteId);
144306
+ if (!existing || !noteBelongsToScope(existing, scope)) {
144307
+ return false;
144308
+ }
144243
144309
  const result = db.prepare("UPDATE notes SET status = 'dismissed', updated_at = ? WHERE id = ? AND status != 'dismissed'").run(Date.now(), noteId);
144244
144310
  return result.changes > 0;
144245
144311
  }
@@ -144901,7 +144967,21 @@ function resolveHistorianContextLimit(historianModelOverride) {
144901
144967
 
144902
144968
  // ../plugin/src/hooks/magic-context/event-resolvers.ts
144903
144969
  init_logger();
144970
+ var DEFAULT_CONTEXT_LIMIT = 128000;
144904
144971
  var MAX_EXECUTE_THRESHOLD = 80;
144972
+ function resolveContextLimit(providerID, modelID, ctx) {
144973
+ const fromModelsDev = providerID && modelID ? getModelsDevContextLimit(providerID, modelID) : undefined;
144974
+ const baseline = fromModelsDev ?? DEFAULT_CONTEXT_LIMIT;
144975
+ if (ctx?.db && ctx.sessionID) {
144976
+ try {
144977
+ const overflow = getOverflowState(ctx.db, ctx.sessionID);
144978
+ if (overflow.detectedContextLimit > 0 && overflow.detectedContextLimit < baseline) {
144979
+ return overflow.detectedContextLimit;
144980
+ }
144981
+ } catch {}
144982
+ }
144983
+ return baseline;
144984
+ }
144905
144985
  function resolveCacheTtl(cacheTtl, modelKey) {
144906
144986
  if (typeof cacheTtl === "string") {
144907
144987
  return cacheTtl;
@@ -145269,6 +145349,14 @@ class PiSubagentRunner {
145269
145349
  }
145270
145350
  async run(options) {
145271
145351
  const startTime = Date.now();
145352
+ if (options.signal?.aborted) {
145353
+ return {
145354
+ ok: false,
145355
+ reason: "abort",
145356
+ error: "pi subagent aborted by caller",
145357
+ durationMs: Date.now() - startTime
145358
+ };
145359
+ }
145272
145360
  const args = buildArgs(options);
145273
145361
  return new Promise((resolve2) => {
145274
145362
  let settled = false;
@@ -145301,6 +145389,16 @@ class PiSubagentRunner {
145301
145389
  });
145302
145390
  return;
145303
145391
  }
145392
+ if (options.signal?.aborted) {
145393
+ terminateChild(child);
145394
+ settle({
145395
+ ok: false,
145396
+ reason: "abort",
145397
+ error: "pi subagent aborted by caller",
145398
+ durationMs: Date.now() - startTime
145399
+ });
145400
+ return;
145401
+ }
145304
145402
  emitProgress({ type: "spawned", argv: args, pid: child.pid });
145305
145403
  let stderr = "";
145306
145404
  child.stderr?.on("data", (chunk) => {
@@ -146297,6 +146395,43 @@ function normalizeProjectRelativePath(projectPath, filePath) {
146297
146395
  return null;
146298
146396
  return rel;
146299
146397
  }
146398
+ function isDocumentationOrMetaFile(rel) {
146399
+ const lower = rel.toLowerCase();
146400
+ if (lower.endsWith(".md") || lower.endsWith(".mdx") || lower.endsWith(".rst"))
146401
+ return true;
146402
+ if (lower.endsWith(".txt"))
146403
+ return true;
146404
+ const base = lower.split("/").pop() ?? "";
146405
+ const baseNoExt = base.replace(/\.[^.]+$/, "");
146406
+ const META_BASENAMES = new Set([
146407
+ "license",
146408
+ "licence",
146409
+ "notice",
146410
+ "copying",
146411
+ "authors",
146412
+ "contributors",
146413
+ "changelog",
146414
+ "changes",
146415
+ "history",
146416
+ "readme",
146417
+ "contributing",
146418
+ "code_of_conduct",
146419
+ "security",
146420
+ "support",
146421
+ "maintainers",
146422
+ "governance",
146423
+ "package-lock",
146424
+ "bun.lock",
146425
+ "bun.lockb",
146426
+ "yarn.lock",
146427
+ "pnpm-lock",
146428
+ "cargo.lock",
146429
+ "uv.lock",
146430
+ "poetry.lock",
146431
+ "gemfile.lock"
146432
+ ]);
146433
+ return META_BASENAMES.has(base) || META_BASENAMES.has(baseNoExt);
146434
+ }
146300
146435
  function primarySessionIds(db) {
146301
146436
  try {
146302
146437
  const rows = db.prepare("SELECT session_id AS sessionId FROM session_meta WHERE is_subagent = 0").all();
@@ -146328,6 +146463,8 @@ function collectKeyFileCandidates(args) {
146328
146463
  const rel = normalizeProjectRelativePath(args.projectPath, row.file_path);
146329
146464
  if (!rel)
146330
146465
  continue;
146466
+ if (isDocumentationOrMetaFile(rel))
146467
+ continue;
146331
146468
  const timestamp = toMs(row.time_created);
146332
146469
  const candidate = byPath.get(rel) ?? {
146333
146470
  path: rel,
@@ -146464,7 +146601,8 @@ Rules:
146464
146601
  - Total approx_token_estimate must be < ${args.config.token_budget}.
146465
146602
  - path must be relative, no .., no absolute paths, no symlinks escaping project root.
146466
146603
  - path must be unique case-sensitively and case-insensitively.
146467
- - content must be plain text; no XML tags inside.`;
146604
+ - content must be plain text; no XML tags inside.
146605
+ - DO NOT pick prose documentation (README.md, CONTRIBUTING.md, CHANGELOG, LICENSE, *.md/*.mdx/*.rst/*.txt) or lockfiles. Key files are project SOURCE the agent needs repeated orientation context on, not reference docs. Project docs are surfaced through a separate injection path.`;
146468
146606
  }
146469
146607
  function validateLlmOutput(raw, config, projectPath) {
146470
146608
  let obj;
@@ -148269,6 +148407,13 @@ async function evaluateSmartNotes(args) {
148269
148407
  For each note below, determine whether its surface condition has been met.
148270
148408
  You have access to tools like GitHub CLI (gh), web search, and the local codebase to verify conditions.
148271
148409
 
148410
+ You DO NOT have access to:
148411
+ - Any conversation between the user and the original agent that wrote the note
148412
+ - The state of any active session, including whether messages have been sent
148413
+ - The current task, mood, or intent of the human user
148414
+
148415
+ If a condition references conversation context the user is having ("When the user mentions X", "When they ask to do Y", "When we revisit Z", "When relevant to current discussion", etc.), it is UNEVALUATABLE — skip it (do not include in results) so the note stays pending. These are misuse cases that should never have been written as smart notes; leaving them pending is the correct outcome, the dreamer's archive-stale task will eventually retire them.
148416
+
148272
148417
  ## Pending Smart Notes
148273
148418
 
148274
148419
  ${noteDescriptions}
@@ -148277,7 +148422,8 @@ ${noteDescriptions}
148277
148422
 
148278
148423
  1. Check each condition using the tools available to you.
148279
148424
  2. Be conservative — only mark a condition as met when you have clear evidence.
148280
- 3. Respond with a JSON array of results:
148425
+ 3. Skip conditions that depend on session/conversation context you cannot observe — do not invent a "false" verdict for them, just omit them from your response.
148426
+ 4. Respond with a JSON array of results:
148281
148427
 
148282
148428
  \`\`\`json
148283
148429
  [
@@ -148285,7 +148431,7 @@ ${noteDescriptions}
148285
148431
  ]
148286
148432
  \`\`\`
148287
148433
 
148288
- Only include notes whose conditions you could definitively evaluate. Skip notes where you cannot determine the status (they will be re-evaluated next run).`;
148434
+ Only include notes whose conditions you could definitively evaluate against external signals. Skip notes where you cannot determine the status (they will be re-evaluated next run, or eventually archived as stale).`;
148289
148435
  const taskStartedAt = Date.now();
148290
148436
  let agentSessionId = null;
148291
148437
  const abortController = new AbortController;
@@ -163039,7 +163185,6 @@ var MagicContextConfigSchema = exports_external.object({
163039
163185
  enabled: exports_external.boolean().default(true),
163040
163186
  min_clusters: exports_external.number().min(1).default(3)
163041
163187
  }).default({ enabled: true, min_clusters: 3 }),
163042
- compaction_markers: exports_external.boolean().default(true),
163043
163188
  system_prompt_injection: exports_external.object({
163044
163189
  enabled: exports_external.boolean().default(true),
163045
163190
  skip_signatures: exports_external.array(exports_external.string()).default(["<!-- magic-context: skip -->"])
@@ -164703,6 +164848,21 @@ var FILE_PATTERN = /\{file:([^}]+)\}/g;
164703
164848
  function substituteConfigVariables(input) {
164704
164849
  const warnings = [];
164705
164850
  let text = input.text;
164851
+ if (input.isProjectConfig) {
164852
+ const hasEnvTokens = ENV_PATTERN.test(text);
164853
+ const hasFileTokens = FILE_PATTERN.test(text);
164854
+ ENV_PATTERN.lastIndex = 0;
164855
+ FILE_PATTERN.lastIndex = 0;
164856
+ if (hasEnvTokens || hasFileTokens) {
164857
+ const tokenTypes = [
164858
+ hasEnvTokens ? "{env:}" : undefined,
164859
+ hasFileTokens ? "{file:}" : undefined
164860
+ ].filter(Boolean).join(" and ");
164861
+ warnings.push(`Project-level config no longer supports ${tokenTypes} tokens for security reasons; leaving tokens literal. Move secret expansion to user-level config.`);
164862
+ }
164863
+ return { text, warnings };
164864
+ }
164865
+ text = stripJsonComments(text);
164706
164866
  text = text.replace(ENV_PATTERN, (_, rawName) => {
164707
164867
  const varName = rawName.trim();
164708
164868
  const value = varName ? process.env[varName] : undefined;
@@ -164710,7 +164870,7 @@ function substituteConfigVariables(input) {
164710
164870
  warnings.push(`Environment variable ${varName} is not set (referenced via {env:${varName}}); using empty string`);
164711
164871
  return "";
164712
164872
  }
164713
- return value;
164873
+ return JSON.stringify(value).slice(1, -1);
164714
164874
  });
164715
164875
  const fileMatches = Array.from(text.matchAll(FILE_PATTERN));
164716
164876
  if (fileMatches.length === 0) {
@@ -166148,8 +166308,7 @@ var FORCE_COMPARTMENT_PERCENTAGE = 80;
166148
166308
  function getProactiveCompartmentTriggerPercentage(executeThresholdPercentage) {
166149
166309
  return Math.max(0, executeThresholdPercentage - PROACTIVE_TRIGGER_OFFSET_PERCENTAGE);
166150
166310
  }
166151
- function estimateProjectedPostDropPercentage(db, sessionId, usage, autoDropToolAge, protectedTags, clearReasoningAge, clearedReasoningThroughTag, dropToolStructure = true) {
166152
- const activeTags = getTagsBySession(db, sessionId).filter((tag) => tag.status === "active");
166311
+ function estimateProjectedPostDropPercentage(db, sessionId, usage, activeTags, autoDropToolAge, protectedTags, clearReasoningAge, clearedReasoningThroughTag, dropToolStructure = true) {
166153
166312
  const totalActiveBytes = activeTags.reduce((sum, tag) => sum + tag.byteSize + tag.reasoningByteSize, 0);
166154
166313
  if (totalActiveBytes === 0)
166155
166314
  return null;
@@ -166236,15 +166395,24 @@ function getUnsummarizedTailInfo(db, sessionId, triggerBudget) {
166236
166395
  }
166237
166396
  });
166238
166397
  }
166239
- function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, autoDropToolAge, protectedTagCount, clearReasoningAge, dropToolStructure = true, commitClusterTrigger) {
166398
+ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, triggerBudget, autoDropToolAge, protectedTagCount, clearReasoningAge, dropToolStructure = true, commitClusterTrigger, preloadedActiveTags) {
166240
166399
  if (sessionMeta.compartmentInProgress) {
166400
+ sessionLog(sessionId, `compartment trigger: skipped — historian already in progress (usage=${usage.percentage.toFixed(1)}%)`);
166241
166401
  return { shouldFire: false };
166242
166402
  }
166243
166403
  const tailInfo = getUnsummarizedTailInfo(db, sessionId, triggerBudget);
166244
166404
  if (!tailInfo.hasNewRawHistory) {
166405
+ try {
166406
+ const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
166407
+ const rawMessageCount = getRawSessionMessageCount(sessionId);
166408
+ const protectedTailStart = getProtectedTailStartOrdinal(sessionId);
166409
+ sessionLog(sessionId, `compartment trigger: skipped — no new raw history (usage=${usage.percentage.toFixed(1)}% nextStartOrdinal=${tailInfo.nextStartOrdinal} lastCompartmentEnd=${lastCompartmentEnd} rawMessageCount=${rawMessageCount} protectedTailStart=${protectedTailStart})`);
166410
+ } catch (error51) {
166411
+ sessionLog(sessionId, `compartment trigger: skipped — no new raw history (usage=${usage.percentage.toFixed(1)}% nextStartOrdinal=${tailInfo.nextStartOrdinal} diagnostic-collection-failed: ${error51 instanceof Error ? error51.message : String(error51)})`);
166412
+ }
166245
166413
  return { shouldFire: false };
166246
166414
  }
166247
- const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, autoDropToolAge, protectedTagCount, clearReasoningAge, sessionMeta.clearedReasoningThroughTag, dropToolStructure);
166415
+ const projectedPostDropPercentage = estimateProjectedPostDropPercentage(db, sessionId, usage, preloadedActiveTags ?? getActiveTagsBySession(db, sessionId), autoDropToolAge, protectedTagCount, clearReasoningAge, sessionMeta.clearedReasoningThroughTag, dropToolStructure);
166248
166416
  const relativePostDropTarget = executeThresholdPercentage * POST_DROP_TARGET_RATIO;
166249
166417
  if (usage.percentage >= FORCE_COMPARTMENT_PERCENTAGE) {
166250
166418
  if (projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
@@ -166266,6 +166434,7 @@ function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPer
166266
166434
  }
166267
166435
  const proactiveTriggerPercentage = getProactiveCompartmentTriggerPercentage(executeThresholdPercentage);
166268
166436
  if (usage.percentage < proactiveTriggerPercentage) {
166437
+ sessionLog(sessionId, `compartment trigger: not firing at ${usage.percentage.toFixed(1)}% — below proactive floor (${proactiveTriggerPercentage}%)`);
166269
166438
  return { shouldFire: false };
166270
166439
  }
166271
166440
  if (projectedPostDropPercentage !== null && projectedPostDropPercentage <= relativePostDropTarget) {
@@ -167667,11 +167836,12 @@ async function runAutoSearchHintForPi(args) {
167667
167836
  }) : args.entryIds;
167668
167837
  if (!options.enabled)
167669
167838
  return messages;
167670
- if (entryIds === null) {
167671
- sessionLog(sessionId, "Pi auto-search: strict entry-id resolution failed; skipping fresh decision");
167672
- return messages;
167673
- }
167674
- const found = findLatestMeaningfulUserMessage(messages, entryIds);
167839
+ const strictResolutionFailed = entryIds === null;
167840
+ const effectiveEntryIds = strictResolutionFailed ? messages.map((message) => {
167841
+ const id = message.id;
167842
+ return typeof id === "string" ? id : undefined;
167843
+ }) : entryIds;
167844
+ const found = findLatestMeaningfulUserMessage(messages, effectiveEntryIds);
167675
167845
  if (found === null)
167676
167846
  return messages;
167677
167847
  const { message: userMsg, messageId: userMsgId } = found;
@@ -167683,6 +167853,10 @@ async function runAutoSearchHintForPi(args) {
167683
167853
  }
167684
167854
  return messages;
167685
167855
  }
167856
+ if (strictResolutionFailed) {
167857
+ sessionLog(sessionId, "Pi auto-search: strict entry-id resolution failed; replayed persisted decisions only");
167858
+ return messages;
167859
+ }
167686
167860
  const writeNoHintAndReconcile = (reason) => {
167687
167861
  const outcome2 = appendAutoSearchHintDecision(db, sessionId, {
167688
167862
  messageId: userMsgId,
@@ -167769,6 +167943,59 @@ ${hintText}`;
167769
167943
  }
167770
167944
  function clearAutoSearchForPiSession(_sessionId) {}
167771
167945
 
167946
+ // src/compaction-marker-manager-pi.ts
167947
+ init_logger();
167948
+ function applyDeferredPiCompactionMarker(deps, sessionId, pending) {
167949
+ try {
167950
+ const matches = getCompartmentsByEndMessageId(deps.db, sessionId, pending.endMessageId);
167951
+ if (matches.length === 0 || matches.length > 1) {
167952
+ if (matches.length > 1) {
167953
+ sessionLog(sessionId, `Pi compaction-marker drain: ${matches.length} compartments share endMessageId=${pending.endMessageId}; treating as stale`);
167954
+ }
167955
+ return { kind: "stale-skip", reason: "compartment-removed" };
167956
+ }
167957
+ if (matches[0]?.endMessage !== pending.ordinal) {
167958
+ return { kind: "stale-skip", reason: "target-superseded" };
167959
+ }
167960
+ const branchEntries = deps.readBranchEntries();
167961
+ if (!branchEntries.some((entry) => getEntryId(entry) === pending.firstKeptEntryId)) {
167962
+ return { kind: "stale-skip", reason: "entry-removed" };
167963
+ }
167964
+ const latestFirstKept = findLatestCompactionFirstKept(branchEntries);
167965
+ if (latestFirstKept === pending.firstKeptEntryId) {
167966
+ return { kind: "already-current" };
167967
+ }
167968
+ deps.appendCompaction(pending.summary, pending.firstKeptEntryId, pending.tokensBefore, {
167969
+ source: "magic-context",
167970
+ lastCompactedOrdinal: pending.ordinal
167971
+ }, true);
167972
+ sessionLog(sessionId, `Pi compaction-marker drain: applied firstKept=${pending.firstKeptEntryId} tokensBefore=${pending.tokensBefore}`);
167973
+ return { kind: "applied", firstKeptEntryId: pending.firstKeptEntryId };
167974
+ } catch (err) {
167975
+ const error51 = err instanceof Error ? err : new Error(String(err));
167976
+ sessionLog(sessionId, `Pi compaction-marker drain: retryable failure for ordinal ${pending.ordinal}:`, error51);
167977
+ return { kind: "retryable-failure", error: error51 };
167978
+ }
167979
+ }
167980
+ function findLatestCompactionFirstKept(branchEntries) {
167981
+ for (let i = branchEntries.length - 1;i >= 0; i--) {
167982
+ const entry = branchEntries[i];
167983
+ if (entry === null || typeof entry !== "object")
167984
+ continue;
167985
+ const record2 = entry;
167986
+ if (record2.type === "compaction" && typeof record2.firstKeptEntryId === "string") {
167987
+ return record2.firstKeptEntryId;
167988
+ }
167989
+ }
167990
+ return null;
167991
+ }
167992
+ function getEntryId(entry) {
167993
+ if (entry === null || typeof entry !== "object")
167994
+ return null;
167995
+ const id = entry.id;
167996
+ return typeof id === "string" ? id : null;
167997
+ }
167998
+
167772
167999
  // src/detect-recent-commit.ts
167773
168000
  var COMMIT_LOOKBACK = 5;
167774
168001
  var COMMIT_HASH_PATTERN2 = /\b[0-9a-f]{7,12}\b/;
@@ -169549,7 +169776,6 @@ async function runPiHistorian(deps) {
169549
169776
  memoryEnabled,
169550
169777
  autoPromote,
169551
169778
  onPublished,
169552
- appendCompaction,
169553
169779
  readBranchEntries,
169554
169780
  notifyIssue
169555
169781
  } = deps;
@@ -169722,20 +169948,34 @@ ${chunk.text}`, { stateFilePath });
169722
169948
  await notify(`Historian failed: ${errorMsg}`);
169723
169949
  return;
169724
169950
  }
169951
+ const markerSummary = buildPiCompactionSummary(newCompartments);
169952
+ const lastNewEndMessageId = newCompartments[newCompartments.length - 1]?.endMessageId;
169953
+ let firstKeptEntryId = null;
169954
+ if (readBranchEntries) {
169955
+ try {
169956
+ firstKeptEntryId = findFirstKeptEntryId(readBranchEntries(), lastNewEnd);
169957
+ if (!firstKeptEntryId) {
169958
+ sessionLog(sessionId, `historian: native compaction queue skipped; no firstKeptEntryId after ordinal ${lastNewEnd}`);
169959
+ }
169960
+ } catch (error51) {
169961
+ sessionLog(sessionId, `historian: native compaction queue lookup failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
169962
+ }
169963
+ }
169725
169964
  db.transaction(() => {
169726
169965
  appendCompartments(db, sessionId, newCompartments);
169727
169966
  replaceSessionFacts(db, sessionId, validatedPass.facts ?? []);
169728
169967
  clearHistorianFailureState(db, sessionId);
169968
+ if (firstKeptEntryId && lastNewEndMessageId) {
169969
+ setPendingPiCompactionMarkerState(db, sessionId, {
169970
+ firstKeptEntryId,
169971
+ endMessageId: lastNewEndMessageId,
169972
+ ordinal: lastNewEnd,
169973
+ tokensBefore: chunk.tokenEstimate,
169974
+ summary: markerSummary,
169975
+ publishedAt: Date.now()
169976
+ });
169977
+ }
169729
169978
  })();
169730
- appendPiNativeCompaction({
169731
- sessionId,
169732
- appendCompaction,
169733
- readBranchEntries,
169734
- lastCompactedOrdinal: lastNewEnd,
169735
- tokensBefore: chunk.tokenEstimate,
169736
- summary: buildPiCompactionSummary(newCompartments)
169737
- });
169738
- clearInjectionCache(sessionId);
169739
169979
  onNoteTrigger(db, sessionId, "historian_complete");
169740
169980
  onPublished?.();
169741
169981
  if (memoryEnabled !== false && autoPromote !== false) {
@@ -169796,25 +170036,6 @@ function buildPiCompactionSummary(compartments) {
169796
170036
  }
169797
170037
  return `Magic Context compacted: ${titles.join("; ")}`;
169798
170038
  }
169799
- function appendPiNativeCompaction(args) {
169800
- const { appendCompaction, readBranchEntries } = args;
169801
- if (!appendCompaction || !readBranchEntries)
169802
- return;
169803
- try {
169804
- const firstKeptEntryId = findFirstKeptEntryId(readBranchEntries(), args.lastCompactedOrdinal);
169805
- if (!firstKeptEntryId) {
169806
- sessionLog(args.sessionId, `historian: native compaction skipped; no firstKeptEntryId after ordinal ${args.lastCompactedOrdinal}`);
169807
- return;
169808
- }
169809
- appendCompaction(args.summary, firstKeptEntryId, args.tokensBefore, {
169810
- source: "magic-context",
169811
- lastCompactedOrdinal: args.lastCompactedOrdinal
169812
- }, true);
169813
- sessionLog(args.sessionId, `historian: appended native compaction firstKept=${firstKeptEntryId} tokensBefore=${args.tokensBefore}`);
169814
- } catch (error51) {
169815
- sessionLog(args.sessionId, `historian: native compaction append failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
169816
- }
169817
- }
169818
170039
  function findFirstKeptEntryId(entries, lastCompactedOrdinal) {
169819
170040
  const rawMessages = convertEntriesToRawMessages(entries);
169820
170041
  const target = lastCompactedOrdinal + 1;
@@ -170695,6 +170916,19 @@ function stripTagPrefix2(text) {
170695
170916
  return text.slice(match[0].length);
170696
170917
  }
170697
170918
 
170919
+ // src/timeout.ts
170920
+ function withTimeout(p, ms) {
170921
+ let handle;
170922
+ const timeout = new Promise((resolve4) => {
170923
+ handle = setTimeout(() => resolve4(undefined), ms);
170924
+ handle.unref?.();
170925
+ });
170926
+ return Promise.race([p, timeout]).finally(() => {
170927
+ if (handle)
170928
+ clearTimeout(handle);
170929
+ });
170930
+ }
170931
+
170698
170932
  // src/tokenize-pi-messages.ts
170699
170933
  function tokenizePiMessages(messages) {
170700
170934
  let conversation = 0;
@@ -171197,6 +171431,7 @@ var deferredMaterializationSessions = new Set;
171197
171431
  var sessionsByProject = new Map;
171198
171432
  var lastSeenProjectIdentityBySession = new Map;
171199
171433
  var rawMessageProviderUnregistersBySession = new Map;
171434
+ var activeContextHandlerSessions = new Set;
171200
171435
  var lastHeuristicsTurnIdBySession = new Map;
171201
171436
  var firstContextPassSeenBySession = new Set;
171202
171437
  var recentReduceBySession = new Map;
@@ -171248,6 +171483,7 @@ function consumeDeferredMaterialization(sessionId) {
171248
171483
  return wasSet;
171249
171484
  }
171250
171485
  function trackSessionForProject(projectIdentity, sessionId) {
171486
+ activeContextHandlerSessions.add(sessionId);
171251
171487
  let sessions = sessionsByProject.get(projectIdentity);
171252
171488
  if (!sessions) {
171253
171489
  sessions = new Set;
@@ -171255,6 +171491,9 @@ function trackSessionForProject(projectIdentity, sessionId) {
171255
171491
  }
171256
171492
  sessions.add(sessionId);
171257
171493
  }
171494
+ function isContextHandlerSessionActive(sessionId) {
171495
+ return activeContextHandlerSessions.has(sessionId);
171496
+ }
171258
171497
  function updateSessionProjectTracking(sessionId, projectIdentity) {
171259
171498
  const prev = lastSeenProjectIdentityBySession.get(sessionId);
171260
171499
  if (prev && prev !== projectIdentity) {
@@ -171351,20 +171590,26 @@ function resolveSessionId2(ctx) {
171351
171590
  return;
171352
171591
  }
171353
171592
  }
171354
- function collectMessageEntryIdsByRef(ctx, messages, sessionId) {
171355
- const sm = ctx.sessionManager;
171356
- if (typeof sm?.getBranch !== "function")
171357
- return null;
171593
+ function collectMessageEntryIdsByRef(ctx, messages, sessionId, preloadedBranchEntries) {
171358
171594
  let entries;
171359
- try {
171360
- entries = sm.getBranch.call(sm);
171361
- } catch (error51) {
171362
- sessionLog(sessionId ?? "pi", `collectMessageEntryIdsByRef getBranch failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
171363
- return null;
171595
+ if (preloadedBranchEntries !== undefined) {
171596
+ entries = preloadedBranchEntries;
171597
+ } else {
171598
+ const sm = ctx.sessionManager;
171599
+ if (typeof sm?.getBranch !== "function")
171600
+ return null;
171601
+ try {
171602
+ const branch = sm.getBranch.call(sm);
171603
+ if (!Array.isArray(branch))
171604
+ return null;
171605
+ entries = branch;
171606
+ } catch (error51) {
171607
+ sessionLog(sessionId ?? "pi", `collectMessageEntryIdsByRef getBranch failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
171608
+ return null;
171609
+ }
171364
171610
  }
171365
- if (!Array.isArray(entries))
171366
- return null;
171367
171611
  const entryIdByMsgRef = new Map;
171612
+ const entryIdsByFingerprint = new Map;
171368
171613
  for (const entry of entries) {
171369
171614
  if (!entry || typeof entry !== "object")
171370
171615
  continue;
@@ -171375,10 +171620,21 @@ function collectMessageEntryIdsByRef(ctx, messages, sessionId) {
171375
171620
  continue;
171376
171621
  if (!e.message || typeof e.message !== "object")
171377
171622
  continue;
171378
- entryIdByMsgRef.set(e.message, e.id);
171623
+ const message = e.message;
171624
+ entryIdByMsgRef.set(message, e.id);
171625
+ const fingerprint = piMessageEntryFingerprint(e.message);
171626
+ if (fingerprint) {
171627
+ const bucket = entryIdsByFingerprint.get(fingerprint);
171628
+ if (bucket)
171629
+ bucket.push(e.id);
171630
+ else
171631
+ entryIdsByFingerprint.set(fingerprint, [e.id]);
171632
+ }
171379
171633
  }
171380
171634
  const result = new Array(messages.length);
171381
171635
  let resolved = 0;
171636
+ let fingerprintResolved = 0;
171637
+ const consumedFingerprintIds = new Set;
171382
171638
  for (let i = 0;i < messages.length; i++) {
171383
171639
  const msg = messages[i];
171384
171640
  if (!msg || typeof msg !== "object") {
@@ -171389,15 +171645,67 @@ function collectMessageEntryIdsByRef(ctx, messages, sessionId) {
171389
171645
  if (typeof id === "string") {
171390
171646
  result[i] = id;
171391
171647
  resolved += 1;
171648
+ continue;
171649
+ }
171650
+ const fingerprint = piMessageEntryFingerprint(msg);
171651
+ const fingerprintId = fingerprint ? entryIdsByFingerprint.get(fingerprint)?.find((candidate) => !consumedFingerprintIds.has(candidate)) : undefined;
171652
+ if (typeof fingerprintId === "string") {
171653
+ consumedFingerprintIds.add(fingerprintId);
171654
+ result[i] = fingerprintId;
171655
+ resolved += 1;
171656
+ fingerprintResolved += 1;
171392
171657
  } else {
171393
171658
  result[i] = undefined;
171394
171659
  }
171395
171660
  }
171396
171661
  if (resolved < messages.length) {
171397
- log(`[magic-context][pi]${sessionId ? `[${sessionId}]` : ""} ` + `collectMessageEntryIdsByRef: resolved=${resolved}/${messages.length} ` + `(branchEntries=${entries.length}, messageEntries=${entryIdByMsgRef.size}) — ` + `unmapped slots fall through to synthesized ids; boundary lookup still works ` + `for any compartment whose start/end message is among the resolved set`);
171662
+ log(`[magic-context][pi]${sessionId ? `[${sessionId}]` : ""} ` + `collectMessageEntryIdsByRef: resolved=${resolved}/${messages.length} ` + `(fingerprint=${fingerprintResolved}, branchEntries=${entries.length}, messageEntries=${entryIdByMsgRef.size}) — ` + `unmapped slots fall through to synthesized ids; boundary lookup still works ` + `for any compartment whose start/end message is among the resolved set`);
171398
171663
  }
171399
171664
  return result;
171400
171665
  }
171666
+ function readPiBranchEntriesForContext(ctx, sessionId) {
171667
+ const sm = ctx.sessionManager;
171668
+ if (typeof sm?.getBranch !== "function")
171669
+ return null;
171670
+ try {
171671
+ const entries = sm.getBranch.call(sm);
171672
+ return Array.isArray(entries) ? entries : null;
171673
+ } catch (error51) {
171674
+ sessionLog(sessionId, `Pi branch pre-read failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
171675
+ return null;
171676
+ }
171677
+ }
171678
+ function piMessageEntryFingerprint(message) {
171679
+ if (!message || typeof message !== "object")
171680
+ return null;
171681
+ const record2 = message;
171682
+ if (typeof record2.role !== "string")
171683
+ return null;
171684
+ const firstText = firstPiTextContent(record2.content);
171685
+ const firstTextHash = crypto2.createHash("sha256").update(firstText ?? "").digest("hex").slice(0, 16);
171686
+ return JSON.stringify([
171687
+ typeof record2.responseId === "string" ? record2.responseId : null,
171688
+ typeof record2.timestamp === "number" || typeof record2.timestamp === "string" ? record2.timestamp : null,
171689
+ record2.role,
171690
+ typeof record2.toolCallId === "string" ? record2.toolCallId : null,
171691
+ firstTextHash
171692
+ ]);
171693
+ }
171694
+ function firstPiTextContent(content) {
171695
+ if (typeof content === "string")
171696
+ return content;
171697
+ if (!Array.isArray(content))
171698
+ return null;
171699
+ for (const part of content) {
171700
+ if (!part || typeof part !== "object")
171701
+ continue;
171702
+ const record2 = part;
171703
+ if (record2.type === "text" && typeof record2.text === "string") {
171704
+ return record2.text;
171705
+ }
171706
+ }
171707
+ return null;
171708
+ }
171401
171709
  function registerPiContextHandler(pi, options) {
171402
171710
  const tagger = createTagger();
171403
171711
  const schedulerConfig = options.scheduler ?? {
@@ -171429,15 +171737,16 @@ function registerPiContextHandler(pi, options) {
171429
171737
  const projectIdentity = resolveProjectIdentity(projectDirectory);
171430
171738
  updateSessionProjectTracking(sessionId, projectIdentity);
171431
171739
  logTransformTiming(sessionId, "findSessionId", tFindSession, `messages=${event.messages.length}`);
171740
+ const branchEntries = readPiBranchEntriesForContext(ctx, sessionId);
171432
171741
  const rawMessageProvider = {
171433
- readMessages: () => readPiSessionMessages(ctx),
171742
+ readMessages: () => branchEntries !== null ? convertEntriesToRawMessages([...branchEntries]) : readPiSessionMessages(ctx),
171434
171743
  readMessageById: (messageId) => readPiSessionMessageById(ctx, messageId)
171435
171744
  };
171436
171745
  rawMessageProviderUnregistersBySession.get(sessionId)?.();
171437
171746
  const unregisterRaw = setRawMessageProvider(sessionId, rawMessageProvider);
171438
171747
  rawMessageProviderUnregistersBySession.set(sessionId, unregisterRaw);
171439
171748
  scheduleReconciliation(options.db, sessionId, readRawSessionMessages);
171440
- const strictEntryIds = collectMessageEntryIdsByRef(ctx, event.messages, sessionId);
171749
+ const strictEntryIds = branchEntries === null ? null : collectMessageEntryIdsByRef(ctx, event.messages, sessionId, branchEntries);
171441
171750
  const tLastUser = performance.now();
171442
171751
  const latestUser = findLatestUserMessageIdPi(event.messages, buildPiMessageIdByIndex(event.messages, strictEntryIds));
171443
171752
  logTransformTiming(sessionId, "findLastUserMessageId", tLastUser);
@@ -171559,10 +171868,7 @@ function registerPiContextHandler(pi, options) {
171559
171868
  const histPromise = inFlightHistorian.get(sessionId);
171560
171869
  if (histPromise) {
171561
171870
  try {
171562
- await Promise.race([
171563
- histPromise,
171564
- new Promise((resolve4) => setTimeout(resolve4, 30000))
171565
- ]);
171871
+ await withTimeout(histPromise, 30000);
171566
171872
  sessionLog(sessionId, "EMERGENCY: historian wait completed (or timed out)");
171567
171873
  } catch {}
171568
171874
  }
@@ -171570,7 +171876,7 @@ function registerPiContextHandler(pi, options) {
171570
171876
  const isCacheBusting = historyRefreshSessions.has(sessionId);
171571
171877
  sessionLog(sessionId, `transform: usage=${usagePercentage.toFixed(1)}% (${usageInputTokens} tokens, limit=${usageContextLimit ?? "?"}) decision=${schedulerDecision}${forceMaterialization ? " force=true" : ""}${isEmergency ? " EMERGENCY=true" : ""}${isCacheBusting ? " busting=true" : ""}`);
171572
171878
  logTransformTiming(sessionId, "emergencyRecoveryBlock", tEmergencyRecovery);
171573
- const entryIds = collectMessageEntryIdsByRef(ctx, event.messages, sessionId) ?? undefined;
171879
+ const entryIds = strictEntryIds ?? undefined;
171574
171880
  const result = await runPipeline({
171575
171881
  db: options.db,
171576
171882
  tagger,
@@ -171592,7 +171898,9 @@ function registerPiContextHandler(pi, options) {
171592
171898
  reasoningClearing: {
171593
171899
  clearReasoningAge: options.heuristics?.clearReasoningAge ?? DEFAULT_CLEAR_REASONING_AGE
171594
171900
  },
171595
- temporalAwareness: options.injection?.temporalAwareness === true
171901
+ temporalAwareness: options.injection?.temporalAwareness === true,
171902
+ appendCompaction: resolvePiAppendCompaction(ctx),
171903
+ readBranchEntries: resolvePiReadBranchEntries(ctx)
171596
171904
  });
171597
171905
  if (options.historian) {
171598
171906
  maybeFireHistorian({
@@ -171600,7 +171908,9 @@ function registerPiContextHandler(pi, options) {
171600
171908
  sessionId,
171601
171909
  db: options.db,
171602
171910
  historian: options.historian,
171603
- isFirstContextPassForSession
171911
+ isFirstContextPassForSession,
171912
+ activeTags: result.activeTags,
171913
+ rawMessageProvider
171604
171914
  });
171605
171915
  maybeFireCompressor({
171606
171916
  ctx,
@@ -171719,6 +172029,43 @@ async function awaitInFlightHistorians() {
171719
172029
  ];
171720
172030
  await Promise.allSettled(promises);
171721
172031
  }
172032
+ function splitModelKeyForPi(modelKey) {
172033
+ if (!modelKey)
172034
+ return { providerID: undefined, modelID: undefined };
172035
+ const slash = modelKey.indexOf("/");
172036
+ if (slash <= 0 || slash === modelKey.length - 1) {
172037
+ return { providerID: undefined, modelID: undefined };
172038
+ }
172039
+ return {
172040
+ providerID: modelKey.slice(0, slash),
172041
+ modelID: modelKey.slice(slash + 1)
172042
+ };
172043
+ }
172044
+ function resolvePiHistorianTriggerInputs(args) {
172045
+ const { providerID, modelID } = splitModelKeyForPi(args.modelKey);
172046
+ let contextLimit = resolveContextLimit(providerID, modelID, {
172047
+ db: args.db,
172048
+ sessionID: args.sessionId
172049
+ });
172050
+ if ((providerID === undefined || modelID === undefined) && typeof args.usageContextLimit === "number" && Number.isFinite(args.usageContextLimit) && args.usageContextLimit > 0) {
172051
+ contextLimit = args.usageContextLimit;
172052
+ }
172053
+ const executeThresholdPercentage = resolveExecuteThreshold(args.historian.executeThresholdPercentage ?? 65, args.modelKey, 65, {
172054
+ tokensConfig: args.historian.executeThresholdTokens,
172055
+ contextLimit,
172056
+ sessionId: args.sessionId
172057
+ });
172058
+ return {
172059
+ executeThresholdPercentage,
172060
+ triggerBudget: deriveTriggerBudget(contextLimit, executeThresholdPercentage),
172061
+ autoDropToolAge: args.historian.autoDropToolAge ?? 100,
172062
+ protectedTags: args.historian.protectedTags,
172063
+ clearReasoningAge: args.historian.clearReasoningAge ?? DEFAULT_CLEAR_REASONING_AGE,
172064
+ dropToolStructure: args.historian.dropToolStructure ?? true,
172065
+ commitClusterTrigger: args.historian.commitClusterTrigger,
172066
+ contextLimit
172067
+ };
172068
+ }
171722
172069
  function resolveHistoryBudgetTokensForPi(args) {
171723
172070
  const {
171724
172071
  historyBudgetPercentage,
@@ -171777,6 +172124,10 @@ function maybeFireCompressor(args) {
171777
172124
  maxCompartmentsPerPass: compressor.maxCompartmentsPerPass,
171778
172125
  graceCompartments: compressor.graceCompartments,
171779
172126
  onPublished: () => {
172127
+ if (!isContextHandlerSessionActive(sessionId)) {
172128
+ sessionLog(sessionId, "compressor publication ignored: session was cleared");
172129
+ return;
172130
+ }
171780
172131
  signalPiDeferredHistoryRefresh(sessionId);
171781
172132
  signalPiDeferredMaterialization(sessionId);
171782
172133
  historian.onStatusChange?.(ctx, sessionId);
@@ -171789,7 +172140,9 @@ function maybeFireCompressor(args) {
171789
172140
  sessionLog(sessionId, `compressor failed in background: ${err instanceof Error ? err.message : String(err)}`);
171790
172141
  }).finally(() => {
171791
172142
  inFlightCompressor.delete(sessionId);
171792
- historian.onStatusChange?.(ctx, sessionId);
172143
+ if (isContextHandlerSessionActive(sessionId)) {
172144
+ historian.onStatusChange?.(ctx, sessionId);
172145
+ }
171793
172146
  });
171794
172147
  inFlightCompressor.set(sessionId, runPromise);
171795
172148
  }
@@ -171834,6 +172187,10 @@ function spawnPiHistorianRun(args) {
171834
172187
  memoryEnabled: historian.memoryEnabled,
171835
172188
  autoPromote: historian.autoPromote,
171836
172189
  onPublished: () => {
172190
+ if (!isContextHandlerSessionActive(sessionId)) {
172191
+ sessionLog(sessionId, "historian publication ignored: session was cleared");
172192
+ return;
172193
+ }
171837
172194
  try {
171838
172195
  clearEmergencyRecovery(db, sessionId);
171839
172196
  } catch (err) {
@@ -171846,7 +172203,9 @@ function spawnPiHistorianRun(args) {
171846
172203
  }).finally(() => {
171847
172204
  inFlightHistorian.delete(sessionId);
171848
172205
  unregister();
171849
- historian.onStatusChange?.(ctx, sessionId);
172206
+ if (isContextHandlerSessionActive(sessionId)) {
172207
+ historian.onStatusChange?.(ctx, sessionId);
172208
+ }
171850
172209
  });
171851
172210
  inFlightHistorian.set(sessionId, runPromise);
171852
172211
  historian.onStatusChange?.(ctx, sessionId);
@@ -171877,7 +172236,10 @@ function maybeFireHistorian(args) {
171877
172236
  return;
171878
172237
  }
171879
172238
  let usage;
172239
+ let usageContextLimit;
171880
172240
  try {
172241
+ const piUsage = ctx.getContextUsage?.();
172242
+ usageContextLimit = typeof piUsage?.contextWindow === "number" && piUsage.contextWindow > 0 ? piUsage.contextWindow : undefined;
171881
172243
  const sessionMetaForUsage = getOrCreateSessionMeta(db, sessionId);
171882
172244
  if (sessionMetaForUsage.lastContextPercentage > 0 && sessionMetaForUsage.lastInputTokens > 0) {
171883
172245
  usage = {
@@ -171886,7 +172248,6 @@ function maybeFireHistorian(args) {
171886
172248
  };
171887
172249
  sessionLog(sessionId, `historian trigger eval: usage=${usage.percentage.toFixed(1)}% (${usage.inputTokens} tokens) [from session_meta], checking trigger...`);
171888
172250
  } else {
171889
- const piUsage = ctx.getContextUsage?.();
171890
172251
  if (!piUsage || piUsage.tokens === null || piUsage.percent === null || piUsage.contextWindow === 0) {
171891
172252
  sessionLog(sessionId, `historian trigger eval: no usage info yet (tokens=${piUsage?.tokens ?? "<no piUsage>"}, percent=${piUsage?.percent ?? "<no piUsage>"}, contextWindow=${piUsage?.contextWindow ?? "<no piUsage>"})`);
171892
172253
  return;
@@ -171901,7 +172262,7 @@ function maybeFireHistorian(args) {
171901
172262
  sessionLog(sessionId, `historian trigger eval: getContextUsage threw: ${err instanceof Error ? err.message : String(err)}`);
171902
172263
  return;
171903
172264
  }
171904
- const provider2 = {
172265
+ const provider2 = args.rawMessageProvider ?? {
171905
172266
  readMessages: () => readPiSessionMessages(ctx)
171906
172267
  };
171907
172268
  const unregister = setRawMessageProvider(sessionId, provider2);
@@ -171933,7 +172294,15 @@ Historian previously failed ${failureState.failureCount} time(s), so magic-conte
171933
172294
  }
171934
172295
  }
171935
172296
  const sessionMeta = getOrCreateSessionMeta(db, sessionId);
171936
- const trigger = checkCompartmentTrigger(db, sessionId, sessionMeta, usage, 0, resolveExecuteThreshold(historian.executeThresholdPercentage ?? 65, liveModelBySession.get(sessionId), 65), historian.triggerBudget ?? 8000);
172297
+ const modelKey = liveModelBySession.get(sessionId);
172298
+ const triggerInputs = resolvePiHistorianTriggerInputs({
172299
+ db,
172300
+ sessionId,
172301
+ historian,
172302
+ modelKey,
172303
+ usageContextLimit
172304
+ });
172305
+ const trigger = checkCompartmentTrigger(db, sessionId, sessionMeta, usage, 0, triggerInputs.executeThresholdPercentage, triggerInputs.triggerBudget, triggerInputs.autoDropToolAge, triggerInputs.protectedTags, triggerInputs.clearReasoningAge, triggerInputs.dropToolStructure, triggerInputs.commitClusterTrigger, args.activeTags);
171937
172306
  if (!trigger.shouldFire) {
171938
172307
  sessionLog(sessionId, `historian trigger eval: shouldFire=false (no trigger condition met)`);
171939
172308
  return;
@@ -171951,12 +172320,17 @@ Historian previously failed ${failureState.failureCount} time(s), so magic-conte
171951
172320
  } catch (err) {
171952
172321
  const message = err instanceof Error ? err.message : String(err);
171953
172322
  sessionLog(sessionId, `historian trigger eval failed: ${message}`);
172323
+ } finally {
171954
172324
  if (!triggered)
171955
172325
  unregister();
171956
172326
  }
171957
172327
  }
171958
172328
  async function runPipeline(args) {
171959
172329
  let executedWorkThisPass = false;
172330
+ let historyWasConsumedThisPass = false;
172331
+ let suppressDeferredHistoryDrain = false;
172332
+ let casLost = false;
172333
+ const deferredHistoryWasPendingAtPassStart = deferredHistoryRefreshSessions.has(args.sessionId);
171960
172334
  if (args.temporalAwareness) {
171961
172335
  const tTemporal = performance.now();
171962
172336
  try {
@@ -171997,7 +172371,7 @@ async function runPipeline(args) {
171997
172371
  }
171998
172372
  const hasPendingMaterializeSignal = hasPendingMaterialization(args.sessionId);
171999
172373
  const deferredMaterializationWasPending = deferredMaterializationSessions.has(args.sessionId);
172000
- const deferredHistoryRefreshWasPending = deferredHistoryRefreshSessions.has(args.sessionId);
172374
+ const deferredHistoryRefreshWasPending = deferredHistoryWasPendingAtPassStart;
172001
172375
  const pendingOps = getPendingOps(args.db, args.sessionId);
172002
172376
  const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal;
172003
172377
  const canConsumeDeferredLate = baseShouldApplyPendingOps || shouldRunHeuristics;
@@ -172140,9 +172514,10 @@ async function runPipeline(args) {
172140
172514
  injectionResult = injectSessionHistoryIntoPi(args.db, args.sessionId, args.messages, args.isCacheBusting || deferredHistoryRefresh, args.projectIdentity, args.injection.injectionBudgetTokens, args.injection.temporalAwareness, args.entryIds);
172141
172515
  if (args.isCacheBusting) {
172142
172516
  historyRefreshSessions.delete(args.sessionId);
172517
+ historyWasConsumedThisPass = true;
172143
172518
  }
172144
172519
  if (deferredHistoryRefresh) {
172145
- consumeDeferredHistoryRefresh(args.sessionId);
172520
+ historyWasConsumedThisPass = true;
172146
172521
  }
172147
172522
  logTransformTiming(args.sessionId, "prepareCompartmentInjection", tInjection);
172148
172523
  logTransformTiming(args.sessionId, "compartmentPhase", tInjection);
@@ -172156,6 +172531,34 @@ async function runPipeline(args) {
172156
172531
  messages: args.messages,
172157
172532
  isCacheBusting: args.isCacheBusting
172158
172533
  });
172534
+ const deferredHistoryDrainEligible = historyWasConsumedThisPass && deferredHistoryWasPendingAtPassStart && !suppressDeferredHistoryDrain && !casLost;
172535
+ if (deferredHistoryDrainEligible) {
172536
+ try {
172537
+ const pending = getPendingPiCompactionMarkerState(args.db, args.sessionId);
172538
+ if (!pending) {
172539
+ consumeDeferredHistoryRefresh(args.sessionId);
172540
+ } else if (!args.appendCompaction || !args.readBranchEntries) {
172541
+ suppressDeferredHistoryDrain = true;
172542
+ sessionLog(args.sessionId, "Pi compaction-marker drain skipped: sessionManager appendCompaction/getBranch unavailable; preserving deferred-history signal");
172543
+ } else {
172544
+ const outcome = applyDeferredPiCompactionMarker({
172545
+ db: args.db,
172546
+ appendCompaction: args.appendCompaction,
172547
+ readBranchEntries: args.readBranchEntries
172548
+ }, args.sessionId, pending);
172549
+ if (outcome.kind === "retryable-failure") {
172550
+ sessionLog(args.sessionId, `Pi compaction-marker drain retryable failure: ${outcome.error.message}`);
172551
+ } else if (clearPendingPiCompactionMarkerStateIf(args.db, args.sessionId, pending)) {
172552
+ consumeDeferredHistoryRefresh(args.sessionId);
172553
+ } else {
172554
+ casLost = true;
172555
+ sessionLog(args.sessionId, "CAS-clear failed (newer blob written or another actor cleared); preserving deferred-history signal");
172556
+ }
172557
+ }
172558
+ } catch (err) {
172559
+ sessionLog(args.sessionId, `Pi compaction-marker drain failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
172560
+ }
172561
+ }
172159
172562
  if (executedWorkThisPass) {
172160
172563
  try {
172161
172564
  const currentFlag = peekDeferredExecutePending(args.db, args.sessionId);
@@ -172185,7 +172588,8 @@ async function runPipeline(args) {
172185
172588
  heuristicsResult,
172186
172589
  injectionResult,
172187
172590
  targetCount: targets.size,
172188
- reasoningWatermark: getOrCreateSessionMeta(args.db, args.sessionId).clearedReasoningThroughTag ?? 0
172591
+ reasoningWatermark: getOrCreateSessionMeta(args.db, args.sessionId).clearedReasoningThroughTag ?? 0,
172592
+ activeTags
172189
172593
  };
172190
172594
  }
172191
172595
  function applyRollingNudge(args) {
@@ -172217,11 +172621,15 @@ function applyStickyTurnReminder(args) {
172217
172621
  const messageIdByIndex = buildPiMessageIdByIndex(args.messages, args.entryIds);
172218
172622
  if (reminder.messageId) {
172219
172623
  const reinjected = appendReminderToUserMessageByIdPi(args.messages, messageIdByIndex, reminder.messageId, reminder.text);
172220
- if (!reinjected && args.isCacheBustingPass) {
172624
+ if (!reinjected && args.isCacheBustingPass && args.entryIds !== null) {
172221
172625
  clearPersistedStickyTurnReminder(args.db, args.sessionId);
172222
172626
  }
172223
172627
  return args.messages;
172224
172628
  }
172629
+ if (args.entryIds === null) {
172630
+ sessionLog(args.sessionId, "Pi sticky turn reminder: strict resolution failed; replay-only until next pass");
172631
+ return args.messages;
172632
+ }
172225
172633
  const latest = findLatestUserMessageIdPi(args.messages, messageIdByIndex);
172226
172634
  if (latest) {
172227
172635
  appendReminderToPiUserMessage(args.messages[latest.index], reminder.text);
@@ -172303,8 +172711,6 @@ function buildPiMessageIdByIndex(messages, entryIds) {
172303
172711
  const messageId = messages[index]?.id;
172304
172712
  if (typeof messageId === "string") {
172305
172713
  ids.set(index, messageId);
172306
- } else if (entryIds === null) {
172307
- ids.set(index, `pi:${index}:${readTimestamp(messages[index])}`);
172308
172714
  }
172309
172715
  }
172310
172716
  return ids;
@@ -172333,10 +172739,6 @@ function appendReminderToUserMessageByIdPi(messages, messageIdByIndex, messageId
172333
172739
  }
172334
172740
  return false;
172335
172741
  }
172336
- function readTimestamp(message) {
172337
- const ts = message.timestamp;
172338
- return typeof ts === "number" && Number.isFinite(ts) ? String(ts) : "no-ts";
172339
- }
172340
172742
  function appendReminderToPiUserMessage(message, reminder) {
172341
172743
  if (message.role !== "user")
172342
172744
  return;
@@ -172363,6 +172765,7 @@ function appendReminderToPiUserMessage(message, reminder) {
172363
172765
  contentArr.push({ type: "text", text: reminder.trimStart() });
172364
172766
  }
172365
172767
  function clearContextHandlerSession(sessionId) {
172768
+ activeContextHandlerSessions.delete(sessionId);
172366
172769
  clearAutoSearchForPiSession(sessionId);
172367
172770
  lastEmergencyNotificationAtMs.delete(sessionId);
172368
172771
  historyRefreshSessions.delete(sessionId);
@@ -173501,7 +173904,7 @@ async function executePartialRecompInternal(deps, range) {
173501
173904
  }
173502
173905
  deps.onCompartmentStatePublished?.(sessionId);
173503
173906
  const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
173504
- if (deps.experimentalCompactionMarkers && lastEnd > 0) {
173907
+ if (lastEnd > 0) {
173505
173908
  updateCompactionMarkerAfterPublication(db, sessionId, lastEnd, deps.directory);
173506
173909
  const stalePending = getPendingCompactionMarkerState(db, sessionId);
173507
173910
  if (stalePending) {
@@ -173760,7 +174163,7 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
173760
174163
  if (lastCompartmentEnd2 > 0) {
173761
174164
  queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd2);
173762
174165
  }
173763
- if (deps.experimentalCompactionMarkers && lastCompartmentEnd2 > 0) {
174166
+ if (lastCompartmentEnd2 > 0) {
173764
174167
  updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd2, deps.directory);
173765
174168
  const stalePending = getPendingCompactionMarkerState(db, sessionId);
173766
174169
  if (stalePending) {
@@ -174184,6 +174587,7 @@ Historian recomp started. Rebuilding compartments and facts from raw Pi session
174184
174587
  text: result,
174185
174588
  level: inferLevel(result)
174186
174589
  });
174590
+ queueAndApplyPiRecompMarker({ db: deps.db, sessionId, ctx });
174187
174591
  signalPiHistoryRefresh(sessionId);
174188
174592
  signalPiPendingMaterialization(sessionId);
174189
174593
  clearPiCompressorState(sessionId);
@@ -174206,6 +174610,60 @@ ${describeError(error51).brief}`,
174206
174610
  }
174207
174611
  });
174208
174612
  }
174613
+ function queueAndApplyPiRecompMarker(args) {
174614
+ const appendCompaction = resolvePiAppendCompaction2(args.ctx);
174615
+ const readBranchEntries = resolvePiReadBranchEntries2(args.ctx);
174616
+ if (!appendCompaction || !readBranchEntries)
174617
+ return;
174618
+ const compartments = getCompartments(args.db, args.sessionId);
174619
+ const last = compartments[compartments.length - 1];
174620
+ if (!last)
174621
+ return;
174622
+ let firstKeptEntryId = null;
174623
+ try {
174624
+ firstKeptEntryId = findFirstKeptEntryId(readBranchEntries(), last.endMessage);
174625
+ } catch {
174626
+ firstKeptEntryId = null;
174627
+ }
174628
+ if (!firstKeptEntryId || last.endMessageId.length === 0)
174629
+ return;
174630
+ const pending = {
174631
+ firstKeptEntryId,
174632
+ endMessageId: last.endMessageId,
174633
+ ordinal: last.endMessage,
174634
+ tokensBefore: 0,
174635
+ summary: buildPiCompactionSummary(compartments),
174636
+ publishedAt: Date.now()
174637
+ };
174638
+ setPendingPiCompactionMarkerState(args.db, args.sessionId, pending);
174639
+ const outcome = applyDeferredPiCompactionMarker({ db: args.db, appendCompaction, readBranchEntries }, args.sessionId, pending);
174640
+ if (outcome.kind === "retryable-failure") {
174641
+ signalPiDeferredHistoryRefresh(args.sessionId);
174642
+ return;
174643
+ }
174644
+ if (!clearPendingPiCompactionMarkerStateIf(args.db, args.sessionId, pending)) {
174645
+ signalPiDeferredHistoryRefresh(args.sessionId);
174646
+ }
174647
+ }
174648
+ function resolvePiAppendCompaction2(ctx) {
174649
+ const sm = ctx?.sessionManager;
174650
+ if (typeof sm?.appendCompaction !== "function")
174651
+ return;
174652
+ return sm.appendCompaction.bind(sm);
174653
+ }
174654
+ function resolvePiReadBranchEntries2(ctx) {
174655
+ const sm = ctx?.sessionManager;
174656
+ if (typeof sm?.getBranch !== "function")
174657
+ return;
174658
+ return () => {
174659
+ try {
174660
+ const entries = sm.getBranch?.call(sm);
174661
+ return Array.isArray(entries) ? entries : [];
174662
+ } catch {
174663
+ return [];
174664
+ }
174665
+ };
174666
+ }
174209
174667
  function parseRecompArgs(raw) {
174210
174668
  const trimmed = raw.trim();
174211
174669
  if (trimmed.length === 0)
@@ -174477,7 +174935,7 @@ import {
174477
174935
  // package.json
174478
174936
  var package_default = {
174479
174937
  name: "@cortexkit/pi-magic-context",
174480
- version: "0.21.2",
174938
+ version: "0.21.5",
174481
174939
  type: "module",
174482
174940
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
174483
174941
  main: "dist/index.js",
@@ -179579,8 +180037,15 @@ function createCtxNoteTool(deps) {
179579
180037
  if (typeof params.note_id !== "number") {
179580
180038
  return err3("Error: 'note_id' is required when action is 'dismiss'.");
179581
180039
  }
179582
- const dismissed = dismissNote(deps.db, params.note_id);
179583
- return ok3(dismissed ? `Note #${params.note_id} dismissed.` : `Note #${params.note_id} not found or already dismissed.`);
180040
+ const projectIdentity = resolveProjectIdentity(ctx.cwd);
180041
+ if (!projectIdentity) {
180042
+ return err3("Error: Could not resolve project identity for note dismiss.");
180043
+ }
180044
+ const dismissed = dismissNote(deps.db, params.note_id, {
180045
+ projectPath: projectIdentity,
180046
+ sessionId
180047
+ });
180048
+ return dismissed ? ok3(`Note #${params.note_id} dismissed.`) : err3(`Error: Note #${params.note_id} not found in your session/project or already dismissed.`);
179584
180049
  }
179585
180050
  if (action2 === "update") {
179586
180051
  if (typeof params.note_id !== "number") {
@@ -179594,9 +180059,16 @@ function createCtxNoteTool(deps) {
179594
180059
  if (!updates.content && !updates.surfaceCondition) {
179595
180060
  return err3("Error: Provide 'content' and/or 'surface_condition' to update.");
179596
180061
  }
179597
- const updated = updateNote(deps.db, params.note_id, updates);
180062
+ const projectIdentity = resolveProjectIdentity(ctx.cwd);
180063
+ if (!projectIdentity) {
180064
+ return err3("Error: Could not resolve project identity for note update.");
180065
+ }
180066
+ const updated = updateNote(deps.db, params.note_id, updates, {
180067
+ projectPath: projectIdentity,
180068
+ sessionId
180069
+ });
179598
180070
  if (!updated) {
179599
- return err3(`Note #${params.note_id} not found.`);
180071
+ return err3(`Error: Note #${params.note_id} not found in your session/project.`);
179600
180072
  }
179601
180073
  const parts = [];
179602
180074
  if (updates.content)
@@ -180207,7 +180679,6 @@ function resolveHistorianFromConfig(config2) {
180207
180679
  if (!model || model.length === 0)
180208
180680
  return;
180209
180681
  const historianContextLimit = resolveHistorianContextLimit(model);
180210
- const triggerBudget = deriveTriggerBudget(historianContextLimit, 65);
180211
180682
  const historianChunkTokens = deriveHistorianChunkTokens(historianContextLimit);
180212
180683
  const fbRaw = historian?.fallback_models;
180213
180684
  const fallbackModels = typeof fbRaw === "string" ? [fbRaw] : fbRaw;
@@ -180220,7 +180691,12 @@ function resolveHistorianFromConfig(config2) {
180220
180691
  twoPass: historian?.two_pass === true,
180221
180692
  thinkingLevel: historian?.thinking_level,
180222
180693
  executeThresholdPercentage: config2.execute_threshold_percentage,
180223
- triggerBudget,
180694
+ executeThresholdTokens: config2.execute_threshold_tokens,
180695
+ commitClusterTrigger: config2.commit_cluster_trigger,
180696
+ autoDropToolAge: config2.auto_drop_tool_age,
180697
+ protectedTags: config2.protected_tags,
180698
+ clearReasoningAge: config2.clear_reasoning_age,
180699
+ dropToolStructure: config2.drop_tool_structure,
180224
180700
  historyBudgetPercentage: config2.history_budget_percentage,
180225
180701
  compressor: {
180226
180702
  enabled: config2.compressor.enabled,
@@ -180270,6 +180746,17 @@ async function src_default2(pi) {
180270
180746
  const projectDir = process.cwd();
180271
180747
  const projectIdentity = resolveProjectIdentity(projectDir);
180272
180748
  const seenDreamerProjectIdentities = new Set([projectIdentity]);
180749
+ try {
180750
+ const pendingPiMarkerSessions = getSessionsWithPendingPiMarker(db);
180751
+ for (const sid of pendingPiMarkerSessions) {
180752
+ signalPiDeferredHistoryRefresh(sid);
180753
+ }
180754
+ if (pendingPiMarkerSessions.length > 0) {
180755
+ log(`${PREFIX2} rehydrated ${pendingPiMarkerSessions.length} Pi deferred compaction marker session(s)`);
180756
+ }
180757
+ } catch (err5) {
180758
+ warn(`Magic Context (pi) failed to rehydrate deferred Pi compaction markers: ${err5 instanceof Error ? err5.message : String(err5)}`);
180759
+ }
180273
180760
  info(`loaded v${PLUGIN_VERSION} | harness=pi | db=${dbPath} | ` + `project=${projectIdentity} | dir=${projectDir}`);
180274
180761
  const { config: config2, warnings, loadedFromPaths } = loadPiConfig({
180275
180762
  cwd: projectDir
@@ -180625,18 +181112,12 @@ ${block}` : event.systemPrompt;
180625
181112
  pi.on("session_shutdown", async (_event, ctx) => {
180626
181113
  const SHUTDOWN_DRAIN_MS = 5000;
180627
181114
  try {
180628
- await Promise.race([
180629
- awaitInFlightHistorians(),
180630
- new Promise((resolve4) => setTimeout(resolve4, SHUTDOWN_DRAIN_MS))
180631
- ]);
181115
+ await withTimeout(awaitInFlightHistorians(), SHUTDOWN_DRAIN_MS);
180632
181116
  } catch (err5) {
180633
181117
  warn("shutdown: historian drain threw:", err5);
180634
181118
  }
180635
181119
  try {
180636
- await Promise.race([
180637
- awaitInFlightDreamers(),
180638
- new Promise((resolve4) => setTimeout(resolve4, SHUTDOWN_DRAIN_MS))
180639
- ]);
181120
+ await withTimeout(awaitInFlightDreamers(), SHUTDOWN_DRAIN_MS);
180640
181121
  } catch (err5) {
180641
181122
  warn("shutdown: dreamer drain threw:", err5);
180642
181123
  }