@cortexkit/pi-magic-context 0.45.0 → 0.46.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/embedding-worker.js +4 -4
- package/dist/{index-j0mbc5vj.js → index-266qrgss.js} +59 -1
- package/dist/index-2p1e8706.js +30 -0
- package/dist/{index-k0yd1ph9.js → index-4vfrjwf6.js} +129 -166
- package/dist/{index-g0xfx1c2.js → index-phh7e055.js} +16 -1
- package/dist/{index-ttf0cqq8.js → index-r01b1b78.js} +25 -24
- package/dist/index-td885aah.js +576 -0
- package/dist/index-vf38qhee.js +150 -0
- package/dist/{index-2pbbk3en.js → index-wv28nczk.js} +55 -1
- package/dist/{index-vxjgsr9m.js → index-xvw8zptx.js} +3565 -3349
- package/dist/{index-2bw9k8nx.js → index-ykb8kkm3.js} +1310 -1021
- package/dist/index.js +3309 -1480
- package/dist/{message-time-backfill-g83dkh8m.js → message-time-backfill-4688z1k2.js} +2 -2
- package/dist/migration-worker.js +11 -6
- package/dist/{read-session-chunk-kmt7a6zj.js → read-session-chunk-tc6yn2pe.js} +5 -5
- package/dist/subagent-entry.js +10 -10
- package/package.json +4 -3
- package/dist/index-4d3cba70.js +0 -10
- package/dist/index-7s5yk3za.js +0 -16
- package/dist/index-e16q5sd7.js +0 -240
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sessionLog
|
|
3
|
+
} from "./index-7n8gb6j3.js";
|
|
4
|
+
|
|
5
|
+
// ../plugin/src/shared/sqlite-helpers.ts
|
|
6
|
+
function closeQuietly(db) {
|
|
7
|
+
if (!db)
|
|
8
|
+
return;
|
|
9
|
+
try {
|
|
10
|
+
db.close();
|
|
11
|
+
} catch {}
|
|
12
|
+
}
|
|
13
|
+
function isKnownAutocommit(db) {
|
|
14
|
+
const state = db;
|
|
15
|
+
try {
|
|
16
|
+
return state.inTransaction === false || state.isTransaction === false;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ../plugin/src/shared/stable-json.ts
|
|
23
|
+
function stableStringify(value, seen = new WeakSet) {
|
|
24
|
+
if (value === undefined)
|
|
25
|
+
return "undefined";
|
|
26
|
+
if (value === null || typeof value !== "object")
|
|
27
|
+
return JSON.stringify(value) ?? String(value);
|
|
28
|
+
if (seen.has(value))
|
|
29
|
+
return '"[Circular]"';
|
|
30
|
+
seen.add(value);
|
|
31
|
+
if (Array.isArray(value)) {
|
|
32
|
+
return `[${value.map((item) => stableStringify(item, seen)).join(",")}]`;
|
|
33
|
+
}
|
|
34
|
+
const entries = Object.entries(value).sort(([a], [b]) => {
|
|
35
|
+
if (a < b)
|
|
36
|
+
return -1;
|
|
37
|
+
if (a > b)
|
|
38
|
+
return 1;
|
|
39
|
+
return 0;
|
|
40
|
+
});
|
|
41
|
+
return `{${entries.map(([key, child]) => `${JSON.stringify(key)}:${stableStringify(child, seen)}`).join(",")}}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ../plugin/src/features/magic-context/storage-schema-helpers.ts
|
|
45
|
+
var columnCaches = new WeakMap;
|
|
46
|
+
function readColumnNames(db, table) {
|
|
47
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
48
|
+
return new Set(rows.flatMap((row) => typeof row.name === "string" ? [row.name] : []));
|
|
49
|
+
}
|
|
50
|
+
function columnNames(db, table) {
|
|
51
|
+
if (!isKnownAutocommit(db)) {
|
|
52
|
+
columnCaches.delete(db);
|
|
53
|
+
return readColumnNames(db, table);
|
|
54
|
+
}
|
|
55
|
+
let cache = columnCaches.get(db);
|
|
56
|
+
if (!cache) {
|
|
57
|
+
cache = { version: -1, stamp: db.prepare("PRAGMA schema_version"), tables: new Map };
|
|
58
|
+
columnCaches.set(db, cache);
|
|
59
|
+
}
|
|
60
|
+
const [{ schema_version: version }] = cache.stamp.all();
|
|
61
|
+
if (version !== cache.version) {
|
|
62
|
+
cache.tables.clear();
|
|
63
|
+
cache.version = version;
|
|
64
|
+
}
|
|
65
|
+
let columns = cache.tables.get(table);
|
|
66
|
+
if (!columns) {
|
|
67
|
+
columns = readColumnNames(db, table);
|
|
68
|
+
cache.tables.set(table, columns);
|
|
69
|
+
}
|
|
70
|
+
return columns;
|
|
71
|
+
}
|
|
72
|
+
function getTableColumnNames(db, table) {
|
|
73
|
+
if (!/^[a-z][a-z0-9_]*$/.test(table))
|
|
74
|
+
throw new Error(`Unsafe schema identifier: ${table}`);
|
|
75
|
+
return columnNames(db, table);
|
|
76
|
+
}
|
|
77
|
+
function ensureColumn(db, table, column, definition) {
|
|
78
|
+
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_"'(),[\]\s]+$/i.test(definition)) {
|
|
79
|
+
throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
|
|
80
|
+
}
|
|
81
|
+
if (columnNames(db, table).has(column)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
|
|
86
|
+
} catch (err) {
|
|
87
|
+
columnCaches.delete(db);
|
|
88
|
+
const recheck = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
89
|
+
if (recheck.some((row) => row.name === column)) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
throw err;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function healAllNullColumns(db) {
|
|
96
|
+
const existingColumns = getSessionMetaColumns(db);
|
|
97
|
+
const fallbacks = [
|
|
98
|
+
["cache_ttl", ""],
|
|
99
|
+
["last_nudge_band", ""],
|
|
100
|
+
["last_nudge_level", ""],
|
|
101
|
+
["channel2_nudge_claim_token", ""],
|
|
102
|
+
["last_transform_error", ""],
|
|
103
|
+
["nudge_anchor_message_id", ""],
|
|
104
|
+
["nudge_anchor_text", ""],
|
|
105
|
+
["sticky_turn_reminder_text", ""],
|
|
106
|
+
["sticky_turn_reminder_message_id", ""],
|
|
107
|
+
["note_nudge_trigger_message_id", ""],
|
|
108
|
+
["note_nudge_sticky_text", ""],
|
|
109
|
+
["note_nudge_sticky_message_id", ""],
|
|
110
|
+
["last_todo_state", ""],
|
|
111
|
+
["todo_synthetic_call_id", ""],
|
|
112
|
+
["todo_synthetic_anchor_message_id", ""],
|
|
113
|
+
["todo_synthetic_state_json", ""],
|
|
114
|
+
["system_prompt_hash", ""],
|
|
115
|
+
["stripped_placeholder_ids", ""],
|
|
116
|
+
["stale_reduce_stripped_ids", ""],
|
|
117
|
+
["processed_image_stripped_ids", ""],
|
|
118
|
+
["merged_reasoning_stripped_ids", ""],
|
|
119
|
+
["thinking_binding_recovery_target", ""],
|
|
120
|
+
["trailing_blank_decisions", ""],
|
|
121
|
+
["memory_block_cache", ""],
|
|
122
|
+
["memory_block_ids", ""],
|
|
123
|
+
["compaction_marker_state", ""],
|
|
124
|
+
["key_files", ""],
|
|
125
|
+
["times_execute_threshold_reached", 0],
|
|
126
|
+
["compartment_in_progress", 0],
|
|
127
|
+
["historian_failure_count", 0],
|
|
128
|
+
["cleared_reasoning_through_tag", 0],
|
|
129
|
+
["memory_block_count", 0],
|
|
130
|
+
["system_prompt_tokens", 0],
|
|
131
|
+
["conversation_tokens", 0],
|
|
132
|
+
["tool_call_tokens", 0],
|
|
133
|
+
["note_nudge_trigger_pending", 0],
|
|
134
|
+
["observed_safe_input_tokens", 0],
|
|
135
|
+
["cache_alert_sent", 0],
|
|
136
|
+
["new_work_tokens", 0],
|
|
137
|
+
["total_input_tokens", 0],
|
|
138
|
+
["last_emergency_input_sample", 0],
|
|
139
|
+
["channel2_nudge_claimed_at", 0],
|
|
140
|
+
["last_usage_context_limit", 0],
|
|
141
|
+
["prior_boundary_ordinal", 1],
|
|
142
|
+
["protected_tail_policy_version", 0],
|
|
143
|
+
["protected_tail_drain_window_started_at", 0],
|
|
144
|
+
["protected_tail_drain_tokens", 0],
|
|
145
|
+
["recovery_no_eligible_head_count", 0],
|
|
146
|
+
["force_emergency_bypass_window_start", 0],
|
|
147
|
+
["force_emergency_bypass_used", 0],
|
|
148
|
+
["emergency_drain_active", 0],
|
|
149
|
+
["historian_drain_failure_at", 0]
|
|
150
|
+
];
|
|
151
|
+
const presentFallbacks = fallbacks.filter(([column]) => existingColumns.has(column));
|
|
152
|
+
if (presentFallbacks.length > 0) {
|
|
153
|
+
const assignments = presentFallbacks.map(([column]) => `${column} = COALESCE(${column}, ?)`).join(", ");
|
|
154
|
+
const nullPredicate = presentFallbacks.map(([column]) => `${column} IS NULL`).join(" OR ");
|
|
155
|
+
db.prepare(`UPDATE session_meta SET ${assignments} WHERE ${nullPredicate}`).run(...presentFallbacks.map(([, fallback]) => fallback));
|
|
156
|
+
}
|
|
157
|
+
healMissingMemoryBlockIds(db, existingColumns);
|
|
158
|
+
}
|
|
159
|
+
function getSessionMetaColumns(db) {
|
|
160
|
+
const rows = db.prepare("PRAGMA table_info(session_meta)").all();
|
|
161
|
+
return new Set(rows.flatMap((row) => typeof row.name === "string" ? [row.name] : []));
|
|
162
|
+
}
|
|
163
|
+
function healMissingMemoryBlockIds(db, columns) {
|
|
164
|
+
if (!columns.has("memory_block_cache") || !columns.has("memory_block_ids") || !columns.has("memory_block_count")) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
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();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ../plugin/src/features/magic-context/temporal-decisions.ts
|
|
171
|
+
var PREFIX = "temporal-message-v1:";
|
|
172
|
+
function decodeTemporalDecision(entry) {
|
|
173
|
+
if (!entry.startsWith(PREFIX))
|
|
174
|
+
return null;
|
|
175
|
+
try {
|
|
176
|
+
const pair = JSON.parse(entry.slice(PREFIX.length));
|
|
177
|
+
if (Array.isArray(pair) && pair.length === 2 && typeof pair[0] === "string" && pair[0] && typeof pair[1] === "string")
|
|
178
|
+
return [pair[0], pair[1]];
|
|
179
|
+
} catch {}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
function readRows(db, sessionId, messageIds) {
|
|
183
|
+
if (!messageIds)
|
|
184
|
+
return db.prepare("SELECT message_id,marker FROM temporal_decisions WHERE session_id=?").all(sessionId);
|
|
185
|
+
const ids = [...messageIds];
|
|
186
|
+
const result = [];
|
|
187
|
+
for (let offset = 0;offset < ids.length; offset += 400) {
|
|
188
|
+
const chunk = ids.slice(offset, offset + 400);
|
|
189
|
+
result.push(...db.prepare(`SELECT message_id,marker FROM temporal_decisions WHERE session_id=? AND message_id IN (${chunk.map(() => "?").join(",")})`).all(sessionId, ...chunk));
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
function getTemporalDecisions(db, sessionId, messageIds) {
|
|
194
|
+
return new Map(readRows(db, sessionId, messageIds).flatMap((row) => row.marker === null ? [] : [[row.message_id, row.marker]]));
|
|
195
|
+
}
|
|
196
|
+
function observeTemporalDecisions(db, sessionId, candidates, previouslyServed, messageIds) {
|
|
197
|
+
const ids = new Set([...candidates.keys(), ...messageIds ?? []]);
|
|
198
|
+
const rows = readRows(db, sessionId, ids);
|
|
199
|
+
const known = new Set(rows.map((row) => row.message_id));
|
|
200
|
+
const missing = [...candidates].filter(([id]) => !known.has(id));
|
|
201
|
+
if (!missing.length)
|
|
202
|
+
return new Map(rows.flatMap((row) => row.marker === null ? [] : [[row.message_id, row.marker]]));
|
|
203
|
+
const transient = new Map;
|
|
204
|
+
db.transaction(() => {
|
|
205
|
+
const insert = db.prepare("INSERT OR IGNORE INTO temporal_decisions(session_id,message_id,marker) VALUES (?,?,?)");
|
|
206
|
+
const servedTag = db.prepare("SELECT 1 FROM tags WHERE session_id=? AND message_id=? UNION ALL SELECT 1 FROM tags WHERE session_id=? AND message_id>=? AND message_id<? LIMIT 1");
|
|
207
|
+
let served;
|
|
208
|
+
for (const [id, candidate] of missing) {
|
|
209
|
+
const historical = servedTag.get(sessionId, id, sessionId, `${id}:p`, `${id}:q`);
|
|
210
|
+
if (historical) {
|
|
211
|
+
served ??= previouslyServed?.(missing.map(([missingId]) => missingId)) ?? new Map;
|
|
212
|
+
const previous = served.get(id);
|
|
213
|
+
if (previous === undefined) {
|
|
214
|
+
transient.set(id, candidate);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
insert.run(sessionId, id, previous === "" && candidate !== "" ? null : previous);
|
|
218
|
+
} else {
|
|
219
|
+
insert.run(sessionId, id, null);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}).immediate();
|
|
223
|
+
return new Map([...transient, ...getTemporalDecisions(db, sessionId, ids)]);
|
|
224
|
+
}
|
|
225
|
+
function freezeTemporalDecisions(db, sessionId, candidates) {
|
|
226
|
+
if (candidates.size === 0)
|
|
227
|
+
return new Map;
|
|
228
|
+
return db.transaction(() => {
|
|
229
|
+
const insert = db.prepare("INSERT INTO temporal_decisions(session_id,message_id,marker) VALUES (?,?,?) ON CONFLICT(session_id,message_id) DO UPDATE SET marker=excluded.marker WHERE temporal_decisions.marker IS NULL");
|
|
230
|
+
for (const [id, marker] of candidates) {
|
|
231
|
+
insert.run(sessionId, id, marker);
|
|
232
|
+
}
|
|
233
|
+
return getTemporalDecisions(db, sessionId, candidates.keys());
|
|
234
|
+
}).immediate();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ../plugin/src/features/magic-context/migration-v95-perf-indexes.ts
|
|
238
|
+
var TEMPORAL_DECISIONS_DDL = `CREATE TABLE temporal_decisions (
|
|
239
|
+
session_id TEXT NOT NULL,
|
|
240
|
+
message_id TEXT NOT NULL,
|
|
241
|
+
marker TEXT,
|
|
242
|
+
PRIMARY KEY (session_id, message_id)
|
|
243
|
+
) WITHOUT ROWID`;
|
|
244
|
+
var indexes = [
|
|
245
|
+
["message_fts_rowid_map", "idx_message_fts_rowid_map_session_rowid", "session_id, fts_rowid"],
|
|
246
|
+
["transform_decisions", "idx_transform_decisions_retention", "session_id, harness, ts_ms"],
|
|
247
|
+
["plugin_messages", "idx_plugin_messages_session", "session_id"],
|
|
248
|
+
["user_memory_candidates", "idx_user_memory_candidates_session", "session_id"]
|
|
249
|
+
];
|
|
250
|
+
var V95_REDUNDANT_INDEXES = [
|
|
251
|
+
"idx_tags_session_tag_number",
|
|
252
|
+
"idx_compartments_session",
|
|
253
|
+
"idx_pending_ops_session",
|
|
254
|
+
"idx_source_contents_session",
|
|
255
|
+
"idx_compression_depth_session",
|
|
256
|
+
"idx_transform_decisions_session_harness",
|
|
257
|
+
"idx_project_key_files_project"
|
|
258
|
+
];
|
|
259
|
+
var GIT_COMMIT_FTS_ROWID_MAP_DDL = `CREATE TABLE git_commit_fts_rowid_map (
|
|
260
|
+
fts_rowid INTEGER PRIMARY KEY,
|
|
261
|
+
sha BLOB
|
|
262
|
+
)`;
|
|
263
|
+
var GIT_FTS_MAP_REPAIR_COMMAND = "magic-context doctor git-fts-map --repair";
|
|
264
|
+
var GIT_FTS_MAP_DISAGREEMENT_SQL = `
|
|
265
|
+
SELECT 1 FROM git_commits_fts AS f
|
|
266
|
+
LEFT JOIN git_commit_fts_rowid_map AS m ON m.fts_rowid = f.rowid
|
|
267
|
+
WHERE m.fts_rowid IS NULL OR m.sha IS NOT f.sha OR typeof(m.sha) IS NOT typeof(f.sha)
|
|
268
|
+
UNION ALL
|
|
269
|
+
SELECT 1 FROM git_commit_fts_rowid_map AS m
|
|
270
|
+
WHERE NOT EXISTS (SELECT 1 FROM git_commits_fts AS f WHERE f.rowid = m.fts_rowid)
|
|
271
|
+
LIMIT 1`;
|
|
272
|
+
function gitFtsMapRepairMessage(detail) {
|
|
273
|
+
return `${detail}; stop all hosts, then run \`${GIT_FTS_MAP_REPAIR_COMMAND}\` to back up both stores and rebuild only the map`;
|
|
274
|
+
}
|
|
275
|
+
var mapIndex = "CREATE INDEX idx_git_commit_fts_rowid_map_sha ON git_commit_fts_rowid_map(sha)";
|
|
276
|
+
var remove = (row) => `
|
|
277
|
+
DELETE FROM git_commits_fts WHERE rowid IN (
|
|
278
|
+
SELECT fts_rowid FROM git_commit_fts_rowid_map WHERE sha = ${row}.sha
|
|
279
|
+
);
|
|
280
|
+
DELETE FROM git_commit_fts_rowid_map WHERE sha = ${row}.sha;`;
|
|
281
|
+
var insert = `
|
|
282
|
+
INSERT INTO git_commits_fts(sha, project_path, message)
|
|
283
|
+
VALUES (NEW.sha, NEW.project_path, NEW.message);
|
|
284
|
+
INSERT INTO git_commit_fts_rowid_map(fts_rowid, sha)
|
|
285
|
+
VALUES (last_insert_rowid(), NEW.sha);`;
|
|
286
|
+
var triggers = [
|
|
287
|
+
[
|
|
288
|
+
"git_commits_fts_insert",
|
|
289
|
+
`CREATE TRIGGER git_commits_fts_insert AFTER INSERT ON git_commits BEGIN${remove("NEW")}${insert}
|
|
290
|
+
END`
|
|
291
|
+
],
|
|
292
|
+
[
|
|
293
|
+
"git_commits_fts_delete",
|
|
294
|
+
`CREATE TRIGGER git_commits_fts_delete AFTER DELETE ON git_commits BEGIN${remove("OLD")}
|
|
295
|
+
END`
|
|
296
|
+
],
|
|
297
|
+
[
|
|
298
|
+
"git_commits_fts_update",
|
|
299
|
+
`CREATE TRIGGER git_commits_fts_update AFTER UPDATE OF message, project_path ON git_commits BEGIN${remove("OLD")}${insert}
|
|
300
|
+
END`
|
|
301
|
+
]
|
|
302
|
+
];
|
|
303
|
+
function installV95PerfSchema(db, verifyExistingMap = false, allowCreateMap = true) {
|
|
304
|
+
const schema = new Map(db.prepare("SELECT name, sql FROM sqlite_master").all().map((row) => [row.name, row.sql]));
|
|
305
|
+
if (!schema.has("temporal_decisions")) {
|
|
306
|
+
db.exec(TEMPORAL_DECISIONS_DDL);
|
|
307
|
+
if (schema.has("session_meta")) {
|
|
308
|
+
ensureColumn(db, "session_meta", "merged_reasoning_stripped_ids", "TEXT DEFAULT ''");
|
|
309
|
+
const rows = db.prepare("SELECT session_id, merged_reasoning_stripped_ids AS entries FROM session_meta WHERE merged_reasoning_stripped_ids LIKE '%temporal-message-v1:%'").all();
|
|
310
|
+
const insert = db.prepare("INSERT OR IGNORE INTO temporal_decisions(session_id,message_id,marker) VALUES (?,?,?)");
|
|
311
|
+
for (const row of rows) {
|
|
312
|
+
let entries;
|
|
313
|
+
try {
|
|
314
|
+
entries = JSON.parse(row.entries);
|
|
315
|
+
} catch {
|
|
316
|
+
sessionLog(row.session_id, "v95 temporal metadata: malformed JSON skipped; original blob retained");
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (!Array.isArray(entries)) {
|
|
320
|
+
sessionLog(row.session_id, "v95 temporal metadata: non-array JSON skipped; original blob retained");
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const kept = [];
|
|
324
|
+
for (const entry of entries) {
|
|
325
|
+
const decision = typeof entry === "string" ? decodeTemporalDecision(entry) : null;
|
|
326
|
+
if (decision)
|
|
327
|
+
insert.run(row.session_id, ...decision);
|
|
328
|
+
else
|
|
329
|
+
kept.push(entry);
|
|
330
|
+
}
|
|
331
|
+
db.prepare("UPDATE session_meta SET merged_reasoning_stripped_ids=? WHERE session_id=?").run(JSON.stringify(kept), row.session_id);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
for (const [table, name, columns] of indexes) {
|
|
336
|
+
if (schema.has(table) && !schema.has(name))
|
|
337
|
+
db.exec(`CREATE INDEX ${name} ON ${table}(${columns})`);
|
|
338
|
+
}
|
|
339
|
+
for (const name of V95_REDUNDANT_INDEXES) {
|
|
340
|
+
if (schema.has(name))
|
|
341
|
+
db.exec(`DROP INDEX ${name}`);
|
|
342
|
+
}
|
|
343
|
+
if (!schema.has("git_commits") || !schema.has("git_commits_fts"))
|
|
344
|
+
return;
|
|
345
|
+
const installed = schema.get("git_commit_fts_rowid_map");
|
|
346
|
+
if (installed === undefined) {
|
|
347
|
+
if (!allowCreateMap)
|
|
348
|
+
throw new Error(gitFtsMapRepairMessage("git FTS rowid map is missing"));
|
|
349
|
+
db.exec(GIT_COMMIT_FTS_ROWID_MAP_DDL);
|
|
350
|
+
db.exec("INSERT INTO git_commit_fts_rowid_map(fts_rowid, sha) SELECT rowid, sha FROM git_commits_fts");
|
|
351
|
+
} else if (installed !== GIT_COMMIT_FTS_ROWID_MAP_DDL) {
|
|
352
|
+
throw new Error(gitFtsMapRepairMessage("git_commit_fts_rowid_map schema differs; refusing to replace rowid data"));
|
|
353
|
+
}
|
|
354
|
+
if (verifyExistingMap && installed !== undefined && db.prepare(GIT_FTS_MAP_DISAGREEMENT_SQL).get()) {
|
|
355
|
+
throw new Error(gitFtsMapRepairMessage("git FTS rowid inventory differs; refusing migration replay"));
|
|
356
|
+
}
|
|
357
|
+
if (!schema.has("idx_git_commit_fts_rowid_map_sha"))
|
|
358
|
+
db.exec(mapIndex);
|
|
359
|
+
for (const [name, ddl] of triggers) {
|
|
360
|
+
if (schema.get(name) === ddl)
|
|
361
|
+
continue;
|
|
362
|
+
db.exec(`DROP TRIGGER IF EXISTS ${name}`);
|
|
363
|
+
db.exec(ddl);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
var tagOrderIndexes = new WeakMap;
|
|
367
|
+
|
|
368
|
+
// ../plugin/src/shared/opencode-db-path.ts
|
|
369
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
370
|
+
import { homedir } from "node:os";
|
|
371
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
372
|
+
var cachedResolution = null;
|
|
373
|
+
var lastReadFailure = null;
|
|
374
|
+
var claimedDiagnostics = new Set;
|
|
375
|
+
function openCodeDataDir(env = process.env, dataHome) {
|
|
376
|
+
return join(dataHome ?? env.XDG_DATA_HOME ?? join(homedir(), ".local", "share"), "opencode");
|
|
377
|
+
}
|
|
378
|
+
function environmentKey(dataDir, hostGeneration, channel, env) {
|
|
379
|
+
return [
|
|
380
|
+
hostGeneration,
|
|
381
|
+
dataDir,
|
|
382
|
+
env.OPENCODE_DB ?? "",
|
|
383
|
+
env.OPENCODE_DISABLE_CHANNEL_DB ?? "",
|
|
384
|
+
channel ?? env.OPENCODE_CHANNEL ?? ""
|
|
385
|
+
].join("\x00");
|
|
386
|
+
}
|
|
387
|
+
function channelPath(dataDir, channel) {
|
|
388
|
+
return ["latest", "beta", "prod"].includes(channel) ? join(dataDir, "opencode.db") : join(dataDir, `opencode-${channel}.db`);
|
|
389
|
+
}
|
|
390
|
+
function discoveredCandidateNames(dataDir) {
|
|
391
|
+
const names = ["opencode.db", "opencode-local.db", "opencode-dev.db"];
|
|
392
|
+
try {
|
|
393
|
+
const discovered = readdirSync(dataDir, { withFileTypes: true }).filter((entry) => /^opencode-.+\.db$/.test(entry.name) && !names.includes(entry.name)).map((entry) => entry.name).sort();
|
|
394
|
+
names.push(...discovered);
|
|
395
|
+
} catch {}
|
|
396
|
+
return names;
|
|
397
|
+
}
|
|
398
|
+
function discoverOpenCodeDb(dataDir) {
|
|
399
|
+
const candidates = discoveredCandidateNames(dataDir).map((name, order) => {
|
|
400
|
+
const path = join(dataDir, name);
|
|
401
|
+
try {
|
|
402
|
+
const metadata = statSync(path);
|
|
403
|
+
return metadata.isFile() ? { path, order, mtimeMs: metadata.mtimeMs } : null;
|
|
404
|
+
} catch {
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
const existing = candidates.filter((candidate) => candidate !== null).sort((left, right) => right.mtimeMs - left.mtimeMs || left.order - right.order)[0];
|
|
409
|
+
if (!existing) {
|
|
410
|
+
return { path: join(dataDir, "opencode.db"), source: "default", channel: null };
|
|
411
|
+
}
|
|
412
|
+
const name = existing.path.slice(dataDir.length + 1);
|
|
413
|
+
const channel = name === "opencode.db" ? null : name.slice("opencode-".length, -".db".length) || null;
|
|
414
|
+
return { path: existing.path, source: "discovered", channel };
|
|
415
|
+
}
|
|
416
|
+
function resolveV1Fresh(dataDir, env = process.env) {
|
|
417
|
+
const explicit = env.OPENCODE_DB;
|
|
418
|
+
if (explicit !== undefined && explicit.length > 0) {
|
|
419
|
+
if (explicit === ":memory:") {
|
|
420
|
+
return { path: explicit, source: "OPENCODE_DB", channel: null };
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
path: isAbsolute(explicit) ? explicit : join(dataDir, explicit),
|
|
424
|
+
source: "OPENCODE_DB",
|
|
425
|
+
channel: null
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
const disableChannelDb = env.OPENCODE_DISABLE_CHANNEL_DB;
|
|
429
|
+
if (disableChannelDb === "1" || disableChannelDb === "true") {
|
|
430
|
+
return { path: join(dataDir, "opencode.db"), source: "default", channel: null };
|
|
431
|
+
}
|
|
432
|
+
const channel = env.OPENCODE_CHANNEL;
|
|
433
|
+
if (channel !== undefined && channel.length > 0) {
|
|
434
|
+
return { path: channelPath(dataDir, channel), source: "channel", channel };
|
|
435
|
+
}
|
|
436
|
+
return discoverOpenCodeDb(dataDir);
|
|
437
|
+
}
|
|
438
|
+
function sourceOpenCodeDatabaseFilename(hostGeneration, channel, env = process.env) {
|
|
439
|
+
if (hostGeneration === "v1") {
|
|
440
|
+
const explicit = env.OPENCODE_DB;
|
|
441
|
+
if (explicit !== undefined && explicit.length > 0)
|
|
442
|
+
return explicit;
|
|
443
|
+
if (env.OPENCODE_DISABLE_CHANNEL_DB === "1" || env.OPENCODE_DISABLE_CHANNEL_DB === "true") {
|
|
444
|
+
return "opencode.db";
|
|
445
|
+
}
|
|
446
|
+
return ["latest", "beta", "prod"].includes(channel) ? "opencode.db" : `opencode-${channel}.db`;
|
|
447
|
+
}
|
|
448
|
+
return env.OPENCODE_DB ?? (["latest", "dev", "beta", "next", "prod"].includes(channel) || env.OPENCODE_DISABLE_CHANNEL_DB === "1" || env.OPENCODE_DISABLE_CHANNEL_DB === "true" ? "opencode.db" : `opencode-${channel.replace(/[^a-zA-Z0-9._-]/g, "")}.db`);
|
|
449
|
+
}
|
|
450
|
+
function resolveV2Fresh(dataDir, channel, env) {
|
|
451
|
+
const filename = sourceOpenCodeDatabaseFilename("v2", channel, env);
|
|
452
|
+
const explicit = env.OPENCODE_DB !== undefined;
|
|
453
|
+
return {
|
|
454
|
+
path: filename === ":memory:" ? filename : resolve(dataDir, filename),
|
|
455
|
+
source: explicit ? "OPENCODE_DB" : env.OPENCODE_CHANNEL ? "channel" : "default",
|
|
456
|
+
channel: explicit ? null : channel
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function resolveOpenCodeDbPath(hostGeneration = "v1", options = {}) {
|
|
460
|
+
const env = options.env ?? process.env;
|
|
461
|
+
const dataDir = openCodeDataDir(env, options.dataHome);
|
|
462
|
+
const channel = options.channel ?? env.OPENCODE_CHANNEL;
|
|
463
|
+
const key = environmentKey(dataDir, hostGeneration, channel, env);
|
|
464
|
+
if (cachedResolution?.key === key && (!cachedResolution.existed || existsSync(cachedResolution.resolution.path))) {
|
|
465
|
+
if (cachedResolution.existed)
|
|
466
|
+
return cachedResolution.resolution;
|
|
467
|
+
}
|
|
468
|
+
const resolution = hostGeneration === "v2" ? resolveV2Fresh(dataDir, channel ?? "latest", env) : resolveV1Fresh(dataDir, env);
|
|
469
|
+
cachedResolution = {
|
|
470
|
+
key,
|
|
471
|
+
resolution,
|
|
472
|
+
existed: resolution.path !== ":memory:" && existsSync(resolution.path)
|
|
473
|
+
};
|
|
474
|
+
return resolution;
|
|
475
|
+
}
|
|
476
|
+
function schemaTableNames(db, schema = "main") {
|
|
477
|
+
const rows = db.prepare(`SELECT name FROM ${schema}.sqlite_master WHERE type = 'table' AND name IN ('message', 'part', 'session', 'project', 'session_message', 'session_v2')`).all();
|
|
478
|
+
return new Set(rows.flatMap((row) => typeof row.name === "string" ? [row.name] : []));
|
|
479
|
+
}
|
|
480
|
+
function hasV1MessageTables(db, schema = "main") {
|
|
481
|
+
const tables = schemaTableNames(db, schema);
|
|
482
|
+
return tables.has("message") && tables.has("part");
|
|
483
|
+
}
|
|
484
|
+
function detectOpenCodeStoreGeneration(db, schema = "main") {
|
|
485
|
+
const tables = schemaTableNames(db, schema);
|
|
486
|
+
const hasV1Messages = tables.has("message") && tables.has("part");
|
|
487
|
+
if (hasV1Messages)
|
|
488
|
+
return "v1";
|
|
489
|
+
if (tables.has("session_message"))
|
|
490
|
+
return "v2";
|
|
491
|
+
if (tables.has("session") || tables.has("project"))
|
|
492
|
+
return "v1";
|
|
493
|
+
return "unknown";
|
|
494
|
+
}
|
|
495
|
+
function hasMigratedV2Schema(tables) {
|
|
496
|
+
return tables.has("session_message") && tables.has("session_v2");
|
|
497
|
+
}
|
|
498
|
+
function isOpenCodeV2Store(db, schema = "main") {
|
|
499
|
+
return detectOpenCodeStoreGeneration(db, schema) === "v2" || hasMigratedV2Schema(schemaTableNames(db, schema));
|
|
500
|
+
}
|
|
501
|
+
function assertOpenCodeStoreGeneration(db, expected, path, schema = "main") {
|
|
502
|
+
const actual = detectOpenCodeStoreGeneration(db, schema);
|
|
503
|
+
if (actual === expected)
|
|
504
|
+
return;
|
|
505
|
+
if (expected === "v2" && isOpenCodeV2Store(db, schema))
|
|
506
|
+
return;
|
|
507
|
+
if (actual === "unknown")
|
|
508
|
+
return;
|
|
509
|
+
throw new Error(`OpenCode store generation mismatch at ${path}: expected ${expected}, found ${actual}; refusing generation-specific database access`);
|
|
510
|
+
}
|
|
511
|
+
function openCodeDbPathExists(resolution = resolveOpenCodeDbPath()) {
|
|
512
|
+
return resolution.path !== ":memory:" && existsSync(resolution.path);
|
|
513
|
+
}
|
|
514
|
+
function getOpenCodeDbProbeDescriptions(resolution = resolveOpenCodeDbPath()) {
|
|
515
|
+
if (resolution.source === "OPENCODE_DB")
|
|
516
|
+
return [resolution.path];
|
|
517
|
+
if (resolution.source === "channel" || process.env.OPENCODE_DISABLE_CHANNEL_DB === "1" || process.env.OPENCODE_DISABLE_CHANNEL_DB === "true") {
|
|
518
|
+
return [resolution.path];
|
|
519
|
+
}
|
|
520
|
+
const dataDir = openCodeDataDir();
|
|
521
|
+
return [
|
|
522
|
+
join(dataDir, "opencode.db"),
|
|
523
|
+
join(dataDir, "opencode-local.db"),
|
|
524
|
+
join(dataDir, "opencode-dev.db"),
|
|
525
|
+
join(dataDir, "opencode-<channel>.db")
|
|
526
|
+
];
|
|
527
|
+
}
|
|
528
|
+
function recordOpenCodeDbReadFailure(resolution, error) {
|
|
529
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
530
|
+
lastReadFailure = { ...resolution, message };
|
|
531
|
+
return lastReadFailure;
|
|
532
|
+
}
|
|
533
|
+
function clearOpenCodeDbReadFailure(path) {
|
|
534
|
+
if (path === undefined || lastReadFailure?.path === path)
|
|
535
|
+
lastReadFailure = null;
|
|
536
|
+
}
|
|
537
|
+
function claimOpenCodeDbDiagnosticOnce(surface, resolution) {
|
|
538
|
+
const key = `${surface}\x00${resolution.path}\x00${resolution.source}`;
|
|
539
|
+
if (claimedDiagnostics.has(key))
|
|
540
|
+
return false;
|
|
541
|
+
claimedDiagnostics.add(key);
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// ../plugin/src/features/magic-context/tool-definition-tokens.ts
|
|
546
|
+
var measurements = new Map;
|
|
547
|
+
var fingerprints = new Map;
|
|
548
|
+
var persistenceDb = null;
|
|
549
|
+
var cachedInsertStmt = null;
|
|
550
|
+
function keyFor(providerID, modelID, agentName) {
|
|
551
|
+
const agent = agentName && agentName.length > 0 ? agentName : "default";
|
|
552
|
+
return `${providerID}/${modelID}/${agent}`;
|
|
553
|
+
}
|
|
554
|
+
function setDatabase(db) {
|
|
555
|
+
persistenceDb = db;
|
|
556
|
+
cachedInsertStmt = null;
|
|
557
|
+
}
|
|
558
|
+
function loadToolDefinitionMeasurements(db) {
|
|
559
|
+
let rows = [];
|
|
560
|
+
try {
|
|
561
|
+
rows = db.prepare("SELECT provider_id, model_id, agent_name, tool_id, token_count FROM tool_definition_measurements").all();
|
|
562
|
+
} catch {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
for (const row of rows) {
|
|
566
|
+
const key = keyFor(row.provider_id, row.model_id, row.agent_name);
|
|
567
|
+
let inner = measurements.get(key);
|
|
568
|
+
if (!inner) {
|
|
569
|
+
inner = new Map;
|
|
570
|
+
measurements.set(key, inner);
|
|
571
|
+
}
|
|
572
|
+
inner.set(row.tool_id, row.token_count);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export { stableStringify, closeQuietly, isKnownAutocommit, getTableColumnNames, ensureColumn, healAllNullColumns, observeTemporalDecisions, freezeTemporalDecisions, installV95PerfSchema, resolveOpenCodeDbPath, hasV1MessageTables, assertOpenCodeStoreGeneration, openCodeDbPathExists, getOpenCodeDbProbeDescriptions, recordOpenCodeDbReadFailure, clearOpenCodeDbReadFailure, claimOpenCodeDbDiagnosticOnce, setDatabase, loadToolDefinitionMeasurements };
|