@cortexkit/magic-context 0.24.1 → 0.26.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.
Files changed (2) hide show
  1. package/dist/index.js +1187 -443
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11544,6 +11544,14 @@ function buildNodeSqliteDatabaseClass(DatabaseSync) {
11544
11544
  }
11545
11545
  super(typeof filename === "string" ? filename : ":memory:", translated);
11546
11546
  }
11547
+ prepare(sql) {
11548
+ const stmt = super.prepare(sql);
11549
+ for (const method of ["run", "get", "all"]) {
11550
+ const original = stmt[method].bind(stmt);
11551
+ stmt[method] = (...args) => args.length === 1 && Array.isArray(args[0]) ? original(...args[0]) : original(...args);
11552
+ }
11553
+ return stmt;
11554
+ }
11547
11555
  transaction(fn) {
11548
11556
  const self = this;
11549
11557
  const wrapped = function(...args) {
@@ -12204,6 +12212,622 @@ var init_migrate = __esm(async () => {
12204
12212
  await init_sqlite();
12205
12213
  });
12206
12214
 
12215
+ // ../plugin/src/features/magic-context/memory/project-identity.ts
12216
+ import { execFileSync as execFileSync3 } from "node:child_process";
12217
+ import { createHash } from "node:crypto";
12218
+ import { statSync as statSync3 } from "node:fs";
12219
+ import path2 from "node:path";
12220
+ function asError(error) {
12221
+ return error instanceof Error ? error : undefined;
12222
+ }
12223
+ function getErrorCode(error) {
12224
+ if (error === null || typeof error !== "object" || !("code" in error)) {
12225
+ return;
12226
+ }
12227
+ const code = error.code;
12228
+ return typeof code === "string" ? code : undefined;
12229
+ }
12230
+ function getErrorSignal(error) {
12231
+ if (error === null || typeof error !== "object" || !("signal" in error)) {
12232
+ return;
12233
+ }
12234
+ const signal = error.signal;
12235
+ return typeof signal === "string" ? signal : undefined;
12236
+ }
12237
+ function getErrorKilled(error) {
12238
+ if (error === null || typeof error !== "object" || !("killed" in error)) {
12239
+ return false;
12240
+ }
12241
+ return error.killed === true;
12242
+ }
12243
+ function getErrorStderr(error) {
12244
+ if (error === null || typeof error !== "object" || !("stderr" in error)) {
12245
+ return "";
12246
+ }
12247
+ const stderr = error.stderr;
12248
+ if (typeof stderr === "string") {
12249
+ return stderr;
12250
+ }
12251
+ if (Buffer.isBuffer(stderr)) {
12252
+ return stderr.toString("utf8");
12253
+ }
12254
+ return "";
12255
+ }
12256
+ function directoryFallback(directory) {
12257
+ const canonical = path2.resolve(directory);
12258
+ const hash = createHash("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
12259
+ return `dir:${hash}`;
12260
+ }
12261
+ function assertDirectoryUsable(canonicalDirectory, rawDirectory) {
12262
+ try {
12263
+ const stat = statSync3(canonicalDirectory);
12264
+ if (!stat.isDirectory()) {
12265
+ throw new ProjectIdentityError("unknown", rawDirectory, `Project path is not a directory: ${canonicalDirectory}`);
12266
+ }
12267
+ } catch (error) {
12268
+ if (error instanceof ProjectIdentityError) {
12269
+ throw error;
12270
+ }
12271
+ const code = getErrorCode(error);
12272
+ if (code === "EACCES" || code === "EPERM") {
12273
+ throw new ProjectIdentityError("permission_denied", rawDirectory, `Permission denied while accessing project directory: ${canonicalDirectory}`, asError(error));
12274
+ }
12275
+ throw new ProjectIdentityError("unknown", rawDirectory, `Unable to access project directory: ${canonicalDirectory}`, asError(error));
12276
+ }
12277
+ }
12278
+ function isGitTimeoutError(error) {
12279
+ const code = getErrorCode(error);
12280
+ const signal = getErrorSignal(error);
12281
+ return code === "ETIMEDOUT" || signal === "SIGTERM" || signal === "SIGKILL" || getErrorKilled(error);
12282
+ }
12283
+ function classifyGitError(error, rawDirectory) {
12284
+ if (isGitTimeoutError(error)) {
12285
+ return new ProjectIdentityError("git_timeout", rawDirectory, `git rev-list timed out after ${GIT_TIMEOUT_MS}ms`, asError(error));
12286
+ }
12287
+ const code = getErrorCode(error);
12288
+ if (code === "ENOENT") {
12289
+ return new ProjectIdentityError("git_missing", rawDirectory, "git binary is not available in PATH", asError(error));
12290
+ }
12291
+ if (code === "EACCES" || code === "EPERM") {
12292
+ return new ProjectIdentityError("permission_denied", rawDirectory, "Permission denied while spawning git", asError(error));
12293
+ }
12294
+ const stderr = getErrorStderr(error).toLowerCase();
12295
+ if (stderr.includes("not a git repository") || stderr.includes("does not have any commits yet") || stderr.includes("ambiguous argument 'head'") || stderr.includes("unknown revision or path")) {
12296
+ return new ProjectIdentityError("not_git_repo", rawDirectory, "Directory has no git root commit; caller may use directory fallback", asError(error));
12297
+ }
12298
+ return new ProjectIdentityError("unknown", rawDirectory, "git rev-list failed while resolving project identity", asError(error));
12299
+ }
12300
+ function resolveProjectIdentityStrict(directory) {
12301
+ const canonical = path2.resolve(directory);
12302
+ const cached = identityCache.get(canonical);
12303
+ if (cached !== undefined) {
12304
+ return cached;
12305
+ }
12306
+ assertDirectoryUsable(canonical, directory);
12307
+ let output;
12308
+ try {
12309
+ output = execFileSync3("git", ["rev-list", "--max-parents=0", "HEAD"], {
12310
+ cwd: canonical,
12311
+ encoding: "utf8",
12312
+ env: { ...process.env, LC_ALL: "C", LANG: "C" },
12313
+ stdio: ["ignore", "pipe", "pipe"],
12314
+ timeout: GIT_TIMEOUT_MS
12315
+ });
12316
+ } catch (error) {
12317
+ throw classifyGitError(error, directory);
12318
+ }
12319
+ const firstLine = output.split(`
12320
+ `)[0]?.trim() ?? "";
12321
+ const rootCommit = firstLine.slice(0, 64);
12322
+ if (rootCommit.length < 7) {
12323
+ throw new ProjectIdentityError("unknown", directory, "git rev-list returned no valid root commit hash");
12324
+ }
12325
+ const identity = `git:${rootCommit}`;
12326
+ identityCache.set(canonical, identity);
12327
+ return identity;
12328
+ }
12329
+ function shouldUseDirectoryFallback(error) {
12330
+ return error.errorClass === "not_git_repo" || error.errorClass === "unknown" && error.message.startsWith("Unable to access project directory:");
12331
+ }
12332
+ function resolveProjectIdentity(directory) {
12333
+ const canonical = path2.resolve(directory);
12334
+ const cachedFallback = directoryFallbackCache.get(canonical);
12335
+ if (cachedFallback !== undefined) {
12336
+ if (!hasGitDir(canonical)) {
12337
+ return cachedFallback;
12338
+ }
12339
+ directoryFallbackCache.delete(canonical);
12340
+ }
12341
+ try {
12342
+ return resolveProjectIdentityStrict(directory);
12343
+ } catch (error) {
12344
+ if (error instanceof ProjectIdentityError && shouldUseDirectoryFallback(error)) {
12345
+ const fallback = directoryFallback(canonical);
12346
+ if (!hasGitDir(canonical)) {
12347
+ directoryFallbackCache.set(canonical, fallback);
12348
+ }
12349
+ return fallback;
12350
+ }
12351
+ throw error;
12352
+ }
12353
+ }
12354
+ function hasGitDir(canonical) {
12355
+ try {
12356
+ statSync3(path2.join(canonical, ".git"));
12357
+ return true;
12358
+ } catch {
12359
+ return false;
12360
+ }
12361
+ }
12362
+ var GIT_TIMEOUT_MS = 5000, identityCache, directoryFallbackCache, ProjectIdentityError;
12363
+ var init_project_identity = __esm(() => {
12364
+ identityCache = new Map;
12365
+ directoryFallbackCache = new Map;
12366
+ ProjectIdentityError = class ProjectIdentityError extends Error {
12367
+ errorClass;
12368
+ rawDirectory;
12369
+ constructor(errorClass, rawDirectory, message, cause) {
12370
+ super(message);
12371
+ this.name = "ProjectIdentityError";
12372
+ this.errorClass = errorClass;
12373
+ this.rawDirectory = rawDirectory;
12374
+ if (cause) {
12375
+ this.cause = cause;
12376
+ }
12377
+ }
12378
+ };
12379
+ });
12380
+
12381
+ // ../plugin/src/features/magic-context/memory/relocate-memory.ts
12382
+ function selectRelocatableMemoryIds(db, fromProjectPath, selection = {}) {
12383
+ const statuses = selection.statuses ?? DEFAULT_STATUSES;
12384
+ if (statuses.length === 0)
12385
+ return [];
12386
+ const statusPlaceholders = statuses.map(() => "?").join(", ");
12387
+ const params = [fromProjectPath, ...statuses];
12388
+ let sql = `SELECT id FROM memories WHERE project_path = ? AND status IN (${statusPlaceholders})`;
12389
+ if (selection.sourceSessionId !== undefined) {
12390
+ sql += " AND source_session_id = ?";
12391
+ params.push(selection.sourceSessionId);
12392
+ }
12393
+ sql += " ORDER BY id ASC";
12394
+ const rows = db.prepare(sql).all(...params);
12395
+ return rows.map((row) => row.id);
12396
+ }
12397
+ function rekeyMemoryRowWithCollisionMerge(db, rowId, fromProjectPath, toIdentity) {
12398
+ const row = db.prepare("SELECT category, normalized_hash, seen_count FROM memories WHERE id = ?").get(rowId);
12399
+ if (!row)
12400
+ return false;
12401
+ const collision = db.prepare(`SELECT id, seen_count FROM memories
12402
+ WHERE project_path = ? AND category = ? AND normalized_hash = ?
12403
+ LIMIT 1`).get(toIdentity, row.category, row.normalized_hash);
12404
+ if (collision && collision.id !== rowId) {
12405
+ const mergedSeen = Math.max(collision.seen_count ?? 1, row.seen_count ?? 1);
12406
+ if (mergedSeen !== (collision.seen_count ?? 1)) {
12407
+ db.prepare("UPDATE memories SET seen_count = ? WHERE id = ?").run(mergedSeen, collision.id);
12408
+ }
12409
+ db.prepare(`INSERT OR IGNORE INTO memory_embeddings (memory_id, embedding, model_id)
12410
+ SELECT ?, embedding, model_id FROM memory_embeddings WHERE memory_id = ?`).run(collision.id, rowId);
12411
+ db.prepare("DELETE FROM memories WHERE id = ?").run(rowId);
12412
+ return true;
12413
+ }
12414
+ const result = db.prepare("UPDATE memories SET project_path = ? WHERE id = ? AND project_path = ?").run(toIdentity, rowId, fromProjectPath);
12415
+ return (result.changes ?? 0) > 0;
12416
+ }
12417
+ function moveMemoriesToProject(db, ids, fromProjectPath, toIdentity) {
12418
+ let relocated = 0;
12419
+ let merged = 0;
12420
+ for (const id of ids) {
12421
+ const row = db.prepare("SELECT category, normalized_hash FROM memories WHERE id = ?").get(id);
12422
+ if (!row)
12423
+ continue;
12424
+ const collision = db.prepare(`SELECT id FROM memories WHERE project_path = ? AND category = ? AND normalized_hash = ? LIMIT 1`).get(toIdentity, row.category, row.normalized_hash);
12425
+ const changed = rekeyMemoryRowWithCollisionMerge(db, id, fromProjectPath, toIdentity);
12426
+ if (!changed)
12427
+ continue;
12428
+ if (collision && collision.id !== id)
12429
+ merged += 1;
12430
+ else
12431
+ relocated += 1;
12432
+ }
12433
+ return { relocated, merged, skipped: 0 };
12434
+ }
12435
+ function getMemoryCopyColumns(db) {
12436
+ const cached = memoryCopyColumnsCache.get(db);
12437
+ if (cached)
12438
+ return cached;
12439
+ const columns = db.prepare("PRAGMA table_info(memories)").all();
12440
+ const names = columns.map((c2) => c2.name).filter((n) => typeof n === "string" && n !== "id");
12441
+ memoryCopyColumnsCache.set(db, names);
12442
+ return names;
12443
+ }
12444
+ function copyMemoriesToProject(db, ids, toIdentity) {
12445
+ const columns = getMemoryCopyColumns(db);
12446
+ const selectExprs = columns.map((c2) => c2 === "project_path" ? "? AS project_path" : c2);
12447
+ const insertSql = `INSERT OR IGNORE INTO memories (${columns.join(", ")})
12448
+ SELECT ${selectExprs.join(", ")} FROM memories WHERE id = ?`;
12449
+ const insertStmt = db.prepare(insertSql);
12450
+ const copyEmbeddingStmt = db.prepare(`INSERT OR IGNORE INTO memory_embeddings (memory_id, embedding, model_id)
12451
+ SELECT ?, embedding, model_id FROM memory_embeddings WHERE memory_id = ?`);
12452
+ let relocated = 0;
12453
+ let skipped = 0;
12454
+ for (const id of ids) {
12455
+ const result = insertStmt.run(toIdentity, id);
12456
+ if ((result.changes ?? 0) > 0) {
12457
+ relocated += 1;
12458
+ copyEmbeddingStmt.run(Number(result.lastInsertRowid), id);
12459
+ } else {
12460
+ skipped += 1;
12461
+ }
12462
+ }
12463
+ return { relocated, merged: 0, skipped };
12464
+ }
12465
+ var DEFAULT_STATUSES, memoryCopyColumnsCache;
12466
+ var init_relocate_memory = __esm(() => {
12467
+ DEFAULT_STATUSES = ["active", "permanent"];
12468
+ memoryCopyColumnsCache = new WeakMap;
12469
+ });
12470
+
12471
+ // ../plugin/src/features/magic-context/storage-project-state.ts
12472
+ function toProjectState(row) {
12473
+ return {
12474
+ projectPath: row.project_path,
12475
+ projectMemoryEpoch: row.project_memory_epoch,
12476
+ projectUserProfileVersion: row.project_user_profile_version,
12477
+ updatedAt: row.updated_at
12478
+ };
12479
+ }
12480
+ function getProjectState(db, projectPath) {
12481
+ const row = db.prepare(`SELECT project_path, project_memory_epoch, project_user_profile_version, updated_at
12482
+ FROM project_state
12483
+ WHERE project_path = ?`).get(projectPath);
12484
+ return row ? toProjectState(row) : null;
12485
+ }
12486
+ function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
12487
+ db.prepare(`INSERT INTO project_state
12488
+ (project_path, project_memory_epoch, project_user_profile_version, updated_at)
12489
+ VALUES (?, 1, 0, ?)
12490
+ ON CONFLICT(project_path) DO UPDATE SET
12491
+ project_memory_epoch = project_memory_epoch + 1,
12492
+ updated_at = excluded.updated_at`).run(projectPath, now);
12493
+ const state = getProjectState(db, projectPath);
12494
+ if (!state) {
12495
+ throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
12496
+ }
12497
+ return state;
12498
+ }
12499
+
12500
+ // src/commands/migrate-session.ts
12501
+ var exports_migrate_session = {};
12502
+ __export(exports_migrate_session, {
12503
+ runMigrateSessionCli: () => runMigrateSessionCli,
12504
+ planMigrateSession: () => planMigrateSession,
12505
+ applyMigrateSession: () => applyMigrateSession
12506
+ });
12507
+ import { copyFileSync, existsSync as existsSync11, realpathSync } from "node:fs";
12508
+ import { homedir as homedir7 } from "node:os";
12509
+ import path3, { join as join10 } from "node:path";
12510
+ function existingSessionColumns(db) {
12511
+ const rows = db.prepare("PRAGMA table_info(session)").all();
12512
+ return new Set(rows.map((r) => r.name).filter((n) => typeof n === "string"));
12513
+ }
12514
+ function planMigrateSession(sessionId, rawTargetDirectory, deps) {
12515
+ const sessionRow = deps.opencodeDb.prepare("SELECT id, directory FROM session WHERE id = ?").get(sessionId);
12516
+ if (!sessionRow) {
12517
+ throw new Error(`Session ${sessionId} not found in opencode.db.`);
12518
+ }
12519
+ const targetDirectory = deps.realpath(rawTargetDirectory);
12520
+ const targetIsGit = deps.hasGitDir(targetDirectory);
12521
+ const projectRow = deps.opencodeDb.prepare("SELECT id, worktree FROM project WHERE worktree = ?").get(targetDirectory);
12522
+ let ocProjectId;
12523
+ let ocWorktree;
12524
+ const ocProjectResolvedFromRow = projectRow != null;
12525
+ if (projectRow) {
12526
+ ocProjectId = projectRow.id;
12527
+ ocWorktree = projectRow.worktree;
12528
+ } else {
12529
+ const globalRow = deps.opencodeDb.prepare("SELECT id, worktree FROM project WHERE id = 'global'").get();
12530
+ if (!globalRow) {
12531
+ throw new Error(`The OpenCode 'global' project row is missing.
12532
+ ` + "Open any folder in OpenCode once to create it, then re-run.");
12533
+ }
12534
+ ocProjectId = "global";
12535
+ ocWorktree = globalRow.worktree || "/";
12536
+ }
12537
+ const sessionPath = path3.relative(ocWorktree, targetDirectory);
12538
+ const ownershipRow = deps.contextDb.prepare("SELECT project_path FROM session_projects WHERE session_id = ? AND harness = 'opencode'").get(sessionId);
12539
+ const fromMcIdentity = ownershipRow?.project_path ?? (sessionRow.directory ? deps.resolveIdentity(sessionRow.directory) : "");
12540
+ const toMcIdentity = deps.resolveIdentity(targetDirectory);
12541
+ const injectableMemoryCount = deps.contextDb.prepare("SELECT COUNT(*) AS c FROM memories WHERE project_path = ? AND status IN ('active','permanent')").get(fromMcIdentity).c;
12542
+ const originatedMemoryCount = deps.contextDb.prepare("SELECT COUNT(*) AS c FROM memories WHERE project_path = ? AND status IN ('active','permanent') AND source_session_id = ?").get(fromMcIdentity, sessionId).c;
12543
+ return {
12544
+ sessionId,
12545
+ currentDirectory: sessionRow.directory,
12546
+ targetDirectory,
12547
+ ocProjectId,
12548
+ ocWorktree,
12549
+ ocProjectResolvedFromRow,
12550
+ sessionPath,
12551
+ fromMcIdentity,
12552
+ toMcIdentity,
12553
+ targetIsGit,
12554
+ injectableMemoryCount,
12555
+ originatedMemoryCount
12556
+ };
12557
+ }
12558
+ function applyMigrateSession(plan, memoryAction, deps) {
12559
+ const now = deps.now ?? Date.now();
12560
+ const cols = existingSessionColumns(deps.opencodeDb);
12561
+ const sets = ["directory = ?"];
12562
+ const params = [plan.targetDirectory];
12563
+ if (cols.has("project_id")) {
12564
+ sets.push("project_id = ?");
12565
+ params.push(plan.ocProjectId);
12566
+ }
12567
+ if (cols.has("path")) {
12568
+ sets.push("path = ?");
12569
+ params.push(plan.sessionPath);
12570
+ }
12571
+ if (cols.has("workspace_id")) {
12572
+ sets.push("workspace_id = ?");
12573
+ params.push(null);
12574
+ }
12575
+ const restoreCols = ["directory", ...sets.map((s) => s.split(" = ")[0]).slice(1)];
12576
+ const priorRow = deps.opencodeDb.prepare(`SELECT ${restoreCols.join(", ")} FROM session WHERE id = ?`).get(plan.sessionId);
12577
+ deps.opencodeDb.exec("BEGIN IMMEDIATE");
12578
+ try {
12579
+ deps.opencodeDb.prepare(`UPDATE session SET ${sets.join(", ")} WHERE id = ?`).run(...params, plan.sessionId);
12580
+ deps.opencodeDb.exec("COMMIT");
12581
+ } catch (error) {
12582
+ deps.opencodeDb.exec("ROLLBACK");
12583
+ throw error;
12584
+ }
12585
+ const compensateOpenCode = () => {
12586
+ if (!priorRow)
12587
+ return;
12588
+ try {
12589
+ const restoreSets = restoreCols.map((c2) => `${c2} = ?`).join(", ");
12590
+ const restoreParams = restoreCols.map((c2) => priorRow[c2] ?? null);
12591
+ deps.opencodeDb.exec("BEGIN IMMEDIATE");
12592
+ deps.opencodeDb.prepare(`UPDATE session SET ${restoreSets} WHERE id = ?`).run(...restoreParams, plan.sessionId);
12593
+ deps.opencodeDb.exec("COMMIT");
12594
+ } catch {
12595
+ try {
12596
+ deps.opencodeDb.exec("ROLLBACK");
12597
+ } catch {}
12598
+ }
12599
+ };
12600
+ let memoriesRelocated = 0;
12601
+ let memoriesMerged = 0;
12602
+ let memoriesSkipped = 0;
12603
+ let chunkEmbeddingsRestamped = 0;
12604
+ const epochsBumped = [];
12605
+ deps.contextDb.exec("BEGIN IMMEDIATE");
12606
+ try {
12607
+ deps.contextDb.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
12608
+ VALUES (?, 'opencode', ?, ?)
12609
+ ON CONFLICT(session_id, harness)
12610
+ DO UPDATE SET project_path = excluded.project_path, updated_at = excluded.updated_at`).run(plan.sessionId, plan.toMcIdentity, now);
12611
+ const chunkResult = deps.contextDb.prepare("UPDATE compartment_chunk_embeddings SET project_path = ? WHERE session_id = ?").run(plan.toMcIdentity, plan.sessionId);
12612
+ chunkEmbeddingsRestamped = chunkResult.changes ?? 0;
12613
+ deps.contextDb.prepare("UPDATE session_meta SET cached_m0_bytes = NULL, cached_m1_bytes = NULL WHERE session_id = ?").run(plan.sessionId);
12614
+ if (memoryAction !== "leave" && plan.fromMcIdentity && plan.fromMcIdentity !== plan.toMcIdentity) {
12615
+ const originatedOnly = memoryAction === "move-originated" || memoryAction === "copy-originated";
12616
+ const ids = selectRelocatableMemoryIds(deps.contextDb, plan.fromMcIdentity, originatedOnly ? { sourceSessionId: plan.sessionId } : {});
12617
+ const isMove = memoryAction === "move-all" || memoryAction === "move-originated";
12618
+ const result = isMove ? moveMemoriesToProject(deps.contextDb, ids, plan.fromMcIdentity, plan.toMcIdentity) : copyMemoriesToProject(deps.contextDb, ids, plan.toMcIdentity);
12619
+ memoriesRelocated = result.relocated;
12620
+ memoriesMerged = result.merged;
12621
+ memoriesSkipped = result.skipped;
12622
+ if (result.relocated > 0 || result.merged > 0) {
12623
+ bumpProjectMemoryEpoch(deps.contextDb, plan.toMcIdentity, now);
12624
+ epochsBumped.push(plan.toMcIdentity);
12625
+ if (isMove) {
12626
+ bumpProjectMemoryEpoch(deps.contextDb, plan.fromMcIdentity, now);
12627
+ epochsBumped.push(plan.fromMcIdentity);
12628
+ }
12629
+ }
12630
+ }
12631
+ deps.contextDb.exec("COMMIT");
12632
+ } catch (error) {
12633
+ deps.contextDb.exec("ROLLBACK");
12634
+ compensateOpenCode();
12635
+ throw error;
12636
+ }
12637
+ return {
12638
+ plan,
12639
+ memoryAction,
12640
+ dryRun: false,
12641
+ memoriesRelocated,
12642
+ memoriesMerged,
12643
+ memoriesSkipped,
12644
+ chunkEmbeddingsRestamped,
12645
+ epochsBumped
12646
+ };
12647
+ }
12648
+ function defaultOpenCodeDbPath2() {
12649
+ return join10(homedir7(), ".local", "share", "opencode", "opencode.db");
12650
+ }
12651
+ function defaultContextDbPath() {
12652
+ return join10(getMagicContextStorageDir(), "context.db");
12653
+ }
12654
+ function realDeps(opencodeDb, contextDb) {
12655
+ return {
12656
+ opencodeDb,
12657
+ contextDb,
12658
+ resolveIdentity: resolveProjectIdentity,
12659
+ hasGitDir: (dir) => existsSync11(join10(dir, ".git")),
12660
+ realpath: (p2) => realpathSync(p2)
12661
+ };
12662
+ }
12663
+ function valueAfter(args, flag) {
12664
+ const index = args.indexOf(flag);
12665
+ if (index === -1)
12666
+ return null;
12667
+ const next = args[index + 1];
12668
+ if (next === undefined || next.startsWith("--"))
12669
+ return null;
12670
+ return next;
12671
+ }
12672
+ function printMigrateSessionHelp() {
12673
+ console.log("");
12674
+ console.log(" doctor migrate-session — re-home an OpenCode session to another directory");
12675
+ console.log("");
12676
+ console.log(" Required:");
12677
+ console.log(" --session <id> OpenCode session id (ses_...)");
12678
+ console.log(" --to <dir> Target working directory");
12679
+ console.log("");
12680
+ console.log(" Optional:");
12681
+ console.log(" --memories <a> Non-interactive memory action:");
12682
+ console.log(" move-all | move-originated | copy-all |");
12683
+ console.log(" copy-originated | leave");
12684
+ console.log(" --dry-run Show the plan; write nothing");
12685
+ console.log(" --yes Skip the 'OpenCode stopped?' confirmation");
12686
+ console.log("");
12687
+ console.log(" Example:");
12688
+ console.log(" npx @cortexkit/magic-context@latest doctor migrate-session \\");
12689
+ console.log(" --session ses_xxx --to ~/Work/Projects/CortexKit/benchmarks --dry-run");
12690
+ console.log("");
12691
+ }
12692
+ async function promptMemoryAction(plan) {
12693
+ const all = plan.injectableMemoryCount;
12694
+ const originated = plan.originatedMemoryCount;
12695
+ promptIO.note(`${all} memory${all === 1 ? "" : "ies"} live under the current project ` + `(${plan.fromMcIdentity}); ${originated} of them originated from this session.`, "Memories");
12696
+ const choice = await promptIO.selectOne("How should memories be handled?", [
12697
+ {
12698
+ label: `Move only memories originated from this session (${originated})`,
12699
+ value: "move-originated",
12700
+ recommended: true
12701
+ },
12702
+ { label: `Move all memories of this project (${all})`, value: "move-all" },
12703
+ {
12704
+ label: `Copy only memories originated from this session (${originated})`,
12705
+ value: "copy-originated"
12706
+ },
12707
+ { label: `Copy all memories of this project (${all})`, value: "copy-all" },
12708
+ { label: "Leave memories as is", value: "leave" }
12709
+ ]);
12710
+ return choice;
12711
+ }
12712
+ async function runMigrateSessionCli(args) {
12713
+ if (args.includes("--help") || args.includes("-h")) {
12714
+ printMigrateSessionHelp();
12715
+ return 0;
12716
+ }
12717
+ const sessionId = valueAfter(args, "--session");
12718
+ const toDir = valueAfter(args, "--to");
12719
+ const dryRun = args.includes("--dry-run");
12720
+ const skipConfirm = args.includes("--yes");
12721
+ const memoriesFlag = valueAfter(args, "--memories");
12722
+ if (!sessionId) {
12723
+ console.error("Missing required flag: --session <id>");
12724
+ printMigrateSessionHelp();
12725
+ return 1;
12726
+ }
12727
+ if (!toDir) {
12728
+ console.error("Missing required flag: --to <dir>");
12729
+ printMigrateSessionHelp();
12730
+ return 1;
12731
+ }
12732
+ if (memoriesFlag !== null && !VALID_MEMORY_ACTIONS.has(memoriesFlag)) {
12733
+ console.error(`Invalid --memories value: ${memoriesFlag}`);
12734
+ printMigrateSessionHelp();
12735
+ return 1;
12736
+ }
12737
+ const expandedTo = toDir.startsWith("~") ? join10(homedir7(), toDir.slice(1).replace(/^[/\\]/, "")) : toDir;
12738
+ if (!existsSync11(expandedTo)) {
12739
+ console.error(`Target directory does not exist: ${expandedTo}`);
12740
+ return 1;
12741
+ }
12742
+ const opencodeDbPath = defaultOpenCodeDbPath2();
12743
+ const contextDbPath = defaultContextDbPath();
12744
+ const opencodeDb = new Database(opencodeDbPath);
12745
+ const contextDb = new Database(contextDbPath);
12746
+ try {
12747
+ const deps = realDeps(opencodeDb, contextDb);
12748
+ const plan = planMigrateSession(sessionId, expandedTo, deps);
12749
+ promptIO.note([
12750
+ `session: ${plan.sessionId}`,
12751
+ `from: ${plan.currentDirectory ?? "(unknown)"}`,
12752
+ `to: ${plan.targetDirectory}`,
12753
+ `OpenCode project: ${plan.ocProjectId}${plan.targetIsGit ? " (git)" : " (global / non-git)"}`,
12754
+ `MC identity: ${plan.fromMcIdentity} → ${plan.toMcIdentity}`
12755
+ ].join(`
12756
+ `), "Session move plan");
12757
+ if (plan.targetIsGit && !plan.ocProjectResolvedFromRow) {
12758
+ promptIO.log.warn(`${plan.targetDirectory} is a git repo, but OpenCode has no dedicated project for it ` + `(an empty repo with no commits/remote resolves to the shared 'global' project). ` + `For a dedicated project: make a commit (or add a remote), open OpenCode there once, then re-run.`);
12759
+ if (!dryRun) {
12760
+ if (skipConfirm) {
12761
+ promptIO.log.warn("Proceeding — the session will attach to 'global'.");
12762
+ } else {
12763
+ const proceed = await promptIO.confirm("Proceed attaching the session to the shared 'global' project?", false);
12764
+ if (!proceed) {
12765
+ promptIO.log.warn("Aborted. Make a commit / add a remote, then re-run.");
12766
+ return 1;
12767
+ }
12768
+ }
12769
+ }
12770
+ }
12771
+ const memoryAction = memoriesFlag ?? await promptMemoryAction(plan);
12772
+ if (dryRun) {
12773
+ const willMove = memoryAction === "move-all" || memoryAction === "move-originated";
12774
+ const willCopy = memoryAction === "copy-all" || memoryAction === "copy-originated";
12775
+ const count = memoryAction.endsWith("originated") ? plan.originatedMemoryCount : plan.injectableMemoryCount;
12776
+ promptIO.log.info(`[dry-run] Would update opencode.db session row → project ${plan.ocProjectId}, dir ${plan.targetDirectory}.`);
12777
+ promptIO.log.info(`[dry-run] Would re-stamp session_projects + chunk embeddings to ${plan.toMcIdentity} and clear cached m[0]/m[1].`);
12778
+ promptIO.log.info(`[dry-run] Memories: ${memoryAction === "leave" ? "left as is" : `${willMove ? "move" : willCopy ? "copy" : "?"} ${count}`}.`);
12779
+ promptIO.log.info("[dry-run] No changes written.");
12780
+ return 0;
12781
+ }
12782
+ if (!skipConfirm) {
12783
+ const ok = await promptIO.confirm("This edits opencode.db + context.db directly. Is OpenCode (TUI / Desktop / serve) fully stopped?", false);
12784
+ if (!ok) {
12785
+ promptIO.log.warn("Aborted. Stop OpenCode, then re-run.");
12786
+ return 1;
12787
+ }
12788
+ }
12789
+ const stamp = new Date().toISOString().replace(/[:.]/g, "-");
12790
+ const ocBackup = `${opencodeDbPath}.bak-${stamp}`;
12791
+ const ctxBackup = `${contextDbPath}.bak-${stamp}`;
12792
+ copyFileSync(opencodeDbPath, ocBackup);
12793
+ copyFileSync(contextDbPath, ctxBackup);
12794
+ promptIO.log.info(`Backed up: ${ocBackup}`);
12795
+ promptIO.log.info(`Backed up: ${ctxBackup}`);
12796
+ const result = applyMigrateSession(plan, memoryAction, deps);
12797
+ promptIO.log.success("Session re-homed.");
12798
+ console.log(` OpenCode: project ${plan.ocProjectId}, directory ${plan.targetDirectory}`);
12799
+ console.log(` MC identity: ${plan.fromMcIdentity} → ${plan.toMcIdentity}`);
12800
+ console.log(` chunk embeddings re-stamped: ${result.chunkEmbeddingsRestamped}`);
12801
+ console.log(` memories: ${result.memoriesRelocated} ${memoryAction.startsWith("copy") ? "copied" : "moved"}` + (result.memoriesMerged ? `, ${result.memoriesMerged} merged` : "") + (result.memoriesSkipped ? `, ${result.memoriesSkipped} skipped (already present)` : ""));
12802
+ if (result.epochsBumped.length > 0) {
12803
+ console.log(` memory epoch bumped: ${result.epochsBumped.join(", ")}`);
12804
+ }
12805
+ console.log("Restart OpenCode to pick up the moved session.");
12806
+ return 0;
12807
+ } catch (error) {
12808
+ console.error(error instanceof Error ? error.message : String(error));
12809
+ return 1;
12810
+ } finally {
12811
+ opencodeDb.close();
12812
+ contextDb.close();
12813
+ }
12814
+ }
12815
+ var VALID_MEMORY_ACTIONS;
12816
+ var init_migrate_session = __esm(async () => {
12817
+ init_project_identity();
12818
+ init_relocate_memory();
12819
+ init_data_path();
12820
+ init_prompts();
12821
+ await init_sqlite();
12822
+ VALID_MEMORY_ACTIONS = new Set([
12823
+ "move-all",
12824
+ "move-originated",
12825
+ "copy-all",
12826
+ "copy-originated",
12827
+ "leave"
12828
+ ]);
12829
+ });
12830
+
12207
12831
  // ../plugin/src/features/magic-context/compartment-lease.ts
12208
12832
  var COMPARTMENT_LEASE_TTL_MS, COMPARTMENT_LEASE_RENEWAL_MS;
12209
12833
  var init_compartment_lease = __esm(() => {
@@ -12255,9 +12879,9 @@ var init_compartment_storage = __esm(() => {
12255
12879
  });
12256
12880
  // ../plugin/src/shared/logger.ts
12257
12881
  import * as fs from "node:fs";
12258
- import * as path2 from "node:path";
12882
+ import * as path4 from "node:path";
12259
12883
  function ensureDir5(filePath) {
12260
- const dir = path2.dirname(filePath);
12884
+ const dir = path4.dirname(filePath);
12261
12885
  if (dir === lastEnsuredDir)
12262
12886
  return;
12263
12887
  try {
@@ -144790,16 +145414,18 @@ function stripTagPrefix(value) {
144790
145414
  const prev = stripped;
144791
145415
  stripped = stripped.replace(MALFORMED_TAG_PREFIX_REGEX, "");
144792
145416
  stripped = stripped.replace(TAG_PREFIX_REGEX, "");
145417
+ stripped = stripped.replace(DANGLING_TAG_PREFIX_REGEX, "");
144793
145418
  if (stripped === prev)
144794
145419
  break;
144795
145420
  }
144796
145421
  return stripped;
144797
145422
  }
144798
- var encoder, TAG_PREFIX_REGEX, MALFORMED_TAG_PREFIX_REGEX;
145423
+ var encoder, TAG_PREFIX_REGEX, MALFORMED_TAG_PREFIX_REGEX, DANGLING_TAG_PREFIX_REGEX;
144799
145424
  var init_tag_content_primitives = __esm(() => {
144800
145425
  encoder = new TextEncoder;
144801
145426
  TAG_PREFIX_REGEX = /^(?:§\d+§\s*)+/;
144802
145427
  MALFORMED_TAG_PREFIX_REGEX = /^(?:§\d+">§(?:\d+§)?\s*)+/;
145428
+ DANGLING_TAG_PREFIX_REGEX = /^(?:\u00a7\d+(?!\.\d)[^\s\u00a7\w.]?\s*)+/;
144803
145429
  });
144804
145430
 
144805
145431
  // ../plugin/src/hooks/magic-context/tag-part-guards.ts
@@ -144869,13 +145495,14 @@ var init_tool_drop_target = __esm(() => {
144869
145495
  });
144870
145496
 
144871
145497
  // ../plugin/src/hooks/magic-context/read-session-chunk.ts
144872
- var sessionProviders;
145498
+ var blockTokenMemo, sessionProviders;
144873
145499
  var init_read_session_chunk = __esm(async () => {
144874
145500
  init_read_session_formatting();
144875
145501
  init_tag_part_guards();
144876
145502
  init_tool_drop_target();
144877
145503
  init_read_session_formatting();
144878
145504
  await init_read_session_db();
145505
+ blockTokenMemo = new Map;
144879
145506
  sessionProviders = new Map;
144880
145507
  });
144881
145508
 
@@ -144898,7 +145525,7 @@ function getErrorMessage(error) {
144898
145525
  }
144899
145526
 
144900
145527
  // ../plugin/src/features/magic-context/key-files/project-key-files.ts
144901
- import { existsSync as existsSync11, readFileSync as readFileSync7, realpathSync } from "node:fs";
145528
+ import { existsSync as existsSync12, readFileSync as readFileSync7, realpathSync as realpathSync2 } from "node:fs";
144902
145529
  function deleteOrphanProjectKeyFiles(db, now = Date.now()) {
144903
145530
  const cutoff = now - ORPHAN_GRACE_MS;
144904
145531
  const rows = db.prepare(`SELECT project_path AS projectPath, MAX(generated_at) AS lastGen
@@ -144907,7 +145534,7 @@ function deleteOrphanProjectKeyFiles(db, now = Date.now()) {
144907
145534
  HAVING lastGen < ?`).all(cutoff);
144908
145535
  let deletedProjects = 0;
144909
145536
  for (const row of rows) {
144910
- if (existsSync11(row.projectPath))
145537
+ if (existsSync12(row.projectPath))
144911
145538
  continue;
144912
145539
  try {
144913
145540
  db.transaction(() => {
@@ -144960,10 +145587,10 @@ var init_tool_definition_tokens = __esm(() => {
144960
145587
  });
144961
145588
 
144962
145589
  // ../plugin/src/features/magic-context/tool-owner-backfill.ts
144963
- import { existsSync as existsSync12 } from "node:fs";
144964
- import { join as join10 } from "node:path";
145590
+ import { existsSync as existsSync13 } from "node:fs";
145591
+ import { join as join11 } from "node:path";
144965
145592
  function resolveOpencodeDbPath() {
144966
- return join10(getDataDir(), "opencode", "opencode.db");
145593
+ return join11(getDataDir(), "opencode", "opencode.db");
144967
145594
  }
144968
145595
  function ensureBackfillStateTable(db) {
144969
145596
  db.exec(`
@@ -144998,7 +145625,7 @@ function runToolOwnerBackfill(db) {
144998
145625
  return result;
144999
145626
  }
145000
145627
  const opencodeDbPath = resolveOpencodeDbPath();
145001
- if (!existsSync12(opencodeDbPath)) {
145628
+ if (!existsSync13(opencodeDbPath)) {
145002
145629
  log2(`[backfill] OpenCode DB not found at ${opencodeDbPath} — marking all unbackfilled sessions as skipped. Lazy adoption (defense-in-depth) handles legacy rows at runtime.`);
145003
145630
  markAllUnbackfilledSessionsSkipped(db);
145004
145631
  result.sessionsSkippedNoOcDb = countSessionsByStatus(db, "skipped");
@@ -145221,26 +145848,26 @@ var init_tool_owner_backfill = __esm(() => {
145221
145848
  });
145222
145849
 
145223
145850
  // ../plugin/src/features/magic-context/storage-db.ts
145224
- import { copyFileSync, cpSync, existsSync as existsSync13, mkdirSync as mkdirSync5 } from "node:fs";
145225
- import { dirname as dirname6, join as join11 } from "node:path";
145851
+ import { copyFileSync as copyFileSync2, cpSync, existsSync as existsSync14, mkdirSync as mkdirSync5 } from "node:fs";
145852
+ import { dirname as dirname6, join as join12 } from "node:path";
145226
145853
  function resolveDatabasePath(dbPathOverride) {
145227
145854
  if (dbPathOverride) {
145228
145855
  return { dbDir: dirname6(dbPathOverride), dbPath: dbPathOverride };
145229
145856
  }
145230
145857
  const testDataDir = process.env.MAGIC_CONTEXT_TEST_DATA_DIR;
145231
145858
  if (testDataDir && !process.env.XDG_DATA_HOME) {
145232
- const dbDir2 = join11(testDataDir, "cortexkit", "magic-context");
145233
- return { dbDir: dbDir2, dbPath: join11(dbDir2, "context.db") };
145859
+ const dbDir2 = join12(testDataDir, "cortexkit", "magic-context");
145860
+ return { dbDir: dbDir2, dbPath: join12(dbDir2, "context.db") };
145234
145861
  }
145235
145862
  const dbDir = getMagicContextStorageDir();
145236
- return { dbDir, dbPath: join11(dbDir, "context.db") };
145863
+ return { dbDir, dbPath: join12(dbDir, "context.db") };
145237
145864
  }
145238
145865
  function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
145239
- if (existsSync13(targetDbPath))
145866
+ if (existsSync14(targetDbPath))
145240
145867
  return;
145241
145868
  const legacyDir = getLegacyOpenCodeMagicContextStorageDir();
145242
- const legacyDbPath = join11(legacyDir, "context.db");
145243
- if (!existsSync13(legacyDbPath))
145869
+ const legacyDbPath = join12(legacyDir, "context.db");
145870
+ if (!existsSync14(legacyDbPath))
145244
145871
  return;
145245
145872
  log2(`[magic-context] migrating legacy plugin storage: ${legacyDir} -> ${targetDbDir} (legacy left in place as backup)`);
145246
145873
  mkdirSync5(targetDbDir, { recursive: true });
@@ -145256,18 +145883,18 @@ function migrateLegacyStorageIfNeeded(targetDbPath, targetDbDir) {
145256
145883
  }
145257
145884
  for (const suffix of ["", "-wal", "-shm"]) {
145258
145885
  const src = `${legacyDbPath}${suffix}`;
145259
- const dst = join11(targetDbDir, `context.db${suffix}`);
145260
- if (existsSync13(src)) {
145886
+ const dst = join12(targetDbDir, `context.db${suffix}`);
145887
+ if (existsSync14(src)) {
145261
145888
  try {
145262
- copyFileSync(src, dst);
145889
+ copyFileSync2(src, dst);
145263
145890
  } catch (error) {
145264
145891
  log2(`[magic-context] failed to copy ${src}:`, getErrorMessage(error));
145265
145892
  }
145266
145893
  }
145267
145894
  }
145268
- const legacyModelsDir = join11(legacyDir, "models");
145269
- const targetModelsDir = join11(targetDbDir, "models");
145270
- if (existsSync13(legacyModelsDir) && !existsSync13(targetModelsDir)) {
145895
+ const legacyModelsDir = join12(legacyDir, "models");
145896
+ const targetModelsDir = join12(targetDbDir, "models");
145897
+ if (existsSync14(legacyModelsDir) && !existsSync14(targetModelsDir)) {
145271
145898
  try {
145272
145899
  cpSync(legacyModelsDir, targetModelsDir, { recursive: true });
145273
145900
  } catch (error) {
@@ -145736,6 +146363,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
145736
146363
  recovery_no_eligible_head_count INTEGER NOT NULL DEFAULT 0,
145737
146364
  force_emergency_bypass_window_start INTEGER NOT NULL DEFAULT 0,
145738
146365
  force_emergency_bypass_used INTEGER NOT NULL DEFAULT 0,
146366
+ emergency_drain_active INTEGER NOT NULL DEFAULT 0,
146367
+ historian_drain_failure_at INTEGER NOT NULL DEFAULT 0,
145739
146368
  cached_m0_materialized_at INTEGER,
145740
146369
  cached_m0_session_facts_version INTEGER,
145741
146370
  cached_m0_upgrade_state TEXT,
@@ -145799,6 +146428,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
145799
146428
  CREATE INDEX IF NOT EXISTS idx_historian_runs_status
145800
146429
  ON historian_runs(status, created_at DESC);
145801
146430
 
146431
+ CREATE TABLE IF NOT EXISTS transform_decisions (
146432
+ session_id TEXT NOT NULL,
146433
+ harness TEXT NOT NULL DEFAULT 'opencode',
146434
+ message_id TEXT NOT NULL,
146435
+ ts_ms INTEGER NOT NULL,
146436
+ decision TEXT NOT NULL,
146437
+ materialized INTEGER NOT NULL DEFAULT 0,
146438
+ materialize_reason TEXT,
146439
+ emergency INTEGER NOT NULL DEFAULT 0,
146440
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
146441
+ dropped_count INTEGER NOT NULL DEFAULT 0,
146442
+ input_tokens INTEGER NOT NULL DEFAULT 0,
146443
+ PRIMARY KEY (session_id, harness, message_id)
146444
+ );
146445
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
146446
+ ON transform_decisions(session_id, harness);
146447
+
145802
146448
  CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
145803
146449
  CREATE INDEX IF NOT EXISTS idx_tags_session_message_id ON tags(session_id, message_id);
145804
146450
  CREATE INDEX IF NOT EXISTS idx_pending_ops_session ON pending_ops(session_id);
@@ -145876,6 +146522,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
145876
146522
  ensureColumn(db, "session_meta", "historian_last_failure_at", "INTEGER DEFAULT NULL");
145877
146523
  ensureColumn(db, "session_meta", "system_prompt_hash", "TEXT DEFAULT ''");
145878
146524
  ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
146525
+ ensureColumn(db, "session_meta", "tool_reclaim_watermark", "INTEGER DEFAULT 0");
145879
146526
  ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
145880
146527
  ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
145881
146528
  ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
@@ -145949,6 +146596,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
145949
146596
  ensureColumn(db, "session_meta", "recovery_no_eligible_head_count", "INTEGER NOT NULL DEFAULT 0");
145950
146597
  ensureColumn(db, "session_meta", "force_emergency_bypass_window_start", "INTEGER NOT NULL DEFAULT 0");
145951
146598
  ensureColumn(db, "session_meta", "force_emergency_bypass_used", "INTEGER NOT NULL DEFAULT 0");
146599
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
146600
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
145952
146601
  ensureColumn(db, "session_meta", "cached_m0_materialized_at", "INTEGER");
145953
146602
  ensureColumn(db, "session_meta", "cached_m0_session_facts_version", "INTEGER");
145954
146603
  ensureColumn(db, "session_meta", "cached_m0_upgrade_state", "TEXT");
@@ -146027,6 +146676,22 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
146027
146676
  failed_at INTEGER NOT NULL,
146028
146677
  UNIQUE(table_name, row_id)
146029
146678
  );
146679
+ CREATE TABLE IF NOT EXISTS transform_decisions (
146680
+ session_id TEXT NOT NULL,
146681
+ harness TEXT NOT NULL DEFAULT 'opencode',
146682
+ message_id TEXT NOT NULL,
146683
+ ts_ms INTEGER NOT NULL,
146684
+ decision TEXT NOT NULL,
146685
+ materialized INTEGER NOT NULL DEFAULT 0,
146686
+ materialize_reason TEXT,
146687
+ emergency INTEGER NOT NULL DEFAULT 0,
146688
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
146689
+ dropped_count INTEGER NOT NULL DEFAULT 0,
146690
+ input_tokens INTEGER NOT NULL DEFAULT 0,
146691
+ PRIMARY KEY (session_id, harness, message_id)
146692
+ );
146693
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
146694
+ ON transform_decisions(session_id, harness);
146030
146695
  `);
146031
146696
  ensureColumn(db, "tags", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
146032
146697
  ensureColumn(db, "pending_ops", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
@@ -146112,7 +146777,9 @@ function healNullIntegerColumns(db) {
146112
146777
  ["protected_tail_drain_tokens", 0],
146113
146778
  ["recovery_no_eligible_head_count", 0],
146114
146779
  ["force_emergency_bypass_window_start", 0],
146115
- ["force_emergency_bypass_used", 0]
146780
+ ["force_emergency_bypass_used", 0],
146781
+ ["emergency_drain_active", 0],
146782
+ ["historian_drain_failure_at", 0]
146116
146783
  ];
146117
146784
  for (const [column, fallback] of columns) {
146118
146785
  try {
@@ -146188,6 +146855,7 @@ function openDatabase(dbPathOrOptions) {
146188
146855
  setDatabase(db);
146189
146856
  loadToolDefinitionMeasurements(db);
146190
146857
  databases.set(dbPath, db);
146858
+ pathByDatabase.set(db, dbPath);
146191
146859
  persistenceByDatabase.set(db, true);
146192
146860
  persistenceErrorByDatabase.delete(db);
146193
146861
  return db;
@@ -146213,7 +146881,7 @@ function closeDatabase() {
146213
146881
  }
146214
146882
  }
146215
146883
  }
146216
- var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 36, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
146884
+ var databases, persistenceByDatabase, persistenceErrorByDatabase, pathByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 38, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
146217
146885
  var init_storage_db = __esm(async () => {
146218
146886
  init_data_path();
146219
146887
  init_logger();
@@ -146227,6 +146895,7 @@ var init_storage_db = __esm(async () => {
146227
146895
  databases = new Map;
146228
146896
  persistenceByDatabase = new WeakMap;
146229
146897
  persistenceErrorByDatabase = new WeakMap;
146898
+ pathByDatabase = new WeakMap;
146230
146899
  sqlitePragmaConfig = {
146231
146900
  cacheSizeMb: 64,
146232
146901
  mmapSizeMb: 0
@@ -146268,172 +146937,6 @@ var init_constants = __esm(() => {
146268
146937
  };
146269
146938
  });
146270
146939
 
146271
- // ../plugin/src/features/magic-context/memory/project-identity.ts
146272
- import { execFileSync as execFileSync3 } from "node:child_process";
146273
- import { createHash } from "node:crypto";
146274
- import { statSync as statSync3 } from "node:fs";
146275
- import path3 from "node:path";
146276
- function asError(error) {
146277
- return error instanceof Error ? error : undefined;
146278
- }
146279
- function getErrorCode(error) {
146280
- if (error === null || typeof error !== "object" || !("code" in error)) {
146281
- return;
146282
- }
146283
- const code = error.code;
146284
- return typeof code === "string" ? code : undefined;
146285
- }
146286
- function getErrorSignal(error) {
146287
- if (error === null || typeof error !== "object" || !("signal" in error)) {
146288
- return;
146289
- }
146290
- const signal = error.signal;
146291
- return typeof signal === "string" ? signal : undefined;
146292
- }
146293
- function getErrorKilled(error) {
146294
- if (error === null || typeof error !== "object" || !("killed" in error)) {
146295
- return false;
146296
- }
146297
- return error.killed === true;
146298
- }
146299
- function getErrorStderr(error) {
146300
- if (error === null || typeof error !== "object" || !("stderr" in error)) {
146301
- return "";
146302
- }
146303
- const stderr = error.stderr;
146304
- if (typeof stderr === "string") {
146305
- return stderr;
146306
- }
146307
- if (Buffer.isBuffer(stderr)) {
146308
- return stderr.toString("utf8");
146309
- }
146310
- return "";
146311
- }
146312
- function directoryFallback(directory) {
146313
- const canonical = path3.resolve(directory);
146314
- const hash = createHash("md5").update(canonical, "utf8").digest("hex").slice(0, 12);
146315
- return `dir:${hash}`;
146316
- }
146317
- function assertDirectoryUsable(canonicalDirectory, rawDirectory) {
146318
- try {
146319
- const stat = statSync3(canonicalDirectory);
146320
- if (!stat.isDirectory()) {
146321
- throw new ProjectIdentityError("unknown", rawDirectory, `Project path is not a directory: ${canonicalDirectory}`);
146322
- }
146323
- } catch (error) {
146324
- if (error instanceof ProjectIdentityError) {
146325
- throw error;
146326
- }
146327
- const code = getErrorCode(error);
146328
- if (code === "EACCES" || code === "EPERM") {
146329
- throw new ProjectIdentityError("permission_denied", rawDirectory, `Permission denied while accessing project directory: ${canonicalDirectory}`, asError(error));
146330
- }
146331
- throw new ProjectIdentityError("unknown", rawDirectory, `Unable to access project directory: ${canonicalDirectory}`, asError(error));
146332
- }
146333
- }
146334
- function isGitTimeoutError(error) {
146335
- const code = getErrorCode(error);
146336
- const signal = getErrorSignal(error);
146337
- return code === "ETIMEDOUT" || signal === "SIGTERM" || signal === "SIGKILL" || getErrorKilled(error);
146338
- }
146339
- function classifyGitError(error, rawDirectory) {
146340
- if (isGitTimeoutError(error)) {
146341
- return new ProjectIdentityError("git_timeout", rawDirectory, `git rev-list timed out after ${GIT_TIMEOUT_MS}ms`, asError(error));
146342
- }
146343
- const code = getErrorCode(error);
146344
- if (code === "ENOENT") {
146345
- return new ProjectIdentityError("git_missing", rawDirectory, "git binary is not available in PATH", asError(error));
146346
- }
146347
- if (code === "EACCES" || code === "EPERM") {
146348
- return new ProjectIdentityError("permission_denied", rawDirectory, "Permission denied while spawning git", asError(error));
146349
- }
146350
- const stderr = getErrorStderr(error).toLowerCase();
146351
- if (stderr.includes("not a git repository") || stderr.includes("does not have any commits yet") || stderr.includes("ambiguous argument 'head'") || stderr.includes("unknown revision or path")) {
146352
- return new ProjectIdentityError("not_git_repo", rawDirectory, "Directory has no git root commit; caller may use directory fallback", asError(error));
146353
- }
146354
- return new ProjectIdentityError("unknown", rawDirectory, "git rev-list failed while resolving project identity", asError(error));
146355
- }
146356
- function resolveProjectIdentityStrict(directory) {
146357
- const canonical = path3.resolve(directory);
146358
- const cached = identityCache.get(canonical);
146359
- if (cached !== undefined) {
146360
- return cached;
146361
- }
146362
- assertDirectoryUsable(canonical, directory);
146363
- let output;
146364
- try {
146365
- output = execFileSync3("git", ["rev-list", "--max-parents=0", "HEAD"], {
146366
- cwd: canonical,
146367
- encoding: "utf8",
146368
- env: { ...process.env, LC_ALL: "C", LANG: "C" },
146369
- stdio: ["ignore", "pipe", "pipe"],
146370
- timeout: GIT_TIMEOUT_MS
146371
- });
146372
- } catch (error) {
146373
- throw classifyGitError(error, directory);
146374
- }
146375
- const firstLine = output.split(`
146376
- `)[0]?.trim() ?? "";
146377
- const rootCommit = firstLine.slice(0, 64);
146378
- if (rootCommit.length < 7) {
146379
- throw new ProjectIdentityError("unknown", directory, "git rev-list returned no valid root commit hash");
146380
- }
146381
- const identity = `git:${rootCommit}`;
146382
- identityCache.set(canonical, identity);
146383
- return identity;
146384
- }
146385
- function shouldUseDirectoryFallback(error) {
146386
- return error.errorClass === "not_git_repo" || error.errorClass === "unknown" && error.message.startsWith("Unable to access project directory:");
146387
- }
146388
- function resolveProjectIdentity(directory) {
146389
- const canonical = path3.resolve(directory);
146390
- const cachedFallback = directoryFallbackCache.get(canonical);
146391
- if (cachedFallback !== undefined) {
146392
- if (!hasGitDir(canonical)) {
146393
- return cachedFallback;
146394
- }
146395
- directoryFallbackCache.delete(canonical);
146396
- }
146397
- try {
146398
- return resolveProjectIdentityStrict(directory);
146399
- } catch (error) {
146400
- if (error instanceof ProjectIdentityError && shouldUseDirectoryFallback(error)) {
146401
- const fallback = directoryFallback(canonical);
146402
- if (!hasGitDir(canonical)) {
146403
- directoryFallbackCache.set(canonical, fallback);
146404
- }
146405
- return fallback;
146406
- }
146407
- throw error;
146408
- }
146409
- }
146410
- function hasGitDir(canonical) {
146411
- try {
146412
- statSync3(path3.join(canonical, ".git"));
146413
- return true;
146414
- } catch {
146415
- return false;
146416
- }
146417
- }
146418
- var GIT_TIMEOUT_MS = 5000, identityCache, directoryFallbackCache, ProjectIdentityError;
146419
- var init_project_identity = __esm(() => {
146420
- identityCache = new Map;
146421
- directoryFallbackCache = new Map;
146422
- ProjectIdentityError = class ProjectIdentityError extends Error {
146423
- errorClass;
146424
- rawDirectory;
146425
- constructor(errorClass, rawDirectory, message, cause) {
146426
- super(message);
146427
- this.name = "ProjectIdentityError";
146428
- this.errorClass = errorClass;
146429
- this.rawDirectory = rawDirectory;
146430
- if (cause) {
146431
- this.cause = cause;
146432
- }
146433
- }
146434
- };
146435
- });
146436
-
146437
146940
  // ../plugin/src/features/magic-context/project-identity.ts
146438
146941
  var init_project_identity2 = __esm(() => {
146439
146942
  init_project_identity();
@@ -147506,6 +148009,41 @@ var init_migrations = __esm(async () => {
147506
148009
  `);
147507
148010
  }
147508
148011
  }
148012
+ },
148013
+ {
148014
+ version: 37,
148015
+ description: "emergency drain catch-up latch + historian drain failure backoff",
148016
+ up: (db) => {
148017
+ const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta'").get();
148018
+ if (!hasSessionMeta)
148019
+ return;
148020
+ ensureColumn(db, "session_meta", "emergency_drain_active", "INTEGER NOT NULL DEFAULT 0");
148021
+ ensureColumn(db, "session_meta", "historian_drain_failure_at", "INTEGER NOT NULL DEFAULT 0");
148022
+ }
148023
+ },
148024
+ {
148025
+ version: 38,
148026
+ description: "durable transform decisions for cache-event cause attribution",
148027
+ up: (db) => {
148028
+ db.exec(`
148029
+ CREATE TABLE IF NOT EXISTS transform_decisions (
148030
+ session_id TEXT NOT NULL,
148031
+ harness TEXT NOT NULL DEFAULT 'opencode',
148032
+ message_id TEXT NOT NULL,
148033
+ ts_ms INTEGER NOT NULL,
148034
+ decision TEXT NOT NULL,
148035
+ materialized INTEGER NOT NULL DEFAULT 0,
148036
+ materialize_reason TEXT,
148037
+ emergency INTEGER NOT NULL DEFAULT 0,
148038
+ dropped_tokens INTEGER NOT NULL DEFAULT 0,
148039
+ dropped_count INTEGER NOT NULL DEFAULT 0,
148040
+ input_tokens INTEGER NOT NULL DEFAULT 0,
148041
+ PRIMARY KEY (session_id, harness, message_id)
148042
+ );
148043
+ CREATE INDEX IF NOT EXISTS idx_transform_decisions_session_harness
148044
+ ON transform_decisions(session_id, harness);
148045
+ `);
148046
+ }
147509
148047
  }
147510
148048
  ];
147511
148049
  LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
@@ -147537,7 +148075,7 @@ var init_storage_memory_mutation_log = __esm(() => {
147537
148075
  });
147538
148076
 
147539
148077
  // ../plugin/src/features/magic-context/storage-meta-persisted.ts
147540
- var AUTO_SEARCH_NO_HINT_REASONS, DRAIN_WINDOW_MS;
148078
+ var AUTO_SEARCH_NO_HINT_REASONS, DRAIN_WINDOW_MS, EMERGENCY_DRAIN_MAX_LATCH_MS;
147541
148079
  var init_storage_meta_persisted = __esm(() => {
147542
148080
  init_logger();
147543
148081
  init_storage_meta_shared();
@@ -147550,6 +148088,7 @@ var init_storage_meta_persisted = __esm(() => {
147550
148088
  "too-short"
147551
148089
  ]);
147552
148090
  DRAIN_WINDOW_MS = 10 * 60 * 1000;
148091
+ EMERGENCY_DRAIN_MAX_LATCH_MS = 30 * 60 * 1000;
147553
148092
  });
147554
148093
 
147555
148094
  // ../plugin/src/features/magic-context/resolve-subagent-fallback.ts
@@ -147593,10 +148132,11 @@ var init_storage_ops = __esm(() => {
147593
148132
  clearPendingOpsStatements = new WeakMap;
147594
148133
  removePendingOpStatements = new WeakMap;
147595
148134
  });
148135
+
147596
148136
  // ../plugin/src/features/magic-context/storage-source.ts
147597
148137
  var init_storage_source = () => {};
147598
148138
  // ../plugin/src/features/magic-context/storage-tags.ts
147599
- var insertTagStatements, updateTagStatusStatements, updateTagDropModeStatements, updateTagMessageIdStatements, getTagNumbersByMessageIdStatements, deleteTagsByMessageIdStatements, getMaxTagNumberBySessionStatements, getTagNumberByMessageIdStatements, updateTagByteSizeStatements, updateTagInputByteSizeStatements, updateTagTokenCountStatements, updateTagInputTokenCountStatements, getOwnerScopedToolTagNumbersStatements, getActiveTagsBySessionStatements, getMaxDroppedTagNumberStatements, getToolTagNumberByOwnerStatements, getNullOwnerToolTagStatements, adoptNullOwnerToolTagStatements, deleteToolTagsByOwnerStatements;
148139
+ var insertTagStatements, updateTagStatusStatements, updateTagDropModeStatements, updateTagMessageIdStatements, getTagNumbersByMessageIdStatements, deleteTagsByMessageIdStatements, getMaxTagNumberBySessionStatements, getTagNumberByMessageIdStatements, updateTagByteSizeStatements, updateTagInputByteSizeStatements, updateTagTokenCountStatements, updateTagInputTokenCountStatements, getOwnerScopedToolTagNumbersStatements, getMinMessageTagNumberForRawIdStatements, getActiveTagsBySessionStatements, getMaxDroppedTagNumberStatements, getToolTagNumberByOwnerStatements, getNullOwnerToolTagStatements, adoptNullOwnerToolTagStatements, deleteToolTagsByOwnerStatements;
147600
148140
  var init_storage_tags = __esm(() => {
147601
148141
  insertTagStatements = new WeakMap;
147602
148142
  updateTagStatusStatements = new WeakMap;
@@ -147611,6 +148151,7 @@ var init_storage_tags = __esm(() => {
147611
148151
  updateTagTokenCountStatements = new WeakMap;
147612
148152
  updateTagInputTokenCountStatements = new WeakMap;
147613
148153
  getOwnerScopedToolTagNumbersStatements = new WeakMap;
148154
+ getMinMessageTagNumberForRawIdStatements = new WeakMap;
147614
148155
  getActiveTagsBySessionStatements = new WeakMap;
147615
148156
  getMaxDroppedTagNumberStatements = new WeakMap;
147616
148157
  getToolTagNumberByOwnerStatements = new WeakMap;
@@ -147656,8 +148197,8 @@ var init_storage = __esm(async () => {
147656
148197
 
147657
148198
  // ../plugin/src/features/magic-context/v22-deferred-backfill.ts
147658
148199
  import { createHash as createHash2 } from "node:crypto";
147659
- import { realpathSync as realpathSync2 } from "node:fs";
147660
- import path4 from "node:path";
148200
+ import { realpathSync as realpathSync3 } from "node:fs";
148201
+ import path5 from "node:path";
147661
148202
  function readMeta(db, key) {
147662
148203
  const row = db.prepare("SELECT value FROM schema_migrations_meta WHERE key = ?").get(key);
147663
148204
  return row?.value ?? null;
@@ -147697,9 +148238,9 @@ function resolveBackfillIdentity(rawProjectPath) {
147697
148238
  function computeLegacyRustDirIdentity(rawProjectPath) {
147698
148239
  let canonical;
147699
148240
  try {
147700
- canonical = realpathSync2(rawProjectPath);
148241
+ canonical = realpathSync3(rawProjectPath);
147701
148242
  } catch {
147702
- canonical = path4.isAbsolute(rawProjectPath) ? rawProjectPath : path4.join(process.cwd(), rawProjectPath);
148243
+ canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
147703
148244
  }
147704
148245
  return `dir:${createHash2("sha256").update(canonical, "utf8").digest("hex")}`;
147705
148246
  }
@@ -147740,24 +148281,6 @@ function getV22BackfillStatus(db) {
147740
148281
  maxLegacyMemoryId: maxLegacyRow.m
147741
148282
  };
147742
148283
  }
147743
- function rekeyMemoryRowWithCollisionMerge(db, rowId, fromProjectPath, toIdentity) {
147744
- const row = db.prepare("SELECT category, normalized_hash, seen_count FROM memories WHERE id = ?").get(rowId);
147745
- if (!row)
147746
- return false;
147747
- const collision = db.prepare(`SELECT id, seen_count FROM memories
147748
- WHERE project_path = ? AND category = ? AND normalized_hash = ?
147749
- LIMIT 1`).get(toIdentity, row.category, row.normalized_hash);
147750
- if (collision && collision.id !== rowId) {
147751
- const mergedSeen = Math.max(collision.seen_count ?? 1, row.seen_count ?? 1);
147752
- if (mergedSeen !== (collision.seen_count ?? 1)) {
147753
- db.prepare("UPDATE memories SET seen_count = ? WHERE id = ?").run(mergedSeen, collision.id);
147754
- }
147755
- db.prepare("DELETE FROM memories WHERE id = ?").run(rowId);
147756
- return true;
147757
- }
147758
- const result = db.prepare("UPDATE memories SET project_path = ? WHERE id = ? AND project_path = ?").run(toIdentity, rowId, fromProjectPath);
147759
- return (result.changes ?? 0) > 0;
147760
- }
147761
148284
  async function doctorRetryV22Backfill(db) {
147762
148285
  const failures = db.prepare(`SELECT row_id, raw_project_path
147763
148286
  FROM v22_backfill_failures
@@ -147837,6 +148360,7 @@ var BACKFILL_META_KEY = "v22_legacy_memory_backfill", BACKFILL_CURSOR_META_KEY =
147837
148360
  var init_v22_deferred_backfill = __esm(() => {
147838
148361
  init_logger();
147839
148362
  init_project_identity();
148363
+ init_relocate_memory();
147840
148364
  });
147841
148365
 
147842
148366
  // src/lib/v22-backfill-commands.ts
@@ -148365,10 +148889,10 @@ function mergeDefs(...defs) {
148365
148889
  function cloneDef(schema) {
148366
148890
  return mergeDefs(schema._zod.def);
148367
148891
  }
148368
- function getElementAtPath(obj, path5) {
148369
- if (!path5)
148892
+ function getElementAtPath(obj, path6) {
148893
+ if (!path6)
148370
148894
  return obj;
148371
- return path5.reduce((acc, key) => acc?.[key], obj);
148895
+ return path6.reduce((acc, key) => acc?.[key], obj);
148372
148896
  }
148373
148897
  function promiseAllObject(promisesObj) {
148374
148898
  const keys = Object.keys(promisesObj);
@@ -148696,11 +149220,11 @@ function explicitlyAborted(x2, startIndex = 0) {
148696
149220
  }
148697
149221
  return false;
148698
149222
  }
148699
- function prefixIssues(path5, issues) {
149223
+ function prefixIssues(path6, issues) {
148700
149224
  return issues.map((iss) => {
148701
149225
  var _a2;
148702
149226
  (_a2 = iss).path ?? (_a2.path = []);
148703
- iss.path.unshift(path5);
149227
+ iss.path.unshift(path6);
148704
149228
  return iss;
148705
149229
  });
148706
149230
  }
@@ -148913,16 +149437,16 @@ function flattenError(error, mapper = (issue2) => issue2.message) {
148913
149437
  }
148914
149438
  function formatError(error, mapper = (issue2) => issue2.message) {
148915
149439
  const fieldErrors = { _errors: [] };
148916
- const processError = (error2, path5 = []) => {
149440
+ const processError = (error2, path6 = []) => {
148917
149441
  for (const issue2 of error2.issues) {
148918
149442
  if (issue2.code === "invalid_union" && issue2.errors.length) {
148919
- issue2.errors.map((issues) => processError({ issues }, [...path5, ...issue2.path]));
149443
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
148920
149444
  } else if (issue2.code === "invalid_key") {
148921
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
149445
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
148922
149446
  } else if (issue2.code === "invalid_element") {
148923
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
149447
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
148924
149448
  } else {
148925
- const fullpath = [...path5, ...issue2.path];
149449
+ const fullpath = [...path6, ...issue2.path];
148926
149450
  if (fullpath.length === 0) {
148927
149451
  fieldErrors._errors.push(mapper(issue2));
148928
149452
  } else {
@@ -148949,17 +149473,17 @@ function formatError(error, mapper = (issue2) => issue2.message) {
148949
149473
  }
148950
149474
  function treeifyError(error, mapper = (issue2) => issue2.message) {
148951
149475
  const result = { errors: [] };
148952
- const processError = (error2, path5 = []) => {
149476
+ const processError = (error2, path6 = []) => {
148953
149477
  var _a2, _b;
148954
149478
  for (const issue2 of error2.issues) {
148955
149479
  if (issue2.code === "invalid_union" && issue2.errors.length) {
148956
- issue2.errors.map((issues) => processError({ issues }, [...path5, ...issue2.path]));
149480
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
148957
149481
  } else if (issue2.code === "invalid_key") {
148958
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
149482
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
148959
149483
  } else if (issue2.code === "invalid_element") {
148960
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
149484
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
148961
149485
  } else {
148962
- const fullpath = [...path5, ...issue2.path];
149486
+ const fullpath = [...path6, ...issue2.path];
148963
149487
  if (fullpath.length === 0) {
148964
149488
  result.errors.push(mapper(issue2));
148965
149489
  continue;
@@ -148991,8 +149515,8 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
148991
149515
  }
148992
149516
  function toDotPath(_path) {
148993
149517
  const segs = [];
148994
- const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
148995
- for (const seg of path5) {
149518
+ const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
149519
+ for (const seg of path6) {
148996
149520
  if (typeof seg === "number")
148997
149521
  segs.push(`[${seg}]`);
148998
149522
  else if (typeof seg === "symbol")
@@ -161995,13 +162519,13 @@ function resolveRef(ref, ctx) {
161995
162519
  if (!ref.startsWith("#")) {
161996
162520
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
161997
162521
  }
161998
- const path5 = ref.slice(1).split("/").filter(Boolean);
161999
- if (path5.length === 0) {
162522
+ const path6 = ref.slice(1).split("/").filter(Boolean);
162523
+ if (path6.length === 0) {
162000
162524
  return ctx.rootSchema;
162001
162525
  }
162002
162526
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
162003
- if (path5[0] === defsKey) {
162004
- const key = path5[1];
162527
+ if (path6[0] === defsKey) {
162528
+ const key = path6[1];
162005
162529
  if (!key || !ctx.defs[key]) {
162006
162530
  throw new Error(`Reference not found: ${ref}`);
162007
162531
  }
@@ -162825,14 +163349,16 @@ var init_magic_context = __esm(() => {
162825
163349
  }).optional();
162826
163350
  HistorianConfigSchema = AgentOverrideConfigSchema.extend({
162827
163351
  two_pass: exports_external.boolean().default(false).describe("Run a second editor pass over historian output to clean low-signal U: lines and cross-compartment duplicates. Adds ~1 extra API call and ~1.3x cost per historian run. Useful for models without extended thinking support. (default: false)"),
162828
- thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh")
163352
+ thinking_level: PiThinkingLevelSchema.describe("Pi only: explicit thinking level passed as --thinking <level> to Pi historian subagent invocations. Required when using reasoning models (e.g. github-copilot/gpt-5.4) because Pi's default thinking-level resolution can pick a value the provider rejects. OpenCode users set variant instead. Valid: off | minimal | low | medium | high | xhigh"),
163353
+ disallowed_tools: exports_external.array(exports_external.enum(["*", "read", "aft_outline", "aft_zoom", "aft_search"])).default([]).describe(`OpenCode only. Tools to REMOVE from the historian's default allow-list [read, aft_outline, aft_zoom, aft_search]. Applies to both historian and historian-editor agents. Use ["*"] to strip all tool definitions from the model request — this prevents weak instruction-following models (e.g. mistral-small-latest) from entering tool-calling loops. Individual tool names remove just that tool. Note: a user-supplied historian.permission override can re-allow a tool that disallowed_tools removed — disallowed_tools sets the baseline, permission overrides take precedence. (default: [])`)
162829
163354
  }).optional();
162830
163355
  BaseEmbeddingConfigSchema = exports_external.object({
162831
163356
  provider: exports_external.enum(["local", "openai-compatible", "off"]).default("local").describe("Embedding provider. 'local' uses Xenova/all-MiniLM-L6-v2, 'openai-compatible' requires endpoint and model, 'off' disables embeddings."),
162832
163357
  model: exports_external.string().optional().describe("Embedding model name. Required for openai-compatible, ignored for local."),
162833
163358
  endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
162834
163359
  api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
162835
- input_type: exports_external.string().optional().describe("Optional input_type sent in the embedding request body. Required by some openai-compatible providers (e.g. NVIDIA NIM expects 'query' or 'passage'). Omitted from the request when unset."),
163360
+ input_type: exports_external.string().optional().describe("Default input_type for stored/indexed (passage) embeddings in the request body. Required by some openai-compatible providers (e.g. NVIDIA NIM). Omitted from the request when unset."),
163361
+ query_input_type: exports_external.string().optional().describe("Optional input_type for query (search) embeddings on asymmetric models (e.g. NVIDIA NIM 'query'). When unset, query embeddings use embedding.input_type. Passage/stored content always uses embedding.input_type."),
162836
163362
  truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset."),
162837
163363
  max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
162838
163364
  }).superRefine((data, ctx) => {
@@ -162862,6 +163388,7 @@ var init_magic_context = __esm(() => {
162862
163388
  if (data.provider === "openai-compatible") {
162863
163389
  const apiKey = data.api_key?.trim();
162864
163390
  const inputType = data.input_type?.trim();
163391
+ const queryInputType = data.query_input_type?.trim();
162865
163392
  const truncate = data.truncate?.trim();
162866
163393
  return {
162867
163394
  provider: "openai-compatible",
@@ -162869,6 +163396,7 @@ var init_magic_context = __esm(() => {
162869
163396
  endpoint: data.endpoint?.trim() ?? "",
162870
163397
  ...apiKey ? { api_key: apiKey } : {},
162871
163398
  ...inputType ? { input_type: inputType } : {},
163399
+ ...queryInputType ? { query_input_type: queryInputType } : {},
162872
163400
  ...truncate ? { truncate } : {},
162873
163401
  ...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
162874
163402
  };
@@ -162951,11 +163479,11 @@ var init_magic_context = __esm(() => {
162951
163479
  });
162952
163480
 
162953
163481
  // ../plugin/src/config/variable.ts
162954
- import { existsSync as existsSync14, readFileSync as readFileSync8 } from "node:fs";
162955
- import { homedir as homedir7 } from "node:os";
163482
+ import { existsSync as existsSync15, readFileSync as readFileSync8 } from "node:fs";
163483
+ import { homedir as homedir8 } from "node:os";
162956
163484
  import { dirname as dirname7, isAbsolute, resolve as resolve2 } from "node:path";
162957
163485
  function sensitiveFilePathReason(resolvedPath) {
162958
- const home = homedir7();
163486
+ const home = homedir8();
162959
163487
  const sensitiveDirs = [
162960
163488
  { dir: resolve2(home, ".ssh"), label: "SSH keys" },
162961
163489
  { dir: resolve2(home, ".aws"), label: "AWS credentials" },
@@ -163018,7 +163546,7 @@ function substituteConfigVariables(input) {
163018
163546
  }
163019
163547
  let filePath = rawPath.trim();
163020
163548
  if (filePath.startsWith("~/")) {
163021
- filePath = resolve2(homedir7(), filePath.slice(2));
163549
+ filePath = resolve2(homedir8(), filePath.slice(2));
163022
163550
  } else if (!isAbsolute(filePath)) {
163023
163551
  filePath = resolve2(configDir, filePath);
163024
163552
  }
@@ -163026,7 +163554,7 @@ function substituteConfigVariables(input) {
163026
163554
  if (sensitiveReason) {
163027
163555
  warnings.push(`${token} resolves to a sensitive path (${sensitiveReason}: ${filePath}); ` + "inlining its contents into config — make sure this is intentional.");
163028
163556
  }
163029
- if (!existsSync14(filePath)) {
163557
+ if (!existsSync15(filePath)) {
163030
163558
  warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
163031
163559
  continue;
163032
163560
  }
@@ -163051,19 +163579,19 @@ var init_variable = __esm(() => {
163051
163579
  });
163052
163580
 
163053
163581
  // ../plugin/src/config/index.ts
163054
- import { existsSync as existsSync15, readFileSync as readFileSync9 } from "node:fs";
163055
- import { homedir as homedir8 } from "node:os";
163056
- import { join as join12 } from "node:path";
163582
+ import { existsSync as existsSync16, readFileSync as readFileSync9 } from "node:fs";
163583
+ import { homedir as homedir9 } from "node:os";
163584
+ import { join as join13 } from "node:path";
163057
163585
  function getUserConfigBasePath() {
163058
- const configRoot = process.env.XDG_CONFIG_HOME ?? join12(homedir8(), ".config");
163059
- return join12(configRoot, "opencode", CONFIG_FILE_BASENAME);
163586
+ const configRoot = process.env.XDG_CONFIG_HOME ?? join13(homedir9(), ".config");
163587
+ return join13(configRoot, "opencode", CONFIG_FILE_BASENAME);
163060
163588
  }
163061
163589
  function getProjectConfigBasePath(directory) {
163062
- return join12(directory, ".opencode", CONFIG_FILE_BASENAME);
163590
+ return join13(directory, ".opencode", CONFIG_FILE_BASENAME);
163063
163591
  }
163064
163592
  function loadConfigFile(configPath, isProjectConfig = false) {
163065
163593
  try {
163066
- if (!existsSync15(configPath)) {
163594
+ if (!existsSync16(configPath)) {
163067
163595
  return null;
163068
163596
  }
163069
163597
  const rawText = readFileSync9(configPath, "utf-8");
@@ -163207,7 +163735,7 @@ function parsePluginConfig(rawConfig, recoveredTopLevelKeys = []) {
163207
163735
  }
163208
163736
  function loadPluginConfig(directory) {
163209
163737
  const userDetected = detectConfigFile(getUserConfigBasePath());
163210
- const rootDetected = detectConfigFile(join12(directory, CONFIG_FILE_BASENAME));
163738
+ const rootDetected = detectConfigFile(join13(directory, CONFIG_FILE_BASENAME));
163211
163739
  const dotOpenCodeDetected = detectConfigFile(getProjectConfigBasePath(directory));
163212
163740
  const projectDetected = rootDetected.format !== "none" ? rootDetected : dotOpenCodeDetected;
163213
163741
  const userLoaded = userDetected.format === "none" ? null : loadConfigFile(userDetected.path);
@@ -163255,14 +163783,14 @@ var init_config = __esm(() => {
163255
163783
  });
163256
163784
 
163257
163785
  // ../plugin/src/features/magic-context/key-files/aft-availability.ts
163258
- import { existsSync as existsSync16, readFileSync as readFileSync10 } from "node:fs";
163259
- import { homedir as homedir9 } from "node:os";
163260
- import { isAbsolute as isAbsolute2, join as join13, resolve as resolve3 } from "node:path";
163786
+ import { existsSync as existsSync17, readFileSync as readFileSync10 } from "node:fs";
163787
+ import { homedir as homedir10 } from "node:os";
163788
+ import { isAbsolute as isAbsolute2, join as join14, resolve as resolve3 } from "node:path";
163261
163789
  import { fileURLToPath } from "node:url";
163262
- function parseConfig(path5) {
163263
- if (!existsSync16(path5))
163790
+ function parseConfig(path6) {
163791
+ if (!existsSync17(path6))
163264
163792
  return null;
163265
- return import_comment_json6.parse(readFileSync10(path5, "utf-8"));
163793
+ return import_comment_json6.parse(readFileSync10(path6, "utf-8"));
163266
163794
  }
163267
163795
  function stringMentionsAft(value) {
163268
163796
  return AFT_NAME_NEEDLES.some((needle) => value.includes(needle));
@@ -163276,14 +163804,14 @@ function resolveLocalEntryPackageName(value, configDir) {
163276
163804
  return null;
163277
163805
  }
163278
163806
  } else if (value.startsWith("~/")) {
163279
- dir = join13(homedir9(), value.slice(2));
163807
+ dir = join14(homedir10(), value.slice(2));
163280
163808
  } else if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../")) {
163281
163809
  dir = isAbsolute2(value) ? value : resolve3(configDir, value);
163282
163810
  } else {
163283
163811
  return null;
163284
163812
  }
163285
163813
  try {
163286
- const pkg = JSON.parse(readFileSync10(join13(dir, "package.json"), "utf-8"));
163814
+ const pkg = JSON.parse(readFileSync10(join14(dir, "package.json"), "utf-8"));
163287
163815
  return typeof pkg.name === "string" ? pkg.name : null;
163288
163816
  } catch {
163289
163817
  return null;
@@ -163312,18 +163840,18 @@ function hasAftAtKeys(value, keys, configDir) {
163312
163840
  return false;
163313
163841
  }
163314
163842
  function getAftAvailability() {
163315
- const home = process.env.HOME || homedir9();
163843
+ const home = process.env.HOME || homedir10();
163316
163844
  const opencodePaths = [
163317
- join13(home, ".config", "opencode", "opencode.jsonc"),
163318
- join13(home, ".config", "opencode", "opencode.json")
163845
+ join14(home, ".config", "opencode", "opencode.jsonc"),
163846
+ join14(home, ".config", "opencode", "opencode.json")
163319
163847
  ];
163320
- const piPaths = [join13(home, ".pi", "agent", "settings.json")];
163848
+ const piPaths = [join14(home, ".pi", "agent", "settings.json")];
163321
163849
  const checkedPaths = [...opencodePaths, ...piPaths];
163322
163850
  let opencode = false;
163323
- for (const path5 of opencodePaths) {
163851
+ for (const path6 of opencodePaths) {
163324
163852
  try {
163325
- const config2 = parseConfig(path5);
163326
- const configDir = join13(path5, "..");
163853
+ const config2 = parseConfig(path6);
163854
+ const configDir = join14(path6, "..");
163327
163855
  if (hasAftAtKeys(config2, ["plugin", "plugins", "mcp", "mcp_servers"], configDir)) {
163328
163856
  opencode = true;
163329
163857
  break;
@@ -163331,10 +163859,10 @@ function getAftAvailability() {
163331
163859
  } catch {}
163332
163860
  }
163333
163861
  let pi = false;
163334
- for (const path5 of piPaths) {
163862
+ for (const path6 of piPaths) {
163335
163863
  try {
163336
- const config2 = parseConfig(path5);
163337
- const configDir = join13(path5, "..");
163864
+ const config2 = parseConfig(path6);
163865
+ const configDir = join14(path6, "..");
163338
163866
  if (hasAftAtKeys(config2, ["packages", "extensions"], configDir)) {
163339
163867
  pi = true;
163340
163868
  break;
@@ -163472,8 +164000,8 @@ function truncate(text2) {
163472
164000
  var DEFAULT_TIMEOUT_MS = 1e4, MAX_PREVIEW_CHARS = 240;
163473
164001
 
163474
164002
  // ../plugin/src/shared/tui-config.ts
163475
- import { existsSync as existsSync17, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "node:fs";
163476
- import { dirname as dirname8, join as join14 } from "node:path";
164003
+ import { existsSync as existsSync18, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "node:fs";
164004
+ import { dirname as dirname8, join as join15 } from "node:path";
163477
164005
  function isMagicContextEntry(entry) {
163478
164006
  if (!entry)
163479
164007
  return false;
@@ -163487,11 +164015,11 @@ function isMagicContextEntry(entry) {
163487
164015
  }
163488
164016
  function resolveTuiConfigPath() {
163489
164017
  const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
163490
- const jsoncPath = join14(configDir, "tui.jsonc");
163491
- const jsonPath = join14(configDir, "tui.json");
163492
- if (existsSync17(jsoncPath))
164018
+ const jsoncPath = join15(configDir, "tui.jsonc");
164019
+ const jsonPath = join15(configDir, "tui.json");
164020
+ if (existsSync18(jsoncPath))
163493
164021
  return jsoncPath;
163494
- if (existsSync17(jsonPath))
164022
+ if (existsSync18(jsonPath))
163495
164023
  return jsonPath;
163496
164024
  return jsonPath;
163497
164025
  }
@@ -163499,7 +164027,7 @@ function ensureTuiPluginEntry() {
163499
164027
  try {
163500
164028
  const configPath = resolveTuiConfigPath();
163501
164029
  let config2 = {};
163502
- if (existsSync17(configPath)) {
164030
+ if (existsSync18(configPath)) {
163503
164031
  const raw = readFileSync11(configPath, "utf-8");
163504
164032
  config2 = import_comment_json7.parse(raw) ?? {};
163505
164033
  }
@@ -163670,7 +164198,7 @@ var init_compartment_parser = __esm(() => {
163670
164198
  });
163671
164199
 
163672
164200
  // src/lib/redaction.ts
163673
- import { homedir as homedir10, userInfo } from "node:os";
164201
+ import { homedir as homedir11, userInfo } from "node:os";
163674
164202
  function escapeRegex3(value) {
163675
164203
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
163676
164204
  }
@@ -163714,7 +164242,7 @@ function isSecretKey(key) {
163714
164242
  return false;
163715
164243
  }
163716
164244
  function sanitizePathString(value) {
163717
- const home = homedir10();
164245
+ const home = homedir11();
163718
164246
  const username = userInfo().username;
163719
164247
  let sanitized = value;
163720
164248
  if (home) {
@@ -163848,10 +164376,10 @@ var init_redaction = __esm(() => {
163848
164376
  });
163849
164377
 
163850
164378
  // src/lib/diagnostics-opencode.ts
163851
- import { existsSync as existsSync18, readdirSync as readdirSync2, readFileSync as readFileSync12, statSync as statSync4 } from "node:fs";
164379
+ import { existsSync as existsSync19, readdirSync as readdirSync2, readFileSync as readFileSync12, statSync as statSync4 } from "node:fs";
163852
164380
  import { createRequire as createRequire2 } from "node:module";
163853
- import { homedir as homedir11 } from "node:os";
163854
- import { join as join15 } from "node:path";
164381
+ import { homedir as homedir12 } from "node:os";
164382
+ import { join as join16 } from "node:path";
163855
164383
  function getSelfVersion() {
163856
164384
  const require2 = createRequire2(import.meta.url);
163857
164385
  for (const relPath of ["../../package.json", "../package.json"]) {
@@ -163865,26 +164393,26 @@ function getSelfVersion() {
163865
164393
  return "unknown";
163866
164394
  }
163867
164395
  function getPluginCacheInfo() {
163868
- const path5 = join15(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY_WITH_VERSION);
164396
+ const path6 = join16(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY_WITH_VERSION);
163869
164397
  let cached2;
163870
164398
  try {
163871
- const installedPkgPath = join15(path5, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
163872
- if (existsSync18(installedPkgPath)) {
164399
+ const installedPkgPath = join16(path6, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
164400
+ if (existsSync19(installedPkgPath)) {
163873
164401
  const pkg = JSON.parse(readFileSync12(installedPkgPath, "utf-8"));
163874
164402
  cached2 = typeof pkg.version === "string" ? pkg.version : undefined;
163875
164403
  }
163876
164404
  } catch {
163877
164405
  cached2 = undefined;
163878
164406
  }
163879
- return { path: path5, cached: cached2, latest: getSelfVersion() };
164407
+ return { path: path6, cached: cached2, latest: getSelfVersion() };
163880
164408
  }
163881
164409
  function getStorageDir() {
163882
- const dataHome = process.env.XDG_DATA_HOME || join15(homedir11(), ".local", "share");
163883
- return join15(dataHome, "cortexkit", "magic-context");
164410
+ const dataHome = process.env.XDG_DATA_HOME || join16(homedir12(), ".local", "share");
164411
+ return join16(dataHome, "cortexkit", "magic-context");
163884
164412
  }
163885
- function fileSize(path5) {
164413
+ function fileSize(path6) {
163886
164414
  try {
163887
- return existsSync18(path5) ? statSync4(path5).size : 0;
164415
+ return existsSync19(path6) ? statSync4(path6).size : 0;
163888
164416
  } catch {
163889
164417
  return 0;
163890
164418
  }
@@ -163895,11 +164423,11 @@ function sanitizeString(value) {
163895
164423
  function sanitizeValue(value) {
163896
164424
  return sanitizeConfigValue(value);
163897
164425
  }
163898
- function readConfig2(path5) {
163899
- if (!existsSync18(path5))
164426
+ function readConfig2(path6) {
164427
+ if (!existsSync19(path6))
163900
164428
  return { value: null };
163901
164429
  try {
163902
- const raw = readFileSync12(path5, "utf-8");
164430
+ const raw = readFileSync12(path6, "utf-8");
163903
164431
  const value = import_comment_json8.parse(raw);
163904
164432
  return { value };
163905
164433
  } catch (error51) {
@@ -163920,9 +164448,9 @@ function configHasPluginEntry(config2) {
163920
164448
  return false;
163921
164449
  });
163922
164450
  }
163923
- function parseHistorianDumpMeta(path5) {
164451
+ function parseHistorianDumpMeta(path6) {
163924
164452
  try {
163925
- const xml = readFileSync12(path5, "utf-8");
164453
+ const xml = readFileSync12(path6, "utf-8");
163926
164454
  const parsed = parseCompartmentOutput(xml);
163927
164455
  const factCountByCategory = {};
163928
164456
  for (const fact of parsed.facts) {
@@ -163955,11 +164483,11 @@ function parseHistorianDumpMeta(path5) {
163955
164483
  }
163956
164484
  }
163957
164485
  function listDumpsInDir(dir, limit) {
163958
- if (!existsSync18(dir))
164486
+ if (!existsSync19(dir))
163959
164487
  return { count: 0, recent: [] };
163960
164488
  try {
163961
164489
  const entries = readdirSync2(dir).filter((name2) => name2.endsWith(".xml")).map((name2) => {
163962
- const stat = statSync4(join15(dir, name2));
164490
+ const stat = statSync4(join16(dir, name2));
163963
164491
  return {
163964
164492
  name: name2,
163965
164493
  mtime: stat.mtimeMs,
@@ -163968,7 +164496,7 @@ function listDumpsInDir(dir, limit) {
163968
164496
  }).sort((a, b2) => b2.mtime - a.mtime);
163969
164497
  const now = Date.now();
163970
164498
  const recent = entries.slice(0, limit).map((entry) => {
163971
- const meta3 = parseHistorianDumpMeta(join15(dir, entry.name));
164499
+ const meta3 = parseHistorianDumpMeta(join16(dir, entry.name));
163972
164500
  const summary = {
163973
164501
  name: entry.name,
163974
164502
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -164023,8 +164551,8 @@ function collectHistorianDumps(recentSessions) {
164023
164551
  };
164024
164552
  }
164025
164553
  async function collectRecentSessions() {
164026
- const opencodeDbPath = join15(homedir11(), ".local", "share", "opencode", "opencode.db");
164027
- if (!existsSync18(opencodeDbPath))
164554
+ const opencodeDbPath = join16(homedir12(), ".local", "share", "opencode", "opencode.db");
164555
+ if (!existsSync19(opencodeDbPath))
164028
164556
  return [];
164029
164557
  if (typeof globalThis.Bun === "undefined") {
164030
164558
  return [];
@@ -164058,8 +164586,8 @@ async function collectRecentSessions() {
164058
164586
  }
164059
164587
  }
164060
164588
  async function collectHistorianFailures(storageDirPath) {
164061
- const contextDbPath = join15(storageDirPath, "context.db");
164062
- if (!existsSync18(contextDbPath))
164589
+ const contextDbPath = join16(storageDirPath, "context.db");
164590
+ if (!existsSync19(contextDbPath))
164063
164591
  return [];
164064
164592
  if (typeof globalThis.Bun === "undefined") {
164065
164593
  return [];
@@ -164091,6 +164619,70 @@ async function collectHistorianFailures(storageDirPath) {
164091
164619
  } catch {}
164092
164620
  }
164093
164621
  }
164622
+ async function collectHistorianRuns(storageDirPath) {
164623
+ const contextDbPath = join16(storageDirPath, "context.db");
164624
+ if (!existsSync19(contextDbPath))
164625
+ return [];
164626
+ if (typeof globalThis.Bun === "undefined")
164627
+ return [];
164628
+ let DatabaseClass;
164629
+ try {
164630
+ const mod = await new Function("p", "return import(p)")("bun:sqlite");
164631
+ DatabaseClass = mod.Database;
164632
+ } catch {
164633
+ return [];
164634
+ }
164635
+ let db = null;
164636
+ try {
164637
+ db = new DatabaseClass(contextDbPath, { readonly: true });
164638
+ const aggRows = db.prepare(`SELECT session_id,
164639
+ COUNT(*) AS total,
164640
+ SUM(CASE WHEN status='success' THEN 1 ELSE 0 END) AS success,
164641
+ SUM(CASE WHEN status='failed' THEN 1 ELSE 0 END) AS failed,
164642
+ SUM(CASE WHEN status='noop' THEN 1 ELSE 0 END) AS noop,
164643
+ MAX(created_at) AS last_run_at
164644
+ FROM historian_runs
164645
+ GROUP BY session_id
164646
+ ORDER BY last_run_at DESC
164647
+ LIMIT 10`).all();
164648
+ if (aggRows.length === 0)
164649
+ return [];
164650
+ const reasonRows = db.prepare(`SELECT session_id, failure_reason, created_at
164651
+ FROM historian_runs
164652
+ WHERE status='failed' AND failure_reason IS NOT NULL
164653
+ ORDER BY created_at DESC
164654
+ LIMIT 200`).all();
164655
+ const latestReasonBySession = new Map;
164656
+ for (const row of reasonRows) {
164657
+ const sid = typeof row.session_id === "string" ? row.session_id : "";
164658
+ if (!sid || latestReasonBySession.has(sid))
164659
+ continue;
164660
+ if (typeof row.failure_reason === "string") {
164661
+ latestReasonBySession.set(sid, row.failure_reason);
164662
+ }
164663
+ }
164664
+ const asNum = (v2) => typeof v2 === "number" ? v2 : 0;
164665
+ return aggRows.map((row) => {
164666
+ const sessionId = typeof row.session_id === "string" ? row.session_id : "<unknown>";
164667
+ const rawReason = latestReasonBySession.get(sessionId) ?? "";
164668
+ return {
164669
+ sessionId,
164670
+ total: asNum(row.total),
164671
+ success: asNum(row.success),
164672
+ failed: asNum(row.failed),
164673
+ noop: asNum(row.noop),
164674
+ lastFailureReason: sanitizeDiagnosticText(rawReason.replace(/\s+/g, " ").trim().slice(0, 400)),
164675
+ lastRunAt: typeof row.last_run_at === "number" ? new Date(row.last_run_at).toISOString() : ""
164676
+ };
164677
+ });
164678
+ } catch {
164679
+ return [];
164680
+ } finally {
164681
+ try {
164682
+ db?.close();
164683
+ } catch {}
164684
+ }
164685
+ }
164094
164686
  async function collectDiagnostics() {
164095
164687
  const pluginVersion = getSelfVersion();
164096
164688
  const configPaths = detectConfigPaths();
@@ -164098,9 +164690,9 @@ async function collectDiagnostics() {
164098
164690
  const tuiConfig = readConfig2(configPaths.tuiConfig);
164099
164691
  const magicContextConfig = readConfig2(configPaths.magicContextConfig);
164100
164692
  const storageDirPath = getStorageDir();
164101
- const contextDbPath = join15(storageDirPath, "context.db");
164693
+ const contextDbPath = join16(storageDirPath, "context.db");
164102
164694
  const logPath = getMagicContextLogPath2("opencode");
164103
- const logFileSize = existsSync18(logPath) ? statSync4(logPath).size : 0;
164695
+ const logFileSize = existsSync19(logPath) ? statSync4(logPath).size : 0;
164104
164696
  const conflictResult = detectConflicts(process.cwd());
164105
164697
  const recentSessions = await collectRecentSessions();
164106
164698
  return {
@@ -164115,7 +164707,7 @@ async function collectDiagnostics() {
164115
164707
  opencodeConfigHasPlugin: configHasPluginEntry(opencodeConfig.value),
164116
164708
  tuiConfigHasPlugin: configHasPluginEntry(tuiConfig.value),
164117
164709
  magicContextConfig: {
164118
- exists: existsSync18(configPaths.magicContextConfig),
164710
+ exists: existsSync19(configPaths.magicContextConfig),
164119
164711
  ...magicContextConfig.error ? { parseError: magicContextConfig.error } : {},
164120
164712
  flags: sanitizeValue(magicContextConfig.value ?? {}) ?? {}
164121
164713
  },
@@ -164123,7 +164715,7 @@ async function collectDiagnostics() {
164123
164715
  pluginCache: getPluginCacheInfo(),
164124
164716
  storageDir: {
164125
164717
  path: storageDirPath,
164126
- exists: existsSync18(storageDirPath),
164718
+ exists: existsSync19(storageDirPath),
164127
164719
  contextDbSizeBytes: fileSize(contextDbPath)
164128
164720
  },
164129
164721
  conflicts: {
@@ -164132,12 +164724,13 @@ async function collectDiagnostics() {
164132
164724
  },
164133
164725
  logFile: {
164134
164726
  path: logPath,
164135
- exists: existsSync18(logPath),
164727
+ exists: existsSync19(logPath),
164136
164728
  sizeKb: Math.round(logFileSize / 1024)
164137
164729
  },
164138
164730
  recentSessions,
164139
164731
  historianDumps: collectHistorianDumps(recentSessions),
164140
- historianFailures: await collectHistorianFailures(storageDirPath)
164732
+ historianFailures: await collectHistorianFailures(storageDirPath),
164733
+ historianRuns: await collectHistorianRuns(storageDirPath)
164141
164734
  };
164142
164735
  }
164143
164736
  function formatBytes(bytes) {
@@ -164233,11 +164826,21 @@ function renderDiagnosticsMarkdown(report) {
164233
164826
  "```",
164234
164827
  "",
164235
164828
  "### Historian failures (session_meta)",
164829
+ "_Note: this counter RESETS to 0 on every successful run — see 'Historian runs' below for the durable history._",
164236
164830
  report.historianFailures.length === 0 ? "_No sessions with historian failures._" : [
164237
164831
  "```json",
164238
164832
  JSON.stringify(sanitizeConfigValue(report.historianFailures), null, 2),
164239
164833
  "```"
164240
164834
  ].join(`
164835
+ `),
164836
+ "",
164837
+ "### Historian runs (durable telemetry)",
164838
+ "Per-session success/failure/no-op counts from `historian_runs` (never reset).",
164839
+ report.historianRuns.length === 0 ? "_No historian runs recorded (or schema predates v24)._" : [
164840
+ "```json",
164841
+ JSON.stringify(sanitizeConfigValue(report.historianRuns), null, 2),
164842
+ "```"
164843
+ ].join(`
164241
164844
  `),
164242
164845
  "",
164243
164846
  "### Log file",
@@ -164260,6 +164863,99 @@ var init_diagnostics_opencode = __esm(() => {
164260
164863
  PLUGIN_ENTRY_WITH_VERSION = `${PLUGIN_NAME5}@latest`;
164261
164864
  });
164262
164865
 
164866
+ // src/lib/embedding-runtime.ts
164867
+ import { existsSync as existsSync20 } from "node:fs";
164868
+ import { createRequire as createRequire3 } from "node:module";
164869
+ import { dirname as dirname9, join as join17, sep } from "node:path";
164870
+ function expectedBinaryRelPath(platform, arch) {
164871
+ const supportedPlatform = platform === "linux" || platform === "darwin" || platform === "win32";
164872
+ const supportedArch = arch === "x64" || arch === "arm64";
164873
+ if (!supportedPlatform || !supportedArch)
164874
+ return null;
164875
+ return join17("bin", "napi-v6", platform, arch, "onnxruntime_binding.node");
164876
+ }
164877
+ function checkLocalEmbeddingRuntimeAt(installRoot, platform = process.platform, arch = process.arch) {
164878
+ const packageDir = join17(installRoot, "node_modules", "onnxruntime-node");
164879
+ if (!existsSync20(join17(packageDir, "package.json"))) {
164880
+ return { state: "package-missing", packageDir };
164881
+ }
164882
+ const rel = expectedBinaryRelPath(platform, arch);
164883
+ if (rel === null) {
164884
+ return { state: "ok", binaryPath: packageDir };
164885
+ }
164886
+ const binaryPath = join17(packageDir, rel);
164887
+ if (!existsSync20(binaryPath)) {
164888
+ return { state: "binary-missing", packageDir, expectedBinary: binaryPath };
164889
+ }
164890
+ return { state: "ok", binaryPath };
164891
+ }
164892
+ function checkLocalEmbeddingRuntime(installRoots, platform = process.platform, arch = process.arch) {
164893
+ const existing = installRoots.filter((root) => existsSync20(root));
164894
+ if (existing.length === 0) {
164895
+ return {
164896
+ state: "unknown",
164897
+ reason: "no installed plugin tree found to inspect"
164898
+ };
164899
+ }
164900
+ let firstFailure = null;
164901
+ for (const root of existing) {
164902
+ const status = checkLocalEmbeddingRuntimeAt(root, platform, arch);
164903
+ if (status.state === "ok")
164904
+ return status;
164905
+ if (firstFailure === null)
164906
+ firstFailure = status;
164907
+ }
164908
+ return firstFailure ?? { state: "unknown", reason: "no candidate roots" };
164909
+ }
164910
+ function packageDirFromResolved(resolvedPath, packageName) {
164911
+ const marker = `node_modules${sep}${packageName.split("/").join(sep)}`;
164912
+ const idx = resolvedPath.indexOf(marker);
164913
+ return idx >= 0 ? resolvedPath.slice(0, idx + marker.length) : dirname9(resolvedPath);
164914
+ }
164915
+ function checkLocalEmbeddingRuntimeByResolution(pluginDir, platform = process.platform, arch = process.arch) {
164916
+ if (!existsSync20(join17(pluginDir, "package.json"))) {
164917
+ return { state: "unknown", reason: "plugin package dir not found" };
164918
+ }
164919
+ let onnxDir = null;
164920
+ let resolveError;
164921
+ try {
164922
+ const reqPlugin = createRequire3(join17(pluginDir, "package.json"));
164923
+ try {
164924
+ onnxDir = packageDirFromResolved(reqPlugin.resolve("onnxruntime-node"), "onnxruntime-node");
164925
+ } catch {
164926
+ const tfResolved = reqPlugin.resolve("@huggingface/transformers");
164927
+ const tfDir = packageDirFromResolved(tfResolved, "@huggingface/transformers");
164928
+ const reqTf = createRequire3(join17(tfDir, "package.json"));
164929
+ onnxDir = packageDirFromResolved(reqTf.resolve("onnxruntime-node"), "onnxruntime-node");
164930
+ }
164931
+ } catch (error51) {
164932
+ resolveError = error51?.code;
164933
+ if (resolveError === "ERR_MODULE_NOT_FOUND" || resolveError === "MODULE_NOT_FOUND") {
164934
+ return {
164935
+ state: "package-missing",
164936
+ packageDir: join17(pluginDir, "node_modules", "onnxruntime-node")
164937
+ };
164938
+ }
164939
+ return {
164940
+ state: "unknown",
164941
+ reason: `could not resolve onnxruntime-node (${resolveError ?? "unknown error"})`
164942
+ };
164943
+ }
164944
+ if (!onnxDir) {
164945
+ return { state: "unknown", reason: "onnxruntime-node resolution produced no path" };
164946
+ }
164947
+ const rel = expectedBinaryRelPath(platform, arch);
164948
+ if (rel === null) {
164949
+ return { state: "ok", binaryPath: onnxDir };
164950
+ }
164951
+ const binaryPath = join17(onnxDir, rel);
164952
+ if (!existsSync20(binaryPath)) {
164953
+ return { state: "binary-missing", packageDir: onnxDir, expectedBinary: binaryPath };
164954
+ }
164955
+ return { state: "ok", binaryPath };
164956
+ }
164957
+ var init_embedding_runtime = () => {};
164958
+
164263
164959
  // src/lib/issue-body.ts
164264
164960
  function isErrorLogLine(line) {
164265
164961
  return ERROR_LOG_PATTERNS.some((rx) => rx.test(line));
@@ -164347,8 +165043,8 @@ var init_issue_body = __esm(() => {
164347
165043
 
164348
165044
  // src/lib/logs-opencode.ts
164349
165045
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
164350
- import { homedir as homedir12 } from "node:os";
164351
- import { join as join16 } from "node:path";
165046
+ import { homedir as homedir13 } from "node:os";
165047
+ import { join as join18 } from "node:path";
164352
165048
  function sanitizeLogContent(content) {
164353
165049
  return sanitizeDiagnosticText(content);
164354
165050
  }
@@ -164401,7 +165097,7 @@ async function bundleIssueReport(report, description, _title, sessionFilter = nu
164401
165097
  `));
164402
165098
  const recentErrorLines = extractRecentErrors(errorScanWindow, 20);
164403
165099
  const configBody = JSON.stringify(sanitizeConfigValue(report.magicContextConfig.flags), null, 2);
164404
- const sanitizedConfigPath = report.configPaths.magicContextConfig.replace(homedir12(), "~");
165100
+ const sanitizedConfigPath = report.configPaths.magicContextConfig.replace(homedir13(), "~");
164405
165101
  const rawBodyMarkdown = [
164406
165102
  "## Description",
164407
165103
  description,
@@ -164438,10 +165134,10 @@ async function bundleIssueReport(report, description, _title, sessionFilter = nu
164438
165134
  ].join(`
164439
165135
  `);
164440
165136
  const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
164441
- const path5 = join16(process.cwd(), `magic-context-issue-${formatTimestamp(new Date)}.md`);
164442
- writeFileSync8(path5, `${bodyMarkdown}
165137
+ const path6 = join18(process.cwd(), `magic-context-issue-${formatTimestamp(new Date)}.md`);
165138
+ writeFileSync8(path6, `${bodyMarkdown}
164443
165139
  `);
164444
- return { path: path5, bodyMarkdown };
165140
+ return { path: path6, bodyMarkdown };
164445
165141
  }
164446
165142
  var HISTORIAN_LOG_PATTERNS;
164447
165143
  var init_logs_opencode = __esm(() => {
@@ -164461,10 +165157,10 @@ var init_logs_opencode = __esm(() => {
164461
165157
 
164462
165158
  // src/commands/doctor-opencode.ts
164463
165159
  import { execSync as execSync2, spawnSync as spawnSync2 } from "node:child_process";
164464
- import { existsSync as existsSync19, readFileSync as readFileSync14, rmSync, statSync as statSync5, writeFileSync as writeFileSync9 } from "node:fs";
164465
- import { createRequire as createRequire3 } from "node:module";
164466
- import { homedir as homedir13 } from "node:os";
164467
- import { join as join17 } from "node:path";
165160
+ import { existsSync as existsSync21, readFileSync as readFileSync14, rmSync, statSync as statSync5, writeFileSync as writeFileSync9 } from "node:fs";
165161
+ import { createRequire as createRequire4 } from "node:module";
165162
+ import { homedir as homedir14 } from "node:os";
165163
+ import { join as join19 } from "node:path";
164468
165164
  function migrateLegacyAgentEnabledConfigForDoctor(mcConfig, logs) {
164469
165165
  let changed = false;
164470
165166
  let fixes = 0;
@@ -164523,7 +165219,7 @@ async function fetchNpmLatest(pkg, timeoutMs = 5000) {
164523
165219
  }
164524
165220
  }
164525
165221
  function getSelfVersion2() {
164526
- const req = createRequire3(import.meta.url);
165222
+ const req = createRequire4(import.meta.url);
164527
165223
  for (const relPath of ["../../package.json", "../package.json"]) {
164528
165224
  try {
164529
165225
  const pkg = req(relPath);
@@ -164551,21 +165247,21 @@ function compareVersions(a, b2) {
164551
165247
  }
164552
165248
  async function clearPluginCache(force = false) {
164553
165249
  const cacheDir = getOpenCodeCacheDir();
164554
- const pluginCacheDir = join17(cacheDir, "packages", PLUGIN_ENTRY_WITH_VERSION2);
164555
- if (!existsSync19(pluginCacheDir)) {
165250
+ const pluginCacheDir = join19(cacheDir, "packages", PLUGIN_ENTRY_WITH_VERSION2);
165251
+ if (!existsSync21(pluginCacheDir)) {
164556
165252
  return { action: "not_found", path: pluginCacheDir };
164557
165253
  }
164558
165254
  let cachedVersion;
164559
165255
  try {
164560
- const installedPkgPath = join17(pluginCacheDir, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
164561
- if (existsSync19(installedPkgPath)) {
165256
+ const installedPkgPath = join19(pluginCacheDir, "node_modules", "@cortexkit", "opencode-magic-context", "package.json");
165257
+ if (existsSync21(installedPkgPath)) {
164562
165258
  const pkg = JSON.parse(readFileSync14(installedPkgPath, "utf-8"));
164563
165259
  if (typeof pkg?.version === "string") {
164564
165260
  cachedVersion = pkg.version;
164565
165261
  }
164566
165262
  }
164567
165263
  } catch {}
164568
- const require2 = createRequire3(import.meta.url);
165264
+ const require2 = createRequire4(import.meta.url);
164569
165265
  let selfVersion;
164570
165266
  for (const relPath of ["../../package.json", "../package.json"]) {
164571
165267
  try {
@@ -164690,9 +165386,21 @@ async function runIssueFlow() {
164690
165386
  return 1;
164691
165387
  }
164692
165388
  }
165389
+ function checkLocalEmbeddingRuntimeForDoctor() {
165390
+ const runtime = checkLocalEmbeddingRuntime([
165391
+ join19(getOpenCodeCacheDir(), "packages", PLUGIN_ENTRY_WITH_VERSION2),
165392
+ join19(getOpenCodeCacheDir(), "packages", PLUGIN_NAME6)
165393
+ ]);
165394
+ if (runtime.state === "package-missing" || runtime.state === "binary-missing") {
165395
+ log.warn("Embedding provider: local — but the native runtime (onnxruntime-node) " + `is ${runtime.state === "package-missing" ? "not installed" : "missing its platform binary"}. ` + "Local embeddings won't work. Fix: re-run with `doctor --force` to reinstall " + "the plugin, or set `embedding.provider` to `openai-compatible` (LM Studio / " + "Ollama) or `off`. Existing memories are unaffected.");
165396
+ return { issues: 1, localRuntimeBroken: true };
165397
+ }
165398
+ log.success("Embedding provider: local (Xenova/all-MiniLM-L6-v2 bundled)");
165399
+ return { issues: 0 };
165400
+ }
164693
165401
  async function checkEmbeddingConfig(magicContextConfigPath) {
164694
- if (!existsSync19(magicContextConfigPath)) {
164695
- return { issues: 0 };
165402
+ if (!existsSync21(magicContextConfigPath)) {
165403
+ return checkLocalEmbeddingRuntimeForDoctor();
164696
165404
  }
164697
165405
  let rawText;
164698
165406
  try {
@@ -164719,8 +165427,7 @@ async function checkEmbeddingConfig(magicContextConfigPath) {
164719
165427
  return { issues: 0 };
164720
165428
  }
164721
165429
  if (provider === undefined || provider === "local") {
164722
- log.success("Embedding provider: local (Xenova/all-MiniLM-L6-v2 bundled)");
164723
- return { issues: 0 };
165430
+ return checkLocalEmbeddingRuntimeForDoctor();
164724
165431
  }
164725
165432
  if (provider !== "openai-compatible") {
164726
165433
  log.warn(`Unknown embedding provider: ${String(provider)} (expected local | openai-compatible | off)`);
@@ -164859,7 +165566,7 @@ async function runDoctor(options = {}) {
164859
165566
  } else {
164860
165567
  pass(`OpenCode config: ${paths.opencodeConfig}`);
164861
165568
  }
164862
- if (existsSync19(paths.magicContextConfig)) {
165569
+ if (existsSync21(paths.magicContextConfig)) {
164863
165570
  pass(`Magic Context config: ${paths.magicContextConfig}`);
164864
165571
  try {
164865
165572
  const raw = readFileSync14(paths.magicContextConfig, "utf-8");
@@ -164887,7 +165594,7 @@ async function runDoctor(options = {}) {
164887
165594
  warn(`No magic-context.jsonc found — using defaults`);
164888
165595
  log.info(" Run 'setup' to create one with model recommendations");
164889
165596
  }
164890
- if (existsSync19(paths.magicContextConfig)) {
165597
+ if (existsSync21(paths.magicContextConfig)) {
164891
165598
  try {
164892
165599
  const mcRaw = readFileSync14(paths.magicContextConfig, "utf-8");
164893
165600
  const mcConfig = import_comment_json9.parse(mcRaw);
@@ -165094,7 +165801,7 @@ async function runDoctor(options = {}) {
165094
165801
  pass("Added TUI sidebar plugin to tui.json");
165095
165802
  warn("Restart OpenCode to see the sidebar");
165096
165803
  fixed++;
165097
- } else if (existsSync19(paths.tuiConfig)) {
165804
+ } else if (existsSync21(paths.tuiConfig)) {
165098
165805
  try {
165099
165806
  const tuiRaw = readFileSync14(paths.tuiConfig, "utf-8");
165100
165807
  const tuiConfig = import_comment_json9.parse(tuiRaw);
@@ -165142,7 +165849,7 @@ async function runDoctor(options = {}) {
165142
165849
  } else {
165143
165850
  pass("TUI sidebar plugin configured (tui.json created)");
165144
165851
  }
165145
- if (existsSync19(paths.magicContextConfig)) {
165852
+ if (existsSync21(paths.magicContextConfig)) {
165146
165853
  try {
165147
165854
  const mcRaw = readFileSync14(paths.magicContextConfig, "utf-8");
165148
165855
  const mcConfig = import_comment_json9.parse(mcRaw);
@@ -165171,8 +165878,8 @@ async function runDoctor(options = {}) {
165171
165878
  failCount += embeddingCheck.issues;
165172
165879
  else
165173
165880
  passCount++;
165174
- const dbPath = join17(getMagicContextStorageDir(), "context.db");
165175
- if (!existsSync19(dbPath)) {
165881
+ const dbPath = join19(getMagicContextStorageDir(), "context.db");
165882
+ if (!existsSync21(dbPath)) {
165176
165883
  log.info(`Shared context DB not yet created at ${dbPath} (will be created on first run)`);
165177
165884
  } else {
165178
165885
  pass(`Shared context DB exists at ${dbPath}`);
@@ -165233,8 +165940,8 @@ async function runDoctor(options = {}) {
165233
165940
  }
165234
165941
  {
165235
165942
  const ageWarnings = [];
165236
- const npmrcPath = join17(homedir13(), ".npmrc");
165237
- if (existsSync19(npmrcPath)) {
165943
+ const npmrcPath = join19(homedir14(), ".npmrc");
165944
+ if (existsSync21(npmrcPath)) {
165238
165945
  try {
165239
165946
  const npmrc = readFileSync14(npmrcPath, "utf-8");
165240
165947
  for (const line of npmrc.split(`
@@ -165260,7 +165967,7 @@ async function runDoctor(options = {}) {
165260
165967
  }
165261
165968
  }
165262
165969
  const logPath = getMagicContextLogPath2("opencode");
165263
- if (existsSync19(logPath)) {
165970
+ if (existsSync21(logPath)) {
165264
165971
  const logStat = statSync5(logPath);
165265
165972
  const sizeKb = (logStat.size / 1024).toFixed(0);
165266
165973
  log.info(`Log file: ${logPath} (${sizeKb} KB)`);
@@ -165317,6 +166024,7 @@ var init_doctor_opencode = __esm(async () => {
165317
166024
  init_tui_config();
165318
166025
  init_opencode();
165319
166026
  init_diagnostics_opencode();
166027
+ init_embedding_runtime();
165320
166028
  init_logs_opencode();
165321
166029
  init_opencode_helpers();
165322
166030
  init_paths();
@@ -165331,44 +166039,44 @@ var init_doctor_opencode = __esm(async () => {
165331
166039
  });
165332
166040
 
165333
166041
  // ../pi-plugin/src/config/index.ts
165334
- import { existsSync as existsSync20, readFileSync as readFileSync15 } from "node:fs";
165335
- import { homedir as homedir14 } from "node:os";
165336
- import { join as join18 } from "node:path";
166042
+ import { existsSync as existsSync22, readFileSync as readFileSync15 } from "node:fs";
166043
+ import { homedir as homedir15 } from "node:os";
166044
+ import { join as join20 } from "node:path";
165337
166045
  function getProjectConfigPaths(cwd) {
165338
- const basePath = join18(cwd, ".pi", CONFIG_FILE_NAME);
166046
+ const basePath = join20(cwd, ".pi", CONFIG_FILE_NAME);
165339
166047
  return [`${basePath}.jsonc`, `${basePath}.json`];
165340
166048
  }
165341
166049
  function getUserConfigPaths() {
165342
- const home = process.env.HOME ?? homedir14();
165343
- const basePath = join18(home, ".pi", "agent", CONFIG_FILE_NAME);
166050
+ const home = process.env.HOME ?? homedir15();
166051
+ const basePath = join20(home, ".pi", "agent", CONFIG_FILE_NAME);
165344
166052
  return [`${basePath}.jsonc`, `${basePath}.json`];
165345
166053
  }
165346
166054
  function resolveFirstExisting(paths) {
165347
- return paths.find((path5) => existsSync20(path5));
166055
+ return paths.find((path6) => existsSync22(path6));
165348
166056
  }
165349
- function loadConfigFile2(path5, scope) {
166057
+ function loadConfigFile2(path6, scope) {
165350
166058
  try {
165351
- const rawText = readFileSync15(path5, "utf-8");
166059
+ const rawText = readFileSync15(path6, "utf-8");
165352
166060
  const substituted = substituteConfigVariables({
165353
166061
  text: rawText,
165354
- configPath: path5,
166062
+ configPath: path6,
165355
166063
  isProjectConfig: scope === "project"
165356
166064
  });
165357
166065
  return {
165358
- path: path5,
166066
+ path: path6,
165359
166067
  scope,
165360
166068
  config: import_comment_json10.parse(substituted.text),
165361
- warnings: substituted.warnings.map((warning) => `${path5}: ${warning}`),
166069
+ warnings: substituted.warnings.map((warning) => `${path6}: ${warning}`),
165362
166070
  loadOutcome: substituted.warnings.length > 0 ? "substitution-failure" : "ok"
165363
166071
  };
165364
166072
  } catch (error51) {
165365
166073
  const message = error51 instanceof Error ? error51.message : String(error51);
165366
166074
  return {
165367
- path: path5,
166075
+ path: path6,
165368
166076
  scope,
165369
166077
  config: {},
165370
166078
  warnings: [
165371
- `${path5}: failed to load config: ${message}; using defaults for this file.`
166079
+ `${path6}: failed to load config: ${message}; using defaults for this file.`
165372
166080
  ],
165373
166081
  loadOutcome: typeof error51.code === "string" ? "project-file-io-error" : "project-file-parse-error"
165374
166082
  };
@@ -165524,12 +166232,12 @@ var init_config2 = __esm(() => {
165524
166232
 
165525
166233
  // src/lib/diagnostics-pi.ts
165526
166234
  import { createHash as createHash3 } from "node:crypto";
165527
- import { existsSync as existsSync21, readdirSync as readdirSync3, readFileSync as readFileSync16, statSync as statSync6 } from "node:fs";
165528
- import { createRequire as createRequire4 } from "node:module";
165529
- import { homedir as homedir15, userInfo as userInfo2 } from "node:os";
165530
- import { join as join19 } from "node:path";
166235
+ import { existsSync as existsSync23, readdirSync as readdirSync3, readFileSync as readFileSync16, statSync as statSync6 } from "node:fs";
166236
+ import { createRequire as createRequire5 } from "node:module";
166237
+ import { homedir as homedir16, userInfo as userInfo2 } from "node:os";
166238
+ import { join as join21 } from "node:path";
165531
166239
  function getSelfVersion3() {
165532
- const req = createRequire4(import.meta.url);
166240
+ const req = createRequire5(import.meta.url);
165533
166241
  for (const relPath of ["../../package.json", "../package.json"]) {
165534
166242
  try {
165535
166243
  const pkg = req(relPath);
@@ -165540,9 +166248,9 @@ function getSelfVersion3() {
165540
166248
  }
165541
166249
  return "unknown";
165542
166250
  }
165543
- function fileSize2(path5) {
166251
+ function fileSize2(path6) {
165544
166252
  try {
165545
- return existsSync21(path5) ? statSync6(path5).size : 0;
166253
+ return existsSync23(path6) ? statSync6(path6).size : 0;
165546
166254
  } catch {
165547
166255
  return 0;
165548
166256
  }
@@ -165558,7 +166266,7 @@ function redactSecretString(value) {
165558
166266
  return value.replace(/Bearer\s+[A-Za-z0-9._~+\-/=]+/g, "Bearer <REDACTED>").replace(/sk-[A-Za-z0-9_-]{12,}/g, "sk-<REDACTED>").replace(/api[_-]?key=([^\s&]+)/gi, "api_key=<REDACTED>").replace(/token=([^\s&]+)/gi, "token=<REDACTED>");
165559
166267
  }
165560
166268
  function sanitizeString2(value) {
165561
- const home = process.env.HOME || homedir15();
166269
+ const home = process.env.HOME || homedir16();
165562
166270
  const username = userInfo2().username;
165563
166271
  const userHash = `<USER:${currentUserHash()}>`;
165564
166272
  let sanitized = redactSecretString(value);
@@ -165591,12 +166299,12 @@ function sanitizeValue2(value, key = "") {
165591
166299
  }
165592
166300
  return value;
165593
166301
  }
165594
- function readJsonc3(path5) {
165595
- if (!existsSync21(path5))
166302
+ function readJsonc3(path6) {
166303
+ if (!existsSync23(path6))
165596
166304
  return { value: {} };
165597
166305
  try {
165598
166306
  return {
165599
- value: import_comment_json11.parse(readFileSync16(path5, "utf-8"))
166307
+ value: import_comment_json11.parse(readFileSync16(path6, "utf-8"))
165600
166308
  };
165601
166309
  } catch (error51) {
165602
166310
  return {
@@ -165606,13 +166314,13 @@ function readJsonc3(path5) {
165606
166314
  }
165607
166315
  }
165608
166316
  function getProjectConfigPath(cwd) {
165609
- return join19(cwd, ".pi", "magic-context.jsonc");
166317
+ return join21(cwd, ".pi", "magic-context.jsonc");
165610
166318
  }
165611
- function readConfigDiagnostic(path5) {
165612
- const parsed = readJsonc3(path5);
166319
+ function readConfigDiagnostic(path6) {
166320
+ const parsed = readJsonc3(path6);
165613
166321
  return {
165614
- path: path5,
165615
- exists: existsSync21(path5),
166322
+ path: path6,
166323
+ exists: existsSync23(path6),
165616
166324
  ...parsed.parseError ? { parseError: parsed.parseError } : {},
165617
166325
  flags: sanitizeValue2(parsed.value)
165618
166326
  };
@@ -165629,8 +166337,8 @@ function reverseSlugToDirectory(slug) {
165629
166337
  return `/${inner.replace(/-/g, "/")}`;
165630
166338
  }
165631
166339
  function collectPiRecentSessions() {
165632
- const sessionsRoot = join19(homedir15(), ".pi", "agent", "sessions");
165633
- if (!existsSync21(sessionsRoot))
166340
+ const sessionsRoot = join21(homedir16(), ".pi", "agent", "sessions");
166341
+ if (!existsSync23(sessionsRoot))
165634
166342
  return [];
165635
166343
  try {
165636
166344
  const slugs = readdirSync3(sessionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
@@ -165639,7 +166347,7 @@ function collectPiRecentSessions() {
165639
166347
  const directory = reverseSlugToDirectory(slug);
165640
166348
  if (!directory)
165641
166349
  continue;
165642
- const slugDir = join19(sessionsRoot, slug);
166350
+ const slugDir = join21(sessionsRoot, slug);
165643
166351
  let files;
165644
166352
  try {
165645
166353
  files = readdirSync3(slugDir).filter((name2) => name2.endsWith(".jsonl"));
@@ -165648,7 +166356,7 @@ function collectPiRecentSessions() {
165648
166356
  }
165649
166357
  for (const file2 of files) {
165650
166358
  try {
165651
- const mtime = statSync6(join19(slugDir, file2)).mtimeMs;
166359
+ const mtime = statSync6(join21(slugDir, file2)).mtimeMs;
165652
166360
  const sessionId = file2.replace(/\.jsonl$/, "");
165653
166361
  candidates.push({ sessionId, directory, mtime });
165654
166362
  } catch {}
@@ -165664,9 +166372,9 @@ function collectPiRecentSessions() {
165664
166372
  return [];
165665
166373
  }
165666
166374
  }
165667
- function parseHistorianDumpMeta2(path5) {
166375
+ function parseHistorianDumpMeta2(path6) {
165668
166376
  try {
165669
- const xml = readFileSync16(path5, "utf-8");
166377
+ const xml = readFileSync16(path6, "utf-8");
165670
166378
  const parsed = parseCompartmentOutput(xml);
165671
166379
  const factCountByCategory = {};
165672
166380
  for (const fact of parsed.facts) {
@@ -165699,11 +166407,11 @@ function parseHistorianDumpMeta2(path5) {
165699
166407
  }
165700
166408
  }
165701
166409
  function listDumpsInDir2(dir, limit) {
165702
- if (!existsSync21(dir))
166410
+ if (!existsSync23(dir))
165703
166411
  return { count: 0, recent: [] };
165704
166412
  try {
165705
166413
  const entries = readdirSync3(dir).filter((name2) => name2.endsWith(".xml")).map((name2) => {
165706
- const stat = statSync6(join19(dir, name2));
166414
+ const stat = statSync6(join21(dir, name2));
165707
166415
  return {
165708
166416
  name: name2,
165709
166417
  mtime: stat.mtimeMs,
@@ -165712,7 +166420,7 @@ function listDumpsInDir2(dir, limit) {
165712
166420
  }).sort((a, b2) => b2.mtime - a.mtime);
165713
166421
  const now = Date.now();
165714
166422
  const recent = entries.slice(0, limit).map((entry) => {
165715
- const meta3 = parseHistorianDumpMeta2(join19(dir, entry.name));
166423
+ const meta3 = parseHistorianDumpMeta2(join21(dir, entry.name));
165716
166424
  const summary = {
165717
166425
  name: entry.name,
165718
166426
  ageMinutes: Math.round((now - entry.mtime) / 60000),
@@ -165775,9 +166483,9 @@ async function collectDiagnostics2(cwd = process.cwd()) {
165775
166483
  const projectConfigPath = getProjectConfigPath(cwd);
165776
166484
  const loaded = loadPiConfig({ cwd });
165777
166485
  const storageDirPath = getMagicContextStorageDir();
165778
- const dbPath = join19(storageDirPath, "context.db");
166486
+ const dbPath = join21(storageDirPath, "context.db");
165779
166487
  const logPath = getMagicContextLogPath2("pi");
165780
- const logFileSize = existsSync21(logPath) ? statSync6(logPath).size : 0;
166488
+ const logFileSize = existsSync23(logPath) ? statSync6(logPath).size : 0;
165781
166489
  const otherPiExtensions = packages.filter((entry) => !isPiMagicContextPackageEntry(entry)).map(describePiPackageEntry);
165782
166490
  const recentSessions = collectPiRecentSessions();
165783
166491
  const historianDumps = collectPiHistorianDumps(recentSessions);
@@ -165792,7 +166500,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
165792
166500
  piVersion: pi ? getPiVersion(pi.path) : null,
165793
166501
  settings: {
165794
166502
  path: settingsPath,
165795
- exists: existsSync21(settingsPath),
166503
+ exists: existsSync23(settingsPath),
165796
166504
  ...settingsParsed.parseError ? { parseError: settingsParsed.parseError } : {},
165797
166505
  hasMagicContextPackage: hasPiMagicContextPackage(packages),
165798
166506
  packages: sanitizeValue2(packages)
@@ -165808,7 +166516,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
165808
166516
  loadWarnings: loaded.warnings.map(sanitizeString2),
165809
166517
  storageDir: {
165810
166518
  path: storageDirPath,
165811
- exists: existsSync21(storageDirPath),
166519
+ exists: existsSync23(storageDirPath),
165812
166520
  contextDbSizeBytes: fileSize2(dbPath)
165813
166521
  },
165814
166522
  conflicts: {
@@ -165817,7 +166525,7 @@ async function collectDiagnostics2(cwd = process.cwd()) {
165817
166525
  },
165818
166526
  logFile: {
165819
166527
  path: logPath,
165820
- exists: existsSync21(logPath),
166528
+ exists: existsSync23(logPath),
165821
166529
  sizeKb: Math.round(logFileSize / 1024)
165822
166530
  },
165823
166531
  recentSessions,
@@ -165873,7 +166581,7 @@ function renderDiagnosticsMarkdown2(report) {
165873
166581
  "```",
165874
166582
  "",
165875
166583
  "### Loaded config paths",
165876
- report.loadedConfigPaths.length === 0 ? "_No config files loaded; defaults are in use._" : report.loadedConfigPaths.map((path5) => `- ${path5}`).join(`
166584
+ report.loadedConfigPaths.length === 0 ? "_No config files loaded; defaults are in use._" : report.loadedConfigPaths.map((path6) => `- ${path6}`).join(`
165877
166585
  `),
165878
166586
  "",
165879
166587
  "### Config load warnings",
@@ -165911,7 +166619,7 @@ var init_diagnostics_pi = __esm(() => {
165911
166619
 
165912
166620
  // src/lib/logs-pi.ts
165913
166621
  import { readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "node:fs";
165914
- import { join as join20 } from "node:path";
166622
+ import { join as join22 } from "node:path";
165915
166623
  function sanitizeLogContent2(content) {
165916
166624
  return sanitizeString2(content);
165917
166625
  }
@@ -165976,10 +166684,10 @@ async function bundleIssueReport2(report, description, title, options = {}) {
165976
166684
  `);
165977
166685
  const bodyMarkdown = capBodyToGithubLimit(rawBodyMarkdown);
165978
166686
  const cwd = options.cwd ?? process.cwd();
165979
- const path5 = join20(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
165980
- writeFileSync10(path5, `${bodyMarkdown}
166687
+ const path6 = join22(cwd, `magic-context-pi-issue-${formatTimestamp2(options.now ?? new Date)}.md`);
166688
+ writeFileSync10(path6, `${bodyMarkdown}
165981
166689
  `);
165982
- return { path: path5, bodyMarkdown };
166690
+ return { path: path6, bodyMarkdown };
165983
166691
  }
165984
166692
  var init_logs_pi = __esm(() => {
165985
166693
  init_diagnostics_pi();
@@ -165989,7 +166697,7 @@ var init_logs_pi = __esm(() => {
165989
166697
  // src/commands/doctor-pi.ts
165990
166698
  import { execFileSync as execFileSync4, spawnSync as spawnSync3 } from "node:child_process";
165991
166699
  import {
165992
- existsSync as existsSync22,
166700
+ existsSync as existsSync24,
165993
166701
  mkdirSync as mkdirSync7,
165994
166702
  readdirSync as readdirSync4,
165995
166703
  readFileSync as readFileSync18,
@@ -165997,9 +166705,9 @@ import {
165997
166705
  statSync as statSync7,
165998
166706
  writeFileSync as writeFileSync11
165999
166707
  } from "node:fs";
166000
- import { createRequire as createRequire5 } from "node:module";
166001
- import { homedir as homedir16 } from "node:os";
166002
- import { dirname as dirname9, join as join21 } from "node:path";
166708
+ import { createRequire as createRequire6 } from "node:module";
166709
+ import { homedir as homedir17 } from "node:os";
166710
+ import { dirname as dirname10, isAbsolute as isAbsolute3, join as join23 } from "node:path";
166003
166711
  function depsFrom(options) {
166004
166712
  return {
166005
166713
  ...DEFAULT_DEPS,
@@ -166023,7 +166731,7 @@ function printDoctorHelp() {
166023
166731
  console.log("");
166024
166732
  }
166025
166733
  function selfVersion() {
166026
- const req = createRequire5(import.meta.url);
166734
+ const req = createRequire6(import.meta.url);
166027
166735
  for (const relPath of ["../../package.json", "../package.json"]) {
166028
166736
  try {
166029
166737
  const pkg = req(relPath);
@@ -166086,10 +166794,10 @@ function summarize(results) {
166086
166794
  fail: results.filter((result) => result.status === "fail").length
166087
166795
  };
166088
166796
  }
166089
- function readJsonc4(path5) {
166797
+ function readJsonc4(path6) {
166090
166798
  try {
166091
166799
  return {
166092
- value: import_comment_json12.parse(readFileSync18(path5, "utf-8"))
166800
+ value: import_comment_json12.parse(readFileSync18(path6, "utf-8"))
166093
166801
  };
166094
166802
  } catch (error51) {
166095
166803
  return {
@@ -166101,17 +166809,31 @@ function readJsonc4(path5) {
166101
166809
  function packagesFrom(settings) {
166102
166810
  return Array.isArray(settings.packages) ? settings.packages : [];
166103
166811
  }
166812
+ function piPluginDirCandidates(packages, cwd) {
166813
+ const dirs = [];
166814
+ const agentDir = getPiAgentConfigDir();
166815
+ for (const entry of packages) {
166816
+ const spec = typeof entry === "string" ? entry.trim() : "";
166817
+ if (!spec || spec.startsWith("npm:"))
166818
+ continue;
166819
+ const resolved = isAbsolute3(spec) ? spec : join23(agentDir, spec);
166820
+ dirs.push(resolved);
166821
+ }
166822
+ dirs.push(join23(agentDir, "npm", "node_modules", PACKAGE_NAME));
166823
+ dirs.push(join23(cwd, ".pi", "npm", "node_modules", PACKAGE_NAME));
166824
+ return dirs.filter((dir) => existsSync24(join23(dir, "package.json")));
166825
+ }
166104
166826
  function projectConfigPath(cwd) {
166105
- return join21(cwd, ".pi", "magic-context.jsonc");
166827
+ return join23(cwd, ".pi", "magic-context.jsonc");
166106
166828
  }
166107
- function readConfigForEmbedding(path5) {
166108
- if (!existsSync22(path5))
166829
+ function readConfigForEmbedding(path6) {
166830
+ if (!existsSync24(path6))
166109
166831
  return null;
166110
166832
  try {
166111
- const rawText = readFileSync18(path5, "utf-8");
166833
+ const rawText = readFileSync18(path6, "utf-8");
166112
166834
  const substituted = substituteConfigVariables({
166113
166835
  text: rawText,
166114
- configPath: path5
166836
+ configPath: path6
166115
166837
  });
166116
166838
  return import_comment_json12.parse(substituted.text);
166117
166839
  } catch {
@@ -166166,52 +166888,52 @@ function countTable(db, table) {
166166
166888
  }
166167
166889
  }
166168
166890
  function cacheRoots() {
166169
- const home = homedir16();
166170
- const cacheHome = process.env.XDG_CACHE_HOME || join21(home, ".cache");
166891
+ const home = homedir17();
166892
+ const cacheHome = process.env.XDG_CACHE_HOME || join23(home, ".cache");
166171
166893
  return [
166172
- join21(home, ".pi", "cache", "extensions"),
166173
- join21(home, ".pi", "cache", "packages"),
166174
- join21(cacheHome, "pi", "extensions"),
166175
- join21(cacheHome, "pi", "packages"),
166176
- join21(getPiAgentConfigDir(), "cache", "extensions")
166894
+ join23(home, ".pi", "cache", "extensions"),
166895
+ join23(home, ".pi", "cache", "packages"),
166896
+ join23(cacheHome, "pi", "extensions"),
166897
+ join23(cacheHome, "pi", "packages"),
166898
+ join23(getPiAgentConfigDir(), "cache", "extensions")
166177
166899
  ];
166178
166900
  }
166179
166901
  function findPiMagicContextCacheDirs(self, force = false) {
166180
166902
  const found = new Map;
166181
- const visit = (path5, depth) => {
166182
- if (depth < 0 || !existsSync22(path5))
166903
+ const visit = (path6, depth) => {
166904
+ if (depth < 0 || !existsSync24(path6))
166183
166905
  return;
166184
166906
  let stat;
166185
166907
  try {
166186
- stat = statSync7(path5);
166908
+ stat = statSync7(path6);
166187
166909
  } catch {
166188
166910
  return;
166189
166911
  }
166190
166912
  if (!stat.isDirectory())
166191
166913
  return;
166192
- const packageJson = join21(path5, "package.json");
166193
- if (existsSync22(packageJson)) {
166914
+ const packageJson = join23(path6, "package.json");
166915
+ if (existsSync24(packageJson)) {
166194
166916
  try {
166195
166917
  const pkg = JSON.parse(readFileSync18(packageJson, "utf-8"));
166196
166918
  const name2 = typeof pkg.name === "string" ? pkg.name : "";
166197
166919
  const version2 = typeof pkg.version === "string" ? pkg.version : undefined;
166198
- if (name2 === PACKAGE_NAME || path5.includes("pi-magic-context")) {
166920
+ if (name2 === PACKAGE_NAME || path6.includes("pi-magic-context")) {
166199
166921
  if (force || !version2 || version2 !== self)
166200
- found.set(path5, { path: path5, version: version2 });
166922
+ found.set(path6, { path: path6, version: version2 });
166201
166923
  }
166202
166924
  } catch {
166203
- if (path5.includes("pi-magic-context"))
166204
- found.set(path5, { path: path5 });
166925
+ if (path6.includes("pi-magic-context"))
166926
+ found.set(path6, { path: path6 });
166205
166927
  }
166206
166928
  }
166207
166929
  let entries = [];
166208
166930
  try {
166209
- entries = readdirSync4(path5);
166931
+ entries = readdirSync4(path6);
166210
166932
  } catch {
166211
166933
  return;
166212
166934
  }
166213
166935
  for (const entry of entries)
166214
- visit(join21(path5, entry), depth - 1);
166936
+ visit(join23(path6, entry), depth - 1);
166215
166937
  };
166216
166938
  for (const root of cacheRoots())
166217
166939
  visit(root, 5);
@@ -166248,7 +166970,7 @@ async function runHealthChecks(options) {
166248
166970
  }
166249
166971
  const settingsPath = getPiUserExtensionsPath();
166250
166972
  let packages = [];
166251
- if (!existsSync22(settingsPath)) {
166973
+ if (!existsSync24(settingsPath)) {
166252
166974
  add(results, "warn", `Pi settings not found at ${settingsPath}`);
166253
166975
  repairPlan.addPackageEntry = true;
166254
166976
  } else {
@@ -166268,24 +166990,24 @@ async function runHealthChecks(options) {
166268
166990
  }
166269
166991
  const userConfigPath = getPiUserConfigPath();
166270
166992
  const projectPath = projectConfigPath(options.cwd);
166271
- for (const [label, path5, required2] of [
166993
+ for (const [label, path6, required2] of [
166272
166994
  ["user", userConfigPath, true],
166273
166995
  ["project", projectPath, false]
166274
166996
  ]) {
166275
- if (!existsSync22(path5)) {
166997
+ if (!existsSync24(path6)) {
166276
166998
  if (required2) {
166277
- add(results, "warn", `No ${label} magic-context.jsonc found at ${path5}`);
166999
+ add(results, "warn", `No ${label} magic-context.jsonc found at ${path6}`);
166278
167000
  repairPlan.writeUserConfig = true;
166279
167001
  } else {
166280
- add(results, "info", `No project Pi magic-context.jsonc found at ${path5}`);
167002
+ add(results, "info", `No project Pi magic-context.jsonc found at ${path6}`);
166281
167003
  }
166282
167004
  continue;
166283
167005
  }
166284
- const parsed = readJsonc4(path5);
167006
+ const parsed = readJsonc4(path6);
166285
167007
  if (parsed.error)
166286
167008
  add(results, "fail", `${label} magic-context.jsonc is invalid JSONC: ${parsed.error}`);
166287
167009
  else
166288
- add(results, "pass", `${label} magic-context.jsonc is valid JSONC: ${path5}`);
167010
+ add(results, "pass", `${label} magic-context.jsonc is valid JSONC: ${path6}`);
166289
167011
  }
166290
167012
  const loadedConfig = loadPiConfig({ cwd: options.cwd });
166291
167013
  if (loadedConfig.warnings.length > 0) {
@@ -166305,8 +167027,8 @@ async function runHealthChecks(options) {
166305
167027
  add(results, "pass", `historian.model "${historianModel}" has thinking_level "${historianThinkingLevel}" configured`);
166306
167028
  }
166307
167029
  const storageDir = getMagicContextStorageDir();
166308
- const dbPath = join21(storageDir, "context.db");
166309
- const existedBeforeOpen = existsSync22(dbPath);
167030
+ const dbPath = join23(storageDir, "context.db");
167031
+ const existedBeforeOpen = existsSync24(dbPath);
166310
167032
  if (existedBeforeOpen)
166311
167033
  add(results, "pass", `Shared context DB exists at ${dbPath}`);
166312
167034
  else
@@ -166369,7 +167091,23 @@ async function runHealthChecks(options) {
166369
167091
  } else if (loadedConfig.config.embedding.provider === "off") {
166370
167092
  add(results, "info", "Embedding provider disabled");
166371
167093
  } else {
166372
- add(results, "pass", `Embedding provider: ${loadedConfig.config.embedding.provider}`);
167094
+ let runtimeReported = false;
167095
+ for (const pluginDir of piPluginDirCandidates(packages, options.cwd)) {
167096
+ const runtime = checkLocalEmbeddingRuntimeByResolution(pluginDir);
167097
+ if (runtime.state === "ok") {
167098
+ add(results, "pass", `Embedding provider: ${loadedConfig.config.embedding.provider} (native runtime present)`);
167099
+ runtimeReported = true;
167100
+ break;
167101
+ }
167102
+ if (runtime.state === "package-missing" || runtime.state === "binary-missing") {
167103
+ add(results, "warn", `Embedding provider: local — native runtime (onnxruntime-node) is ${runtime.state === "package-missing" ? "not installed" : "missing its platform binary"}. Local embeddings won't work. Fix: reinstall the plugin, or set ` + "`embedding.provider` to `openai-compatible` (LM Studio / Ollama) or `off`. " + "Existing memories are unaffected.");
167104
+ runtimeReported = true;
167105
+ break;
167106
+ }
167107
+ }
167108
+ if (!runtimeReported) {
167109
+ add(results, "pass", `Embedding provider: ${loadedConfig.config.embedding.provider}`);
167110
+ }
166373
167111
  }
166374
167112
  const piEntries = packages.filter(isPiMagicContextPackageEntry).map(describePiPackageEntry);
166375
167113
  if (piEntries.length > 1) {
@@ -166391,7 +167129,7 @@ async function runHealthChecks(options) {
166391
167129
  add(results, "pass", "Pi extension cache clean (no stale cached package found)");
166392
167130
  }
166393
167131
  const logPath = getMagicContextLogPath2("pi");
166394
- if (existsSync22(logPath)) {
167132
+ if (existsSync24(logPath)) {
166395
167133
  const stat = statSync7(logPath);
166396
167134
  const sizeKb = (stat.size / 1024).toFixed(0);
166397
167135
  const lines = readFileSync18(logPath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
@@ -166427,13 +167165,13 @@ async function runHealthChecks(options) {
166427
167165
  }
166428
167166
  return { results, repairPlan, ...summarize(results) };
166429
167167
  }
166430
- function writeDefaultMagicContextConfig(path5) {
166431
- mkdirSync7(dirname9(path5), { recursive: true });
167168
+ function writeDefaultMagicContextConfig(path6) {
167169
+ mkdirSync7(dirname10(path6), { recursive: true });
166432
167170
  const config2 = {
166433
167171
  $schema: "https://raw.githubusercontent.com/cortexkit/magic-context/master/assets/magic-context.schema.json",
166434
167172
  ...MagicContextConfigSchema.parse({})
166435
167173
  };
166436
- writeFileSync11(path5, `${import_comment_json12.stringify(config2, null, 2)}
167174
+ writeFileSync11(path6, `${import_comment_json12.stringify(config2, null, 2)}
166437
167175
  `);
166438
167176
  }
166439
167177
  function repair(plan, prompts) {
@@ -166450,7 +167188,7 @@ function repair(plan, prompts) {
166450
167188
  }
166451
167189
  if (plan.writeUserConfig) {
166452
167190
  const configPath = getPiUserConfigPath();
166453
- if (!existsSync22(configPath)) {
167191
+ if (!existsSync24(configPath)) {
166454
167192
  try {
166455
167193
  writeDefaultMagicContextConfig(configPath);
166456
167194
  prompts.log.success(`Wrote default Magic Context config to ${configPath}`);
@@ -166460,13 +167198,13 @@ function repair(plan, prompts) {
166460
167198
  }
166461
167199
  }
166462
167200
  }
166463
- for (const path5 of plan.clearCachePaths) {
167201
+ for (const path6 of plan.clearCachePaths) {
166464
167202
  try {
166465
- rmSync2(path5, { recursive: true, force: true });
166466
- prompts.log.success(`Cleared stale Pi extension cache: ${path5}`);
167203
+ rmSync2(path6, { recursive: true, force: true });
167204
+ prompts.log.success(`Cleared stale Pi extension cache: ${path6}`);
166467
167205
  fixed += 1;
166468
167206
  } catch (error51) {
166469
- console.error(`FAIL Could not clear ${path5}: ${error51 instanceof Error ? error51.message : String(error51)}`);
167207
+ console.error(`FAIL Could not clear ${path6}: ${error51 instanceof Error ? error51.message : String(error51)}`);
166470
167208
  }
166471
167209
  }
166472
167210
  return fixed;
@@ -166591,7 +167329,7 @@ async function runDoctor2(options = {}) {
166591
167329
  prompts.outro(first.fail > 0 ? "Doctor found failures" : "Doctor complete");
166592
167330
  return first.fail > 0 ? 1 : 0;
166593
167331
  }
166594
- function valueAfter(args, flag) {
167332
+ function valueAfter2(args, flag) {
166595
167333
  const index = args.indexOf(flag);
166596
167334
  if (index === -1)
166597
167335
  return null;
@@ -166601,7 +167339,7 @@ function valueAfter(args, flag) {
166601
167339
  return next;
166602
167340
  }
166603
167341
  function parseDoctorArgs(args) {
166604
- const rekeyV22DirIdentity = valueAfter(args, "--rekey-v22-dir-identity");
167342
+ const rekeyV22DirIdentity = valueAfter2(args, "--rekey-v22-dir-identity");
166605
167343
  return {
166606
167344
  force: args.includes("--force"),
166607
167345
  issue: args.includes("--issue"),
@@ -166621,6 +167359,7 @@ var init_doctor_pi = __esm(async () => {
166621
167359
  init_data_path();
166622
167360
  init_config2();
166623
167361
  init_diagnostics_pi();
167362
+ init_embedding_runtime();
166624
167363
  init_logs_pi();
166625
167364
  init_paths();
166626
167365
  init_pi_helpers();
@@ -166652,7 +167391,7 @@ var exports_doctor = {};
166652
167391
  __export(exports_doctor, {
166653
167392
  runDoctor: () => runDoctor3
166654
167393
  });
166655
- import { existsSync as existsSync23, rmSync as rmSync3 } from "node:fs";
167394
+ import { existsSync as existsSync25, rmSync as rmSync3 } from "node:fs";
166656
167395
  async function runDoctor3(options) {
166657
167396
  if (options.clear)
166658
167397
  return runClear();
@@ -166741,7 +167480,7 @@ async function runClear() {
166741
167480
  const s = spinner();
166742
167481
  s.start(`Clearing ${item.path}`);
166743
167482
  try {
166744
- if (existsSync23(item.path)) {
167483
+ if (existsSync25(item.path)) {
166745
167484
  rmSync3(item.path, { recursive: true, force: true });
166746
167485
  }
166747
167486
  s.stop(`Cleared ${item.path}`);
@@ -166776,9 +167515,9 @@ var init_doctor = __esm(async () => {
166776
167515
  });
166777
167516
 
166778
167517
  // src/index.ts
166779
- import { createRequire as createRequire6 } from "node:module";
167518
+ import { createRequire as createRequire7 } from "node:module";
166780
167519
  function getVersion() {
166781
- const req = createRequire6(import.meta.url);
167520
+ const req = createRequire7(import.meta.url);
166782
167521
  for (const relPath of ["../../package.json", "../package.json"]) {
166783
167522
  try {
166784
167523
  const pkg = req(relPath);
@@ -166789,7 +167528,7 @@ function getVersion() {
166789
167528
  }
166790
167529
  return "0.0.0";
166791
167530
  }
166792
- function valueAfter2(args, flag) {
167531
+ function valueAfter3(args, flag) {
166793
167532
  const index = args.indexOf(flag);
166794
167533
  if (index === -1)
166795
167534
  return null;
@@ -166813,6 +167552,7 @@ function printUsage() {
166813
167552
  console.log(" doctor --retry-v22-backfill Retry failed v22 memory backfill rows");
166814
167553
  console.log(" doctor --rekey-v22-dir-identity <path> Re-key legacy dir identity rows");
166815
167554
  console.log(" doctor migrate Migrate OpenCode session to Pi JSONL");
167555
+ console.log(" doctor migrate-session Re-home an OpenCode session to another directory");
166816
167556
  console.log("");
166817
167557
  console.log(" Harness selection:");
166818
167558
  console.log(" --harness opencode Target OpenCode only");
@@ -166848,8 +167588,12 @@ async function main(argv = process.argv.slice(2)) {
166848
167588
  const { runMigrateCli: runMigrateCli2 } = await init_migrate().then(() => exports_migrate);
166849
167589
  return runMigrateCli2(rest.slice(1));
166850
167590
  }
167591
+ if (rest[0] === "migrate-session") {
167592
+ const { runMigrateSessionCli: runMigrateSessionCli2 } = await init_migrate_session().then(() => exports_migrate_session);
167593
+ return runMigrateSessionCli2(rest.slice(1));
167594
+ }
166851
167595
  const { runDoctor: runDoctor4 } = await init_doctor().then(() => exports_doctor);
166852
- const rekeyV22DirIdentity = valueAfter2(rest, "--rekey-v22-dir-identity");
167596
+ const rekeyV22DirIdentity = valueAfter3(rest, "--rekey-v22-dir-identity");
166853
167597
  return runDoctor4({
166854
167598
  force: rest.includes("--force"),
166855
167599
  issue: rest.includes("--issue"),