@cortexkit/pi-magic-context 0.22.5 → 0.23.1

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.
@@ -46,6 +46,111 @@ 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 path from "node:path";
65
+ function getDataDir() {
66
+ return process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share");
67
+ }
68
+ function getMagicContextTempDir(harness = getHarness()) {
69
+ return path.join(os.tmpdir(), harness, "magic-context");
70
+ }
71
+ function getMagicContextLogPath(harness = getHarness()) {
72
+ return path.join(getMagicContextTempDir(harness), "magic-context.log");
73
+ }
74
+ function getProjectMagicContextDir(directory) {
75
+ return path.join(directory, ".opencode", "magic-context");
76
+ }
77
+ function getProjectMagicContextHistorianDir(directory) {
78
+ return path.join(getProjectMagicContextDir(directory), "historian");
79
+ }
80
+ function getOpenCodeStorageDir() {
81
+ return path.join(getDataDir(), "opencode", "storage");
82
+ }
83
+ function getMagicContextStorageDir() {
84
+ return path.join(getDataDir(), "cortexkit", "magic-context");
85
+ }
86
+ function getLegacyOpenCodeMagicContextStorageDir() {
87
+ return path.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 path2 from "node:path";
94
+ function ensureDir(filePath) {
95
+ const dir = path2.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
+
49
154
  // ../../node_modules/.bun/esprima@4.0.1/node_modules/esprima/dist/esprima.js
50
155
  var require_esprima = __commonJS((exports, module) => {
51
156
  (function webpackUniversalModuleDefinition(root, factory) {
@@ -7804,53 +7909,10 @@ var require_src2 = __commonJS((exports, module) => {
7804
7909
  });
7805
7910
 
7806
7911
  // ../plugin/src/features/magic-context/storage-db.ts
7912
+ init_data_path();
7807
7913
  import { copyFileSync, cpSync, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "node:fs";
7808
7914
  import { dirname as dirname2, join as join4 } from "node:path";
7809
7915
 
7810
- // ../plugin/src/shared/data-path.ts
7811
- import * as os from "node:os";
7812
- import * as path from "node:path";
7813
-
7814
- // ../plugin/src/shared/harness.ts
7815
- var currentHarness = "opencode";
7816
- var harnessLocked = false;
7817
- function setHarness(value) {
7818
- if (harnessLocked && currentHarness !== value) {
7819
- throw new Error(`Magic Context: harness already locked to "${currentHarness}"; cannot change to "${value}"`);
7820
- }
7821
- currentHarness = value;
7822
- harnessLocked = true;
7823
- }
7824
- function getHarness() {
7825
- return currentHarness;
7826
- }
7827
-
7828
- // ../plugin/src/shared/data-path.ts
7829
- function getDataDir() {
7830
- return process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share");
7831
- }
7832
- function getMagicContextTempDir(harness = getHarness()) {
7833
- return path.join(os.tmpdir(), harness, "magic-context");
7834
- }
7835
- function getMagicContextLogPath(harness = getHarness()) {
7836
- return path.join(getMagicContextTempDir(harness), "magic-context.log");
7837
- }
7838
- function getProjectMagicContextDir(directory) {
7839
- return path.join(directory, ".opencode", "magic-context");
7840
- }
7841
- function getProjectMagicContextHistorianDir(directory) {
7842
- return path.join(getProjectMagicContextDir(directory), "historian");
7843
- }
7844
- function getOpenCodeStorageDir() {
7845
- return path.join(getDataDir(), "opencode", "storage");
7846
- }
7847
- function getMagicContextStorageDir() {
7848
- return path.join(getDataDir(), "cortexkit", "magic-context");
7849
- }
7850
- function getLegacyOpenCodeMagicContextStorageDir() {
7851
- return path.join(getOpenCodeStorageDir(), "plugin", "magic-context");
7852
- }
7853
-
7854
7916
  // ../plugin/src/shared/error-message.ts
7855
7917
  function getErrorMessage(error) {
7856
7918
  return error instanceof Error ? error.message : String(error);
@@ -7927,69 +7989,8 @@ function safeString(value) {
7927
7989
  }
7928
7990
  }
7929
7991
 
7930
- // ../plugin/src/shared/logger.ts
7931
- import * as fs from "node:fs";
7932
- import * as path2 from "node:path";
7933
- var isTestEnv = false;
7934
- var buffer = [];
7935
- var flushTimer = null;
7936
- var FLUSH_INTERVAL_MS = 500;
7937
- var BUFFER_SIZE_LIMIT = 50;
7938
- var lastEnsuredDir = null;
7939
- function ensureDir(filePath) {
7940
- const dir = path2.dirname(filePath);
7941
- if (dir === lastEnsuredDir)
7942
- return;
7943
- try {
7944
- fs.mkdirSync(dir, { recursive: true });
7945
- lastEnsuredDir = dir;
7946
- } catch {}
7947
- }
7948
- function flush() {
7949
- if (flushTimer) {
7950
- clearTimeout(flushTimer);
7951
- flushTimer = null;
7952
- }
7953
- if (buffer.length === 0)
7954
- return;
7955
- const data = buffer.join("");
7956
- buffer = [];
7957
- try {
7958
- const logFile = getMagicContextLogPath();
7959
- ensureDir(logFile);
7960
- fs.appendFileSync(logFile, data);
7961
- } catch {}
7962
- }
7963
- function scheduleFlush() {
7964
- if (flushTimer)
7965
- return;
7966
- flushTimer = setTimeout(() => {
7967
- flushTimer = null;
7968
- flush();
7969
- }, FLUSH_INTERVAL_MS);
7970
- }
7971
- function log(message, data) {
7972
- if (isTestEnv)
7973
- return;
7974
- try {
7975
- const timestamp = new Date().toISOString();
7976
- const serialized = data === undefined ? "" : data instanceof Error ? ` ${data.message}${data.stack ? `
7977
- ${data.stack}` : ""}` : ` ${JSON.stringify(data)}`;
7978
- buffer.push(`[${timestamp}] ${message}${serialized}
7979
- `);
7980
- if (buffer.length >= BUFFER_SIZE_LIMIT) {
7981
- flush();
7982
- } else {
7983
- scheduleFlush();
7984
- }
7985
- } catch {}
7986
- }
7987
- function sessionLog(sessionId, message, data) {
7988
- log(`[magic-context][${sessionId}] ${message}`, data);
7989
- }
7990
- if (!isTestEnv) {
7991
- process.on("exit", flush);
7992
- }
7992
+ // ../plugin/src/features/magic-context/storage-db.ts
7993
+ init_logger();
7993
7994
 
7994
7995
  // ../plugin/src/shared/sqlite.ts
7995
7996
  var isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
@@ -8045,6 +8046,7 @@ function closeQuietly(db) {
8045
8046
  }
8046
8047
 
8047
8048
  // ../plugin/src/features/magic-context/key-files/project-key-files.ts
8049
+ init_logger();
8048
8050
  import { createHash } from "node:crypto";
8049
8051
  import { existsSync, readFileSync, realpathSync } from "node:fs";
8050
8052
  import { join as join2, resolve, sep } from "node:path";
@@ -8161,6 +8163,7 @@ function isRelativeProjectFile(projectPath, relativePath) {
8161
8163
  }
8162
8164
 
8163
8165
  // ../plugin/src/features/magic-context/migrations.ts
8166
+ init_logger();
8164
8167
  function tableExists(db, name) {
8165
8168
  return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name));
8166
8169
  }
@@ -8916,6 +8919,50 @@ var MIGRATIONS = [
8916
8919
  cached_m0_model_key = NULL`).run();
8917
8920
  }
8918
8921
  }
8922
+ },
8923
+ {
8924
+ version: 31,
8925
+ description: "Nudge redesign: Channel 1 cadence (last_nudge_undropped) + Channel 2 ceiling lease " + "(channel2_nudge_state); zero legacy ctx_reduce-nudge sticky/anchor state (startup heal)",
8926
+ up: (db) => {
8927
+ const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
8928
+ if (!hasSessionMeta)
8929
+ return;
8930
+ ensureColumn(db, "session_meta", "last_nudge_undropped", "INTEGER DEFAULT 0");
8931
+ ensureColumn(db, "session_meta", "channel2_nudge_state", "TEXT DEFAULT ''");
8932
+ const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
8933
+ if (columns.has("sticky_turn_reminder_text")) {
8934
+ db.prepare(`UPDATE session_meta SET
8935
+ sticky_turn_reminder_text = '',
8936
+ sticky_turn_reminder_message_id = '',
8937
+ nudge_anchor_message_id = '',
8938
+ nudge_anchor_text = ''`).run();
8939
+ }
8940
+ }
8941
+ },
8942
+ {
8943
+ version: 32,
8944
+ description: "Protected tail boundary state, usage resolver fields, recovery escape, and drain quota",
8945
+ up: (db) => {
8946
+ const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
8947
+ if (!hasSessionMeta)
8948
+ return;
8949
+ ensureColumn(db, "session_meta", "prior_boundary_ordinal", "INTEGER NOT NULL DEFAULT 1");
8950
+ ensureColumn(db, "session_meta", "protected_tail_policy_version", "INTEGER NOT NULL DEFAULT 0");
8951
+ ensureColumn(db, "session_meta", "protected_tail_drain_window_started_at", "INTEGER NOT NULL DEFAULT 0");
8952
+ ensureColumn(db, "session_meta", "protected_tail_drain_tokens", "INTEGER NOT NULL DEFAULT 0");
8953
+ ensureColumn(db, "session_meta", "recovery_no_eligible_head_count", "INTEGER NOT NULL DEFAULT 0");
8954
+ ensureColumn(db, "session_meta", "force_emergency_bypass_window_start", "INTEGER NOT NULL DEFAULT 0");
8955
+ ensureColumn(db, "session_meta", "force_emergency_bypass_used", "INTEGER NOT NULL DEFAULT 0");
8956
+ ensureColumn(db, "session_meta", "last_usage_context_limit", "INTEGER NOT NULL DEFAULT 0");
8957
+ db.prepare("UPDATE session_meta SET prior_boundary_ordinal = 1 WHERE prior_boundary_ordinal IS NULL OR prior_boundary_ordinal < 1").run();
8958
+ db.prepare("UPDATE session_meta SET protected_tail_policy_version = 0 WHERE protected_tail_policy_version IS NULL").run();
8959
+ db.prepare("UPDATE session_meta SET protected_tail_drain_window_started_at = 0 WHERE protected_tail_drain_window_started_at IS NULL").run();
8960
+ db.prepare("UPDATE session_meta SET protected_tail_drain_tokens = 0 WHERE protected_tail_drain_tokens IS NULL").run();
8961
+ db.prepare("UPDATE session_meta SET recovery_no_eligible_head_count = 0 WHERE recovery_no_eligible_head_count IS NULL").run();
8962
+ db.prepare("UPDATE session_meta SET force_emergency_bypass_window_start = 0 WHERE force_emergency_bypass_window_start IS NULL").run();
8963
+ db.prepare("UPDATE session_meta SET force_emergency_bypass_used = 0 WHERE force_emergency_bypass_used IS NULL").run();
8964
+ db.prepare("UPDATE session_meta SET last_usage_context_limit = 0 WHERE last_usage_context_limit IS NULL").run();
8965
+ }
8919
8966
  }
8920
8967
  ];
8921
8968
  var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -141521,7 +141568,7 @@ var tokenizer = new src_default(exports_claude);
141521
141568
  function estimateTokens(text) {
141522
141569
  if (!text)
141523
141570
  return 0;
141524
- return tokenizer.count(text);
141571
+ return tokenizer.encode(text, "all").length;
141525
141572
  }
141526
141573
  function normalizeText(text) {
141527
141574
  return text.replace(/\s+/g, " ").trim();
@@ -141631,6 +141678,8 @@ function loadToolDefinitionMeasurements(db) {
141631
141678
  }
141632
141679
 
141633
141680
  // ../plugin/src/features/magic-context/tool-owner-backfill.ts
141681
+ init_data_path();
141682
+ init_logger();
141634
141683
  import { existsSync as existsSync2 } from "node:fs";
141635
141684
  import { join as join3 } from "node:path";
141636
141685
  var LEASE_DURATION_MS = 5 * 60 * 1000;
@@ -141746,6 +141795,11 @@ function markSessionCompleted(db, sessionId, now) {
141746
141795
  SET status = 'completed', completed_at = ?, lease_expires_at = NULL, last_error = NULL
141747
141796
  WHERE session_id = ?`).run(now, sessionId);
141748
141797
  }
141798
+ function markSessionPendingRetry(db, sessionId) {
141799
+ db.prepare(`UPDATE tool_owner_backfill_state
141800
+ SET status = 'pending', completed_at = NULL, lease_expires_at = NULL, last_error = NULL
141801
+ WHERE session_id = ?`).run(sessionId);
141802
+ }
141749
141803
  function markSessionSkipped(db, sessionId, now, reason) {
141750
141804
  db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, completed_at, last_error)
141751
141805
  VALUES (?, 'skipped', ?, ?)
@@ -141822,12 +141876,18 @@ function applyOwnersForSession(db, sessionId, ownersByCallId) {
141822
141876
  const updateRowStmt = db.prepare(`UPDATE tags
141823
141877
  SET tool_owner_message_id = ?
141824
141878
  WHERE id = ? AND tool_owner_message_id IS NULL`);
141879
+ const existingOwnerStmt = db.prepare(`SELECT 1 AS hit FROM tags
141880
+ WHERE session_id = ? AND message_id = ? AND type = 'tool'
141881
+ AND tool_owner_message_id = ?
141882
+ LIMIT 1`);
141825
141883
  let rowsUpdated = 0;
141826
141884
  db.transaction(() => {
141827
141885
  for (const [callId, ownerId] of ownersByCallId) {
141828
141886
  const orphan = findOrphanStmt.get(sessionId, callId);
141829
141887
  if (!orphan)
141830
141888
  continue;
141889
+ if (existingOwnerStmt.get(sessionId, callId, ownerId))
141890
+ continue;
141831
141891
  const result = updateRowStmt.run(ownerId, orphan.id);
141832
141892
  rowsUpdated += result.changes ?? 0;
141833
141893
  }
@@ -141856,6 +141916,8 @@ function backfillToolOwnersInChunks(db, result) {
141856
141916
  if (owners.size === 0) {
141857
141917
  markSessionSkipped(db, sessionId, Date.now(), "no_oc_matches");
141858
141918
  result.sessionsSkippedNoMatches += 1;
141919
+ } else if (rowsLeftNull > 0) {
141920
+ markSessionPendingRetry(db, sessionId);
141859
141921
  } else {
141860
141922
  markSessionCompleted(db, sessionId, Date.now());
141861
141923
  result.sessionsCompleted += 1;
@@ -141878,7 +141940,7 @@ var databases = new Map;
141878
141940
  var persistenceByDatabase = new WeakMap;
141879
141941
  var persistenceErrorByDatabase = new WeakMap;
141880
141942
  var lastSchemaFenceRejection = null;
141881
- var LATEST_SUPPORTED_VERSION = 30;
141943
+ var LATEST_SUPPORTED_VERSION = 32;
141882
141944
  function resolveDatabasePath(dbPathOverride) {
141883
141945
  if (dbPathOverride) {
141884
141946
  return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
@@ -141980,9 +142042,9 @@ function runSqliteOptimize(db) {
141980
142042
  } catch {}
141981
142043
  }
141982
142044
  function initializeDatabase(db) {
142045
+ db.exec("PRAGMA busy_timeout=5000");
141983
142046
  db.exec("PRAGMA foreign_keys=ON");
141984
142047
  db.exec("PRAGMA journal_mode=WAL");
141985
- db.exec("PRAGMA busy_timeout=5000");
141986
142048
  applySqliteTuningPragmas(db);
141987
142049
  db.exec(`
141988
142050
  CREATE TABLE IF NOT EXISTS tags (
@@ -141995,6 +142057,9 @@ function initializeDatabase(db) {
141995
142057
  tag_number INTEGER,
141996
142058
  harness TEXT NOT NULL DEFAULT 'opencode',
141997
142059
  entry_fingerprint TEXT,
142060
+ token_count INTEGER,
142061
+ input_token_count INTEGER,
142062
+ reasoning_token_count INTEGER,
141998
142063
  UNIQUE(session_id, tag_number)
141999
142064
  );
142000
142065
 
@@ -142284,6 +142349,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
142284
142349
  counter INTEGER DEFAULT 0,
142285
142350
  last_nudge_tokens INTEGER DEFAULT 0,
142286
142351
  last_nudge_band TEXT DEFAULT '',
142352
+ last_nudge_undropped INTEGER DEFAULT 0,
142353
+ last_nudge_level TEXT DEFAULT '',
142354
+ channel2_nudge_state TEXT DEFAULT '',
142355
+ channel2_nudge_claimed_at INTEGER DEFAULT 0,
142356
+ last_emergency_input_sample INTEGER DEFAULT 0,
142287
142357
  last_transform_error TEXT DEFAULT '',
142288
142358
  nudge_anchor_message_id TEXT DEFAULT '',
142289
142359
  nudge_anchor_text TEXT DEFAULT '',
@@ -142340,6 +142410,14 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
142340
142410
  cached_m0_project_docs_hash TEXT,
142341
142411
  cached_m1_bytes BLOB,
142342
142412
  last_observed_model_key TEXT,
142413
+ last_usage_context_limit INTEGER NOT NULL DEFAULT 0,
142414
+ prior_boundary_ordinal INTEGER NOT NULL DEFAULT 1,
142415
+ protected_tail_policy_version INTEGER NOT NULL DEFAULT 0,
142416
+ protected_tail_drain_window_started_at INTEGER NOT NULL DEFAULT 0,
142417
+ protected_tail_drain_tokens INTEGER NOT NULL DEFAULT 0,
142418
+ recovery_no_eligible_head_count INTEGER NOT NULL DEFAULT 0,
142419
+ force_emergency_bypass_window_start INTEGER NOT NULL DEFAULT 0,
142420
+ force_emergency_bypass_used INTEGER NOT NULL DEFAULT 0,
142343
142421
  cached_m0_materialized_at INTEGER,
142344
142422
  cached_m0_session_facts_version INTEGER,
142345
142423
  cached_m0_upgrade_state TEXT,
@@ -142450,6 +142528,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
142450
142528
  CREATE INDEX IF NOT EXISTS idx_message_history_index_updated_at ON message_history_index(updated_at);
142451
142529
  `);
142452
142530
  ensureColumn(db, "session_meta", "last_nudge_band", "TEXT DEFAULT ''");
142531
+ ensureColumn(db, "session_meta", "last_nudge_undropped", "INTEGER DEFAULT 0");
142532
+ ensureColumn(db, "session_meta", "last_nudge_level", "TEXT DEFAULT ''");
142533
+ ensureColumn(db, "session_meta", "channel2_nudge_state", "TEXT DEFAULT ''");
142534
+ ensureColumn(db, "session_meta", "channel2_nudge_claimed_at", "INTEGER DEFAULT 0");
142535
+ ensureColumn(db, "session_meta", "last_emergency_input_sample", "INTEGER DEFAULT 0");
142453
142536
  ensureColumn(db, "session_meta", "last_transform_error", "TEXT DEFAULT ''");
142454
142537
  ensureColumn(db, "session_meta", "nudge_anchor_message_id", "TEXT DEFAULT ''");
142455
142538
  ensureColumn(db, "session_meta", "nudge_anchor_text", "TEXT DEFAULT ''");
@@ -142495,6 +142578,9 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
142495
142578
  db.exec(`CREATE INDEX IF NOT EXISTS idx_tags_pi_adopt
142496
142579
  ON tags(session_id, entry_fingerprint)
142497
142580
  WHERE type='message' AND entry_fingerprint IS NOT NULL`);
142581
+ ensureColumn(db, "tags", "token_count", "INTEGER");
142582
+ ensureColumn(db, "tags", "input_token_count", "INTEGER");
142583
+ ensureColumn(db, "tags", "reasoning_token_count", "INTEGER");
142498
142584
  ensureColumn(db, "session_meta", "system_prompt_tokens", "INTEGER DEFAULT 0");
142499
142585
  ensureColumn(db, "session_meta", "compaction_marker_state", "TEXT DEFAULT ''");
142500
142586
  ensureColumn(db, "session_meta", "key_files", "TEXT DEFAULT ''");
@@ -142535,6 +142621,14 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
142535
142621
  ensureColumn(db, "session_meta", "cached_m0_project_docs_hash", "TEXT");
142536
142622
  ensureColumn(db, "session_meta", "cached_m1_bytes", "BLOB");
142537
142623
  ensureColumn(db, "session_meta", "last_observed_model_key", "TEXT");
142624
+ ensureColumn(db, "session_meta", "last_usage_context_limit", "INTEGER NOT NULL DEFAULT 0");
142625
+ ensureColumn(db, "session_meta", "prior_boundary_ordinal", "INTEGER NOT NULL DEFAULT 1");
142626
+ ensureColumn(db, "session_meta", "protected_tail_policy_version", "INTEGER NOT NULL DEFAULT 0");
142627
+ ensureColumn(db, "session_meta", "protected_tail_drain_window_started_at", "INTEGER NOT NULL DEFAULT 0");
142628
+ ensureColumn(db, "session_meta", "protected_tail_drain_tokens", "INTEGER NOT NULL DEFAULT 0");
142629
+ ensureColumn(db, "session_meta", "recovery_no_eligible_head_count", "INTEGER NOT NULL DEFAULT 0");
142630
+ ensureColumn(db, "session_meta", "force_emergency_bypass_window_start", "INTEGER NOT NULL DEFAULT 0");
142631
+ ensureColumn(db, "session_meta", "force_emergency_bypass_used", "INTEGER NOT NULL DEFAULT 0");
142538
142632
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
142539
142633
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
142540
142634
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
@@ -142604,6 +142698,13 @@ function healAllNullColumns(db) {
142604
142698
  healNullIntegerColumns(db);
142605
142699
  healMissingMemoryBlockIds(db);
142606
142700
  }
142701
+ var CHANNEL2_CLAIM_TTL_MS = 120000;
142702
+ function healWedgedChannel2Claims(db) {
142703
+ try {
142704
+ const staleBefore = Date.now() - CHANNEL2_CLAIM_TTL_MS;
142705
+ db.prepare("UPDATE session_meta SET channel2_nudge_state = 'pending', channel2_nudge_claimed_at = 0 WHERE channel2_nudge_state = 'claimed' AND (channel2_nudge_claimed_at IS NULL OR channel2_nudge_claimed_at = 0 OR channel2_nudge_claimed_at <= ?)").run(staleBefore);
142706
+ } catch {}
142707
+ }
142607
142708
  function healMissingMemoryBlockIds(db) {
142608
142709
  try {
142609
142710
  db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
@@ -142613,6 +142714,7 @@ function healNullTextColumns(db) {
142613
142714
  const columns = [
142614
142715
  ["cache_ttl", ""],
142615
142716
  ["last_nudge_band", ""],
142717
+ ["last_nudge_level", ""],
142616
142718
  ["last_transform_error", ""],
142617
142719
  ["nudge_anchor_message_id", ""],
142618
142720
  ["nudge_anchor_text", ""],
@@ -142653,7 +142755,17 @@ function healNullIntegerColumns(db) {
142653
142755
  ["observed_safe_input_tokens", 0],
142654
142756
  ["cache_alert_sent", 0],
142655
142757
  ["new_work_tokens", 0],
142656
- ["total_input_tokens", 0]
142758
+ ["total_input_tokens", 0],
142759
+ ["last_emergency_input_sample", 0],
142760
+ ["channel2_nudge_claimed_at", 0],
142761
+ ["last_usage_context_limit", 0],
142762
+ ["prior_boundary_ordinal", 1],
142763
+ ["protected_tail_policy_version", 0],
142764
+ ["protected_tail_drain_window_started_at", 0],
142765
+ ["protected_tail_drain_tokens", 0],
142766
+ ["recovery_no_eligible_head_count", 0],
142767
+ ["force_emergency_bypass_window_start", 0],
142768
+ ["force_emergency_bypass_used", 0]
142657
142769
  ];
142658
142770
  for (const [column, fallback] of columns) {
142659
142771
  try {
@@ -142692,6 +142804,7 @@ function openDatabase(dbPathOrOptions) {
142692
142804
  if (!persistenceByDatabase.has(existing)) {
142693
142805
  persistenceByDatabase.set(existing, true);
142694
142806
  }
142807
+ healWedgedChannel2Claims(existing);
142695
142808
  return existing;
142696
142809
  }
142697
142810
  try {
@@ -142717,6 +142830,7 @@ function openDatabase(dbPathOrOptions) {
142717
142830
  log(`[magic-context] key-files orphan GC failed: ${getErrorMessage(error)}`);
142718
142831
  }
142719
142832
  }
142833
+ healWedgedChannel2Claims(db);
142720
142834
  if (!explicitDbPath) {
142721
142835
  try {
142722
142836
  runToolOwnerBackfill(db);
@@ -142737,6 +142851,9 @@ function openDatabase(dbPathOrOptions) {
142737
142851
  }
142738
142852
  }
142739
142853
 
142854
+ // src/subagent-entry.ts
142855
+ init_logger();
142856
+
142740
142857
  // ../plugin/src/config/prune-config-leaf.ts
142741
142858
  function isPlainObject(value) {
142742
142859
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -142915,6 +143032,10 @@ function stripUnsafeProjectConfigFields(projectRaw) {
142915
143032
  delete projectRaw.auto_update;
142916
143033
  warnings.push("Ignoring auto_update from project config (security: this setting only honors user-level config).");
142917
143034
  }
143035
+ if ("sqlite" in projectRaw) {
143036
+ delete projectRaw.sqlite;
143037
+ warnings.push("Ignoring sqlite.* from project config (security: SQLite cache/mmap PRAGMAs apply to the " + "process-global shared database handle; only user-level config may set them).");
143038
+ }
142918
143039
  for (const agentKey of HIDDEN_AGENT_KEYS) {
142919
143040
  const block = projectRaw[agentKey];
142920
143041
  if (!isPlainObject2(block))
@@ -157273,7 +157394,6 @@ var AgentOverrideConfigSchema = exports_external.object({
157273
157394
  });
157274
157395
 
157275
157396
  // ../plugin/src/config/schema/magic-context.ts
157276
- var DEFAULT_NUDGE_INTERVAL_TOKENS = 1e4;
157277
157397
  var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
157278
157398
  var EXECUTE_THRESHOLD_CAP_MESSAGE = "execute_threshold is capped at 80% for cache safety: a single large agent step can overflow the context window before Magic Context can compact between turns, forcing OpenCode's native compaction (hard to recover from). 80% also leaves headroom below the 85%/95% emergency bands. Use a value between 20 and 80.";
157279
157399
  var DEFAULT_HISTORIAN_TIMEOUT_MS = 300000;
@@ -157372,7 +157492,6 @@ var MagicContextConfigSchema = exports_external.object({
157372
157492
  historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
157373
157493
  dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
157374
157494
  cache_ttl: exports_external.union([exports_external.string(), exports_external.object({ default: exports_external.string() }).catchall(exports_external.string())]).default("5m").describe('Cache TTL: string (e.g. "5m") or per-model object ({ default: "5m", "model-id": "10m" })'),
157375
- nudge_interval_tokens: exports_external.number().min(1000).default(DEFAULT_NUDGE_INTERVAL_TOKENS).describe("Minimum token growth between low-priority rolling nudges (default: DEFAULT_NUDGE_INTERVAL_TOKENS)"),
157376
157495
  execute_threshold_percentage: exports_external.union([
157377
157496
  exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE),
157378
157497
  exports_external.object({ default: exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE) }).catchall(exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE))
@@ -157381,10 +157500,7 @@ var MagicContextConfigSchema = exports_external.object({
157381
157500
  default: exports_external.number().min(5000).max(2000000).optional()
157382
157501
  }).catchall(exports_external.number().min(5000).max(2000000)).optional().describe("Absolute token thresholds per model. When matched, overrides execute_threshold_percentage for that model. Accepts `default` for all models or per-model keys. Values above 80% × context_limit are clamped with a warning log. Min 5_000, max 2_000_000."),
157383
157502
  protected_tags: exports_external.number().min(1).max(100).optional().describe("Number of recent tags to protect from dropping (min: 1, max: 100, default: 20)"),
157384
- auto_drop_tool_age: exports_external.number().min(10).default(100).describe("Auto-drop tool outputs older than N tags during queue execution (default: 100)"),
157385
- drop_tool_structure: exports_external.boolean().default(true).describe("When true, dropped tool parts are fully removed instead of truncated in place (default: true)"),
157386
157503
  clear_reasoning_age: exports_external.number().min(10).default(50).describe("Clear reasoning/thinking blocks older than N tags (default: 50)"),
157387
- iteration_nudge_threshold: exports_external.number().min(5).default(15).describe("Number of consecutive assistant messages without user input to trigger iteration nudge (default: 15)"),
157388
157504
  history_budget_percentage: exports_external.number().min(0.05).max(0.5).default(DEFAULT_HISTORY_BUDGET_PERCENTAGE).describe("Fraction of usable context (context_limit × execute_threshold) reserved for the session history block (default: 0.15)"),
157389
157505
  historian_timeout_ms: exports_external.number().min(60000).default(DEFAULT_HISTORIAN_TIMEOUT_MS).describe("Timeout for each historian prompt call in milliseconds (default: 300000)"),
157390
157506
  commit_cluster_trigger: exports_external.object({
@@ -157887,6 +158003,9 @@ function loadPiConfigDetailed(opts = {}) {
157887
158003
  };
157888
158004
  }
157889
158005
 
158006
+ // ../plugin/src/features/magic-context/memory/embedding.ts
158007
+ init_logger();
158008
+
157890
158009
  // ../plugin/src/features/magic-context/memory/cosine-similarity.ts
157891
158010
  function cosineSimilarity(a, b) {
157892
158011
  if (a.length !== b.length) {
@@ -157942,6 +158061,8 @@ import { mkdirSync as mkdirSync3 } from "node:fs";
157942
158061
  import { open, stat, unlink, writeFile } from "node:fs/promises";
157943
158062
  import { dirname as dirname4, join as join6 } from "node:path";
157944
158063
  import { pathToFileURL } from "node:url";
158064
+ init_data_path();
158065
+ init_logger();
157945
158066
  var LOCK_POLL_MS = 150;
157946
158067
  var STALE_LOCK_MS = 3 * 60000;
157947
158068
  var MAX_LOCK_WAIT_MS = 5 * 60000;
@@ -158276,6 +158397,9 @@ class LocalEmbeddingProvider {
158276
158397
  }
158277
158398
  }
158278
158399
 
158400
+ // ../plugin/src/features/magic-context/memory/embedding-openai.ts
158401
+ init_logger();
158402
+
158279
158403
  // ../plugin/src/features/magic-context/memory/embedding-ssrf.ts
158280
158404
  var METADATA_HOSTNAMES = new Set(["metadata.google.internal", "metadata.goog"]);
158281
158405
  var IPV6_METADATA_HOSTS = new Set(["fd00:ec2::254"]);
@@ -158627,6 +158751,7 @@ function getDistinctStoredModelIds(db, projectPath) {
158627
158751
 
158628
158752
  // ../plugin/src/features/magic-context/project-embedding-registry.ts
158629
158753
  import { createHash as createHash3, randomUUID } from "node:crypto";
158754
+ init_logger();
158630
158755
 
158631
158756
  // ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
158632
158757
  var saveStatements = new WeakMap;
@@ -159383,6 +159508,7 @@ function storedPathBelongsToIdentity(storedProjectPath, projectIdentity) {
159383
159508
 
159384
159509
  // ../plugin/src/plugin/embedding-bootstrap-helpers.ts
159385
159510
  import { createHash as createHash5 } from "node:crypto";
159511
+ init_logger();
159386
159512
  var EMBEDDING_AFFECTING_KEYS = new Set([
159387
159513
  "embedding.api_key",
159388
159514
  "embedding.endpoint",
@@ -159480,7 +159606,6 @@ async function ensureProjectRegisteredFromPiDirectory(directory, db) {
159480
159606
  };
159481
159607
  registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, detailed.config.embedding, features, directory);
159482
159608
  }
159483
-
159484
159609
  // ../plugin/src/features/magic-context/compartment-lease.ts
159485
159610
  var COMPARTMENT_LEASE_TTL_MS = 5 * 60 * 1000;
159486
159611
  var COMPARTMENT_LEASE_RENEWAL_MS = 60 * 1000;
@@ -159578,6 +159703,14 @@ var SESSION_META_SELECT_COLUMNS = [
159578
159703
  "cached_m0_tool_set_hash",
159579
159704
  "cached_m0_model_key",
159580
159705
  "last_observed_model_key",
159706
+ "last_usage_context_limit",
159707
+ "prior_boundary_ordinal",
159708
+ "protected_tail_policy_version",
159709
+ "protected_tail_drain_window_started_at",
159710
+ "protected_tail_drain_tokens",
159711
+ "recovery_no_eligible_head_count",
159712
+ "force_emergency_bypass_window_start",
159713
+ "force_emergency_bypass_used",
159581
159714
  "upgrade_reminded_at",
159582
159715
  "pi_stable_id_scheme"
159583
159716
  ];
@@ -159617,6 +159750,14 @@ var META_COLUMNS = {
159617
159750
  cachedM0ToolSetHash: "cached_m0_tool_set_hash",
159618
159751
  cachedM0ModelKey: "cached_m0_model_key",
159619
159752
  lastObservedModelKey: "last_observed_model_key",
159753
+ lastUsageContextLimit: "last_usage_context_limit",
159754
+ priorBoundaryOrdinal: "prior_boundary_ordinal",
159755
+ protectedTailPolicyVersion: "protected_tail_policy_version",
159756
+ protectedTailDrainWindowStartedAt: "protected_tail_drain_window_started_at",
159757
+ protectedTailDrainTokens: "protected_tail_drain_tokens",
159758
+ recoveryNoEligibleHeadCount: "recovery_no_eligible_head_count",
159759
+ forceEmergencyBypassWindowStart: "force_emergency_bypass_window_start",
159760
+ forceEmergencyBypassUsed: "force_emergency_bypass_used",
159620
159761
  upgradeRemindedAt: "upgrade_reminded_at",
159621
159762
  piStableIdScheme: "pi_stable_id_scheme"
159622
159763
  };
@@ -159658,7 +159799,7 @@ function isSessionMetaRow(row) {
159658
159799
  if (row === null || typeof row !== "object")
159659
159800
  return false;
159660
159801
  const r = row;
159661
- 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);
159802
+ 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.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
159662
159803
  }
159663
159804
  function getDefaultSessionMeta(sessionId) {
159664
159805
  return {
@@ -159698,6 +159839,14 @@ function getDefaultSessionMeta(sessionId) {
159698
159839
  cachedM0ToolSetHash: null,
159699
159840
  cachedM0ModelKey: null,
159700
159841
  lastObservedModelKey: null,
159842
+ lastUsageContextLimit: 0,
159843
+ priorBoundaryOrdinal: 1,
159844
+ protectedTailPolicyVersion: 0,
159845
+ protectedTailDrainWindowStartedAt: 0,
159846
+ protectedTailDrainTokens: 0,
159847
+ recoveryNoEligibleHeadCount: 0,
159848
+ forceEmergencyBypassWindowStart: 0,
159849
+ forceEmergencyBypassUsed: 0,
159701
159850
  upgradeRemindedAt: null,
159702
159851
  piStableIdScheme: null
159703
159852
  };
@@ -159752,6 +159901,14 @@ function toSessionMeta(row) {
159752
159901
  cachedM0ToolSetHash: stringOrNull(row.cached_m0_tool_set_hash),
159753
159902
  cachedM0ModelKey: stringOrNull(row.cached_m0_model_key),
159754
159903
  lastObservedModelKey: stringOrNull(row.last_observed_model_key),
159904
+ lastUsageContextLimit: numOrZero(row.last_usage_context_limit),
159905
+ priorBoundaryOrdinal: Math.max(1, numOrZero(row.prior_boundary_ordinal) || 1),
159906
+ protectedTailPolicyVersion: numOrZero(row.protected_tail_policy_version),
159907
+ protectedTailDrainWindowStartedAt: numOrZero(row.protected_tail_drain_window_started_at),
159908
+ protectedTailDrainTokens: numOrZero(row.protected_tail_drain_tokens),
159909
+ recoveryNoEligibleHeadCount: numOrZero(row.recovery_no_eligible_head_count),
159910
+ forceEmergencyBypassWindowStart: numOrZero(row.force_emergency_bypass_window_start),
159911
+ forceEmergencyBypassUsed: numOrZero(row.force_emergency_bypass_used),
159755
159912
  upgradeRemindedAt: numOrNull(row.upgrade_reminded_at),
159756
159913
  piStableIdScheme: numOrNull(row.pi_stable_id_scheme)
159757
159914
  };
@@ -159772,9 +159929,8 @@ function persistCachedM0(db, sessionId, payload) {
159772
159929
  cached_m0_session_facts_version = ?,
159773
159930
  cached_m0_upgrade_state = ?,
159774
159931
  cached_m0_system_hash = ?,
159775
- cached_m0_tool_set_hash = ?,
159776
159932
  cached_m0_model_key = ?
159777
- 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);
159933
+ 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.modelKey ?? "", sessionId);
159778
159934
  }
159779
159935
  function clearCachedM0M1(db, sessionId) {
159780
159936
  ensureSessionMetaRow(db, sessionId);
@@ -159872,6 +160028,11 @@ function getLastCompartmentEndMessage(db, sessionId) {
159872
160028
  const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
159873
160029
  return row?.max_end ?? -1;
159874
160030
  }
160031
+ function getLastCompartmentEndMessageId(db, sessionId) {
160032
+ const row = db.prepare("SELECT end_message_id FROM compartments WHERE session_id = ? ORDER BY sequence DESC LIMIT 1").get(sessionId);
160033
+ const id = row?.end_message_id;
160034
+ return id && id.length > 0 ? id : null;
160035
+ }
159875
160036
  function getCompartmentsByEndMessageId(db, sessionId, endMessageId) {
159876
160037
  const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? AND end_message_id = ? ORDER BY sequence ASC").all(sessionId, endMessageId).filter(isCompartmentRow);
159877
160038
  return rows.map(toCompartment);
@@ -159974,6 +160135,8 @@ function escapeXmlContent(s) {
159974
160135
  }
159975
160136
 
159976
160137
  // ../plugin/src/hooks/magic-context/read-session-db.ts
160138
+ init_data_path();
160139
+ init_logger();
159977
160140
  import { existsSync as existsSync6 } from "node:fs";
159978
160141
  import { join as join7 } from "node:path";
159979
160142
  function getOpenCodeDbPath() {
@@ -160046,13 +160209,27 @@ function parseJsonUnknown(value) {
160046
160209
  return null;
160047
160210
  }
160048
160211
  }
160212
+ function attachRawPartVersion(value, timeUpdated) {
160213
+ if (value === null || typeof value !== "object" || Array.isArray(value))
160214
+ return value;
160215
+ if (typeof timeUpdated !== "number")
160216
+ return value;
160217
+ try {
160218
+ Object.defineProperty(value, "__magicContextPartUpdatedAt", {
160219
+ value: timeUpdated,
160220
+ enumerable: false,
160221
+ configurable: true
160222
+ });
160223
+ } catch {}
160224
+ return value;
160225
+ }
160049
160226
  function readRawSessionMessagesFromDb(db, sessionId) {
160050
- const messageRows = db.prepare("SELECT id, data FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawMessageRow);
160051
- const partRows = db.prepare("SELECT message_id, data FROM part WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawPartRow);
160227
+ const messageRows = db.prepare("SELECT id, data, time_updated FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawMessageRow);
160228
+ const partRows = db.prepare("SELECT message_id, data, time_updated FROM part WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawPartRow);
160052
160229
  const partsByMessageId = new Map;
160053
160230
  for (const part of partRows) {
160054
160231
  const list = partsByMessageId.get(part.message_id) ?? [];
160055
- list.push(parseJsonUnknown(part.data));
160232
+ list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
160056
160233
  partsByMessageId.set(part.message_id, list);
160057
160234
  }
160058
160235
  const filtered = messageRows.filter((row) => {
@@ -160068,10 +160245,63 @@ function readRawSessionMessagesFromDb(db, sessionId) {
160068
160245
  ordinal: index + 1,
160069
160246
  id: row.id,
160070
160247
  role,
160071
- parts: partsByMessageId.get(row.id) ?? []
160248
+ parts: partsByMessageId.get(row.id) ?? [],
160249
+ version: row.time_updated ?? null
160072
160250
  };
160073
160251
  });
160074
160252
  }
160253
+ function isAnchorRow(row) {
160254
+ return row !== null && typeof row === "object" && typeof row.time_created === "number" && typeof row.id === "string";
160255
+ }
160256
+ function readRawSessionTailFromDb(db, sessionId, baseOrdinal, anchorMessageId) {
160257
+ const anchorRow = db.prepare("SELECT time_created, id, data FROM message WHERE id = ? AND session_id = ?").get(anchorMessageId, sessionId);
160258
+ if (!isAnchorRow(anchorRow))
160259
+ return null;
160260
+ const anchorInfo = parseJsonRecord(anchorRow.data ?? "");
160261
+ if (anchorInfo?.summary === true && anchorInfo?.finish === "stop")
160262
+ return null;
160263
+ const messageRows = db.prepare(`SELECT id, data, time_updated FROM message
160264
+ WHERE session_id = ?
160265
+ AND (time_created > ? OR (time_created = ? AND id >= ?))
160266
+ ORDER BY time_created ASC, id ASC`).all(sessionId, anchorRow.time_created, anchorRow.time_created, anchorRow.id).filter(isRawMessageRow);
160267
+ const filtered = messageRows.filter((row) => {
160268
+ const info = parseJsonRecord(row.data);
160269
+ return !(info?.summary === true && info?.finish === "stop");
160270
+ });
160271
+ const ids = filtered.map((row) => row.id);
160272
+ const partsByMessageId = new Map;
160273
+ if (ids.length > 0) {
160274
+ const CHUNK = 800;
160275
+ for (let i = 0;i < ids.length; i += CHUNK) {
160276
+ const slice = ids.slice(i, i + CHUNK);
160277
+ const placeholders = slice.map(() => "?").join(",");
160278
+ const partRows = db.prepare(`SELECT message_id, data, time_updated FROM part WHERE session_id = ? AND message_id IN (${placeholders}) ORDER BY time_created ASC, id ASC`).all(sessionId, ...slice).filter(isRawPartRow);
160279
+ for (const part of partRows) {
160280
+ const list = partsByMessageId.get(part.message_id) ?? [];
160281
+ list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
160282
+ partsByMessageId.set(part.message_id, list);
160283
+ }
160284
+ }
160285
+ }
160286
+ const messages = [];
160287
+ let ord = baseOrdinal;
160288
+ for (const row of filtered) {
160289
+ const info = parseJsonRecord(row.data);
160290
+ if (!info) {
160291
+ ord += 1;
160292
+ continue;
160293
+ }
160294
+ messages.push({
160295
+ ordinal: ord,
160296
+ id: row.id,
160297
+ role: typeof info.role === "string" ? info.role : "unknown",
160298
+ parts: partsByMessageId.get(row.id) ?? [],
160299
+ version: row.time_updated ?? null
160300
+ });
160301
+ ord += 1;
160302
+ }
160303
+ return { messages, absoluteMessageCount: Math.max(0, ord - 1) };
160304
+ }
160075
160305
 
160076
160306
  // ../plugin/src/hooks/magic-context/tag-content-primitives.ts
160077
160307
  var encoder = new TextEncoder;
@@ -160216,6 +160446,7 @@ class ToolMutationBatch {
160216
160446
 
160217
160447
  // ../plugin/src/hooks/magic-context/read-session-chunk.ts
160218
160448
  var activeRawMessageCache = null;
160449
+ var activeAbsoluteCountCache = null;
160219
160450
  var sessionProviders = new Map;
160220
160451
  function setRawMessageProvider(sessionId, provider2) {
160221
160452
  sessionProviders.set(sessionId, provider2);
@@ -160247,12 +160478,14 @@ function withRawSessionMessageCache(fn) {
160247
160478
  const outerCache = activeRawMessageCache;
160248
160479
  if (!outerCache) {
160249
160480
  activeRawMessageCache = new Map;
160481
+ activeAbsoluteCountCache = new Map;
160250
160482
  }
160251
160483
  try {
160252
160484
  return fn();
160253
160485
  } finally {
160254
160486
  if (!outerCache) {
160255
160487
  activeRawMessageCache = null;
160488
+ activeAbsoluteCountCache = null;
160256
160489
  }
160257
160490
  }
160258
160491
  }
@@ -160268,6 +160501,40 @@ function readRawSessionMessages(sessionId) {
160268
160501
  }
160269
160502
  return readRawSessionMessagesFromSource(sessionId);
160270
160503
  }
160504
+ function primeTailRawMessageCache(args) {
160505
+ const { sessionId, lastCompartmentEnd, anchorMessageId } = args;
160506
+ if (!activeRawMessageCache)
160507
+ return false;
160508
+ if (activeRawMessageCache.has(sessionId))
160509
+ return false;
160510
+ if (sessionProviders.has(sessionId))
160511
+ return false;
160512
+ if (!openCodeDbExists())
160513
+ return false;
160514
+ if (lastCompartmentEnd < 1 || !anchorMessageId)
160515
+ return false;
160516
+ const result = withReadOnlySessionDb((db) => readRawSessionTailFromDb(db, sessionId, lastCompartmentEnd, anchorMessageId));
160517
+ if (!result)
160518
+ return false;
160519
+ activeRawMessageCache.set(sessionId, result.messages);
160520
+ activeAbsoluteCountCache?.set(sessionId, result.absoluteMessageCount);
160521
+ return true;
160522
+ }
160523
+ function getCachedAbsoluteMessageCount(sessionId) {
160524
+ return activeAbsoluteCountCache?.get(sessionId) ?? null;
160525
+ }
160526
+ function primeInMemoryTailRawMessageCache(args) {
160527
+ const { sessionId, messages, absoluteMessageCount } = args;
160528
+ if (!activeRawMessageCache)
160529
+ return false;
160530
+ if (activeRawMessageCache.has(sessionId))
160531
+ return false;
160532
+ if (sessionProviders.has(sessionId))
160533
+ return false;
160534
+ activeRawMessageCache.set(sessionId, messages);
160535
+ activeAbsoluteCountCache?.set(sessionId, absoluteMessageCount);
160536
+ return true;
160537
+ }
160271
160538
  function readRawSessionMessagesFromSource(sessionId) {
160272
160539
  const provider2 = sessionProviders.get(sessionId);
160273
160540
  if (provider2)
@@ -160332,7 +160599,7 @@ function getRawSessionTagKeysThrough(sessionId, upToMessageIndex) {
160332
160599
  return { messageFileKeys, toolObservations };
160333
160600
  }
160334
160601
  var PROTECTED_TAIL_USER_TURNS = 5;
160335
- function getProtectedTailStartOrdinal(sessionId) {
160602
+ function getLegacyProtectedTailStartOrdinal(sessionId) {
160336
160603
  const messages = readRawSessionMessages(sessionId);
160337
160604
  const userOrdinals = messages.filter((m) => m.role === "user" && hasMeaningfulUserText(m.parts)).map((m) => m.ordinal);
160338
160605
  if (userOrdinals.length < PROTECTED_TAIL_USER_TURNS) {
@@ -160342,6 +160609,7 @@ function getProtectedTailStartOrdinal(sessionId) {
160342
160609
  }
160343
160610
  function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal) {
160344
160611
  const messages = readRawSessionMessages(sessionId);
160612
+ const totalMessageCount = getCachedAbsoluteMessageCount(sessionId) ?? messages.length;
160345
160613
  const startOrdinal = Math.max(1, offset);
160346
160614
  const lines = [];
160347
160615
  const lineMeta = [];
@@ -160469,7 +160737,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
160469
160737
  endMessageId: lastMessageId,
160470
160738
  messageCount: messagesProcessed,
160471
160739
  tokenEstimate: totalTokens,
160472
- hasMore: lastOrdinal < (eligibleEndOrdinal !== undefined ? Math.min(eligibleEndOrdinal - 1, messages.length) : messages.length),
160740
+ hasMore: lastOrdinal < (eligibleEndOrdinal !== undefined ? Math.min(eligibleEndOrdinal - 1, totalMessageCount) : totalMessageCount),
160473
160741
  text: lines.join(`
160474
160742
  `),
160475
160743
  lines: lineMeta,
@@ -160479,7 +160747,13 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
160479
160747
  }
160480
160748
 
160481
160749
  // ../plugin/src/tools/ctx-expand/constants.ts
160482
- var CTX_EXPAND_DESCRIPTION = "Decompress a compartment range to see the original conversation transcript. " + 'Use start/end from <compartment start="N" end="M"> attributes. ' + "Returns the compacted U:/A: transcript for that message range, capped at ~15K tokens.";
160750
+ var CTX_EXPAND_DESCRIPTION = `Recover the original conversation from your compacted history.
160751
+
160752
+ Older parts of this session are summarized into <compartment> blocks inside <session-history> — e.g. <compartment start="120" end="245" title="Fixed tagger collision">. Each one replaces the raw messages in that ordinal range with a summary. When the summary isn't enough — you need exact wording, a specific value, an error message, or the reasoning behind a decision — expand the range:
160753
+
160754
+ ctx_expand(start=120, end=245) ← the compartment's own start/end attributes
160755
+
160756
+ Returns the raw transcript as [N] U:/A: lines, capped at ~15K tokens; an oversized range returns the head and tells you where to continue. Also works with ordinals from ctx_search message results — expand a window around a hit (e.g. start=N-10, end=N+5). Ranges after the last compartment are your live tail — already visible in context, not expandable.`;
160483
160757
  var CTX_EXPAND_TOKEN_BUDGET = 15000;
160484
160758
 
160485
160759
  // ../../node_modules/.bun/typebox@1.1.38/node_modules/typebox/build/system/memory/memory.mjs
@@ -164648,11 +164922,31 @@ function findLastModelKeyFromBranch(entries) {
164648
164922
  }
164649
164923
  return;
164650
164924
  }
164925
+ function rawEntryVersion(entry) {
164926
+ const record4 = entry;
164927
+ const updated = record4.updatedAt ?? record4.updated_at ?? record4.timestamp;
164928
+ return typeof updated === "string" || typeof updated === "number" ? updated : entry.id;
164929
+ }
164930
+ function attachPiPartVersion(parts, version2) {
164931
+ return parts.map((part) => {
164932
+ if (part === null || typeof part !== "object" || Array.isArray(part))
164933
+ return part;
164934
+ try {
164935
+ Object.defineProperty(part, "__magicContextPartUpdatedAt", {
164936
+ value: version2,
164937
+ enumerable: false,
164938
+ configurable: true
164939
+ });
164940
+ } catch {}
164941
+ return part;
164942
+ });
164943
+ }
164651
164944
  function convertEntriesToRawMessages(entries) {
164652
164945
  const result = [];
164653
164946
  let nextOrdinal = 1;
164654
164947
  let pendingToolParts = [];
164655
164948
  let pendingFirstRealId = "";
164949
+ let pendingFirstRealVersion = "";
164656
164950
  for (const entry of entries) {
164657
164951
  if (!isMessageEntry(entry)) {
164658
164952
  continue;
@@ -164660,24 +164954,29 @@ function convertEntriesToRawMessages(entries) {
164660
164954
  const msg = entry.message;
164661
164955
  const role = msg.role;
164662
164956
  if (role === "toolResult") {
164663
- pendingToolParts.push(...synthesizeToolResultParts(msg));
164957
+ const version2 = rawEntryVersion(entry);
164958
+ pendingToolParts.push(...attachPiPartVersion(synthesizeToolResultParts(msg), version2));
164664
164959
  if (pendingFirstRealId === "") {
164665
164960
  pendingFirstRealId = entry.id;
164961
+ pendingFirstRealVersion = version2;
164666
164962
  }
164667
164963
  continue;
164668
164964
  }
164669
164965
  if (role === "user") {
164966
+ const version2 = rawEntryVersion(entry);
164670
164967
  const parts = [
164671
164968
  ...pendingToolParts,
164672
- ...synthesizeUserParts(msg)
164969
+ ...attachPiPartVersion(synthesizeUserParts(msg), version2)
164673
164970
  ];
164674
164971
  pendingToolParts = [];
164675
164972
  pendingFirstRealId = "";
164973
+ pendingFirstRealVersion = "";
164676
164974
  result.push({
164677
164975
  ordinal: nextOrdinal++,
164678
164976
  id: entry.id,
164679
164977
  role: "user",
164680
- parts
164978
+ parts,
164979
+ version: version2
164681
164980
  });
164682
164981
  continue;
164683
164982
  }
@@ -164687,16 +164986,20 @@ function convertEntriesToRawMessages(entries) {
164687
164986
  ordinal: nextOrdinal++,
164688
164987
  id: `${SYNTH_USER_ID_PREFIX}${pendingFirstRealId}`,
164689
164988
  role: "user",
164690
- parts: pendingToolParts
164989
+ parts: pendingToolParts,
164990
+ version: pendingFirstRealVersion
164691
164991
  });
164692
164992
  pendingToolParts = [];
164693
164993
  pendingFirstRealId = "";
164994
+ pendingFirstRealVersion = "";
164694
164995
  }
164996
+ const version2 = rawEntryVersion(entry);
164695
164997
  result.push({
164696
164998
  ordinal: nextOrdinal++,
164697
164999
  id: entry.id,
164698
165000
  role: "assistant",
164699
- parts: synthesizeAssistantParts(msg)
165001
+ parts: attachPiPartVersion(synthesizeAssistantParts(msg), version2),
165002
+ version: version2
164700
165003
  });
164701
165004
  continue;
164702
165005
  }
@@ -164704,7 +165007,8 @@ function convertEntriesToRawMessages(entries) {
164704
165007
  ordinal: nextOrdinal++,
164705
165008
  id: entry.id,
164706
165009
  role: typeof role === "string" ? role : "unknown",
164707
- parts: []
165010
+ parts: [],
165011
+ version: rawEntryVersion(entry)
164708
165012
  });
164709
165013
  }
164710
165014
  if (pendingToolParts.length > 0) {
@@ -164712,7 +165016,8 @@ function convertEntriesToRawMessages(entries) {
164712
165016
  ordinal: nextOrdinal,
164713
165017
  id: `${SYNTH_USER_ID_PREFIX}${pendingFirstRealId}`,
164714
165018
  role: "user",
164715
- parts: pendingToolParts
165019
+ parts: pendingToolParts,
165020
+ version: pendingFirstRealVersion
164716
165021
  });
164717
165022
  }
164718
165023
  return result;
@@ -164869,6 +165174,13 @@ function createCtxExpandTool(deps) {
164869
165174
  }
164870
165175
 
164871
165176
  // ../plugin/src/features/magic-context/memory/constants.ts
165177
+ var V2_MEMORY_CATEGORIES = [
165178
+ "PROJECT_RULES",
165179
+ "ARCHITECTURE",
165180
+ "CONSTRAINTS",
165181
+ "CONFIG_VALUES",
165182
+ "NAMING"
165183
+ ];
164872
165184
  var PROMOTABLE_CATEGORIES = [
164873
165185
  "PROJECT_RULES",
164874
165186
  "ARCHITECTURE",
@@ -164908,6 +165220,7 @@ var CATEGORY_DEFAULT_TTL = {
164908
165220
  KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
164909
165221
  };
164910
165222
  // ../plugin/src/features/magic-context/memory/embedding-backfill.ts
165223
+ init_logger();
164911
165224
  async function ensureMemoryEmbeddings(args) {
164912
165225
  const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
164913
165226
  if (!snapshot?.enabled) {
@@ -164945,6 +165258,9 @@ async function ensureMemoryEmbeddings(args) {
164945
165258
  }
164946
165259
  return args.existingEmbeddings;
164947
165260
  }
165261
+ // ../plugin/src/features/magic-context/memory/promotion.ts
165262
+ init_logger();
165263
+
164948
165264
  // ../plugin/src/features/magic-context/memory/storage-memory.ts
164949
165265
  var COLUMN_MAP = {
164950
165266
  id: "id",
@@ -165856,6 +166172,7 @@ function getMaxMemoryMutationId(db, projectPath) {
165856
166172
  return row?.max_id ?? null;
165857
166173
  }
165858
166174
  // ../plugin/src/features/magic-context/storage-meta-persisted.ts
166175
+ init_logger();
165859
166176
  var CAS_RETRY_LIMIT = 5;
165860
166177
  var AUTO_SEARCH_NO_HINT_REASONS = new Set([
165861
166178
  "below-threshold",
@@ -165865,12 +166182,6 @@ var AUTO_SEARCH_NO_HINT_REASONS = new Set([
165865
166182
  "stacked",
165866
166183
  "too-short"
165867
166184
  ]);
165868
- function isPersistedStickyTurnReminderRow(row) {
165869
- if (row === null || typeof row !== "object")
165870
- return false;
165871
- const r = row;
165872
- return typeof r.sticky_turn_reminder_text === "string" && typeof r.sticky_turn_reminder_message_id === "string";
165873
- }
165874
166185
  function isPersistedNoteNudgeRow(row) {
165875
166186
  if (row === null || typeof row !== "object")
165876
166187
  return false;
@@ -165936,6 +166247,139 @@ function getDefaultHistorianFailureState() {
165936
166247
  lastFailureAt: null
165937
166248
  };
165938
166249
  }
166250
+ var DEFAULT_PROTECTED_TAIL_META = {
166251
+ priorBoundaryOrdinal: 1,
166252
+ protectedTailPolicyVersion: 0,
166253
+ protectedTailDrainWindowStartedAt: 0,
166254
+ protectedTailDrainTokens: 0,
166255
+ recoveryNoEligibleHeadCount: 0,
166256
+ forceEmergencyBypassWindowStart: 0,
166257
+ forceEmergencyBypassUsed: 0
166258
+ };
166259
+ function toProtectedTailMeta(row) {
166260
+ if (row === null || typeof row !== "object")
166261
+ return { ...DEFAULT_PROTECTED_TAIL_META };
166262
+ const r = row;
166263
+ const numberOr = (value, fallback) => typeof value === "number" && Number.isFinite(value) ? value : fallback;
166264
+ return {
166265
+ priorBoundaryOrdinal: Math.max(1, numberOr(r.prior_boundary_ordinal, 1)),
166266
+ protectedTailPolicyVersion: numberOr(r.protected_tail_policy_version, 0),
166267
+ protectedTailDrainWindowStartedAt: numberOr(r.protected_tail_drain_window_started_at, 0),
166268
+ protectedTailDrainTokens: numberOr(r.protected_tail_drain_tokens, 0),
166269
+ recoveryNoEligibleHeadCount: numberOr(r.recovery_no_eligible_head_count, 0),
166270
+ forceEmergencyBypassWindowStart: numberOr(r.force_emergency_bypass_window_start, 0),
166271
+ forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0)
166272
+ };
166273
+ }
166274
+ function loadProtectedTailMeta(db, sessionId) {
166275
+ ensureSessionMetaRow(db, sessionId);
166276
+ const row = db.prepare(`SELECT prior_boundary_ordinal, protected_tail_policy_version,
166277
+ protected_tail_drain_window_started_at, protected_tail_drain_tokens,
166278
+ recovery_no_eligible_head_count, force_emergency_bypass_window_start,
166279
+ force_emergency_bypass_used
166280
+ FROM session_meta WHERE session_id = ?`).get(sessionId);
166281
+ return toProtectedTailMeta(row);
166282
+ }
166283
+ function markProtectedTailPolicyV3Seeded(db, sessionId, priorBoundaryOrdinal) {
166284
+ let seeded = false;
166285
+ db.transaction(() => {
166286
+ ensureSessionMetaRow(db, sessionId);
166287
+ const existing = loadProtectedTailMeta(db, sessionId);
166288
+ if (existing.protectedTailPolicyVersion < 3) {
166289
+ db.prepare(`UPDATE session_meta
166290
+ SET prior_boundary_ordinal = ?, protected_tail_policy_version = 3
166291
+ WHERE session_id = ? AND protected_tail_policy_version < 3`).run(Math.max(1, Math.floor(priorBoundaryOrdinal)), sessionId);
166292
+ seeded = true;
166293
+ }
166294
+ })();
166295
+ return { ...loadProtectedTailMeta(db, sessionId), seeded };
166296
+ }
166297
+ function recordProtectedTailPublicationFloor(db, sessionId, floorOrdinal) {
166298
+ db.transaction(() => {
166299
+ ensureSessionMetaRow(db, sessionId);
166300
+ db.prepare(`UPDATE session_meta
166301
+ SET prior_boundary_ordinal = MAX(COALESCE(prior_boundary_ordinal, 1), ?),
166302
+ recovery_no_eligible_head_count = 0
166303
+ WHERE session_id = ?`).run(Math.max(1, Math.floor(floorOrdinal)), sessionId);
166304
+ })();
166305
+ }
166306
+ function recordProtectedTailNoEligibleHead(db, sessionId) {
166307
+ db.transaction(() => {
166308
+ ensureSessionMetaRow(db, sessionId);
166309
+ db.prepare(`UPDATE session_meta
166310
+ SET recovery_no_eligible_head_count = COALESCE(recovery_no_eligible_head_count, 0) + 1
166311
+ WHERE session_id = ?`).run(sessionId);
166312
+ })();
166313
+ return loadProtectedTailMeta(db, sessionId).recoveryNoEligibleHeadCount;
166314
+ }
166315
+ var DRAIN_WINDOW_MS = 10 * 60 * 1000;
166316
+ function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
166317
+ if (usagePercentage >= 95)
166318
+ return Math.min(1e6, Math.max(4 * perRunCap, Math.round(0.5 * usable)));
166319
+ if (usagePercentage >= 80)
166320
+ return Math.min(750000, Math.max(3 * perRunCap, Math.round(0.35 * usable)));
166321
+ return Math.min(500000, Math.max(perRunCap, Math.round(0.2 * usable)));
166322
+ }
166323
+ function reserveProtectedTailDrainTokens(args) {
166324
+ const now = args.now ?? Date.now();
166325
+ const requested = Math.max(0, Math.floor(args.trueRawTokens));
166326
+ if (requested === 0) {
166327
+ return { ok: true, reservedTokens: 0, overQuotaBypass: false, reservation: null };
166328
+ }
166329
+ let result = {
166330
+ ok: false,
166331
+ reservedTokens: 0,
166332
+ overQuotaBypass: false,
166333
+ reservation: null,
166334
+ skippedReason: "quota exhausted"
166335
+ };
166336
+ args.db.transaction(() => {
166337
+ ensureSessionMetaRow(args.db, args.sessionId);
166338
+ let meta3 = loadProtectedTailMeta(args.db, args.sessionId);
166339
+ if (now - meta3.protectedTailDrainWindowStartedAt > DRAIN_WINDOW_MS) {
166340
+ args.db.prepare(`UPDATE session_meta
166341
+ SET protected_tail_drain_window_started_at = ?, protected_tail_drain_tokens = 0,
166342
+ force_emergency_bypass_window_start = ?, force_emergency_bypass_used = 0
166343
+ WHERE session_id = ?`).run(now, now, args.sessionId);
166344
+ meta3 = loadProtectedTailMeta(args.db, args.sessionId);
166345
+ }
166346
+ const budget = protectedTailWindowBudget(args.usagePercentage, args.usable, args.perRunCap);
166347
+ const remaining = Math.max(0, budget - meta3.protectedTailDrainTokens);
166348
+ let reserved = Math.min(requested, args.perRunCap, remaining);
166349
+ let bypass = false;
166350
+ const bypassWindowExpired = now - meta3.forceEmergencyBypassWindowStart > DRAIN_WINDOW_MS;
166351
+ const bypassUsed = bypassWindowExpired ? 0 : meta3.forceEmergencyBypassUsed;
166352
+ if (reserved <= 0 && args.usagePercentage >= 95 && bypassUsed === 0) {
166353
+ reserved = Math.min(requested, args.perRunCap);
166354
+ bypass = true;
166355
+ }
166356
+ if (reserved <= 0)
166357
+ return;
166358
+ args.db.prepare(`UPDATE session_meta
166359
+ SET protected_tail_drain_window_started_at = CASE WHEN protected_tail_drain_window_started_at = 0 THEN ? ELSE protected_tail_drain_window_started_at END,
166360
+ protected_tail_drain_tokens = COALESCE(protected_tail_drain_tokens, 0) + ?,
166361
+ force_emergency_bypass_window_start = CASE WHEN ? THEN ? ELSE force_emergency_bypass_window_start END,
166362
+ force_emergency_bypass_used = CASE WHEN ? THEN 1 ELSE force_emergency_bypass_used END
166363
+ WHERE session_id = ?`).run(now, reserved, bypass ? 1 : 0, now, bypass ? 1 : 0, args.sessionId);
166364
+ result = {
166365
+ ok: true,
166366
+ reservedTokens: reserved,
166367
+ overQuotaBypass: bypass,
166368
+ reservation: { sessionId: args.sessionId, runId: args.runId, tokens: reserved }
166369
+ };
166370
+ })();
166371
+ return result;
166372
+ }
166373
+ function rollbackProtectedTailDrainReservation(db, reservation) {
166374
+ if (!reservation || reservation.tokens <= 0)
166375
+ return;
166376
+ db.transaction(() => {
166377
+ ensureSessionMetaRow(db, reservation.sessionId);
166378
+ db.prepare(`UPDATE session_meta
166379
+ SET protected_tail_drain_tokens = MAX(0, COALESCE(protected_tail_drain_tokens, 0) - ?)
166380
+ WHERE session_id = ?`).run(reservation.tokens, reservation.sessionId);
166381
+ })();
166382
+ }
165939
166383
  function setPersistedReasoningWatermark(db, sessionId, tagNumber) {
165940
166384
  ensureSessionMetaRow(db, sessionId);
165941
166385
  db.prepare("UPDATE session_meta SET cleared_reasoning_through_tag = ? WHERE session_id = ?").run(tagNumber, sessionId);
@@ -165943,27 +166387,95 @@ function setPersistedReasoningWatermark(db, sessionId, tagNumber) {
165943
166387
  function clearPersistedReasoningWatermark(db, sessionId) {
165944
166388
  setPersistedReasoningWatermark(db, sessionId, 0);
165945
166389
  }
165946
- function getPersistedStickyTurnReminder(db, sessionId) {
165947
- const result = db.prepare("SELECT sticky_turn_reminder_text, sticky_turn_reminder_message_id FROM session_meta WHERE session_id = ?").get(sessionId);
165948
- if (!isPersistedStickyTurnReminderRow(result)) {
165949
- return null;
165950
- }
165951
- if (result.sticky_turn_reminder_text.length === 0) {
165952
- return null;
165953
- }
165954
- return {
165955
- text: result.sticky_turn_reminder_text,
165956
- messageId: result.sticky_turn_reminder_message_id.length > 0 ? result.sticky_turn_reminder_message_id : null
165957
- };
166390
+ function isEmergencyInputSampleRow(row) {
166391
+ return typeof row === "object" && row !== null && typeof row.last_emergency_input_sample === "number";
166392
+ }
166393
+ function getEmergencyInputSample(db, sessionId) {
166394
+ const result = db.prepare("SELECT last_emergency_input_sample FROM session_meta WHERE session_id = ?").get(sessionId);
166395
+ return isEmergencyInputSampleRow(result) ? result.last_emergency_input_sample : 0;
166396
+ }
166397
+ function setEmergencyDropSample(db, sessionId, inputSample) {
166398
+ db.transaction(() => {
166399
+ ensureSessionMetaRow(db, sessionId);
166400
+ db.prepare("UPDATE session_meta SET last_emergency_input_sample = ? WHERE session_id = ?").run(Math.max(0, Math.round(inputSample)), sessionId);
166401
+ })();
166402
+ }
166403
+ function clearEmergencyDropSample(db, sessionId) {
166404
+ db.transaction(() => {
166405
+ ensureSessionMetaRow(db, sessionId);
166406
+ db.prepare("UPDATE session_meta SET last_emergency_input_sample = 0 WHERE session_id = ?").run(sessionId);
166407
+ })();
166408
+ }
166409
+ function isLastNudgeUndroppedRow(row) {
166410
+ return typeof row === "object" && row !== null && typeof row.last_nudge_undropped === "number";
166411
+ }
166412
+ function isLastNudgeLevelRow(row) {
166413
+ return typeof row === "object" && row !== null && typeof row.last_nudge_level === "string";
166414
+ }
166415
+ function normalizeLastNudgeLevel(value) {
166416
+ return value === "gentle" || value === "firm" || value === "urgent" ? value : "";
166417
+ }
166418
+ function getLastNudgeUndropped(db, sessionId) {
166419
+ const result = db.prepare("SELECT last_nudge_undropped FROM session_meta WHERE session_id = ?").get(sessionId);
166420
+ return isLastNudgeUndroppedRow(result) ? result.last_nudge_undropped : 0;
166421
+ }
166422
+ function setLastNudgeUndropped(db, sessionId, value) {
166423
+ db.transaction(() => {
166424
+ ensureSessionMetaRow(db, sessionId);
166425
+ db.prepare("UPDATE session_meta SET last_nudge_undropped = ? WHERE session_id = ?").run(Math.max(0, Math.round(value)), sessionId);
166426
+ })();
166427
+ }
166428
+ function getLastNudgeLevel(db, sessionId) {
166429
+ const result = db.prepare("SELECT last_nudge_level FROM session_meta WHERE session_id = ?").get(sessionId);
166430
+ return isLastNudgeLevelRow(result) ? normalizeLastNudgeLevel(result.last_nudge_level) : "";
165958
166431
  }
165959
- function setPersistedStickyTurnReminder(db, sessionId, text, messageId = "") {
166432
+ function setLastNudgeLevel(db, sessionId, value) {
165960
166433
  db.transaction(() => {
165961
166434
  ensureSessionMetaRow(db, sessionId);
165962
- db.prepare("UPDATE session_meta SET sticky_turn_reminder_text = ?, sticky_turn_reminder_message_id = ? WHERE session_id = ?").run(text, messageId, sessionId);
166435
+ db.prepare("UPDATE session_meta SET last_nudge_level = ? WHERE session_id = ?").run(normalizeLastNudgeLevel(value), sessionId);
165963
166436
  })();
165964
166437
  }
165965
- function clearPersistedStickyTurnReminder(db, sessionId) {
165966
- db.prepare("UPDATE session_meta SET sticky_turn_reminder_text = '', sticky_turn_reminder_message_id = '' WHERE session_id = ?").run(sessionId);
166438
+ function resetLastNudgeCycle(db, sessionId) {
166439
+ db.transaction(() => {
166440
+ ensureSessionMetaRow(db, sessionId);
166441
+ db.prepare("UPDATE session_meta SET last_nudge_undropped = 0, last_nudge_level = '' WHERE session_id = ?").run(sessionId);
166442
+ })();
166443
+ }
166444
+ function resetLastNudgeCycleIfTailShrank(db, sessionId, measuredUndropped) {
166445
+ let changed = false;
166446
+ db.transaction(() => {
166447
+ ensureSessionMetaRow(db, sessionId);
166448
+ const result = db.prepare("UPDATE session_meta SET last_nudge_undropped = 0, last_nudge_level = '' WHERE session_id = ? AND last_nudge_undropped > ?").run(sessionId, Math.max(0, Math.round(measuredUndropped)));
166449
+ changed = (result.changes ?? 0) > 0;
166450
+ })();
166451
+ return changed;
166452
+ }
166453
+ function isChannel2StateRow(row) {
166454
+ return typeof row === "object" && row !== null && typeof row.channel2_nudge_state === "string";
166455
+ }
166456
+ function getChannel2NudgeState(db, sessionId) {
166457
+ const result = db.prepare("SELECT channel2_nudge_state FROM session_meta WHERE session_id = ?").get(sessionId);
166458
+ if (!isChannel2StateRow(result))
166459
+ return "";
166460
+ const raw = result.channel2_nudge_state;
166461
+ return raw === "pending" || raw === "claimed" || raw === "delivered" ? raw : "";
166462
+ }
166463
+ function setChannel2NudgeState(db, sessionId, state) {
166464
+ db.transaction(() => {
166465
+ ensureSessionMetaRow(db, sessionId);
166466
+ const claimedAt = state === "claimed" ? Date.now() : 0;
166467
+ db.prepare("UPDATE session_meta SET channel2_nudge_state = ?, channel2_nudge_claimed_at = ? WHERE session_id = ?").run(state, claimedAt, sessionId);
166468
+ })();
166469
+ }
166470
+ function casChannel2NudgeState(db, sessionId, from, to) {
166471
+ let changed = false;
166472
+ db.transaction(() => {
166473
+ ensureSessionMetaRow(db, sessionId);
166474
+ const claimedAt = to === "claimed" ? Date.now() : 0;
166475
+ const result = db.prepare("UPDATE session_meta SET channel2_nudge_state = ?, channel2_nudge_claimed_at = ? WHERE session_id = ? AND channel2_nudge_state = ?").run(to, claimedAt, sessionId, from);
166476
+ changed = (result.changes ?? 0) > 0;
166477
+ })();
166478
+ return changed;
165967
166479
  }
165968
166480
  function getPersistedNoteNudge(db, sessionId) {
165969
166481
  const result = db.prepare("SELECT note_nudge_trigger_pending, note_nudge_trigger_message_id, note_nudge_sticky_text, note_nudge_sticky_message_id FROM session_meta WHERE session_id = ?").get(sessionId);
@@ -166187,7 +166699,11 @@ function recordOverflowDetected(db, sessionId, reportedLimit) {
166187
166699
  function clearEmergencyRecovery(db, sessionId) {
166188
166700
  db.transaction(() => {
166189
166701
  ensureSessionMetaRow(db, sessionId);
166190
- db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0 WHERE session_id = ?").run(sessionId);
166702
+ try {
166703
+ db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0, recovery_no_eligible_head_count = 0 WHERE session_id = ?").run(sessionId);
166704
+ } catch {
166705
+ db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0 WHERE session_id = ?").run(sessionId);
166706
+ }
166191
166707
  })();
166192
166708
  }
166193
166709
  function clearDetectedContextLimit(db, sessionId) {
@@ -166350,6 +166866,7 @@ function setSessionWorkMetrics(db, sessionId, newWorkTokens, totalInputTokens) {
166350
166866
  import { Buffer as Buffer3 } from "node:buffer";
166351
166867
 
166352
166868
  // ../plugin/src/features/magic-context/resolve-subagent-fallback.ts
166869
+ init_logger();
166353
166870
  function resolveIsSubagentFromOpenCodeDb(sessionId) {
166354
166871
  try {
166355
166872
  return withReadOnlySessionDb((openCodeDb) => {
@@ -166568,7 +167085,8 @@ function updateNote(db, noteId, updates, scope) {
166568
167085
  sets.push("session_id = ?");
166569
167086
  params.push(updates.sessionId);
166570
167087
  }
166571
- if (updates.status !== undefined) {
167088
+ const smartConditionChanged = existing.type === "smart" && updates.surfaceCondition !== undefined && updates.surfaceCondition !== existing.surfaceCondition;
167089
+ if (updates.status !== undefined && !smartConditionChanged) {
166572
167090
  sets.push("status = ?");
166573
167091
  params.push(updates.status);
166574
167092
  }
@@ -166581,17 +167099,21 @@ function updateNote(db, noteId, updates, scope) {
166581
167099
  sets.push("surface_condition = ?");
166582
167100
  params.push(updates.surfaceCondition);
166583
167101
  }
166584
- if (updates.lastCheckedAt !== undefined) {
166585
- sets.push("last_checked_at = ?");
166586
- params.push(updates.lastCheckedAt);
166587
- }
166588
- if (updates.readyAt !== undefined) {
166589
- sets.push("ready_at = ?");
166590
- params.push(updates.readyAt);
166591
- }
166592
- if (updates.readyReason !== undefined) {
166593
- sets.push("ready_reason = ?");
166594
- params.push(updates.readyReason);
167102
+ if (smartConditionChanged) {
167103
+ sets.push("status = 'pending'", "last_checked_at = NULL", "ready_at = NULL", "ready_reason = NULL");
167104
+ } else {
167105
+ if (updates.lastCheckedAt !== undefined) {
167106
+ sets.push("last_checked_at = ?");
167107
+ params.push(updates.lastCheckedAt);
167108
+ }
167109
+ if (updates.readyAt !== undefined) {
167110
+ sets.push("ready_at = ?");
167111
+ params.push(updates.readyAt);
167112
+ }
167113
+ if (updates.readyReason !== undefined) {
167114
+ sets.push("ready_reason = ?");
167115
+ params.push(updates.readyReason);
167116
+ }
166595
167117
  }
166596
167118
  }
166597
167119
  if (sets.length === 1) {
@@ -166618,6 +167140,7 @@ function markNoteChecked(db, noteId) {
166618
167140
  db.prepare("UPDATE notes SET last_checked_at = ?, updated_at = ? WHERE id = ? AND type = 'smart'").run(now, now, noteId);
166619
167141
  }
166620
167142
  // ../plugin/src/features/magic-context/storage-ops.ts
167143
+ init_logger();
166621
167144
  var queuePendingOpStatements = new WeakMap;
166622
167145
  var getPendingOpsStatements = new WeakMap;
166623
167146
  var clearPendingOpsStatements = new WeakMap;
@@ -166780,7 +167303,7 @@ var getTagNumberByMessageIdStatements = new WeakMap;
166780
167303
  function getInsertTagStatement(db) {
166781
167304
  let stmt = insertTagStatements.get(db);
166782
167305
  if (!stmt) {
166783
- stmt = db.prepare("INSERT INTO tags (session_id, message_id, type, byte_size, reasoning_byte_size, tag_number, tool_name, input_byte_size, harness, tool_owner_message_id, entry_fingerprint) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
167306
+ stmt = db.prepare("INSERT INTO tags (session_id, message_id, type, byte_size, reasoning_byte_size, tag_number, tool_name, input_byte_size, harness, tool_owner_message_id, entry_fingerprint, token_count, input_token_count, reasoning_token_count) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
166784
167307
  insertTagStatements.set(db, stmt);
166785
167308
  }
166786
167309
  return stmt;
@@ -166822,9 +167345,95 @@ function getUpdateTagInputByteSizeStatement(db) {
166822
167345
  function updateTagByteSize(db, sessionId, tagNumber, newByteSize) {
166823
167346
  getUpdateTagByteSizeStatement(db).run(newByteSize, sessionId, tagNumber);
166824
167347
  }
167348
+ var CONTENT_ID_SUFFIX = /:(?:p|file)\d+$/;
167349
+ function ownerMessageIdForTagRow(row) {
167350
+ if (row.type === "tool") {
167351
+ return row.tool_owner_message_id ?? row.message_id;
167352
+ }
167353
+ return row.message_id.replace(CONTENT_ID_SUFFIX, "");
167354
+ }
167355
+ function getActiveTagTokenAggregate(db, sessionId) {
167356
+ const row = db.prepare(`SELECT
167357
+ COALESCE(SUM(CASE WHEN type != 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0)
167358
+ + COALESCE(SUM(COALESCE(reasoning_token_count, 0)), 0) AS conversation,
167359
+ COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) + COALESCE(input_token_count, 0) ELSE 0 END), 0) AS tool_call,
167360
+ COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0) AS tool_output,
167361
+ COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
167362
+ FROM tags
167363
+ WHERE session_id = ? AND status = 'active'`).get(sessionId);
167364
+ return {
167365
+ conversation: row?.conversation ?? 0,
167366
+ toolCall: row?.tool_call ?? 0,
167367
+ toolOutput: row?.tool_output ?? 0,
167368
+ nullCount: row?.null_count ?? 0
167369
+ };
167370
+ }
167371
+ function getTriggerTagTokenUpperBound(db, sessionId) {
167372
+ const row = db.prepare(`SELECT
167373
+ COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
167374
+ COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
167375
+ FROM tags
167376
+ WHERE session_id = ? AND status IN ('active', 'dropped')`).get(sessionId);
167377
+ return { bound: row?.bound ?? 0, nullCount: row?.null_count ?? 0 };
167378
+ }
166825
167379
  function updateTagInputByteSize(db, sessionId, tagNumber, newInputByteSize) {
166826
167380
  getUpdateTagInputByteSizeStatement(db).run(newInputByteSize, sessionId, tagNumber);
166827
167381
  }
167382
+ var updateTagTokenCountStatements = new WeakMap;
167383
+ var updateTagInputTokenCountStatements = new WeakMap;
167384
+ function getUpdateTagTokenCountStatement(db) {
167385
+ let stmt = updateTagTokenCountStatements.get(db);
167386
+ if (!stmt) {
167387
+ stmt = db.prepare("UPDATE tags SET token_count = ? WHERE session_id = ? AND tag_number = ?");
167388
+ updateTagTokenCountStatements.set(db, stmt);
167389
+ }
167390
+ return stmt;
167391
+ }
167392
+ function getUpdateTagInputTokenCountStatement(db) {
167393
+ let stmt = updateTagInputTokenCountStatements.get(db);
167394
+ if (!stmt) {
167395
+ stmt = db.prepare("UPDATE tags SET input_token_count = ? WHERE session_id = ? AND tag_number = ?");
167396
+ updateTagInputTokenCountStatements.set(db, stmt);
167397
+ }
167398
+ return stmt;
167399
+ }
167400
+ function updateTagTokenCount(db, sessionId, tagNumber, newTokenCount) {
167401
+ getUpdateTagTokenCountStatement(db).run(newTokenCount, sessionId, tagNumber);
167402
+ }
167403
+ function getAllStatusTagTokenTotalsFlat(db, sessionId) {
167404
+ const rows = db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
167405
+ FROM tags
167406
+ WHERE session_id = ?`).all(sessionId);
167407
+ const totals = new Map;
167408
+ const nullMessageIds = new Set;
167409
+ for (const row of rows) {
167410
+ if (row.type === "tool" && row.tool_owner_message_id === null)
167411
+ continue;
167412
+ const owner = ownerMessageIdForTagRow(row);
167413
+ if (row.token_count === null) {
167414
+ nullMessageIds.add(owner);
167415
+ totals.delete(owner);
167416
+ continue;
167417
+ }
167418
+ if (nullMessageIds.has(owner))
167419
+ continue;
167420
+ const weight = (row.token_count ?? 0) + (row.input_token_count ?? 0) + (row.reasoning_token_count ?? 0);
167421
+ totals.set(owner, (totals.get(owner) ?? 0) + weight);
167422
+ }
167423
+ return { totals, nullMessageIds };
167424
+ }
167425
+ function updateTagInputTokenCount(db, sessionId, tagNumber, newInputTokenCount) {
167426
+ getUpdateTagInputTokenCountStatement(db).run(newInputTokenCount, sessionId, tagNumber);
167427
+ }
167428
+ function tagTokenCountIsNull(db, sessionId, tagNumber) {
167429
+ const row = db.prepare("SELECT token_count FROM tags WHERE session_id = ? AND tag_number = ?").get(sessionId, tagNumber);
167430
+ return row !== undefined && row.token_count === null;
167431
+ }
167432
+ function backfillTagTokenCounts(db, sessionId, tagNumber, counts) {
167433
+ db.prepare(`UPDATE tags
167434
+ SET token_count = ?, input_token_count = ?, reasoning_token_count = ?
167435
+ WHERE session_id = ? AND tag_number = ? AND token_count IS NULL`).run(counts.tokenCount ?? null, counts.inputTokenCount ?? null, counts.reasoningTokenCount ?? null, sessionId, tagNumber);
167436
+ }
166828
167437
  function getMaxTagNumberBySessionStatement(db) {
166829
167438
  let stmt = getMaxTagNumberBySessionStatements.get(db);
166830
167439
  if (!stmt) {
@@ -166877,8 +167486,8 @@ function isMaxTagNumberRow(row) {
166877
167486
  const r = row;
166878
167487
  return typeof r.max_tag_number === "number";
166879
167488
  }
166880
- function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0, toolOwnerMessageId = null, entryFingerprint = null) {
166881
- getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness(), toolOwnerMessageId, entryFingerprint);
167489
+ function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0, toolOwnerMessageId = null, entryFingerprint = null, tokenCounts = null) {
167490
+ getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness(), toolOwnerMessageId, entryFingerprint, tokenCounts?.tokenCount ?? null, tokenCounts?.inputTokenCount ?? null, tokenCounts?.reasoningTokenCount ?? null);
166882
167491
  return tagNumber;
166883
167492
  }
166884
167493
  function updateTagStatus(db, sessionId, tagId, status) {
@@ -166946,13 +167555,6 @@ function getTagsByNumbers(db, sessionId, tagNumbers) {
166946
167555
  const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${placeholders}) ORDER BY tag_number ASC, id ASC`).all(sessionId, ...tagNumbers).filter(isTagRow);
166947
167556
  return rows.map(toTagEntry);
166948
167557
  }
166949
- function getTopNBySize(db, sessionId, n) {
166950
- if (n <= 0) {
166951
- return [];
166952
- }
166953
- const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND status = 'active' ORDER BY byte_size DESC, tag_number ASC LIMIT ?`).all(sessionId, n).filter(isTagRow);
166954
- return rows.map(toTagEntry);
166955
- }
166956
167558
  var getToolTagNumberByOwnerStatements = new WeakMap;
166957
167559
  var getNullOwnerToolTagStatements = new WeakMap;
166958
167560
  var adoptNullOwnerToolTagStatements = new WeakMap;
@@ -167018,44 +167620,43 @@ var ERROR_CLASSES = new Set([
167018
167620
  "permission_denied",
167019
167621
  "unknown"
167020
167622
  ]);
167623
+ // src/tools/ctx-memory.ts
167624
+ init_logger();
167625
+
167626
+ // ../plugin/src/tools/ctx-memory/constants.ts
167627
+ var CTX_MEMORY_DESCRIPTION = `Durable project knowledge shared across every session on this project.
167628
+
167629
+ Your active memories are already visible in <project-memory> (each with its id), and every future session starts with them — write one when you learn something future sessions must know: a project rule, an architectural fact, a hard-won constraint, a config value, or a naming convention. Keep each memory one standalone fact, phrased to make sense without this session's context.
167630
+
167631
+ Actions:
167632
+ - write: save a new memory (content + category).
167633
+ - update: rewrite one memory whose fact changed (ids: [one], content).
167634
+ - archive: retire wrong or obsolete memories (ids: [one or more], optional reason).
167635
+ - merge: collapse duplicates into one memory (ids: [two or more], content).
167636
+
167637
+ Example: ctx_memory(action="write", category="CONSTRAINTS", content="Pi stores sessions as JSONL under ~/.pi/agent/sessions/, not SQLite")`;
167638
+
167021
167639
  // src/tools/ctx-memory.ts
167022
167640
  var DEFAULT_LIST_LIMIT = 10;
167023
- var VALID_CATEGORIES = new Set(CATEGORY_PRIORITY);
167024
- function isMemoryCategory2(value) {
167025
- return VALID_CATEGORIES.has(value);
167026
- }
167027
- var ALL_ACTIONS = [
167028
- "write",
167029
- "delete",
167030
- "list",
167031
- "update",
167032
- "merge",
167033
- "archive"
167034
- ];
167035
- var DREAMER_ONLY_ACTIONS = new Set([
167036
- "list",
167037
- "update",
167038
- "merge",
167039
- "archive"
167040
- ]);
167641
+ var ALL_ACTIONS = ["write", "archive", "update", "merge", "list"];
167642
+ var DREAMER_ONLY_ACTIONS = new Set(["list"]);
167041
167643
  var ParamsSchema2 = exports_typebox.Object({
167042
- action: exports_typebox.Union(ALL_ACTIONS.map((a) => exports_typebox.Literal(a)), { description: "Action to perform on memories" }),
167644
+ action: exports_typebox.Union(ALL_ACTIONS.map((a) => exports_typebox.Literal(a)), { description: "What to do: write, update, archive, or merge" }),
167043
167645
  content: exports_typebox.Optional(exports_typebox.String({
167044
- description: "Memory content (required for write, update, merge)"
167045
- })),
167046
- category: exports_typebox.Optional(exports_typebox.String({
167047
- description: "Memory category (required for write, optional filter for list, optional override for merge). One of: " + CATEGORY_PRIORITY.join(", ")
167646
+ description: "The memory text — one standalone fact (required for write, update, merge)"
167048
167647
  })),
167049
- id: exports_typebox.Optional(exports_typebox.Number({
167050
- description: "Memory ID (required for delete, update, archive)"
167648
+ category: exports_typebox.Optional(exports_typebox.Union(V2_MEMORY_CATEGORIES.map((c) => exports_typebox.Literal(c)), {
167649
+ description: "What kind of fact this is (required for write; optional merge override)"
167051
167650
  })),
167052
167651
  ids: exports_typebox.Optional(exports_typebox.Array(exports_typebox.Number(), {
167053
- description: "Memory IDs to merge (required for merge)"
167652
+ description: "Target memory id(s) from <project-memory>: update takes exactly one, archive one or more, merge two or more"
167054
167653
  })),
167055
167654
  limit: exports_typebox.Optional(exports_typebox.Number({
167056
- description: "Maximum results to return for list (default: 10)"
167655
+ description: "Max results for list (default: 10)"
167057
167656
  })),
167058
- reason: exports_typebox.Optional(exports_typebox.String({ description: "Archive reason (optional for archive)" }))
167657
+ reason: exports_typebox.Optional(exports_typebox.String({
167658
+ description: "Why the memory is being archived (optional, recommended)"
167659
+ }))
167059
167660
  });
167060
167661
  function ok2(text) {
167061
167662
  return { content: [{ type: "text", text }], details: undefined };
@@ -167102,6 +167703,12 @@ function formatMemoryList(memories) {
167102
167703
  ].join(`
167103
167704
  `);
167104
167705
  }
167706
+ function isPrimaryMutableMemory(memory2) {
167707
+ return (memory2.status === "active" || memory2.status === "permanent") && memory2.supersededByMemoryId === null;
167708
+ }
167709
+ function inactiveMemoryError(id, action2) {
167710
+ return `Error: Memory with ID ${id} is archived or superseded; restore it before ${action2}.`;
167711
+ }
167105
167712
  function queueEmbedding(args) {
167106
167713
  const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
167107
167714
  if (!snapshot?.enabled)
@@ -167122,7 +167729,8 @@ function queueEmbedding(args) {
167122
167729
  }
167123
167730
  function createCtxMemoryTool(deps) {
167124
167731
  const dreamerAllowed = deps.allowDreamerActions === true;
167125
- const description = dreamerAllowed ? "Manage cross-session project memories. Memories persist across sessions and are " + "shared with OpenCode sessions on the same project. " + "Supported actions: write, delete, list, update, merge, archive." : "Manage cross-session project memories. Memories persist across sessions and are " + "shared with OpenCode sessions on the same project. " + "Supported actions: write, delete.";
167732
+ const description = dreamerAllowed ? `${CTX_MEMORY_DESCRIPTION}
167733
+ - list: enumerate stored memories (maintenance sessions).` : CTX_MEMORY_DESCRIPTION;
167126
167734
  return {
167127
167735
  name: "ctx_memory",
167128
167736
  label: "Magic Context: Memory",
@@ -167143,13 +167751,10 @@ function createCtxMemoryTool(deps) {
167143
167751
  const content = params.content?.trim();
167144
167752
  if (!content)
167145
167753
  return err2("Error: 'content' is required when action is 'write'.");
167146
- const rawCategory = params.category?.trim();
167754
+ const rawCategory = params.category;
167147
167755
  if (!rawCategory) {
167148
167756
  return err2("Error: 'category' is required when action is 'write'.");
167149
167757
  }
167150
- if (!isMemoryCategory2(rawCategory)) {
167151
- return err2(`Error: Unknown memory category '${rawCategory}'. Valid: ${CATEGORY_PRIORITY.join(", ")}`);
167152
- }
167153
167758
  const existing = getMemoryByHash(deps.db, projectIdentity, rawCategory, computeNormalizedHash(content));
167154
167759
  if (existing) {
167155
167760
  updateMemorySeenCount(deps.db, existing.id);
@@ -167165,42 +167770,29 @@ function createCtxMemoryTool(deps) {
167165
167770
  queueEmbedding({ deps, projectIdentity, memoryId: memory2.id, content });
167166
167771
  return ok2(`Saved memory [ID: ${memory2.id}] in ${rawCategory}.`);
167167
167772
  }
167168
- if (params.action === "delete") {
167169
- if (typeof params.id !== "number" || !Number.isInteger(params.id)) {
167170
- return err2("Error: 'id' is required when action is 'delete'.");
167171
- }
167172
- const memory2 = getMemoryById(deps.db, params.id);
167173
- if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
167174
- return err2(`Error: Memory with ID ${params.id} was not found.`);
167175
- }
167176
- deps.db.transaction(() => {
167177
- archiveMemory(deps.db, params.id);
167178
- queueMemoryMutation(deps.db, {
167179
- projectPath: projectIdentity,
167180
- mutationType: "delete",
167181
- targetMemoryId: params.id
167182
- });
167183
- })();
167184
- return ok2(`Archived memory [ID: ${params.id}].`);
167185
- }
167186
167773
  if (params.action === "list") {
167187
167774
  const limit = normalizeLimit(params.limit);
167188
167775
  const filtered = getMemoriesByProject(deps.db, projectIdentity);
167189
- const category = params.category?.trim();
167776
+ const category = params.category;
167190
167777
  const filtered2 = category ? filtered.filter((m) => m.category === category) : filtered;
167191
167778
  return ok2(formatMemoryList(filtered2.slice(0, limit)));
167192
167779
  }
167193
167780
  if (params.action === "update") {
167194
- if (typeof params.id !== "number" || !Number.isInteger(params.id)) {
167195
- return err2("Error: 'id' is required when action is 'update'.");
167781
+ const updateIds = params.ids;
167782
+ if (!updateIds || updateIds.length !== 1 || !updateIds.every(Number.isInteger)) {
167783
+ return err2("Error: 'ids' must contain exactly one integer memory ID when action is 'update'.");
167196
167784
  }
167785
+ const updateId = updateIds[0];
167197
167786
  const content = params.content?.trim();
167198
167787
  if (!content) {
167199
167788
  return err2("Error: 'content' is required when action is 'update'.");
167200
167789
  }
167201
- const memory2 = getMemoryById(deps.db, params.id);
167790
+ const memory2 = getMemoryById(deps.db, updateId);
167202
167791
  if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
167203
- return err2(`Error: Memory with ID ${params.id} was not found.`);
167792
+ return err2(`Error: Memory with ID ${updateId} was not found.`);
167793
+ }
167794
+ if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
167795
+ return err2(inactiveMemoryError(updateId, "updating"));
167204
167796
  }
167205
167797
  const normalizedHash = computeNormalizedHash(content);
167206
167798
  const duplicate = getMemoryByHash(deps.db, projectIdentity, memory2.category, normalizedHash);
@@ -167221,9 +167813,12 @@ function createCtxMemoryTool(deps) {
167221
167813
  return ok2(`Updated memory [ID: ${memory2.id}] in ${memory2.category}.`);
167222
167814
  }
167223
167815
  if (params.action === "merge") {
167224
- const ids = params.ids?.filter((id) => Number.isInteger(id));
167225
- if (!ids || ids.length < 2) {
167226
- return err2("Error: 'ids' must include at least two memory IDs when action is 'merge'.");
167816
+ const ids = params.ids;
167817
+ if (!ids || ids.length < 2 || !ids.every(Number.isInteger)) {
167818
+ return err2("Error: 'ids' must include at least two integer memory IDs when action is 'merge'.");
167819
+ }
167820
+ if (new Set(ids).size !== ids.length) {
167821
+ return err2("Error: 'ids' must include at least two distinct memory IDs when action is 'merge'.");
167227
167822
  }
167228
167823
  const content = params.content?.trim();
167229
167824
  if (!content) {
@@ -167233,11 +167828,17 @@ function createCtxMemoryTool(deps) {
167233
167828
  if (sourceMemories.length !== ids.length) {
167234
167829
  return err2("Error: One or more source memories were not found.");
167235
167830
  }
167236
- const requestedCategory = params.category?.trim();
167237
- if (requestedCategory && !isMemoryCategory2(requestedCategory)) {
167238
- return err2(`Error: Unknown memory category '${requestedCategory}'. Valid: ${CATEGORY_PRIORITY.join(", ")}`);
167831
+ if (!dreamerAllowed) {
167832
+ const foreign = sourceMemories.find((memory2) => !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity));
167833
+ if (foreign) {
167834
+ return err2(`Error: Memory with ID ${foreign.id} was not found.`);
167835
+ }
167836
+ const inactive = sourceMemories.find((memory2) => !isPrimaryMutableMemory(memory2));
167837
+ if (inactive) {
167838
+ return err2(inactiveMemoryError(inactive.id, "merging"));
167839
+ }
167239
167840
  }
167240
- const requestedCategoryTyped = requestedCategory && isMemoryCategory2(requestedCategory) ? requestedCategory : undefined;
167841
+ const requestedCategoryTyped = params.category;
167241
167842
  const fallbackCategory = sourceMemories[0]?.category;
167242
167843
  const category = requestedCategoryTyped ?? fallbackCategory;
167243
167844
  if (!category) {
@@ -167317,29 +167918,57 @@ function createCtxMemoryTool(deps) {
167317
167918
  return ok2(`Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`);
167318
167919
  }
167319
167920
  if (params.action === "archive") {
167320
- if (typeof params.id !== "number" || !Number.isInteger(params.id)) {
167321
- return err2("Error: 'id' is required when action is 'archive'.");
167921
+ const archiveIds = params.ids;
167922
+ if (!archiveIds || archiveIds.length === 0 || !archiveIds.every(Number.isInteger)) {
167923
+ return err2("Error: 'ids' must contain at least one integer memory ID when action is 'archive'.");
167322
167924
  }
167323
- const memory2 = getMemoryById(deps.db, params.id);
167324
- if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
167325
- return err2(`Error: Memory with ID ${params.id} was not found.`);
167925
+ for (const memoryId of archiveIds) {
167926
+ const memory2 = getMemoryById(deps.db, memoryId);
167927
+ if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
167928
+ return err2(`Error: Memory with ID ${memoryId} was not found.`);
167929
+ }
167930
+ if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
167931
+ return err2(inactiveMemoryError(memoryId, "archiving"));
167932
+ }
167326
167933
  }
167327
167934
  deps.db.transaction(() => {
167328
- archiveMemory(deps.db, params.id, params.reason);
167329
- queueMemoryMutation(deps.db, {
167330
- projectPath: projectIdentity,
167331
- mutationType: "archive",
167332
- targetMemoryId: params.id
167333
- });
167935
+ for (const memoryId of archiveIds) {
167936
+ archiveMemory(deps.db, memoryId, params.reason);
167937
+ queueMemoryMutation(deps.db, {
167938
+ projectPath: projectIdentity,
167939
+ mutationType: "archive",
167940
+ targetMemoryId: memoryId
167941
+ });
167942
+ }
167334
167943
  })();
167335
167944
  const reasonSuffix = params.reason ? ` (${params.reason})` : "";
167336
- return ok2(`Archived memory [ID: ${params.id}]${reasonSuffix}.`);
167945
+ const idList = archiveIds.join(", ");
167946
+ const plural = archiveIds.length > 1 ? "memories" : "memory";
167947
+ return ok2(`Archived ${plural} [ID: ${idList}]${reasonSuffix}.`);
167337
167948
  }
167338
167949
  return err2("Error: Unknown action.");
167339
167950
  }
167340
167951
  };
167341
167952
  }
167342
167953
 
167954
+ // ../plugin/src/tools/ctx-note/constants.ts
167955
+ var CTX_NOTE_DESCRIPTION = `Working notes for this session's future — reminders, follow-ups, and things to revisit later.
167956
+
167957
+ Use a note when something matters LATER but not in the next few steps: "revisit the retry logic after the release", "user wants the dashboard polish batched", "flaky test to investigate when touching CI". Don't use notes for active multi-step work (use todos) or for durable project knowledge that should outlive this session (use ctx_memory). Notes resurface automatically at natural work boundaries and whenever you read them.
167958
+
167959
+ Actions:
167960
+ - write: save a note (content). Add surface_condition to make it a smart note (below).
167961
+ - read: list notes, newest first. Default: latest active session notes + ready smart notes; page older ones with limit/offset, or inspect other states with filter.
167962
+ - update / dismiss: change or retire a note by note_id.
167963
+
167964
+ Smart notes: pass surface_condition and the note stays hidden until a background checker confirms the condition — using ONLY externally verifiable signals (GitHub state via gh, files on disk, git history, web pages). It cannot see this conversation, so the condition must be checkable from outside:
167965
+ ✓ "When PR #42 in cortexkit/magic-context is merged"
167966
+ ✓ "When the latest release tag is >= v0.22.0"
167967
+ ✓ "When packages/plugin/src/foo.ts contains a function named bar"
167968
+ ✗ "When the user mentions X" / "when we revisit Y" / "after we finish this refactor" — no external signal; write a regular note instead.
167969
+
167970
+ Example: ctx_note(action="write", content="Re-run the perf benchmark once the boundary rework ships", surface_condition="When the latest release tag is >= v0.23.0")`;
167971
+
167343
167972
  // src/tools/ctx-note.ts
167344
167973
  var FILTER_VALUES = [
167345
167974
  "active",
@@ -167359,13 +167988,19 @@ var ParamsSchema3 = exports_typebox.Object({
167359
167988
  })),
167360
167989
  content: exports_typebox.Optional(exports_typebox.String({ description: "Note text to store when action is 'write'." })),
167361
167990
  surface_condition: exports_typebox.Optional(exports_typebox.String({
167362
- description: "Open-ended condition for smart notes. When provided, creates a project-scoped smart note that the dreamer evaluates nightly. The note surfaces when the condition is met."
167991
+ description: "Externally verifiable condition for smart notes. A background checker verifies it using ONLY outside signals (GitHub state via gh, files on disk, git history, web) — it cannot see this conversation. Use for PR/issue state, release tags, file contents, workflow runs. NOT for 'when the user mentions X' / 'when we revisit Y' — write a regular note instead."
167363
167992
  })),
167364
167993
  note_id: exports_typebox.Optional(exports_typebox.Number({
167365
167994
  description: "Note ID (required for 'dismiss' and 'update' actions)."
167366
167995
  })),
167367
167996
  filter: exports_typebox.Optional(exports_typebox.Union(FILTER_VALUES.map((value) => exports_typebox.Literal(value)), {
167368
167997
  description: "Optional read filter. Defaults to active session notes + ready smart notes. Use 'all' to inspect every status or 'pending' to inspect unsurfaced smart notes."
167998
+ })),
167999
+ limit: exports_typebox.Optional(exports_typebox.Number({
168000
+ description: "Max notes per section for read, newest first (default: 25)"
168001
+ })),
168002
+ offset: exports_typebox.Optional(exports_typebox.Number({
168003
+ description: "Skip this many newest notes for read — page older ones (default: 0)"
167369
168004
  }))
167370
168005
  });
167371
168006
  function ok3(text) {
@@ -167402,15 +168037,20 @@ function formatNoteLine(note) {
167402
168037
  var DISMISS_FOOTER = `
167403
168038
 
167404
168039
  To dismiss a stale note: ctx_note(action="dismiss", note_id=N)`;
168040
+ var DEFAULT_READ_LIMIT = 25;
168041
+ function paginateNewestFirst(notes, limit, offset) {
168042
+ const total = notes.length;
168043
+ const newestFirst = [...notes].reverse();
168044
+ const page = newestFirst.slice(offset, offset + limit);
168045
+ const remaining = total - offset - page.length;
168046
+ const footer = remaining > 0 ? `Showing ${page.length} of ${total} (newest first) — ${remaining} older: ctx_note(action="read", offset=${offset + page.length})` : null;
168047
+ return { page, total, footer };
168048
+ }
167405
168049
  function createCtxNoteTool(deps) {
167406
168050
  return {
167407
168051
  name: "ctx_note",
167408
168052
  label: "Magic Context: Notes",
167409
- description: `Save or inspect durable session notes that persist for this session.
167410
- ` + `Use this for short goals, constraints, decisions, or reminders worth carrying forward.
167411
-
167412
- ` + `Actions:
167413
- ` + "- `write`: Append one note. Optionally provide `surface_condition` to create a smart note.\n" + "- `read`: Show current notes. Defaults to active session notes + ready smart notes; use `filter` to inspect all, pending, ready, active, or dismissed notes.\n" + "- `dismiss`: Dismiss a note by `note_id`.\n" + "- `update`: Update a note by `note_id`.\n\n" + "**Smart Notes**: When `surface_condition` is provided with `write`, the note becomes a project-scoped smart note. " + "The dreamer evaluates smart note conditions during nightly runs and surfaces them when conditions are met. " + 'Example: `ctx_note(action="write", content="Implement X because Y", surface_condition="When PR #42 is merged in this repo")`',
168053
+ description: CTX_NOTE_DESCRIPTION,
167414
168054
  parameters: ParamsSchema3,
167415
168055
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
167416
168056
  const sessionId = ctx.sessionManager.getSessionId();
@@ -167492,11 +168132,15 @@ function createCtxNoteTool(deps) {
167492
168132
  - ${parts.join(`
167493
168133
  - `)}`);
167494
168134
  }
168135
+ const limit = typeof params.limit === "number" && params.limit > 0 ? Math.floor(params.limit) : DEFAULT_READ_LIMIT;
168136
+ const offset = typeof params.offset === "number" && params.offset > 0 ? Math.floor(params.offset) : 0;
167495
168137
  const sections = readNotes({
167496
168138
  db: deps.db,
167497
168139
  sessionId,
167498
168140
  cwd: ctx.cwd,
167499
- filter: params.filter
168141
+ filter: params.filter,
168142
+ limit,
168143
+ offset
167500
168144
  });
167501
168145
  try {
167502
168146
  setNoteLastReadAt(deps.db, sessionId);
@@ -167504,7 +168148,7 @@ function createCtxNoteTool(deps) {
167504
168148
  if (sections.length === 0) {
167505
168149
  return ok3(`## Notes
167506
168150
 
167507
- No notes for the current filter.`);
168151
+ No session notes or smart notes.`);
167508
168152
  }
167509
168153
  const body = sections.join(`
167510
168154
 
@@ -167531,10 +168175,14 @@ function readNotes(args) {
167531
168175
  }) : [];
167532
168176
  const sections2 = [];
167533
168177
  if (sessionNotes2.length > 0) {
168178
+ const { page, footer } = paginateNewestFirst(sessionNotes2, args.limit, args.offset);
168179
+ const lines = page.map(formatNoteLine).join(`
168180
+ `);
167534
168181
  sections2.push(`## Session Notes
167535
168182
 
167536
- ${sessionNotes2.map(formatNoteLine).join(`
167537
- `)}`);
168183
+ ${lines}${footer ? `
168184
+
168185
+ ${footer}` : ""}`);
167538
168186
  }
167539
168187
  if (readySmartNotes.length > 0) {
167540
168188
  sections2.push(`## \uD83D\uDD14 Ready Smart Notes
@@ -167565,17 +168213,25 @@ ${readySmartNotes.map(formatNoteLine).join(`
167565
168213
  }) : [];
167566
168214
  const sections = [];
167567
168215
  if (sessionNotes.length > 0) {
168216
+ const { page, footer } = paginateNewestFirst(sessionNotes, args.limit, args.offset);
168217
+ const lines = page.map(formatNoteLine).join(`
168218
+ `);
167568
168219
  sections.push(`## Session Notes
167569
168220
 
167570
- ${sessionNotes.map(formatNoteLine).join(`
167571
- `)}`);
168221
+ ${lines}${footer ? `
168222
+
168223
+ ${footer}` : ""}`);
167572
168224
  }
167573
168225
  if (smartNotes.length > 0) {
168226
+ const { page, footer } = paginateNewestFirst(smartNotes, args.limit, args.offset);
168227
+ const lines = page.map(formatNoteLine).join(`
168228
+
168229
+ `);
167574
168230
  sections.push(`## Smart Notes
167575
168231
 
167576
- ${smartNotes.map(formatNoteLine).join(`
168232
+ ${lines}${footer ? `
167577
168233
 
167578
- `)}`);
168234
+ ${footer}` : ""}`);
167579
168235
  }
167580
168236
  return sections;
167581
168237
  }
@@ -167731,7 +168387,11 @@ function createCtxReduceTool(deps) {
167731
168387
  };
167732
168388
  }
167733
168389
 
168390
+ // ../plugin/src/features/magic-context/search.ts
168391
+ init_logger();
168392
+
167734
168393
  // ../plugin/src/features/magic-context/git-commits/git-log-reader.ts
168394
+ init_logger();
167735
168395
  import { execFile } from "node:child_process";
167736
168396
  import { promisify } from "node:util";
167737
168397
  var execFileAsync = promisify(execFile);
@@ -167815,7 +168475,11 @@ ${body}` : subject;
167815
168475
  }
167816
168476
  return commits;
167817
168477
  }
168478
+ // ../plugin/src/features/magic-context/git-commits/indexer.ts
168479
+ init_logger();
168480
+
167818
168481
  // ../plugin/src/features/magic-context/git-commits/storage-git-commits.ts
168482
+ init_logger();
167819
168483
  var insertStatements = new WeakMap;
167820
168484
  var existingShasStatements = new WeakMap;
167821
168485
  var projectCountStatements = new WeakMap;
@@ -168028,6 +168692,7 @@ async function embedUnembeddedCommits(db, projectPath) {
168028
168692
  }
168029
168693
  }
168030
168694
  // ../plugin/src/features/magic-context/git-commits/search-git-commits.ts
168695
+ init_logger();
168031
168696
  var ftsStatements = new WeakMap;
168032
168697
  var ftsPlainStatements = new WeakMap;
168033
168698
  var getBySHAStatements = new WeakMap;
@@ -168698,6 +169363,9 @@ class BoundedSessionMap {
168698
169363
  }
168699
169364
  }
168700
169365
 
169366
+ // ../plugin/src/hooks/magic-context/inject-compartments.ts
169367
+ init_logger();
169368
+
168701
169369
  // ../plugin/src/hooks/magic-context/decay-curve.ts
168702
169370
  var H50 = 24;
168703
169371
  var D = 25;
@@ -168980,6 +169648,7 @@ function isAftAvailable() {
168980
169648
  }
168981
169649
 
168982
169650
  // ../plugin/src/hooks/magic-context/key-files-block.ts
169651
+ init_logger();
168983
169652
  var cachedKeyFilesBySession = new Map;
168984
169653
  var staleUpdates = new Map;
168985
169654
  function staleKey(update2) {
@@ -169233,6 +169902,21 @@ function renderMemoryBlockV2(memories, wrapper = "project-memory") {
169233
169902
  `);
169234
169903
  }
169235
169904
 
169905
+ // ../plugin/src/tools/ctx-search/constants.ts
169906
+ var CTX_SEARCH_DESCRIPTION = `Your long-term recall for this project — search everything that ever happened here, not just what's currently visible.
169907
+
169908
+ Reach for it when something feels familiar but isn't in view: "did we solve this before?", "what did we decide about X?", "when did this break?", "where does Y live?". Results only contain things you CANNOT currently see — memories already shown in <project-memory> and the live conversation tail are filtered out.
169909
+
169910
+ Sources (omit for a broad search across all):
169911
+ - memory: curated cross-session project knowledge — rules, constraints, conventions.
169912
+ - message: the raw conversation behind your compacted history. Hits include message ordinals — expand the surrounding exchange with ctx_expand(start=N-10, end=N+5).
169913
+ - git_commit: this repository's commit history.
169914
+
169915
+ Picking sources:
169916
+ - "when did this change / was this working before" → ["git_commit", "message"]
169917
+ - "did we discuss this earlier" → ["message"]
169918
+ - "what's our convention / rule for X" → ["memory"]`;
169919
+
169236
169920
  // src/tools/ctx-search.ts
169237
169921
  var DEFAULT_LIMIT = 10;
169238
169922
  var ParamsSchema5 = exports_typebox.Object({
@@ -169316,18 +170000,7 @@ function createCtxSearchTool(deps) {
169316
170000
  return {
169317
170001
  name: "ctx_search",
169318
170002
  label: "Magic Context: Search",
169319
- description: `Search across project memories, indexed git commits, and raw conversation history.
169320
-
169321
- ` + `Sources:
169322
- ` + `- memory: curated cross-session knowledge for this project
169323
- ` + `- message: raw user/assistant messages from older compartmentalized history
169324
- ` + `- git_commit: HEAD git commits (when git commit indexing is enabled)
169325
-
169326
- ` + "Narrow via the `sources` param when the question maps to a specific channel:\n" + `- "was this working before / when did this break" → ["git_commit", "message"]
169327
- ` + `- "when did we change this" → ["git_commit"]
169328
- ` + `- "what is our naming convention" → ["memory"]
169329
- ` + `- "did we discuss this earlier" → ["message"]
169330
- ` + "Omit sources for a broad search across all enabled channels.",
170003
+ description: CTX_SEARCH_DESCRIPTION,
169331
170004
  parameters: ParamsSchema5,
169332
170005
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
169333
170006
  const query = params.query?.trim();
@@ -169444,13 +170117,15 @@ function registerMagicContextTools(pi, opts) {
169444
170117
  embeddingEnabled: opts.embeddingEnabled,
169445
170118
  gitCommitsEnabled: opts.gitCommitsEnabled
169446
170119
  }));
169447
- pi.registerTool(createCtxMemoryTool({
169448
- db: opts.db,
169449
- ensureProjectRegistered: opts.ensureProjectRegistered,
169450
- memoryEnabled: opts.memoryEnabled,
169451
- embeddingEnabled: opts.embeddingEnabled,
169452
- allowDreamerActions: opts.allowDreamerActions ?? false
169453
- }));
170120
+ if (opts.memoryToolEnabled !== false) {
170121
+ pi.registerTool(createCtxMemoryTool({
170122
+ db: opts.db,
170123
+ ensureProjectRegistered: opts.ensureProjectRegistered,
170124
+ memoryEnabled: opts.memoryEnabled,
170125
+ embeddingEnabled: opts.embeddingEnabled,
170126
+ allowDreamerActions: opts.allowDreamerActions ?? false
170127
+ }));
170128
+ }
169454
170129
  if (!opts.sessionScopedToolsDisabled) {
169455
170130
  pi.registerTool(createCtxNoteTool({
169456
170131
  db: opts.db,
@@ -169473,7 +170148,7 @@ var openedDb;
169473
170148
  function magicContextSubagentExtension(pi) {
169474
170149
  setHarness("pi");
169475
170150
  pi.registerFlag(SUBAGENT_DREAMER_ACTIONS_FLAG, {
169476
- description: "Enable dreamer-only ctx_memory actions (update, merge, archive).",
170151
+ description: "Register ctx_memory with dreamer actions for Magic Context subagents.",
169477
170152
  type: "boolean",
169478
170153
  default: false
169479
170154
  });
@@ -169491,10 +170166,11 @@ function magicContextSubagentExtension(pi) {
169491
170166
  registerMagicContextTools(pi, {
169492
170167
  db,
169493
170168
  ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
170169
+ memoryToolEnabled: dreamerActionsEnabled,
169494
170170
  allowDreamerActions: dreamerActionsEnabled,
169495
170171
  sessionScopedToolsDisabled: true
169496
170172
  });
169497
- log(`[pi-subagent] registered tools: ctx_search, ctx_memory` + ` (ctx_note/ctx_expand omitted: --no-session child;` + ` memory=${cfg.memory.enabled}, embedding=${cfg.embedding.provider !== "off"},` + ` git_commits=${cfg.memory.git_commit_indexing.enabled}, dreamer_actions=${dreamerActionsEnabled})`);
170173
+ log(`[pi-subagent] registered tools: ctx_search${dreamerActionsEnabled ? ", ctx_memory" : ""}` + ` (ctx_note/ctx_expand omitted: --no-session child;` + ` memory=${cfg.memory.enabled}, embedding=${cfg.embedding.provider !== "off"},` + ` git_commits=${cfg.memory.git_commit_indexing.enabled}, dreamer_actions=${dreamerActionsEnabled})`);
169498
170174
  } catch (err5) {
169499
170175
  const message = err5 instanceof Error ? err5.message : String(err5);
169500
170176
  log(`[pi-subagent] startup failed: ${message}`);