@wolfx/pi-magic-context 0.22.3 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/dist/index.js +3954 -1210
- package/dist/subagent-entry.js +1348 -372
- package/package.json +3 -1
package/dist/subagent-entry.js
CHANGED
|
@@ -151,62 +151,6 @@ var init_logger = __esm(() => {
|
|
|
151
151
|
}
|
|
152
152
|
});
|
|
153
153
|
|
|
154
|
-
// ../plugin/src/shared/sqlite.ts
|
|
155
|
-
function buildNodeSqliteDatabaseClass(DatabaseSync) {
|
|
156
|
-
const SAVEPOINT = "mc_tx_sp";
|
|
157
|
-
|
|
158
|
-
class NodeSqliteDatabase extends DatabaseSync {
|
|
159
|
-
constructor(filename, options) {
|
|
160
|
-
const translated = { ...options };
|
|
161
|
-
if (options && "readonly" in options) {
|
|
162
|
-
translated.readOnly = options.readonly;
|
|
163
|
-
delete translated.readonly;
|
|
164
|
-
}
|
|
165
|
-
super(typeof filename === "string" ? filename : ":memory:", translated);
|
|
166
|
-
}
|
|
167
|
-
transaction(fn) {
|
|
168
|
-
const self = this;
|
|
169
|
-
const wrapped = function(...args) {
|
|
170
|
-
const nested = self.isTransaction === true;
|
|
171
|
-
self.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : "BEGIN");
|
|
172
|
-
try {
|
|
173
|
-
const result = fn.apply(this, args);
|
|
174
|
-
self.exec(nested ? `RELEASE ${SAVEPOINT}` : "COMMIT");
|
|
175
|
-
return result;
|
|
176
|
-
} catch (error) {
|
|
177
|
-
if (nested) {
|
|
178
|
-
self.exec(`ROLLBACK TO ${SAVEPOINT}`);
|
|
179
|
-
self.exec(`RELEASE ${SAVEPOINT}`);
|
|
180
|
-
} else {
|
|
181
|
-
self.exec("ROLLBACK");
|
|
182
|
-
}
|
|
183
|
-
throw error;
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
return wrapped;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return NodeSqliteDatabase;
|
|
190
|
-
}
|
|
191
|
-
var isBun, bunSpec, nodeSpec, sqliteModule, DatabaseImpl, Database;
|
|
192
|
-
var init_sqlite = __esm(async () => {
|
|
193
|
-
isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
|
|
194
|
-
bunSpec = "bun:" + "sqlite";
|
|
195
|
-
nodeSpec = "node:" + "sqlite";
|
|
196
|
-
sqliteModule = isBun ? await import(bunSpec) : await import(nodeSpec);
|
|
197
|
-
DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
|
|
198
|
-
Database = DatabaseImpl;
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
// ../plugin/src/shared/sqlite-helpers.ts
|
|
202
|
-
function closeQuietly(db) {
|
|
203
|
-
if (!db)
|
|
204
|
-
return;
|
|
205
|
-
try {
|
|
206
|
-
db.close();
|
|
207
|
-
} catch {}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
154
|
// ../../node_modules/.bun/esprima@4.0.1/node_modules/esprima/dist/esprima.js
|
|
211
155
|
var require_esprima = __commonJS((exports, module) => {
|
|
212
156
|
(function webpackUniversalModuleDefinition(root, factory) {
|
|
@@ -7964,53 +7908,6 @@ var require_src2 = __commonJS((exports, module) => {
|
|
|
7964
7908
|
};
|
|
7965
7909
|
});
|
|
7966
7910
|
|
|
7967
|
-
// ../plugin/src/hooks/magic-context/read-session-db.ts
|
|
7968
|
-
import { existsSync as existsSync6 } from "node:fs";
|
|
7969
|
-
import { join as join7 } from "node:path";
|
|
7970
|
-
function getOpenCodeDbPath() {
|
|
7971
|
-
return join7(getDataDir(), "opencode", "opencode.db");
|
|
7972
|
-
}
|
|
7973
|
-
function openCodeDbExists() {
|
|
7974
|
-
return existsSync6(getOpenCodeDbPath());
|
|
7975
|
-
}
|
|
7976
|
-
function closeCachedReadOnlyDb() {
|
|
7977
|
-
if (!cachedReadOnlyDb) {
|
|
7978
|
-
return;
|
|
7979
|
-
}
|
|
7980
|
-
try {
|
|
7981
|
-
closeQuietly(cachedReadOnlyDb.db);
|
|
7982
|
-
} catch (error51) {
|
|
7983
|
-
log("[magic-context] failed to close cached OpenCode read-only DB:", error51);
|
|
7984
|
-
} finally {
|
|
7985
|
-
cachedReadOnlyDb = null;
|
|
7986
|
-
}
|
|
7987
|
-
}
|
|
7988
|
-
function getReadOnlySessionDb() {
|
|
7989
|
-
const dbPath = getOpenCodeDbPath();
|
|
7990
|
-
if (cachedReadOnlyDb?.path === dbPath) {
|
|
7991
|
-
return cachedReadOnlyDb.db;
|
|
7992
|
-
}
|
|
7993
|
-
closeCachedReadOnlyDb();
|
|
7994
|
-
const db = new Database(dbPath, { readonly: true });
|
|
7995
|
-
cachedReadOnlyDb = { path: dbPath, db };
|
|
7996
|
-
return db;
|
|
7997
|
-
}
|
|
7998
|
-
function withReadOnlySessionDb(fn) {
|
|
7999
|
-
return fn(getReadOnlySessionDb());
|
|
8000
|
-
}
|
|
8001
|
-
function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
8002
|
-
const row = db.prepare(`SELECT COUNT(*) as count FROM message WHERE session_id = ?
|
|
8003
|
-
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
8004
|
-
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
|
|
8005
|
-
return typeof row?.count === "number" ? row.count : 0;
|
|
8006
|
-
}
|
|
8007
|
-
var cachedReadOnlyDb = null;
|
|
8008
|
-
var init_read_session_db = __esm(async () => {
|
|
8009
|
-
init_data_path();
|
|
8010
|
-
init_logger();
|
|
8011
|
-
await init_sqlite();
|
|
8012
|
-
});
|
|
8013
|
-
|
|
8014
7911
|
// ../plugin/src/features/magic-context/storage-db.ts
|
|
8015
7912
|
init_data_path();
|
|
8016
7913
|
import { copyFileSync, cpSync, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "node:fs";
|
|
@@ -8094,7 +7991,59 @@ function safeString(value) {
|
|
|
8094
7991
|
|
|
8095
7992
|
// ../plugin/src/features/magic-context/storage-db.ts
|
|
8096
7993
|
init_logger();
|
|
8097
|
-
|
|
7994
|
+
|
|
7995
|
+
// ../plugin/src/shared/sqlite.ts
|
|
7996
|
+
var isBun = typeof process !== "undefined" && typeof process.versions?.bun === "string";
|
|
7997
|
+
var bunSpec = "bun:" + "sqlite";
|
|
7998
|
+
var nodeSpec = "node:" + "sqlite";
|
|
7999
|
+
var sqliteModule = isBun ? await import(bunSpec) : await import(nodeSpec);
|
|
8000
|
+
var DatabaseImpl = isBun ? sqliteModule.Database : buildNodeSqliteDatabaseClass(sqliteModule.DatabaseSync);
|
|
8001
|
+
function buildNodeSqliteDatabaseClass(DatabaseSync) {
|
|
8002
|
+
const SAVEPOINT = "mc_tx_sp";
|
|
8003
|
+
|
|
8004
|
+
class NodeSqliteDatabase extends DatabaseSync {
|
|
8005
|
+
constructor(filename, options) {
|
|
8006
|
+
const translated = { ...options };
|
|
8007
|
+
if (options && "readonly" in options) {
|
|
8008
|
+
translated.readOnly = options.readonly;
|
|
8009
|
+
delete translated.readonly;
|
|
8010
|
+
}
|
|
8011
|
+
super(typeof filename === "string" ? filename : ":memory:", translated);
|
|
8012
|
+
}
|
|
8013
|
+
transaction(fn) {
|
|
8014
|
+
const self = this;
|
|
8015
|
+
const wrapped = function(...args) {
|
|
8016
|
+
const nested = self.isTransaction === true;
|
|
8017
|
+
self.exec(nested ? `SAVEPOINT ${SAVEPOINT}` : "BEGIN");
|
|
8018
|
+
try {
|
|
8019
|
+
const result = fn.apply(this, args);
|
|
8020
|
+
self.exec(nested ? `RELEASE ${SAVEPOINT}` : "COMMIT");
|
|
8021
|
+
return result;
|
|
8022
|
+
} catch (error) {
|
|
8023
|
+
if (nested) {
|
|
8024
|
+
self.exec(`ROLLBACK TO ${SAVEPOINT}`);
|
|
8025
|
+
self.exec(`RELEASE ${SAVEPOINT}`);
|
|
8026
|
+
} else {
|
|
8027
|
+
self.exec("ROLLBACK");
|
|
8028
|
+
}
|
|
8029
|
+
throw error;
|
|
8030
|
+
}
|
|
8031
|
+
};
|
|
8032
|
+
return wrapped;
|
|
8033
|
+
}
|
|
8034
|
+
}
|
|
8035
|
+
return NodeSqliteDatabase;
|
|
8036
|
+
}
|
|
8037
|
+
var Database = DatabaseImpl;
|
|
8038
|
+
|
|
8039
|
+
// ../plugin/src/shared/sqlite-helpers.ts
|
|
8040
|
+
function closeQuietly(db) {
|
|
8041
|
+
if (!db)
|
|
8042
|
+
return;
|
|
8043
|
+
try {
|
|
8044
|
+
db.close();
|
|
8045
|
+
} catch {}
|
|
8046
|
+
}
|
|
8098
8047
|
|
|
8099
8048
|
// ../plugin/src/features/magic-context/key-files/project-key-files.ts
|
|
8100
8049
|
init_logger();
|
|
@@ -8948,6 +8897,72 @@ var MIGRATIONS = [
|
|
|
8948
8897
|
db.exec("ALTER TABLE notes ADD COLUMN anchor_ordinal INTEGER");
|
|
8949
8898
|
}
|
|
8950
8899
|
}
|
|
8900
|
+
},
|
|
8901
|
+
{
|
|
8902
|
+
version: 30,
|
|
8903
|
+
description: "HARD-bust m[0] markers: cached system/tool-set/model identity",
|
|
8904
|
+
up: (db) => {
|
|
8905
|
+
const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
|
|
8906
|
+
if (!hasSessionMeta)
|
|
8907
|
+
return;
|
|
8908
|
+
ensureColumn(db, "session_meta", "cached_m0_system_hash", "TEXT");
|
|
8909
|
+
ensureColumn(db, "session_meta", "cached_m0_tool_set_hash", "TEXT");
|
|
8910
|
+
ensureColumn(db, "session_meta", "cached_m0_model_key", "TEXT");
|
|
8911
|
+
const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
|
|
8912
|
+
if (columns.has("cached_m0_bytes")) {
|
|
8913
|
+
db.prepare(`UPDATE session_meta SET
|
|
8914
|
+
cached_m0_bytes = NULL,
|
|
8915
|
+
cached_m1_bytes = NULL,
|
|
8916
|
+
cached_m0_materialized_at = NULL,
|
|
8917
|
+
cached_m0_system_hash = NULL,
|
|
8918
|
+
cached_m0_tool_set_hash = NULL,
|
|
8919
|
+
cached_m0_model_key = NULL`).run();
|
|
8920
|
+
}
|
|
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
|
+
}
|
|
8951
8966
|
}
|
|
8952
8967
|
];
|
|
8953
8968
|
var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -141553,7 +141568,7 @@ var tokenizer = new src_default(exports_claude);
|
|
|
141553
141568
|
function estimateTokens(text) {
|
|
141554
141569
|
if (!text)
|
|
141555
141570
|
return 0;
|
|
141556
|
-
return tokenizer.
|
|
141571
|
+
return tokenizer.encode(text, "all").length;
|
|
141557
141572
|
}
|
|
141558
141573
|
function normalizeText(text) {
|
|
141559
141574
|
return text.replace(/\s+/g, " ").trim();
|
|
@@ -141780,6 +141795,11 @@ function markSessionCompleted(db, sessionId, now) {
|
|
|
141780
141795
|
SET status = 'completed', completed_at = ?, lease_expires_at = NULL, last_error = NULL
|
|
141781
141796
|
WHERE session_id = ?`).run(now, sessionId);
|
|
141782
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
|
+
}
|
|
141783
141803
|
function markSessionSkipped(db, sessionId, now, reason) {
|
|
141784
141804
|
db.prepare(`INSERT INTO tool_owner_backfill_state(session_id, status, completed_at, last_error)
|
|
141785
141805
|
VALUES (?, 'skipped', ?, ?)
|
|
@@ -141856,12 +141876,18 @@ function applyOwnersForSession(db, sessionId, ownersByCallId) {
|
|
|
141856
141876
|
const updateRowStmt = db.prepare(`UPDATE tags
|
|
141857
141877
|
SET tool_owner_message_id = ?
|
|
141858
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`);
|
|
141859
141883
|
let rowsUpdated = 0;
|
|
141860
141884
|
db.transaction(() => {
|
|
141861
141885
|
for (const [callId, ownerId] of ownersByCallId) {
|
|
141862
141886
|
const orphan = findOrphanStmt.get(sessionId, callId);
|
|
141863
141887
|
if (!orphan)
|
|
141864
141888
|
continue;
|
|
141889
|
+
if (existingOwnerStmt.get(sessionId, callId, ownerId))
|
|
141890
|
+
continue;
|
|
141865
141891
|
const result = updateRowStmt.run(ownerId, orphan.id);
|
|
141866
141892
|
rowsUpdated += result.changes ?? 0;
|
|
141867
141893
|
}
|
|
@@ -141890,6 +141916,8 @@ function backfillToolOwnersInChunks(db, result) {
|
|
|
141890
141916
|
if (owners.size === 0) {
|
|
141891
141917
|
markSessionSkipped(db, sessionId, Date.now(), "no_oc_matches");
|
|
141892
141918
|
result.sessionsSkippedNoMatches += 1;
|
|
141919
|
+
} else if (rowsLeftNull > 0) {
|
|
141920
|
+
markSessionPendingRetry(db, sessionId);
|
|
141893
141921
|
} else {
|
|
141894
141922
|
markSessionCompleted(db, sessionId, Date.now());
|
|
141895
141923
|
result.sessionsCompleted += 1;
|
|
@@ -141912,7 +141940,7 @@ var databases = new Map;
|
|
|
141912
141940
|
var persistenceByDatabase = new WeakMap;
|
|
141913
141941
|
var persistenceErrorByDatabase = new WeakMap;
|
|
141914
141942
|
var lastSchemaFenceRejection = null;
|
|
141915
|
-
var LATEST_SUPPORTED_VERSION =
|
|
141943
|
+
var LATEST_SUPPORTED_VERSION = 32;
|
|
141916
141944
|
function resolveDatabasePath(dbPathOverride) {
|
|
141917
141945
|
if (dbPathOverride) {
|
|
141918
141946
|
return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
|
|
@@ -142014,9 +142042,9 @@ function runSqliteOptimize(db) {
|
|
|
142014
142042
|
} catch {}
|
|
142015
142043
|
}
|
|
142016
142044
|
function initializeDatabase(db) {
|
|
142045
|
+
db.exec("PRAGMA busy_timeout=5000");
|
|
142017
142046
|
db.exec("PRAGMA foreign_keys=ON");
|
|
142018
142047
|
db.exec("PRAGMA journal_mode=WAL");
|
|
142019
|
-
db.exec("PRAGMA busy_timeout=5000");
|
|
142020
142048
|
applySqliteTuningPragmas(db);
|
|
142021
142049
|
db.exec(`
|
|
142022
142050
|
CREATE TABLE IF NOT EXISTS tags (
|
|
@@ -142029,6 +142057,9 @@ function initializeDatabase(db) {
|
|
|
142029
142057
|
tag_number INTEGER,
|
|
142030
142058
|
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
142031
142059
|
entry_fingerprint TEXT,
|
|
142060
|
+
token_count INTEGER,
|
|
142061
|
+
input_token_count INTEGER,
|
|
142062
|
+
reasoning_token_count INTEGER,
|
|
142032
142063
|
UNIQUE(session_id, tag_number)
|
|
142033
142064
|
);
|
|
142034
142065
|
|
|
@@ -142318,6 +142349,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
142318
142349
|
counter INTEGER DEFAULT 0,
|
|
142319
142350
|
last_nudge_tokens INTEGER DEFAULT 0,
|
|
142320
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,
|
|
142321
142357
|
last_transform_error TEXT DEFAULT '',
|
|
142322
142358
|
nudge_anchor_message_id TEXT DEFAULT '',
|
|
142323
142359
|
nudge_anchor_text TEXT DEFAULT '',
|
|
@@ -142374,9 +142410,20 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
142374
142410
|
cached_m0_project_docs_hash TEXT,
|
|
142375
142411
|
cached_m1_bytes BLOB,
|
|
142376
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,
|
|
142377
142421
|
cached_m0_materialized_at INTEGER,
|
|
142378
142422
|
cached_m0_session_facts_version INTEGER,
|
|
142379
142423
|
cached_m0_upgrade_state TEXT,
|
|
142424
|
+
cached_m0_system_hash TEXT,
|
|
142425
|
+
cached_m0_tool_set_hash TEXT,
|
|
142426
|
+
cached_m0_model_key TEXT,
|
|
142380
142427
|
cached_m0_last_baseline_end_message_id TEXT,
|
|
142381
142428
|
upgrade_reminded_at INTEGER,
|
|
142382
142429
|
pi_stable_id_scheme INTEGER
|
|
@@ -142481,6 +142528,11 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
142481
142528
|
CREATE INDEX IF NOT EXISTS idx_message_history_index_updated_at ON message_history_index(updated_at);
|
|
142482
142529
|
`);
|
|
142483
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");
|
|
142484
142536
|
ensureColumn(db, "session_meta", "last_transform_error", "TEXT DEFAULT ''");
|
|
142485
142537
|
ensureColumn(db, "session_meta", "nudge_anchor_message_id", "TEXT DEFAULT ''");
|
|
142486
142538
|
ensureColumn(db, "session_meta", "nudge_anchor_text", "TEXT DEFAULT ''");
|
|
@@ -142507,6 +142559,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
142507
142559
|
ensureColumn(db, "session_meta", "system_prompt_hash", "TEXT DEFAULT ''");
|
|
142508
142560
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
142509
142561
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
142562
|
+
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
142510
142563
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
142511
142564
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
142512
142565
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -142525,6 +142578,9 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
142525
142578
|
db.exec(`CREATE INDEX IF NOT EXISTS idx_tags_pi_adopt
|
|
142526
142579
|
ON tags(session_id, entry_fingerprint)
|
|
142527
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");
|
|
142528
142584
|
ensureColumn(db, "session_meta", "system_prompt_tokens", "INTEGER DEFAULT 0");
|
|
142529
142585
|
ensureColumn(db, "session_meta", "compaction_marker_state", "TEXT DEFAULT ''");
|
|
142530
142586
|
ensureColumn(db, "session_meta", "key_files", "TEXT DEFAULT ''");
|
|
@@ -142565,9 +142621,20 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
142565
142621
|
ensureColumn(db, "session_meta", "cached_m0_project_docs_hash", "TEXT");
|
|
142566
142622
|
ensureColumn(db, "session_meta", "cached_m1_bytes", "BLOB");
|
|
142567
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");
|
|
142568
142632
|
ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
|
|
142569
142633
|
ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
|
|
142570
142634
|
ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
|
|
142635
|
+
ensureColumn(db, "session_meta", "cached_m0_system_hash", "TEXT");
|
|
142636
|
+
ensureColumn(db, "session_meta", "cached_m0_tool_set_hash", "TEXT");
|
|
142637
|
+
ensureColumn(db, "session_meta", "cached_m0_model_key", "TEXT");
|
|
142571
142638
|
ensureColumn(db, "session_meta", "cached_m0_last_baseline_end_message_id", "TEXT");
|
|
142572
142639
|
ensureColumn(db, "session_meta", "upgrade_reminded_at", "INTEGER");
|
|
142573
142640
|
db.exec(`
|
|
@@ -142631,6 +142698,13 @@ function healAllNullColumns(db) {
|
|
|
142631
142698
|
healNullIntegerColumns(db);
|
|
142632
142699
|
healMissingMemoryBlockIds(db);
|
|
142633
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
|
+
}
|
|
142634
142708
|
function healMissingMemoryBlockIds(db) {
|
|
142635
142709
|
try {
|
|
142636
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();
|
|
@@ -142640,6 +142714,7 @@ function healNullTextColumns(db) {
|
|
|
142640
142714
|
const columns = [
|
|
142641
142715
|
["cache_ttl", ""],
|
|
142642
142716
|
["last_nudge_band", ""],
|
|
142717
|
+
["last_nudge_level", ""],
|
|
142643
142718
|
["last_transform_error", ""],
|
|
142644
142719
|
["nudge_anchor_message_id", ""],
|
|
142645
142720
|
["nudge_anchor_text", ""],
|
|
@@ -142654,6 +142729,7 @@ function healNullTextColumns(db) {
|
|
|
142654
142729
|
["todo_synthetic_state_json", ""],
|
|
142655
142730
|
["system_prompt_hash", ""],
|
|
142656
142731
|
["stripped_placeholder_ids", ""],
|
|
142732
|
+
["stale_reduce_stripped_ids", ""],
|
|
142657
142733
|
["memory_block_cache", ""],
|
|
142658
142734
|
["memory_block_ids", ""],
|
|
142659
142735
|
["compaction_marker_state", ""],
|
|
@@ -142679,7 +142755,17 @@ function healNullIntegerColumns(db) {
|
|
|
142679
142755
|
["observed_safe_input_tokens", 0],
|
|
142680
142756
|
["cache_alert_sent", 0],
|
|
142681
142757
|
["new_work_tokens", 0],
|
|
142682
|
-
["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]
|
|
142683
142769
|
];
|
|
142684
142770
|
for (const [column, fallback] of columns) {
|
|
142685
142771
|
try {
|
|
@@ -142718,6 +142804,7 @@ function openDatabase(dbPathOrOptions) {
|
|
|
142718
142804
|
if (!persistenceByDatabase.has(existing)) {
|
|
142719
142805
|
persistenceByDatabase.set(existing, true);
|
|
142720
142806
|
}
|
|
142807
|
+
healWedgedChannel2Claims(existing);
|
|
142721
142808
|
return existing;
|
|
142722
142809
|
}
|
|
142723
142810
|
try {
|
|
@@ -142743,6 +142830,7 @@ function openDatabase(dbPathOrOptions) {
|
|
|
142743
142830
|
log(`[magic-context] key-files orphan GC failed: ${getErrorMessage(error)}`);
|
|
142744
142831
|
}
|
|
142745
142832
|
}
|
|
142833
|
+
healWedgedChannel2Claims(db);
|
|
142746
142834
|
if (!explicitDbPath) {
|
|
142747
142835
|
try {
|
|
142748
142836
|
runToolOwnerBackfill(db);
|
|
@@ -142766,6 +142854,31 @@ function openDatabase(dbPathOrOptions) {
|
|
|
142766
142854
|
// src/subagent-entry.ts
|
|
142767
142855
|
init_logger();
|
|
142768
142856
|
|
|
142857
|
+
// ../plugin/src/config/prune-config-leaf.ts
|
|
142858
|
+
function isPlainObject(value) {
|
|
142859
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
142860
|
+
}
|
|
142861
|
+
function pruneNestedConfigLeaf(block, relativePath) {
|
|
142862
|
+
if (relativePath.length === 0)
|
|
142863
|
+
return null;
|
|
142864
|
+
const result = { ...block };
|
|
142865
|
+
let cursor = result;
|
|
142866
|
+
for (let i = 0;i < relativePath.length - 1; i++) {
|
|
142867
|
+
const seg = String(relativePath[i]);
|
|
142868
|
+
const child = cursor[seg];
|
|
142869
|
+
if (!isPlainObject(child))
|
|
142870
|
+
return null;
|
|
142871
|
+
const clonedChild = { ...child };
|
|
142872
|
+
cursor[seg] = clonedChild;
|
|
142873
|
+
cursor = clonedChild;
|
|
142874
|
+
}
|
|
142875
|
+
const leaf = String(relativePath[relativePath.length - 1]);
|
|
142876
|
+
if (!(leaf in cursor))
|
|
142877
|
+
return null;
|
|
142878
|
+
delete cursor[leaf];
|
|
142879
|
+
return { block: result, removed: relativePath.map(String).join(".") };
|
|
142880
|
+
}
|
|
142881
|
+
|
|
142769
142882
|
// src/config/index.ts
|
|
142770
142883
|
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
142771
142884
|
import { homedir as homedir3 } from "node:os";
|
|
@@ -142911,6 +143024,74 @@ function migrateLegacyExperimental(rawConfig, warnings) {
|
|
|
142911
143024
|
return patched;
|
|
142912
143025
|
}
|
|
142913
143026
|
|
|
143027
|
+
// ../plugin/src/config/project-security.ts
|
|
143028
|
+
var HIDDEN_AGENT_KEYS = ["historian", "dreamer", "sidekick"];
|
|
143029
|
+
var AGENT_ESCALATION_FIELDS = ["prompt", "permission", "tools", "system_prompt"];
|
|
143030
|
+
function isPlainObject2(value) {
|
|
143031
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
143032
|
+
}
|
|
143033
|
+
function stripUnsafeProjectConfigFields(projectRaw) {
|
|
143034
|
+
const warnings = [];
|
|
143035
|
+
if ("auto_update" in projectRaw) {
|
|
143036
|
+
delete projectRaw.auto_update;
|
|
143037
|
+
warnings.push("Ignoring auto_update from project config (security: this setting only honors user-level config).");
|
|
143038
|
+
}
|
|
143039
|
+
if ("sqlite" in projectRaw) {
|
|
143040
|
+
delete projectRaw.sqlite;
|
|
143041
|
+
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).");
|
|
143042
|
+
}
|
|
143043
|
+
for (const agentKey of HIDDEN_AGENT_KEYS) {
|
|
143044
|
+
const block = projectRaw[agentKey];
|
|
143045
|
+
if (!isPlainObject2(block))
|
|
143046
|
+
continue;
|
|
143047
|
+
const removed = [];
|
|
143048
|
+
for (const field of AGENT_ESCALATION_FIELDS) {
|
|
143049
|
+
if (field in block) {
|
|
143050
|
+
delete block[field];
|
|
143051
|
+
removed.push(field);
|
|
143052
|
+
}
|
|
143053
|
+
}
|
|
143054
|
+
if (removed.length > 0) {
|
|
143055
|
+
warnings.push(`Ignoring ${agentKey}.${removed.join("/")} from project config ` + "(security: a repository cannot reprogram or re-permission hidden agents).");
|
|
143056
|
+
}
|
|
143057
|
+
}
|
|
143058
|
+
return warnings;
|
|
143059
|
+
}
|
|
143060
|
+
function normalizeEndpoint(value) {
|
|
143061
|
+
if (typeof value !== "string")
|
|
143062
|
+
return;
|
|
143063
|
+
const trimmed = value.trim().replace(/\/+$/, "");
|
|
143064
|
+
return trimmed.length > 0 ? trimmed.toLowerCase() : undefined;
|
|
143065
|
+
}
|
|
143066
|
+
function dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, userRaw) {
|
|
143067
|
+
const projectEmbedding = projectRaw.embedding;
|
|
143068
|
+
if (!isPlainObject2(projectEmbedding))
|
|
143069
|
+
return [];
|
|
143070
|
+
const redirectsEndpoint = "endpoint" in projectEmbedding;
|
|
143071
|
+
if (!redirectsEndpoint)
|
|
143072
|
+
return [];
|
|
143073
|
+
const userEmbedding = userRaw?.embedding;
|
|
143074
|
+
if (isPlainObject2(userEmbedding)) {
|
|
143075
|
+
const projectEndpoint = normalizeEndpoint(projectEmbedding.endpoint);
|
|
143076
|
+
const userEndpoint = normalizeEndpoint(userEmbedding.endpoint);
|
|
143077
|
+
if (projectEndpoint !== undefined && projectEndpoint === userEndpoint) {
|
|
143078
|
+
return [];
|
|
143079
|
+
}
|
|
143080
|
+
}
|
|
143081
|
+
const providesOwnKey = typeof projectEmbedding.api_key === "string" && projectEmbedding.api_key.length > 0;
|
|
143082
|
+
if (providesOwnKey)
|
|
143083
|
+
return [];
|
|
143084
|
+
const mergedEmbedding = mergedRaw.embedding;
|
|
143085
|
+
if (!isPlainObject2(mergedEmbedding))
|
|
143086
|
+
return [];
|
|
143087
|
+
if (!("api_key" in mergedEmbedding))
|
|
143088
|
+
return [];
|
|
143089
|
+
delete mergedEmbedding.api_key;
|
|
143090
|
+
return [
|
|
143091
|
+
"Dropped inherited user embedding api_key because project config redirected " + "embedding.endpoint without supplying its own key (security: prevents key " + "exfiltration to a repository-chosen endpoint)."
|
|
143092
|
+
];
|
|
143093
|
+
}
|
|
143094
|
+
|
|
142914
143095
|
// ../../node_modules/.bun/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
142915
143096
|
var exports_external = {};
|
|
142916
143097
|
__export(exports_external, {
|
|
@@ -143542,7 +143723,7 @@ __export(exports_util, {
|
|
|
143542
143723
|
jsonStringifyReplacer: () => jsonStringifyReplacer,
|
|
143543
143724
|
joinValues: () => joinValues,
|
|
143544
143725
|
issue: () => issue,
|
|
143545
|
-
isPlainObject: () =>
|
|
143726
|
+
isPlainObject: () => isPlainObject3,
|
|
143546
143727
|
isObject: () => isObject,
|
|
143547
143728
|
hexToUint8Array: () => hexToUint8Array,
|
|
143548
143729
|
getSizableOrigin: () => getSizableOrigin,
|
|
@@ -143724,7 +143905,7 @@ var allowsEval = /* @__PURE__ */ cached(() => {
|
|
|
143724
143905
|
return false;
|
|
143725
143906
|
}
|
|
143726
143907
|
});
|
|
143727
|
-
function
|
|
143908
|
+
function isPlainObject3(o) {
|
|
143728
143909
|
if (isObject(o) === false)
|
|
143729
143910
|
return false;
|
|
143730
143911
|
const ctor = o.constructor;
|
|
@@ -143741,7 +143922,7 @@ function isPlainObject(o) {
|
|
|
143741
143922
|
return true;
|
|
143742
143923
|
}
|
|
143743
143924
|
function shallowClone(o) {
|
|
143744
|
-
if (
|
|
143925
|
+
if (isPlainObject3(o))
|
|
143745
143926
|
return { ...o };
|
|
143746
143927
|
if (Array.isArray(o))
|
|
143747
143928
|
return [...o];
|
|
@@ -143945,7 +144126,7 @@ function omit(schema, mask) {
|
|
|
143945
144126
|
return clone(schema, def);
|
|
143946
144127
|
}
|
|
143947
144128
|
function extend(schema, shape) {
|
|
143948
|
-
if (!
|
|
144129
|
+
if (!isPlainObject3(shape)) {
|
|
143949
144130
|
throw new Error("Invalid input to extend: expected a plain object");
|
|
143950
144131
|
}
|
|
143951
144132
|
const checks = schema._zod.def.checks;
|
|
@@ -143968,7 +144149,7 @@ function extend(schema, shape) {
|
|
|
143968
144149
|
return clone(schema, def);
|
|
143969
144150
|
}
|
|
143970
144151
|
function safeExtend(schema, shape) {
|
|
143971
|
-
if (!
|
|
144152
|
+
if (!isPlainObject3(shape)) {
|
|
143972
144153
|
throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
143973
144154
|
}
|
|
143974
144155
|
const def = mergeDefs(schema._zod.def, {
|
|
@@ -146311,7 +146492,7 @@ function mergeValues(a, b) {
|
|
|
146311
146492
|
if (a instanceof Date && b instanceof Date && +a === +b) {
|
|
146312
146493
|
return { valid: true, data: a };
|
|
146313
146494
|
}
|
|
146314
|
-
if (
|
|
146495
|
+
if (isPlainObject3(a) && isPlainObject3(b)) {
|
|
146315
146496
|
const bKeys = Object.keys(b);
|
|
146316
146497
|
const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
|
|
146317
146498
|
const newObj = { ...a, ...b };
|
|
@@ -146497,7 +146678,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
|
|
|
146497
146678
|
$ZodType.init(inst, def);
|
|
146498
146679
|
inst._zod.parse = (payload, ctx) => {
|
|
146499
146680
|
const input = payload.value;
|
|
146500
|
-
if (!
|
|
146681
|
+
if (!isPlainObject3(input)) {
|
|
146501
146682
|
payload.issues.push({
|
|
146502
146683
|
expected: "record",
|
|
146503
146684
|
code: "invalid_type",
|
|
@@ -157217,7 +157398,6 @@ var AgentOverrideConfigSchema = exports_external.object({
|
|
|
157217
157398
|
});
|
|
157218
157399
|
|
|
157219
157400
|
// ../plugin/src/config/schema/magic-context.ts
|
|
157220
|
-
var DEFAULT_NUDGE_INTERVAL_TOKENS = 1e4;
|
|
157221
157401
|
var DEFAULT_EXECUTE_THRESHOLD_PERCENTAGE = 65;
|
|
157222
157402
|
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.";
|
|
157223
157403
|
var DEFAULT_HISTORIAN_TIMEOUT_MS = 300000;
|
|
@@ -157315,7 +157495,6 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
157315
157495
|
historian: HistorianConfigSchema.describe("Historian agent configuration (model, fallback_models, variant, temperature, maxTokens, permission, two_pass, etc.)"),
|
|
157316
157496
|
dreamer: DreamerConfigSchema.optional().describe("Dreamer agent + scheduling configuration (model, fallback_models, disable, schedule, tasks, etc.)"),
|
|
157317
157497
|
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" })'),
|
|
157318
|
-
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)"),
|
|
157319
157498
|
execute_threshold_percentage: exports_external.union([
|
|
157320
157499
|
exports_external.number().min(20).max(80, EXECUTE_THRESHOLD_CAP_MESSAGE),
|
|
157321
157500
|
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))
|
|
@@ -157324,10 +157503,7 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
157324
157503
|
default: exports_external.number().min(5000).max(2000000).optional()
|
|
157325
157504
|
}).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."),
|
|
157326
157505
|
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)"),
|
|
157327
|
-
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)"),
|
|
157328
|
-
drop_tool_structure: exports_external.boolean().default(true).describe("When true, dropped tool parts are fully removed instead of truncated in place (default: true)"),
|
|
157329
157506
|
clear_reasoning_age: exports_external.number().min(10).default(50).describe("Clear reasoning/thinking blocks older than N tags (default: 50)"),
|
|
157330
|
-
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)"),
|
|
157331
157507
|
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)"),
|
|
157332
157508
|
historian_timeout_ms: exports_external.number().min(60000).default(DEFAULT_HISTORIAN_TIMEOUT_MS).describe("Timeout for each historian prompt call in milliseconds (default: 300000)"),
|
|
157333
157509
|
commit_cluster_trigger: exports_external.object({
|
|
@@ -157350,6 +157526,7 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
157350
157526
|
model: DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
157351
157527
|
}).describe("Embedding provider configuration"),
|
|
157352
157528
|
temporal_awareness: exports_external.boolean().default(true).describe('Inject wall-clock gap markers (<!-- +Xm -->) between user messages where > 5 min elapsed since the previous message, and add start/end date attributes on compartments. Gives the agent a sense of session pacing and "how long ago" across multi-day sessions. Graduated from experimental.temporal_awareness; default: true (set false to opt out).'),
|
|
157529
|
+
keep_subagents: exports_external.boolean().default(false).describe("Debug: keep the child sessions Magic Context spawns for its own subagents (historian, dreamer, sidekick, memory-migration) instead of deleting them on success. Useful for short-term inspection/data collection — their full transcript (prompt, tool calls, token usage, output) stays in the host session store. Kept sessions accumulate until manually cleared; leave false for normal use. Requires a restart to take effect."),
|
|
157353
157530
|
caveman_text_compression: exports_external.object({
|
|
157354
157531
|
enabled: exports_external.boolean().default(false).describe("Apply deterministic caveman-style text compression to old conversation text. Only active when ctx_reduce_enabled=false. Compresses user/assistant text in oldest-first tiers: ultra (oldest 20%), full, lite, untouched (newest 40%)."),
|
|
157355
157532
|
min_chars: exports_external.number().min(100).max(1e4).default(500).describe("Text parts shorter than this (characters) stay untouched. Min 100, max 10000. Default: 500.")
|
|
@@ -157453,6 +157630,21 @@ function stripJsonComments(content) {
|
|
|
157453
157630
|
// ../plugin/src/config/variable.ts
|
|
157454
157631
|
var ENV_PATTERN = /\{env:([^}]+)\}/g;
|
|
157455
157632
|
var FILE_PATTERN = /\{file:([^}]+)\}/g;
|
|
157633
|
+
function sensitiveFilePathReason(resolvedPath) {
|
|
157634
|
+
const home = homedir2();
|
|
157635
|
+
const sensitiveDirs = [
|
|
157636
|
+
{ dir: resolve2(home, ".ssh"), label: "SSH keys" },
|
|
157637
|
+
{ dir: resolve2(home, ".aws"), label: "AWS credentials" },
|
|
157638
|
+
{ dir: resolve2(home, ".gnupg"), label: "GnuPG keyring" },
|
|
157639
|
+
{ dir: resolve2(home, ".config", "gh"), label: "GitHub CLI auth" }
|
|
157640
|
+
];
|
|
157641
|
+
for (const { dir, label } of sensitiveDirs) {
|
|
157642
|
+
if (resolvedPath === dir || resolvedPath.startsWith(`${dir}/`)) {
|
|
157643
|
+
return label;
|
|
157644
|
+
}
|
|
157645
|
+
}
|
|
157646
|
+
return null;
|
|
157647
|
+
}
|
|
157456
157648
|
function substituteConfigVariables(input) {
|
|
157457
157649
|
const warnings = [];
|
|
157458
157650
|
let text = input.text;
|
|
@@ -157506,6 +157698,10 @@ function substituteConfigVariables(input) {
|
|
|
157506
157698
|
} else if (!isAbsolute(filePath)) {
|
|
157507
157699
|
filePath = resolve2(configDir, filePath);
|
|
157508
157700
|
}
|
|
157701
|
+
const sensitiveReason = sensitiveFilePathReason(filePath);
|
|
157702
|
+
if (sensitiveReason) {
|
|
157703
|
+
warnings.push(`${token} resolves to a sensitive path (${sensitiveReason}: ${filePath}); ` + "inlining its contents into config — make sure this is intentional.");
|
|
157704
|
+
}
|
|
157509
157705
|
if (!existsSync4(filePath)) {
|
|
157510
157706
|
warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
|
|
157511
157707
|
continue;
|
|
@@ -157544,7 +157740,8 @@ function loadConfigFile(path3, scope) {
|
|
|
157544
157740
|
const rawText = readFileSync3(path3, "utf-8");
|
|
157545
157741
|
const substituted = substituteConfigVariables({
|
|
157546
157742
|
text: rawText,
|
|
157547
|
-
configPath: path3
|
|
157743
|
+
configPath: path3,
|
|
157744
|
+
isProjectConfig: scope === "project"
|
|
157548
157745
|
});
|
|
157549
157746
|
return {
|
|
157550
157747
|
path: path3,
|
|
@@ -157586,14 +157783,14 @@ function redactConfigValue(value) {
|
|
|
157586
157783
|
}
|
|
157587
157784
|
return typeof value;
|
|
157588
157785
|
}
|
|
157589
|
-
function
|
|
157786
|
+
function isPlainObject4(value) {
|
|
157590
157787
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
157591
157788
|
}
|
|
157592
157789
|
function mergeRawConfigs(base, override) {
|
|
157593
157790
|
const merged = { ...base };
|
|
157594
157791
|
for (const [key, overrideValue] of Object.entries(override)) {
|
|
157595
157792
|
const baseValue = merged[key];
|
|
157596
|
-
merged[key] =
|
|
157793
|
+
merged[key] = isPlainObject4(baseValue) && isPlainObject4(overrideValue) ? mergeRawConfigs(baseValue, overrideValue) : overrideValue;
|
|
157597
157794
|
}
|
|
157598
157795
|
return merged;
|
|
157599
157796
|
}
|
|
@@ -157607,10 +157804,15 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
157607
157804
|
}
|
|
157608
157805
|
const defaults = MagicContextConfigSchema.parse({});
|
|
157609
157806
|
const errorPaths = new Set;
|
|
157807
|
+
const issuePathsByKey = new Map;
|
|
157610
157808
|
for (const issue2 of parsed.error.issues) {
|
|
157611
157809
|
const topKey = issue2.path[0];
|
|
157612
157810
|
if (topKey !== undefined) {
|
|
157613
|
-
|
|
157811
|
+
const key = String(topKey);
|
|
157812
|
+
errorPaths.add(key);
|
|
157813
|
+
const paths = issuePathsByKey.get(key) ?? [];
|
|
157814
|
+
paths.push([...issue2.path]);
|
|
157815
|
+
issuePathsByKey.set(key, paths);
|
|
157614
157816
|
}
|
|
157615
157817
|
}
|
|
157616
157818
|
const patched = { ...migrated };
|
|
@@ -157618,11 +157820,32 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
157618
157820
|
for (const key of errorPaths) {
|
|
157619
157821
|
recoveredTopLevelKeys.push(key);
|
|
157620
157822
|
const isAgentConfig = key === "historian" || key === "dreamer" || key === "sidekick";
|
|
157621
|
-
delete patched[key];
|
|
157622
157823
|
if (isAgentConfig) {
|
|
157824
|
+
delete patched[key];
|
|
157623
157825
|
warnings.push(`"${key}": invalid agent configuration, ignoring. Check your magic-context.jsonc.`);
|
|
157624
157826
|
continue;
|
|
157625
157827
|
}
|
|
157828
|
+
const issuePaths = issuePathsByKey.get(key) ?? [];
|
|
157829
|
+
const rawValue = migrated[key];
|
|
157830
|
+
const allNested = issuePaths.length > 0 && issuePaths.every((p) => p.length >= 2) && typeof rawValue === "object" && rawValue !== null && !Array.isArray(rawValue);
|
|
157831
|
+
if (allNested) {
|
|
157832
|
+
let prunedBlock = {
|
|
157833
|
+
...rawValue
|
|
157834
|
+
};
|
|
157835
|
+
const prunedLeaves = [];
|
|
157836
|
+
for (const p of issuePaths) {
|
|
157837
|
+
const relative = p.slice(1);
|
|
157838
|
+
const result = pruneNestedConfigLeaf(prunedBlock, relative);
|
|
157839
|
+
if (result) {
|
|
157840
|
+
prunedBlock = result.block;
|
|
157841
|
+
prunedLeaves.push(result.removed);
|
|
157842
|
+
}
|
|
157843
|
+
}
|
|
157844
|
+
patched[key] = prunedBlock;
|
|
157845
|
+
warnings.push(`"${key}": invalid nested field(s) ${prunedLeaves.map((l) => `"${l}"`).join(", ")}, using defaults for those.`);
|
|
157846
|
+
continue;
|
|
157847
|
+
}
|
|
157848
|
+
delete patched[key];
|
|
157626
157849
|
const defaultValue = defaults[key];
|
|
157627
157850
|
warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultValue)}.`);
|
|
157628
157851
|
}
|
|
@@ -157655,10 +157878,22 @@ function loadPiConfig(opts = {}) {
|
|
|
157655
157878
|
return 0;
|
|
157656
157879
|
return a.scope === "user" ? -1 : 1;
|
|
157657
157880
|
});
|
|
157881
|
+
const userRaw = mergeFiles.find((f) => f.scope === "user")?.config;
|
|
157658
157882
|
for (const loaded of mergeFiles) {
|
|
157659
157883
|
const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
|
|
157660
157884
|
warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
|
|
157661
|
-
|
|
157885
|
+
if (loaded.scope === "project") {
|
|
157886
|
+
const projectRaw = { ...loaded.config };
|
|
157887
|
+
for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
|
|
157888
|
+
warnings.push(`${prefix} ${warning}`);
|
|
157889
|
+
}
|
|
157890
|
+
rawConfig = mergeRawConfigs(rawConfig, projectRaw);
|
|
157891
|
+
for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, userRaw)) {
|
|
157892
|
+
warnings.push(`${prefix} ${warning}`);
|
|
157893
|
+
}
|
|
157894
|
+
} else {
|
|
157895
|
+
rawConfig = mergeRawConfigs(rawConfig, loaded.config);
|
|
157896
|
+
}
|
|
157662
157897
|
}
|
|
157663
157898
|
const parsed = parsePiConfig(rawConfig);
|
|
157664
157899
|
warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
|
|
@@ -157733,10 +157968,22 @@ function loadPiConfigDetailed(opts = {}) {
|
|
|
157733
157968
|
return 0;
|
|
157734
157969
|
return a.scope === "user" ? -1 : 1;
|
|
157735
157970
|
});
|
|
157971
|
+
const userRaw = mergeFiles.find((f) => f.scope === "user")?.config;
|
|
157736
157972
|
for (const loaded of mergeFiles) {
|
|
157737
157973
|
const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
|
|
157738
157974
|
warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
|
|
157739
|
-
|
|
157975
|
+
if (loaded.scope === "project") {
|
|
157976
|
+
const projectRaw = { ...loaded.config };
|
|
157977
|
+
for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
|
|
157978
|
+
warnings.push(`${prefix} ${warning}`);
|
|
157979
|
+
}
|
|
157980
|
+
rawConfig = mergeRawConfigs(rawConfig, projectRaw);
|
|
157981
|
+
for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, userRaw)) {
|
|
157982
|
+
warnings.push(`${prefix} ${warning}`);
|
|
157983
|
+
}
|
|
157984
|
+
} else {
|
|
157985
|
+
rawConfig = mergeRawConfigs(rawConfig, loaded.config);
|
|
157986
|
+
}
|
|
157740
157987
|
}
|
|
157741
157988
|
const recoveredTopLevelKeys = [];
|
|
157742
157989
|
const parsed = parsePiConfig(rawConfig, recoveredTopLevelKeys);
|
|
@@ -157794,7 +158041,7 @@ function computeNormalizedHash(content) {
|
|
|
157794
158041
|
}
|
|
157795
158042
|
|
|
157796
158043
|
// ../plugin/src/features/magic-context/memory/embedding-identity.ts
|
|
157797
|
-
function
|
|
158044
|
+
function normalizeEndpoint2(endpoint) {
|
|
157798
158045
|
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
157799
158046
|
}
|
|
157800
158047
|
function getEmbeddingProviderIdentity(config2) {
|
|
@@ -157804,7 +158051,7 @@ function getEmbeddingProviderIdentity(config2) {
|
|
|
157804
158051
|
const identityInput = config2.provider === "openai-compatible" ? {
|
|
157805
158052
|
provider: "openai-compatible",
|
|
157806
158053
|
model: config2.model.trim(),
|
|
157807
|
-
endpoint:
|
|
158054
|
+
endpoint: normalizeEndpoint2(config2.endpoint),
|
|
157808
158055
|
apiKeyPresent: Boolean(config2.api_key?.trim()),
|
|
157809
158056
|
inputType: config2.input_type?.trim() || ""
|
|
157810
158057
|
} : {
|
|
@@ -158159,7 +158406,62 @@ class LocalEmbeddingProvider {
|
|
|
158159
158406
|
|
|
158160
158407
|
// ../plugin/src/features/magic-context/memory/embedding-openai.ts
|
|
158161
158408
|
init_logger();
|
|
158162
|
-
|
|
158409
|
+
|
|
158410
|
+
// ../plugin/src/features/magic-context/memory/embedding-ssrf.ts
|
|
158411
|
+
var METADATA_HOSTNAMES = new Set(["metadata.google.internal", "metadata.goog"]);
|
|
158412
|
+
var IPV6_METADATA_HOSTS = new Set(["fd00:ec2::254"]);
|
|
158413
|
+
function isLinkLocalIpv4(host) {
|
|
158414
|
+
return /^169\.254\.\d{1,3}\.\d{1,3}$/.test(host);
|
|
158415
|
+
}
|
|
158416
|
+
function ipv4FromMappedIpv6(host) {
|
|
158417
|
+
const m = /^::ffff:(.+)$/.exec(host);
|
|
158418
|
+
if (!m)
|
|
158419
|
+
return null;
|
|
158420
|
+
const tail = m[1];
|
|
158421
|
+
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(tail))
|
|
158422
|
+
return tail;
|
|
158423
|
+
const hex3 = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(tail);
|
|
158424
|
+
if (hex3) {
|
|
158425
|
+
const hi = Number.parseInt(hex3[1], 16);
|
|
158426
|
+
const lo = Number.parseInt(hex3[2], 16);
|
|
158427
|
+
if (Number.isNaN(hi) || Number.isNaN(lo))
|
|
158428
|
+
return null;
|
|
158429
|
+
return `${hi >> 8 & 255}.${hi & 255}.${lo >> 8 & 255}.${lo & 255}`;
|
|
158430
|
+
}
|
|
158431
|
+
return null;
|
|
158432
|
+
}
|
|
158433
|
+
function blockedEmbeddingEndpointReason(endpoint) {
|
|
158434
|
+
const trimmed = endpoint.trim();
|
|
158435
|
+
if (trimmed.length === 0)
|
|
158436
|
+
return null;
|
|
158437
|
+
let url2;
|
|
158438
|
+
try {
|
|
158439
|
+
url2 = new URL(trimmed);
|
|
158440
|
+
} catch {
|
|
158441
|
+
return `embedding endpoint is not a valid URL: ${trimmed}`;
|
|
158442
|
+
}
|
|
158443
|
+
const host = url2.hostname.toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
|
|
158444
|
+
if (METADATA_HOSTNAMES.has(host)) {
|
|
158445
|
+
return `embedding endpoint host ${host} is a cloud metadata service (blocked)`;
|
|
158446
|
+
}
|
|
158447
|
+
if (IPV6_METADATA_HOSTS.has(host)) {
|
|
158448
|
+
return `embedding endpoint host ${host} is the AWS IPv6 metadata service (blocked)`;
|
|
158449
|
+
}
|
|
158450
|
+
if (isLinkLocalIpv4(host)) {
|
|
158451
|
+
return `embedding endpoint host ${host} is link-local / cloud metadata (blocked)`;
|
|
158452
|
+
}
|
|
158453
|
+
const mappedV4 = ipv4FromMappedIpv6(host);
|
|
158454
|
+
if (mappedV4 && isLinkLocalIpv4(mappedV4)) {
|
|
158455
|
+
return `embedding endpoint host ${host} (IPv4-mapped ${mappedV4}) is link-local / cloud metadata (blocked)`;
|
|
158456
|
+
}
|
|
158457
|
+
if (host.startsWith("fe80:")) {
|
|
158458
|
+
return `embedding endpoint host ${host} is link-local / cloud metadata (blocked)`;
|
|
158459
|
+
}
|
|
158460
|
+
return null;
|
|
158461
|
+
}
|
|
158462
|
+
|
|
158463
|
+
// ../plugin/src/features/magic-context/memory/embedding-openai.ts
|
|
158464
|
+
function normalizeEndpoint3(endpoint) {
|
|
158163
158465
|
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
158164
158466
|
}
|
|
158165
158467
|
var FAILURE_THRESHOLD = 3;
|
|
@@ -158180,7 +158482,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
158180
158482
|
openLogged = false;
|
|
158181
158483
|
halfOpenProbeInFlight = false;
|
|
158182
158484
|
constructor(options) {
|
|
158183
|
-
this.endpoint =
|
|
158485
|
+
this.endpoint = normalizeEndpoint3(options.endpoint);
|
|
158184
158486
|
this.model = options.model?.trim() ?? "";
|
|
158185
158487
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
158186
158488
|
this.inputType = options.inputType?.trim() ?? "";
|
|
@@ -158200,6 +158502,12 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
158200
158502
|
this.initialized = false;
|
|
158201
158503
|
return false;
|
|
158202
158504
|
}
|
|
158505
|
+
const blockedReason = blockedEmbeddingEndpointReason(this.endpoint);
|
|
158506
|
+
if (blockedReason) {
|
|
158507
|
+
log(`[magic-context] embedding endpoint blocked: ${blockedReason}`);
|
|
158508
|
+
this.initialized = false;
|
|
158509
|
+
return false;
|
|
158510
|
+
}
|
|
158203
158511
|
this.initialized = true;
|
|
158204
158512
|
return true;
|
|
158205
158513
|
}
|
|
@@ -158245,6 +158553,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
158245
158553
|
...this.inputType ? { input_type: this.inputType } : {},
|
|
158246
158554
|
...this.truncate ? { truncate: this.truncate } : {}
|
|
158247
158555
|
}),
|
|
158556
|
+
redirect: "error",
|
|
158248
158557
|
signal: internalController.signal
|
|
158249
158558
|
});
|
|
158250
158559
|
if (!response.ok) {
|
|
@@ -158725,11 +159034,15 @@ function resolveEmbeddingConfig(config2) {
|
|
|
158725
159034
|
}
|
|
158726
159035
|
if (config2.provider === "openai-compatible") {
|
|
158727
159036
|
const apiKey = config2.api_key?.trim();
|
|
159037
|
+
const inputType = config2.input_type?.trim();
|
|
159038
|
+
const truncate = config2.truncate?.trim();
|
|
158728
159039
|
return {
|
|
158729
159040
|
provider: "openai-compatible",
|
|
158730
159041
|
model: config2.model.trim(),
|
|
158731
159042
|
endpoint: config2.endpoint.trim(),
|
|
158732
|
-
...apiKey ? { api_key: apiKey } : {}
|
|
159043
|
+
...apiKey ? { api_key: apiKey } : {},
|
|
159044
|
+
...inputType ? { input_type: inputType } : {},
|
|
159045
|
+
...truncate ? { truncate } : {}
|
|
158733
159046
|
};
|
|
158734
159047
|
}
|
|
158735
159048
|
return { provider: "off" };
|
|
@@ -158745,7 +159058,9 @@ function createProvider(config2) {
|
|
|
158745
159058
|
return new OpenAICompatibleEmbeddingProvider({
|
|
158746
159059
|
endpoint: config2.endpoint,
|
|
158747
159060
|
model: config2.model,
|
|
158748
|
-
apiKey: config2.api_key
|
|
159061
|
+
apiKey: config2.api_key,
|
|
159062
|
+
inputType: config2.input_type,
|
|
159063
|
+
truncate: config2.truncate
|
|
158749
159064
|
});
|
|
158750
159065
|
}
|
|
158751
159066
|
return new LocalEmbeddingProvider(config2.model);
|
|
@@ -159184,6 +159499,19 @@ function hasGitDir(canonical) {
|
|
|
159184
159499
|
return false;
|
|
159185
159500
|
}
|
|
159186
159501
|
}
|
|
159502
|
+
function normalizeStoredProjectPath(rawOrStored) {
|
|
159503
|
+
if (rawOrStored.startsWith("git:") || rawOrStored.startsWith("dir:")) {
|
|
159504
|
+
return rawOrStored;
|
|
159505
|
+
}
|
|
159506
|
+
try {
|
|
159507
|
+
return resolveProjectIdentity(rawOrStored);
|
|
159508
|
+
} catch {
|
|
159509
|
+
return directoryFallback(rawOrStored);
|
|
159510
|
+
}
|
|
159511
|
+
}
|
|
159512
|
+
function storedPathBelongsToIdentity(storedProjectPath, projectIdentity) {
|
|
159513
|
+
return storedProjectPath === projectIdentity || normalizeStoredProjectPath(storedProjectPath) === projectIdentity;
|
|
159514
|
+
}
|
|
159187
159515
|
|
|
159188
159516
|
// ../plugin/src/plugin/embedding-bootstrap-helpers.ts
|
|
159189
159517
|
import { createHash as createHash5 } from "node:crypto";
|
|
@@ -159192,10 +159520,20 @@ var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
|
159192
159520
|
"embedding.api_key",
|
|
159193
159521
|
"embedding.endpoint",
|
|
159194
159522
|
"embedding.model",
|
|
159195
|
-
"embedding.provider"
|
|
159523
|
+
"embedding.provider",
|
|
159524
|
+
"embedding.input_type",
|
|
159525
|
+
"embedding.truncate"
|
|
159196
159526
|
]);
|
|
159197
159527
|
var EMBEDDING_AFFECTING_TOP_LEVEL_KEYS = new Set(["embedding", "memory", "experimental"]);
|
|
159198
|
-
var EMBEDDING_WARNING_TERMS = [
|
|
159528
|
+
var EMBEDDING_WARNING_TERMS = [
|
|
159529
|
+
"api_key",
|
|
159530
|
+
"endpoint",
|
|
159531
|
+
"model",
|
|
159532
|
+
"provider",
|
|
159533
|
+
"embedding",
|
|
159534
|
+
"input_type",
|
|
159535
|
+
"truncate"
|
|
159536
|
+
];
|
|
159199
159537
|
var loggedFailureSignatures = new Map;
|
|
159200
159538
|
function sha256Prefix2(value, length = 16) {
|
|
159201
159539
|
return createHash5("sha256").update(value).digest("hex").slice(0, length);
|
|
@@ -159368,7 +159706,18 @@ var SESSION_META_SELECT_COLUMNS = [
|
|
|
159368
159706
|
"cached_m0_materialized_at",
|
|
159369
159707
|
"cached_m0_session_facts_version",
|
|
159370
159708
|
"cached_m0_upgrade_state",
|
|
159709
|
+
"cached_m0_system_hash",
|
|
159710
|
+
"cached_m0_tool_set_hash",
|
|
159711
|
+
"cached_m0_model_key",
|
|
159371
159712
|
"last_observed_model_key",
|
|
159713
|
+
"last_usage_context_limit",
|
|
159714
|
+
"prior_boundary_ordinal",
|
|
159715
|
+
"protected_tail_policy_version",
|
|
159716
|
+
"protected_tail_drain_window_started_at",
|
|
159717
|
+
"protected_tail_drain_tokens",
|
|
159718
|
+
"recovery_no_eligible_head_count",
|
|
159719
|
+
"force_emergency_bypass_window_start",
|
|
159720
|
+
"force_emergency_bypass_used",
|
|
159372
159721
|
"upgrade_reminded_at",
|
|
159373
159722
|
"pi_stable_id_scheme"
|
|
159374
159723
|
];
|
|
@@ -159404,7 +159753,18 @@ var META_COLUMNS = {
|
|
|
159404
159753
|
cachedM0MaterializedAt: "cached_m0_materialized_at",
|
|
159405
159754
|
cachedM0SessionFactsVersion: "cached_m0_session_facts_version",
|
|
159406
159755
|
cachedM0UpgradeState: "cached_m0_upgrade_state",
|
|
159756
|
+
cachedM0SystemHash: "cached_m0_system_hash",
|
|
159757
|
+
cachedM0ToolSetHash: "cached_m0_tool_set_hash",
|
|
159758
|
+
cachedM0ModelKey: "cached_m0_model_key",
|
|
159407
159759
|
lastObservedModelKey: "last_observed_model_key",
|
|
159760
|
+
lastUsageContextLimit: "last_usage_context_limit",
|
|
159761
|
+
priorBoundaryOrdinal: "prior_boundary_ordinal",
|
|
159762
|
+
protectedTailPolicyVersion: "protected_tail_policy_version",
|
|
159763
|
+
protectedTailDrainWindowStartedAt: "protected_tail_drain_window_started_at",
|
|
159764
|
+
protectedTailDrainTokens: "protected_tail_drain_tokens",
|
|
159765
|
+
recoveryNoEligibleHeadCount: "recovery_no_eligible_head_count",
|
|
159766
|
+
forceEmergencyBypassWindowStart: "force_emergency_bypass_window_start",
|
|
159767
|
+
forceEmergencyBypassUsed: "force_emergency_bypass_used",
|
|
159408
159768
|
upgradeRemindedAt: "upgrade_reminded_at",
|
|
159409
159769
|
piStableIdScheme: "pi_stable_id_scheme"
|
|
159410
159770
|
};
|
|
@@ -159446,7 +159806,7 @@ function isSessionMetaRow(row) {
|
|
|
159446
159806
|
if (row === null || typeof row !== "object")
|
|
159447
159807
|
return false;
|
|
159448
159808
|
const r = row;
|
|
159449
|
-
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
159809
|
+
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);
|
|
159450
159810
|
}
|
|
159451
159811
|
function getDefaultSessionMeta(sessionId) {
|
|
159452
159812
|
return {
|
|
@@ -159482,7 +159842,18 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
159482
159842
|
cachedM0MaterializedAt: null,
|
|
159483
159843
|
cachedM0SessionFactsVersion: null,
|
|
159484
159844
|
cachedM0UpgradeState: null,
|
|
159845
|
+
cachedM0SystemHash: null,
|
|
159846
|
+
cachedM0ToolSetHash: null,
|
|
159847
|
+
cachedM0ModelKey: null,
|
|
159485
159848
|
lastObservedModelKey: null,
|
|
159849
|
+
lastUsageContextLimit: 0,
|
|
159850
|
+
priorBoundaryOrdinal: 1,
|
|
159851
|
+
protectedTailPolicyVersion: 0,
|
|
159852
|
+
protectedTailDrainWindowStartedAt: 0,
|
|
159853
|
+
protectedTailDrainTokens: 0,
|
|
159854
|
+
recoveryNoEligibleHeadCount: 0,
|
|
159855
|
+
forceEmergencyBypassWindowStart: 0,
|
|
159856
|
+
forceEmergencyBypassUsed: 0,
|
|
159486
159857
|
upgradeRemindedAt: null,
|
|
159487
159858
|
piStableIdScheme: null
|
|
159488
159859
|
};
|
|
@@ -159533,7 +159904,18 @@ function toSessionMeta(row) {
|
|
|
159533
159904
|
cachedM0MaterializedAt: numOrNull(row.cached_m0_materialized_at),
|
|
159534
159905
|
cachedM0SessionFactsVersion: numOrNull(row.cached_m0_session_facts_version),
|
|
159535
159906
|
cachedM0UpgradeState: stringOrNull(row.cached_m0_upgrade_state),
|
|
159907
|
+
cachedM0SystemHash: stringOrNull(row.cached_m0_system_hash),
|
|
159908
|
+
cachedM0ToolSetHash: stringOrNull(row.cached_m0_tool_set_hash),
|
|
159909
|
+
cachedM0ModelKey: stringOrNull(row.cached_m0_model_key),
|
|
159536
159910
|
lastObservedModelKey: stringOrNull(row.last_observed_model_key),
|
|
159911
|
+
lastUsageContextLimit: numOrZero(row.last_usage_context_limit),
|
|
159912
|
+
priorBoundaryOrdinal: Math.max(1, numOrZero(row.prior_boundary_ordinal) || 1),
|
|
159913
|
+
protectedTailPolicyVersion: numOrZero(row.protected_tail_policy_version),
|
|
159914
|
+
protectedTailDrainWindowStartedAt: numOrZero(row.protected_tail_drain_window_started_at),
|
|
159915
|
+
protectedTailDrainTokens: numOrZero(row.protected_tail_drain_tokens),
|
|
159916
|
+
recoveryNoEligibleHeadCount: numOrZero(row.recovery_no_eligible_head_count),
|
|
159917
|
+
forceEmergencyBypassWindowStart: numOrZero(row.force_emergency_bypass_window_start),
|
|
159918
|
+
forceEmergencyBypassUsed: numOrZero(row.force_emergency_bypass_used),
|
|
159537
159919
|
upgradeRemindedAt: numOrNull(row.upgrade_reminded_at),
|
|
159538
159920
|
piStableIdScheme: numOrNull(row.pi_stable_id_scheme)
|
|
159539
159921
|
};
|
|
@@ -159552,8 +159934,11 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
159552
159934
|
cached_m0_project_docs_hash = ?,
|
|
159553
159935
|
cached_m0_materialized_at = ?,
|
|
159554
159936
|
cached_m0_session_facts_version = ?,
|
|
159555
|
-
cached_m0_upgrade_state =
|
|
159556
|
-
|
|
159937
|
+
cached_m0_upgrade_state = ?,
|
|
159938
|
+
cached_m0_system_hash = ?,
|
|
159939
|
+
cached_m0_tool_set_hash = ?,
|
|
159940
|
+
cached_m0_model_key = ?
|
|
159941
|
+
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);
|
|
159557
159942
|
}
|
|
159558
159943
|
function clearCachedM0M1(db, sessionId) {
|
|
159559
159944
|
ensureSessionMetaRow(db, sessionId);
|
|
@@ -159571,6 +159956,9 @@ function clearCachedM0M1(db, sessionId) {
|
|
|
159571
159956
|
["cached_m0_materialized_at", null],
|
|
159572
159957
|
["cached_m0_session_facts_version", null],
|
|
159573
159958
|
["cached_m0_upgrade_state", null],
|
|
159959
|
+
["cached_m0_system_hash", null],
|
|
159960
|
+
["cached_m0_tool_set_hash", null],
|
|
159961
|
+
["cached_m0_model_key", null],
|
|
159574
159962
|
["cached_m0_last_baseline_end_message_id", null],
|
|
159575
159963
|
["memory_block_cache", ""],
|
|
159576
159964
|
["memory_block_count", 0],
|
|
@@ -159612,12 +160000,6 @@ function isCompartmentRow(row) {
|
|
|
159612
160000
|
const candidate = row;
|
|
159613
160001
|
return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && isStringOrNullish(candidate.p1) && isStringOrNullish(candidate.p2) && isStringOrNullish(candidate.p3) && isStringOrNullish(candidate.p4) && isNumberOrNullish(candidate.importance) && isStringOrNullish(candidate.episode_type) && isNumberOrNullish(candidate.legacy) && typeof candidate.created_at === "number";
|
|
159614
160002
|
}
|
|
159615
|
-
function isSessionFactRow(row) {
|
|
159616
|
-
if (row === null || typeof row !== "object")
|
|
159617
|
-
return false;
|
|
159618
|
-
const candidate = row;
|
|
159619
|
-
return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.category === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number" && typeof candidate.updated_at === "number";
|
|
159620
|
-
}
|
|
159621
160003
|
function insertCompartmentRows(db, sessionId, compartments, now) {
|
|
159622
160004
|
const stmt = getInsertCompartmentStatement(db);
|
|
159623
160005
|
for (const compartment of compartments) {
|
|
@@ -159646,16 +160028,6 @@ function toCompartment(row) {
|
|
|
159646
160028
|
createdAt: row.created_at
|
|
159647
160029
|
};
|
|
159648
160030
|
}
|
|
159649
|
-
function toSessionFact(row) {
|
|
159650
|
-
return {
|
|
159651
|
-
id: row.id,
|
|
159652
|
-
sessionId: row.session_id,
|
|
159653
|
-
category: row.category,
|
|
159654
|
-
content: row.content,
|
|
159655
|
-
createdAt: row.created_at,
|
|
159656
|
-
updatedAt: row.updated_at
|
|
159657
|
-
};
|
|
159658
|
-
}
|
|
159659
160031
|
function getCompartments(db, sessionId) {
|
|
159660
160032
|
const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isCompartmentRow);
|
|
159661
160033
|
return rows.map(toCompartment);
|
|
@@ -159664,6 +160036,11 @@ function getLastCompartmentEndMessage(db, sessionId) {
|
|
|
159664
160036
|
const row = db.prepare("SELECT MAX(end_message) as max_end FROM compartments WHERE session_id = ?").get(sessionId);
|
|
159665
160037
|
return row?.max_end ?? -1;
|
|
159666
160038
|
}
|
|
160039
|
+
function getLastCompartmentEndMessageId(db, sessionId) {
|
|
160040
|
+
const row = db.prepare("SELECT end_message_id FROM compartments WHERE session_id = ? ORDER BY sequence DESC LIMIT 1").get(sessionId);
|
|
160041
|
+
const id = row?.end_message_id;
|
|
160042
|
+
return id && id.length > 0 ? id : null;
|
|
160043
|
+
}
|
|
159667
160044
|
function getCompartmentsByEndMessageId(db, sessionId, endMessageId) {
|
|
159668
160045
|
const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? AND end_message_id = ? ORDER BY sequence ASC").all(sessionId, endMessageId).filter(isCompartmentRow);
|
|
159669
160046
|
return rows.map(toCompartment);
|
|
@@ -159676,10 +160053,6 @@ function appendCompartments(db, sessionId, compartments) {
|
|
|
159676
160053
|
insertCompartmentRows(db, sessionId, compartments, now);
|
|
159677
160054
|
})();
|
|
159678
160055
|
}
|
|
159679
|
-
function getSessionFacts(db, sessionId) {
|
|
159680
|
-
const rows = db.prepare("SELECT * FROM session_facts WHERE session_id = ? ORDER BY category ASC, id ASC").all(sessionId).filter(isSessionFactRow);
|
|
159681
|
-
return rows.map(toSessionFact);
|
|
159682
|
-
}
|
|
159683
160056
|
function saveRecompStagingPass(db, sessionId, passNumber, compartments, facts) {
|
|
159684
160057
|
const now = Date.now();
|
|
159685
160058
|
db.transaction(() => {
|
|
@@ -159723,14 +160096,6 @@ function getRecompStaging(db, sessionId) {
|
|
|
159723
160096
|
lastEndMessage: lastEnd
|
|
159724
160097
|
};
|
|
159725
160098
|
}
|
|
159726
|
-
function invalidateAllMemoryBlockCaches(db) {
|
|
159727
|
-
try {
|
|
159728
|
-
const rows = db.prepare("SELECT session_id FROM session_meta").all();
|
|
159729
|
-
for (const row of rows) {
|
|
159730
|
-
clearCachedM0M1(db, row.session_id);
|
|
159731
|
-
}
|
|
159732
|
-
} catch {}
|
|
159733
|
-
}
|
|
159734
160099
|
function clearRecompStaging(db, sessionId) {
|
|
159735
160100
|
db.transaction(() => {
|
|
159736
160101
|
db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
|
|
@@ -159777,8 +160142,49 @@ function escapeXmlContent(s) {
|
|
|
159777
160142
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
159778
160143
|
}
|
|
159779
160144
|
|
|
159780
|
-
// ../plugin/src/hooks/magic-context/read-session-
|
|
159781
|
-
|
|
160145
|
+
// ../plugin/src/hooks/magic-context/read-session-db.ts
|
|
160146
|
+
init_data_path();
|
|
160147
|
+
init_logger();
|
|
160148
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
160149
|
+
import { join as join7 } from "node:path";
|
|
160150
|
+
function getOpenCodeDbPath() {
|
|
160151
|
+
return join7(getDataDir(), "opencode", "opencode.db");
|
|
160152
|
+
}
|
|
160153
|
+
function openCodeDbExists() {
|
|
160154
|
+
return existsSync6(getOpenCodeDbPath());
|
|
160155
|
+
}
|
|
160156
|
+
var cachedReadOnlyDb = null;
|
|
160157
|
+
function closeCachedReadOnlyDb() {
|
|
160158
|
+
if (!cachedReadOnlyDb) {
|
|
160159
|
+
return;
|
|
160160
|
+
}
|
|
160161
|
+
try {
|
|
160162
|
+
closeQuietly(cachedReadOnlyDb.db);
|
|
160163
|
+
} catch (error51) {
|
|
160164
|
+
log("[magic-context] failed to close cached OpenCode read-only DB:", error51);
|
|
160165
|
+
} finally {
|
|
160166
|
+
cachedReadOnlyDb = null;
|
|
160167
|
+
}
|
|
160168
|
+
}
|
|
160169
|
+
function getReadOnlySessionDb() {
|
|
160170
|
+
const dbPath = getOpenCodeDbPath();
|
|
160171
|
+
if (cachedReadOnlyDb?.path === dbPath) {
|
|
160172
|
+
return cachedReadOnlyDb.db;
|
|
160173
|
+
}
|
|
160174
|
+
closeCachedReadOnlyDb();
|
|
160175
|
+
const db = new Database(dbPath, { readonly: true });
|
|
160176
|
+
cachedReadOnlyDb = { path: dbPath, db };
|
|
160177
|
+
return db;
|
|
160178
|
+
}
|
|
160179
|
+
function withReadOnlySessionDb(fn) {
|
|
160180
|
+
return fn(getReadOnlySessionDb());
|
|
160181
|
+
}
|
|
160182
|
+
function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
160183
|
+
const row = db.prepare(`SELECT COUNT(*) as count FROM message WHERE session_id = ?
|
|
160184
|
+
AND NOT (COALESCE(json_extract(data, '$.summary'), 0) = 1
|
|
160185
|
+
AND COALESCE(json_extract(data, '$.finish'), '') = 'stop')`).get(sessionId);
|
|
160186
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
160187
|
+
}
|
|
159782
160188
|
|
|
159783
160189
|
// ../plugin/src/hooks/magic-context/read-session-raw.ts
|
|
159784
160190
|
function isRawMessageRow(row) {
|
|
@@ -159811,13 +160217,27 @@ function parseJsonUnknown(value) {
|
|
|
159811
160217
|
return null;
|
|
159812
160218
|
}
|
|
159813
160219
|
}
|
|
160220
|
+
function attachRawPartVersion(value, timeUpdated) {
|
|
160221
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
160222
|
+
return value;
|
|
160223
|
+
if (typeof timeUpdated !== "number")
|
|
160224
|
+
return value;
|
|
160225
|
+
try {
|
|
160226
|
+
Object.defineProperty(value, "__magicContextPartUpdatedAt", {
|
|
160227
|
+
value: timeUpdated,
|
|
160228
|
+
enumerable: false,
|
|
160229
|
+
configurable: true
|
|
160230
|
+
});
|
|
160231
|
+
} catch {}
|
|
160232
|
+
return value;
|
|
160233
|
+
}
|
|
159814
160234
|
function readRawSessionMessagesFromDb(db, sessionId) {
|
|
159815
|
-
const messageRows = db.prepare("SELECT id, data FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawMessageRow);
|
|
159816
|
-
const partRows = db.prepare("SELECT message_id, data FROM part WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawPartRow);
|
|
160235
|
+
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);
|
|
160236
|
+
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);
|
|
159817
160237
|
const partsByMessageId = new Map;
|
|
159818
160238
|
for (const part of partRows) {
|
|
159819
160239
|
const list = partsByMessageId.get(part.message_id) ?? [];
|
|
159820
|
-
list.push(parseJsonUnknown(part.data));
|
|
160240
|
+
list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
|
|
159821
160241
|
partsByMessageId.set(part.message_id, list);
|
|
159822
160242
|
}
|
|
159823
160243
|
const filtered = messageRows.filter((row) => {
|
|
@@ -159833,10 +160253,63 @@ function readRawSessionMessagesFromDb(db, sessionId) {
|
|
|
159833
160253
|
ordinal: index + 1,
|
|
159834
160254
|
id: row.id,
|
|
159835
160255
|
role,
|
|
159836
|
-
parts: partsByMessageId.get(row.id) ?? []
|
|
160256
|
+
parts: partsByMessageId.get(row.id) ?? [],
|
|
160257
|
+
version: row.time_updated ?? null
|
|
159837
160258
|
};
|
|
159838
160259
|
});
|
|
159839
160260
|
}
|
|
160261
|
+
function isAnchorRow(row) {
|
|
160262
|
+
return row !== null && typeof row === "object" && typeof row.time_created === "number" && typeof row.id === "string";
|
|
160263
|
+
}
|
|
160264
|
+
function readRawSessionTailFromDb(db, sessionId, baseOrdinal, anchorMessageId) {
|
|
160265
|
+
const anchorRow = db.prepare("SELECT time_created, id, data FROM message WHERE id = ? AND session_id = ?").get(anchorMessageId, sessionId);
|
|
160266
|
+
if (!isAnchorRow(anchorRow))
|
|
160267
|
+
return null;
|
|
160268
|
+
const anchorInfo = parseJsonRecord(anchorRow.data ?? "");
|
|
160269
|
+
if (anchorInfo?.summary === true && anchorInfo?.finish === "stop")
|
|
160270
|
+
return null;
|
|
160271
|
+
const messageRows = db.prepare(`SELECT id, data, time_updated FROM message
|
|
160272
|
+
WHERE session_id = ?
|
|
160273
|
+
AND (time_created > ? OR (time_created = ? AND id >= ?))
|
|
160274
|
+
ORDER BY time_created ASC, id ASC`).all(sessionId, anchorRow.time_created, anchorRow.time_created, anchorRow.id).filter(isRawMessageRow);
|
|
160275
|
+
const filtered = messageRows.filter((row) => {
|
|
160276
|
+
const info = parseJsonRecord(row.data);
|
|
160277
|
+
return !(info?.summary === true && info?.finish === "stop");
|
|
160278
|
+
});
|
|
160279
|
+
const ids = filtered.map((row) => row.id);
|
|
160280
|
+
const partsByMessageId = new Map;
|
|
160281
|
+
if (ids.length > 0) {
|
|
160282
|
+
const CHUNK = 800;
|
|
160283
|
+
for (let i = 0;i < ids.length; i += CHUNK) {
|
|
160284
|
+
const slice = ids.slice(i, i + CHUNK);
|
|
160285
|
+
const placeholders = slice.map(() => "?").join(",");
|
|
160286
|
+
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);
|
|
160287
|
+
for (const part of partRows) {
|
|
160288
|
+
const list = partsByMessageId.get(part.message_id) ?? [];
|
|
160289
|
+
list.push(attachRawPartVersion(parseJsonUnknown(part.data), part.time_updated));
|
|
160290
|
+
partsByMessageId.set(part.message_id, list);
|
|
160291
|
+
}
|
|
160292
|
+
}
|
|
160293
|
+
}
|
|
160294
|
+
const messages = [];
|
|
160295
|
+
let ord = baseOrdinal;
|
|
160296
|
+
for (const row of filtered) {
|
|
160297
|
+
const info = parseJsonRecord(row.data);
|
|
160298
|
+
if (!info) {
|
|
160299
|
+
ord += 1;
|
|
160300
|
+
continue;
|
|
160301
|
+
}
|
|
160302
|
+
messages.push({
|
|
160303
|
+
ordinal: ord,
|
|
160304
|
+
id: row.id,
|
|
160305
|
+
role: typeof info.role === "string" ? info.role : "unknown",
|
|
160306
|
+
parts: partsByMessageId.get(row.id) ?? [],
|
|
160307
|
+
version: row.time_updated ?? null
|
|
160308
|
+
});
|
|
160309
|
+
ord += 1;
|
|
160310
|
+
}
|
|
160311
|
+
return { messages, absoluteMessageCount: Math.max(0, ord - 1) };
|
|
160312
|
+
}
|
|
159840
160313
|
|
|
159841
160314
|
// ../plugin/src/hooks/magic-context/tag-content-primitives.ts
|
|
159842
160315
|
var encoder = new TextEncoder;
|
|
@@ -159981,6 +160454,7 @@ class ToolMutationBatch {
|
|
|
159981
160454
|
|
|
159982
160455
|
// ../plugin/src/hooks/magic-context/read-session-chunk.ts
|
|
159983
160456
|
var activeRawMessageCache = null;
|
|
160457
|
+
var activeAbsoluteCountCache = null;
|
|
159984
160458
|
var sessionProviders = new Map;
|
|
159985
160459
|
function setRawMessageProvider(sessionId, provider2) {
|
|
159986
160460
|
sessionProviders.set(sessionId, provider2);
|
|
@@ -160012,12 +160486,14 @@ function withRawSessionMessageCache(fn) {
|
|
|
160012
160486
|
const outerCache = activeRawMessageCache;
|
|
160013
160487
|
if (!outerCache) {
|
|
160014
160488
|
activeRawMessageCache = new Map;
|
|
160489
|
+
activeAbsoluteCountCache = new Map;
|
|
160015
160490
|
}
|
|
160016
160491
|
try {
|
|
160017
160492
|
return fn();
|
|
160018
160493
|
} finally {
|
|
160019
160494
|
if (!outerCache) {
|
|
160020
160495
|
activeRawMessageCache = null;
|
|
160496
|
+
activeAbsoluteCountCache = null;
|
|
160021
160497
|
}
|
|
160022
160498
|
}
|
|
160023
160499
|
}
|
|
@@ -160033,6 +160509,40 @@ function readRawSessionMessages(sessionId) {
|
|
|
160033
160509
|
}
|
|
160034
160510
|
return readRawSessionMessagesFromSource(sessionId);
|
|
160035
160511
|
}
|
|
160512
|
+
function primeTailRawMessageCache(args) {
|
|
160513
|
+
const { sessionId, lastCompartmentEnd, anchorMessageId } = args;
|
|
160514
|
+
if (!activeRawMessageCache)
|
|
160515
|
+
return false;
|
|
160516
|
+
if (activeRawMessageCache.has(sessionId))
|
|
160517
|
+
return false;
|
|
160518
|
+
if (sessionProviders.has(sessionId))
|
|
160519
|
+
return false;
|
|
160520
|
+
if (!openCodeDbExists())
|
|
160521
|
+
return false;
|
|
160522
|
+
if (lastCompartmentEnd < 1 || !anchorMessageId)
|
|
160523
|
+
return false;
|
|
160524
|
+
const result = withReadOnlySessionDb((db) => readRawSessionTailFromDb(db, sessionId, lastCompartmentEnd, anchorMessageId));
|
|
160525
|
+
if (!result)
|
|
160526
|
+
return false;
|
|
160527
|
+
activeRawMessageCache.set(sessionId, result.messages);
|
|
160528
|
+
activeAbsoluteCountCache?.set(sessionId, result.absoluteMessageCount);
|
|
160529
|
+
return true;
|
|
160530
|
+
}
|
|
160531
|
+
function getCachedAbsoluteMessageCount(sessionId) {
|
|
160532
|
+
return activeAbsoluteCountCache?.get(sessionId) ?? null;
|
|
160533
|
+
}
|
|
160534
|
+
function primeInMemoryTailRawMessageCache(args) {
|
|
160535
|
+
const { sessionId, messages, absoluteMessageCount } = args;
|
|
160536
|
+
if (!activeRawMessageCache)
|
|
160537
|
+
return false;
|
|
160538
|
+
if (activeRawMessageCache.has(sessionId))
|
|
160539
|
+
return false;
|
|
160540
|
+
if (sessionProviders.has(sessionId))
|
|
160541
|
+
return false;
|
|
160542
|
+
activeRawMessageCache.set(sessionId, messages);
|
|
160543
|
+
activeAbsoluteCountCache?.set(sessionId, absoluteMessageCount);
|
|
160544
|
+
return true;
|
|
160545
|
+
}
|
|
160036
160546
|
function readRawSessionMessagesFromSource(sessionId) {
|
|
160037
160547
|
const provider2 = sessionProviders.get(sessionId);
|
|
160038
160548
|
if (provider2)
|
|
@@ -160097,7 +160607,7 @@ function getRawSessionTagKeysThrough(sessionId, upToMessageIndex) {
|
|
|
160097
160607
|
return { messageFileKeys, toolObservations };
|
|
160098
160608
|
}
|
|
160099
160609
|
var PROTECTED_TAIL_USER_TURNS = 5;
|
|
160100
|
-
function
|
|
160610
|
+
function getLegacyProtectedTailStartOrdinal(sessionId) {
|
|
160101
160611
|
const messages = readRawSessionMessages(sessionId);
|
|
160102
160612
|
const userOrdinals = messages.filter((m) => m.role === "user" && hasMeaningfulUserText(m.parts)).map((m) => m.ordinal);
|
|
160103
160613
|
if (userOrdinals.length < PROTECTED_TAIL_USER_TURNS) {
|
|
@@ -160107,6 +160617,7 @@ function getProtectedTailStartOrdinal(sessionId) {
|
|
|
160107
160617
|
}
|
|
160108
160618
|
function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal) {
|
|
160109
160619
|
const messages = readRawSessionMessages(sessionId);
|
|
160620
|
+
const totalMessageCount = getCachedAbsoluteMessageCount(sessionId) ?? messages.length;
|
|
160110
160621
|
const startOrdinal = Math.max(1, offset);
|
|
160111
160622
|
const lines = [];
|
|
160112
160623
|
const lineMeta = [];
|
|
@@ -160234,7 +160745,7 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
|
|
|
160234
160745
|
endMessageId: lastMessageId,
|
|
160235
160746
|
messageCount: messagesProcessed,
|
|
160236
160747
|
tokenEstimate: totalTokens,
|
|
160237
|
-
hasMore: lastOrdinal < (eligibleEndOrdinal !== undefined ? Math.min(eligibleEndOrdinal - 1,
|
|
160748
|
+
hasMore: lastOrdinal < (eligibleEndOrdinal !== undefined ? Math.min(eligibleEndOrdinal - 1, totalMessageCount) : totalMessageCount),
|
|
160238
160749
|
text: lines.join(`
|
|
160239
160750
|
`),
|
|
160240
160751
|
lines: lineMeta,
|
|
@@ -160244,7 +160755,13 @@ function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal
|
|
|
160244
160755
|
}
|
|
160245
160756
|
|
|
160246
160757
|
// ../plugin/src/tools/ctx-expand/constants.ts
|
|
160247
|
-
var CTX_EXPAND_DESCRIPTION =
|
|
160758
|
+
var CTX_EXPAND_DESCRIPTION = `Recover the original conversation from your compacted history.
|
|
160759
|
+
|
|
160760
|
+
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:
|
|
160761
|
+
|
|
160762
|
+
ctx_expand(start=120, end=245) ← the compartment's own start/end attributes
|
|
160763
|
+
|
|
160764
|
+
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.`;
|
|
160248
160765
|
var CTX_EXPAND_TOKEN_BUDGET = 15000;
|
|
160249
160766
|
|
|
160250
160767
|
// ../../node_modules/.bun/typebox@1.1.38/node_modules/typebox/build/system/memory/memory.mjs
|
|
@@ -164413,11 +164930,31 @@ function findLastModelKeyFromBranch(entries) {
|
|
|
164413
164930
|
}
|
|
164414
164931
|
return;
|
|
164415
164932
|
}
|
|
164933
|
+
function rawEntryVersion(entry) {
|
|
164934
|
+
const record4 = entry;
|
|
164935
|
+
const updated = record4.updatedAt ?? record4.updated_at ?? record4.timestamp;
|
|
164936
|
+
return typeof updated === "string" || typeof updated === "number" ? updated : entry.id;
|
|
164937
|
+
}
|
|
164938
|
+
function attachPiPartVersion(parts, version2) {
|
|
164939
|
+
return parts.map((part) => {
|
|
164940
|
+
if (part === null || typeof part !== "object" || Array.isArray(part))
|
|
164941
|
+
return part;
|
|
164942
|
+
try {
|
|
164943
|
+
Object.defineProperty(part, "__magicContextPartUpdatedAt", {
|
|
164944
|
+
value: version2,
|
|
164945
|
+
enumerable: false,
|
|
164946
|
+
configurable: true
|
|
164947
|
+
});
|
|
164948
|
+
} catch {}
|
|
164949
|
+
return part;
|
|
164950
|
+
});
|
|
164951
|
+
}
|
|
164416
164952
|
function convertEntriesToRawMessages(entries) {
|
|
164417
164953
|
const result = [];
|
|
164418
164954
|
let nextOrdinal = 1;
|
|
164419
164955
|
let pendingToolParts = [];
|
|
164420
164956
|
let pendingFirstRealId = "";
|
|
164957
|
+
let pendingFirstRealVersion = "";
|
|
164421
164958
|
for (const entry of entries) {
|
|
164422
164959
|
if (!isMessageEntry(entry)) {
|
|
164423
164960
|
continue;
|
|
@@ -164425,24 +164962,29 @@ function convertEntriesToRawMessages(entries) {
|
|
|
164425
164962
|
const msg = entry.message;
|
|
164426
164963
|
const role = msg.role;
|
|
164427
164964
|
if (role === "toolResult") {
|
|
164428
|
-
|
|
164965
|
+
const version2 = rawEntryVersion(entry);
|
|
164966
|
+
pendingToolParts.push(...attachPiPartVersion(synthesizeToolResultParts(msg), version2));
|
|
164429
164967
|
if (pendingFirstRealId === "") {
|
|
164430
164968
|
pendingFirstRealId = entry.id;
|
|
164969
|
+
pendingFirstRealVersion = version2;
|
|
164431
164970
|
}
|
|
164432
164971
|
continue;
|
|
164433
164972
|
}
|
|
164434
164973
|
if (role === "user") {
|
|
164974
|
+
const version2 = rawEntryVersion(entry);
|
|
164435
164975
|
const parts = [
|
|
164436
164976
|
...pendingToolParts,
|
|
164437
|
-
...synthesizeUserParts(msg)
|
|
164977
|
+
...attachPiPartVersion(synthesizeUserParts(msg), version2)
|
|
164438
164978
|
];
|
|
164439
164979
|
pendingToolParts = [];
|
|
164440
164980
|
pendingFirstRealId = "";
|
|
164981
|
+
pendingFirstRealVersion = "";
|
|
164441
164982
|
result.push({
|
|
164442
164983
|
ordinal: nextOrdinal++,
|
|
164443
164984
|
id: entry.id,
|
|
164444
164985
|
role: "user",
|
|
164445
|
-
parts
|
|
164986
|
+
parts,
|
|
164987
|
+
version: version2
|
|
164446
164988
|
});
|
|
164447
164989
|
continue;
|
|
164448
164990
|
}
|
|
@@ -164452,16 +164994,20 @@ function convertEntriesToRawMessages(entries) {
|
|
|
164452
164994
|
ordinal: nextOrdinal++,
|
|
164453
164995
|
id: `${SYNTH_USER_ID_PREFIX}${pendingFirstRealId}`,
|
|
164454
164996
|
role: "user",
|
|
164455
|
-
parts: pendingToolParts
|
|
164997
|
+
parts: pendingToolParts,
|
|
164998
|
+
version: pendingFirstRealVersion
|
|
164456
164999
|
});
|
|
164457
165000
|
pendingToolParts = [];
|
|
164458
165001
|
pendingFirstRealId = "";
|
|
165002
|
+
pendingFirstRealVersion = "";
|
|
164459
165003
|
}
|
|
165004
|
+
const version2 = rawEntryVersion(entry);
|
|
164460
165005
|
result.push({
|
|
164461
165006
|
ordinal: nextOrdinal++,
|
|
164462
165007
|
id: entry.id,
|
|
164463
165008
|
role: "assistant",
|
|
164464
|
-
parts: synthesizeAssistantParts(msg)
|
|
165009
|
+
parts: attachPiPartVersion(synthesizeAssistantParts(msg), version2),
|
|
165010
|
+
version: version2
|
|
164465
165011
|
});
|
|
164466
165012
|
continue;
|
|
164467
165013
|
}
|
|
@@ -164469,7 +165015,8 @@ function convertEntriesToRawMessages(entries) {
|
|
|
164469
165015
|
ordinal: nextOrdinal++,
|
|
164470
165016
|
id: entry.id,
|
|
164471
165017
|
role: typeof role === "string" ? role : "unknown",
|
|
164472
|
-
parts: []
|
|
165018
|
+
parts: [],
|
|
165019
|
+
version: rawEntryVersion(entry)
|
|
164473
165020
|
});
|
|
164474
165021
|
}
|
|
164475
165022
|
if (pendingToolParts.length > 0) {
|
|
@@ -164477,7 +165024,8 @@ function convertEntriesToRawMessages(entries) {
|
|
|
164477
165024
|
ordinal: nextOrdinal,
|
|
164478
165025
|
id: `${SYNTH_USER_ID_PREFIX}${pendingFirstRealId}`,
|
|
164479
165026
|
role: "user",
|
|
164480
|
-
parts: pendingToolParts
|
|
165027
|
+
parts: pendingToolParts,
|
|
165028
|
+
version: pendingFirstRealVersion
|
|
164481
165029
|
});
|
|
164482
165030
|
}
|
|
164483
165031
|
return result;
|
|
@@ -164634,6 +165182,13 @@ function createCtxExpandTool(deps) {
|
|
|
164634
165182
|
}
|
|
164635
165183
|
|
|
164636
165184
|
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
165185
|
+
var V2_MEMORY_CATEGORIES = [
|
|
165186
|
+
"PROJECT_RULES",
|
|
165187
|
+
"ARCHITECTURE",
|
|
165188
|
+
"CONSTRAINTS",
|
|
165189
|
+
"CONFIG_VALUES",
|
|
165190
|
+
"NAMING"
|
|
165191
|
+
];
|
|
164637
165192
|
var PROMOTABLE_CATEGORIES = [
|
|
164638
165193
|
"PROJECT_RULES",
|
|
164639
165194
|
"ARCHITECTURE",
|
|
@@ -165385,7 +165940,7 @@ function indexMessagesAfterOrdinal(db, sessionId, messages, lastIndexedOrdinal,
|
|
|
165385
165940
|
}
|
|
165386
165941
|
// ../plugin/src/features/magic-context/project-docs-hash.ts
|
|
165387
165942
|
import { createHash as createHash6 } from "node:crypto";
|
|
165388
|
-
import { readFileSync as readFileSync4, statSync as statSync2 } from "node:fs";
|
|
165943
|
+
import { lstatSync, readFileSync as readFileSync4, statSync as statSync2 } from "node:fs";
|
|
165389
165944
|
import path4 from "node:path";
|
|
165390
165945
|
var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
|
|
165391
165946
|
var PROJECT_DOCS_DELIMITER = `
|
|
@@ -165393,6 +165948,7 @@ var PROJECT_DOCS_DELIMITER = `
|
|
|
165393
165948
|
---
|
|
165394
165949
|
|
|
165395
165950
|
`;
|
|
165951
|
+
var MAX_PROJECT_DOC_BYTES = 256 * 1024;
|
|
165396
165952
|
var docsCache = new Map;
|
|
165397
165953
|
function canonicalizeDocContent(raw) {
|
|
165398
165954
|
return raw.replace(/^\uFEFF/, "").replace(/\r\n/g, `
|
|
@@ -165402,9 +165958,10 @@ function canonicalizeDocContent(raw) {
|
|
|
165402
165958
|
}
|
|
165403
165959
|
function fingerprintFile(filePath) {
|
|
165404
165960
|
try {
|
|
165405
|
-
const stat2 =
|
|
165961
|
+
const stat2 = lstatSync(filePath);
|
|
165962
|
+
const isReadableDoc = stat2.isFile() && stat2.size <= MAX_PROJECT_DOC_BYTES;
|
|
165406
165963
|
return {
|
|
165407
|
-
exists:
|
|
165964
|
+
exists: isReadableDoc,
|
|
165408
165965
|
mtimeMs: stat2.mtimeMs,
|
|
165409
165966
|
size: stat2.size
|
|
165410
165967
|
};
|
|
@@ -165447,6 +166004,16 @@ function readCanonicalPieces(projectDirectory, files) {
|
|
|
165447
166004
|
if (!fingerprint?.exists) {
|
|
165448
166005
|
continue;
|
|
165449
166006
|
}
|
|
166007
|
+
let safeToRead = false;
|
|
166008
|
+
try {
|
|
166009
|
+
const st = lstatSync(filePath);
|
|
166010
|
+
safeToRead = st.isFile() && st.size <= MAX_PROJECT_DOC_BYTES;
|
|
166011
|
+
} catch {
|
|
166012
|
+
safeToRead = false;
|
|
166013
|
+
}
|
|
166014
|
+
if (!safeToRead) {
|
|
166015
|
+
continue;
|
|
166016
|
+
}
|
|
165450
166017
|
const canonicalContent = canonicalizeDocContent(readFileSync4(filePath, "utf8"));
|
|
165451
166018
|
hashPieces.push(`file:${filename}
|
|
165452
166019
|
${canonicalContent}`);
|
|
@@ -165623,12 +166190,6 @@ var AUTO_SEARCH_NO_HINT_REASONS = new Set([
|
|
|
165623
166190
|
"stacked",
|
|
165624
166191
|
"too-short"
|
|
165625
166192
|
]);
|
|
165626
|
-
function isPersistedStickyTurnReminderRow(row) {
|
|
165627
|
-
if (row === null || typeof row !== "object")
|
|
165628
|
-
return false;
|
|
165629
|
-
const r = row;
|
|
165630
|
-
return typeof r.sticky_turn_reminder_text === "string" && typeof r.sticky_turn_reminder_message_id === "string";
|
|
165631
|
-
}
|
|
165632
166193
|
function isPersistedNoteNudgeRow(row) {
|
|
165633
166194
|
if (row === null || typeof row !== "object")
|
|
165634
166195
|
return false;
|
|
@@ -165694,6 +166255,139 @@ function getDefaultHistorianFailureState() {
|
|
|
165694
166255
|
lastFailureAt: null
|
|
165695
166256
|
};
|
|
165696
166257
|
}
|
|
166258
|
+
var DEFAULT_PROTECTED_TAIL_META = {
|
|
166259
|
+
priorBoundaryOrdinal: 1,
|
|
166260
|
+
protectedTailPolicyVersion: 0,
|
|
166261
|
+
protectedTailDrainWindowStartedAt: 0,
|
|
166262
|
+
protectedTailDrainTokens: 0,
|
|
166263
|
+
recoveryNoEligibleHeadCount: 0,
|
|
166264
|
+
forceEmergencyBypassWindowStart: 0,
|
|
166265
|
+
forceEmergencyBypassUsed: 0
|
|
166266
|
+
};
|
|
166267
|
+
function toProtectedTailMeta(row) {
|
|
166268
|
+
if (row === null || typeof row !== "object")
|
|
166269
|
+
return { ...DEFAULT_PROTECTED_TAIL_META };
|
|
166270
|
+
const r = row;
|
|
166271
|
+
const numberOr = (value, fallback) => typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
166272
|
+
return {
|
|
166273
|
+
priorBoundaryOrdinal: Math.max(1, numberOr(r.prior_boundary_ordinal, 1)),
|
|
166274
|
+
protectedTailPolicyVersion: numberOr(r.protected_tail_policy_version, 0),
|
|
166275
|
+
protectedTailDrainWindowStartedAt: numberOr(r.protected_tail_drain_window_started_at, 0),
|
|
166276
|
+
protectedTailDrainTokens: numberOr(r.protected_tail_drain_tokens, 0),
|
|
166277
|
+
recoveryNoEligibleHeadCount: numberOr(r.recovery_no_eligible_head_count, 0),
|
|
166278
|
+
forceEmergencyBypassWindowStart: numberOr(r.force_emergency_bypass_window_start, 0),
|
|
166279
|
+
forceEmergencyBypassUsed: numberOr(r.force_emergency_bypass_used, 0)
|
|
166280
|
+
};
|
|
166281
|
+
}
|
|
166282
|
+
function loadProtectedTailMeta(db, sessionId) {
|
|
166283
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166284
|
+
const row = db.prepare(`SELECT prior_boundary_ordinal, protected_tail_policy_version,
|
|
166285
|
+
protected_tail_drain_window_started_at, protected_tail_drain_tokens,
|
|
166286
|
+
recovery_no_eligible_head_count, force_emergency_bypass_window_start,
|
|
166287
|
+
force_emergency_bypass_used
|
|
166288
|
+
FROM session_meta WHERE session_id = ?`).get(sessionId);
|
|
166289
|
+
return toProtectedTailMeta(row);
|
|
166290
|
+
}
|
|
166291
|
+
function markProtectedTailPolicyV3Seeded(db, sessionId, priorBoundaryOrdinal) {
|
|
166292
|
+
let seeded = false;
|
|
166293
|
+
db.transaction(() => {
|
|
166294
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166295
|
+
const existing = loadProtectedTailMeta(db, sessionId);
|
|
166296
|
+
if (existing.protectedTailPolicyVersion < 3) {
|
|
166297
|
+
db.prepare(`UPDATE session_meta
|
|
166298
|
+
SET prior_boundary_ordinal = ?, protected_tail_policy_version = 3
|
|
166299
|
+
WHERE session_id = ? AND protected_tail_policy_version < 3`).run(Math.max(1, Math.floor(priorBoundaryOrdinal)), sessionId);
|
|
166300
|
+
seeded = true;
|
|
166301
|
+
}
|
|
166302
|
+
})();
|
|
166303
|
+
return { ...loadProtectedTailMeta(db, sessionId), seeded };
|
|
166304
|
+
}
|
|
166305
|
+
function recordProtectedTailPublicationFloor(db, sessionId, floorOrdinal) {
|
|
166306
|
+
db.transaction(() => {
|
|
166307
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166308
|
+
db.prepare(`UPDATE session_meta
|
|
166309
|
+
SET prior_boundary_ordinal = MAX(COALESCE(prior_boundary_ordinal, 1), ?),
|
|
166310
|
+
recovery_no_eligible_head_count = 0
|
|
166311
|
+
WHERE session_id = ?`).run(Math.max(1, Math.floor(floorOrdinal)), sessionId);
|
|
166312
|
+
})();
|
|
166313
|
+
}
|
|
166314
|
+
function recordProtectedTailNoEligibleHead(db, sessionId) {
|
|
166315
|
+
db.transaction(() => {
|
|
166316
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166317
|
+
db.prepare(`UPDATE session_meta
|
|
166318
|
+
SET recovery_no_eligible_head_count = COALESCE(recovery_no_eligible_head_count, 0) + 1
|
|
166319
|
+
WHERE session_id = ?`).run(sessionId);
|
|
166320
|
+
})();
|
|
166321
|
+
return loadProtectedTailMeta(db, sessionId).recoveryNoEligibleHeadCount;
|
|
166322
|
+
}
|
|
166323
|
+
var DRAIN_WINDOW_MS = 10 * 60 * 1000;
|
|
166324
|
+
function protectedTailWindowBudget(usagePercentage, usable, perRunCap) {
|
|
166325
|
+
if (usagePercentage >= 95)
|
|
166326
|
+
return Math.min(1e6, Math.max(4 * perRunCap, Math.round(0.5 * usable)));
|
|
166327
|
+
if (usagePercentage >= 80)
|
|
166328
|
+
return Math.min(750000, Math.max(3 * perRunCap, Math.round(0.35 * usable)));
|
|
166329
|
+
return Math.min(500000, Math.max(perRunCap, Math.round(0.2 * usable)));
|
|
166330
|
+
}
|
|
166331
|
+
function reserveProtectedTailDrainTokens(args) {
|
|
166332
|
+
const now = args.now ?? Date.now();
|
|
166333
|
+
const requested = Math.max(0, Math.floor(args.trueRawTokens));
|
|
166334
|
+
if (requested === 0) {
|
|
166335
|
+
return { ok: true, reservedTokens: 0, overQuotaBypass: false, reservation: null };
|
|
166336
|
+
}
|
|
166337
|
+
let result = {
|
|
166338
|
+
ok: false,
|
|
166339
|
+
reservedTokens: 0,
|
|
166340
|
+
overQuotaBypass: false,
|
|
166341
|
+
reservation: null,
|
|
166342
|
+
skippedReason: "quota exhausted"
|
|
166343
|
+
};
|
|
166344
|
+
args.db.transaction(() => {
|
|
166345
|
+
ensureSessionMetaRow(args.db, args.sessionId);
|
|
166346
|
+
let meta3 = loadProtectedTailMeta(args.db, args.sessionId);
|
|
166347
|
+
if (now - meta3.protectedTailDrainWindowStartedAt > DRAIN_WINDOW_MS) {
|
|
166348
|
+
args.db.prepare(`UPDATE session_meta
|
|
166349
|
+
SET protected_tail_drain_window_started_at = ?, protected_tail_drain_tokens = 0,
|
|
166350
|
+
force_emergency_bypass_window_start = ?, force_emergency_bypass_used = 0
|
|
166351
|
+
WHERE session_id = ?`).run(now, now, args.sessionId);
|
|
166352
|
+
meta3 = loadProtectedTailMeta(args.db, args.sessionId);
|
|
166353
|
+
}
|
|
166354
|
+
const budget = protectedTailWindowBudget(args.usagePercentage, args.usable, args.perRunCap);
|
|
166355
|
+
const remaining = Math.max(0, budget - meta3.protectedTailDrainTokens);
|
|
166356
|
+
let reserved = Math.min(requested, args.perRunCap, remaining);
|
|
166357
|
+
let bypass = false;
|
|
166358
|
+
const bypassWindowExpired = now - meta3.forceEmergencyBypassWindowStart > DRAIN_WINDOW_MS;
|
|
166359
|
+
const bypassUsed = bypassWindowExpired ? 0 : meta3.forceEmergencyBypassUsed;
|
|
166360
|
+
if (reserved <= 0 && args.usagePercentage >= 95 && bypassUsed === 0) {
|
|
166361
|
+
reserved = Math.min(requested, args.perRunCap);
|
|
166362
|
+
bypass = true;
|
|
166363
|
+
}
|
|
166364
|
+
if (reserved <= 0)
|
|
166365
|
+
return;
|
|
166366
|
+
args.db.prepare(`UPDATE session_meta
|
|
166367
|
+
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,
|
|
166368
|
+
protected_tail_drain_tokens = COALESCE(protected_tail_drain_tokens, 0) + ?,
|
|
166369
|
+
force_emergency_bypass_window_start = CASE WHEN ? THEN ? ELSE force_emergency_bypass_window_start END,
|
|
166370
|
+
force_emergency_bypass_used = CASE WHEN ? THEN 1 ELSE force_emergency_bypass_used END
|
|
166371
|
+
WHERE session_id = ?`).run(now, reserved, bypass ? 1 : 0, now, bypass ? 1 : 0, args.sessionId);
|
|
166372
|
+
result = {
|
|
166373
|
+
ok: true,
|
|
166374
|
+
reservedTokens: reserved,
|
|
166375
|
+
overQuotaBypass: bypass,
|
|
166376
|
+
reservation: { sessionId: args.sessionId, runId: args.runId, tokens: reserved }
|
|
166377
|
+
};
|
|
166378
|
+
})();
|
|
166379
|
+
return result;
|
|
166380
|
+
}
|
|
166381
|
+
function rollbackProtectedTailDrainReservation(db, reservation) {
|
|
166382
|
+
if (!reservation || reservation.tokens <= 0)
|
|
166383
|
+
return;
|
|
166384
|
+
db.transaction(() => {
|
|
166385
|
+
ensureSessionMetaRow(db, reservation.sessionId);
|
|
166386
|
+
db.prepare(`UPDATE session_meta
|
|
166387
|
+
SET protected_tail_drain_tokens = MAX(0, COALESCE(protected_tail_drain_tokens, 0) - ?)
|
|
166388
|
+
WHERE session_id = ?`).run(reservation.tokens, reservation.sessionId);
|
|
166389
|
+
})();
|
|
166390
|
+
}
|
|
165697
166391
|
function setPersistedReasoningWatermark(db, sessionId, tagNumber) {
|
|
165698
166392
|
ensureSessionMetaRow(db, sessionId);
|
|
165699
166393
|
db.prepare("UPDATE session_meta SET cleared_reasoning_through_tag = ? WHERE session_id = ?").run(tagNumber, sessionId);
|
|
@@ -165701,27 +166395,95 @@ function setPersistedReasoningWatermark(db, sessionId, tagNumber) {
|
|
|
165701
166395
|
function clearPersistedReasoningWatermark(db, sessionId) {
|
|
165702
166396
|
setPersistedReasoningWatermark(db, sessionId, 0);
|
|
165703
166397
|
}
|
|
165704
|
-
function
|
|
165705
|
-
|
|
165706
|
-
|
|
165707
|
-
|
|
165708
|
-
|
|
165709
|
-
|
|
165710
|
-
|
|
165711
|
-
|
|
165712
|
-
|
|
165713
|
-
|
|
165714
|
-
|
|
165715
|
-
};
|
|
166398
|
+
function isEmergencyInputSampleRow(row) {
|
|
166399
|
+
return typeof row === "object" && row !== null && typeof row.last_emergency_input_sample === "number";
|
|
166400
|
+
}
|
|
166401
|
+
function getEmergencyInputSample(db, sessionId) {
|
|
166402
|
+
const result = db.prepare("SELECT last_emergency_input_sample FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
166403
|
+
return isEmergencyInputSampleRow(result) ? result.last_emergency_input_sample : 0;
|
|
166404
|
+
}
|
|
166405
|
+
function setEmergencyDropSample(db, sessionId, inputSample) {
|
|
166406
|
+
db.transaction(() => {
|
|
166407
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166408
|
+
db.prepare("UPDATE session_meta SET last_emergency_input_sample = ? WHERE session_id = ?").run(Math.max(0, Math.round(inputSample)), sessionId);
|
|
166409
|
+
})();
|
|
165716
166410
|
}
|
|
165717
|
-
function
|
|
166411
|
+
function clearEmergencyDropSample(db, sessionId) {
|
|
165718
166412
|
db.transaction(() => {
|
|
165719
166413
|
ensureSessionMetaRow(db, sessionId);
|
|
165720
|
-
db.prepare("UPDATE session_meta SET
|
|
166414
|
+
db.prepare("UPDATE session_meta SET last_emergency_input_sample = 0 WHERE session_id = ?").run(sessionId);
|
|
165721
166415
|
})();
|
|
165722
166416
|
}
|
|
165723
|
-
function
|
|
165724
|
-
|
|
166417
|
+
function isLastNudgeUndroppedRow(row) {
|
|
166418
|
+
return typeof row === "object" && row !== null && typeof row.last_nudge_undropped === "number";
|
|
166419
|
+
}
|
|
166420
|
+
function isLastNudgeLevelRow(row) {
|
|
166421
|
+
return typeof row === "object" && row !== null && typeof row.last_nudge_level === "string";
|
|
166422
|
+
}
|
|
166423
|
+
function normalizeLastNudgeLevel(value) {
|
|
166424
|
+
return value === "gentle" || value === "firm" || value === "urgent" ? value : "";
|
|
166425
|
+
}
|
|
166426
|
+
function getLastNudgeUndropped(db, sessionId) {
|
|
166427
|
+
const result = db.prepare("SELECT last_nudge_undropped FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
166428
|
+
return isLastNudgeUndroppedRow(result) ? result.last_nudge_undropped : 0;
|
|
166429
|
+
}
|
|
166430
|
+
function setLastNudgeUndropped(db, sessionId, value) {
|
|
166431
|
+
db.transaction(() => {
|
|
166432
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166433
|
+
db.prepare("UPDATE session_meta SET last_nudge_undropped = ? WHERE session_id = ?").run(Math.max(0, Math.round(value)), sessionId);
|
|
166434
|
+
})();
|
|
166435
|
+
}
|
|
166436
|
+
function getLastNudgeLevel(db, sessionId) {
|
|
166437
|
+
const result = db.prepare("SELECT last_nudge_level FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
166438
|
+
return isLastNudgeLevelRow(result) ? normalizeLastNudgeLevel(result.last_nudge_level) : "";
|
|
166439
|
+
}
|
|
166440
|
+
function setLastNudgeLevel(db, sessionId, value) {
|
|
166441
|
+
db.transaction(() => {
|
|
166442
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166443
|
+
db.prepare("UPDATE session_meta SET last_nudge_level = ? WHERE session_id = ?").run(normalizeLastNudgeLevel(value), sessionId);
|
|
166444
|
+
})();
|
|
166445
|
+
}
|
|
166446
|
+
function resetLastNudgeCycle(db, sessionId) {
|
|
166447
|
+
db.transaction(() => {
|
|
166448
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166449
|
+
db.prepare("UPDATE session_meta SET last_nudge_undropped = 0, last_nudge_level = '' WHERE session_id = ?").run(sessionId);
|
|
166450
|
+
})();
|
|
166451
|
+
}
|
|
166452
|
+
function resetLastNudgeCycleIfTailShrank(db, sessionId, measuredUndropped) {
|
|
166453
|
+
let changed = false;
|
|
166454
|
+
db.transaction(() => {
|
|
166455
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166456
|
+
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)));
|
|
166457
|
+
changed = (result.changes ?? 0) > 0;
|
|
166458
|
+
})();
|
|
166459
|
+
return changed;
|
|
166460
|
+
}
|
|
166461
|
+
function isChannel2StateRow(row) {
|
|
166462
|
+
return typeof row === "object" && row !== null && typeof row.channel2_nudge_state === "string";
|
|
166463
|
+
}
|
|
166464
|
+
function getChannel2NudgeState(db, sessionId) {
|
|
166465
|
+
const result = db.prepare("SELECT channel2_nudge_state FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
166466
|
+
if (!isChannel2StateRow(result))
|
|
166467
|
+
return "";
|
|
166468
|
+
const raw = result.channel2_nudge_state;
|
|
166469
|
+
return raw === "pending" || raw === "claimed" || raw === "delivered" ? raw : "";
|
|
166470
|
+
}
|
|
166471
|
+
function setChannel2NudgeState(db, sessionId, state) {
|
|
166472
|
+
db.transaction(() => {
|
|
166473
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166474
|
+
const claimedAt = state === "claimed" ? Date.now() : 0;
|
|
166475
|
+
db.prepare("UPDATE session_meta SET channel2_nudge_state = ?, channel2_nudge_claimed_at = ? WHERE session_id = ?").run(state, claimedAt, sessionId);
|
|
166476
|
+
})();
|
|
166477
|
+
}
|
|
166478
|
+
function casChannel2NudgeState(db, sessionId, from, to) {
|
|
166479
|
+
let changed = false;
|
|
166480
|
+
db.transaction(() => {
|
|
166481
|
+
ensureSessionMetaRow(db, sessionId);
|
|
166482
|
+
const claimedAt = to === "claimed" ? Date.now() : 0;
|
|
166483
|
+
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);
|
|
166484
|
+
changed = (result.changes ?? 0) > 0;
|
|
166485
|
+
})();
|
|
166486
|
+
return changed;
|
|
165725
166487
|
}
|
|
165726
166488
|
function getPersistedNoteNudge(db, sessionId) {
|
|
165727
166489
|
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);
|
|
@@ -165768,7 +166530,8 @@ function casUpdateJsonArrayColumn(db, sessionId, column, validator, mutate, opti
|
|
|
165768
166530
|
}
|
|
165769
166531
|
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
165770
166532
|
const row = db.prepare(`SELECT ${column} FROM session_meta WHERE session_id = ?`).get(sessionId);
|
|
165771
|
-
const
|
|
166533
|
+
const rawCurrent = row?.[column] ?? null;
|
|
166534
|
+
const currentBlob = rawCurrent ?? "[]";
|
|
165772
166535
|
const current = parseJsonArray(currentBlob, validator);
|
|
165773
166536
|
const next = mutate(current);
|
|
165774
166537
|
if (next === null)
|
|
@@ -165776,7 +166539,7 @@ function casUpdateJsonArrayColumn(db, sessionId, column, validator, mutate, opti
|
|
|
165776
166539
|
const nextBlob = stableStringify(next);
|
|
165777
166540
|
if (nextBlob === currentBlob)
|
|
165778
166541
|
return true;
|
|
165779
|
-
const result = db.prepare(`UPDATE session_meta SET ${column} = ? WHERE session_id = ? AND ${column}
|
|
166542
|
+
const result = db.prepare(`UPDATE session_meta SET ${column} = ? WHERE session_id = ? AND ${column} IS ?`).run(nextBlob, sessionId, rawCurrent);
|
|
165780
166543
|
if (result.changes > 0)
|
|
165781
166544
|
return true;
|
|
165782
166545
|
}
|
|
@@ -165905,14 +166668,16 @@ function getHistorianFailureState(db, sessionId) {
|
|
|
165905
166668
|
};
|
|
165906
166669
|
}
|
|
165907
166670
|
function incrementHistorianFailure(db, sessionId, error51) {
|
|
166671
|
+
let nextCount = 1;
|
|
165908
166672
|
db.transaction(() => {
|
|
165909
166673
|
ensureSessionMetaRow(db, sessionId);
|
|
165910
166674
|
const current = getHistorianFailureState(db, sessionId);
|
|
165911
|
-
|
|
166675
|
+
nextCount = current.failureCount + 1;
|
|
165912
166676
|
db.prepare("UPDATE session_meta SET historian_failure_count = ?, historian_last_error = ?, historian_last_failure_at = ? WHERE session_id = ?").run(nextCount, error51, Date.now(), sessionId);
|
|
165913
166677
|
const reason = error51.replace(/\s+/g, " ").trim().slice(0, 300);
|
|
165914
166678
|
sessionLog(sessionId, `historian failure recorded: count=${nextCount} reason="${reason}"`);
|
|
165915
166679
|
})();
|
|
166680
|
+
return nextCount;
|
|
165916
166681
|
}
|
|
165917
166682
|
function clearHistorianFailureState(db, sessionId) {
|
|
165918
166683
|
db.transaction(() => {
|
|
@@ -165942,7 +166707,11 @@ function recordOverflowDetected(db, sessionId, reportedLimit) {
|
|
|
165942
166707
|
function clearEmergencyRecovery(db, sessionId) {
|
|
165943
166708
|
db.transaction(() => {
|
|
165944
166709
|
ensureSessionMetaRow(db, sessionId);
|
|
165945
|
-
|
|
166710
|
+
try {
|
|
166711
|
+
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0, recovery_no_eligible_head_count = 0 WHERE session_id = ?").run(sessionId);
|
|
166712
|
+
} catch {
|
|
166713
|
+
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0 WHERE session_id = ?").run(sessionId);
|
|
166714
|
+
}
|
|
165946
166715
|
})();
|
|
165947
166716
|
}
|
|
165948
166717
|
function clearDetectedContextLimit(db, sessionId) {
|
|
@@ -165981,10 +166750,39 @@ function getStrippedPlaceholderIds(db, sessionId) {
|
|
|
165981
166750
|
} catch {}
|
|
165982
166751
|
return new Set;
|
|
165983
166752
|
}
|
|
165984
|
-
function
|
|
166753
|
+
function applyStrippedPlaceholderDelta(db, sessionId, delta) {
|
|
166754
|
+
const add = delta.add ? [...delta.add] : [];
|
|
166755
|
+
const remove = delta.remove ? [...delta.remove] : [];
|
|
166756
|
+
if (add.length === 0 && remove.length === 0)
|
|
166757
|
+
return true;
|
|
165985
166758
|
ensureSessionMetaRow(db, sessionId);
|
|
165986
|
-
|
|
165987
|
-
|
|
166759
|
+
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
166760
|
+
const row = db.prepare("SELECT stripped_placeholder_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
166761
|
+
const rawStored = row ? row.stripped_placeholder_ids ?? null : null;
|
|
166762
|
+
const current = new Set(parseStrippedBlob(rawStored));
|
|
166763
|
+
for (const id of add)
|
|
166764
|
+
current.add(id);
|
|
166765
|
+
for (const id of remove)
|
|
166766
|
+
current.delete(id);
|
|
166767
|
+
const nextBlob = current.size > 0 ? JSON.stringify([...current]) : "";
|
|
166768
|
+
if (nextBlob === (rawStored ?? ""))
|
|
166769
|
+
return true;
|
|
166770
|
+
const result = db.prepare("UPDATE session_meta SET stripped_placeholder_ids = ? WHERE session_id = ? AND stripped_placeholder_ids IS ?").run(nextBlob, sessionId, rawStored);
|
|
166771
|
+
if (result.changes > 0)
|
|
166772
|
+
return true;
|
|
166773
|
+
}
|
|
166774
|
+
sessionLog(sessionId, `stripped_placeholder_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
166775
|
+
return false;
|
|
166776
|
+
}
|
|
166777
|
+
function parseStrippedBlob(raw) {
|
|
166778
|
+
if (!raw || raw.length === 0)
|
|
166779
|
+
return [];
|
|
166780
|
+
try {
|
|
166781
|
+
const parsed = JSON.parse(raw);
|
|
166782
|
+
if (Array.isArray(parsed))
|
|
166783
|
+
return parsed.filter((v) => typeof v === "string");
|
|
166784
|
+
} catch {}
|
|
166785
|
+
return [];
|
|
165988
166786
|
}
|
|
165989
166787
|
function isPendingCompactionMarker(value) {
|
|
165990
166788
|
return typeof value === "object" && value !== null && typeof value.ordinal === "number" && typeof value.endMessageId === "string" && typeof value.publishedAt === "number";
|
|
@@ -166077,7 +166875,6 @@ import { Buffer as Buffer3 } from "node:buffer";
|
|
|
166077
166875
|
|
|
166078
166876
|
// ../plugin/src/features/magic-context/resolve-subagent-fallback.ts
|
|
166079
166877
|
init_logger();
|
|
166080
|
-
await init_read_session_db();
|
|
166081
166878
|
function resolveIsSubagentFromOpenCodeDb(sessionId) {
|
|
166082
166879
|
try {
|
|
166083
166880
|
return withReadOnlySessionDb((openCodeDb) => {
|
|
@@ -166111,6 +166908,9 @@ var SESSION_META_FALLBACK_SELECTS = {
|
|
|
166111
166908
|
cached_m0_materialized_at: "NULL AS cached_m0_materialized_at",
|
|
166112
166909
|
cached_m0_session_facts_version: "NULL AS cached_m0_session_facts_version",
|
|
166113
166910
|
cached_m0_upgrade_state: "NULL AS cached_m0_upgrade_state",
|
|
166911
|
+
cached_m0_system_hash: "NULL AS cached_m0_system_hash",
|
|
166912
|
+
cached_m0_tool_set_hash: "NULL AS cached_m0_tool_set_hash",
|
|
166913
|
+
cached_m0_model_key: "NULL AS cached_m0_model_key",
|
|
166114
166914
|
last_observed_model_key: "NULL AS last_observed_model_key",
|
|
166115
166915
|
upgrade_reminded_at: "NULL AS upgrade_reminded_at"
|
|
166116
166916
|
};
|
|
@@ -166293,7 +167093,8 @@ function updateNote(db, noteId, updates, scope) {
|
|
|
166293
167093
|
sets.push("session_id = ?");
|
|
166294
167094
|
params.push(updates.sessionId);
|
|
166295
167095
|
}
|
|
166296
|
-
|
|
167096
|
+
const smartConditionChanged = existing.type === "smart" && updates.surfaceCondition !== undefined && updates.surfaceCondition !== existing.surfaceCondition;
|
|
167097
|
+
if (updates.status !== undefined && !smartConditionChanged) {
|
|
166297
167098
|
sets.push("status = ?");
|
|
166298
167099
|
params.push(updates.status);
|
|
166299
167100
|
}
|
|
@@ -166306,17 +167107,21 @@ function updateNote(db, noteId, updates, scope) {
|
|
|
166306
167107
|
sets.push("surface_condition = ?");
|
|
166307
167108
|
params.push(updates.surfaceCondition);
|
|
166308
167109
|
}
|
|
166309
|
-
if (
|
|
166310
|
-
sets.push("last_checked_at =
|
|
166311
|
-
|
|
166312
|
-
|
|
166313
|
-
|
|
166314
|
-
|
|
166315
|
-
|
|
166316
|
-
|
|
166317
|
-
|
|
166318
|
-
|
|
166319
|
-
|
|
167110
|
+
if (smartConditionChanged) {
|
|
167111
|
+
sets.push("status = 'pending'", "last_checked_at = NULL", "ready_at = NULL", "ready_reason = NULL");
|
|
167112
|
+
} else {
|
|
167113
|
+
if (updates.lastCheckedAt !== undefined) {
|
|
167114
|
+
sets.push("last_checked_at = ?");
|
|
167115
|
+
params.push(updates.lastCheckedAt);
|
|
167116
|
+
}
|
|
167117
|
+
if (updates.readyAt !== undefined) {
|
|
167118
|
+
sets.push("ready_at = ?");
|
|
167119
|
+
params.push(updates.readyAt);
|
|
167120
|
+
}
|
|
167121
|
+
if (updates.readyReason !== undefined) {
|
|
167122
|
+
sets.push("ready_reason = ?");
|
|
167123
|
+
params.push(updates.readyReason);
|
|
167124
|
+
}
|
|
166320
167125
|
}
|
|
166321
167126
|
}
|
|
166322
167127
|
if (sets.length === 1) {
|
|
@@ -166506,7 +167311,7 @@ var getTagNumberByMessageIdStatements = new WeakMap;
|
|
|
166506
167311
|
function getInsertTagStatement(db) {
|
|
166507
167312
|
let stmt = insertTagStatements.get(db);
|
|
166508
167313
|
if (!stmt) {
|
|
166509
|
-
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
167314
|
+
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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
166510
167315
|
insertTagStatements.set(db, stmt);
|
|
166511
167316
|
}
|
|
166512
167317
|
return stmt;
|
|
@@ -166548,9 +167353,95 @@ function getUpdateTagInputByteSizeStatement(db) {
|
|
|
166548
167353
|
function updateTagByteSize(db, sessionId, tagNumber, newByteSize) {
|
|
166549
167354
|
getUpdateTagByteSizeStatement(db).run(newByteSize, sessionId, tagNumber);
|
|
166550
167355
|
}
|
|
167356
|
+
var CONTENT_ID_SUFFIX = /:(?:p|file)\d+$/;
|
|
167357
|
+
function ownerMessageIdForTagRow(row) {
|
|
167358
|
+
if (row.type === "tool") {
|
|
167359
|
+
return row.tool_owner_message_id ?? row.message_id;
|
|
167360
|
+
}
|
|
167361
|
+
return row.message_id.replace(CONTENT_ID_SUFFIX, "");
|
|
167362
|
+
}
|
|
167363
|
+
function getActiveTagTokenAggregate(db, sessionId) {
|
|
167364
|
+
const row = db.prepare(`SELECT
|
|
167365
|
+
COALESCE(SUM(CASE WHEN type != 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0)
|
|
167366
|
+
+ COALESCE(SUM(COALESCE(reasoning_token_count, 0)), 0) AS conversation,
|
|
167367
|
+
COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) + COALESCE(input_token_count, 0) ELSE 0 END), 0) AS tool_call,
|
|
167368
|
+
COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0) AS tool_output,
|
|
167369
|
+
COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
|
|
167370
|
+
FROM tags
|
|
167371
|
+
WHERE session_id = ? AND status = 'active'`).get(sessionId);
|
|
167372
|
+
return {
|
|
167373
|
+
conversation: row?.conversation ?? 0,
|
|
167374
|
+
toolCall: row?.tool_call ?? 0,
|
|
167375
|
+
toolOutput: row?.tool_output ?? 0,
|
|
167376
|
+
nullCount: row?.null_count ?? 0
|
|
167377
|
+
};
|
|
167378
|
+
}
|
|
167379
|
+
function getTriggerTagTokenUpperBound(db, sessionId) {
|
|
167380
|
+
const row = db.prepare(`SELECT
|
|
167381
|
+
COALESCE(SUM(COALESCE(token_count, 0) + COALESCE(input_token_count, 0) + COALESCE(reasoning_token_count, 0)), 0) AS bound,
|
|
167382
|
+
COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
|
|
167383
|
+
FROM tags
|
|
167384
|
+
WHERE session_id = ? AND status IN ('active', 'dropped')`).get(sessionId);
|
|
167385
|
+
return { bound: row?.bound ?? 0, nullCount: row?.null_count ?? 0 };
|
|
167386
|
+
}
|
|
166551
167387
|
function updateTagInputByteSize(db, sessionId, tagNumber, newInputByteSize) {
|
|
166552
167388
|
getUpdateTagInputByteSizeStatement(db).run(newInputByteSize, sessionId, tagNumber);
|
|
166553
167389
|
}
|
|
167390
|
+
var updateTagTokenCountStatements = new WeakMap;
|
|
167391
|
+
var updateTagInputTokenCountStatements = new WeakMap;
|
|
167392
|
+
function getUpdateTagTokenCountStatement(db) {
|
|
167393
|
+
let stmt = updateTagTokenCountStatements.get(db);
|
|
167394
|
+
if (!stmt) {
|
|
167395
|
+
stmt = db.prepare("UPDATE tags SET token_count = ? WHERE session_id = ? AND tag_number = ?");
|
|
167396
|
+
updateTagTokenCountStatements.set(db, stmt);
|
|
167397
|
+
}
|
|
167398
|
+
return stmt;
|
|
167399
|
+
}
|
|
167400
|
+
function getUpdateTagInputTokenCountStatement(db) {
|
|
167401
|
+
let stmt = updateTagInputTokenCountStatements.get(db);
|
|
167402
|
+
if (!stmt) {
|
|
167403
|
+
stmt = db.prepare("UPDATE tags SET input_token_count = ? WHERE session_id = ? AND tag_number = ?");
|
|
167404
|
+
updateTagInputTokenCountStatements.set(db, stmt);
|
|
167405
|
+
}
|
|
167406
|
+
return stmt;
|
|
167407
|
+
}
|
|
167408
|
+
function updateTagTokenCount(db, sessionId, tagNumber, newTokenCount) {
|
|
167409
|
+
getUpdateTagTokenCountStatement(db).run(newTokenCount, sessionId, tagNumber);
|
|
167410
|
+
}
|
|
167411
|
+
function getAllStatusTagTokenTotalsFlat(db, sessionId) {
|
|
167412
|
+
const rows = db.prepare(`SELECT type, message_id, tool_owner_message_id, token_count, input_token_count, reasoning_token_count
|
|
167413
|
+
FROM tags
|
|
167414
|
+
WHERE session_id = ?`).all(sessionId);
|
|
167415
|
+
const totals = new Map;
|
|
167416
|
+
const nullMessageIds = new Set;
|
|
167417
|
+
for (const row of rows) {
|
|
167418
|
+
if (row.type === "tool" && row.tool_owner_message_id === null)
|
|
167419
|
+
continue;
|
|
167420
|
+
const owner = ownerMessageIdForTagRow(row);
|
|
167421
|
+
if (row.token_count === null) {
|
|
167422
|
+
nullMessageIds.add(owner);
|
|
167423
|
+
totals.delete(owner);
|
|
167424
|
+
continue;
|
|
167425
|
+
}
|
|
167426
|
+
if (nullMessageIds.has(owner))
|
|
167427
|
+
continue;
|
|
167428
|
+
const weight = (row.token_count ?? 0) + (row.input_token_count ?? 0) + (row.reasoning_token_count ?? 0);
|
|
167429
|
+
totals.set(owner, (totals.get(owner) ?? 0) + weight);
|
|
167430
|
+
}
|
|
167431
|
+
return { totals, nullMessageIds };
|
|
167432
|
+
}
|
|
167433
|
+
function updateTagInputTokenCount(db, sessionId, tagNumber, newInputTokenCount) {
|
|
167434
|
+
getUpdateTagInputTokenCountStatement(db).run(newInputTokenCount, sessionId, tagNumber);
|
|
167435
|
+
}
|
|
167436
|
+
function tagTokenCountIsNull(db, sessionId, tagNumber) {
|
|
167437
|
+
const row = db.prepare("SELECT token_count FROM tags WHERE session_id = ? AND tag_number = ?").get(sessionId, tagNumber);
|
|
167438
|
+
return row !== undefined && row.token_count === null;
|
|
167439
|
+
}
|
|
167440
|
+
function backfillTagTokenCounts(db, sessionId, tagNumber, counts) {
|
|
167441
|
+
db.prepare(`UPDATE tags
|
|
167442
|
+
SET token_count = ?, input_token_count = ?, reasoning_token_count = ?
|
|
167443
|
+
WHERE session_id = ? AND tag_number = ? AND token_count IS NULL`).run(counts.tokenCount ?? null, counts.inputTokenCount ?? null, counts.reasoningTokenCount ?? null, sessionId, tagNumber);
|
|
167444
|
+
}
|
|
166554
167445
|
function getMaxTagNumberBySessionStatement(db) {
|
|
166555
167446
|
let stmt = getMaxTagNumberBySessionStatements.get(db);
|
|
166556
167447
|
if (!stmt) {
|
|
@@ -166603,8 +167494,8 @@ function isMaxTagNumberRow(row) {
|
|
|
166603
167494
|
const r = row;
|
|
166604
167495
|
return typeof r.max_tag_number === "number";
|
|
166605
167496
|
}
|
|
166606
|
-
function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0, toolOwnerMessageId = null, entryFingerprint = null) {
|
|
166607
|
-
getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness(), toolOwnerMessageId, entryFingerprint);
|
|
167497
|
+
function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber, reasoningByteSize = 0, toolName = null, inputByteSize = 0, toolOwnerMessageId = null, entryFingerprint = null, tokenCounts = null) {
|
|
167498
|
+
getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, reasoningByteSize, tagNumber, toolName, inputByteSize, getHarness(), toolOwnerMessageId, entryFingerprint, tokenCounts?.tokenCount ?? null, tokenCounts?.inputTokenCount ?? null, tokenCounts?.reasoningTokenCount ?? null);
|
|
166608
167499
|
return tagNumber;
|
|
166609
167500
|
}
|
|
166610
167501
|
function updateTagStatus(db, sessionId, tagId, status) {
|
|
@@ -166672,13 +167563,6 @@ function getTagsByNumbers(db, sessionId, tagNumbers) {
|
|
|
166672
167563
|
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);
|
|
166673
167564
|
return rows.map(toTagEntry);
|
|
166674
167565
|
}
|
|
166675
|
-
function getTopNBySize(db, sessionId, n) {
|
|
166676
|
-
if (n <= 0) {
|
|
166677
|
-
return [];
|
|
166678
|
-
}
|
|
166679
|
-
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);
|
|
166680
|
-
return rows.map(toTagEntry);
|
|
166681
|
-
}
|
|
166682
167566
|
var getToolTagNumberByOwnerStatements = new WeakMap;
|
|
166683
167567
|
var getNullOwnerToolTagStatements = new WeakMap;
|
|
166684
167568
|
var adoptNullOwnerToolTagStatements = new WeakMap;
|
|
@@ -166746,43 +167630,41 @@ var ERROR_CLASSES = new Set([
|
|
|
166746
167630
|
]);
|
|
166747
167631
|
// src/tools/ctx-memory.ts
|
|
166748
167632
|
init_logger();
|
|
167633
|
+
|
|
167634
|
+
// ../plugin/src/tools/ctx-memory/constants.ts
|
|
167635
|
+
var CTX_MEMORY_DESCRIPTION = `Durable project knowledge shared across every session on this project.
|
|
167636
|
+
|
|
167637
|
+
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.
|
|
167638
|
+
|
|
167639
|
+
Actions:
|
|
167640
|
+
- write: save a new memory (content + category).
|
|
167641
|
+
- update: rewrite one memory whose fact changed (ids: [one], content).
|
|
167642
|
+
- archive: retire wrong or obsolete memories (ids: [one or more], optional reason).
|
|
167643
|
+
- merge: collapse duplicates into one memory (ids: [two or more], content).
|
|
167644
|
+
|
|
167645
|
+
Example: ctx_memory(action="write", category="CONSTRAINTS", content="Pi stores sessions as JSONL under ~/.pi/agent/sessions/, not SQLite")`;
|
|
167646
|
+
|
|
167647
|
+
// src/tools/ctx-memory.ts
|
|
166749
167648
|
var DEFAULT_LIST_LIMIT = 10;
|
|
166750
|
-
var
|
|
166751
|
-
|
|
166752
|
-
return VALID_CATEGORIES.has(value);
|
|
166753
|
-
}
|
|
166754
|
-
var ALL_ACTIONS = [
|
|
166755
|
-
"write",
|
|
166756
|
-
"delete",
|
|
166757
|
-
"list",
|
|
166758
|
-
"update",
|
|
166759
|
-
"merge",
|
|
166760
|
-
"archive"
|
|
166761
|
-
];
|
|
166762
|
-
var DREAMER_ONLY_ACTIONS = new Set([
|
|
166763
|
-
"list",
|
|
166764
|
-
"update",
|
|
166765
|
-
"merge",
|
|
166766
|
-
"archive"
|
|
166767
|
-
]);
|
|
167649
|
+
var ALL_ACTIONS = ["write", "archive", "update", "merge", "list"];
|
|
167650
|
+
var DREAMER_ONLY_ACTIONS = new Set(["list"]);
|
|
166768
167651
|
var ParamsSchema2 = exports_typebox.Object({
|
|
166769
|
-
action: exports_typebox.Union(ALL_ACTIONS.map((a) => exports_typebox.Literal(a)), { description: "
|
|
167652
|
+
action: exports_typebox.Union(ALL_ACTIONS.map((a) => exports_typebox.Literal(a)), { description: "What to do: write, update, archive, or merge" }),
|
|
166770
167653
|
content: exports_typebox.Optional(exports_typebox.String({
|
|
166771
|
-
description: "
|
|
166772
|
-
})),
|
|
166773
|
-
category: exports_typebox.Optional(exports_typebox.String({
|
|
166774
|
-
description: "Memory category (required for write, optional filter for list, optional override for merge). One of: " + CATEGORY_PRIORITY.join(", ")
|
|
167654
|
+
description: "The memory text — one standalone fact (required for write, update, merge)"
|
|
166775
167655
|
})),
|
|
166776
|
-
|
|
166777
|
-
description: "
|
|
167656
|
+
category: exports_typebox.Optional(exports_typebox.Union(V2_MEMORY_CATEGORIES.map((c) => exports_typebox.Literal(c)), {
|
|
167657
|
+
description: "What kind of fact this is (required for write; optional merge override)"
|
|
166778
167658
|
})),
|
|
166779
167659
|
ids: exports_typebox.Optional(exports_typebox.Array(exports_typebox.Number(), {
|
|
166780
|
-
description: "
|
|
167660
|
+
description: "Target memory id(s) from <project-memory>: update takes exactly one, archive one or more, merge two or more"
|
|
166781
167661
|
})),
|
|
166782
167662
|
limit: exports_typebox.Optional(exports_typebox.Number({
|
|
166783
|
-
description: "
|
|
167663
|
+
description: "Max results for list (default: 10)"
|
|
166784
167664
|
})),
|
|
166785
|
-
reason: exports_typebox.Optional(exports_typebox.String({
|
|
167665
|
+
reason: exports_typebox.Optional(exports_typebox.String({
|
|
167666
|
+
description: "Why the memory is being archived (optional, recommended)"
|
|
167667
|
+
}))
|
|
166786
167668
|
});
|
|
166787
167669
|
function ok2(text) {
|
|
166788
167670
|
return { content: [{ type: "text", text }], details: undefined };
|
|
@@ -166829,6 +167711,12 @@ function formatMemoryList(memories) {
|
|
|
166829
167711
|
].join(`
|
|
166830
167712
|
`);
|
|
166831
167713
|
}
|
|
167714
|
+
function isPrimaryMutableMemory(memory2) {
|
|
167715
|
+
return (memory2.status === "active" || memory2.status === "permanent") && memory2.supersededByMemoryId === null;
|
|
167716
|
+
}
|
|
167717
|
+
function inactiveMemoryError(id, action2) {
|
|
167718
|
+
return `Error: Memory with ID ${id} is archived or superseded; restore it before ${action2}.`;
|
|
167719
|
+
}
|
|
166832
167720
|
function queueEmbedding(args) {
|
|
166833
167721
|
const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
166834
167722
|
if (!snapshot?.enabled)
|
|
@@ -166849,7 +167737,8 @@ function queueEmbedding(args) {
|
|
|
166849
167737
|
}
|
|
166850
167738
|
function createCtxMemoryTool(deps) {
|
|
166851
167739
|
const dreamerAllowed = deps.allowDreamerActions === true;
|
|
166852
|
-
const description = dreamerAllowed ?
|
|
167740
|
+
const description = dreamerAllowed ? `${CTX_MEMORY_DESCRIPTION}
|
|
167741
|
+
- list: enumerate stored memories (maintenance sessions).` : CTX_MEMORY_DESCRIPTION;
|
|
166853
167742
|
return {
|
|
166854
167743
|
name: "ctx_memory",
|
|
166855
167744
|
label: "Magic Context: Memory",
|
|
@@ -166870,13 +167759,10 @@ function createCtxMemoryTool(deps) {
|
|
|
166870
167759
|
const content = params.content?.trim();
|
|
166871
167760
|
if (!content)
|
|
166872
167761
|
return err2("Error: 'content' is required when action is 'write'.");
|
|
166873
|
-
const rawCategory = params.category
|
|
167762
|
+
const rawCategory = params.category;
|
|
166874
167763
|
if (!rawCategory) {
|
|
166875
167764
|
return err2("Error: 'category' is required when action is 'write'.");
|
|
166876
167765
|
}
|
|
166877
|
-
if (!isMemoryCategory2(rawCategory)) {
|
|
166878
|
-
return err2(`Error: Unknown memory category '${rawCategory}'. Valid: ${CATEGORY_PRIORITY.join(", ")}`);
|
|
166879
|
-
}
|
|
166880
167766
|
const existing = getMemoryByHash(deps.db, projectIdentity, rawCategory, computeNormalizedHash(content));
|
|
166881
167767
|
if (existing) {
|
|
166882
167768
|
updateMemorySeenCount(deps.db, existing.id);
|
|
@@ -166890,45 +167776,31 @@ function createCtxMemoryTool(deps) {
|
|
|
166890
167776
|
sourceType: dreamerAllowed ? "dreamer" : "agent"
|
|
166891
167777
|
});
|
|
166892
167778
|
queueEmbedding({ deps, projectIdentity, memoryId: memory2.id, content });
|
|
166893
|
-
invalidateAllMemoryBlockCaches(deps.db);
|
|
166894
167779
|
return ok2(`Saved memory [ID: ${memory2.id}] in ${rawCategory}.`);
|
|
166895
167780
|
}
|
|
166896
|
-
if (params.action === "delete") {
|
|
166897
|
-
if (typeof params.id !== "number" || !Number.isInteger(params.id)) {
|
|
166898
|
-
return err2("Error: 'id' is required when action is 'delete'.");
|
|
166899
|
-
}
|
|
166900
|
-
const memory2 = getMemoryById(deps.db, params.id);
|
|
166901
|
-
if (!memory2 || memory2.projectPath !== projectIdentity) {
|
|
166902
|
-
return err2(`Error: Memory with ID ${params.id} was not found.`);
|
|
166903
|
-
}
|
|
166904
|
-
deps.db.transaction(() => {
|
|
166905
|
-
archiveMemory(deps.db, params.id);
|
|
166906
|
-
queueMemoryMutation(deps.db, {
|
|
166907
|
-
projectPath: projectIdentity,
|
|
166908
|
-
mutationType: "delete",
|
|
166909
|
-
targetMemoryId: params.id
|
|
166910
|
-
});
|
|
166911
|
-
})();
|
|
166912
|
-
return ok2(`Archived memory [ID: ${params.id}].`);
|
|
166913
|
-
}
|
|
166914
167781
|
if (params.action === "list") {
|
|
166915
167782
|
const limit = normalizeLimit(params.limit);
|
|
166916
167783
|
const filtered = getMemoriesByProject(deps.db, projectIdentity);
|
|
166917
|
-
const category = params.category
|
|
167784
|
+
const category = params.category;
|
|
166918
167785
|
const filtered2 = category ? filtered.filter((m) => m.category === category) : filtered;
|
|
166919
167786
|
return ok2(formatMemoryList(filtered2.slice(0, limit)));
|
|
166920
167787
|
}
|
|
166921
167788
|
if (params.action === "update") {
|
|
166922
|
-
|
|
166923
|
-
|
|
167789
|
+
const updateIds = params.ids;
|
|
167790
|
+
if (!updateIds || updateIds.length !== 1 || !updateIds.every(Number.isInteger)) {
|
|
167791
|
+
return err2("Error: 'ids' must contain exactly one integer memory ID when action is 'update'.");
|
|
166924
167792
|
}
|
|
167793
|
+
const updateId = updateIds[0];
|
|
166925
167794
|
const content = params.content?.trim();
|
|
166926
167795
|
if (!content) {
|
|
166927
167796
|
return err2("Error: 'content' is required when action is 'update'.");
|
|
166928
167797
|
}
|
|
166929
|
-
const memory2 = getMemoryById(deps.db,
|
|
166930
|
-
if (!memory2 || memory2.projectPath
|
|
166931
|
-
return err2(`Error: Memory with ID ${
|
|
167798
|
+
const memory2 = getMemoryById(deps.db, updateId);
|
|
167799
|
+
if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
|
|
167800
|
+
return err2(`Error: Memory with ID ${updateId} was not found.`);
|
|
167801
|
+
}
|
|
167802
|
+
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
167803
|
+
return err2(inactiveMemoryError(updateId, "updating"));
|
|
166932
167804
|
}
|
|
166933
167805
|
const normalizedHash = computeNormalizedHash(content);
|
|
166934
167806
|
const duplicate = getMemoryByHash(deps.db, projectIdentity, memory2.category, normalizedHash);
|
|
@@ -166949,9 +167821,12 @@ function createCtxMemoryTool(deps) {
|
|
|
166949
167821
|
return ok2(`Updated memory [ID: ${memory2.id}] in ${memory2.category}.`);
|
|
166950
167822
|
}
|
|
166951
167823
|
if (params.action === "merge") {
|
|
166952
|
-
const ids = params.ids
|
|
166953
|
-
if (!ids || ids.length < 2) {
|
|
166954
|
-
return err2("Error: 'ids' must include at least two memory IDs when action is 'merge'.");
|
|
167824
|
+
const ids = params.ids;
|
|
167825
|
+
if (!ids || ids.length < 2 || !ids.every(Number.isInteger)) {
|
|
167826
|
+
return err2("Error: 'ids' must include at least two integer memory IDs when action is 'merge'.");
|
|
167827
|
+
}
|
|
167828
|
+
if (new Set(ids).size !== ids.length) {
|
|
167829
|
+
return err2("Error: 'ids' must include at least two distinct memory IDs when action is 'merge'.");
|
|
166955
167830
|
}
|
|
166956
167831
|
const content = params.content?.trim();
|
|
166957
167832
|
if (!content) {
|
|
@@ -166961,14 +167836,17 @@ function createCtxMemoryTool(deps) {
|
|
|
166961
167836
|
if (sourceMemories.length !== ids.length) {
|
|
166962
167837
|
return err2("Error: One or more source memories were not found.");
|
|
166963
167838
|
}
|
|
166964
|
-
if (
|
|
166965
|
-
|
|
166966
|
-
|
|
166967
|
-
|
|
166968
|
-
|
|
166969
|
-
|
|
167839
|
+
if (!dreamerAllowed) {
|
|
167840
|
+
const foreign = sourceMemories.find((memory2) => !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity));
|
|
167841
|
+
if (foreign) {
|
|
167842
|
+
return err2(`Error: Memory with ID ${foreign.id} was not found.`);
|
|
167843
|
+
}
|
|
167844
|
+
const inactive = sourceMemories.find((memory2) => !isPrimaryMutableMemory(memory2));
|
|
167845
|
+
if (inactive) {
|
|
167846
|
+
return err2(inactiveMemoryError(inactive.id, "merging"));
|
|
167847
|
+
}
|
|
166970
167848
|
}
|
|
166971
|
-
const requestedCategoryTyped =
|
|
167849
|
+
const requestedCategoryTyped = params.category;
|
|
166972
167850
|
const fallbackCategory = sourceMemories[0]?.category;
|
|
166973
167851
|
const category = requestedCategoryTyped ?? fallbackCategory;
|
|
166974
167852
|
if (!category) {
|
|
@@ -167022,7 +167900,7 @@ function createCtxMemoryTool(deps) {
|
|
|
167022
167900
|
}
|
|
167023
167901
|
supersededMemory(deps.db, memory2.id, canonicalMemory.id);
|
|
167024
167902
|
queueMemoryMutation(deps.db, {
|
|
167025
|
-
projectPath: memory2.projectPath,
|
|
167903
|
+
projectPath: normalizeStoredProjectPath(memory2.projectPath),
|
|
167026
167904
|
mutationType: "superseded",
|
|
167027
167905
|
targetMemoryId: memory2.id,
|
|
167028
167906
|
supersededById: canonicalMemory.id
|
|
@@ -167030,7 +167908,7 @@ function createCtxMemoryTool(deps) {
|
|
|
167030
167908
|
}
|
|
167031
167909
|
if (canonicalExisting && canonicalContentChanged) {
|
|
167032
167910
|
queueMemoryMutation(deps.db, {
|
|
167033
|
-
projectPath: canonicalMemory.projectPath,
|
|
167911
|
+
projectPath: normalizeStoredProjectPath(canonicalMemory.projectPath),
|
|
167034
167912
|
mutationType: "update",
|
|
167035
167913
|
targetMemoryId: canonicalMemory.id,
|
|
167036
167914
|
category,
|
|
@@ -167048,29 +167926,57 @@ function createCtxMemoryTool(deps) {
|
|
|
167048
167926
|
return ok2(`Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`);
|
|
167049
167927
|
}
|
|
167050
167928
|
if (params.action === "archive") {
|
|
167051
|
-
|
|
167052
|
-
|
|
167929
|
+
const archiveIds = params.ids;
|
|
167930
|
+
if (!archiveIds || archiveIds.length === 0 || !archiveIds.every(Number.isInteger)) {
|
|
167931
|
+
return err2("Error: 'ids' must contain at least one integer memory ID when action is 'archive'.");
|
|
167053
167932
|
}
|
|
167054
|
-
const
|
|
167055
|
-
|
|
167056
|
-
|
|
167933
|
+
for (const memoryId of archiveIds) {
|
|
167934
|
+
const memory2 = getMemoryById(deps.db, memoryId);
|
|
167935
|
+
if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
|
|
167936
|
+
return err2(`Error: Memory with ID ${memoryId} was not found.`);
|
|
167937
|
+
}
|
|
167938
|
+
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
167939
|
+
return err2(inactiveMemoryError(memoryId, "archiving"));
|
|
167940
|
+
}
|
|
167057
167941
|
}
|
|
167058
167942
|
deps.db.transaction(() => {
|
|
167059
|
-
|
|
167060
|
-
|
|
167061
|
-
|
|
167062
|
-
|
|
167063
|
-
|
|
167064
|
-
|
|
167943
|
+
for (const memoryId of archiveIds) {
|
|
167944
|
+
archiveMemory(deps.db, memoryId, params.reason);
|
|
167945
|
+
queueMemoryMutation(deps.db, {
|
|
167946
|
+
projectPath: projectIdentity,
|
|
167947
|
+
mutationType: "archive",
|
|
167948
|
+
targetMemoryId: memoryId
|
|
167949
|
+
});
|
|
167950
|
+
}
|
|
167065
167951
|
})();
|
|
167066
167952
|
const reasonSuffix = params.reason ? ` (${params.reason})` : "";
|
|
167067
|
-
|
|
167953
|
+
const idList = archiveIds.join(", ");
|
|
167954
|
+
const plural = archiveIds.length > 1 ? "memories" : "memory";
|
|
167955
|
+
return ok2(`Archived ${plural} [ID: ${idList}]${reasonSuffix}.`);
|
|
167068
167956
|
}
|
|
167069
167957
|
return err2("Error: Unknown action.");
|
|
167070
167958
|
}
|
|
167071
167959
|
};
|
|
167072
167960
|
}
|
|
167073
167961
|
|
|
167962
|
+
// ../plugin/src/tools/ctx-note/constants.ts
|
|
167963
|
+
var CTX_NOTE_DESCRIPTION = `Working notes for this session's future — reminders, follow-ups, and things to revisit later.
|
|
167964
|
+
|
|
167965
|
+
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.
|
|
167966
|
+
|
|
167967
|
+
Actions:
|
|
167968
|
+
- write: save a note (content). Add surface_condition to make it a smart note (below).
|
|
167969
|
+
- 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.
|
|
167970
|
+
- update / dismiss: change or retire a note by note_id.
|
|
167971
|
+
|
|
167972
|
+
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:
|
|
167973
|
+
✓ "When PR #42 in cortexkit/magic-context is merged"
|
|
167974
|
+
✓ "When the latest release tag is >= v0.22.0"
|
|
167975
|
+
✓ "When packages/plugin/src/foo.ts contains a function named bar"
|
|
167976
|
+
✗ "When the user mentions X" / "when we revisit Y" / "after we finish this refactor" — no external signal; write a regular note instead.
|
|
167977
|
+
|
|
167978
|
+
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")`;
|
|
167979
|
+
|
|
167074
167980
|
// src/tools/ctx-note.ts
|
|
167075
167981
|
var FILTER_VALUES = [
|
|
167076
167982
|
"active",
|
|
@@ -167090,13 +167996,19 @@ var ParamsSchema3 = exports_typebox.Object({
|
|
|
167090
167996
|
})),
|
|
167091
167997
|
content: exports_typebox.Optional(exports_typebox.String({ description: "Note text to store when action is 'write'." })),
|
|
167092
167998
|
surface_condition: exports_typebox.Optional(exports_typebox.String({
|
|
167093
|
-
description: "
|
|
167999
|
+
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."
|
|
167094
168000
|
})),
|
|
167095
168001
|
note_id: exports_typebox.Optional(exports_typebox.Number({
|
|
167096
168002
|
description: "Note ID (required for 'dismiss' and 'update' actions)."
|
|
167097
168003
|
})),
|
|
167098
168004
|
filter: exports_typebox.Optional(exports_typebox.Union(FILTER_VALUES.map((value) => exports_typebox.Literal(value)), {
|
|
167099
168005
|
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."
|
|
168006
|
+
})),
|
|
168007
|
+
limit: exports_typebox.Optional(exports_typebox.Number({
|
|
168008
|
+
description: "Max notes per section for read, newest first (default: 25)"
|
|
168009
|
+
})),
|
|
168010
|
+
offset: exports_typebox.Optional(exports_typebox.Number({
|
|
168011
|
+
description: "Skip this many newest notes for read — page older ones (default: 0)"
|
|
167100
168012
|
}))
|
|
167101
168013
|
});
|
|
167102
168014
|
function ok3(text) {
|
|
@@ -167133,15 +168045,20 @@ function formatNoteLine(note) {
|
|
|
167133
168045
|
var DISMISS_FOOTER = `
|
|
167134
168046
|
|
|
167135
168047
|
To dismiss a stale note: ctx_note(action="dismiss", note_id=N)`;
|
|
168048
|
+
var DEFAULT_READ_LIMIT = 25;
|
|
168049
|
+
function paginateNewestFirst(notes, limit, offset) {
|
|
168050
|
+
const total = notes.length;
|
|
168051
|
+
const newestFirst = [...notes].reverse();
|
|
168052
|
+
const page = newestFirst.slice(offset, offset + limit);
|
|
168053
|
+
const remaining = total - offset - page.length;
|
|
168054
|
+
const footer = remaining > 0 ? `Showing ${page.length} of ${total} (newest first) — ${remaining} older: ctx_note(action="read", offset=${offset + page.length})` : null;
|
|
168055
|
+
return { page, total, footer };
|
|
168056
|
+
}
|
|
167136
168057
|
function createCtxNoteTool(deps) {
|
|
167137
168058
|
return {
|
|
167138
168059
|
name: "ctx_note",
|
|
167139
168060
|
label: "Magic Context: Notes",
|
|
167140
|
-
description:
|
|
167141
|
-
` + `Use this for short goals, constraints, decisions, or reminders worth carrying forward.
|
|
167142
|
-
|
|
167143
|
-
` + `Actions:
|
|
167144
|
-
` + "- `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")`',
|
|
168061
|
+
description: CTX_NOTE_DESCRIPTION,
|
|
167145
168062
|
parameters: ParamsSchema3,
|
|
167146
168063
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
167147
168064
|
const sessionId = ctx.sessionManager.getSessionId();
|
|
@@ -167223,11 +168140,15 @@ function createCtxNoteTool(deps) {
|
|
|
167223
168140
|
- ${parts.join(`
|
|
167224
168141
|
- `)}`);
|
|
167225
168142
|
}
|
|
168143
|
+
const limit = typeof params.limit === "number" && params.limit > 0 ? Math.floor(params.limit) : DEFAULT_READ_LIMIT;
|
|
168144
|
+
const offset = typeof params.offset === "number" && params.offset > 0 ? Math.floor(params.offset) : 0;
|
|
167226
168145
|
const sections = readNotes({
|
|
167227
168146
|
db: deps.db,
|
|
167228
168147
|
sessionId,
|
|
167229
168148
|
cwd: ctx.cwd,
|
|
167230
|
-
filter: params.filter
|
|
168149
|
+
filter: params.filter,
|
|
168150
|
+
limit,
|
|
168151
|
+
offset
|
|
167231
168152
|
});
|
|
167232
168153
|
try {
|
|
167233
168154
|
setNoteLastReadAt(deps.db, sessionId);
|
|
@@ -167235,7 +168156,7 @@ function createCtxNoteTool(deps) {
|
|
|
167235
168156
|
if (sections.length === 0) {
|
|
167236
168157
|
return ok3(`## Notes
|
|
167237
168158
|
|
|
167238
|
-
No notes
|
|
168159
|
+
No session notes or smart notes.`);
|
|
167239
168160
|
}
|
|
167240
168161
|
const body = sections.join(`
|
|
167241
168162
|
|
|
@@ -167262,10 +168183,14 @@ function readNotes(args) {
|
|
|
167262
168183
|
}) : [];
|
|
167263
168184
|
const sections2 = [];
|
|
167264
168185
|
if (sessionNotes2.length > 0) {
|
|
168186
|
+
const { page, footer } = paginateNewestFirst(sessionNotes2, args.limit, args.offset);
|
|
168187
|
+
const lines = page.map(formatNoteLine).join(`
|
|
168188
|
+
`);
|
|
167265
168189
|
sections2.push(`## Session Notes
|
|
167266
168190
|
|
|
167267
|
-
${
|
|
167268
|
-
|
|
168191
|
+
${lines}${footer ? `
|
|
168192
|
+
|
|
168193
|
+
${footer}` : ""}`);
|
|
167269
168194
|
}
|
|
167270
168195
|
if (readySmartNotes.length > 0) {
|
|
167271
168196
|
sections2.push(`## \uD83D\uDD14 Ready Smart Notes
|
|
@@ -167296,17 +168221,25 @@ ${readySmartNotes.map(formatNoteLine).join(`
|
|
|
167296
168221
|
}) : [];
|
|
167297
168222
|
const sections = [];
|
|
167298
168223
|
if (sessionNotes.length > 0) {
|
|
168224
|
+
const { page, footer } = paginateNewestFirst(sessionNotes, args.limit, args.offset);
|
|
168225
|
+
const lines = page.map(formatNoteLine).join(`
|
|
168226
|
+
`);
|
|
167299
168227
|
sections.push(`## Session Notes
|
|
167300
168228
|
|
|
167301
|
-
${
|
|
167302
|
-
|
|
168229
|
+
${lines}${footer ? `
|
|
168230
|
+
|
|
168231
|
+
${footer}` : ""}`);
|
|
167303
168232
|
}
|
|
167304
168233
|
if (smartNotes.length > 0) {
|
|
168234
|
+
const { page, footer } = paginateNewestFirst(smartNotes, args.limit, args.offset);
|
|
168235
|
+
const lines = page.map(formatNoteLine).join(`
|
|
168236
|
+
|
|
168237
|
+
`);
|
|
167305
168238
|
sections.push(`## Smart Notes
|
|
167306
168239
|
|
|
167307
|
-
${
|
|
168240
|
+
${lines}${footer ? `
|
|
167308
168241
|
|
|
167309
|
-
`
|
|
168242
|
+
${footer}` : ""}`);
|
|
167310
168243
|
}
|
|
167311
168244
|
return sections;
|
|
167312
168245
|
}
|
|
@@ -167314,7 +168247,7 @@ ${smartNotes.map(formatNoteLine).join(`
|
|
|
167314
168247
|
// ../plugin/src/features/magic-context/range-parser.ts
|
|
167315
168248
|
function parseRangeString(input) {
|
|
167316
168249
|
const maxRangeElements = 1000;
|
|
167317
|
-
const trimmed = input.trim();
|
|
168250
|
+
const trimmed = input.replace(/§/g, "").trim();
|
|
167318
168251
|
if (trimmed === "") {
|
|
167319
168252
|
throw new Error("Range string must not be empty");
|
|
167320
168253
|
}
|
|
@@ -168504,6 +169437,9 @@ function escapeXmlAttr2(s) {
|
|
|
168504
169437
|
function escapeXmlContent2(s) {
|
|
168505
169438
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
168506
169439
|
}
|
|
169440
|
+
function isTieredRow(c) {
|
|
169441
|
+
return typeof c.p1 === "string" && c.p1.length > 0;
|
|
169442
|
+
}
|
|
168507
169443
|
function tierBody(c, tier2) {
|
|
168508
169444
|
const tiers = [c.p1, c.p2, c.p3, c.p4];
|
|
168509
169445
|
const requested = tiers[tier2 - 1];
|
|
@@ -168533,12 +169469,13 @@ function renderOneCompartment(c, tier2) {
|
|
|
168533
169469
|
const baseAttrs = `start="${c.startMessage}" end="${c.endMessage}" title="${escapeXmlAttr2(c.title)}"`;
|
|
168534
169470
|
if (tier2 >= 5)
|
|
168535
169471
|
return "";
|
|
168536
|
-
if (c.legacy === 1) {
|
|
168537
|
-
|
|
169472
|
+
if (c.legacy === 1 || !isTieredRow(c)) {
|
|
169473
|
+
const flat = (c.content ?? "").trim();
|
|
169474
|
+
if (tier2 >= 4 || flat.length === 0)
|
|
168538
169475
|
return `<compartment ${baseAttrs} />`;
|
|
168539
169476
|
return [
|
|
168540
169477
|
`<compartment ${baseAttrs}>`,
|
|
168541
|
-
escapeXmlContent2(legacyBodyForTier(
|
|
169478
|
+
escapeXmlContent2(legacyBodyForTier(flat, tier2)),
|
|
168542
169479
|
"</compartment>"
|
|
168543
169480
|
].join(`
|
|
168544
169481
|
`);
|
|
@@ -168615,26 +169552,58 @@ import { join as join9, sep as sep2 } from "node:path";
|
|
|
168615
169552
|
var import_comment_json2 = __toESM(require_src2(), 1);
|
|
168616
169553
|
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "node:fs";
|
|
168617
169554
|
import { homedir as homedir4 } from "node:os";
|
|
168618
|
-
import { join as join8 } from "node:path";
|
|
169555
|
+
import { isAbsolute as isAbsolute2, join as join8, resolve as resolve3 } from "node:path";
|
|
169556
|
+
import { fileURLToPath } from "node:url";
|
|
168619
169557
|
var overrideAvailability = null;
|
|
168620
169558
|
function parseConfig(path5) {
|
|
168621
169559
|
if (!existsSync7(path5))
|
|
168622
169560
|
return null;
|
|
168623
169561
|
return import_comment_json2.parse(readFileSync5(path5, "utf-8"));
|
|
168624
169562
|
}
|
|
168625
|
-
|
|
169563
|
+
var AFT_NAME_NEEDLES = ["@cortexkit/aft", "aft-opencode", "aft-pi"];
|
|
169564
|
+
function stringMentionsAft(value) {
|
|
169565
|
+
return AFT_NAME_NEEDLES.some((needle) => value.includes(needle));
|
|
169566
|
+
}
|
|
169567
|
+
function resolveLocalEntryPackageName(value, configDir) {
|
|
169568
|
+
let dir = null;
|
|
169569
|
+
if (value.startsWith("file://")) {
|
|
169570
|
+
try {
|
|
169571
|
+
dir = fileURLToPath(value);
|
|
169572
|
+
} catch {
|
|
169573
|
+
return null;
|
|
169574
|
+
}
|
|
169575
|
+
} else if (value.startsWith("~/")) {
|
|
169576
|
+
dir = join8(homedir4(), value.slice(2));
|
|
169577
|
+
} else if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../")) {
|
|
169578
|
+
dir = isAbsolute2(value) ? value : resolve3(configDir, value);
|
|
169579
|
+
} else {
|
|
169580
|
+
return null;
|
|
169581
|
+
}
|
|
169582
|
+
try {
|
|
169583
|
+
const pkg = JSON.parse(readFileSync5(join8(dir, "package.json"), "utf-8"));
|
|
169584
|
+
return typeof pkg.name === "string" ? pkg.name : null;
|
|
169585
|
+
} catch {
|
|
169586
|
+
return null;
|
|
169587
|
+
}
|
|
169588
|
+
}
|
|
169589
|
+
function entryMatchesAft(entry, configDir) {
|
|
168626
169590
|
const value = Array.isArray(entry) ? entry[0] : entry;
|
|
168627
|
-
|
|
169591
|
+
if (typeof value !== "string")
|
|
169592
|
+
return false;
|
|
169593
|
+
if (stringMentionsAft(value))
|
|
169594
|
+
return true;
|
|
169595
|
+
const name2 = resolveLocalEntryPackageName(value, configDir);
|
|
169596
|
+
return name2 != null && stringMentionsAft(name2);
|
|
168628
169597
|
}
|
|
168629
|
-
function hasAftInArray(value) {
|
|
168630
|
-
return Array.isArray(value) && value.some(entryMatchesAft);
|
|
169598
|
+
function hasAftInArray(value, configDir) {
|
|
169599
|
+
return Array.isArray(value) && value.some((entry) => entryMatchesAft(entry, configDir));
|
|
168631
169600
|
}
|
|
168632
|
-
function hasAftAtKeys(value, keys2) {
|
|
169601
|
+
function hasAftAtKeys(value, keys2, configDir) {
|
|
168633
169602
|
if (!value || typeof value !== "object")
|
|
168634
169603
|
return false;
|
|
168635
169604
|
const record4 = value;
|
|
168636
169605
|
for (const key of keys2) {
|
|
168637
|
-
if (hasAftInArray(record4[key]))
|
|
169606
|
+
if (hasAftInArray(record4[key], configDir))
|
|
168638
169607
|
return true;
|
|
168639
169608
|
}
|
|
168640
169609
|
return false;
|
|
@@ -168651,7 +169620,8 @@ function getAftAvailability() {
|
|
|
168651
169620
|
for (const path5 of opencodePaths) {
|
|
168652
169621
|
try {
|
|
168653
169622
|
const config2 = parseConfig(path5);
|
|
168654
|
-
|
|
169623
|
+
const configDir = join8(path5, "..");
|
|
169624
|
+
if (hasAftAtKeys(config2, ["plugin", "plugins", "mcp", "mcp_servers"], configDir)) {
|
|
168655
169625
|
opencode = true;
|
|
168656
169626
|
break;
|
|
168657
169627
|
}
|
|
@@ -168661,12 +169631,13 @@ function getAftAvailability() {
|
|
|
168661
169631
|
for (const path5 of piPaths) {
|
|
168662
169632
|
try {
|
|
168663
169633
|
const config2 = parseConfig(path5);
|
|
168664
|
-
|
|
169634
|
+
const configDir = join8(path5, "..");
|
|
169635
|
+
if (hasAftAtKeys(config2, ["packages", "extensions"], configDir)) {
|
|
168665
169636
|
pi = true;
|
|
168666
169637
|
break;
|
|
168667
169638
|
}
|
|
168668
169639
|
const agent = config2?.agent;
|
|
168669
|
-
if (hasAftAtKeys(agent, ["packages", "extensions"])) {
|
|
169640
|
+
if (hasAftAtKeys(agent, ["packages", "extensions"], configDir)) {
|
|
168670
169641
|
pi = true;
|
|
168671
169642
|
break;
|
|
168672
169643
|
}
|
|
@@ -168783,9 +169754,6 @@ ${blocks.join(`
|
|
|
168783
169754
|
return rendered;
|
|
168784
169755
|
}
|
|
168785
169756
|
|
|
168786
|
-
// ../plugin/src/hooks/magic-context/inject-compartments.ts
|
|
168787
|
-
await init_read_session_db();
|
|
168788
|
-
|
|
168789
169757
|
// ../plugin/src/hooks/magic-context/temporal-awareness.ts
|
|
168790
169758
|
var TEMPORAL_AWARENESS_THRESHOLD_SECONDS = 300;
|
|
168791
169759
|
var SECONDS_PER_MINUTE = 60;
|
|
@@ -168942,6 +169910,21 @@ function renderMemoryBlockV2(memories, wrapper = "project-memory") {
|
|
|
168942
169910
|
`);
|
|
168943
169911
|
}
|
|
168944
169912
|
|
|
169913
|
+
// ../plugin/src/tools/ctx-search/constants.ts
|
|
169914
|
+
var CTX_SEARCH_DESCRIPTION = `Your long-term recall for this project — search everything that ever happened here, not just what's currently visible.
|
|
169915
|
+
|
|
169916
|
+
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.
|
|
169917
|
+
|
|
169918
|
+
Sources (omit for a broad search across all):
|
|
169919
|
+
- memory: curated cross-session project knowledge — rules, constraints, conventions.
|
|
169920
|
+
- 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).
|
|
169921
|
+
- git_commit: this repository's commit history.
|
|
169922
|
+
|
|
169923
|
+
Picking sources:
|
|
169924
|
+
- "when did this change / was this working before" → ["git_commit", "message"]
|
|
169925
|
+
- "did we discuss this earlier" → ["message"]
|
|
169926
|
+
- "what's our convention / rule for X" → ["memory"]`;
|
|
169927
|
+
|
|
168945
169928
|
// src/tools/ctx-search.ts
|
|
168946
169929
|
var DEFAULT_LIMIT = 10;
|
|
168947
169930
|
var ParamsSchema5 = exports_typebox.Object({
|
|
@@ -169025,18 +170008,7 @@ function createCtxSearchTool(deps) {
|
|
|
169025
170008
|
return {
|
|
169026
170009
|
name: "ctx_search",
|
|
169027
170010
|
label: "Magic Context: Search",
|
|
169028
|
-
description:
|
|
169029
|
-
|
|
169030
|
-
` + `Sources:
|
|
169031
|
-
` + `- memory: curated cross-session knowledge for this project
|
|
169032
|
-
` + `- message: raw user/assistant messages from older compartmentalized history
|
|
169033
|
-
` + `- git_commit: HEAD git commits (when git commit indexing is enabled)
|
|
169034
|
-
|
|
169035
|
-
` + "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"]
|
|
169036
|
-
` + `- "when did we change this" → ["git_commit"]
|
|
169037
|
-
` + `- "what is our naming convention" → ["memory"]
|
|
169038
|
-
` + `- "did we discuss this earlier" → ["message"]
|
|
169039
|
-
` + "Omit sources for a broad search across all enabled channels.",
|
|
170011
|
+
description: CTX_SEARCH_DESCRIPTION,
|
|
169040
170012
|
parameters: ParamsSchema5,
|
|
169041
170013
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
169042
170014
|
const query = params.query?.trim();
|
|
@@ -169055,6 +170027,7 @@ function createCtxSearchTool(deps) {
|
|
|
169055
170027
|
const embeddingEnabled = snapshot ? snapshot.enabled || snapshot.gitCommitEnabled : deps.embeddingEnabled;
|
|
169056
170028
|
const gitCommitsEnabled = snapshot?.gitCommitEnabled ?? deps.gitCommitsEnabled ?? false;
|
|
169057
170029
|
const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, sessionId);
|
|
170030
|
+
const messageOrdinalCutoff = lastCompartmentEnd >= 0 ? lastCompartmentEnd : 0;
|
|
169058
170031
|
const visibleMemoryIds = getVisibleMemoryIds(deps.db, sessionId);
|
|
169059
170032
|
const results = await unifiedSearch(deps.db, sessionId, projectIdentity, query, {
|
|
169060
170033
|
limit: normalizeLimit3(params.limit),
|
|
@@ -169065,7 +170038,7 @@ function createCtxSearchTool(deps) {
|
|
|
169065
170038
|
return result?.vector ?? null;
|
|
169066
170039
|
},
|
|
169067
170040
|
isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
|
|
169068
|
-
maxMessageOrdinal:
|
|
170041
|
+
maxMessageOrdinal: messageOrdinalCutoff,
|
|
169069
170042
|
gitCommitsEnabled,
|
|
169070
170043
|
sources: params.sources,
|
|
169071
170044
|
visibleMemoryIds,
|
|
@@ -169152,13 +170125,15 @@ function registerMagicContextTools(pi, opts) {
|
|
|
169152
170125
|
embeddingEnabled: opts.embeddingEnabled,
|
|
169153
170126
|
gitCommitsEnabled: opts.gitCommitsEnabled
|
|
169154
170127
|
}));
|
|
169155
|
-
|
|
169156
|
-
|
|
169157
|
-
|
|
169158
|
-
|
|
169159
|
-
|
|
169160
|
-
|
|
169161
|
-
|
|
170128
|
+
if (opts.memoryToolEnabled !== false) {
|
|
170129
|
+
pi.registerTool(createCtxMemoryTool({
|
|
170130
|
+
db: opts.db,
|
|
170131
|
+
ensureProjectRegistered: opts.ensureProjectRegistered,
|
|
170132
|
+
memoryEnabled: opts.memoryEnabled,
|
|
170133
|
+
embeddingEnabled: opts.embeddingEnabled,
|
|
170134
|
+
allowDreamerActions: opts.allowDreamerActions ?? false
|
|
170135
|
+
}));
|
|
170136
|
+
}
|
|
169162
170137
|
if (!opts.sessionScopedToolsDisabled) {
|
|
169163
170138
|
pi.registerTool(createCtxNoteTool({
|
|
169164
170139
|
db: opts.db,
|
|
@@ -169181,7 +170156,7 @@ var openedDb;
|
|
|
169181
170156
|
function magicContextSubagentExtension(pi) {
|
|
169182
170157
|
setHarness("pi");
|
|
169183
170158
|
pi.registerFlag(SUBAGENT_DREAMER_ACTIONS_FLAG, {
|
|
169184
|
-
description: "
|
|
170159
|
+
description: "Register ctx_memory with dreamer actions for Magic Context subagents.",
|
|
169185
170160
|
type: "boolean",
|
|
169186
170161
|
default: false
|
|
169187
170162
|
});
|
|
@@ -169199,10 +170174,11 @@ function magicContextSubagentExtension(pi) {
|
|
|
169199
170174
|
registerMagicContextTools(pi, {
|
|
169200
170175
|
db,
|
|
169201
170176
|
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
170177
|
+
memoryToolEnabled: dreamerActionsEnabled,
|
|
169202
170178
|
allowDreamerActions: dreamerActionsEnabled,
|
|
169203
170179
|
sessionScopedToolsDisabled: true
|
|
169204
170180
|
});
|
|
169205
|
-
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})`);
|
|
170181
|
+
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})`);
|
|
169206
170182
|
} catch (err5) {
|
|
169207
170183
|
const message = err5 instanceof Error ? err5.message : String(err5);
|
|
169208
170184
|
log(`[pi-subagent] startup failed: ${message}`);
|