@cortexkit/pi-magic-context 0.47.0 → 0.49.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/dist/auto-search-worker.js +27 -22
- package/dist/embedding-activity-ew6dshfd.js +10 -0
- package/dist/embedding-backfill-b71dvfs8.js +20 -0
- package/dist/embedding-cache-7rp4gqzr.js +16 -0
- package/dist/embedding-worker.js +11 -8
- package/dist/harness-9872e0ym.js +10 -0
- package/dist/historian-calibration-extension.js +30 -4
- package/dist/index-041ex0cj.js +519 -0
- package/dist/index-0h2mkab2.js +17 -0
- package/dist/{index-2p1e8706.js → index-0vrkp1jq.js} +3 -3
- package/dist/index-135e8hvg.js +43 -0
- package/dist/{index-vgcemg0n.js → index-1evzceyw.js} +151 -2452
- package/dist/index-21v1kfs7.js +2309 -0
- package/dist/{index-n3g5mwa8.js → index-290tzwp1.js} +3 -3
- package/dist/{index-0qejsd7f.js → index-3cgbv47m.js} +289 -45
- package/dist/{index-xpbh1ypk.js → index-3mgf68pn.js} +38 -741
- package/dist/index-3rea6zd9.js +2396 -0
- package/dist/index-674f6qs2.js +16 -0
- package/dist/index-8976mezv.js +209 -0
- package/dist/index-904reqtg.js +152 -0
- package/dist/index-9p40dgkm.js +22 -0
- package/dist/index-9x1f96r8.js +11 -0
- package/dist/index-bejpsj10.js +1060 -0
- package/dist/{index-spk5vrhy.js → index-bgmv2kaf.js} +1 -16
- package/dist/{index-k3ezsjng.js → index-ehybv5nr.js} +14657 -13951
- package/dist/index-fapenpch.js +13 -0
- package/dist/index-hwqb3s7f.js +3804 -0
- package/dist/index-kjd1fj55.js +3106 -0
- package/dist/{index-td885aah.js → index-mcgehvgw.js} +181 -230
- package/dist/index-r024r8da.js +171 -0
- package/dist/{index-266qrgss.js → index-r56xgha8.js} +301 -27
- package/dist/{index-kztsbkqq.js → index-t7xfqtg6.js} +171 -168
- package/dist/index-vakawmbc.js +1262 -0
- package/dist/{index-7n8gb6j3.js → index-x3dcnxh0.js} +34 -33
- package/dist/index-xjqheg7a.js +931 -0
- package/dist/index-yarjn32j.js +3026 -0
- package/dist/index-yhzhdp3m.js +143 -0
- package/dist/index-yzcjxnt2.js +787 -0
- package/dist/{index-w76x3af7.js → index-zh1jw8qp.js} +107 -4
- package/dist/index.js +4926 -2437
- package/dist/logger-j6tecd1h.js +19 -0
- package/dist/message-index-bounded-qz5dz2se.js +120 -0
- package/dist/{message-time-backfill-d3db2etr.js → message-time-backfill-05ppypkz.js} +7 -6
- package/dist/migration-worker.js +20 -14
- package/dist/project-embedding-registry-ky7wrkr1.js +85 -0
- package/dist/raw-ordinal-warmup-worker.js +60 -0
- package/dist/{read-session-chunk-atxsyfqv.js → read-session-chunk-24sd89tf.js} +14 -6
- package/dist/read-session-raw-npx3920c.js +57 -0
- package/dist/{safe-notification-target-6cn3z99t.js → safe-notification-target-vn9kpmv4.js} +3 -2
- package/dist/search-jbh28nwy.js +40 -0
- package/dist/sqlite-3yye76ht.js +44 -0
- package/dist/sqlite-context-pragmas-gcgch6qz.js +6 -0
- package/dist/storage-memory-1z20y55x.js +71 -0
- package/dist/storage-tags-kjnsqbdb.js +127 -0
- package/dist/subagent-entry.js +35 -17
- package/dist/transformers-node-wasm.js +18415 -18415
- package/package.json +3 -3
- package/dist/index-7s8vw2y0.js +0 -5207
- package/dist/index-qaa5j277.js +0 -8544
- /package/dist/{index-en1k8h8m.js → index-5prbx026.js} +0 -0
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
} from "./index-
|
|
2
|
+
sessionLog2
|
|
3
|
+
} from "./index-x3dcnxh0.js";
|
|
4
|
+
|
|
5
|
+
// ../plugin/src/shared/stable-json.ts
|
|
6
|
+
function stableStringify(value, seen = new WeakSet) {
|
|
7
|
+
const pieces = [];
|
|
8
|
+
writeStable(value, seen, pieces);
|
|
9
|
+
return pieces.join("");
|
|
10
|
+
}
|
|
11
|
+
function writeStable(value, seen, pieces) {
|
|
12
|
+
if (value === undefined) {
|
|
13
|
+
pieces.push("undefined");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (value === null || typeof value !== "object") {
|
|
17
|
+
pieces.push(JSON.stringify(value) ?? String(value));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (seen.has(value)) {
|
|
21
|
+
pieces.push('"[Circular]"');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
seen.add(value);
|
|
25
|
+
if (Array.isArray(value)) {
|
|
26
|
+
pieces.push("[");
|
|
27
|
+
for (let index = 0;index < value.length; index += 1) {
|
|
28
|
+
if (index > 0)
|
|
29
|
+
pieces.push(",");
|
|
30
|
+
if (index in value)
|
|
31
|
+
writeStable(value[index], seen, pieces);
|
|
32
|
+
}
|
|
33
|
+
pieces.push("]");
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const entries = Object.entries(value).sort(([a], [b]) => {
|
|
37
|
+
if (a < b)
|
|
38
|
+
return -1;
|
|
39
|
+
if (a > b)
|
|
40
|
+
return 1;
|
|
41
|
+
return 0;
|
|
42
|
+
});
|
|
43
|
+
pieces.push("{");
|
|
44
|
+
entries.forEach(([key, child], index) => {
|
|
45
|
+
if (index > 0)
|
|
46
|
+
pieces.push(",");
|
|
47
|
+
pieces.push(JSON.stringify(key), ":");
|
|
48
|
+
writeStable(child, seen, pieces);
|
|
49
|
+
});
|
|
50
|
+
pieces.push("}");
|
|
51
|
+
}
|
|
4
52
|
|
|
5
53
|
// ../plugin/src/shared/sqlite-helpers.ts
|
|
6
54
|
function closeQuietly(db) {
|
|
@@ -19,28 +67,6 @@ function isKnownAutocommit(db) {
|
|
|
19
67
|
}
|
|
20
68
|
}
|
|
21
69
|
|
|
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
70
|
// ../plugin/src/features/magic-context/storage-schema-helpers.ts
|
|
45
71
|
var columnCaches = new WeakMap;
|
|
46
72
|
function readColumnNames(db, table) {
|
|
@@ -313,11 +339,11 @@ function installV95PerfSchema(db, verifyExistingMap = false, allowCreateMap = tr
|
|
|
313
339
|
try {
|
|
314
340
|
entries = JSON.parse(row.entries);
|
|
315
341
|
} catch {
|
|
316
|
-
|
|
342
|
+
sessionLog2(row.session_id, "v95 temporal metadata: malformed JSON skipped; original blob retained");
|
|
317
343
|
continue;
|
|
318
344
|
}
|
|
319
345
|
if (!Array.isArray(entries)) {
|
|
320
|
-
|
|
346
|
+
sessionLog2(row.session_id, "v95 temporal metadata: non-array JSON skipped; original blob retained");
|
|
321
347
|
continue;
|
|
322
348
|
}
|
|
323
349
|
const kept = [];
|
|
@@ -364,213 +390,138 @@ function installV95PerfSchema(db, verifyExistingMap = false, allowCreateMap = tr
|
|
|
364
390
|
}
|
|
365
391
|
}
|
|
366
392
|
var tagOrderIndexes = new WeakMap;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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];
|
|
393
|
+
function tagOrderConstraintIndex(db) {
|
|
394
|
+
const version = db.prepare("PRAGMA schema_version").get().schema_version;
|
|
395
|
+
const cacheable = isKnownAutocommit(db);
|
|
396
|
+
if (!cacheable)
|
|
397
|
+
tagOrderIndexes.delete(db);
|
|
398
|
+
const cached = tagOrderIndexes.get(db);
|
|
399
|
+
if (cached?.schemaVersion === version)
|
|
400
|
+
return cached.name;
|
|
401
|
+
const candidates = db.prepare("PRAGMA index_list(tags)").all();
|
|
402
|
+
for (const candidate of candidates) {
|
|
403
|
+
if (!candidate.unique || candidate.origin !== "u")
|
|
404
|
+
continue;
|
|
405
|
+
const quoted = `"${candidate.name.replaceAll('"', '""')}"`;
|
|
406
|
+
const columns = db.prepare(`PRAGMA index_info(${quoted})`).all();
|
|
407
|
+
if (columns.length !== 2 || columns[0]?.name !== "session_id" || columns[1]?.name !== "tag_number")
|
|
408
|
+
continue;
|
|
409
|
+
if (cacheable)
|
|
410
|
+
tagOrderIndexes.set(db, { schemaVersion: version, name: quoted });
|
|
411
|
+
return quoted;
|
|
519
412
|
}
|
|
520
|
-
|
|
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;
|
|
413
|
+
throw new Error("tags lacks its UNIQUE(session_id, tag_number) ordering constraint");
|
|
543
414
|
}
|
|
544
415
|
|
|
545
|
-
// ../plugin/src/features/magic-context/
|
|
546
|
-
var
|
|
547
|
-
var
|
|
548
|
-
var
|
|
549
|
-
var
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
416
|
+
// ../plugin/src/features/magic-context/storage-tag-identity-revision.ts
|
|
417
|
+
var TAG_IDENTITY_REVISION_PREFIX = "tag_identity_revision:";
|
|
418
|
+
var TAG_REVISION_PREFIX = "tag_revision:";
|
|
419
|
+
var TAG_TOMBSTONE_OWNER_PREFIX = "tag_revision_owner:";
|
|
420
|
+
var TAG_REVISION_INCARNATION_KEY = "tag_revision_incarnation";
|
|
421
|
+
var tagRevisionIncarnationSql = (value) => `CASE WHEN INSTR(${value}, ':') > 0 THEN SUBSTR(${value}, 1, INSTR(${value}, ':') - 1) ELSE '0' END`;
|
|
422
|
+
var tagRevisionCountSql = (value) => `CAST(CASE WHEN INSTR(${value}, ':') > 0 THEN SUBSTR(${value}, INSTR(${value}, ':') + 1) ELSE ${value} END AS INTEGER)`;
|
|
423
|
+
var ADVANCE = (delta = "1") => `CASE
|
|
424
|
+
WHEN ${tagRevisionCountSql("value")} <= 9223372036854775807 - ${delta}
|
|
425
|
+
THEN (${tagRevisionIncarnationSql("value")}) || ':' || CAST(${tagRevisionCountSql("value")} + ${delta} AS TEXT)
|
|
426
|
+
ELSE NULL END`;
|
|
427
|
+
function tagTombstoneOwnerRange(sessionId) {
|
|
428
|
+
const stem = `${TAG_TOMBSTONE_OWNER_PREFIX}${JSON.stringify(sessionId)}`;
|
|
429
|
+
return [`${stem}:`, `${stem};`];
|
|
430
|
+
}
|
|
431
|
+
function tagTombstoneOwnerKey(sessionId, harness) {
|
|
432
|
+
return `${tagTombstoneOwnerRange(sessionId)[0]}${harness}`;
|
|
433
|
+
}
|
|
434
|
+
function tagRevisionKey(sessionId) {
|
|
435
|
+
return `${TAG_REVISION_PREFIX}${sessionId}`;
|
|
436
|
+
}
|
|
437
|
+
function tagIdentityRevisionKey(sessionId) {
|
|
438
|
+
return `${TAG_IDENTITY_REVISION_PREFIX}${sessionId}`;
|
|
439
|
+
}
|
|
440
|
+
var BUMP = (session, prefix = TAG_IDENTITY_REVISION_PREFIX) => `INSERT INTO schema_migrations_meta (key, value)
|
|
441
|
+
VALUES ('${prefix}' || ${session}, '1')
|
|
442
|
+
ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()}`;
|
|
443
|
+
var TAG_INSERT_CONFLICT_ROWS = `SELECT id, session_id, tag_number FROM tags WHERE id = NEW.id
|
|
444
|
+
UNION SELECT id, session_id, tag_number FROM tags WHERE session_id = NEW.session_id AND tag_number = NEW.tag_number
|
|
445
|
+
UNION SELECT id, session_id, tag_number FROM tags
|
|
446
|
+
WHERE NEW.type = 'tool' AND NEW.tool_owner_message_id IS NOT NULL
|
|
447
|
+
AND type = 'tool' AND tool_owner_message_id IS NOT NULL
|
|
448
|
+
AND session_id = NEW.session_id AND message_id = NEW.message_id
|
|
449
|
+
AND tool_owner_message_id = NEW.tool_owner_message_id`;
|
|
450
|
+
var BUMP_INSERT_CONFLICTS = (prefix) => `INSERT INTO schema_migrations_meta (key, value)
|
|
451
|
+
SELECT '${prefix}' || session_id, CAST(COUNT(*) AS TEXT)
|
|
452
|
+
FROM (${TAG_INSERT_CONFLICT_ROWS}) GROUP BY session_id
|
|
453
|
+
ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE("CAST(excluded.value AS INTEGER)")}`;
|
|
454
|
+
var TRIGGER_SQL = `CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_identity_revision_au
|
|
455
|
+
AFTER UPDATE OF id, session_id, message_id, tag_number, type, tool_owner_message_id, reasoning_token_count
|
|
456
|
+
ON main.tags
|
|
457
|
+
BEGIN
|
|
458
|
+
${BUMP("OLD.session_id")};
|
|
459
|
+
INSERT INTO schema_migrations_meta (key, value)
|
|
460
|
+
SELECT '${TAG_IDENTITY_REVISION_PREFIX}' || NEW.session_id, '1'
|
|
461
|
+
WHERE NEW.session_id IS NOT OLD.session_id
|
|
462
|
+
ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()};
|
|
463
|
+
END`;
|
|
464
|
+
function installTagIdentityRevisionTrigger(db) {
|
|
465
|
+
db.exec(`DROP TRIGGER IF EXISTS temp.mc_tag_identity_revision_au;
|
|
466
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_bi;
|
|
467
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_ai;
|
|
468
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_au;
|
|
469
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_ad;
|
|
470
|
+
DROP TRIGGER IF EXISTS temp.mc_tag_revision_seed_ai;`);
|
|
471
|
+
db.exec(`CREATE TEMP TRIGGER mc_tag_revision_seed_ai AFTER INSERT ON main.schema_migrations_meta
|
|
472
|
+
WHEN INSTR(NEW.value, ':') = 0 AND (
|
|
473
|
+
SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
|
|
474
|
+
OR SUBSTR(NEW.key, 1, ${TAG_IDENTITY_REVISION_PREFIX.length}) = '${TAG_IDENTITY_REVISION_PREFIX}')
|
|
475
|
+
BEGIN
|
|
476
|
+
INSERT INTO schema_migrations_meta (key, value) VALUES ('${TAG_REVISION_INCARNATION_KEY}', '1')
|
|
477
|
+
ON CONFLICT(key) DO UPDATE SET value = CAST(CASE
|
|
478
|
+
WHEN CAST(value AS INTEGER) < 9223372036854775807 THEN CAST(value AS INTEGER) + 1
|
|
479
|
+
ELSE NULL END AS TEXT);
|
|
480
|
+
UPDATE schema_migrations_meta SET value =
|
|
481
|
+
(SELECT value FROM schema_migrations_meta WHERE key = '${TAG_REVISION_INCARNATION_KEY}')
|
|
482
|
+
|| ':' || CAST(NEW.value AS TEXT) WHERE key = NEW.key;
|
|
483
|
+
INSERT INTO schema_migrations_meta (key, value)
|
|
484
|
+
SELECT '${TAG_REVISION_INCARNATION_KEY}', '1'
|
|
485
|
+
WHERE SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
|
|
486
|
+
AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta
|
|
487
|
+
WHERE key = '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}))
|
|
488
|
+
ON CONFLICT(key) DO UPDATE SET value = CAST(CASE
|
|
489
|
+
WHEN CAST(value AS INTEGER) < 9223372036854775807 THEN CAST(value AS INTEGER) + 1
|
|
490
|
+
ELSE NULL END AS TEXT);
|
|
491
|
+
INSERT INTO schema_migrations_meta (key, value)
|
|
492
|
+
SELECT '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}),
|
|
493
|
+
(SELECT value FROM schema_migrations_meta WHERE key = '${TAG_REVISION_INCARNATION_KEY}') || ':0'
|
|
494
|
+
WHERE SUBSTR(NEW.key, 1, ${TAG_REVISION_PREFIX.length}) = '${TAG_REVISION_PREFIX}'
|
|
495
|
+
AND NOT EXISTS (SELECT 1 FROM schema_migrations_meta
|
|
496
|
+
WHERE key = '${TAG_IDENTITY_REVISION_PREFIX}' || SUBSTR(NEW.key, ${TAG_REVISION_PREFIX.length + 1}));
|
|
497
|
+
END;`);
|
|
498
|
+
db.exec(TRIGGER_SQL);
|
|
499
|
+
db.exec(`CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_bi BEFORE INSERT ON main.tags BEGIN
|
|
500
|
+
${BUMP_INSERT_CONFLICTS(TAG_REVISION_PREFIX)};
|
|
501
|
+
${BUMP_INSERT_CONFLICTS(TAG_IDENTITY_REVISION_PREFIX)};
|
|
502
|
+
UPDATE session_meta SET tags_version = tags_version + 1
|
|
503
|
+
WHERE session_id IN (SELECT session_id FROM (${TAG_INSERT_CONFLICT_ROWS}));
|
|
504
|
+
END;`);
|
|
505
|
+
db.exec(`CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_ai AFTER INSERT ON main.tags BEGIN
|
|
506
|
+
${BUMP("NEW.session_id", TAG_REVISION_PREFIX)};
|
|
507
|
+
END;
|
|
508
|
+
CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_au AFTER UPDATE ON main.tags BEGIN
|
|
509
|
+
${BUMP("OLD.session_id", TAG_REVISION_PREFIX)};
|
|
510
|
+
INSERT INTO schema_migrations_meta (key, value)
|
|
511
|
+
SELECT '${TAG_REVISION_PREFIX}' || NEW.session_id, '1'
|
|
512
|
+
WHERE NEW.session_id IS NOT OLD.session_id
|
|
513
|
+
ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()};
|
|
514
|
+
END;
|
|
515
|
+
CREATE TEMP TRIGGER IF NOT EXISTS mc_tag_revision_ad AFTER DELETE ON main.tags BEGIN
|
|
516
|
+
${BUMP("OLD.session_id", TAG_REVISION_PREFIX)};
|
|
517
|
+
END;`);
|
|
518
|
+
}
|
|
519
|
+
function deleteTagIdentityRevisions(db, sessionIds) {
|
|
520
|
+
const statement = db.prepare(`INSERT INTO schema_migrations_meta (key, value) VALUES (?, '1')
|
|
521
|
+
ON CONFLICT(key) DO UPDATE SET value = ${ADVANCE()}`);
|
|
522
|
+
for (const sessionId of sessionIds) {
|
|
523
|
+
statement.run(tagIdentityRevisionKey(sessionId));
|
|
573
524
|
}
|
|
574
525
|
}
|
|
575
526
|
|
|
576
|
-
export { stableStringify, closeQuietly, isKnownAutocommit, getTableColumnNames, ensureColumn, healAllNullColumns, observeTemporalDecisions, freezeTemporalDecisions, installV95PerfSchema,
|
|
527
|
+
export { stableStringify, closeQuietly, isKnownAutocommit, getTableColumnNames, ensureColumn, healAllNullColumns, observeTemporalDecisions, freezeTemporalDecisions, installV95PerfSchema, tagOrderConstraintIndex, TAG_TOMBSTONE_OWNER_PREFIX, tagRevisionIncarnationSql, tagRevisionCountSql, tagTombstoneOwnerRange, tagTombstoneOwnerKey, tagRevisionKey, tagIdentityRevisionKey, TAG_INSERT_CONFLICT_ROWS, installTagIdentityRevisionTrigger, deleteTagIdentityRevisions };
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {
|
|
2
|
+
withSqliteBackgroundWriter2,
|
|
3
|
+
withoutSqliteTransformPass2
|
|
4
|
+
} from "./index-3cgbv47m.js";
|
|
5
|
+
import {
|
|
6
|
+
logSlowWriteTransaction
|
|
7
|
+
} from "./index-0vrkp1jq.js";
|
|
8
|
+
|
|
9
|
+
// ../plugin/src/features/magic-context/message-fts-rowid-map.ts
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
var MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE = 100;
|
|
12
|
+
var BACKFILL_STATE_ID = 1;
|
|
13
|
+
var EMPTY_INDEX_CONTENT_HASH = createHash("sha256").update("").digest("hex");
|
|
14
|
+
var upsertMapStatements = new WeakMap;
|
|
15
|
+
var rangeReadyStatements = new WeakMap;
|
|
16
|
+
var updateTimeStatements = new WeakMap;
|
|
17
|
+
var activeBackfills = new WeakMap;
|
|
18
|
+
function getUpsertMapStatement(db) {
|
|
19
|
+
let statement = upsertMapStatements.get(db);
|
|
20
|
+
if (!statement) {
|
|
21
|
+
statement = db.prepare(`INSERT INTO message_fts_rowid_map
|
|
22
|
+
(session_id, message_ordinal, fts_rowid, message_time_ms)
|
|
23
|
+
VALUES (?, ?, ?, ?)
|
|
24
|
+
ON CONFLICT(session_id, message_ordinal) DO UPDATE SET
|
|
25
|
+
fts_rowid = excluded.fts_rowid,
|
|
26
|
+
message_time_ms = COALESCE(
|
|
27
|
+
excluded.message_time_ms,
|
|
28
|
+
message_fts_rowid_map.message_time_ms
|
|
29
|
+
)`);
|
|
30
|
+
upsertMapStatements.set(db, statement);
|
|
31
|
+
}
|
|
32
|
+
return statement;
|
|
33
|
+
}
|
|
34
|
+
function getBackfillState(db) {
|
|
35
|
+
const row = db.prepare(`SELECT watermark_rowid AS watermarkRowid, completed
|
|
36
|
+
FROM message_fts_rowid_map_backfill_state
|
|
37
|
+
WHERE id = ?`).get(BACKFILL_STATE_ID);
|
|
38
|
+
return {
|
|
39
|
+
processed: 0,
|
|
40
|
+
watermarkRowid: typeof row?.watermarkRowid === "number" && Number.isSafeInteger(row.watermarkRowid) ? row.watermarkRowid : 0,
|
|
41
|
+
completed: row?.completed === 1
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function recordMessageFtsRowid(db, sessionId, messageOrdinal, ftsRowid, messageTimeMs = null) {
|
|
45
|
+
const numericRowid = Number(ftsRowid);
|
|
46
|
+
if (!Number.isSafeInteger(numericRowid) || numericRowid <= 0) {
|
|
47
|
+
throw new Error(`invalid message FTS rowid: ${String(ftsRowid)}`);
|
|
48
|
+
}
|
|
49
|
+
const normalizedTime = typeof messageTimeMs === "number" && Number.isSafeInteger(messageTimeMs) && messageTimeMs >= 0 ? messageTimeMs : null;
|
|
50
|
+
getUpsertMapStatement(db).run(sessionId, messageOrdinal, numericRowid, normalizedTime);
|
|
51
|
+
}
|
|
52
|
+
function recordIndexedMessageTime(db, sessionId, messageOrdinal, messageTimeMs) {
|
|
53
|
+
if (typeof messageTimeMs !== "number" || !Number.isSafeInteger(messageTimeMs) || messageTimeMs < 0) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
let statement = updateTimeStatements.get(db);
|
|
57
|
+
if (!statement) {
|
|
58
|
+
statement = db.prepare(`UPDATE message_fts_rowid_map
|
|
59
|
+
SET message_time_ms = ?
|
|
60
|
+
WHERE session_id = ? AND message_ordinal = ?
|
|
61
|
+
AND message_time_ms IS NULL`);
|
|
62
|
+
updateTimeStatements.set(db, statement);
|
|
63
|
+
}
|
|
64
|
+
statement.run(messageTimeMs, sessionId, messageOrdinal);
|
|
65
|
+
}
|
|
66
|
+
function backfillMessageFtsRowidMapBatch(db, batchSize = MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE) {
|
|
67
|
+
const boundedBatchSize = Number.isFinite(batchSize) ? Math.min(MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE, Math.max(1, Math.floor(batchSize))) : MESSAGE_FTS_ROWID_MAP_BACKFILL_BATCH_SIZE;
|
|
68
|
+
let progress = {
|
|
69
|
+
processed: 0,
|
|
70
|
+
watermarkRowid: 0,
|
|
71
|
+
completed: false
|
|
72
|
+
};
|
|
73
|
+
let transactionStartedAt = 0;
|
|
74
|
+
db.transaction(() => {
|
|
75
|
+
transactionStartedAt = performance.now();
|
|
76
|
+
db.prepare(`INSERT OR IGNORE INTO message_fts_rowid_map_backfill_state
|
|
77
|
+
(id, watermark_rowid, completed) VALUES (?, 0, 0)`).run(BACKFILL_STATE_ID);
|
|
78
|
+
const state = getBackfillState(db);
|
|
79
|
+
if (state.completed) {
|
|
80
|
+
progress = state;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const rows = db.prepare(`SELECT rowid AS ftsRowid,
|
|
84
|
+
session_id AS sessionId, message_ordinal AS messageOrdinal
|
|
85
|
+
FROM message_history_fts WHERE rowid > ? ORDER BY rowid ASC LIMIT ?`).all(state.watermarkRowid, boundedBatchSize);
|
|
86
|
+
let watermarkRowid = state.watermarkRowid;
|
|
87
|
+
for (const row of rows) {
|
|
88
|
+
const ftsRowid = Number(row.ftsRowid);
|
|
89
|
+
const messageOrdinal = Number(row.messageOrdinal);
|
|
90
|
+
if (Number.isSafeInteger(ftsRowid) && ftsRowid > watermarkRowid) {
|
|
91
|
+
watermarkRowid = ftsRowid;
|
|
92
|
+
}
|
|
93
|
+
if (typeof row.sessionId === "string" && Number.isSafeInteger(messageOrdinal) && messageOrdinal >= 0 && Number.isSafeInteger(ftsRowid) && ftsRowid > 0) {
|
|
94
|
+
recordMessageFtsRowid(db, row.sessionId, messageOrdinal, ftsRowid);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const completed = rows.length < boundedBatchSize;
|
|
98
|
+
db.prepare(`UPDATE message_fts_rowid_map_backfill_state
|
|
99
|
+
SET watermark_rowid = ?, completed = ?, updated_at = ?
|
|
100
|
+
WHERE id = ?`).run(watermarkRowid, completed ? 1 : 0, Date.now(), BACKFILL_STATE_ID);
|
|
101
|
+
progress = {
|
|
102
|
+
processed: rows.length,
|
|
103
|
+
watermarkRowid,
|
|
104
|
+
completed
|
|
105
|
+
};
|
|
106
|
+
}).immediate();
|
|
107
|
+
logSlowWriteTransaction("message_fts_rowid_backfill", transactionStartedAt);
|
|
108
|
+
return progress;
|
|
109
|
+
}
|
|
110
|
+
async function runMessageFtsRowidMapBackfill(db) {
|
|
111
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
112
|
+
for (;; ) {
|
|
113
|
+
const progress = backfillMessageFtsRowidMapBatch(db);
|
|
114
|
+
if (progress.completed)
|
|
115
|
+
return;
|
|
116
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
function startMessageFtsRowidMapBackfill(db) {
|
|
120
|
+
const active = activeBackfills.get(db);
|
|
121
|
+
if (active)
|
|
122
|
+
return active;
|
|
123
|
+
const run = withoutSqliteTransformPass2(() => withSqliteBackgroundWriter2(() => runMessageFtsRowidMapBackfill(db))).finally(() => {
|
|
124
|
+
activeBackfills.delete(db);
|
|
125
|
+
});
|
|
126
|
+
activeBackfills.set(db, run);
|
|
127
|
+
return run;
|
|
128
|
+
}
|
|
129
|
+
function messageFtsOrdinalRangeIsMapped(db, sessionId, startOrdinal, endOrdinal) {
|
|
130
|
+
if (endOrdinal < startOrdinal)
|
|
131
|
+
return true;
|
|
132
|
+
if (getBackfillState(db).completed)
|
|
133
|
+
return true;
|
|
134
|
+
let statement = rangeReadyStatements.get(db);
|
|
135
|
+
if (!statement) {
|
|
136
|
+
statement = db.prepare(`SELECT COUNT(DISTINCT source.message_ordinal) AS sourceOrdinalCount,
|
|
137
|
+
COUNT(DISTINCT CASE
|
|
138
|
+
WHEN source.role IN ('user', 'assistant')
|
|
139
|
+
AND source.normalized_content_hash != ?
|
|
140
|
+
THEN source.message_ordinal
|
|
141
|
+
END) AS expectedMapCount,
|
|
142
|
+
COUNT(DISTINCT CASE
|
|
143
|
+
WHEN source.role IN ('user', 'assistant')
|
|
144
|
+
AND source.normalized_content_hash != ?
|
|
145
|
+
AND map.fts_rowid IS NOT NULL
|
|
146
|
+
THEN source.message_ordinal
|
|
147
|
+
END) AS mappedCount
|
|
148
|
+
FROM message_history_source AS source
|
|
149
|
+
LEFT JOIN message_fts_rowid_map AS map
|
|
150
|
+
ON map.session_id = source.session_id
|
|
151
|
+
AND map.message_ordinal = source.message_ordinal
|
|
152
|
+
WHERE source.session_id = ?
|
|
153
|
+
AND source.message_ordinal BETWEEN ? AND ?`);
|
|
154
|
+
rangeReadyStatements.set(db, statement);
|
|
155
|
+
}
|
|
156
|
+
const row = statement.get(EMPTY_INDEX_CONTENT_HASH, EMPTY_INDEX_CONTENT_HASH, sessionId, startOrdinal, endOrdinal);
|
|
157
|
+
const ordinalCount = endOrdinal - startOrdinal + 1;
|
|
158
|
+
return row?.sourceOrdinalCount === ordinalCount && row.expectedMapCount === row.mappedCount;
|
|
159
|
+
}
|
|
160
|
+
function deleteUnmappedMessageFtsRows(db, sessionIds) {
|
|
161
|
+
if (sessionIds.length === 0)
|
|
162
|
+
return;
|
|
163
|
+
const state = getBackfillState(db);
|
|
164
|
+
if (state.completed)
|
|
165
|
+
return;
|
|
166
|
+
const placeholders = sessionIds.map(() => "?").join(", ");
|
|
167
|
+
db.prepare(`DELETE FROM message_history_fts
|
|
168
|
+
WHERE rowid > ? AND session_id IN (${placeholders})`).run(state.watermarkRowid, ...sessionIds);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export { recordMessageFtsRowid, recordIndexedMessageTime, startMessageFtsRowidMapBackfill, messageFtsOrdinalRangeIsMapped, deleteUnmappedMessageFtsRows };
|