@cortexkit/pi-magic-context 0.22.3 → 0.22.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
@@ -46,214 +46,6 @@ var __export = (target, all) => {
46
46
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
47
47
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
48
48
 
49
- // ../plugin/src/shared/harness.ts
50
- function setHarness(value) {
51
- if (harnessLocked && currentHarness !== value) {
52
- throw new Error(`Magic Context: harness already locked to "${currentHarness}"; cannot change to "${value}"`);
53
- }
54
- currentHarness = value;
55
- harnessLocked = true;
56
- }
57
- function getHarness() {
58
- return currentHarness;
59
- }
60
- var currentHarness = "opencode", harnessLocked = false;
61
-
62
- // ../plugin/src/shared/data-path.ts
63
- import * as os from "node:os";
64
- import * as path2 from "node:path";
65
- function getDataDir() {
66
- return process.env.XDG_DATA_HOME ?? path2.join(os.homedir(), ".local", "share");
67
- }
68
- function getMagicContextTempDir(harness = getHarness()) {
69
- return path2.join(os.tmpdir(), harness, "magic-context");
70
- }
71
- function getMagicContextLogPath(harness = getHarness()) {
72
- return path2.join(getMagicContextTempDir(harness), "magic-context.log");
73
- }
74
- function getProjectMagicContextDir(directory) {
75
- return path2.join(directory, ".opencode", "magic-context");
76
- }
77
- function getProjectMagicContextHistorianDir(directory) {
78
- return path2.join(getProjectMagicContextDir(directory), "historian");
79
- }
80
- function getOpenCodeStorageDir() {
81
- return path2.join(getDataDir(), "opencode", "storage");
82
- }
83
- function getMagicContextStorageDir() {
84
- return path2.join(getDataDir(), "cortexkit", "magic-context");
85
- }
86
- function getLegacyOpenCodeMagicContextStorageDir() {
87
- return path2.join(getOpenCodeStorageDir(), "plugin", "magic-context");
88
- }
89
- var init_data_path = () => {};
90
-
91
- // ../plugin/src/shared/logger.ts
92
- import * as fs from "node:fs";
93
- import * as path3 from "node:path";
94
- function ensureDir(filePath) {
95
- const dir = path3.dirname(filePath);
96
- if (dir === lastEnsuredDir)
97
- return;
98
- try {
99
- fs.mkdirSync(dir, { recursive: true });
100
- lastEnsuredDir = dir;
101
- } catch {}
102
- }
103
- function flush() {
104
- if (flushTimer) {
105
- clearTimeout(flushTimer);
106
- flushTimer = null;
107
- }
108
- if (buffer.length === 0)
109
- return;
110
- const data = buffer.join("");
111
- buffer = [];
112
- try {
113
- const logFile = getMagicContextLogPath();
114
- ensureDir(logFile);
115
- fs.appendFileSync(logFile, data);
116
- } catch {}
117
- }
118
- function scheduleFlush() {
119
- if (flushTimer)
120
- return;
121
- flushTimer = setTimeout(() => {
122
- flushTimer = null;
123
- flush();
124
- }, FLUSH_INTERVAL_MS);
125
- }
126
- function log(message, data) {
127
- if (isTestEnv)
128
- return;
129
- try {
130
- const timestamp = new Date().toISOString();
131
- const serialized = data === undefined ? "" : data instanceof Error ? ` ${data.message}${data.stack ? `
132
- ${data.stack}` : ""}` : ` ${JSON.stringify(data)}`;
133
- buffer.push(`[${timestamp}] ${message}${serialized}
134
- `);
135
- if (buffer.length >= BUFFER_SIZE_LIMIT) {
136
- flush();
137
- } else {
138
- scheduleFlush();
139
- }
140
- } catch {}
141
- }
142
- function sessionLog(sessionId, message, data) {
143
- log(`[magic-context][${sessionId}] ${message}`, data);
144
- }
145
- var isTestEnv = false, buffer, flushTimer = null, FLUSH_INTERVAL_MS = 500, BUFFER_SIZE_LIMIT = 50, lastEnsuredDir = null;
146
- var init_logger = __esm(() => {
147
- init_data_path();
148
- buffer = [];
149
- if (!isTestEnv) {
150
- process.on("exit", flush);
151
- }
152
- });
153
-
154
- // ../plugin/src/shared/sqlite.ts
155
- function buildNodeSqliteDatabaseClass(DatabaseSync) {
156
- const SAVEPOINT = "mc_tx_sp";
157
-
158
- class NodeSqliteDatabase extends DatabaseSync {
159
- constructor(filename, options) {
160
- const translated = { ...options };
161
- if (options && "readonly" in options) {
162
- translated.readOnly = options.readonly;
163
- delete translated.readonly;
164
- }
165
- super(typeof filename === "string" ? filename : ":memory:", translated);
166
- }
167
- transaction(fn) {
168
- const self = this;
169
- const wrapped = function(...args) {
170
- const nested = self.isTransaction === true;
171
- self.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : "BEGIN");
172
- try {
173
- const result = fn.apply(this, args);
174
- self.exec(nested ? `RELEASE ${SAVEPOINT}` : "COMMIT");
175
- return result;
176
- } catch (error) {
177
- if (nested) {
178
- self.exec(`ROLLBACK TO ${SAVEPOINT}`);
179
- self.exec(`RELEASE ${SAVEPOINT}`);
180
- } else {
181
- self.exec("ROLLBACK");
182
- }
183
- throw error;
184
- }
185
- };
186
- return wrapped;
187
- }
188
- }
189
- return NodeSqliteDatabase;
190
- }
191
- var isBun, bunSpec, nodeSpec, sqliteModule, DatabaseImpl, Database;
192
- var init_sqlite = __esm(async () => {
193
- isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
194
- bunSpec = "bun:" + "sqlite";
195
- nodeSpec = "node:" + "sqlite";
196
- sqliteModule = isBun ? await import(bunSpec) : await import(nodeSpec);
197
- DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
198
- Database = DatabaseImpl;
199
- });
200
-
201
- // ../plugin/src/shared/sqlite-helpers.ts
202
- function closeQuietly(db) {
203
- if (!db)
204
- return;
205
- try {
206
- db.close();
207
- } catch {}
208
- }
209
-
210
- // ../plugin/src/hooks/magic-context/read-session-db.ts
211
- import { existsSync } from "node:fs";
212
- import { join as join2 } from "node:path";
213
- function getOpenCodeDbPath() {
214
- return join2(getDataDir(), "opencode", "opencode.db");
215
- }
216
- function openCodeDbExists() {
217
- return existsSync(getOpenCodeDbPath());
218
- }
219
- function closeCachedReadOnlyDb() {
220
- if (!cachedReadOnlyDb) {
221
- return;
222
- }
223
- try {
224
- closeQuietly(cachedReadOnlyDb.db);
225
- } catch (error) {
226
- log("[magic-context] failed to close cached OpenCode read-only DB:", error);
227
- } finally {
228
- cachedReadOnlyDb = null;
229
- }
230
- }
231
- function getReadOnlySessionDb() {
232
- const dbPath = getOpenCodeDbPath();
233
- if (cachedReadOnlyDb?.path === dbPath) {
234
- return cachedReadOnlyDb.db;
235
- }
236
- closeCachedReadOnlyDb();
237
- const db = new Database(dbPath, { readonly: true });
238
- cachedReadOnlyDb = { path: dbPath, db };
239
- return db;
240
- }
241
- function withReadOnlySessionDb(fn) {
242
- return fn(getReadOnlySessionDb());
243
- }
244
- function getRawSessionMessageCountFromDb(db, sessionId) {
245
- const row = db.prepare(`SELECT COUNT(*) as count FROM message WHERE session_id = ?
246
- AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
247
- AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
248
- return typeof row?.count === "number" ? row.count : 0;
249
- }
250
- var cachedReadOnlyDb = null;
251
- var init_read_session_db = __esm(async () => {
252
- init_data_path();
253
- init_logger();
254
- await init_sqlite();
255
- });
256
-
257
49
  // ../../node_modules/.bun/esprima@4.0.1/node_modules/esprima/dist/esprima.js
258
50
  var require_esprima = __commonJS((exports, module) => {
259
51
  (function webpackUniversalModuleDefinition(root, factory) {
@@ -8281,9 +8073,129 @@ function hasGitDir(canonical) {
8281
8073
  return false;
8282
8074
  }
8283
8075
  }
8076
+ function normalizeStoredProjectPath(rawOrStored) {
8077
+ if (rawOrStored.startsWith("git:") || rawOrStored.startsWith("dir:")) {
8078
+ return rawOrStored;
8079
+ }
8080
+ try {
8081
+ return resolveProjectIdentity(rawOrStored);
8082
+ } catch {
8083
+ return directoryFallback(rawOrStored);
8084
+ }
8085
+ }
8086
+ function storedPathBelongsToIdentity(storedProjectPath, projectIdentity) {
8087
+ return storedProjectPath === projectIdentity || normalizeStoredProjectPath(storedProjectPath) === projectIdentity;
8088
+ }
8284
8089
 
8285
- // ../plugin/src/features/magic-context/message-index-async.ts
8286
- init_logger();
8090
+ // ../plugin/src/shared/logger.ts
8091
+ import * as fs from "node:fs";
8092
+ import * as path3 from "node:path";
8093
+
8094
+ // ../plugin/src/shared/data-path.ts
8095
+ import * as os from "node:os";
8096
+ import * as path2 from "node:path";
8097
+
8098
+ // ../plugin/src/shared/harness.ts
8099
+ var currentHarness = "opencode";
8100
+ var harnessLocked = false;
8101
+ function setHarness(value) {
8102
+ if (harnessLocked && currentHarness !== value) {
8103
+ throw new Error(`Magic Context: harness already locked to "${currentHarness}"; cannot change to "${value}"`);
8104
+ }
8105
+ currentHarness = value;
8106
+ harnessLocked = true;
8107
+ }
8108
+ function getHarness() {
8109
+ return currentHarness;
8110
+ }
8111
+
8112
+ // ../plugin/src/shared/data-path.ts
8113
+ function getDataDir() {
8114
+ return process.env.XDG_DATA_HOME ?? path2.join(os.homedir(), ".local", "share");
8115
+ }
8116
+ function getMagicContextTempDir(harness = getHarness()) {
8117
+ return path2.join(os.tmpdir(), harness, "magic-context");
8118
+ }
8119
+ function getMagicContextLogPath(harness = getHarness()) {
8120
+ return path2.join(getMagicContextTempDir(harness), "magic-context.log");
8121
+ }
8122
+ function getProjectMagicContextDir(directory) {
8123
+ return path2.join(directory, ".opencode", "magic-context");
8124
+ }
8125
+ function getProjectMagicContextHistorianDir(directory) {
8126
+ return path2.join(getProjectMagicContextDir(directory), "historian");
8127
+ }
8128
+ function getOpenCodeStorageDir() {
8129
+ return path2.join(getDataDir(), "opencode", "storage");
8130
+ }
8131
+ function getMagicContextStorageDir() {
8132
+ return path2.join(getDataDir(), "cortexkit", "magic-context");
8133
+ }
8134
+ function getLegacyOpenCodeMagicContextStorageDir() {
8135
+ return path2.join(getOpenCodeStorageDir(), "plugin", "magic-context");
8136
+ }
8137
+
8138
+ // ../plugin/src/shared/logger.ts
8139
+ var isTestEnv = false;
8140
+ var buffer = [];
8141
+ var flushTimer = null;
8142
+ var FLUSH_INTERVAL_MS = 500;
8143
+ var BUFFER_SIZE_LIMIT = 50;
8144
+ var lastEnsuredDir = null;
8145
+ function ensureDir(filePath) {
8146
+ const dir = path3.dirname(filePath);
8147
+ if (dir === lastEnsuredDir)
8148
+ return;
8149
+ try {
8150
+ fs.mkdirSync(dir, { recursive: true });
8151
+ lastEnsuredDir = dir;
8152
+ } catch {}
8153
+ }
8154
+ function flush() {
8155
+ if (flushTimer) {
8156
+ clearTimeout(flushTimer);
8157
+ flushTimer = null;
8158
+ }
8159
+ if (buffer.length === 0)
8160
+ return;
8161
+ const data = buffer.join("");
8162
+ buffer = [];
8163
+ try {
8164
+ const logFile = getMagicContextLogPath();
8165
+ ensureDir(logFile);
8166
+ fs.appendFileSync(logFile, data);
8167
+ } catch {}
8168
+ }
8169
+ function scheduleFlush() {
8170
+ if (flushTimer)
8171
+ return;
8172
+ flushTimer = setTimeout(() => {
8173
+ flushTimer = null;
8174
+ flush();
8175
+ }, FLUSH_INTERVAL_MS);
8176
+ }
8177
+ function log(message, data) {
8178
+ if (isTestEnv)
8179
+ return;
8180
+ try {
8181
+ const timestamp = new Date().toISOString();
8182
+ const serialized = data === undefined ? "" : data instanceof Error ? ` ${data.message}${data.stack ? `
8183
+ ${data.stack}` : ""}` : ` ${JSON.stringify(data)}`;
8184
+ buffer.push(`[${timestamp}] ${message}${serialized}
8185
+ `);
8186
+ if (buffer.length >= BUFFER_SIZE_LIMIT) {
8187
+ flush();
8188
+ } else {
8189
+ scheduleFlush();
8190
+ }
8191
+ } catch {}
8192
+ }
8193
+ function sessionLog(sessionId, message, data) {
8194
+ log(`[magic-context][${sessionId}] ${message}`, data);
8195
+ }
8196
+ if (!isTestEnv) {
8197
+ process.on("exit", flush);
8198
+ }
8287
8199
 
8288
8200
  // ../plugin/src/shared/internal-initiator-marker.ts
8289
8201
  var OMO_INTERNAL_INITIATOR_MARKER = "<!-- OMO_INTERNAL_INITIATOR -->";
@@ -8297,8 +8209,102 @@ function removeSystemReminders(text) {
8297
8209
  return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, "").trim();
8298
8210
  }
8299
8211
 
8300
- // ../plugin/src/hooks/magic-context/read-session-chunk.ts
8301
- await init_read_session_db();
8212
+ // ../plugin/src/hooks/magic-context/read-session-db.ts
8213
+ import { existsSync } from "node:fs";
8214
+ import { join as join2 } from "node:path";
8215
+
8216
+ // ../plugin/src/shared/sqlite.ts
8217
+ var isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
8218
+ var bunSpec = "bun:" + "sqlite";
8219
+ var nodeSpec = "node:" + "sqlite";
8220
+ var sqliteModule = isBun ? await import(bunSpec) : await import(nodeSpec);
8221
+ var DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
8222
+ function buildNodeSqliteDatabaseClass(DatabaseSync) {
8223
+ const SAVEPOINT = "mc_tx_sp";
8224
+
8225
+ class NodeSqliteDatabase extends DatabaseSync {
8226
+ constructor(filename, options) {
8227
+ const translated = { ...options };
8228
+ if (options && "readonly" in options) {
8229
+ translated.readOnly = options.readonly;
8230
+ delete translated.readonly;
8231
+ }
8232
+ super(typeof filename === "string" ? filename : ":memory:", translated);
8233
+ }
8234
+ transaction(fn) {
8235
+ const self = this;
8236
+ const wrapped = function(...args) {
8237
+ const nested = self.isTransaction === true;
8238
+ self.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : "BEGIN");
8239
+ try {
8240
+ const result = fn.apply(this, args);
8241
+ self.exec(nested ? `RELEASE ${SAVEPOINT}` : "COMMIT");
8242
+ return result;
8243
+ } catch (error) {
8244
+ if (nested) {
8245
+ self.exec(`ROLLBACK TO ${SAVEPOINT}`);
8246
+ self.exec(`RELEASE ${SAVEPOINT}`);
8247
+ } else {
8248
+ self.exec("ROLLBACK");
8249
+ }
8250
+ throw error;
8251
+ }
8252
+ };
8253
+ return wrapped;
8254
+ }
8255
+ }
8256
+ return NodeSqliteDatabase;
8257
+ }
8258
+ var Database = DatabaseImpl;
8259
+
8260
+ // ../plugin/src/shared/sqlite-helpers.ts
8261
+ function closeQuietly(db) {
8262
+ if (!db)
8263
+ return;
8264
+ try {
8265
+ db.close();
8266
+ } catch {}
8267
+ }
8268
+
8269
+ // ../plugin/src/hooks/magic-context/read-session-db.ts
8270
+ function getOpenCodeDbPath() {
8271
+ return join2(getDataDir(), "opencode", "opencode.db");
8272
+ }
8273
+ function openCodeDbExists() {
8274
+ return existsSync(getOpenCodeDbPath());
8275
+ }
8276
+ var cachedReadOnlyDb = null;
8277
+ function closeCachedReadOnlyDb() {
8278
+ if (!cachedReadOnlyDb) {
8279
+ return;
8280
+ }
8281
+ try {
8282
+ closeQuietly(cachedReadOnlyDb.db);
8283
+ } catch (error) {
8284
+ log("[magic-context] failed to close cached OpenCode read-only DB:", error);
8285
+ } finally {
8286
+ cachedReadOnlyDb = null;
8287
+ }
8288
+ }
8289
+ function getReadOnlySessionDb() {
8290
+ const dbPath = getOpenCodeDbPath();
8291
+ if (cachedReadOnlyDb?.path === dbPath) {
8292
+ return cachedReadOnlyDb.db;
8293
+ }
8294
+ closeCachedReadOnlyDb();
8295
+ const db = new Database(dbPath, { readonly: true });
8296
+ cachedReadOnlyDb = { path: dbPath, db };
8297
+ return db;
8298
+ }
8299
+ function withReadOnlySessionDb(fn) {
8300
+ return fn(getReadOnlySessionDb());
8301
+ }
8302
+ function getRawSessionMessageCountFromDb(db, sessionId) {
8303
+ const row = db.prepare(`SELECT COUNT(*) as count FROM message WHERE session_id = ?
8304
+ AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
8305
+ AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
8306
+ return typeof row?.count === "number" ? row.count : 0;
8307
+ }
8302
8308
 
8303
8309
  // ../../node_modules/.bun/ai-tokenizer@1.0.6/node_modules/ai-tokenizer/dist/index.js
8304
8310
  function _typeof(o) {
@@ -141342,6 +141348,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
141342
141348
  toolOnlyRanges
141343
141349
  };
141344
141350
  }
141351
+
141345
141352
  // ../plugin/src/features/magic-context/compression-depth-storage.ts
141346
141353
  var incrementDepthStatements = new WeakMap;
141347
141354
  var totalDepthStatements = new WeakMap;
@@ -141745,6 +141752,7 @@ function parseReportedLimit(message) {
141745
141752
  }
141746
141753
  return;
141747
141754
  }
141755
+
141748
141756
  // ../plugin/src/features/magic-context/compartment-lease.ts
141749
141757
  var COMPARTMENT_LEASE_TTL_MS = 5 * 60 * 1000;
141750
141758
  var COMPARTMENT_LEASE_RENEWAL_MS = 60 * 1000;
@@ -141815,6 +141823,9 @@ var SESSION_META_SELECT_COLUMNS = [
141815
141823
  "cached_m0_materialized_at",
141816
141824
  "cached_m0_session_facts_version",
141817
141825
  "cached_m0_upgrade_state",
141826
+ "cached_m0_system_hash",
141827
+ "cached_m0_tool_set_hash",
141828
+ "cached_m0_model_key",
141818
141829
  "last_observed_model_key",
141819
141830
  "upgrade_reminded_at",
141820
141831
  "pi_stable_id_scheme"
@@ -141851,6 +141862,9 @@ var META_COLUMNS = {
141851
141862
  cachedM0MaterializedAt: "cached_m0_materialized_at",
141852
141863
  cachedM0SessionFactsVersion: "cached_m0_session_facts_version",
141853
141864
  cachedM0UpgradeState: "cached_m0_upgrade_state",
141865
+ cachedM0SystemHash: "cached_m0_system_hash",
141866
+ cachedM0ToolSetHash: "cached_m0_tool_set_hash",
141867
+ cachedM0ModelKey: "cached_m0_model_key",
141854
141868
  lastObservedModelKey: "last_observed_model_key",
141855
141869
  upgradeRemindedAt: "upgrade_reminded_at",
141856
141870
  piStableIdScheme: "pi_stable_id_scheme"
@@ -141893,7 +141907,7 @@ function isSessionMetaRow(row) {
141893
141907
  if (row === null || typeof row !== "object")
141894
141908
  return false;
141895
141909
  const r = row;
141896
- return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
141910
+ return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
141897
141911
  }
141898
141912
  function getDefaultSessionMeta(sessionId) {
141899
141913
  return {
@@ -141929,6 +141943,9 @@ function getDefaultSessionMeta(sessionId) {
141929
141943
  cachedM0MaterializedAt: null,
141930
141944
  cachedM0SessionFactsVersion: null,
141931
141945
  cachedM0UpgradeState: null,
141946
+ cachedM0SystemHash: null,
141947
+ cachedM0ToolSetHash: null,
141948
+ cachedM0ModelKey: null,
141932
141949
  lastObservedModelKey: null,
141933
141950
  upgradeRemindedAt: null,
141934
141951
  piStableIdScheme: null
@@ -141980,6 +141997,9 @@ function toSessionMeta(row) {
141980
141997
  cachedM0MaterializedAt: numOrNull(row.cached_m0_materialized_at),
141981
141998
  cachedM0SessionFactsVersion: numOrNull(row.cached_m0_session_facts_version),
141982
141999
  cachedM0UpgradeState: stringOrNull(row.cached_m0_upgrade_state),
142000
+ cachedM0SystemHash: stringOrNull(row.cached_m0_system_hash),
142001
+ cachedM0ToolSetHash: stringOrNull(row.cached_m0_tool_set_hash),
142002
+ cachedM0ModelKey: stringOrNull(row.cached_m0_model_key),
141983
142003
  lastObservedModelKey: stringOrNull(row.last_observed_model_key),
141984
142004
  upgradeRemindedAt: numOrNull(row.upgrade_reminded_at),
141985
142005
  piStableIdScheme: numOrNull(row.pi_stable_id_scheme)
@@ -141999,8 +142019,11 @@ function persistCachedM0(db, sessionId, payload) {
141999
142019
  cached_m0_project_docs_hash = ?,
142000
142020
  cached_m0_materialized_at = ?,
142001
142021
  cached_m0_session_facts_version = ?,
142002
- cached_m0_upgrade_state = ?
142003
- WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, sessionId);
142022
+ cached_m0_upgrade_state = ?,
142023
+ cached_m0_system_hash = ?,
142024
+ cached_m0_tool_set_hash = ?,
142025
+ cached_m0_model_key = ?
142026
+ WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.toolSetHash ?? "", payload.modelKey ?? "", sessionId);
142004
142027
  }
142005
142028
  function clearCachedM0M1(db, sessionId) {
142006
142029
  ensureSessionMetaRow(db, sessionId);
@@ -142018,6 +142041,9 @@ function clearCachedM0M1(db, sessionId) {
142018
142041
  ["cached_m0_materialized_at", null],
142019
142042
  ["cached_m0_session_facts_version", null],
142020
142043
  ["cached_m0_upgrade_state", null],
142044
+ ["cached_m0_system_hash", null],
142045
+ ["cached_m0_tool_set_hash", null],
142046
+ ["cached_m0_model_key", null],
142021
142047
  ["cached_m0_last_baseline_end_message_id", null],
142022
142048
  ["memory_block_cache", ""],
142023
142049
  ["memory_block_count", 0],
@@ -142059,12 +142085,6 @@ function isCompartmentRow(row) {
142059
142085
  const candidate = row;
142060
142086
  return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && isStringOrNullish(candidate.p1) && isStringOrNullish(candidate.p2) && isStringOrNullish(candidate.p3) && isStringOrNullish(candidate.p4) && isNumberOrNullish(candidate.importance) && isStringOrNullish(candidate.episode_type) && isNumberOrNullish(candidate.legacy) && typeof candidate.created_at === "number";
142061
142087
  }
142062
- function isSessionFactRow(row) {
142063
- if (row === null || typeof row !== "object")
142064
- return false;
142065
- const candidate = row;
142066
- return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.category === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number" && typeof candidate.updated_at === "number";
142067
- }
142068
142088
  function insertCompartmentRows(db, sessionId, compartments, now) {
142069
142089
  const stmt = getInsertCompartmentStatement(db);
142070
142090
  for (const compartment of compartments) {
@@ -142093,16 +142113,6 @@ function toCompartment(row) {
142093
142113
  createdAt: row.created_at
142094
142114
  };
142095
142115
  }
142096
- function toSessionFact(row) {
142097
- return {
142098
- id: row.id,
142099
- sessionId: row.session_id,
142100
- category: row.category,
142101
- content: row.content,
142102
- createdAt: row.created_at,
142103
- updatedAt: row.updated_at
142104
- };
142105
- }
142106
142116
  function getCompartments(db, sessionId) {
142107
142117
  const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isCompartmentRow);
142108
142118
  return rows.map(toCompartment);
@@ -142123,10 +142133,6 @@ function appendCompartments(db, sessionId, compartments) {
142123
142133
  insertCompartmentRows(db, sessionId, compartments, now);
142124
142134
  })();
142125
142135
  }
142126
- function getSessionFacts(db, sessionId) {
142127
- const rows = db.prepare("SELECT * FROM session_facts WHERE session_id = ? ORDER BY category ASC, id ASC").all(sessionId).filter(isSessionFactRow);
142128
- return rows.map(toSessionFact);
142129
- }
142130
142136
  function saveRecompStagingPass(db, sessionId, passNumber, compartments, facts) {
142131
142137
  const now = Date.now();
142132
142138
  db.transaction(() => {
@@ -142170,14 +142176,6 @@ function getRecompStaging(db, sessionId) {
142170
142176
  lastEndMessage: lastEnd
142171
142177
  };
142172
142178
  }
142173
- function invalidateAllMemoryBlockCaches(db) {
142174
- try {
142175
- const rows = db.prepare("SELECT session_id FROM session_meta").all();
142176
- for (const row of rows) {
142177
- clearCachedM0M1(db, row.session_id);
142178
- }
142179
- } catch {}
142180
- }
142181
142179
  function clearRecompStaging(db, sessionId) {
142182
142180
  db.transaction(() => {
142183
142181
  db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
@@ -142223,11 +142221,7 @@ function escapeXmlAttr(s) {
142223
142221
  function escapeXmlContent(s) {
142224
142222
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
142225
142223
  }
142226
- // ../plugin/src/features/magic-context/migrations.ts
142227
- init_logger();
142228
-
142229
142224
  // ../plugin/src/features/magic-context/storage-db.ts
142230
- init_data_path();
142231
142225
  import { copyFileSync, cpSync, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "node:fs";
142232
142226
  import { dirname as dirname2, join as join5 } from "node:path";
142233
142227
 
@@ -142307,12 +142301,7 @@ function safeString(value) {
142307
142301
  }
142308
142302
  }
142309
142303
 
142310
- // ../plugin/src/features/magic-context/storage-db.ts
142311
- init_logger();
142312
- await init_sqlite();
142313
-
142314
142304
  // ../plugin/src/features/magic-context/key-files/project-key-files.ts
142315
- init_logger();
142316
142305
  import { createHash as createHash2 } from "node:crypto";
142317
142306
  import { existsSync as existsSync2, readFileSync, realpathSync } from "node:fs";
142318
142307
  import { join as join3, resolve, sep } from "node:path";
@@ -142482,8 +142471,6 @@ function loadToolDefinitionMeasurements(db) {
142482
142471
  }
142483
142472
 
142484
142473
  // ../plugin/src/features/magic-context/tool-owner-backfill.ts
142485
- init_data_path();
142486
- init_logger();
142487
142474
  import { existsSync as existsSync3 } from "node:fs";
142488
142475
  import { join as join4 } from "node:path";
142489
142476
  var LEASE_DURATION_MS = 5 * 60 * 1000;
@@ -142731,7 +142718,7 @@ var databases = new Map;
142731
142718
  var persistenceByDatabase = new WeakMap;
142732
142719
  var persistenceErrorByDatabase = new WeakMap;
142733
142720
  var lastSchemaFenceRejection = null;
142734
- var LATEST_SUPPORTED_VERSION = 29;
142721
+ var LATEST_SUPPORTED_VERSION = 30;
142735
142722
  function resolveDatabasePath(dbPathOverride) {
142736
142723
  if (dbPathOverride) {
142737
142724
  return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
@@ -143196,6 +143183,9 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143196
143183
  cached_m0_materialized_at INTEGER,
143197
143184
  cached_m0_session_facts_version INTEGER,
143198
143185
  cached_m0_upgrade_state TEXT,
143186
+ cached_m0_system_hash TEXT,
143187
+ cached_m0_tool_set_hash TEXT,
143188
+ cached_m0_model_key TEXT,
143199
143189
  cached_m0_last_baseline_end_message_id TEXT,
143200
143190
  upgrade_reminded_at INTEGER,
143201
143191
  pi_stable_id_scheme INTEGER
@@ -143326,6 +143316,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143326
143316
  ensureColumn(db, "session_meta", "system_prompt_hash", "TEXT DEFAULT ''");
143327
143317
  ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
143328
143318
  ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
143319
+ ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
143329
143320
  ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
143330
143321
  ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
143331
143322
  ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
@@ -143387,6 +143378,9 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
143387
143378
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
143388
143379
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
143389
143380
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
143381
+ ensureColumn(db, "session_meta", "cached_m0_system_hash", "TEXT");
143382
+ ensureColumn(db, "session_meta", "cached_m0_tool_set_hash", "TEXT");
143383
+ ensureColumn(db, "session_meta", "cached_m0_model_key", "TEXT");
143390
143384
  ensureColumn(db, "session_meta", "cached_m0_last_baseline_end_message_id", "TEXT");
143391
143385
  ensureColumn(db, "session_meta", "upgrade_reminded_at", "INTEGER");
143392
143386
  db.exec(`
@@ -143473,6 +143467,7 @@ function healNullTextColumns(db) {
143473
143467
  ["todo_synthetic_state_json", ""],
143474
143468
  ["system_prompt_hash", ""],
143475
143469
  ["stripped_placeholder_ids", ""],
143470
+ ["stale_reduce_stripped_ids", ""],
143476
143471
  ["memory_block_cache", ""],
143477
143472
  ["memory_block_ids", ""],
143478
143473
  ["compaction_marker_state", ""],
@@ -144316,6 +144311,28 @@ var MIGRATIONS = [
144316
144311
  db.exec("ALTER TABLE notes ADD COLUMN anchor_ordinal INTEGER");
144317
144312
  }
144318
144313
  }
144314
+ },
144315
+ {
144316
+ version: 30,
144317
+ description: "HARD-bust m[0] markers: cached system/tool-set/model identity",
144318
+ up: (db) => {
144319
+ const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
144320
+ if (!hasSessionMeta)
144321
+ return;
144322
+ ensureColumn(db, "session_meta", "cached_m0_system_hash", "TEXT");
144323
+ ensureColumn(db, "session_meta", "cached_m0_tool_set_hash", "TEXT");
144324
+ ensureColumn(db, "session_meta", "cached_m0_model_key", "TEXT");
144325
+ const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
144326
+ if (columns.has("cached_m0_bytes")) {
144327
+ db.prepare(`UPDATE session_meta SET
144328
+ cached_m0_bytes = NULL,
144329
+ cached_m1_bytes = NULL,
144330
+ cached_m0_materialized_at = NULL,
144331
+ cached_m0_system_hash = NULL,
144332
+ cached_m0_tool_set_hash = NULL,
144333
+ cached_m0_model_key = NULL`).run();
144334
+ }
144335
+ }
144319
144336
  }
144320
144337
  ];
144321
144338
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -144386,7 +144403,7 @@ function runMigrations(db) {
144386
144403
  }
144387
144404
  // ../plugin/src/features/magic-context/project-docs-hash.ts
144388
144405
  import { createHash as createHash3 } from "node:crypto";
144389
- import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
144406
+ import { lstatSync, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
144390
144407
  import path4 from "node:path";
144391
144408
  var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
144392
144409
  var PROJECT_DOCS_DELIMITER = `
@@ -144394,6 +144411,7 @@ var PROJECT_DOCS_DELIMITER = `
144394
144411
  ---
144395
144412
 
144396
144413
  `;
144414
+ var MAX_PROJECT_DOC_BYTES = 256 * 1024;
144397
144415
  var docsCache = new Map;
144398
144416
  function canonicalizeDocContent(raw) {
144399
144417
  return raw.replace(/^\uFEFF/, "").replace(/\r\n/g, `
@@ -144403,9 +144421,10 @@ function canonicalizeDocContent(raw) {
144403
144421
  }
144404
144422
  function fingerprintFile(filePath) {
144405
144423
  try {
144406
- const stat = statSync2(filePath);
144424
+ const stat = lstatSync(filePath);
144425
+ const isReadableDoc = stat.isFile() && stat.size <= MAX_PROJECT_DOC_BYTES;
144407
144426
  return {
144408
- exists: stat.isFile(),
144427
+ exists: isReadableDoc,
144409
144428
  mtimeMs: stat.mtimeMs,
144410
144429
  size: stat.size
144411
144430
  };
@@ -144448,6 +144467,16 @@ function readCanonicalPieces(projectDirectory, files) {
144448
144467
  if (!fingerprint?.exists) {
144449
144468
  continue;
144450
144469
  }
144470
+ let safeToRead = false;
144471
+ try {
144472
+ const st = lstatSync(filePath);
144473
+ safeToRead = st.isFile() && st.size <= MAX_PROJECT_DOC_BYTES;
144474
+ } catch {
144475
+ safeToRead = false;
144476
+ }
144477
+ if (!safeToRead) {
144478
+ continue;
144479
+ }
144451
144480
  const canonicalContent = canonicalizeDocContent(readFileSync2(filePath, "utf8"));
144452
144481
  hashPieces.push(`file:${filename}
144453
144482
  ${canonicalContent}`);
@@ -144614,7 +144643,6 @@ function getMaxMemoryMutationId(db, projectPath) {
144614
144643
  return row?.max_id ?? null;
144615
144644
  }
144616
144645
  // ../plugin/src/features/magic-context/storage-meta-persisted.ts
144617
- init_logger();
144618
144646
  var CAS_RETRY_LIMIT = 5;
144619
144647
  var AUTO_SEARCH_NO_HINT_REASONS = new Set([
144620
144648
  "below-threshold",
@@ -144769,7 +144797,8 @@ function casUpdateJsonArrayColumn(db, sessionId, column, validator, mutate, opti
144769
144797
  }
144770
144798
  for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
144771
144799
  const row = db.prepare(`SELECT ${column} FROM session_meta WHERE session_id = ?`).get(sessionId);
144772
- const currentBlob = row?.[column] ?? "[]";
144800
+ const rawCurrent = row?.[column] ?? null;
144801
+ const currentBlob = rawCurrent ?? "[]";
144773
144802
  const current = parseJsonArray(currentBlob, validator);
144774
144803
  const next = mutate(current);
144775
144804
  if (next === null)
@@ -144777,7 +144806,7 @@ function casUpdateJsonArrayColumn(db, sessionId, column, validator, mutate, opti
144777
144806
  const nextBlob = stableStringify(next);
144778
144807
  if (nextBlob === currentBlob)
144779
144808
  return true;
144780
- const result = db.prepare(`UPDATE session_meta SET ${column} = ? WHERE session_id = ? AND ${column} = ?`).run(nextBlob, sessionId, currentBlob);
144809
+ const result = db.prepare(`UPDATE session_meta SET ${column} = ? WHERE session_id = ? AND ${column} IS ?`).run(nextBlob, sessionId, rawCurrent);
144781
144810
  if (result.changes > 0)
144782
144811
  return true;
144783
144812
  }
@@ -144906,14 +144935,16 @@ function getHistorianFailureState(db, sessionId) {
144906
144935
  };
144907
144936
  }
144908
144937
  function incrementHistorianFailure(db, sessionId, error) {
144938
+ let nextCount = 1;
144909
144939
  db.transaction(() => {
144910
144940
  ensureSessionMetaRow(db, sessionId);
144911
144941
  const current = getHistorianFailureState(db, sessionId);
144912
- const nextCount = current.failureCount + 1;
144942
+ nextCount = current.failureCount + 1;
144913
144943
  db.prepare("UPDATE session_meta SET historian_failure_count = ?, historian_last_error = ?, historian_last_failure_at = ? WHERE session_id = ?").run(nextCount, error, Date.now(), sessionId);
144914
144944
  const reason = error.replace(/\s+/g, " ").trim().slice(0, 300);
144915
144945
  sessionLog(sessionId, `historian failure recorded: count=${nextCount} reason="${reason}"`);
144916
144946
  })();
144947
+ return nextCount;
144917
144948
  }
144918
144949
  function clearHistorianFailureState(db, sessionId) {
144919
144950
  db.transaction(() => {
@@ -144982,10 +145013,39 @@ function getStrippedPlaceholderIds(db, sessionId) {
144982
145013
  } catch {}
144983
145014
  return new Set;
144984
145015
  }
144985
- function setStrippedPlaceholderIds(db, sessionId, ids) {
145016
+ function applyStrippedPlaceholderDelta(db, sessionId, delta) {
145017
+ const add = delta.add ? [...delta.add] : [];
145018
+ const remove = delta.remove ? [...delta.remove] : [];
145019
+ if (add.length === 0 && remove.length === 0)
145020
+ return true;
144986
145021
  ensureSessionMetaRow(db, sessionId);
144987
- const json = ids.size > 0 ? JSON.stringify([...ids]) : "";
144988
- db.prepare("UPDATE session_meta SET stripped_placeholder_ids = ? WHERE session_id = ?").run(json, sessionId);
145022
+ for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
145023
+ const row = db.prepare("SELECT stripped_placeholder_ids FROM session_meta WHERE session_id = ?").get(sessionId);
145024
+ const rawStored = row ? row.stripped_placeholder_ids ?? null : null;
145025
+ const current = new Set(parseStrippedBlob(rawStored));
145026
+ for (const id of add)
145027
+ current.add(id);
145028
+ for (const id of remove)
145029
+ current.delete(id);
145030
+ const nextBlob = current.size > 0 ? JSON.stringify([...current]) : "";
145031
+ if (nextBlob === (rawStored ?? ""))
145032
+ return true;
145033
+ const result = db.prepare("UPDATE session_meta SET stripped_placeholder_ids = ? WHERE session_id = ? AND stripped_placeholder_ids IS ?").run(nextBlob, sessionId, rawStored);
145034
+ if (result.changes > 0)
145035
+ return true;
145036
+ }
145037
+ sessionLog(sessionId, `stripped_placeholder_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
145038
+ return false;
145039
+ }
145040
+ function parseStrippedBlob(raw) {
145041
+ if (!raw || raw.length === 0)
145042
+ return [];
145043
+ try {
145044
+ const parsed = JSON.parse(raw);
145045
+ if (Array.isArray(parsed))
145046
+ return parsed.filter((v) => typeof v === "string");
145047
+ } catch {}
145048
+ return [];
144989
145049
  }
144990
145050
  function isPendingCompactionMarker(value) {
144991
145051
  return typeof value === "object" && value !== null && typeof value.ordinal === "number" && typeof value.endMessageId === "string" && typeof value.publishedAt === "number";
@@ -145077,8 +145137,6 @@ function setSessionWorkMetrics(db, sessionId, newWorkTokens, totalInputTokens) {
145077
145137
  import { Buffer as Buffer3 } from "node:buffer";
145078
145138
 
145079
145139
  // ../plugin/src/features/magic-context/resolve-subagent-fallback.ts
145080
- init_logger();
145081
- await init_read_session_db();
145082
145140
  function resolveIsSubagentFromOpenCodeDb(sessionId) {
145083
145141
  try {
145084
145142
  return withReadOnlySessionDb((openCodeDb) => {
@@ -145112,6 +145170,9 @@ var SESSION_META_FALLBACK_SELECTS = {
145112
145170
  cached_m0_materialized_at: "NULL AS cached_m0_materialized_at",
145113
145171
  cached_m0_session_facts_version: "NULL AS cached_m0_session_facts_version",
145114
145172
  cached_m0_upgrade_state: "NULL AS cached_m0_upgrade_state",
145173
+ cached_m0_system_hash: "NULL AS cached_m0_system_hash",
145174
+ cached_m0_tool_set_hash: "NULL AS cached_m0_tool_set_hash",
145175
+ cached_m0_model_key: "NULL AS cached_m0_model_key",
145115
145176
  last_observed_model_key: "NULL AS last_observed_model_key",
145116
145177
  upgrade_reminded_at: "NULL AS upgrade_reminded_at"
145117
145178
  };
@@ -145344,7 +145405,6 @@ function markNoteChecked(db, noteId) {
145344
145405
  db.prepare("UPDATE notes SET last_checked_at = ?, updated_at = ? WHERE id = ? AND type = 'smart'").run(now, now, noteId);
145345
145406
  }
145346
145407
  // ../plugin/src/features/magic-context/storage-ops.ts
145347
- init_logger();
145348
145408
  var queuePendingOpStatements = new WeakMap;
145349
145409
  var getPendingOpsStatements = new WeakMap;
145350
145410
  var clearPendingOpsStatements = new WeakMap;
@@ -145746,7 +145806,6 @@ var ERROR_CLASSES = new Set([
145746
145806
  "unknown"
145747
145807
  ]);
145748
145808
  // ../plugin/src/features/magic-context/v22-deferred-backfill.ts
145749
- init_logger();
145750
145809
  import { createHash as createHash4 } from "node:crypto";
145751
145810
  import { realpathSync as realpathSync2 } from "node:fs";
145752
145811
  import path5 from "node:path";
@@ -146025,8 +146084,6 @@ function getAgentFallbackModels(agent) {
146025
146084
  }
146026
146085
 
146027
146086
  // ../plugin/src/shared/models-dev-cache.ts
146028
- init_data_path();
146029
- init_logger();
146030
146087
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, renameSync, writeFileSync } from "node:fs";
146031
146088
  import { join as join6 } from "node:path";
146032
146089
  var MIN_SANE_LIMIT = 20000;
@@ -146136,7 +146193,6 @@ function resolveHistorianContextLimit(historianModelOverride) {
146136
146193
  }
146137
146194
 
146138
146195
  // ../plugin/src/hooks/magic-context/event-resolvers.ts
146139
- init_logger();
146140
146196
  var DEFAULT_CONTEXT_LIMIT = 128000;
146141
146197
  var MAX_EXECUTE_THRESHOLD = 80;
146142
146198
  function resolveCacheTtl(cacheTtl, modelKey) {
@@ -146269,7 +146325,6 @@ function resolveTokensMatchWithKey(tokensConfig, modelKey) {
146269
146325
  }
146270
146326
 
146271
146327
  // ../plugin/src/hooks/magic-context/note-nudger.ts
146272
- init_logger();
146273
146328
  var NOTE_NUDGE_COOLDOWN_MS = 15 * 60 * 1000;
146274
146329
  var lastDeliveredAt = new Map;
146275
146330
  function getPersistedNoteNudgeDeliveredAt(_db, sessionId) {
@@ -146437,7 +146492,6 @@ function isTodoItem(value) {
146437
146492
  }
146438
146493
 
146439
146494
  // ../plugin/src/hooks/magic-context/upgrade-reminder.ts
146440
- init_logger();
146441
146495
  var remindedThisProcess = new Set;
146442
146496
  var UPGRADE_REMINDER_TEXT = [
146443
146497
  "\uD83C\uDF86 Historian V2 is released!",
@@ -146538,7 +146592,6 @@ async function maybeSendUpgradeReminder(deps, sessionId) {
146538
146592
  }
146539
146593
 
146540
146594
  // ../plugin/src/shared/announcement.ts
146541
- init_data_path();
146542
146595
  import * as fs2 from "node:fs";
146543
146596
  import * as path6 from "node:path";
146544
146597
  var ANNOUNCEMENT_VERSION = "0.22.0";
@@ -146584,9 +146637,14 @@ function shouldShowAnnouncement() {
146584
146637
  return lastVersion !== ANNOUNCEMENT_VERSION;
146585
146638
  }
146586
146639
 
146587
- // src/index.ts
146588
- init_data_path();
146589
- init_logger();
146640
+ // ../plugin/src/shared/keep-subagents.ts
146641
+ var keepSubagents = false;
146642
+ function setKeepSubagents(value) {
146643
+ keepSubagents = value === true;
146644
+ }
146645
+ function shouldKeepSubagents() {
146646
+ return keepSubagents;
146647
+ }
146590
146648
 
146591
146649
  // ../plugin/src/shared/resolve-fallbacks.ts
146592
146650
  function resolveFallbackChain(agentName, userFallbacks) {
@@ -146653,9 +146711,6 @@ function isEmptySidekickResult(text) {
146653
146711
  return trimmed.length === 0 || trimmed === "no relevant memories found";
146654
146712
  }
146655
146713
 
146656
- // src/commands/ctx-aug.ts
146657
- init_logger();
146658
-
146659
146714
  // src/subagent-runner.ts
146660
146715
  import * as childProcess from "node:child_process";
146661
146716
  import { existsSync as existsSync6 } from "node:fs";
@@ -146665,7 +146720,6 @@ import { createInterface } from "node:readline";
146665
146720
  import { fileURLToPath } from "node:url";
146666
146721
 
146667
146722
  // ../plugin/src/features/magic-context/subagent-token-capture.ts
146668
- init_logger();
146669
146723
  function asNumber(value) {
146670
146724
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
146671
146725
  }
@@ -146756,7 +146810,6 @@ function recordChildInvocation(input) {
146756
146810
  }
146757
146811
 
146758
146812
  // src/subagent-runner.ts
146759
- init_logger();
146760
146813
  function resolveBundledPiCli() {
146761
146814
  try {
146762
146815
  const require_ = createRequire2(import.meta.url);
@@ -147529,18 +147582,10 @@ function clearStaleEntries(db, maxAgeMs, projectIdentity) {
147529
147582
  const result = projectIdentity ? db.prepare("DELETE FROM dream_queue WHERE project_path = ? AND started_at IS NOT NULL AND started_at < ?").run(projectIdentity, cutoff) : db.prepare("DELETE FROM dream_queue WHERE started_at IS NOT NULL AND started_at < ?").run(cutoff);
147530
147583
  return result.changes;
147531
147584
  }
147532
-
147533
- // src/commands/ctx-dream.ts
147534
- init_logger();
147535
147585
  // ../plugin/src/features/magic-context/dreamer/runner.ts
147536
147586
  import { existsSync as existsSync8 } from "node:fs";
147537
147587
  import { join as join11 } from "node:path";
147538
-
147539
- // ../plugin/src/shared/index.ts
147540
- init_logger();
147541
-
147542
147588
  // ../plugin/src/shared/model-suggestion-retry.ts
147543
- init_logger();
147544
147589
  function extractMessage(error) {
147545
147590
  if (typeof error === "string")
147546
147591
  return error;
@@ -147775,40 +147820,66 @@ function extractLatestAssistantText(messages) {
147775
147820
  `) || null;
147776
147821
  }
147777
147822
 
147778
- // ../plugin/src/features/magic-context/dreamer/runner.ts
147779
- init_data_path();
147780
- init_logger();
147781
- await init_sqlite();
147782
-
147783
147823
  // ../plugin/src/features/magic-context/key-files/identify-key-files.ts
147784
147824
  import { readFileSync as readFileSync6 } from "node:fs";
147785
- import { isAbsolute, join as join10, relative as relative2 } from "node:path";
147786
- init_logger();
147825
+ import { isAbsolute as isAbsolute2, join as join10, relative as relative2 } from "node:path";
147787
147826
 
147788
147827
  // ../plugin/src/features/magic-context/key-files/aft-availability.ts
147789
147828
  var import_comment_json = __toESM(require_src2(), 1);
147790
147829
  import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
147791
147830
  import { homedir as homedir2 } from "node:os";
147792
- import { join as join9 } from "node:path";
147831
+ import { isAbsolute, join as join9, resolve as resolve2 } from "node:path";
147832
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
147793
147833
  var overrideAvailability = null;
147794
147834
  function parseConfig(path7) {
147795
147835
  if (!existsSync7(path7))
147796
147836
  return null;
147797
147837
  return import_comment_json.parse(readFileSync5(path7, "utf-8"));
147798
147838
  }
147799
- function entryMatchesAft(entry) {
147839
+ var AFT_NAME_NEEDLES = ["@cortexkit/aft", "aft-opencode", "aft-pi"];
147840
+ function stringMentionsAft(value) {
147841
+ return AFT_NAME_NEEDLES.some((needle) => value.includes(needle));
147842
+ }
147843
+ function resolveLocalEntryPackageName(value, configDir) {
147844
+ let dir = null;
147845
+ if (value.startsWith("file://")) {
147846
+ try {
147847
+ dir = fileURLToPath2(value);
147848
+ } catch {
147849
+ return null;
147850
+ }
147851
+ } else if (value.startsWith("~/")) {
147852
+ dir = join9(homedir2(), value.slice(2));
147853
+ } else if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../")) {
147854
+ dir = isAbsolute(value) ? value : resolve2(configDir, value);
147855
+ } else {
147856
+ return null;
147857
+ }
147858
+ try {
147859
+ const pkg = JSON.parse(readFileSync5(join9(dir, "package.json"), "utf-8"));
147860
+ return typeof pkg.name === "string" ? pkg.name : null;
147861
+ } catch {
147862
+ return null;
147863
+ }
147864
+ }
147865
+ function entryMatchesAft(entry, configDir) {
147800
147866
  const value = Array.isArray(entry) ? entry[0] : entry;
147801
- return typeof value === "string" && (value.includes("@cortexkit/aft") || value.includes("aft-opencode") || value.includes("aft-pi"));
147867
+ if (typeof value !== "string")
147868
+ return false;
147869
+ if (stringMentionsAft(value))
147870
+ return true;
147871
+ const name2 = resolveLocalEntryPackageName(value, configDir);
147872
+ return name2 != null && stringMentionsAft(name2);
147802
147873
  }
147803
- function hasAftInArray(value) {
147804
- return Array.isArray(value) && value.some(entryMatchesAft);
147874
+ function hasAftInArray(value, configDir) {
147875
+ return Array.isArray(value) && value.some((entry) => entryMatchesAft(entry, configDir));
147805
147876
  }
147806
- function hasAftAtKeys(value, keys) {
147877
+ function hasAftAtKeys(value, keys, configDir) {
147807
147878
  if (!value || typeof value !== "object")
147808
147879
  return false;
147809
147880
  const record = value;
147810
147881
  for (const key of keys) {
147811
- if (hasAftInArray(record[key]))
147882
+ if (hasAftInArray(record[key], configDir))
147812
147883
  return true;
147813
147884
  }
147814
147885
  return false;
@@ -147825,7 +147896,8 @@ function getAftAvailability() {
147825
147896
  for (const path7 of opencodePaths) {
147826
147897
  try {
147827
147898
  const config = parseConfig(path7);
147828
- if (hasAftAtKeys(config, ["plugin", "plugins", "mcp", "mcp_servers"])) {
147899
+ const configDir = join9(path7, "..");
147900
+ if (hasAftAtKeys(config, ["plugin", "plugins", "mcp", "mcp_servers"], configDir)) {
147829
147901
  opencode = true;
147830
147902
  break;
147831
147903
  }
@@ -147835,12 +147907,13 @@ function getAftAvailability() {
147835
147907
  for (const path7 of piPaths) {
147836
147908
  try {
147837
147909
  const config = parseConfig(path7);
147838
- if (hasAftAtKeys(config, ["packages", "extensions"])) {
147910
+ const configDir = join9(path7, "..");
147911
+ if (hasAftAtKeys(config, ["packages", "extensions"], configDir)) {
147839
147912
  pi = true;
147840
147913
  break;
147841
147914
  }
147842
147915
  const agent = config?.agent;
147843
- if (hasAftAtKeys(agent, ["packages", "extensions"])) {
147916
+ if (hasAftAtKeys(agent, ["packages", "extensions"], configDir)) {
147844
147917
  pi = true;
147845
147918
  break;
147846
147919
  }
@@ -147860,7 +147933,7 @@ function isAftAvailable() {
147860
147933
 
147861
147934
  // ../plugin/src/features/magic-context/key-files/read-history.ts
147862
147935
  import { realpathSync as realpathSync3 } from "node:fs";
147863
- import { relative, resolve as resolve2 } from "node:path";
147936
+ import { relative, resolve as resolve3 } from "node:path";
147864
147937
  function toMs(value) {
147865
147938
  if (typeof value === "number" && Number.isFinite(value))
147866
147939
  return value;
@@ -147897,7 +147970,7 @@ function coalesceRanges(ranges) {
147897
147970
  }
147898
147971
  function normalizeProjectRelativePath(projectPath, filePath) {
147899
147972
  const root = realpathSync3(projectPath);
147900
- const abs = filePath.startsWith("/") ? resolve2(filePath) : resolve2(root, filePath);
147973
+ const abs = filePath.startsWith("/") ? resolve3(filePath) : resolve3(root, filePath);
147901
147974
  let real = abs;
147902
147975
  try {
147903
147976
  real = realpathSync3(abs);
@@ -148040,9 +148113,6 @@ function collectKeyFileCandidates(args) {
148040
148113
  })).sort((a, b) => b.totalReads - a.totalReads || b.lastReadAt - a.lastReadAt).slice(0, 200);
148041
148114
  }
148042
148115
 
148043
- // ../plugin/src/features/magic-context/key-files/storage-key-files.ts
148044
- init_logger();
148045
-
148046
148116
  // ../plugin/src/features/magic-context/key-files/identify-key-files.ts
148047
148117
  var KEY_FILES_SYSTEM_PROMPT = "You are a file importance evaluator. Given read statistics about files in a coding session, identify which are core orientation files worth pinning in context. Return a JSON array.";
148048
148118
  class KeyFilesValidationError extends Error {
@@ -148262,11 +148332,13 @@ async function runKeyFilesLlm(args) {
148262
148332
  const text = extractLatestAssistantText(messages);
148263
148333
  if (!text)
148264
148334
  throw new Error("Dreamer returned no key-files output.");
148265
- return text;
148335
+ return { text, messages };
148266
148336
  } finally {
148267
- await args.client.session.delete({ path: { id: agentSessionId } }).catch(() => {
148268
- return;
148269
- });
148337
+ if (!shouldKeepSubagents()) {
148338
+ await args.client.session.delete({ path: { id: agentSessionId } }).catch(() => {
148339
+ return;
148340
+ });
148341
+ }
148270
148342
  }
148271
148343
  }
148272
148344
  async function runKeyFilesTask(args) {
@@ -148312,9 +148384,27 @@ async function runKeyFilesTask(args) {
148312
148384
  log(`[key-files] lease renewal threw: ${getErrorMessage(error)}`);
148313
148385
  }
148314
148386
  }, 60000);
148387
+ let invocationRecorded = false;
148388
+ const llmStartedAt = Date.now();
148389
+ const recordKeyFilesInvocation = (params) => {
148390
+ if (!args.parentSessionId || invocationRecorded)
148391
+ return;
148392
+ invocationRecorded = true;
148393
+ recordChildInvocation({
148394
+ db: args.db,
148395
+ parentSessionId: args.parentSessionId,
148396
+ harness: getHarness(),
148397
+ subagent: "dreamer",
148398
+ task: "key files",
148399
+ startedAt: llmStartedAt,
148400
+ status: params.status,
148401
+ messages: params.messages,
148402
+ error: params.error
148403
+ });
148404
+ };
148315
148405
  try {
148316
148406
  try {
148317
- const raw = await runKeyFilesLlm({
148407
+ const { text: raw, messages: llmMessages } = await runKeyFilesLlm({
148318
148408
  client: args.client,
148319
148409
  parentSessionId: args.parentSessionId,
148320
148410
  projectPath,
@@ -148322,8 +148412,10 @@ async function runKeyFilesTask(args) {
148322
148412
  deadline: args.deadline,
148323
148413
  fallbackModels: args.fallbackModels
148324
148414
  });
148415
+ recordKeyFilesInvocation({ status: "completed", messages: llmMessages });
148325
148416
  validated = validateLlmOutput(raw, args.config, projectPath, new Set(candidates.map((candidate) => candidate.path)));
148326
148417
  } catch (error) {
148418
+ recordKeyFilesInvocation({ status: "failed", error });
148327
148419
  log(`[key-files] LLM validation failed: ${getErrorMessage(error)}`);
148328
148420
  throw error;
148329
148421
  }
@@ -148917,9 +149009,6 @@ function getMemoryCountsByStatus(db, projectPath) {
148917
149009
  return counts;
148918
149010
  }
148919
149011
 
148920
- // ../plugin/src/features/magic-context/user-memory/review-user-memories.ts
148921
- init_logger();
148922
-
148923
149012
  // ../plugin/src/features/magic-context/dreamer/task-prompts.ts
148924
149013
  var DREAMER_SYSTEM_PROMPT = `You are a memory maintenance agent for the magic-context system.
148925
149014
  You run during scheduled dream windows to maintain a project's cross-session memory store and codebase documentation.
@@ -149422,7 +149511,8 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
149422
149511
  db: args.db,
149423
149512
  parentSessionId: args.parentSessionId,
149424
149513
  harness: "opencode",
149425
- subagent: "user_memory_review",
149514
+ subagent: "dreamer",
149515
+ task: "user memories",
149426
149516
  startedAt,
149427
149517
  status: params.status,
149428
149518
  messages: params.messages,
@@ -149546,7 +149636,7 @@ If no promotions are warranted, return empty arrays. Always consume reviewed can
149546
149636
  return result;
149547
149637
  } finally {
149548
149638
  clearInterval(leaseInterval);
149549
- if (agentSessionId) {
149639
+ if (agentSessionId && !shouldKeepSubagents()) {
149550
149640
  await args.client.session.delete({
149551
149641
  path: { id: agentSessionId },
149552
149642
  query: { directory: args.sessionDirectory }
@@ -149673,7 +149763,7 @@ async function runDream(args) {
149673
149763
  }
149674
149764
  }
149675
149765
  const deadline = startedAt + args.maxRuntimeMinutes * 60 * 1000;
149676
- const lastDreamAt = getDreamState(args.db, `last_dream_at:${args.projectIdentity}`) ?? getDreamState(args.db, "last_dream_at");
149766
+ const lastDreamAt = getDreamState(args.db, `last_dream_at:${args.projectIdentity}`);
149677
149767
  log(`[dreamer] last dream at: ${lastDreamAt ?? "never"} (project=${args.projectIdentity})`);
149678
149768
  let lastErrorSignature = null;
149679
149769
  let consecutiveSameErrorFailures = 0;
@@ -149870,14 +149960,14 @@ async function runDream(args) {
149870
149960
  }
149871
149961
  } finally {
149872
149962
  clearInterval(leaseRenewalInterval);
149873
- if (agentSessionId && !taskFailed) {
149963
+ if (agentSessionId && !taskFailed && !shouldKeepSubagents()) {
149874
149964
  await args.client.session.delete({
149875
149965
  path: { id: agentSessionId }
149876
149966
  }).catch((error) => {
149877
149967
  log("[dreamer] failed to delete child session:", error);
149878
149968
  });
149879
- } else if (agentSessionId && taskFailed) {
149880
- log(`[dreamer] KEEPING failed child session ${agentSessionId} for task ${taskName} (debugging)`);
149969
+ } else if (agentSessionId && (taskFailed || shouldKeepSubagents())) {
149970
+ log(`[dreamer] KEEPING child session ${agentSessionId} for task ${taskName} (${taskFailed ? "failed" : "keep_subagents"})`);
149881
149971
  }
149882
149972
  }
149883
149973
  if (lostLease) {
@@ -150055,7 +150145,6 @@ async function runDream(args) {
150055
150145
  const hasSuccessfulTask = result.tasks.some((t) => !t.error && !POST_TASK_NAMES.has(t.name));
150056
150146
  if (hasSuccessfulTask && !lostLease) {
150057
150147
  setDreamState(args.db, `last_dream_at:${args.projectIdentity}`, String(result.finishedAt));
150058
- setDreamState(args.db, "last_dream_at", String(result.finishedAt));
150059
150148
  }
150060
150149
  const totalDuration = ((result.finishedAt - startedAt) / 1000).toFixed(1);
150061
150150
  const succeeded = result.tasks.filter((t) => !t.error).length;
@@ -150162,7 +150251,7 @@ Only include notes whose conditions you could definitively evaluate against exte
150162
150251
  parts: [{ type: "text", text: evaluationPrompt, synthetic: true }]
150163
150252
  }
150164
150253
  }, {
150165
- timeoutMs: Math.min(remainingMs, 300000),
150254
+ timeoutMs: Math.min(remainingMs, 5 * 60 * 1000),
150166
150255
  signal: abortController.signal,
150167
150256
  fallbackModels: args.fallbackModels,
150168
150257
  callContext: "dreamer:smart-notes"
@@ -150238,7 +150327,7 @@ Only include notes whose conditions you could definitively evaluate against exte
150238
150327
  });
150239
150328
  } finally {
150240
150329
  clearInterval(leaseInterval);
150241
- if (agentSessionId) {
150330
+ if (agentSessionId && !shouldKeepSubagents()) {
150242
150331
  await args.client.session.delete({
150243
150332
  path: { id: agentSessionId }
150244
150333
  }).catch(() => {});
@@ -150249,7 +150338,7 @@ var MAX_LEASE_RETRIES = 3;
150249
150338
  async function processDreamQueue(args) {
150250
150339
  const maxRuntimeMs = args.maxRuntimeMinutes * 60 * 1000;
150251
150340
  if (!hasActiveDreamLease(args.db)) {
150252
- clearStaleEntries(args.db, maxRuntimeMs + 1800000, args.projectIdentity);
150341
+ clearStaleEntries(args.db, maxRuntimeMs + 30 * 60 * 1000, args.projectIdentity);
150253
150342
  }
150254
150343
  const entry = dequeueNext(args.db, args.projectIdentity);
150255
150344
  if (!entry) {
@@ -150292,7 +150381,6 @@ async function processDreamQueue(args) {
150292
150381
  return result;
150293
150382
  }
150294
150383
  // ../plugin/src/features/magic-context/dreamer/scheduler.ts
150295
- init_logger();
150296
150384
  function parseScheduleWindow(schedule) {
150297
150385
  const match = /^(\d{1,2}):(\d{2})-(\d{1,2}):(\d{2})$/.exec(schedule.trim());
150298
150386
  if (!match)
@@ -150332,8 +150420,7 @@ function findProjectsNeedingDream(db) {
150332
150420
  const now = new Date;
150333
150421
  for (const row of projectRows) {
150334
150422
  const lastDreamAtStr = getDreamState(db, `last_dream_at:${row.project_path}`);
150335
- const fallbackStr = !lastDreamAtStr ? getDreamState(db, "last_dream_at") : null;
150336
- const lastDreamAt = Number(lastDreamAtStr ?? fallbackStr ?? "0") || 0;
150423
+ const lastDreamAt = Number(lastDreamAtStr ?? "0") || 0;
150337
150424
  if (lastDreamAt > 0 && isDreamFromCurrentWindow(lastDreamAt, now)) {
150338
150425
  continue;
150339
150426
  }
@@ -150367,7 +150454,6 @@ function checkScheduleAndEnqueue(db, schedule, ownProjectIdentity) {
150367
150454
  return enqueued;
150368
150455
  }
150369
150456
  // ../plugin/src/features/magic-context/git-commits/git-log-reader.ts
150370
- init_logger();
150371
150457
  import { execFile } from "node:child_process";
150372
150458
  import { promisify } from "node:util";
150373
150459
  var execFileAsync = promisify(execFile);
@@ -150451,9 +150537,6 @@ ${body}` : subject;
150451
150537
  }
150452
150538
  return commits;
150453
150539
  }
150454
- // ../plugin/src/features/magic-context/git-commits/indexer.ts
150455
- init_logger();
150456
-
150457
150540
  // ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
150458
150541
  var exports_external = {};
150459
150542
  __export(exports_external, {
@@ -164894,6 +164977,7 @@ var MagicContextConfigSchema = exports_external.object({
164894
164977
  model: DEFAULT_LOCAL_EMBEDDING_MODEL
164895
164978
  }).describe("Embedding provider configuration"),
164896
164979
  temporal_awareness: exports_external.boolean().default(true).describe('Inject wall-clock gap markers (<!-- +Xm -->) between user messages where > 5 min elapsed since the previous message, and add start/end date attributes on compartments. Gives the agent a sense of session pacing and "how long ago" across multi-day sessions. Graduated from experimental.temporal_awareness; default: true (set false to opt out).'),
164980
+ keep_subagents: exports_external.boolean().default(false).describe("Debug: keep the child sessions Magic Context spawns for its own subagents (historian, dreamer, sidekick, memory-migration) instead of deleting them on success. Useful for short-term inspection/data collection — their full transcript (prompt, tool calls, token usage, output) stays in the host session store. Kept sessions accumulate until manually cleared; leave false for normal use. Requires a restart to take effect."),
164897
164981
  caveman_text_compression: exports_external.object({
164898
164982
  enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Only active when ctx_reduce_enabled=false. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
164899
164983
  min_chars: exports_external.number().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
@@ -164929,9 +165013,6 @@ var MagicContextConfigSchema = exports_external.object({
164929
165013
  };
164930
165014
  });
164931
165015
 
164932
- // ../plugin/src/features/magic-context/memory/embedding.ts
164933
- init_logger();
164934
-
164935
165016
  // ../plugin/src/features/magic-context/memory/cosine-similarity.ts
164936
165017
  function cosineSimilarity(a, b) {
164937
165018
  if (a.length !== b.length) {
@@ -164977,8 +165058,6 @@ import { mkdirSync as mkdirSync5 } from "node:fs";
164977
165058
  import { open, stat, unlink, writeFile } from "node:fs/promises";
164978
165059
  import { dirname as dirname4, join as join12 } from "node:path";
164979
165060
  import { pathToFileURL } from "node:url";
164980
- init_data_path();
164981
- init_logger();
164982
165061
  var LOCK_POLL_MS = 150;
164983
165062
  var STALE_LOCK_MS = 3 * 60000;
164984
165063
  var MAX_LOCK_WAIT_MS = 5 * 60000;
@@ -165017,7 +165096,7 @@ async function acquireModelLoadLock(lockPath) {
165017
165096
  if (Date.now() - waitStart > MAX_LOCK_WAIT_MS) {
165018
165097
  throw new Error(`[magic-context] embedding-load lock wait exceeded ${MAX_LOCK_WAIT_MS}ms; another process is still loading the model. Skipping this init attempt to avoid an unsynchronized native load.`);
165019
165098
  }
165020
- await new Promise((resolve3) => setTimeout(resolve3, LOCK_POLL_MS));
165099
+ await new Promise((resolve4) => setTimeout(resolve4, LOCK_POLL_MS));
165021
165100
  }
165022
165101
  }
165023
165102
  }
@@ -165186,7 +165265,7 @@ class LocalEmbeddingProvider {
165186
165265
  }
165187
165266
  const delayMs = 300 * attempt + Math.floor(Math.random() * 200);
165188
165267
  log(`[magic-context] embedding model load attempt ${attempt}/${MAX_ATTEMPTS} failed transiently, retrying in ${delayMs}ms`);
165189
- await new Promise((resolve3) => setTimeout(resolve3, delayMs));
165268
+ await new Promise((resolve4) => setTimeout(resolve4, delayMs));
165190
165269
  }
165191
165270
  }
165192
165271
  if (this.pipeline) {
@@ -165214,8 +165293,8 @@ class LocalEmbeddingProvider {
165214
165293
  if (this.inFlight === 0) {
165215
165294
  return Promise.resolve();
165216
165295
  }
165217
- return new Promise((resolve3) => {
165218
- this.inFlightWaiters.push(resolve3);
165296
+ return new Promise((resolve4) => {
165297
+ this.inFlightWaiters.push(resolve4);
165219
165298
  });
165220
165299
  }
165221
165300
  finishInFlight() {
@@ -165313,8 +165392,60 @@ class LocalEmbeddingProvider {
165313
165392
  }
165314
165393
  }
165315
165394
 
165395
+ // ../plugin/src/features/magic-context/memory/embedding-ssrf.ts
165396
+ var METADATA_HOSTNAMES = new Set(["metadata.google.internal", "metadata.goog"]);
165397
+ var IPV6_METADATA_HOSTS = new Set(["fd00:ec2::254"]);
165398
+ function isLinkLocalIpv4(host) {
165399
+ return /^169\.254\.\d{1,3}\.\d{1,3}$/.test(host);
165400
+ }
165401
+ function ipv4FromMappedIpv6(host) {
165402
+ const m = /^::ffff:(.+)$/.exec(host);
165403
+ if (!m)
165404
+ return null;
165405
+ const tail = m[1];
165406
+ if (/^\d{1,3}(\.\d{1,3}){3}$/.test(tail))
165407
+ return tail;
165408
+ const hex3 = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(tail);
165409
+ if (hex3) {
165410
+ const hi = Number.parseInt(hex3[1], 16);
165411
+ const lo = Number.parseInt(hex3[2], 16);
165412
+ if (Number.isNaN(hi) || Number.isNaN(lo))
165413
+ return null;
165414
+ return `${hi >> 8 & 255}.${hi & 255}.${lo >> 8 & 255}.${lo & 255}`;
165415
+ }
165416
+ return null;
165417
+ }
165418
+ function blockedEmbeddingEndpointReason(endpoint) {
165419
+ const trimmed = endpoint.trim();
165420
+ if (trimmed.length === 0)
165421
+ return null;
165422
+ let url2;
165423
+ try {
165424
+ url2 = new URL(trimmed);
165425
+ } catch {
165426
+ return `embedding endpoint is not a valid URL: ${trimmed}`;
165427
+ }
165428
+ const host = url2.hostname.toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
165429
+ if (METADATA_HOSTNAMES.has(host)) {
165430
+ return `embedding endpoint host ${host} is a cloud metadata service (blocked)`;
165431
+ }
165432
+ if (IPV6_METADATA_HOSTS.has(host)) {
165433
+ return `embedding endpoint host ${host} is the AWS IPv6 metadata service (blocked)`;
165434
+ }
165435
+ if (isLinkLocalIpv4(host)) {
165436
+ return `embedding endpoint host ${host} is link-local / cloud metadata (blocked)`;
165437
+ }
165438
+ const mappedV4 = ipv4FromMappedIpv6(host);
165439
+ if (mappedV4 && isLinkLocalIpv4(mappedV4)) {
165440
+ return `embedding endpoint host ${host} (IPv4-mapped ${mappedV4}) is link-local / cloud metadata (blocked)`;
165441
+ }
165442
+ if (host.startsWith("fe80:")) {
165443
+ return `embedding endpoint host ${host} is link-local / cloud metadata (blocked)`;
165444
+ }
165445
+ return null;
165446
+ }
165447
+
165316
165448
  // ../plugin/src/features/magic-context/memory/embedding-openai.ts
165317
- init_logger();
165318
165449
  function normalizeEndpoint2(endpoint) {
165319
165450
  return endpoint?.trim().replace(/\/+$/, "") ?? "";
165320
165451
  }
@@ -165356,6 +165487,12 @@ class OpenAICompatibleEmbeddingProvider {
165356
165487
  this.initialized = false;
165357
165488
  return false;
165358
165489
  }
165490
+ const blockedReason = blockedEmbeddingEndpointReason(this.endpoint);
165491
+ if (blockedReason) {
165492
+ log(`[magic-context] embedding endpoint blocked: ${blockedReason}`);
165493
+ this.initialized = false;
165494
+ return false;
165495
+ }
165359
165496
  this.initialized = true;
165360
165497
  return true;
165361
165498
  }
@@ -165401,6 +165538,7 @@ class OpenAICompatibleEmbeddingProvider {
165401
165538
  ...this.inputType ? { input_type: this.inputType } : {},
165402
165539
  ...this.truncate ? { truncate: this.truncate } : {}
165403
165540
  }),
165541
+ redirect: "error",
165404
165542
  signal: internalController.signal
165405
165543
  });
165406
165544
  if (!response.ok) {
@@ -165530,7 +165668,6 @@ class OpenAICompatibleEmbeddingProvider {
165530
165668
 
165531
165669
  // ../plugin/src/features/magic-context/project-embedding-registry.ts
165532
165670
  import { createHash as createHash7, randomUUID } from "node:crypto";
165533
- init_logger();
165534
165671
 
165535
165672
  // ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
165536
165673
  var saveStatements = new WeakMap;
@@ -165768,11 +165905,15 @@ function resolveEmbeddingConfig(config2) {
165768
165905
  }
165769
165906
  if (config2.provider === "openai-compatible") {
165770
165907
  const apiKey = config2.api_key?.trim();
165908
+ const inputType = config2.input_type?.trim();
165909
+ const truncate = config2.truncate?.trim();
165771
165910
  return {
165772
165911
  provider: "openai-compatible",
165773
165912
  model: config2.model.trim(),
165774
165913
  endpoint: config2.endpoint.trim(),
165775
- ...apiKey ? { api_key: apiKey } : {}
165914
+ ...apiKey ? { api_key: apiKey } : {},
165915
+ ...inputType ? { input_type: inputType } : {},
165916
+ ...truncate ? { truncate } : {}
165776
165917
  };
165777
165918
  }
165778
165919
  return { provider: "off" };
@@ -165788,7 +165929,9 @@ function createProvider(config2) {
165788
165929
  return new OpenAICompatibleEmbeddingProvider({
165789
165930
  endpoint: config2.endpoint,
165790
165931
  model: config2.model,
165791
- apiKey: config2.api_key
165932
+ apiKey: config2.api_key,
165933
+ inputType: config2.input_type,
165934
+ truncate: config2.truncate
165792
165935
  });
165793
165936
  }
165794
165937
  return new LocalEmbeddingProvider(config2.model);
@@ -166064,7 +166207,6 @@ async function embedText(text, signal) {
166064
166207
  var SWEEP_MAX_WALL_CLOCK_MS2 = 10 * 60 * 1000;
166065
166208
 
166066
166209
  // ../plugin/src/features/magic-context/git-commits/storage-git-commits.ts
166067
- init_logger();
166068
166210
  var insertStatements = new WeakMap;
166069
166211
  var existingShasStatements = new WeakMap;
166070
166212
  var projectCountStatements = new WeakMap;
@@ -166276,9 +166418,6 @@ async function embedUnembeddedCommits(db, projectPath) {
166276
166418
  embedInProgress.delete(projectPath);
166277
166419
  }
166278
166420
  }
166279
- // ../plugin/src/features/magic-context/git-commits/search-git-commits.ts
166280
- init_logger();
166281
-
166282
166421
  // ../plugin/src/features/magic-context/memory/storage-memory-fts.ts
166283
166422
  var DEFAULT_SEARCH_LIMIT = 10;
166284
166423
  var searchStatements = new WeakMap;
@@ -166441,7 +166580,6 @@ function searchGitCommitsSync(db, projectPath, query, options) {
166441
166580
  return results.slice(0, options.limit);
166442
166581
  }
166443
166582
  // ../plugin/src/plugin/dream-timer.ts
166444
- init_logger();
166445
166583
  var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
166446
166584
  var activeTimer = null;
166447
166585
  function openTimerDatabaseOrNull(context) {
@@ -166601,15 +166739,24 @@ async function sweepGitCommits(args) {
166601
166739
 
166602
166740
  // ../plugin/src/plugin/embedding-bootstrap-helpers.ts
166603
166741
  import { createHash as createHash8 } from "node:crypto";
166604
- init_logger();
166605
166742
  var EMBEDDING_AFFECTING_KEYS = new Set([
166606
166743
  "embedding.api_key",
166607
166744
  "embedding.endpoint",
166608
166745
  "embedding.model",
166609
- "embedding.provider"
166746
+ "embedding.provider",
166747
+ "embedding.input_type",
166748
+ "embedding.truncate"
166610
166749
  ]);
166611
166750
  var EMBEDDING_AFFECTING_TOP_LEVEL_KEYS = new Set(["embedding", "memory", "experimental"]);
166612
- var EMBEDDING_WARNING_TERMS = ["api_key", "endpoint", "model", "provider", "embedding"];
166751
+ var EMBEDDING_WARNING_TERMS = [
166752
+ "api_key",
166753
+ "endpoint",
166754
+ "model",
166755
+ "provider",
166756
+ "embedding",
166757
+ "input_type",
166758
+ "truncate"
166759
+ ];
166613
166760
  var loggedFailureSignatures = new Map;
166614
166761
  function sha256Prefix2(value, length = 16) {
166615
166762
  return createHash8("sha256").update(value).digest("hex").slice(0, length);
@@ -166675,6 +166822,31 @@ function handleUntrustedLoad(db, projectIdentity, directory, detailed) {
166675
166822
  return true;
166676
166823
  }
166677
166824
 
166825
+ // ../plugin/src/config/prune-config-leaf.ts
166826
+ function isPlainObject2(value) {
166827
+ return typeof value === "object" && value !== null && !Array.isArray(value);
166828
+ }
166829
+ function pruneNestedConfigLeaf(block, relativePath) {
166830
+ if (relativePath.length === 0)
166831
+ return null;
166832
+ const result = { ...block };
166833
+ let cursor = result;
166834
+ for (let i = 0;i < relativePath.length - 1; i++) {
166835
+ const seg = String(relativePath[i]);
166836
+ const child = cursor[seg];
166837
+ if (!isPlainObject2(child))
166838
+ return null;
166839
+ const clonedChild = { ...child };
166840
+ cursor[seg] = clonedChild;
166841
+ cursor = clonedChild;
166842
+ }
166843
+ const leaf = String(relativePath[relativePath.length - 1]);
166844
+ if (!(leaf in cursor))
166845
+ return null;
166846
+ delete cursor[leaf];
166847
+ return { block: result, removed: relativePath.map(String).join(".") };
166848
+ }
166849
+
166678
166850
  // src/config/index.ts
166679
166851
  import { existsSync as existsSync10, readFileSync as readFileSync8 } from "node:fs";
166680
166852
  import { homedir as homedir4 } from "node:os";
@@ -166766,10 +166938,74 @@ function migrateLegacyExperimental(rawConfig, warnings) {
166766
166938
  return patched;
166767
166939
  }
166768
166940
 
166941
+ // ../plugin/src/config/project-security.ts
166942
+ var HIDDEN_AGENT_KEYS = ["historian", "dreamer", "sidekick"];
166943
+ var AGENT_ESCALATION_FIELDS = ["prompt", "permission", "tools", "system_prompt"];
166944
+ function isPlainObject3(value) {
166945
+ return typeof value === "object" && value !== null && !Array.isArray(value);
166946
+ }
166947
+ function stripUnsafeProjectConfigFields(projectRaw) {
166948
+ const warnings = [];
166949
+ if ("auto_update" in projectRaw) {
166950
+ delete projectRaw.auto_update;
166951
+ warnings.push("Ignoring auto_update from project config (security: this setting only honors user-level config).");
166952
+ }
166953
+ for (const agentKey of HIDDEN_AGENT_KEYS) {
166954
+ const block = projectRaw[agentKey];
166955
+ if (!isPlainObject3(block))
166956
+ continue;
166957
+ const removed = [];
166958
+ for (const field of AGENT_ESCALATION_FIELDS) {
166959
+ if (field in block) {
166960
+ delete block[field];
166961
+ removed.push(field);
166962
+ }
166963
+ }
166964
+ if (removed.length > 0) {
166965
+ warnings.push(`Ignoring ${agentKey}.${removed.join("/")} from project config ` + "(security: a repository cannot reprogram or re-permission hidden agents).");
166966
+ }
166967
+ }
166968
+ return warnings;
166969
+ }
166970
+ function normalizeEndpoint3(value) {
166971
+ if (typeof value !== "string")
166972
+ return;
166973
+ const trimmed = value.trim().replace(/\/+$/, "");
166974
+ return trimmed.length > 0 ? trimmed.toLowerCase() : undefined;
166975
+ }
166976
+ function dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, userRaw) {
166977
+ const projectEmbedding = projectRaw.embedding;
166978
+ if (!isPlainObject3(projectEmbedding))
166979
+ return [];
166980
+ const redirectsEndpoint = "endpoint" in projectEmbedding;
166981
+ if (!redirectsEndpoint)
166982
+ return [];
166983
+ const userEmbedding = userRaw?.embedding;
166984
+ if (isPlainObject3(userEmbedding)) {
166985
+ const projectEndpoint = normalizeEndpoint3(projectEmbedding.endpoint);
166986
+ const userEndpoint = normalizeEndpoint3(userEmbedding.endpoint);
166987
+ if (projectEndpoint !== undefined && projectEndpoint === userEndpoint) {
166988
+ return [];
166989
+ }
166990
+ }
166991
+ const providesOwnKey = typeof projectEmbedding.api_key === "string" && projectEmbedding.api_key.length > 0;
166992
+ if (providesOwnKey)
166993
+ return [];
166994
+ const mergedEmbedding = mergedRaw.embedding;
166995
+ if (!isPlainObject3(mergedEmbedding))
166996
+ return [];
166997
+ if (!("api_key" in mergedEmbedding))
166998
+ return [];
166999
+ delete mergedEmbedding.api_key;
167000
+ return [
167001
+ "Dropped inherited user embedding api_key because project config redirected " + "embedding.endpoint without supplying its own key (security: prevents key " + "exfiltration to a repository-chosen endpoint)."
167002
+ ];
167003
+ }
167004
+
166769
167005
  // ../plugin/src/config/variable.ts
166770
167006
  import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
166771
167007
  import { homedir as homedir3 } from "node:os";
166772
- import { dirname as dirname5, isAbsolute as isAbsolute2, resolve as resolve3 } from "node:path";
167008
+ import { dirname as dirname5, isAbsolute as isAbsolute3, resolve as resolve4 } from "node:path";
166773
167009
 
166774
167010
  // ../plugin/src/shared/jsonc-parser.ts
166775
167011
  function stripJsonComments(content) {
@@ -166830,6 +167066,21 @@ function stripJsonComments(content) {
166830
167066
  // ../plugin/src/config/variable.ts
166831
167067
  var ENV_PATTERN = /\{env:([^}]+)\}/g;
166832
167068
  var FILE_PATTERN = /\{file:([^}]+)\}/g;
167069
+ function sensitiveFilePathReason(resolvedPath) {
167070
+ const home = homedir3();
167071
+ const sensitiveDirs = [
167072
+ { dir: resolve4(home, ".ssh"), label: "SSH keys" },
167073
+ { dir: resolve4(home, ".aws"), label: "AWS credentials" },
167074
+ { dir: resolve4(home, ".gnupg"), label: "GnuPG keyring" },
167075
+ { dir: resolve4(home, ".config", "gh"), label: "GitHub CLI auth" }
167076
+ ];
167077
+ for (const { dir, label } of sensitiveDirs) {
167078
+ if (resolvedPath === dir || resolvedPath.startsWith(`${dir}/`)) {
167079
+ return label;
167080
+ }
167081
+ }
167082
+ return null;
167083
+ }
166833
167084
  function substituteConfigVariables(input) {
166834
167085
  const warnings = [];
166835
167086
  let text = input.text;
@@ -166879,9 +167130,13 @@ function substituteConfigVariables(input) {
166879
167130
  }
166880
167131
  let filePath = rawPath.trim();
166881
167132
  if (filePath.startsWith("~/")) {
166882
- filePath = resolve3(homedir3(), filePath.slice(2));
166883
- } else if (!isAbsolute2(filePath)) {
166884
- filePath = resolve3(configDir, filePath);
167133
+ filePath = resolve4(homedir3(), filePath.slice(2));
167134
+ } else if (!isAbsolute3(filePath)) {
167135
+ filePath = resolve4(configDir, filePath);
167136
+ }
167137
+ const sensitiveReason = sensitiveFilePathReason(filePath);
167138
+ if (sensitiveReason) {
167139
+ warnings.push(`${token} resolves to a sensitive path (${sensitiveReason}: ${filePath}); ` + "inlining its contents into config — make sure this is intentional.");
166885
167140
  }
166886
167141
  if (!existsSync9(filePath)) {
166887
167142
  warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
@@ -166921,7 +167176,8 @@ function loadConfigFile(path7, scope) {
166921
167176
  const rawText = readFileSync8(path7, "utf-8");
166922
167177
  const substituted = substituteConfigVariables({
166923
167178
  text: rawText,
166924
- configPath: path7
167179
+ configPath: path7,
167180
+ isProjectConfig: scope === "project"
166925
167181
  });
166926
167182
  return {
166927
167183
  path: path7,
@@ -166963,14 +167219,14 @@ function redactConfigValue(value) {
166963
167219
  }
166964
167220
  return typeof value;
166965
167221
  }
166966
- function isPlainObject2(value) {
167222
+ function isPlainObject4(value) {
166967
167223
  return typeof value === "object" && value !== null && !Array.isArray(value);
166968
167224
  }
166969
167225
  function mergeRawConfigs(base, override) {
166970
167226
  const merged = { ...base };
166971
167227
  for (const [key, overrideValue] of Object.entries(override)) {
166972
167228
  const baseValue = merged[key];
166973
- merged[key] = isPlainObject2(baseValue) && isPlainObject2(overrideValue) ? mergeRawConfigs(baseValue, overrideValue) : overrideValue;
167229
+ merged[key] = isPlainObject4(baseValue) && isPlainObject4(overrideValue) ? mergeRawConfigs(baseValue, overrideValue) : overrideValue;
166974
167230
  }
166975
167231
  return merged;
166976
167232
  }
@@ -166984,10 +167240,15 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
166984
167240
  }
166985
167241
  const defaults = MagicContextConfigSchema.parse({});
166986
167242
  const errorPaths = new Set;
167243
+ const issuePathsByKey = new Map;
166987
167244
  for (const issue2 of parsed.error.issues) {
166988
167245
  const topKey = issue2.path[0];
166989
167246
  if (topKey !== undefined) {
166990
- errorPaths.add(String(topKey));
167247
+ const key = String(topKey);
167248
+ errorPaths.add(key);
167249
+ const paths = issuePathsByKey.get(key) ?? [];
167250
+ paths.push([...issue2.path]);
167251
+ issuePathsByKey.set(key, paths);
166991
167252
  }
166992
167253
  }
166993
167254
  const patched = { ...migrated };
@@ -166995,11 +167256,32 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
166995
167256
  for (const key of errorPaths) {
166996
167257
  recoveredTopLevelKeys.push(key);
166997
167258
  const isAgentConfig = key === "historian" || key === "dreamer" || key === "sidekick";
166998
- delete patched[key];
166999
167259
  if (isAgentConfig) {
167260
+ delete patched[key];
167000
167261
  warnings.push(`"${key}": invalid agent configuration, ignoring. Check your magic-context.jsonc.`);
167001
167262
  continue;
167002
167263
  }
167264
+ const issuePaths = issuePathsByKey.get(key) ?? [];
167265
+ const rawValue = migrated[key];
167266
+ const allNested = issuePaths.length > 0 && issuePaths.every((p) => p.length >= 2) && typeof rawValue === "object" && rawValue !== null && !Array.isArray(rawValue);
167267
+ if (allNested) {
167268
+ let prunedBlock = {
167269
+ ...rawValue
167270
+ };
167271
+ const prunedLeaves = [];
167272
+ for (const p of issuePaths) {
167273
+ const relative3 = p.slice(1);
167274
+ const result = pruneNestedConfigLeaf(prunedBlock, relative3);
167275
+ if (result) {
167276
+ prunedBlock = result.block;
167277
+ prunedLeaves.push(result.removed);
167278
+ }
167279
+ }
167280
+ patched[key] = prunedBlock;
167281
+ warnings.push(`"${key}": invalid nested field(s) ${prunedLeaves.map((l) => `"${l}"`).join(", ")}, using defaults for those.`);
167282
+ continue;
167283
+ }
167284
+ delete patched[key];
167003
167285
  const defaultValue = defaults[key];
167004
167286
  warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultValue)}.`);
167005
167287
  }
@@ -167032,10 +167314,22 @@ function loadPiConfig(opts = {}) {
167032
167314
  return 0;
167033
167315
  return a.scope === "user" ? -1 : 1;
167034
167316
  });
167317
+ const userRaw = mergeFiles.find((f) => f.scope === "user")?.config;
167035
167318
  for (const loaded of mergeFiles) {
167036
167319
  const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
167037
167320
  warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
167038
- rawConfig = mergeRawConfigs(rawConfig, loaded.config);
167321
+ if (loaded.scope === "project") {
167322
+ const projectRaw = { ...loaded.config };
167323
+ for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
167324
+ warnings.push(`${prefix} ${warning}`);
167325
+ }
167326
+ rawConfig = mergeRawConfigs(rawConfig, projectRaw);
167327
+ for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, userRaw)) {
167328
+ warnings.push(`${prefix} ${warning}`);
167329
+ }
167330
+ } else {
167331
+ rawConfig = mergeRawConfigs(rawConfig, loaded.config);
167332
+ }
167039
167333
  }
167040
167334
  const parsed = parsePiConfig(rawConfig);
167041
167335
  warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
@@ -167110,10 +167404,22 @@ function loadPiConfigDetailed(opts = {}) {
167110
167404
  return 0;
167111
167405
  return a.scope === "user" ? -1 : 1;
167112
167406
  });
167407
+ const userRaw = mergeFiles.find((f) => f.scope === "user")?.config;
167113
167408
  for (const loaded of mergeFiles) {
167114
167409
  const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
167115
167410
  warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
167116
- rawConfig = mergeRawConfigs(rawConfig, loaded.config);
167411
+ if (loaded.scope === "project") {
167412
+ const projectRaw = { ...loaded.config };
167413
+ for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
167414
+ warnings.push(`${prefix} ${warning}`);
167415
+ }
167416
+ rawConfig = mergeRawConfigs(rawConfig, projectRaw);
167417
+ for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, userRaw)) {
167418
+ warnings.push(`${prefix} ${warning}`);
167419
+ }
167420
+ } else {
167421
+ rawConfig = mergeRawConfigs(rawConfig, loaded.config);
167422
+ }
167117
167423
  }
167118
167424
  const recoveredTopLevelKeys = [];
167119
167425
  const parsed = parsePiConfig(rawConfig, recoveredTopLevelKeys);
@@ -167168,7 +167474,11 @@ function registerPiDreamerProject(opts) {
167168
167474
  }
167169
167475
  const existing = registeredProjects2.get(opts.projectIdentity);
167170
167476
  if (existing) {
167171
- return;
167477
+ if (existing.projectDir === opts.projectDir) {
167478
+ return;
167479
+ }
167480
+ existing.cleanup();
167481
+ registeredProjects2.delete(opts.projectIdentity);
167172
167482
  }
167173
167483
  registerDreamProjectDirectory(opts.projectIdentity, opts.projectDir);
167174
167484
  const client = createPiDreamerClient(opts);
@@ -167214,7 +167524,8 @@ function registerPiDreamerProject(opts) {
167214
167524
  cancelled = true;
167215
167525
  cleanup?.();
167216
167526
  },
167217
- runOnce
167527
+ runOnce,
167528
+ projectDir: opts.projectDir
167218
167529
  });
167219
167530
  }
167220
167531
  async function runPiDreamForProject(projectIdentity) {
@@ -167241,7 +167552,7 @@ async function awaitInFlightDreamers() {
167241
167552
  function createPiDreamerClient(opts) {
167242
167553
  const runner2 = piSubagentRunnerFactory();
167243
167554
  const model = opts.config.model;
167244
- const fallbackModels = normalizeFallbackModels(opts.config.fallback_models);
167555
+ const fallbackModels = resolveFallbackChain(DREAMER_AGENT, opts.config.fallback_models);
167245
167556
  const session = {
167246
167557
  create: async (args) => {
167247
167558
  const sessionId = `magic-context-pi-dream-${++sessionCounter}`;
@@ -167301,15 +167612,6 @@ function createPiDreamerClient(opts) {
167301
167612
  };
167302
167613
  return { session };
167303
167614
  }
167304
- function normalizeFallbackModels(value) {
167305
- if (Array.isArray(value)) {
167306
- return value;
167307
- }
167308
- if (typeof value === "string" && value.trim().length > 0) {
167309
- return [value];
167310
- }
167311
- return;
167312
- }
167313
167615
  function readDirectory(args) {
167314
167616
  const query = args.query;
167315
167617
  if (typeof query !== "object" || query === null) {
@@ -167496,7 +167798,6 @@ function registerCtxDreamCommand(pi, deps) {
167496
167798
  }
167497
167799
 
167498
167800
  // ../plugin/src/hooks/magic-context/execute-flush.ts
167499
- init_logger();
167500
167801
  function executeFlush(db, sessionId) {
167501
167802
  try {
167502
167803
  const pendingOps = getPendingOps(db, sessionId);
@@ -167528,7 +167829,6 @@ function executeFlush(db, sessionId) {
167528
167829
  import * as crypto2 from "node:crypto";
167529
167830
 
167530
167831
  // ../plugin/src/features/magic-context/scheduler.ts
167531
- init_logger();
167532
167832
  var TTL_PATTERN = /^(\d+)([smh])$/;
167533
167833
  var NUMERIC_PATTERN = /^\d+$/;
167534
167834
  var UNIT_TO_MS = {
@@ -167583,6 +167883,7 @@ function createScheduler(config2) {
167583
167883
  }
167584
167884
  };
167585
167885
  }
167886
+
167586
167887
  // ../plugin/src/features/magic-context/tagger.ts
167587
167888
  var TOOL_COMPOSITE_KEY_SEP = "\x00";
167588
167889
  function makeToolCompositeKey(ownerMsgId, callId) {
@@ -168342,7 +168643,6 @@ function replayCavemanCompression(sessionId, db, targets, tags) {
168342
168643
  }
168343
168644
 
168344
168645
  // ../plugin/src/hooks/magic-context/compartment-trigger.ts
168345
- init_logger();
168346
168646
  var PROACTIVE_TRIGGER_OFFSET_PERCENTAGE = 2;
168347
168647
  var POST_DROP_TARGET_RATIO = 0.75;
168348
168648
  var MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE = 6000;
@@ -168579,9 +168879,6 @@ class BoundedSessionMap {
168579
168879
  }
168580
168880
  }
168581
168881
 
168582
- // ../plugin/src/hooks/magic-context/inject-compartments.ts
168583
- init_logger();
168584
-
168585
168882
  // ../plugin/src/hooks/magic-context/decay-curve.ts
168586
168883
  var H50 = 24;
168587
168884
  var D = 25;
@@ -168645,6 +168942,9 @@ function escapeXmlAttr2(s) {
168645
168942
  function escapeXmlContent2(s) {
168646
168943
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
168647
168944
  }
168945
+ function isTieredRow(c) {
168946
+ return typeof c.p1 === "string" && c.p1.length > 0;
168947
+ }
168648
168948
  function tierBody(c, tier2) {
168649
168949
  const tiers = [c.p1, c.p2, c.p3, c.p4];
168650
168950
  const requested = tiers[tier2 - 1];
@@ -168674,12 +168974,13 @@ function renderOneCompartment(c, tier2) {
168674
168974
  const baseAttrs = `start="${c.startMessage}" end="${c.endMessage}" title="${escapeXmlAttr2(c.title)}"`;
168675
168975
  if (tier2 >= 5)
168676
168976
  return "";
168677
- if (c.legacy === 1) {
168678
- if (tier2 >= 4)
168977
+ if (c.legacy === 1 || !isTieredRow(c)) {
168978
+ const flat = (c.content ?? "").trim();
168979
+ if (tier2 >= 4 || flat.length === 0)
168679
168980
  return `<compartment ${baseAttrs} />`;
168680
168981
  return [
168681
168982
  `<compartment ${baseAttrs}>`,
168682
- escapeXmlContent2(legacyBodyForTier(c.content, tier2)),
168983
+ escapeXmlContent2(legacyBodyForTier(flat, tier2)),
168683
168984
  "</compartment>"
168684
168985
  ].join(`
168685
168986
  `);
@@ -168751,7 +169052,6 @@ function extractM0Block(m0Text, tag) {
168751
169052
  // ../plugin/src/hooks/magic-context/key-files-block.ts
168752
169053
  import { readFileSync as readFileSync9, realpathSync as realpathSync4 } from "node:fs";
168753
169054
  import { join as join14, sep as sep2 } from "node:path";
168754
- init_logger();
168755
169055
  var cachedKeyFilesBySession = new Map;
168756
169056
  var staleUpdates = new Map;
168757
169057
  function staleKey(update) {
@@ -168849,9 +169149,6 @@ ${blocks.join(`
168849
169149
  return rendered;
168850
169150
  }
168851
169151
 
168852
- // ../plugin/src/hooks/magic-context/inject-compartments.ts
168853
- await init_read_session_db();
168854
-
168855
169152
  // ../plugin/src/hooks/magic-context/temporal-awareness.ts
168856
169153
  var TEMPORAL_AWARENESS_THRESHOLD_SECONDS = 300;
168857
169154
  var SECONDS_PER_MINUTE = 60;
@@ -169008,9 +169305,6 @@ function renderMemoryBlockV2(memories, wrapper = "project-memory") {
169008
169305
  `);
169009
169306
  }
169010
169307
 
169011
- // ../plugin/src/hooks/magic-context/nudger.ts
169012
- init_logger();
169013
-
169014
169308
  // ../plugin/src/shared/format-bytes.ts
169015
169309
  function formatBytes(bytes) {
169016
169310
  if (bytes < 1024)
@@ -169212,9 +169506,6 @@ function estimateProjectedPercentage(db, sessionId, contextUsage, preloadedTags)
169212
169506
  return contextUsage.percentage * (1 - dropRatio);
169213
169507
  }
169214
169508
 
169215
- // src/context-handler.ts
169216
- init_logger();
169217
-
169218
169509
  // ../plugin/src/shared/tag-transcript.ts
169219
169510
  function tagTranscript(sessionId, transcript, tagger, db, options = {}) {
169220
169511
  const skipPrefixInjection = options.skipPrefixInjection === true;
@@ -169516,9 +169807,6 @@ function buildToolTarget(part, message) {
169516
169807
  };
169517
169808
  }
169518
169809
 
169519
- // ../plugin/src/features/magic-context/search.ts
169520
- init_logger();
169521
-
169522
169810
  // ../plugin/src/features/magic-context/literal-probes.ts
169523
169811
  var MAX_PROBES = 5;
169524
169812
  var MIN_PROBE_LENGTH = 3;
@@ -169575,7 +169863,6 @@ function containsProbeVerbatim(text, probes) {
169575
169863
  return probes.some((probe) => haystack.includes(probe.toLowerCase()));
169576
169864
  }
169577
169865
  // ../plugin/src/features/magic-context/memory/embedding-backfill.ts
169578
- init_logger();
169579
169866
  async function ensureMemoryEmbeddings(args) {
169580
169867
  const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
169581
169868
  if (!snapshot?.enabled) {
@@ -169614,7 +169901,6 @@ async function ensureMemoryEmbeddings(args) {
169614
169901
  return args.existingEmbeddings;
169615
169902
  }
169616
169903
  // ../plugin/src/features/magic-context/memory/promotion.ts
169617
- init_logger();
169618
169904
  function isPromotableCategory(category) {
169619
169905
  return PROMOTABLE_CATEGORIES.some((promotableCategory) => promotableCategory === category);
169620
169906
  }
@@ -170116,17 +170402,16 @@ ${trimmedBody}…
170116
170402
  }
170117
170403
 
170118
170404
  // src/auto-search-pi.ts
170119
- init_logger();
170120
170405
  var AUTO_SEARCH_TIMEOUT_MS = 3000;
170121
170406
  var DEFAULT_SCORE_THRESHOLD = 0.55;
170122
170407
  var DEFAULT_MIN_PROMPT_CHARS = 20;
170123
170408
  async function unifiedSearchWithTimeout(db, sessionId, projectPath, prompt, options, timeoutMs) {
170124
170409
  const controller = new AbortController;
170125
170410
  let timer;
170126
- const timeoutPromise = new Promise((resolve4) => {
170411
+ const timeoutPromise = new Promise((resolve5) => {
170127
170412
  timer = setTimeout(() => {
170128
170413
  controller.abort();
170129
- resolve4(null);
170414
+ resolve5(null);
170130
170415
  }, timeoutMs);
170131
170416
  });
170132
170417
  try {
@@ -170346,7 +170631,6 @@ ${hintText}`;
170346
170631
  function clearAutoSearchForPiSession(_sessionId) {}
170347
170632
 
170348
170633
  // src/compaction-marker-manager-pi.ts
170349
- init_logger();
170350
170634
  function applyDeferredPiCompactionMarker(deps, sessionId, pending) {
170351
170635
  try {
170352
170636
  const matches = getCompartmentsByEndMessageId(deps.db, sessionId, pending.endMessageId);
@@ -170488,7 +170772,6 @@ function stripSystemInjection(text) {
170488
170772
  }
170489
170773
 
170490
170774
  // src/heuristic-cleanup-pi.ts
170491
- init_logger();
170492
170775
  var DEDUP_SAFE_TOOLS = new Set([
170493
170776
  "mcp_grep",
170494
170777
  "mcp_read",
@@ -170738,9 +171021,6 @@ function buildMessageIdToMaxTagFromTargets(targets) {
170738
171021
  return byMessage;
170739
171022
  }
170740
171023
 
170741
- // src/inject-compartments-pi.ts
170742
- init_logger();
170743
-
170744
171024
  // src/read-session-pi.ts
170745
171025
  var SYNTH_USER_ID_PREFIX = "synth-user-";
170746
171026
  function resolvePiStableId(msg, index, entryIds, entryIdByRef) {
@@ -171123,6 +171403,16 @@ function safeGetActiveUserMemoriesPi(db) {
171123
171403
  throw error51;
171124
171404
  }
171125
171405
  }
171406
+ function memoryProjectPath(state) {
171407
+ return state.memoryEnabled === false ? undefined : state.projectIdentity;
171408
+ }
171409
+ var EMPTY_PI_HARD_SIGNALS = {
171410
+ systemHash: "",
171411
+ toolSetHash: "",
171412
+ modelKey: "",
171413
+ cacheExpired: false,
171414
+ lastResponseTime: 0
171415
+ };
171126
171416
  function decodeCachedM0(value) {
171127
171417
  if (!value)
171128
171418
  return null;
@@ -171169,7 +171459,10 @@ function getCachedMarkers(db, state, compartmentsForNormalization) {
171169
171459
  sessionFactsVersion: meta3.cachedM0SessionFactsVersion,
171170
171460
  materializedAt: meta3.cachedM0MaterializedAt,
171171
171461
  upgradeState: meta3.cachedM0UpgradeState,
171172
- lastBaselineEndMessageId: cachedBoundary
171462
+ lastBaselineEndMessageId: cachedBoundary,
171463
+ systemHash: meta3.cachedM0SystemHash ?? "",
171464
+ toolSetHash: meta3.cachedM0ToolSetHash ?? "",
171465
+ modelKey: meta3.cachedM0ModelKey ?? ""
171173
171466
  };
171174
171467
  }
171175
171468
  function lastBaselineEndMessageId(compartments) {
@@ -171180,24 +171473,25 @@ function readCurrentMarkers(db, state, projectDocsHash) {
171180
171473
  return readCurrentMarkersFromCompartments(db, state, getCompartments(db, state.sessionId), projectDocsHash);
171181
171474
  }
171182
171475
  function readCurrentMarkersFromCompartments(db, state, compartments, projectDocsHash) {
171183
- const memories = getMemoriesByProject(db, state.projectIdentity, [
171184
- "active",
171185
- "permanent"
171186
- ]);
171187
- const projectState = getProjectState(db, state.projectIdentity);
171476
+ const memPath = memoryProjectPath(state);
171477
+ const memories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"]) : [];
171478
+ const projectState = memPath ? getProjectState(db, memPath) : undefined;
171188
171479
  const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
171189
171480
  return {
171190
171481
  maxCompartmentSeq: compartments.length > 0 ? compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ) : EMPTY_MAX_COMPARTMENT_SEQ,
171191
171482
  maxMemoryId: memories.length > 0 ? memories.reduce((max, memory) => memory.id > max ? memory.id : max, 0) : 0,
171192
171483
  maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
171193
- maxMemoryMutationId: getMaxMemoryMutationId(db, state.projectIdentity) ?? 0,
171484
+ maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
171194
171485
  projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
171195
171486
  projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
171196
171487
  projectDocsHash: projectDocsHash ?? readProjectDocsCanonical(state.projectDirectory).canonicalHash,
171197
171488
  sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
171198
171489
  materializedAt: Date.now(),
171199
171490
  upgradeState: `${PI_M0_UPGRADE_STATE}:${compartments.some((c) => c.legacy === 1) ? "legacy" : "ready"}`,
171200
- lastBaselineEndMessageId: lastBaselineEndMessageId(compartments)
171491
+ lastBaselineEndMessageId: lastBaselineEndMessageId(compartments),
171492
+ systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
171493
+ toolSetHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).toolSetHash,
171494
+ modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey
171201
171495
  };
171202
171496
  }
171203
171497
  function mustMaterializePi(state, db, currentCompartmentsOverride) {
@@ -171214,7 +171508,19 @@ function mustMaterializePi(state, db, currentCompartmentsOverride) {
171214
171508
  if (getCachedMarkers(db, state, currentCompartments) === null) {
171215
171509
  return { value: true, reason: "cache_invalid" };
171216
171510
  }
171217
- const cachedMaxCompartmentSeq = normalizeCachedMaxCompartmentSeq(meta3.cachedM0MaxCompartmentSeq ?? EMPTY_MAX_COMPARTMENT_SEQ, currentCompartments);
171511
+ const hard = state.hardSignals ?? EMPTY_PI_HARD_SIGNALS;
171512
+ if (hard.modelKey !== "" && hard.modelKey !== (meta3.cachedM0ModelKey ?? "")) {
171513
+ return { value: true, reason: "model_change" };
171514
+ }
171515
+ if (hard.systemHash !== "" && hard.systemHash !== (meta3.cachedM0SystemHash ?? "")) {
171516
+ return { value: true, reason: "system_hash" };
171517
+ }
171518
+ if (hard.toolSetHash !== "" && hard.toolSetHash !== (meta3.cachedM0ToolSetHash ?? "")) {
171519
+ return { value: true, reason: "tool_set_hash" };
171520
+ }
171521
+ if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (meta3.cachedM0MaterializedAt ?? 0)) {
171522
+ return { value: true, reason: "ttl_idle" };
171523
+ }
171218
171524
  if (meta3.cachedM0UpgradeState !== current.upgradeState) {
171219
171525
  return { value: true, reason: "renderer_upgrade" };
171220
171526
  }
@@ -171224,15 +171530,9 @@ function mustMaterializePi(state, db, currentCompartmentsOverride) {
171224
171530
  if (current.projectMemoryEpoch !== (meta3.cachedM0ProjectMemoryEpoch ?? 0)) {
171225
171531
  return { value: true, reason: "project_memory_change" };
171226
171532
  }
171227
- if (current.projectUserProfileVersion !== (meta3.cachedM0ProjectUserProfileVersion ?? 0)) {
171228
- return { value: true, reason: "user_profile_change" };
171229
- }
171230
171533
  if (current.maxMutationId !== (meta3.cachedM0MaxMutationId ?? 0)) {
171231
171534
  return { value: true, reason: "pending_mutations" };
171232
171535
  }
171233
- if (current.maxCompartmentSeq !== cachedMaxCompartmentSeq) {
171234
- return { value: true, reason: "new_compartment" };
171235
- }
171236
171536
  return { value: false, reason: null };
171237
171537
  }
171238
171538
  function renderUserProfileBlock(db, wrapper = "user-profile", memoriesOverride) {
@@ -171245,7 +171545,8 @@ ${memories.map((memory) => `- ${escapeXmlContent(memory.content)}`).join(`
171245
171545
  </${wrapper}>`;
171246
171546
  }
171247
171547
  function renderM0Pi(state, db, projectDocs = readProjectDocsCanonical(state.projectDirectory).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride) {
171248
- const allMemories = memoriesOverride ?? getMemoriesByProject(db, state.projectIdentity, ["active", "permanent"]);
171548
+ const memPath = memoryProjectPath(state);
171549
+ const allMemories = memoriesOverride ?? (memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"]) : []);
171249
171550
  const memories = allMemories.length > 0 ? trimMemoriesToBudgetV2(state.sessionId, allMemories, state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS).renderOrder : allMemories;
171250
171551
  const memoryBlock = memories.length > 0 ? renderMemoryBlockV2(memories) : undefined;
171251
171552
  const baseHistoryBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
@@ -171295,24 +171596,28 @@ class PiMaterializeContentionError extends Error {
171295
171596
  }
171296
171597
  }
171297
171598
  function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.projectDirectory), memoryCutoff) {
171599
+ const memPath = memoryProjectPath(state);
171298
171600
  const read = db.transaction(() => {
171299
171601
  const compartments = getCompartments(db, state.sessionId);
171300
- const memories = getMemoriesByProject(db, state.projectIdentity, ["active", "permanent"], memoryCutoff);
171602
+ const memories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], memoryCutoff) : [];
171301
171603
  const userProfile = safeGetActiveUserMemoriesPi(db);
171302
- const projectState = getProjectState(db, state.projectIdentity);
171604
+ const projectState = memPath ? getProjectState(db, memPath) : undefined;
171303
171605
  const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
171304
171606
  const markers = {
171305
171607
  maxCompartmentSeq: compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ),
171306
171608
  maxMemoryId: memories.reduce((max, memory) => memory.id > max ? memory.id : max, 0),
171307
171609
  maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
171308
- maxMemoryMutationId: getMaxMemoryMutationId(db, state.projectIdentity) ?? 0,
171610
+ maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
171309
171611
  projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
171310
171612
  projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
171311
171613
  projectDocsHash: docs.canonicalHash,
171312
171614
  sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
171313
171615
  materializedAt: Date.now(),
171314
171616
  upgradeState: `${PI_M0_UPGRADE_STATE}:${compartments.some((c) => c.legacy === 1) ? "legacy" : "ready"}`,
171315
- lastBaselineEndMessageId: lastBaselineEndMessageId(compartments)
171617
+ lastBaselineEndMessageId: lastBaselineEndMessageId(compartments),
171618
+ systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
171619
+ toolSetHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).toolSetHash,
171620
+ modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey
171316
171621
  };
171317
171622
  return { docs, markers, compartments, memories, userProfile };
171318
171623
  });
@@ -171388,7 +171693,10 @@ function materializeM0Pi(state, db) {
171388
171693
  projectDocsHash: snapshotMarkers.projectDocsHash,
171389
171694
  materializedAt: snapshotMarkers.materializedAt,
171390
171695
  sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
171391
- upgradeState: snapshotMarkers.upgradeState
171696
+ upgradeState: snapshotMarkers.upgradeState,
171697
+ systemHash: snapshotMarkers.systemHash,
171698
+ toolSetHash: snapshotMarkers.toolSetHash,
171699
+ modelKey: snapshotMarkers.modelKey
171392
171700
  });
171393
171701
  db.prepare("UPDATE session_meta SET memory_block_count = ?, memory_block_ids = ? WHERE session_id = ?").run(renderedMemoryIds.length, JSON.stringify(renderedMemoryIds), state.sessionId);
171394
171702
  setCachedBoundary(db, state.sessionId, snapshotMarkers.lastBaselineEndMessageId);
@@ -171470,20 +171778,21 @@ ${lines.join(`
171470
171778
  count: mutations.length
171471
171779
  };
171472
171780
  }
171473
- function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRenderedKeyFilesBlock) {
171781
+ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRenderedKeyFilesBlock, compartmentsOverride) {
171474
171782
  const sections = [];
171475
171783
  const keyFiles = renderedKeyFilesBlockPi(state, db, preRenderedKeyFilesBlock);
171476
171784
  if (keyFiles)
171477
171785
  sections.push(keyFiles);
171478
- const memoryUpdates = renderMemoryUpdatesBlockPi({
171786
+ const memPath = memoryProjectPath(state);
171787
+ const memoryUpdates = memPath ? renderMemoryUpdatesBlockPi({
171479
171788
  db,
171480
- projectPath: state.projectIdentity,
171789
+ projectPath: memPath,
171481
171790
  afterId: markers.maxMemoryMutationId,
171482
171791
  renderedMemoryIds
171483
- });
171792
+ }) : { block: undefined, count: 0 };
171484
171793
  if (memoryUpdates.block)
171485
171794
  sections.push(memoryUpdates.block);
171486
- const newCompartments = getCompartments(db, state.sessionId).filter((compartment) => compartment.sequence > markers.maxCompartmentSeq);
171795
+ const newCompartments = (compartmentsOverride ?? getCompartments(db, state.sessionId)).filter((compartment) => compartment.sequence > markers.maxCompartmentSeq);
171487
171796
  if (newCompartments.length > 0) {
171488
171797
  const body = newCompartments.map((compartment) => renderCompartmentAtTier(compartment, 1)).join(`
171489
171798
 
@@ -171492,7 +171801,7 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
171492
171801
  ${body}
171493
171802
  </new-compartments>`);
171494
171803
  }
171495
- const newMemories = getMemoriesByProject(db, state.projectIdentity, ["active", "permanent"], markers.materializedAt).filter((memory) => memory.id > markers.maxMemoryId);
171804
+ const newMemories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], markers.materializedAt).filter((memory) => memory.id > markers.maxMemoryId) : [];
171496
171805
  if (newMemories.length > 0) {
171497
171806
  const memoryBudget = state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
171498
171807
  const trimmedNewMemories = trimMemoriesToBudgetV2(state.sessionId, newMemories, Math.max(1, Math.floor(memoryBudget * 0.25))).renderOrder;
@@ -171554,6 +171863,9 @@ function readCachedPiM0M1Row(db, sessionId) {
171554
171863
  cached_m0_materialized_at,
171555
171864
  cached_m0_session_facts_version,
171556
171865
  cached_m0_upgrade_state,
171866
+ cached_m0_system_hash,
171867
+ cached_m0_tool_set_hash,
171868
+ cached_m0_model_key,
171557
171869
  cached_m0_last_baseline_end_message_id,
171558
171870
  memory_block_ids
171559
171871
  FROM session_meta
@@ -171591,14 +171903,17 @@ function markersFromCachedPiRow(row, compartmentsForNormalization) {
171591
171903
  materializedAt: row.cached_m0_materialized_at,
171592
171904
  sessionFactsVersion: row.cached_m0_session_facts_version,
171593
171905
  upgradeState: row.cached_m0_upgrade_state,
171594
- lastBaselineEndMessageId: typeof row.cached_m0_last_baseline_end_message_id === "string" && row.cached_m0_last_baseline_end_message_id.length > 0 ? row.cached_m0_last_baseline_end_message_id : null
171906
+ lastBaselineEndMessageId: typeof row.cached_m0_last_baseline_end_message_id === "string" && row.cached_m0_last_baseline_end_message_id.length > 0 ? row.cached_m0_last_baseline_end_message_id : null,
171907
+ systemHash: row.cached_m0_system_hash ?? "",
171908
+ toolSetHash: row.cached_m0_tool_set_hash ?? "",
171909
+ modelKey: row.cached_m0_model_key ?? ""
171595
171910
  };
171596
171911
  }
171597
171912
  function cachedPiRowMatchesSnapshot(args) {
171598
171913
  const rowMarkers = markersFromCachedPiRow(args.row, args.compartmentsForNormalization);
171599
171914
  if (!rowMarkers)
171600
171915
  return false;
171601
- return bufferEqualsNullable(args.row.cached_m0_bytes, args.m0Bytes) && rowMarkers.projectMemoryEpoch === args.markers.projectMemoryEpoch && rowMarkers.projectUserProfileVersion === args.markers.projectUserProfileVersion && rowMarkers.maxCompartmentSeq === args.markers.maxCompartmentSeq && rowMarkers.maxMemoryId === args.markers.maxMemoryId && rowMarkers.maxMutationId === args.markers.maxMutationId && rowMarkers.maxMemoryMutationId === args.markers.maxMemoryMutationId && (rowMarkers.projectDocsHash ?? "") === (args.markers.projectDocsHash ?? "") && rowMarkers.materializedAt === args.markers.materializedAt && rowMarkers.sessionFactsVersion === args.markers.sessionFactsVersion && (rowMarkers.upgradeState ?? null) === (args.markers.upgradeState ?? null);
171916
+ return bufferEqualsNullable(args.row.cached_m0_bytes, args.m0Bytes) && rowMarkers.projectMemoryEpoch === args.markers.projectMemoryEpoch && rowMarkers.projectUserProfileVersion === args.markers.projectUserProfileVersion && rowMarkers.maxCompartmentSeq === args.markers.maxCompartmentSeq && rowMarkers.maxMemoryId === args.markers.maxMemoryId && rowMarkers.maxMutationId === args.markers.maxMutationId && rowMarkers.maxMemoryMutationId === args.markers.maxMemoryMutationId && (rowMarkers.projectDocsHash ?? "") === (args.markers.projectDocsHash ?? "") && rowMarkers.materializedAt === args.markers.materializedAt && rowMarkers.sessionFactsVersion === args.markers.sessionFactsVersion && (rowMarkers.upgradeState ?? null) === (args.markers.upgradeState ?? null) && (rowMarkers.systemHash ?? "") === (args.markers.systemHash ?? "") && (rowMarkers.toolSetHash ?? "") === (args.markers.toolSetHash ?? "") && (rowMarkers.modelKey ?? "") === (args.markers.modelKey ?? "");
171602
171917
  }
171603
171918
  function decodeCachedM1(row, sessionId) {
171604
171919
  if (!row.cached_m1_bytes) {
@@ -171656,14 +171971,16 @@ function softRefreshCachedM1Pi(args) {
171656
171971
  if (!markers) {
171657
171972
  throw new PiMaterializeContentionError(`invalid cached m[0] markers for ${args.state.sessionId}`);
171658
171973
  }
171659
- const rendered = renderM1PiWithMetadata(args.state, args.db, markers, parseMemoryBlockIds(row.memory_block_ids), preRenderedKeyFilesBlock);
171974
+ const rendered = renderM1PiWithMetadata(args.state, args.db, markers, parseMemoryBlockIds(row.memory_block_ids), preRenderedKeyFilesBlock, args.compartmentsForNormalization);
171660
171975
  const m1Bytes = Buffer.from(rendered.text, "utf8");
171661
- args.db.prepare("UPDATE session_meta SET cached_m1_bytes = ? WHERE session_id = ?").run(m1Bytes, args.state.sessionId);
171976
+ const latestCompartment = args.compartmentsForNormalization.at(-1);
171977
+ const advancedBoundary = latestCompartment?.endMessageId && latestCompartment.endMessageId.length > 0 ? latestCompartment.endMessageId : markers.lastBaselineEndMessageId;
171978
+ args.db.prepare("UPDATE session_meta SET cached_m1_bytes = ?, cached_m0_last_baseline_end_message_id = ? WHERE session_id = ?").run(m1Bytes, advancedBoundary, args.state.sessionId);
171662
171979
  args.db.exec("COMMIT");
171663
171980
  return {
171664
171981
  m0: decodeCachedM0(row.cached_m0_bytes) ?? "",
171665
171982
  m1: rendered.text,
171666
- markers,
171983
+ markers: { ...markers, lastBaselineEndMessageId: advancedBoundary },
171667
171984
  memoryUpdateCount: rendered.memoryUpdateCount,
171668
171985
  recomputed: true
171669
171986
  };
@@ -171782,8 +172099,15 @@ function injectM0M1Pi(state, db, piMessages, entryIds, recomputeM1ThisPass = fal
171782
172099
  m1 = replayed.m1;
171783
172100
  markers = replayed.markers;
171784
172101
  }
171785
- const M0_DRIFT_RATIO_FLOOR = 2000;
171786
- if (!materialized && !contentionExhausted && m1Recomputed && recomputeM1ThisPass && (memoryUpdateCount > 40 || m1 !== PI_M1_PLACEHOLDER && m0.length >= M0_DRIFT_RATIO_FLOOR && m1.length > m0.length * 0.15)) {
172102
+ const M0_DRIFT_RATIO_FLOOR_TOKENS = 500;
172103
+ const M1_DRIFT_RATIO = 0.15;
172104
+ const M1_ABSOLUTE_CAP_RATIO = 0.2;
172105
+ const m1AbsoluteBudget = (state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS) * M1_ABSOLUTE_CAP_RATIO;
172106
+ const m1HasContent = m1 !== PI_M1_PLACEHOLDER;
172107
+ const m1Tokens = m1HasContent ? estimateTokens(m1) : 0;
172108
+ const m0Tokens = estimateTokens(m0);
172109
+ const m1OverAbsoluteCap = m1HasContent && m1Tokens > m1AbsoluteBudget;
172110
+ if (!materialized && !contentionExhausted && m1Recomputed && recomputeM1ThisPass && (memoryUpdateCount > 40 || m1OverAbsoluteCap || m1HasContent && m0Tokens >= M0_DRIFT_RATIO_FLOOR_TOKENS && m1Tokens > m0Tokens * M1_DRIFT_RATIO)) {
171787
172111
  decision = { value: true, reason: "drift" };
171788
172112
  try {
171789
172113
  const result = materializeM0PiWithRetry(state, db);
@@ -171804,10 +172128,10 @@ function injectM0M1Pi(state, db, piMessages, entryIds, recomputeM1ThisPass = fal
171804
172128
  injected: true,
171805
172129
  compartmentCount: getCompartments(db, state.sessionId).length,
171806
172130
  factCount: 0,
171807
- memoryCount: getMemoriesByProject(db, state.projectIdentity, [
172131
+ memoryCount: memoryProjectPath(state) ? getMemoriesByProject(db, memoryProjectPath(state), [
171808
172132
  "active",
171809
172133
  "permanent"
171810
- ]).length,
172134
+ ]).length : 0,
171811
172135
  skippedVisibleMessages,
171812
172136
  m0Materialized: materialized,
171813
172137
  m0Reason: decision.reason,
@@ -171966,7 +172290,6 @@ function isRecord3(value) {
171966
172290
  }
171967
172291
 
171968
172292
  // ../plugin/src/features/magic-context/compartment-embedding.ts
171969
- init_logger();
171970
172293
  async function embedAndStoreCompartments(db, sessionId, projectPath, compartments) {
171971
172294
  if (compartments.length === 0)
171972
172295
  return;
@@ -172863,7 +173186,6 @@ Memory is disabled for this project: do NOT emit a <facts> block. Produce compar
172863
173186
  }
172864
173187
 
172865
173188
  // ../plugin/src/hooks/magic-context/compartment-runner-drop-queue.ts
172866
- init_logger();
172867
173189
  function queueDropsForCompartmentalizedMessages(db, sessionId, upToMessageIndex) {
172868
173190
  const tags = getTagsBySession(db, sessionId);
172869
173191
  const { messageFileKeys, toolObservations } = getRawSessionTagKeysThrough(sessionId, upToMessageIndex);
@@ -173105,6 +173427,27 @@ function validateHistorianOutput(text, _sessionId, chunk, _priorCompartments, se
173105
173427
  events: parsed.events.length > 0 ? parsed.events : undefined
173106
173428
  };
173107
173429
  }
173430
+ var HISTORIAN_PERSISTENT_FAILURE_THRESHOLD = 3;
173431
+ function buildHistorianFailureNotice(failureCount, lastError) {
173432
+ if (failureCount >= HISTORIAN_PERSISTENT_FAILURE_THRESHOLD) {
173433
+ return [
173434
+ "## Magic Context — history comparting needs attention",
173435
+ "",
173436
+ `Magic Context has been unable to compart this session's history ${failureCount} times in a row. This usually means the configured historian model is misconfigured or unreachable (Magic Context already retried every fallback model automatically).`,
173437
+ "",
173438
+ `Last error: ${lastError}`,
173439
+ "",
173440
+ "Check your historian model in magic-context.jsonc, then restart. Your conversation keeps working normally in the meantime — this only affects how older history is summarized."
173441
+ ].join(`
173442
+ `);
173443
+ }
173444
+ return [
173445
+ "## Magic Context",
173446
+ "",
173447
+ "Hit a transient issue comparting history this turn — Magic Context will retry automatically on the next turn. Nothing is lost and your conversation continues normally. You'll only be alerted again if this keeps happening."
173448
+ ].join(`
173449
+ `);
173450
+ }
173108
173451
  function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationError) {
173109
173452
  return [
173110
173453
  originalPrompt,
@@ -174943,7 +175286,7 @@ ${body}
174943
175286
  function renderSessionRefCompartment(c) {
174944
175287
  const importance = c.importance ?? 50;
174945
175288
  const attrs = `start="${c.startMessage}" end="${c.endMessage}" title="${escapeXmlAttr(c.title)}"` + (c.episodeType ? ` episode_type="${escapeXmlAttr(c.episodeType)}"` : "") + ` importance="${importance}"`;
174946
- if (c.p1 != null) {
175289
+ if (typeof c.p1 === "string" && c.p1.length > 0) {
174947
175290
  const p4 = c.p4 && c.p4.length > 0 ? `<p4>
174948
175291
  ${escapeXmlContent(c.p4)}
174949
175292
  </p4>` : "<p4/>";
@@ -174987,7 +175330,6 @@ function buildReferenceBlocks(args) {
174987
175330
  }
174988
175331
 
174989
175332
  // src/pi-historian-runner.ts
174990
- init_logger();
174991
175333
  var HISTORIAN_AGENT_NAME = "magic-context-historian";
174992
175334
  var DEFAULT_HISTORIAN_TIMEOUT_MS2 = 120000;
174993
175335
  var HISTORIAN_ALERT_COOLDOWN_MS = 60 * 1000;
@@ -175045,8 +175387,10 @@ async function runPiHistorian(deps) {
175045
175387
  const existingValidationError = validateStoredCompartments(priorCompartments);
175046
175388
  if (existingValidationError) {
175047
175389
  sessionLog(sessionId, `historian failure: source=existing-validation reason="${existingValidationError}"`);
175048
- incrementHistorianFailure(db, sessionId, existingValidationError);
175049
- await notify(`Historian skipped: existing stored compartments are invalid: ${existingValidationError}`);
175390
+ {
175391
+ const failCount = incrementHistorianFailure(db, sessionId, existingValidationError);
175392
+ await notify(buildHistorianFailureNotice(failCount, existingValidationError));
175393
+ }
175050
175394
  return;
175051
175395
  }
175052
175396
  const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
@@ -175065,8 +175409,10 @@ async function runPiHistorian(deps) {
175065
175409
  const chunkCoverageError = validateChunkCoverage(chunk);
175066
175410
  if (chunkCoverageError) {
175067
175411
  sessionLog(sessionId, `historian failure: source=chunk-coverage reason="${chunkCoverageError}" chunkRange=${chunk.startIndex}-${chunk.endIndex}`);
175068
- incrementHistorianFailure(db, sessionId, chunkCoverageError);
175069
- await notify(`Historian skipped: raw chunk could not be safely chunked: ${chunkCoverageError}`);
175412
+ {
175413
+ const failCount = incrementHistorianFailure(db, sessionId, chunkCoverageError);
175414
+ await notify(buildHistorianFailureNotice(failCount, chunkCoverageError));
175415
+ }
175070
175416
  return;
175071
175417
  }
175072
175418
  const projectPath = resolveProjectIdentity(directory);
@@ -175195,8 +175541,10 @@ ${chunk.text}`,
175195
175541
  if (validatedPass.kind !== "ok") {
175196
175542
  const errorMsg = validatedPass.kind === "validation-failed" ? validatedPass.error : validatedPass.kind === "spawn-failed" ? `subagent run failed (${validatedPass.reason}): ${validatedPass.error}` : "historian returned no usable text";
175197
175543
  sessionLog(sessionId, `historian failure: ${errorMsg}`);
175198
- incrementHistorianFailure(db, sessionId, errorMsg);
175199
- await notify(`Historian failed: ${errorMsg}`);
175544
+ {
175545
+ const failCount = incrementHistorianFailure(db, sessionId, errorMsg);
175546
+ await notify(buildHistorianFailureNotice(failCount, errorMsg));
175547
+ }
175200
175548
  return;
175201
175549
  }
175202
175550
  if (twoPass && validatedPass.kind === "ok") {
@@ -175241,8 +175589,10 @@ ${chunk.text}`,
175241
175589
  if (lastNewEnd + 1 <= offset) {
175242
175590
  const errorMsg = `historian returned compartments that did not advance past raw message ${offset - 1}`;
175243
175591
  sessionLog(sessionId, `historian failure: source=no-progress newCompartmentCount=${newCompartments.length} lastNewEnd=${lastNewEnd} priorEnd=${offset - 1}`);
175244
- incrementHistorianFailure(db, sessionId, errorMsg);
175245
- await notify(`Historian failed: ${errorMsg}`);
175592
+ {
175593
+ const failCount = incrementHistorianFailure(db, sessionId, errorMsg);
175594
+ await notify(buildHistorianFailureNotice(failCount, errorMsg));
175595
+ }
175246
175596
  return;
175247
175597
  }
175248
175598
  const markerSummary = buildPiCompactionSummary(newCompartments);
@@ -175356,8 +175706,10 @@ ${chunk.text}`,
175356
175706
  const desc = describeError(error51);
175357
175707
  telemetry.failureReason = `exception: ${desc.brief}`;
175358
175708
  sessionLog(sessionId, `historian failure: source=exception ${desc.brief}${desc.stackHead ? ` stackHead="${desc.stackHead}"` : ""}`);
175359
- incrementHistorianFailure(db, sessionId, desc.brief);
175360
- await notify(`Historian failed unexpectedly: ${desc.brief}`);
175709
+ {
175710
+ const failCount = incrementHistorianFailure(db, sessionId, desc.brief);
175711
+ await notify(buildHistorianFailureNotice(failCount, desc.brief));
175712
+ }
175361
175713
  } finally {
175362
175714
  updateSessionMeta(db, sessionId, { compartmentInProgress: false });
175363
175715
  try {
@@ -175770,7 +176122,6 @@ function replayStrippedInlineThinkingPi(args) {
175770
176122
  }
175771
176123
 
175772
176124
  // src/strip-placeholders-pi.ts
175773
- init_logger();
175774
176125
  var DROPPED_SEGMENT_PATTERN = /^\[dropped(?: §[^§]+§)?\]$/;
175775
176126
  function isDroppedOnlyText(text) {
175776
176127
  const trimmed = text.trim();
@@ -175822,6 +176173,7 @@ function stripPiDroppedPlaceholderMessages(args) {
175822
176173
  };
175823
176174
  const canPrune = (isCacheBusting || args.forceDiscovery === true) && !!stableIdByRef;
175824
176175
  const presentIds = canPrune ? new Set : null;
176176
+ const discoveredIds = [];
175825
176177
  if (isCacheBusting || args.forceDiscovery) {
175826
176178
  for (let i = 0;i < messages.length; i++) {
175827
176179
  const id = idOf(messages[i], i);
@@ -175832,6 +176184,7 @@ function stripPiDroppedPlaceholderMessages(args) {
175832
176184
  continue;
175833
176185
  if (!idsToStrip.has(id)) {
175834
176186
  idsToStrip.add(id);
176187
+ discoveredIds.push(id);
175835
176188
  discovered++;
175836
176189
  }
175837
176190
  }
@@ -175846,17 +176199,20 @@ function stripPiDroppedPlaceholderMessages(args) {
175846
176199
  }
175847
176200
  let pruned = 0;
175848
176201
  if (presentIds) {
175849
- const finalIds = new Set;
175850
- for (const id of idsToStrip) {
175851
- if (presentIds.has(id))
175852
- finalIds.add(id);
175853
- }
175854
- pruned = idsToStrip.size - finalIds.size;
175855
- if (discovered > 0 || pruned > 0) {
175856
- setStrippedPlaceholderIds(db, sessionId, finalIds);
176202
+ const removedIds = [];
176203
+ for (const id of persistedIds) {
176204
+ if (!presentIds.has(id))
176205
+ removedIds.push(id);
176206
+ }
176207
+ pruned = removedIds.length;
176208
+ if (discoveredIds.length > 0 || removedIds.length > 0) {
176209
+ applyStrippedPlaceholderDelta(db, sessionId, {
176210
+ add: discoveredIds,
176211
+ remove: removedIds
176212
+ });
175857
176213
  }
175858
- } else if (discovered > 0) {
175859
- setStrippedPlaceholderIds(db, sessionId, idsToStrip);
176214
+ } else if (discoveredIds.length > 0) {
176215
+ applyStrippedPlaceholderDelta(db, sessionId, { add: discoveredIds });
175860
176216
  }
175861
176217
  if (removed > 0 || discovered > 0 || pruned > 0) {
175862
176218
  sessionLog(sessionId, `placeholder strip: removed=${removed} discovered=${discovered} pruned=${pruned}`);
@@ -175881,6 +176237,7 @@ var PARTNER_FRAME_CLOSER_REDUCE = `
175881
176237
  Reduction prompts are routine housekeeping to keep the session fast and cheap — act on them as light maintenance, never as scarcity warnings. Keep individual operations efficient, but never let context size change *what* work you take on or *how thoroughly* you do it.`;
175882
176238
  var PARTNER_FRAME_CLOSER_NO_REDUCE = `
175883
176239
  Context is managed for you entirely automatically — there's nothing to prune and no warnings to act on. Stay reasonably concise per operation, and never let context size change *what* work you take on or *how thoroughly* you do it.`;
176240
+ var CTX_NOTE_GUIDANCE = `Use \`ctx_note\` ONLY for genuinely future concerns — something to revisit much later, not work coming up in the next few turns (that's already in your active context) and not active multi-step work (use todos for that). Magic Context preserves your full context across both compaction and restarts, so an upcoming restart or "let's come back to this later" is never a reason to take a note — nothing is lost either way. Notes you do take survive compression and resurface at natural work boundaries (after commits, historian runs, todo completion).`;
175884
176241
  function getToolHistoryGuidance(dropToolStructure) {
175885
176242
  if (dropToolStructure) {
175886
176243
  return `Compressed history intentionally omits tool calls and their outputs — summaries like "I edited file X" are historian records, not patterns to replicate. In the live conversation, older tool calls and their results are cleaned up to save context — you may see your own past messages referencing actions without the corresponding tool call or result visible. This is normal context management. ALWAYS use real tool calls; never simulate, fabricate, or inline tool outputs in your text. If there is no tool result message, the action did not happen. NEVER simulate, hallucinate or claim tool calls, command output, search results, file edits, or diffs in plain text as if they actually occurred.`;
@@ -175891,7 +176248,8 @@ var BASE_INTRO = (protectedTags, dropToolStructure) => `Messages and tool output
175891
176248
  Use \`ctx_reduce\` to manage context size. It supports one operation:
175892
176249
  - \`drop\`: Remove entirely (best for tool outputs you already acted on).
175893
176250
  Syntax: "3-5", "1,2,9", or "1-5,8,12-15". Last ${protectedTags} tags are protected.
175894
- Use \`ctx_note\` for deferred intentions — things to tackle later, not right now. NOT for task tracking (use todos). Notes survive context compression and you'll be reminded at natural work boundaries (after commits, historian runs, todo completion).
176251
+ Do not announce or narrate \`ctx_reduce\` drops — just call the tool silently. Saying "I'll drop these outputs" wastes tokens the user does not care about.
176252
+ ${CTX_NOTE_GUIDANCE}
175895
176253
  Use \`ctx_memory\` to manage cross-session project memories. Write new memories or delete stale ones. Memories persist across sessions and are automatically injected into new sessions.
175896
176254
  **Save to memory proactively**: If you spent multiple turns finding something (a file path, a DB location, a config pattern, a workaround), save it with \`ctx_memory\` so future sessions don't repeat the search. Examples:
175897
176255
  - Found a project's source code path after searching → \`ctx_memory(action="write", category="ENVIRONMENT", content="OpenCode source is at ~/Work/OSS/opencode")\`
@@ -175911,7 +176269,7 @@ NEVER drop large ranges blindly (e.g., "1-50"). Review each tag before deciding.
175911
176269
  NEVER drop user messages — they are short and will be summarized by compartmentalization automatically. Dropping them loses context the historian needs.
175912
176270
  NEVER drop assistant text messages unless they are exceptionally large. Your conversation messages are lightweight; only large tool outputs are worth dropping.
175913
176271
  Before your turn finishes, consider using \`ctx_reduce\` to drop large tool outputs you no longer need.`;
175914
- var BASE_INTRO_NO_REDUCE = (dropToolStructure) => `Use \`ctx_note\` for deferred intentions — things to tackle later, not right now. NOT for task tracking (use todos). Notes survive context compression and you'll be reminded at natural work boundaries (after commits, historian runs, todo completion).
176272
+ var BASE_INTRO_NO_REDUCE = (dropToolStructure) => `${CTX_NOTE_GUIDANCE}
175915
176273
  Use \`ctx_memory\` to manage cross-session project memories. Write new memories or delete stale ones. Memories persist across sessions and are automatically injected into new sessions.
175916
176274
  **Save to memory proactively**: If you spent multiple turns finding something (a file path, a DB location, a config pattern, a workaround), save it with \`ctx_memory\` so future sessions don't repeat the search. Examples:
175917
176275
  - Found a project's source code path after searching → \`ctx_memory(action="write", category="ENVIRONMENT", content="OpenCode source is at ~/Work/OSS/opencode")\`
@@ -175974,7 +176332,6 @@ Prefer many small targeted operations over one large blanket operation, and keep
175974
176332
  }
175975
176333
 
175976
176334
  // src/system-prompt.ts
175977
- init_logger();
175978
176335
  var MAGIC_CONTEXT_MARKER = "## Magic Context";
175979
176336
  var stickyDateBySession = new Map;
175980
176337
  function buildMagicContextBlock(opts) {
@@ -176094,8 +176451,8 @@ function injectPiTemporalMarkers(messages) {
176094
176451
  // src/timeout.ts
176095
176452
  function withTimeout(p, ms) {
176096
176453
  let handle;
176097
- const timeout = new Promise((resolve4) => {
176098
- handle = setTimeout(() => resolve4(undefined), ms);
176454
+ const timeout = new Promise((resolve5) => {
176455
+ handle = setTimeout(() => resolve5(undefined), ms);
176099
176456
  handle.unref?.();
176100
176457
  });
176101
176458
  return Promise.race([p, timeout]).finally(() => {
@@ -176702,7 +177059,9 @@ function consumeDeferredMaterialization(sessionId) {
176702
177059
  deferredMaterializationSessions.delete(sessionId);
176703
177060
  return wasSet;
176704
177061
  }
177062
+ var MAX_TRACKED_SESSIONS = 100;
176705
177063
  function trackSessionForProject(projectIdentity, sessionId) {
177064
+ activeContextHandlerSessions.delete(sessionId);
176706
177065
  activeContextHandlerSessions.add(sessionId);
176707
177066
  let sessions = sessionsByProject.get(projectIdentity);
176708
177067
  if (!sessions) {
@@ -176710,6 +177069,12 @@ function trackSessionForProject(projectIdentity, sessionId) {
176710
177069
  sessionsByProject.set(projectIdentity, sessions);
176711
177070
  }
176712
177071
  sessions.add(sessionId);
177072
+ while (activeContextHandlerSessions.size > MAX_TRACKED_SESSIONS) {
177073
+ const oldest = activeContextHandlerSessions.values().next().value;
177074
+ if (oldest === undefined || oldest === sessionId)
177075
+ break;
177076
+ clearContextHandlerSession(oldest);
177077
+ }
176713
177078
  }
176714
177079
  function isContextHandlerSessionActive(sessionId) {
176715
177080
  return activeContextHandlerSessions.has(sessionId);
@@ -177093,24 +177458,26 @@ function registerPiContextHandler(pi, options) {
177093
177458
  }
177094
177459
  let usagePercentage = 0;
177095
177460
  let usageInputTokens = 0;
177461
+ let usedPersistedUsage = false;
177096
177462
  if (sessionMetaForUsage.lastContextPercentage > 0 && sessionMetaForUsage.lastInputTokens > 0) {
177097
177463
  usagePercentage = sessionMetaForUsage.lastContextPercentage;
177098
177464
  usageInputTokens = sessionMetaForUsage.lastInputTokens;
177465
+ usedPersistedUsage = true;
177099
177466
  } else {
177100
177467
  usagePercentage = typeof piUsage?.percent === "number" ? piUsage.percent : 0;
177101
177468
  usageInputTokens = typeof piUsage?.tokens === "number" ? piUsage.tokens : 0;
177102
177469
  }
177103
- let usageContextLimit = typeof piUsage?.contextWindow === "number" && piUsage.contextWindow > 0 ? piUsage.contextWindow : undefined;
177470
+ let usageContextLimit = isSaneLimit(piUsage?.contextWindow) ? piUsage.contextWindow : undefined;
177104
177471
  const tEmergencyRecovery = performance.now();
177472
+ let needsEmergencyBump = false;
177473
+ let emergencyRecoveryArmed = false;
177105
177474
  try {
177106
177475
  const overflowState = getOverflowState(options.db, sessionId);
177107
177476
  if (overflowState.detectedContextLimit > 0) {
177108
177477
  usageContextLimit = Math.min(usageContextLimit ?? overflowState.detectedContextLimit, overflowState.detectedContextLimit);
177109
177478
  }
177110
- if (overflowState.needsEmergencyRecovery && usagePercentage < 95) {
177111
- sessionLog(sessionId, `transform: overflow recovery flag set — bumping percentage from ${usagePercentage.toFixed(1)}% to 95% (detectedLimit=${overflowState.detectedContextLimit || "unknown"})`);
177112
- usagePercentage = 95;
177113
- }
177479
+ emergencyRecoveryArmed = overflowState.needsEmergencyRecovery;
177480
+ needsEmergencyBump = overflowState.needsEmergencyRecovery && usagePercentage < 95;
177114
177481
  } catch (err) {
177115
177482
  sessionLog(sessionId, `transform: overflow state read failed: ${err instanceof Error ? err.message : String(err)}`);
177116
177483
  }
@@ -177122,6 +177489,13 @@ function registerPiContextHandler(pi, options) {
177122
177489
  usageContextLimit = modelWindow;
177123
177490
  }
177124
177491
  }
177492
+ if (!usedPersistedUsage && isSaneLimit(usageContextLimit) && usageInputTokens > 0) {
177493
+ usagePercentage = usageInputTokens / usageContextLimit * 100;
177494
+ }
177495
+ if (needsEmergencyBump) {
177496
+ sessionLog(sessionId, `transform: overflow recovery flag set — bumping percentage to 95% (detectedLimit=${usageContextLimit ?? "unknown"})`);
177497
+ usagePercentage = 95;
177498
+ }
177125
177499
  let schedulerDecision;
177126
177500
  const tScheduler = performance.now();
177127
177501
  try {
@@ -177171,10 +177545,6 @@ function registerPiContextHandler(pi, options) {
177171
177545
  setDeferredExecutePendingIfAbsent(options.db, sessionId, flagPayload);
177172
177546
  }
177173
177547
  schedulerDecision = midTurnAdjustedSchedulerDecision;
177174
- const deferredExecutePending = peekDeferredExecutePending(options.db, sessionId);
177175
- if (deferredExecutePending !== null && schedulerDecision === "defer" && !midTurn) {
177176
- schedulerDecision = "execute";
177177
- }
177178
177548
  sessionLog(sessionId, `[boundary-exec] base=${schedulerDecisionEarly} bypass=${bypassReason} midTurn=${midTurn} effective=${midTurnAdjustedSchedulerDecision} sideEffect=${sideEffect}`);
177179
177549
  const forceMaterialization = usagePercentage >= FORCE_MATERIALIZATION_PERCENTAGE;
177180
177550
  const isEmergency = usagePercentage >= EMERGENCY_BLOCK_PERCENTAGE;
@@ -177192,6 +177562,14 @@ function registerPiContextHandler(pi, options) {
177192
177562
  sessionLog(sessionId, "EMERGENCY: historian wait completed (or timed out)");
177193
177563
  } catch {}
177194
177564
  }
177565
+ if (emergencyRecoveryArmed && !inFlightHistorian.has(sessionId) && !hasEligiblePiCompartmentHistory(options.db, sessionId)) {
177566
+ try {
177567
+ clearEmergencyRecovery(options.db, sessionId);
177568
+ sessionLog(sessionId, "EMERGENCY: disarming recovery — no eligible pre-tail history to compact (would otherwise loop at 95%)");
177569
+ } catch (err) {
177570
+ sessionLog(sessionId, `EMERGENCY: clearEmergencyRecovery failed: ${err instanceof Error ? err.message : String(err)}`);
177571
+ }
177572
+ }
177195
177573
  }
177196
177574
  const isCacheBusting = historyRefreshSessions.has(sessionId);
177197
177575
  sessionLog(sessionId, `transform: usage=${usagePercentage.toFixed(1)}% (${usageInputTokens} tokens, limit=${usageContextLimit ?? "?"}) decision=${schedulerDecision}${forceMaterialization ? " force=true" : ""}${isEmergency ? " EMERGENCY=true" : ""}${isCacheBusting ? " busting=true" : ""}`);
@@ -177209,6 +177587,7 @@ function registerPiContextHandler(pi, options) {
177209
177587
  heuristics: options.heuristics,
177210
177588
  injection: options.injection ? {
177211
177589
  ...options.injection,
177590
+ memoryEnabled: options.injection.memoryEnabled,
177212
177591
  historyBudgetTokens: resolveHistoryBudgetTokensForPi({
177213
177592
  historyBudgetPercentage: options.historian?.historyBudgetPercentage,
177214
177593
  usagePercentage,
@@ -177526,7 +177905,16 @@ function maybeFireHistorian(args) {
177526
177905
  let usageContextLimit;
177527
177906
  try {
177528
177907
  const piUsage = ctx.getContextUsage?.();
177529
- usageContextLimit = typeof piUsage?.contextWindow === "number" && piUsage.contextWindow > 0 ? piUsage.contextWindow : undefined;
177908
+ usageContextLimit = isSaneLimit(piUsage?.contextWindow) ? piUsage.contextWindow : undefined;
177909
+ if (usageContextLimit === undefined && isSaneLimit(ctx.model?.contextWindow)) {
177910
+ usageContextLimit = ctx.model.contextWindow;
177911
+ }
177912
+ try {
177913
+ const overflowState = getOverflowState(db, sessionId);
177914
+ if (overflowState.detectedContextLimit > 0) {
177915
+ usageContextLimit = Math.min(usageContextLimit ?? overflowState.detectedContextLimit, overflowState.detectedContextLimit);
177916
+ }
177917
+ } catch {}
177530
177918
  const sessionMetaForUsage = getOrCreateSessionMeta(db, sessionId);
177531
177919
  if (sessionMetaForUsage.lastContextPercentage > 0 && sessionMetaForUsage.lastInputTokens > 0) {
177532
177920
  usage = {
@@ -177539,8 +177927,9 @@ function maybeFireHistorian(args) {
177539
177927
  sessionLog(sessionId, `historian trigger eval: no usage info yet (tokens=${piUsage?.tokens ?? "<no piUsage>"}, percent=${piUsage?.percent ?? "<no piUsage>"}, contextWindow=${piUsage?.contextWindow ?? "<no piUsage>"})`);
177540
177928
  return;
177541
177929
  }
177930
+ const fallbackPercentage = isSaneLimit(usageContextLimit) && piUsage.tokens > 0 ? piUsage.tokens / usageContextLimit * 100 : piUsage.percent;
177542
177931
  usage = {
177543
- percentage: piUsage.percent,
177932
+ percentage: fallbackPercentage,
177544
177933
  inputTokens: piUsage.tokens
177545
177934
  };
177546
177935
  sessionLog(sessionId, `historian trigger eval: usage=${usage.percentage.toFixed(1)}% (${usage.inputTokens} tokens) [piUsage fallback], checking trigger...`);
@@ -177616,6 +178005,7 @@ async function runPipeline(args) {
177616
178005
  let executedWorkThisPass = false;
177617
178006
  let historyWasConsumedThisPass = false;
177618
178007
  let materializationSatisfiedThisPass = false;
178008
+ let pendingOpsAppliedThisPass = false;
177619
178009
  let suppressDeferredHistoryDrain = false;
177620
178010
  let casLost = false;
177621
178011
  const deferredHistoryWasPendingAtPassStart = deferredHistoryRefreshSessions.has(args.sessionId);
@@ -177639,7 +178029,9 @@ async function runPipeline(args) {
177639
178029
  return findLatestUserMessageIdPi(args.messages, ids)?.messageId ?? null;
177640
178030
  })();
177641
178031
  const alreadyRanHeuristicsThisTurn = currentTurnId !== null && lastHeuristicsTurnIdBySession.get(args.sessionId) === currentTurnId;
177642
- const shouldRunHeuristics = args.heuristics !== undefined && (args.forceMaterialization === true || hasPendingMaterialization(args.sessionId) || deferredMaterializationSessions.has(args.sessionId) || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
178032
+ const canConsumeDeferredLate = args.schedulerDecision === "execute" || args.forceMaterialization === true || args.contextUsage.percentage >= FORCE_MATERIALIZATION_PERCENTAGE;
178033
+ const deferredMaterializeEligible = canConsumeDeferredLate && deferredMaterializationSessions.has(args.sessionId);
178034
+ const shouldRunHeuristics = args.heuristics !== undefined && (args.forceMaterialization === true || hasPendingMaterialization(args.sessionId) || deferredMaterializeEligible || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
177643
178035
  const entryFingerprintByMessageId = buildEntryFingerprintMap(args.messages, stableIdResolver);
177644
178036
  adoptPiFallbackTags(args.db, args.sessionId, args.tagger, entryFingerprintByMessageId);
177645
178037
  const tTag = performance.now();
@@ -177665,15 +178057,13 @@ async function runPipeline(args) {
177665
178057
  const hasPendingMaterializeSignal = hasPendingMaterialization(args.sessionId);
177666
178058
  const deferredMaterializationWasPending = deferredMaterializationSessions.has(args.sessionId);
177667
178059
  const deferredHistoryRefreshWasPending = deferredHistoryWasPendingAtPassStart;
177668
- const deferredExecuteWasPending = peekDeferredExecutePending(args.db, args.sessionId) !== null;
177669
178060
  const pendingOps = getPendingOps(args.db, args.sessionId);
177670
- const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal || deferredExecuteWasPending;
177671
- const canConsumeDeferredLate = baseShouldApplyPendingOps || shouldRunHeuristics;
178061
+ const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal;
177672
178062
  const deferredMaterialize = canConsumeDeferredLate && deferredMaterializationWasPending;
177673
178063
  const deferredHistoryRefresh = canConsumeDeferredLate && deferredHistoryRefreshWasPending;
177674
178064
  const shouldApplyPendingOps = baseShouldApplyPendingOps || deferredMaterialize;
177675
178065
  if (shouldApplyPendingOps) {
177676
- const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredExecuteWasPending ? "deferred_boundary_execute" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
178066
+ const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
177677
178067
  sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
177678
178068
  try {
177679
178069
  const tApplyPending = performance.now();
@@ -177681,14 +178071,12 @@ async function runPipeline(args) {
177681
178071
  logTransformTiming(args.sessionId, "applyPendingOperations", tApplyPending);
177682
178072
  executedWorkThisPass = true;
177683
178073
  materializationSatisfiedThisPass = true;
178074
+ pendingOpsAppliedThisPass = true;
177684
178075
  if (hasPendingMaterializeSignal) {
177685
178076
  if (args.heuristics === undefined) {
177686
178077
  consumePendingMaterialization(args.sessionId);
177687
178078
  }
177688
178079
  }
177689
- if (deferredMaterialize) {
177690
- consumeDeferredMaterialization(args.sessionId);
177691
- }
177692
178080
  } catch (err) {
177693
178081
  sessionLog(args.sessionId, `pending operations failed: ${err instanceof Error ? err.message : String(err)}`);
177694
178082
  throw err;
@@ -177775,6 +178163,12 @@ async function runPipeline(args) {
177775
178163
  sessionLog(args.sessionId, `heuristic cleanup failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
177776
178164
  }
177777
178165
  }
178166
+ if (deferredMaterialize && pendingOpsAppliedThisPass) {
178167
+ const fullPassSucceeded = shouldRunHeuristics ? heuristicsExecuted : true;
178168
+ if (fullPassSucceeded) {
178169
+ consumeDeferredMaterialization(args.sessionId);
178170
+ }
178171
+ }
177778
178172
  if (args.reasoningClearing && shouldRunHeuristics) {
177779
178173
  try {
177780
178174
  const tClearReasoning = performance.now();
@@ -177827,18 +178221,29 @@ async function runPipeline(args) {
177827
178221
  if (args.injection) {
177828
178222
  try {
177829
178223
  const tInjection = performance.now();
177830
- if (args.isCacheBusting || deferredHistoryRefresh) {
177831
- clearM0M1PiCache(args.db, args.sessionId, args.isCacheBusting ? "history refresh" : "deferred history refresh");
177832
- }
178224
+ const hardMeta = getOrCreateSessionMeta(args.db, args.sessionId);
178225
+ let piTtlMs = 5 * 60 * 1000;
178226
+ try {
178227
+ piTtlMs = parseCacheTtl(hardMeta.cacheTtl);
178228
+ } catch {}
178229
+ const piHardSignals = {
178230
+ systemHash: typeof hardMeta.systemPromptHash === "string" ? hardMeta.systemPromptHash : "",
178231
+ toolSetHash: "",
178232
+ modelKey: liveModelBySession.get(args.sessionId) ?? "",
178233
+ cacheExpired: hardMeta.lastResponseTime > 0 && Date.now() - hardMeta.lastResponseTime >= piTtlMs,
178234
+ lastResponseTime: hardMeta.lastResponseTime
178235
+ };
177833
178236
  injectionResult = injectM0M1Pi({
177834
178237
  sessionId: args.sessionId,
177835
178238
  projectIdentity: args.projectIdentity,
177836
178239
  projectDirectory: args.projectDirectory,
178240
+ memoryEnabled: args.injection.memoryEnabled,
177837
178241
  injectionBudgetTokens: args.injection.injectionBudgetTokens,
177838
178242
  historyBudgetTokens: args.injection.historyBudgetTokens,
177839
178243
  keyFilesEnabled: args.injection.keyFilesEnabled,
177840
- keyFilesTokenBudget: args.injection.keyFilesTokenBudget
177841
- }, args.db, args.messages, args.entryIds, executedWorkThisPass);
178244
+ keyFilesTokenBudget: args.injection.keyFilesTokenBudget,
178245
+ hardSignals: piHardSignals
178246
+ }, args.db, args.messages, args.entryIds, args.isCacheBusting || deferredHistoryRefresh || executedWorkThisPass);
177842
178247
  if (args.isCacheBusting) {
177843
178248
  historyRefreshSessions.delete(args.sessionId);
177844
178249
  historyWasConsumedThisPass = true;
@@ -178191,12 +178596,8 @@ ${result}`;
178191
178596
  });
178192
178597
  }
178193
178598
 
178194
- // ../plugin/src/hooks/magic-context/compartment-runner.ts
178195
- init_logger();
178196
-
178197
178599
  // ../plugin/src/hooks/magic-context/historian-state-file.ts
178198
178600
  import { mkdirSync as mkdirSync6, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
178199
- init_data_path();
178200
178601
  function cleanupHistorianStateFile(path7) {
178201
178602
  if (!path7)
178202
178603
  return;
@@ -178204,13 +178605,7 @@ function cleanupHistorianStateFile(path7) {
178204
178605
  unlinkSync(path7);
178205
178606
  } catch {}
178206
178607
  }
178207
- // ../plugin/src/hooks/magic-context/compartment-runner-incremental.ts
178208
- init_logger();
178209
-
178210
178608
  // ../plugin/src/features/magic-context/compaction-marker.ts
178211
- init_data_path();
178212
- init_logger();
178213
- await init_sqlite();
178214
178609
  import { join as join15 } from "node:path";
178215
178610
  var BASE62_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
178216
178611
  function randomBase62(length) {
@@ -178365,23 +178760,20 @@ function removeCompactionMarker(state) {
178365
178760
  }
178366
178761
 
178367
178762
  // ../plugin/src/hooks/magic-context/compaction-marker-manager.ts
178368
- init_data_path();
178369
- init_logger();
178370
- await init_sqlite();
178371
178763
  var MARKER_SUMMARY_TEXT = "[Compacted by magic-context — session history is managed by the plugin]";
178372
178764
  function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, directory) {
178373
178765
  const existing = getPersistedCompactionMarkerState(db, sessionId);
178374
178766
  if (existing) {
178375
178767
  if (existing.boundaryOrdinal === lastCompartmentEnd) {
178376
- return;
178768
+ return true;
178377
178769
  }
178378
- try {
178379
- removeCompactionMarker(existing);
178380
- setPersistedCompactionMarkerState(db, sessionId, null);
178381
- sessionLog(sessionId, `compaction-marker: removed old boundary at ordinal ${existing.boundaryOrdinal}, moving to ${lastCompartmentEnd}`);
178382
- } catch (error51) {
178383
- sessionLog(sessionId, `compaction-marker: failed to remove old boundary at ordinal ${existing.boundaryOrdinal}, proceeding with new injection:`, error51);
178770
+ const removed = removeCompactionMarker(existing);
178771
+ if (!removed) {
178772
+ sessionLog(sessionId, `compaction-marker: failed to remove old boundary at ordinal ${existing.boundaryOrdinal}; preserving persisted state for retry (not injecting new marker this pass)`);
178773
+ return false;
178384
178774
  }
178775
+ setPersistedCompactionMarkerState(db, sessionId, null);
178776
+ sessionLog(sessionId, `compaction-marker: removed old boundary at ordinal ${existing.boundaryOrdinal}, moving to ${lastCompartmentEnd}`);
178385
178777
  }
178386
178778
  const result = injectCompactionMarker({
178387
178779
  sessionId,
@@ -178395,13 +178787,14 @@ function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEn
178395
178787
  boundaryOrdinal: lastCompartmentEnd
178396
178788
  });
178397
178789
  sessionLog(sessionId, `compaction-marker: injected at ordinal ${lastCompartmentEnd}, boundary user msg ${result.boundaryMessageId}`);
178790
+ return true;
178398
178791
  }
178792
+ return false;
178399
178793
  }
178400
178794
 
178401
178795
  // ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
178402
178796
  import { mkdirSync as mkdirSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync4 } from "node:fs";
178403
178797
  import { join as join16 } from "node:path";
178404
- init_data_path();
178405
178798
  function historianResponseDumpDir(directory) {
178406
178799
  return getProjectMagicContextHistorianDir(directory);
178407
178800
  }
@@ -178601,12 +178994,12 @@ async function runHistorianPrompt(args) {
178601
178994
  error: `Historian failed while processing this session: ${desc.brief}`
178602
178995
  };
178603
178996
  } finally {
178604
- if (agentSessionId && outcomeOk) {
178997
+ if (agentSessionId && outcomeOk && !shouldKeepSubagents()) {
178605
178998
  await client.session.delete({ path: { id: agentSessionId } }).catch((e) => {
178606
178999
  sessionLog(parentSessionId, "compartment agent: session cleanup failed", getErrorMessage(e));
178607
179000
  });
178608
- } else if (agentSessionId && !outcomeOk) {
178609
- sessionLog(parentSessionId, `historian: KEEPING failed child session ${agentSessionId} for debugging (not deleted)`);
179001
+ } else if (agentSessionId && (!outcomeOk || shouldKeepSubagents())) {
179002
+ sessionLog(parentSessionId, `historian: KEEPING child session ${agentSessionId} (${outcomeOk ? "keep_subagents" : "failed"}) — not deleted`);
178610
179003
  }
178611
179004
  }
178612
179005
  }
@@ -178685,8 +179078,8 @@ function isTransientHistorianPromptError(message) {
178685
179078
  ].some((token) => normalized.includes(token));
178686
179079
  }
178687
179080
  function sleep(ms) {
178688
- return new Promise((resolve4) => {
178689
- setTimeout(resolve4, ms);
179081
+ return new Promise((resolve5) => {
179082
+ setTimeout(resolve5, ms);
178690
179083
  });
178691
179084
  }
178692
179085
  function cleanupHistorianDump(sessionId, dumpPath) {
@@ -178727,7 +179120,6 @@ function sanitizeDumpName(value) {
178727
179120
  }
178728
179121
 
178729
179122
  // ../plugin/src/hooks/magic-context/send-session-notification.ts
178730
- init_logger();
178731
179123
  function hasNotificationSessionClient(client) {
178732
179124
  if (client === null || typeof client !== "object")
178733
179125
  return false;
@@ -178826,11 +179218,7 @@ async function sendIgnoredMessage(client, sessionId, text, params, forcePersist
178826
179218
  var HISTORIAN_ALERT_COOLDOWN_MS2 = 60 * 1000;
178827
179219
  var lastHistorianAlertBySession2 = new Map;
178828
179220
 
178829
- // ../plugin/src/hooks/magic-context/compartment-runner-partial-recomp.ts
178830
- init_logger();
178831
-
178832
179221
  // ../plugin/src/hooks/magic-context/compartment-runner-recomp.ts
178833
- init_logger();
178834
179222
  function insertRecompCompartmentRows(db, sessionId, compartments, now) {
178835
179223
  const stmt = db.prepare("INSERT INTO compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, p1, p2, p3, p4, importance, episode_type, legacy, created_at, harness) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
178836
179224
  for (const c of compartments) {
@@ -178953,7 +179341,6 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
178953
179341
  if (deps.preserveInjectionCacheUntilConsumed !== true) {
178954
179342
  clearInjectionCache(sessionId);
178955
179343
  }
178956
- deps.onCompartmentStatePublished?.(sessionId);
178957
179344
  promoted2.facts;
178958
179345
  if (deps.memoryEnabled !== false) {
178959
179346
  const projectIdentity = resolveProjectIdentity(sessionDirectory);
@@ -178966,11 +179353,14 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
178966
179353
  if (lastCompartmentEnd2 > 0) {
178967
179354
  queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd2);
178968
179355
  }
179356
+ deps.onCompartmentStatePublished?.(sessionId);
178969
179357
  if (lastCompartmentEnd2 > 0) {
178970
- updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd2, deps.directory);
178971
- const stalePending = getPendingCompactionMarkerState(db, sessionId);
178972
- if (stalePending) {
178973
- clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
179358
+ const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd2, deps.directory);
179359
+ if (markerUpdated) {
179360
+ const stalePending = getPendingCompactionMarkerState(db, sessionId);
179361
+ if (stalePending) {
179362
+ clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
179363
+ }
178974
179364
  }
178975
179365
  }
178976
179366
  return [
@@ -179159,13 +179549,13 @@ Another process acquired the compartment-state lease before recomp could publish
179159
179549
  if (deps.preserveInjectionCacheUntilConsumed !== true) {
179160
179550
  clearInjectionCache(sessionId);
179161
179551
  }
179162
- deps.onCompartmentStatePublished?.(sessionId);
179163
179552
  const finalCompartments = promoted?.compartments ?? candidateCompartments;
179164
179553
  const finalFacts = promoted?.facts ?? candidateFacts;
179165
179554
  const lastCompartmentEnd = finalCompartments[finalCompartments.length - 1]?.endMessage ?? 0;
179166
179555
  if (lastCompartmentEnd > 0) {
179167
179556
  queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
179168
179557
  }
179558
+ deps.onCompartmentStatePublished?.(sessionId);
179169
179559
  if (deps.memoryEnabled !== false) {
179170
179560
  const projectIdentity = resolveProjectIdentity(sessionDirectory);
179171
179561
  await deps.ensureProjectRegistered?.(sessionDirectory, db);
@@ -179174,10 +179564,12 @@ Another process acquired the compartment-state lease before recomp could publish
179174
179564
  embedAndStoreCompartments(db, sessionId, projectIdentity, toEmbed);
179175
179565
  }
179176
179566
  if (lastCompartmentEnd > 0) {
179177
- updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
179178
- const stalePending = getPendingCompactionMarkerState(db, sessionId);
179179
- if (stalePending) {
179180
- clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
179567
+ const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
179568
+ if (markerUpdated) {
179569
+ const stalePending = getPendingCompactionMarkerState(db, sessionId);
179570
+ if (stalePending) {
179571
+ clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
179572
+ }
179181
179573
  }
179182
179574
  }
179183
179575
  return [
@@ -179311,7 +179703,7 @@ Could not acquire the compartment-state lease for this session.`;
179311
179703
  log(`[magic-context] partial recomp merged validation failed: ${mergedError}`);
179312
179704
  return null;
179313
179705
  }
179314
- saveRecompStagingPass(db, sessionId, passCount + 1, merged, currentFacts);
179706
+ saveRecompStagingPass(db, sessionId, passCount + 1, merged, stagedFacts);
179315
179707
  const promoted = promoteRecompStagingWithM0Mutation(db, sessionId, leaseHolderId);
179316
179708
  if (!promoted) {
179317
179709
  log("[magic-context] partial recomp promote returned null");
@@ -179331,10 +179723,12 @@ Could not acquire the compartment-state lease for this session.`;
179331
179723
  }
179332
179724
  const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
179333
179725
  if (lastEnd > 0) {
179334
- updateCompactionMarkerAfterPublication(db, sessionId, lastEnd, deps.directory);
179335
- const stalePending = getPendingCompactionMarkerState(db, sessionId);
179336
- if (stalePending) {
179337
- clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
179726
+ const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastEnd, deps.directory);
179727
+ if (markerUpdated) {
179728
+ const stalePending = getPendingCompactionMarkerState(db, sessionId);
179729
+ if (stalePending) {
179730
+ clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
179731
+ }
179338
179732
  }
179339
179733
  }
179340
179734
  return { compartmentCount: merged.length, lastEndMessage: lastEnd };
@@ -179376,10 +179770,7 @@ Snapped range ${snapStart}-${snapEnd} would cross into the protected tail (start
179376
179770
  ].join(`
179377
179771
  `);
179378
179772
  }
179379
- const currentFacts = getSessionFacts(db, sessionId).map((f) => ({
179380
- category: f.category,
179381
- content: f.content
179382
- }));
179773
+ const stagedFacts = [];
179383
179774
  const parentSessionResponse = await client.session.get({ path: { id: sessionId } }).catch(() => null);
179384
179775
  const parentSession = normalizeSDKResponse(parentSessionResponse, null, { preferResponseOnMissingData: true });
179385
179776
  const sessionDirectory = parentSession?.directory ?? directory;
@@ -179396,7 +179787,7 @@ Snapped range ${snapStart}-${snapEnd} would cross into the protected tail (start
179396
179787
  candidateCompartments = priorCompartments.map((c, idx) => compartmentToInput(c, idx));
179397
179788
  passCount = 0;
179398
179789
  offset = snapStart;
179399
- saveRecompStagingPass(db, sessionId, 0, candidateCompartments, currentFacts);
179790
+ saveRecompStagingPass(db, sessionId, 0, candidateCompartments, stagedFacts);
179400
179791
  setRecompPartialRange(db, sessionId, { start: snapStart, end: snapEnd });
179401
179792
  }
179402
179793
  let currentTokenBudget = historianChunkTokens;
@@ -179489,7 +179880,7 @@ Original state preserved (staging kept for retry).`;
179489
179880
  passCount += 1;
179490
179881
  currentTokenBudget = historianChunkTokens;
179491
179882
  passAttempt = 1;
179492
- saveRecompStagingPass(db, sessionId, passCount, candidateCompartments, currentFacts);
179883
+ saveRecompStagingPass(db, sessionId, passCount, candidateCompartments, stagedFacts);
179493
179884
  const nextOffset = (validatedPass.compartments?.[validatedPass.compartments.length - 1]?.endMessage ?? chunk.endIndex) + 1;
179494
179885
  if (nextOffset <= offset) {
179495
179886
  return `## Magic Recomp — Failed
@@ -179510,7 +179901,6 @@ Partial recomp completed historian passes but the final compartment set failed v
179510
179901
  ...resumed ? ["Resumed from previous interrupted partial run."] : [],
179511
179902
  `Rebuilt compartments covering messages ${snapStart}-${snapEnd} using ${passCount} historian pass${passCount === 1 ? "" : "es"}.`,
179512
179903
  `Preserved ${priorCompartments.length} prior compartment(s) and ${tailCompartments.length} tail compartment(s) unchanged.`,
179513
- `Facts unchanged (${currentFacts.length} entr${currentFacts.length === 1 ? "y" : "ies"}).`,
179514
179904
  `Total compartments: ${finalResult.compartmentCount}.`
179515
179905
  ].join(`
179516
179906
  `);
@@ -179599,9 +179989,6 @@ async function executeContextRecompWithResult(deps, options = {}) {
179599
179989
  }
179600
179990
  }
179601
179991
 
179602
- // src/commands/ctx-recomp.ts
179603
- init_logger();
179604
-
179605
179992
  // src/pi-recomp-client-shared.ts
179606
179993
  function createPiHistorianClient(args) {
179607
179994
  const sessions = new Map;
@@ -179733,9 +180120,6 @@ function resolvePiReadBranchEntries2(ctx) {
179733
180120
  };
179734
180121
  }
179735
180122
 
179736
- // src/pi-recomp-runner.ts
179737
- init_logger();
179738
-
179739
180123
  // src/status-line.ts
179740
180124
  var STATUS_KEY = "magic-context";
179741
180125
  var RECENT_FAILURE_MS = 60000;
@@ -180064,7 +180448,6 @@ function inferLevel(text) {
180064
180448
  }
180065
180449
 
180066
180450
  // ../plugin/src/features/magic-context/memory/memory-migration.ts
180067
- init_logger();
180068
180451
  function memoryMigrationGuardKey(projectPath) {
180069
180452
  return `memory_migration_5cat:${projectPath}`;
180070
180453
  }
@@ -180174,11 +180557,7 @@ function contextualizeUpgradeReason(reason) {
180174
180557
  return rewritten;
180175
180558
  }
180176
180559
 
180177
- // src/commands/ctx-session-upgrade.ts
180178
- init_logger();
180179
-
180180
180560
  // src/pi-memory-migration.ts
180181
- init_logger();
180182
180561
  var MIGRATION_SYSTEM_PROMPT2 = "You re-organize a software project's long-term memory into a stricter taxonomy. " + "Follow the user instructions exactly. Output ONLY the requested XML blocks, nothing else.";
180183
180562
  async function runPiMemoryMigration(deps) {
180184
180563
  const projectPath = resolveProjectIdentity(deps.directory);
@@ -180453,7 +180832,6 @@ ${migrationSummary}` : "",
180453
180832
  }
180454
180833
 
180455
180834
  // ../plugin/src/hooks/magic-context/execute-status.ts
180456
- init_logger();
180457
180835
  function formatExecuteThreshold(thresholdPercentage, mode, contextLimit) {
180458
180836
  if (mode === "tokens" && contextLimit > 0) {
180459
180837
  const tokens = Math.floor(thresholdPercentage / 100 * contextLimit);
@@ -180620,7 +180998,7 @@ function formatThresholdPercent(value) {
180620
180998
  // package.json
180621
180999
  var package_default = {
180622
181000
  name: "@cortexkit/pi-magic-context",
180623
- version: "0.22.3",
181001
+ version: "0.22.5",
180624
181002
  type: "module",
180625
181003
  description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
180626
181004
  main: "dist/index.js",
@@ -185358,7 +185736,6 @@ function createCtxExpandTool(deps) {
185358
185736
  }
185359
185737
 
185360
185738
  // src/tools/ctx-memory.ts
185361
- init_logger();
185362
185739
  var DEFAULT_LIST_LIMIT = 10;
185363
185740
  var VALID_CATEGORIES = new Set(CATEGORY_PRIORITY);
185364
185741
  function isMemoryCategory2(value) {
@@ -185503,7 +185880,6 @@ function createCtxMemoryTool(deps) {
185503
185880
  sourceType: dreamerAllowed ? "dreamer" : "agent"
185504
185881
  });
185505
185882
  queueEmbedding({ deps, projectIdentity, memoryId: memory2.id, content });
185506
- invalidateAllMemoryBlockCaches(deps.db);
185507
185883
  return ok2(`Saved memory [ID: ${memory2.id}] in ${rawCategory}.`);
185508
185884
  }
185509
185885
  if (params.action === "delete") {
@@ -185511,7 +185887,7 @@ function createCtxMemoryTool(deps) {
185511
185887
  return err2("Error: 'id' is required when action is 'delete'.");
185512
185888
  }
185513
185889
  const memory2 = getMemoryById(deps.db, params.id);
185514
- if (!memory2 || memory2.projectPath !== projectIdentity) {
185890
+ if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
185515
185891
  return err2(`Error: Memory with ID ${params.id} was not found.`);
185516
185892
  }
185517
185893
  deps.db.transaction(() => {
@@ -185540,7 +185916,7 @@ function createCtxMemoryTool(deps) {
185540
185916
  return err2("Error: 'content' is required when action is 'update'.");
185541
185917
  }
185542
185918
  const memory2 = getMemoryById(deps.db, params.id);
185543
- if (!memory2 || memory2.projectPath !== projectIdentity) {
185919
+ if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
185544
185920
  return err2(`Error: Memory with ID ${params.id} was not found.`);
185545
185921
  }
185546
185922
  const normalizedHash = computeNormalizedHash(content);
@@ -185574,9 +185950,6 @@ function createCtxMemoryTool(deps) {
185574
185950
  if (sourceMemories.length !== ids.length) {
185575
185951
  return err2("Error: One or more source memories were not found.");
185576
185952
  }
185577
- if (sourceMemories.some((memory2) => memory2.projectPath !== projectIdentity)) {
185578
- return err2("Error: All memories to merge must belong to the current project.");
185579
- }
185580
185953
  const requestedCategory = params.category?.trim();
185581
185954
  if (requestedCategory && !isMemoryCategory2(requestedCategory)) {
185582
185955
  return err2(`Error: Unknown memory category '${requestedCategory}'. Valid: ${CATEGORY_PRIORITY.join(", ")}`);
@@ -185635,7 +186008,7 @@ function createCtxMemoryTool(deps) {
185635
186008
  }
185636
186009
  supersededMemory(deps.db, memory2.id, canonicalMemory.id);
185637
186010
  queueMemoryMutation(deps.db, {
185638
- projectPath: memory2.projectPath,
186011
+ projectPath: normalizeStoredProjectPath(memory2.projectPath),
185639
186012
  mutationType: "superseded",
185640
186013
  targetMemoryId: memory2.id,
185641
186014
  supersededById: canonicalMemory.id
@@ -185643,7 +186016,7 @@ function createCtxMemoryTool(deps) {
185643
186016
  }
185644
186017
  if (canonicalExisting && canonicalContentChanged) {
185645
186018
  queueMemoryMutation(deps.db, {
185646
- projectPath: canonicalMemory.projectPath,
186019
+ projectPath: normalizeStoredProjectPath(canonicalMemory.projectPath),
185647
186020
  mutationType: "update",
185648
186021
  targetMemoryId: canonicalMemory.id,
185649
186022
  category,
@@ -185665,7 +186038,7 @@ function createCtxMemoryTool(deps) {
185665
186038
  return err2("Error: 'id' is required when action is 'archive'.");
185666
186039
  }
185667
186040
  const memory2 = getMemoryById(deps.db, params.id);
185668
- if (!memory2 || memory2.projectPath !== projectIdentity) {
186041
+ if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
185669
186042
  return err2(`Error: Memory with ID ${params.id} was not found.`);
185670
186043
  }
185671
186044
  deps.db.transaction(() => {
@@ -185927,7 +186300,7 @@ ${smartNotes.map(formatNoteLine).join(`
185927
186300
  // ../plugin/src/features/magic-context/range-parser.ts
185928
186301
  function parseRangeString(input) {
185929
186302
  const maxRangeElements = 1000;
185930
- const trimmed = input.trim();
186303
+ const trimmed = input.replace(/§/g, "").trim();
185931
186304
  if (trimmed === "") {
185932
186305
  throw new Error("Range string must not be empty");
185933
186306
  }
@@ -186188,6 +186561,7 @@ function createCtxSearchTool(deps) {
186188
186561
  const embeddingEnabled = snapshot ? snapshot.enabled || snapshot.gitCommitEnabled : deps.embeddingEnabled;
186189
186562
  const gitCommitsEnabled = snapshot?.gitCommitEnabled ?? deps.gitCommitsEnabled ?? false;
186190
186563
  const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, sessionId);
186564
+ const messageOrdinalCutoff = lastCompartmentEnd >= 0 ? lastCompartmentEnd : 0;
186191
186565
  const visibleMemoryIds = getVisibleMemoryIds(deps.db, sessionId);
186192
186566
  const results = await unifiedSearch(deps.db, sessionId, projectIdentity, query, {
186193
186567
  limit: normalizeLimit3(params.limit),
@@ -186198,7 +186572,7 @@ function createCtxSearchTool(deps) {
186198
186572
  return result?.vector ?? null;
186199
186573
  },
186200
186574
  isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
186201
- maxMessageOrdinal: lastCompartmentEnd >= 0 ? lastCompartmentEnd : undefined,
186575
+ maxMessageOrdinal: messageOrdinalCutoff,
186202
186576
  gitCommitsEnabled,
186203
186577
  sources: params.sources,
186204
186578
  visibleMemoryIds,
@@ -186526,6 +186900,7 @@ async function src_default2(pi) {
186526
186900
  mmapSizeMb: config2.sqlite.mmap_size_mb
186527
186901
  });
186528
186902
  applySqliteTuningPragmas(db);
186903
+ setKeepSubagents(config2.keep_subagents === true);
186529
186904
  if (!config2.enabled) {
186530
186905
  info("plugin DISABLED via config (enabled: false) — skipping registration");
186531
186906
  return;
@@ -186566,6 +186941,7 @@ async function src_default2(pi) {
186566
186941
  clearReasoningAge: config2.clear_reasoning_age
186567
186942
  },
186568
186943
  injection: {
186944
+ memoryEnabled: config2.memory.enabled,
186569
186945
  injectionBudgetTokens: config2.memory.injection_budget_tokens,
186570
186946
  temporalAwareness: config2.temporal_awareness === true,
186571
186947
  keyFilesEnabled: config2.dreamer?.pin_key_files?.enabled ?? false,
@@ -186677,6 +187053,33 @@ async function src_default2(pi) {
186677
187053
  try {
186678
187054
  const currentProject = resolveCurrentProject(ctx);
186679
187055
  seenDreamerProjectIdentities.add(currentProject.projectIdentity);
187056
+ const switchedProject = currentProject.projectDir !== projectDir;
187057
+ const effectiveConfig = switchedProject ? loadPiConfig({ cwd: currentProject.projectDir }).config : config2;
187058
+ const effectiveDreamerConfig = switchedProject ? resolveDreamerFromConfig(effectiveConfig) : dreamerConfig;
187059
+ if (effectiveDreamerConfig) {
187060
+ try {
187061
+ registerPiDreamerProject({
187062
+ db,
187063
+ projectDir: currentProject.projectDir,
187064
+ projectIdentity: currentProject.projectIdentity,
187065
+ config: effectiveDreamerConfig,
187066
+ embeddingConfig: effectiveConfig.embedding,
187067
+ memoryEnabled: effectiveConfig.memory.enabled,
187068
+ gitCommitIndexing: effectiveConfig.memory.git_commit_indexing,
187069
+ onAdjunctsRefreshNeeded: signalPiSystemPromptRefreshForProject
187070
+ });
187071
+ } catch (err5) {
187072
+ warn("before_agent_start: registerPiDreamerProject threw:", err5);
187073
+ }
187074
+ } else if (switchedProject) {
187075
+ try {
187076
+ unregisterPiDreamerProject({
187077
+ projectIdentity: currentProject.projectIdentity
187078
+ });
187079
+ } catch (err5) {
187080
+ warn("before_agent_start: unregisterPiDreamerProject threw:", err5);
187081
+ }
187082
+ }
186680
187083
  const sm = ctx.sessionManager;
186681
187084
  let sessionId;
186682
187085
  if (sm !== undefined) {