imprnt 0.1.3-edge.59 → 0.1.3-edge.61

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 (3) hide show
  1. package/dist/cli.js +152 -44
  2. package/dist/imp.js +152 -44
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -766,14 +766,9 @@ function registerVault(path, opts = {}) {
766
766
  const name = opts.name ?? "personal";
767
767
  reg.vaults[name] = path;
768
768
  reg.default = name;
769
- const p = configPath();
770
- try {
771
- mkdirSync2(dirname2(p), { recursive: true });
772
- writeFileSync5(p, JSON.stringify(reg, null, 2) + `
773
- `);
774
- } catch (e) {
775
- return { status: "error", current: path, error: e instanceof Error ? e.message : String(e) };
776
- }
769
+ const w = writeRegistry(reg);
770
+ if (!w.ok)
771
+ return { status: "error", current: path, error: w.error };
777
772
  return { status: "registered", current: path };
778
773
  }
779
774
  function readDefaultAgent() {
@@ -842,8 +837,9 @@ var init_registry = () => {};
842
837
  // scripts/lib/launch.ts
843
838
  import { existsSync as existsSync7, mkdtempSync as mkdtempSync2, readFileSync as readFileSync7, realpathSync, rmSync as rmSync3, statSync as statSync5, writeFileSync as writeFileSync6 } from "node:fs";
844
839
  import { homedir as homedir2, tmpdir as tmpdir2 } from "node:os";
845
- import { isAbsolute, join as join8, resolve as resolve4, sep as sep2 } from "node:path";
840
+ import { basename as basename2, isAbsolute, join as join8, resolve as resolve4, sep as sep2 } from "node:path";
846
841
  import { spawnSync as spawnSync2 } from "node:child_process";
842
+ import { createInterface } from "node:readline/promises";
847
843
  function importPath(root, target) {
848
844
  if (target.startsWith("~/"))
849
845
  return join8(homedir2(), target.slice(2));
@@ -1013,7 +1009,12 @@ function claudeRenderArgs(spec) {
1013
1009
  const systemPrompt = spec.insideProject ? spec.globals : joinFragments([spec.cast, spec.pointer, spec.globals]);
1014
1010
  const harness = spec.pluginsRoot ? harnessFlags(spec.pluginsRoot) : [];
1015
1011
  const extra = spec.addDirs.flatMap((d) => ["--add-dir", d]);
1016
- const pass = spec.skipPermissions && !spec.passthrough.includes("--dangerously-skip-permissions") ? ["--dangerously-skip-permissions", ...spec.passthrough] : spec.passthrough;
1012
+ const lead = [];
1013
+ if (spec.skipPermissions && !spec.passthrough.includes("--dangerously-skip-permissions"))
1014
+ lead.push("--dangerously-skip-permissions");
1015
+ if (spec.model && !spec.passthrough.some((a) => a === "--model" || a.startsWith("--model=")))
1016
+ lead.push("--model", spec.model);
1017
+ const pass = lead.length ? [...lead, ...spec.passthrough] : spec.passthrough;
1017
1018
  const body = systemPrompt ? mergeFragment(pass, systemPrompt, extra) : [...pass, ...extra];
1018
1019
  return [...harness, ...body];
1019
1020
  }
@@ -1023,6 +1024,19 @@ function expandGeminiModel(m) {
1023
1024
  function escapeGeminiImports(text) {
1024
1025
  return text.replaceAll("@", "\\@");
1025
1026
  }
1027
+ function trackGeminiTempDir(dir) {
1028
+ geminiTempDirs.add(dir);
1029
+ if (geminiCleanupArmed)
1030
+ return;
1031
+ geminiCleanupArmed = true;
1032
+ process.on("exit", () => {
1033
+ for (const d of geminiTempDirs) {
1034
+ try {
1035
+ rmSync3(d, { recursive: true, force: true });
1036
+ } catch {}
1037
+ }
1038
+ });
1039
+ }
1026
1040
  function geminiRenderArgs(spec) {
1027
1041
  const includes = [];
1028
1042
  const systemPrompt = joinFragments([spec.cast, spec.pointer, spec.globals]);
@@ -1030,11 +1044,7 @@ function geminiRenderArgs(spec) {
1030
1044
  const dir = mkdtempSync2(join8(tmpdir2(), "imprnt-gemini-"));
1031
1045
  writeFileSync6(join8(dir, "GEMINI.md"), escapeGeminiImports(systemPrompt) + `
1032
1046
  `);
1033
- process.on("exit", () => {
1034
- try {
1035
- rmSync3(dir, { recursive: true, force: true });
1036
- } catch {}
1037
- });
1047
+ trackGeminiTempDir(dir);
1038
1048
  includes.push(dir);
1039
1049
  }
1040
1050
  includes.push(...spec.addDirs);
@@ -1049,24 +1059,117 @@ function geminiRenderArgs(spec) {
1049
1059
  lead.push("--skip-trust");
1050
1060
  }
1051
1061
  const pass = [...spec.passthrough];
1052
- const mIdx = pass.findIndex((a) => a === "-m" || a === "--model");
1053
- if (mIdx >= 0 && pass[mIdx + 1] !== undefined) {
1054
- pass[mIdx + 1] = expandGeminiModel(pass[mIdx + 1]);
1055
- } else if (mIdx < 0 && spec.model) {
1062
+ const mTerm = pass.indexOf("--");
1063
+ const mEnd = mTerm < 0 ? pass.length : mTerm;
1064
+ const isModelFlag = (a) => a === "-m" || a === "--model" || a.startsWith("-m=") || a.startsWith("--model=");
1065
+ const mIdx = pass.slice(0, mEnd).findIndex(isModelFlag);
1066
+ if (mIdx >= 0) {
1067
+ const tok = pass[mIdx];
1068
+ const eq = tok.indexOf("=");
1069
+ if (eq >= 0)
1070
+ pass[mIdx] = tok.slice(0, eq + 1) + expandGeminiModel(tok.slice(eq + 1));
1071
+ else if (mIdx + 1 < mEnd && pass[mIdx + 1] !== undefined)
1072
+ pass[mIdx + 1] = expandGeminiModel(pass[mIdx + 1]);
1073
+ } else if (spec.model) {
1056
1074
  pass.unshift("-m", expandGeminiModel(spec.model));
1057
1075
  }
1058
- const rIdx = pass.findIndex((a) => a === "-r" || a === "--resume");
1059
- if (rIdx >= 0 && (pass[rIdx + 1] === undefined || pass[rIdx + 1].startsWith("-"))) {
1076
+ const rIdx = valuelessResumeIndex(pass);
1077
+ if (rIdx >= 0)
1060
1078
  pass.splice(rIdx + 1, 0, "latest");
1061
- }
1062
1079
  const flags = includes.length ? ["--include-directories", includes.join(",")] : [];
1063
1080
  return [...lead, ...flags, ...pass];
1064
1081
  }
1082
+ function parseGeminiSessions(stdout) {
1083
+ const out = [];
1084
+ for (const raw of stdout.split(/\r?\n/)) {
1085
+ const m = raw.match(/^\s*(\d+)\.\s+(.+?)\s+\(([^()]+)\)\s+\[([0-9a-fA-F-]{8,})\]\s*$/);
1086
+ if (m)
1087
+ out.push({ index: Number(m[1]), name: m[2].trim(), age: m[3].trim(), id: m[4] });
1088
+ }
1089
+ return out;
1090
+ }
1091
+ function valuelessResumeIndex(args) {
1092
+ const term = args.indexOf("--");
1093
+ const end = term < 0 ? args.length : term;
1094
+ let i = -1;
1095
+ for (let k = 0;k < end; k++) {
1096
+ if (args[k] === "-r" || args[k] === "--resume") {
1097
+ i = k;
1098
+ break;
1099
+ }
1100
+ }
1101
+ if (i < 0)
1102
+ return -1;
1103
+ const next = i + 1 < end ? args[i + 1] : undefined;
1104
+ return next === undefined || next.startsWith("-") ? i : -1;
1105
+ }
1106
+ function listGeminiSessions(cwd) {
1107
+ const r = spawnSync2("gemini", ["--list-sessions", "--skip-trust"], { cwd, encoding: "utf8" });
1108
+ if (r.error || r.status !== 0)
1109
+ return { sessions: [], ran: false };
1110
+ const stdout = r.stdout || "";
1111
+ const sessions = parseGeminiSessions(stdout);
1112
+ if (!sessions.length && stdout.trim() && !/\(\s*0\s*\)|no sessions/i.test(stdout)) {
1113
+ console.error("imp: couldn't parse gemini's session list (its format may have changed) - starting fresh");
1114
+ }
1115
+ return { sessions, ran: true };
1116
+ }
1117
+ async function pickGeminiSession(sessions, label) {
1118
+ const cols = process.stdout.columns || 80;
1119
+ const nameW = Math.max(20, Math.min(64, cols - 16));
1120
+ const trunc = (s) => s.length > nameW ? s.slice(0, nameW - 1) + "…" : s;
1121
+ process.stderr.write(`
1122
+ resume a chat - gemini · ${label}
1123
+
1124
+ `);
1125
+ sessions.forEach((s, i) => {
1126
+ process.stderr.write(` ${String(i + 1).padStart(2)} ${trunc(s.name).padEnd(nameW)} ${s.age.replace(/\s*ago$/, "")}
1127
+ `);
1128
+ });
1129
+ process.stderr.write(`
1130
+ `);
1131
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
1132
+ const answer = (await rl.question(" number to resume · enter for newest · q to cancel › ")).trim();
1133
+ rl.close();
1134
+ if (answer === "")
1135
+ return "latest";
1136
+ if (answer.toLowerCase() === "q")
1137
+ return null;
1138
+ const n = Number(answer);
1139
+ if (Number.isInteger(n) && n >= 1 && n <= sessions.length)
1140
+ return sessions[n - 1].id;
1141
+ process.stderr.write(` not a valid choice - starting a fresh session
1142
+ `);
1143
+ return null;
1144
+ }
1145
+ async function geminiResolveResume(passthrough, cwd) {
1146
+ const rIdx = valuelessResumeIndex(passthrough);
1147
+ if (rIdx < 0)
1148
+ return passthrough;
1149
+ if (!(process.stdin.isTTY && process.stdout.isTTY))
1150
+ return passthrough;
1151
+ const { sessions, ran } = listGeminiSessions(cwd);
1152
+ if (!ran)
1153
+ return passthrough;
1154
+ if (!sessions.length) {
1155
+ console.error("imp: no saved gemini chats for this project yet - starting fresh");
1156
+ return passthrough.filter((_, i) => i !== rIdx);
1157
+ }
1158
+ const chosen = await pickGeminiSession(sessions, basename2(cwd));
1159
+ if (chosen === null)
1160
+ return passthrough.filter((_, i) => i !== rIdx);
1161
+ const out = [...passthrough];
1162
+ out.splice(rIdx + 1, 0, chosen);
1163
+ return out;
1164
+ }
1065
1165
  function resolveLaunch(passthrough, config = {}) {
1166
+ const term = passthrough.indexOf("--");
1167
+ const head = term < 0 ? passthrough : passthrough.slice(0, term);
1168
+ const tail = term < 0 ? [] : passthrough.slice(term);
1066
1169
  let agentFlag;
1067
1170
  let yoloFlag;
1068
1171
  const rest = [];
1069
- for (const a of passthrough) {
1172
+ for (const a of head) {
1070
1173
  if (a === "--gemini")
1071
1174
  agentFlag = agentFlag ?? "gemini";
1072
1175
  else if (a === "--claude")
@@ -1084,9 +1187,10 @@ function resolveLaunch(passthrough, config = {}) {
1084
1187
  console.error(`imp: unknown agent "${name}" - falling back to claude (valid: ${Object.keys(backends).join(", ")})`);
1085
1188
  backend = claudeBackend;
1086
1189
  }
1087
- const envYolo = "IMPRNT_YOLO" in process.env ? !["0", "false", ""].includes(process.env.IMPRNT_YOLO ?? "") : undefined;
1190
+ const yoloEnv = process.env.IMPRNT_YOLO;
1191
+ const envYolo = yoloEnv === undefined ? undefined : !["0", "false", "", "off", "no"].includes(yoloEnv.toLowerCase());
1088
1192
  const skipPermissions = yoloFlag ?? envYolo ?? config.yolo ?? false;
1089
- return { backend, skipPermissions, passthrough: rest };
1193
+ return { backend, skipPermissions, passthrough: [...rest, ...tail] };
1090
1194
  }
1091
1195
  function launchBackend(backend, cwd, args, env = process.env) {
1092
1196
  if (!isDir(cwd)) {
@@ -1101,7 +1205,7 @@ function launchBackend(backend, cwd, args, env = process.env) {
1101
1205
  }
1102
1206
  return r.status ?? 1;
1103
1207
  }
1104
- var claudeBackend, GEMINI_MODEL_ALIASES, geminiBackend, backends;
1208
+ var claudeBackend, GEMINI_MODEL_ALIASES, geminiTempDirs, geminiCleanupArmed = false, geminiBackend, backends;
1105
1209
  var init_launch = __esm(() => {
1106
1210
  init_plugins();
1107
1211
  init_global();
@@ -1118,10 +1222,12 @@ var init_launch = __esm(() => {
1118
1222
  gemma31: "gemma-4-31b-it",
1119
1223
  gemma26: "gemma-4-26b-a4b-it"
1120
1224
  };
1225
+ geminiTempDirs = new Set;
1121
1226
  geminiBackend = {
1122
1227
  name: "gemini",
1123
1228
  missingHint: "Install the Gemini CLI first: npm i -g @google/gemini-cli",
1124
- renderArgs: geminiRenderArgs
1229
+ renderArgs: geminiRenderArgs,
1230
+ resolveResume: geminiResolveResume
1125
1231
  };
1126
1232
  backends = {
1127
1233
  claude: claudeBackend,
@@ -1164,7 +1270,7 @@ var init_manifest = () => {};
1164
1270
  var exports_ingest = {};
1165
1271
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, mkdirSync as mkdirSync3, existsSync as existsSync9, copyFileSync, readdirSync as readdirSync5, rmSync as rmSync4, statSync as statSync6 } from "node:fs";
1166
1272
  import { createHash } from "node:crypto";
1167
- import { basename as basename2, extname, join as join10, relative as relative3 } from "node:path";
1273
+ import { basename as basename3, extname, join as join10, relative as relative3 } from "node:path";
1168
1274
  function slugify(s) {
1169
1275
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
1170
1276
  }
@@ -1245,7 +1351,7 @@ function applyStaged(staged, vault) {
1245
1351
  return "error";
1246
1352
  }
1247
1353
  const title = text.match(/^#\s+(.+)$/m)?.[1]?.trim() ?? "";
1248
- const slug = deriveSlug([fmScalar2(fm, "slug"), title, basename2(staged, ".md")]);
1354
+ const slug = deriveSlug([fmScalar2(fm, "slug"), title, basename3(staged, ".md")]);
1249
1355
  if (!slug) {
1250
1356
  console.error(` ✗ ${staged}: can't derive a slug - slug:, the H1 title, and the filename all slugify to nothing`);
1251
1357
  return "error";
@@ -1472,7 +1578,7 @@ ${filed} filed, ${noop} no-op, ${conflict} conflict, ${error} error.`);
1472
1578
  console.log(`unchanged (hash ${hash}) — skipping ${src}. note: ${prior.note}`);
1473
1579
  process.exit(0);
1474
1580
  }
1475
- fname = basename2(src);
1581
+ fname = basename3(src);
1476
1582
  dateMatch = fname.match(/(\d{4}-\d{2}-\d{2})/) || text.match(/^\s*date:\s*(\d{4}-\d{2}-\d{2})/im);
1477
1583
  date = dateMatch ? dateMatch[1] : new Date().toISOString().slice(0, 10);
1478
1584
  lines = text.split(/\r?\n/);
@@ -1506,7 +1612,7 @@ ${filed} filed, ${noop} no-op, ${conflict} conflict, ${error} error.`);
1506
1612
  }
1507
1613
  recurringSpeaker = [...turnsBySpeaker.values()].some((n) => n >= 2);
1508
1614
  isTranscript = isFile && looksLikeTranscript(speakers, turnCount, contentLines, recurringSpeaker);
1509
- slugBasis = slugHint || subject || [...speakers].join("-") || (isFile ? basename2(src, extname(src)) : text.slice(0, 60));
1615
+ slugBasis = slugHint || subject || [...speakers].join("-") || (isFile ? basename3(src, extname(src)) : text.slice(0, 60));
1510
1616
  subjectSlug = slugify(slugBasis) || "source";
1511
1617
  noteSlug = `${date}-${subjectSlug}`;
1512
1618
  rawDir = join10(vault, "..", "raw", isTranscript ? "transcripts" : "adhoc");
@@ -1747,7 +1853,7 @@ var init_tags = __esm(() => {
1747
1853
  // scripts/recall.ts
1748
1854
  var exports_recall = {};
1749
1855
  import { lstatSync as lstatSync2, readdirSync as readdirSync6, readFileSync as readFileSync11 } from "node:fs";
1750
- import { basename as basename3, join as join12, relative as relative4 } from "node:path";
1856
+ import { basename as basename4, join as join12, relative as relative4 } from "node:path";
1751
1857
  function walk2(dir2) {
1752
1858
  const out = [];
1753
1859
  for (const entry of readdirSync6(dir2)) {
@@ -1964,7 +2070,7 @@ var init_recall = __esm(() => {
1964
2070
  for (const t of tokens)
1965
2071
  tf.set(t, (tf.get(t) ?? 0) + weight);
1966
2072
  };
1967
- add([...tokenize(titleText), ...tokenize(basename3(path, ".md"))], TITLE_BOOST);
2073
+ add([...tokenize(titleText), ...tokenize(basename4(path, ".md"))], TITLE_BOOST);
1968
2074
  add(tokenize(aliases), TITLE_BOOST);
1969
2075
  add(tags.flatMap(tokenize), TAG_BOOST);
1970
2076
  add(tokenize(summary), SUMMARY_BOOST);
@@ -2029,7 +2135,7 @@ var init_recall = __esm(() => {
2029
2135
  var exports_snapshot = {};
2030
2136
  import { readdirSync as readdirSync7, readFileSync as readFileSync12, copyFileSync as copyFileSync2, mkdirSync as mkdirSync4, existsSync as existsSync11, statSync as statSync7, lstatSync as lstatSync3 } from "node:fs";
2031
2137
  import { createHash as createHash2 } from "node:crypto";
2032
- import { join as join13, relative as relative5, basename as basename4, extname as extname2, resolve as resolve5, sep as sep3 } from "node:path";
2138
+ import { join as join13, relative as relative5, basename as basename5, extname as extname2, resolve as resolve5, sep as sep3 } from "node:path";
2033
2139
  function destWithinRaw(rawRoot, dest) {
2034
2140
  const rootResolved = resolve5(rawRoot);
2035
2141
  const destResolved = resolve5(rootResolved, dest);
@@ -2041,7 +2147,7 @@ function collect(p, base) {
2041
2147
  let skippedLinks = 0;
2042
2148
  const st = statSync7(p);
2043
2149
  if (st.isFile())
2044
- return { files: [{ abs: p, rel: basename4(p) }], skippedLinks };
2150
+ return { files: [{ abs: p, rel: basename5(p) }], skippedLinks };
2045
2151
  const out = [];
2046
2152
  const walk3 = (dir2) => {
2047
2153
  for (const entry of readdirSync7(dir2)) {
@@ -2519,10 +2625,10 @@ all plugin checks passed.`);
2519
2625
  var exports_cli = {};
2520
2626
  import { cpSync as cpSync3, mkdirSync as mkdirSync5, chmodSync, existsSync as existsSync13, readFileSync as readFileSync14, lstatSync as lstatSync4, statSync as statSync9, realpathSync as realpathSync2 } from "node:fs";
2521
2627
  import { spawnSync as spawnSync4 } from "node:child_process";
2522
- import { join as join15, dirname as dirname4, resolve as resolve6, basename as basename5 } from "node:path";
2628
+ import { join as join15, dirname as dirname4, resolve as resolve6, basename as basename6 } from "node:path";
2523
2629
  import { homedir as homedir4 } from "node:os";
2524
2630
  import { fileURLToPath } from "node:url";
2525
- import { createInterface } from "node:readline/promises";
2631
+ import { createInterface as createInterface2 } from "node:readline/promises";
2526
2632
  function pluginRoot() {
2527
2633
  const local = projectRoot();
2528
2634
  if (process.env.IMPRNT_ROOT || process.env.IMPRINT_ROOT)
@@ -2569,7 +2675,7 @@ function physicalTarget(target) {
2569
2675
  const parent = dirname4(existing);
2570
2676
  if (parent === existing)
2571
2677
  return target;
2572
- tail.unshift(basename5(existing));
2678
+ tail.unshift(basename6(existing));
2573
2679
  existing = parent;
2574
2680
  }
2575
2681
  try {
@@ -2647,7 +2753,8 @@ var init_cli = __esm(async () => {
2647
2753
  case "lair": {
2648
2754
  const home = requireVaultHome();
2649
2755
  const { backend, skipPermissions, passthrough } = resolveLaunch(rest, { agent: readDefaultAgent(), yolo: readSkipPermissions() });
2650
- const spec = assembleSession({ cwd: home, vaultProject: home, pkgRoot, passthrough, skipPermissions, model: readDefaultModel() });
2756
+ const resumed = backend.resolveResume ? await backend.resolveResume(passthrough, home) : passthrough;
2757
+ const spec = assembleSession({ cwd: home, vaultProject: home, pkgRoot, passthrough: resumed, skipPermissions, model: readDefaultModel() });
2651
2758
  process.exit(launchBackend(backend, home, backend.renderArgs(spec), spec.env));
2652
2759
  }
2653
2760
  case "context": {
@@ -2670,8 +2777,8 @@ var init_cli = __esm(async () => {
2670
2777
  console.log("set: imprnt agent <claude|gemini> override one session: imp --gemini | imp --claude");
2671
2778
  break;
2672
2779
  }
2673
- if (name !== "claude" && name !== "gemini") {
2674
- console.error(`unknown agent "${name}" — valid: claude, gemini`);
2780
+ if (!(name in backends)) {
2781
+ console.error(`unknown agent "${name}" — valid: ${Object.keys(backends).join(", ")}`);
2675
2782
  process.exit(1);
2676
2783
  }
2677
2784
  const r = setDefaultAgent(name);
@@ -2709,7 +2816,7 @@ var init_cli = __esm(async () => {
2709
2816
  const m = readDefaultModel();
2710
2817
  console.log(`default model: ${m ?? "(agent's own default)"}`);
2711
2818
  console.log("set: imprnt model <alias|id> clear: imprnt model off");
2712
- console.log("gemini aliases: pro=gemini-3.1-pro-preview, flash=gemini-3.5-flash, pro25=gemini-2.5-pro, lite=gemini-3.1-flash-lite, gemma31, gemma26");
2819
+ console.log(`gemini aliases: ${Object.entries(GEMINI_MODEL_ALIASES).map(([k, v]) => `${k}=${v}`).join(", ")}`);
2713
2820
  break;
2714
2821
  }
2715
2822
  if (arg === "off" || arg === "default" || arg === "none") {
@@ -2934,7 +3041,7 @@ enable: imprnt plugin add <name> disable: imprnt plugin rm <name> [--purge]`);
2934
3041
  const inPlace = isVaultProject(process.cwd());
2935
3042
  const display = inPlace ? process.cwd() : "~/imprnt";
2936
3043
  const fallback = inPlace ? process.cwd() : join15(homedir4(), "imprnt");
2937
- const rl = createInterface({ input: process.stdin, output: process.stdout });
3044
+ const rl = createInterface2({ input: process.stdin, output: process.stdout });
2938
3045
  const answer = (await rl.question(`vault location [${display}]: `)).trim();
2939
3046
  rl.close();
2940
3047
  target = answer ? resolvePath(answer) : fallback;
@@ -3046,7 +3153,8 @@ enable: imprnt plugin add <name> disable: imprnt plugin rm <name> [--purge]`);
3046
3153
  }
3047
3154
  const raw = bare ? [] : [cmd, ...rest];
3048
3155
  const { backend, skipPermissions, passthrough } = resolveLaunch(raw, { agent: readDefaultAgent(), yolo: readSkipPermissions() });
3049
- const spec = assembleSession({ cwd: process.cwd(), vaultProject: home, pkgRoot, passthrough, skipPermissions, model: readDefaultModel() });
3156
+ const resumed = backend.resolveResume ? await backend.resolveResume(passthrough, process.cwd()) : passthrough;
3157
+ const spec = assembleSession({ cwd: process.cwd(), vaultProject: home, pkgRoot, passthrough: resumed, skipPermissions, model: readDefaultModel() });
3050
3158
  process.exit(launchBackend(backend, process.cwd(), backend.renderArgs(spec), spec.env));
3051
3159
  }
3052
3160
  console.log(`imprnt — deterministic-first markdown knowledge vault
package/dist/imp.js CHANGED
@@ -766,14 +766,9 @@ function registerVault(path, opts = {}) {
766
766
  const name = opts.name ?? "personal";
767
767
  reg.vaults[name] = path;
768
768
  reg.default = name;
769
- const p = configPath();
770
- try {
771
- mkdirSync2(dirname2(p), { recursive: true });
772
- writeFileSync5(p, JSON.stringify(reg, null, 2) + `
773
- `);
774
- } catch (e) {
775
- return { status: "error", current: path, error: e instanceof Error ? e.message : String(e) };
776
- }
769
+ const w = writeRegistry(reg);
770
+ if (!w.ok)
771
+ return { status: "error", current: path, error: w.error };
777
772
  return { status: "registered", current: path };
778
773
  }
779
774
  function readDefaultAgent() {
@@ -842,8 +837,9 @@ var init_registry = () => {};
842
837
  // scripts/lib/launch.ts
843
838
  import { existsSync as existsSync7, mkdtempSync as mkdtempSync2, readFileSync as readFileSync7, realpathSync, rmSync as rmSync3, statSync as statSync5, writeFileSync as writeFileSync6 } from "node:fs";
844
839
  import { homedir as homedir2, tmpdir as tmpdir2 } from "node:os";
845
- import { isAbsolute, join as join8, resolve as resolve4, sep as sep2 } from "node:path";
840
+ import { basename as basename2, isAbsolute, join as join8, resolve as resolve4, sep as sep2 } from "node:path";
846
841
  import { spawnSync as spawnSync2 } from "node:child_process";
842
+ import { createInterface } from "node:readline/promises";
847
843
  function importPath(root, target) {
848
844
  if (target.startsWith("~/"))
849
845
  return join8(homedir2(), target.slice(2));
@@ -1013,7 +1009,12 @@ function claudeRenderArgs(spec) {
1013
1009
  const systemPrompt = spec.insideProject ? spec.globals : joinFragments([spec.cast, spec.pointer, spec.globals]);
1014
1010
  const harness = spec.pluginsRoot ? harnessFlags(spec.pluginsRoot) : [];
1015
1011
  const extra = spec.addDirs.flatMap((d) => ["--add-dir", d]);
1016
- const pass = spec.skipPermissions && !spec.passthrough.includes("--dangerously-skip-permissions") ? ["--dangerously-skip-permissions", ...spec.passthrough] : spec.passthrough;
1012
+ const lead = [];
1013
+ if (spec.skipPermissions && !spec.passthrough.includes("--dangerously-skip-permissions"))
1014
+ lead.push("--dangerously-skip-permissions");
1015
+ if (spec.model && !spec.passthrough.some((a) => a === "--model" || a.startsWith("--model=")))
1016
+ lead.push("--model", spec.model);
1017
+ const pass = lead.length ? [...lead, ...spec.passthrough] : spec.passthrough;
1017
1018
  const body = systemPrompt ? mergeFragment(pass, systemPrompt, extra) : [...pass, ...extra];
1018
1019
  return [...harness, ...body];
1019
1020
  }
@@ -1023,6 +1024,19 @@ function expandGeminiModel(m) {
1023
1024
  function escapeGeminiImports(text) {
1024
1025
  return text.replaceAll("@", "\\@");
1025
1026
  }
1027
+ function trackGeminiTempDir(dir) {
1028
+ geminiTempDirs.add(dir);
1029
+ if (geminiCleanupArmed)
1030
+ return;
1031
+ geminiCleanupArmed = true;
1032
+ process.on("exit", () => {
1033
+ for (const d of geminiTempDirs) {
1034
+ try {
1035
+ rmSync3(d, { recursive: true, force: true });
1036
+ } catch {}
1037
+ }
1038
+ });
1039
+ }
1026
1040
  function geminiRenderArgs(spec) {
1027
1041
  const includes = [];
1028
1042
  const systemPrompt = joinFragments([spec.cast, spec.pointer, spec.globals]);
@@ -1030,11 +1044,7 @@ function geminiRenderArgs(spec) {
1030
1044
  const dir = mkdtempSync2(join8(tmpdir2(), "imprnt-gemini-"));
1031
1045
  writeFileSync6(join8(dir, "GEMINI.md"), escapeGeminiImports(systemPrompt) + `
1032
1046
  `);
1033
- process.on("exit", () => {
1034
- try {
1035
- rmSync3(dir, { recursive: true, force: true });
1036
- } catch {}
1037
- });
1047
+ trackGeminiTempDir(dir);
1038
1048
  includes.push(dir);
1039
1049
  }
1040
1050
  includes.push(...spec.addDirs);
@@ -1049,24 +1059,117 @@ function geminiRenderArgs(spec) {
1049
1059
  lead.push("--skip-trust");
1050
1060
  }
1051
1061
  const pass = [...spec.passthrough];
1052
- const mIdx = pass.findIndex((a) => a === "-m" || a === "--model");
1053
- if (mIdx >= 0 && pass[mIdx + 1] !== undefined) {
1054
- pass[mIdx + 1] = expandGeminiModel(pass[mIdx + 1]);
1055
- } else if (mIdx < 0 && spec.model) {
1062
+ const mTerm = pass.indexOf("--");
1063
+ const mEnd = mTerm < 0 ? pass.length : mTerm;
1064
+ const isModelFlag = (a) => a === "-m" || a === "--model" || a.startsWith("-m=") || a.startsWith("--model=");
1065
+ const mIdx = pass.slice(0, mEnd).findIndex(isModelFlag);
1066
+ if (mIdx >= 0) {
1067
+ const tok = pass[mIdx];
1068
+ const eq = tok.indexOf("=");
1069
+ if (eq >= 0)
1070
+ pass[mIdx] = tok.slice(0, eq + 1) + expandGeminiModel(tok.slice(eq + 1));
1071
+ else if (mIdx + 1 < mEnd && pass[mIdx + 1] !== undefined)
1072
+ pass[mIdx + 1] = expandGeminiModel(pass[mIdx + 1]);
1073
+ } else if (spec.model) {
1056
1074
  pass.unshift("-m", expandGeminiModel(spec.model));
1057
1075
  }
1058
- const rIdx = pass.findIndex((a) => a === "-r" || a === "--resume");
1059
- if (rIdx >= 0 && (pass[rIdx + 1] === undefined || pass[rIdx + 1].startsWith("-"))) {
1076
+ const rIdx = valuelessResumeIndex(pass);
1077
+ if (rIdx >= 0)
1060
1078
  pass.splice(rIdx + 1, 0, "latest");
1061
- }
1062
1079
  const flags = includes.length ? ["--include-directories", includes.join(",")] : [];
1063
1080
  return [...lead, ...flags, ...pass];
1064
1081
  }
1082
+ function parseGeminiSessions(stdout) {
1083
+ const out = [];
1084
+ for (const raw of stdout.split(/\r?\n/)) {
1085
+ const m = raw.match(/^\s*(\d+)\.\s+(.+?)\s+\(([^()]+)\)\s+\[([0-9a-fA-F-]{8,})\]\s*$/);
1086
+ if (m)
1087
+ out.push({ index: Number(m[1]), name: m[2].trim(), age: m[3].trim(), id: m[4] });
1088
+ }
1089
+ return out;
1090
+ }
1091
+ function valuelessResumeIndex(args) {
1092
+ const term = args.indexOf("--");
1093
+ const end = term < 0 ? args.length : term;
1094
+ let i = -1;
1095
+ for (let k = 0;k < end; k++) {
1096
+ if (args[k] === "-r" || args[k] === "--resume") {
1097
+ i = k;
1098
+ break;
1099
+ }
1100
+ }
1101
+ if (i < 0)
1102
+ return -1;
1103
+ const next = i + 1 < end ? args[i + 1] : undefined;
1104
+ return next === undefined || next.startsWith("-") ? i : -1;
1105
+ }
1106
+ function listGeminiSessions(cwd) {
1107
+ const r = spawnSync2("gemini", ["--list-sessions", "--skip-trust"], { cwd, encoding: "utf8" });
1108
+ if (r.error || r.status !== 0)
1109
+ return { sessions: [], ran: false };
1110
+ const stdout = r.stdout || "";
1111
+ const sessions = parseGeminiSessions(stdout);
1112
+ if (!sessions.length && stdout.trim() && !/\(\s*0\s*\)|no sessions/i.test(stdout)) {
1113
+ console.error("imp: couldn't parse gemini's session list (its format may have changed) - starting fresh");
1114
+ }
1115
+ return { sessions, ran: true };
1116
+ }
1117
+ async function pickGeminiSession(sessions, label) {
1118
+ const cols = process.stdout.columns || 80;
1119
+ const nameW = Math.max(20, Math.min(64, cols - 16));
1120
+ const trunc = (s) => s.length > nameW ? s.slice(0, nameW - 1) + "…" : s;
1121
+ process.stderr.write(`
1122
+ resume a chat - gemini · ${label}
1123
+
1124
+ `);
1125
+ sessions.forEach((s, i) => {
1126
+ process.stderr.write(` ${String(i + 1).padStart(2)} ${trunc(s.name).padEnd(nameW)} ${s.age.replace(/\s*ago$/, "")}
1127
+ `);
1128
+ });
1129
+ process.stderr.write(`
1130
+ `);
1131
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
1132
+ const answer = (await rl.question(" number to resume · enter for newest · q to cancel › ")).trim();
1133
+ rl.close();
1134
+ if (answer === "")
1135
+ return "latest";
1136
+ if (answer.toLowerCase() === "q")
1137
+ return null;
1138
+ const n = Number(answer);
1139
+ if (Number.isInteger(n) && n >= 1 && n <= sessions.length)
1140
+ return sessions[n - 1].id;
1141
+ process.stderr.write(` not a valid choice - starting a fresh session
1142
+ `);
1143
+ return null;
1144
+ }
1145
+ async function geminiResolveResume(passthrough, cwd) {
1146
+ const rIdx = valuelessResumeIndex(passthrough);
1147
+ if (rIdx < 0)
1148
+ return passthrough;
1149
+ if (!(process.stdin.isTTY && process.stdout.isTTY))
1150
+ return passthrough;
1151
+ const { sessions, ran } = listGeminiSessions(cwd);
1152
+ if (!ran)
1153
+ return passthrough;
1154
+ if (!sessions.length) {
1155
+ console.error("imp: no saved gemini chats for this project yet - starting fresh");
1156
+ return passthrough.filter((_, i) => i !== rIdx);
1157
+ }
1158
+ const chosen = await pickGeminiSession(sessions, basename2(cwd));
1159
+ if (chosen === null)
1160
+ return passthrough.filter((_, i) => i !== rIdx);
1161
+ const out = [...passthrough];
1162
+ out.splice(rIdx + 1, 0, chosen);
1163
+ return out;
1164
+ }
1065
1165
  function resolveLaunch(passthrough, config = {}) {
1166
+ const term = passthrough.indexOf("--");
1167
+ const head = term < 0 ? passthrough : passthrough.slice(0, term);
1168
+ const tail = term < 0 ? [] : passthrough.slice(term);
1066
1169
  let agentFlag;
1067
1170
  let yoloFlag;
1068
1171
  const rest = [];
1069
- for (const a of passthrough) {
1172
+ for (const a of head) {
1070
1173
  if (a === "--gemini")
1071
1174
  agentFlag = agentFlag ?? "gemini";
1072
1175
  else if (a === "--claude")
@@ -1084,9 +1187,10 @@ function resolveLaunch(passthrough, config = {}) {
1084
1187
  console.error(`imp: unknown agent "${name}" - falling back to claude (valid: ${Object.keys(backends).join(", ")})`);
1085
1188
  backend = claudeBackend;
1086
1189
  }
1087
- const envYolo = "IMPRNT_YOLO" in process.env ? !["0", "false", ""].includes(process.env.IMPRNT_YOLO ?? "") : undefined;
1190
+ const yoloEnv = process.env.IMPRNT_YOLO;
1191
+ const envYolo = yoloEnv === undefined ? undefined : !["0", "false", "", "off", "no"].includes(yoloEnv.toLowerCase());
1088
1192
  const skipPermissions = yoloFlag ?? envYolo ?? config.yolo ?? false;
1089
- return { backend, skipPermissions, passthrough: rest };
1193
+ return { backend, skipPermissions, passthrough: [...rest, ...tail] };
1090
1194
  }
1091
1195
  function launchBackend(backend, cwd, args, env = process.env) {
1092
1196
  if (!isDir(cwd)) {
@@ -1101,7 +1205,7 @@ function launchBackend(backend, cwd, args, env = process.env) {
1101
1205
  }
1102
1206
  return r.status ?? 1;
1103
1207
  }
1104
- var claudeBackend, GEMINI_MODEL_ALIASES, geminiBackend, backends;
1208
+ var claudeBackend, GEMINI_MODEL_ALIASES, geminiTempDirs, geminiCleanupArmed = false, geminiBackend, backends;
1105
1209
  var init_launch = __esm(() => {
1106
1210
  init_plugins();
1107
1211
  init_global();
@@ -1118,10 +1222,12 @@ var init_launch = __esm(() => {
1118
1222
  gemma31: "gemma-4-31b-it",
1119
1223
  gemma26: "gemma-4-26b-a4b-it"
1120
1224
  };
1225
+ geminiTempDirs = new Set;
1121
1226
  geminiBackend = {
1122
1227
  name: "gemini",
1123
1228
  missingHint: "Install the Gemini CLI first: npm i -g @google/gemini-cli",
1124
- renderArgs: geminiRenderArgs
1229
+ renderArgs: geminiRenderArgs,
1230
+ resolveResume: geminiResolveResume
1125
1231
  };
1126
1232
  backends = {
1127
1233
  claude: claudeBackend,
@@ -1164,7 +1270,7 @@ var init_manifest = () => {};
1164
1270
  var exports_ingest = {};
1165
1271
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, mkdirSync as mkdirSync3, existsSync as existsSync9, copyFileSync, readdirSync as readdirSync5, rmSync as rmSync4, statSync as statSync6 } from "node:fs";
1166
1272
  import { createHash } from "node:crypto";
1167
- import { basename as basename2, extname, join as join10, relative as relative3 } from "node:path";
1273
+ import { basename as basename3, extname, join as join10, relative as relative3 } from "node:path";
1168
1274
  function slugify(s) {
1169
1275
  return s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
1170
1276
  }
@@ -1245,7 +1351,7 @@ function applyStaged(staged, vault) {
1245
1351
  return "error";
1246
1352
  }
1247
1353
  const title = text.match(/^#\s+(.+)$/m)?.[1]?.trim() ?? "";
1248
- const slug = deriveSlug([fmScalar2(fm, "slug"), title, basename2(staged, ".md")]);
1354
+ const slug = deriveSlug([fmScalar2(fm, "slug"), title, basename3(staged, ".md")]);
1249
1355
  if (!slug) {
1250
1356
  console.error(` ✗ ${staged}: can't derive a slug - slug:, the H1 title, and the filename all slugify to nothing`);
1251
1357
  return "error";
@@ -1472,7 +1578,7 @@ ${filed} filed, ${noop} no-op, ${conflict} conflict, ${error} error.`);
1472
1578
  console.log(`unchanged (hash ${hash}) — skipping ${src}. note: ${prior.note}`);
1473
1579
  process.exit(0);
1474
1580
  }
1475
- fname = basename2(src);
1581
+ fname = basename3(src);
1476
1582
  dateMatch = fname.match(/(\d{4}-\d{2}-\d{2})/) || text.match(/^\s*date:\s*(\d{4}-\d{2}-\d{2})/im);
1477
1583
  date = dateMatch ? dateMatch[1] : new Date().toISOString().slice(0, 10);
1478
1584
  lines = text.split(/\r?\n/);
@@ -1506,7 +1612,7 @@ ${filed} filed, ${noop} no-op, ${conflict} conflict, ${error} error.`);
1506
1612
  }
1507
1613
  recurringSpeaker = [...turnsBySpeaker.values()].some((n) => n >= 2);
1508
1614
  isTranscript = isFile && looksLikeTranscript(speakers, turnCount, contentLines, recurringSpeaker);
1509
- slugBasis = slugHint || subject || [...speakers].join("-") || (isFile ? basename2(src, extname(src)) : text.slice(0, 60));
1615
+ slugBasis = slugHint || subject || [...speakers].join("-") || (isFile ? basename3(src, extname(src)) : text.slice(0, 60));
1510
1616
  subjectSlug = slugify(slugBasis) || "source";
1511
1617
  noteSlug = `${date}-${subjectSlug}`;
1512
1618
  rawDir = join10(vault, "..", "raw", isTranscript ? "transcripts" : "adhoc");
@@ -1747,7 +1853,7 @@ var init_tags = __esm(() => {
1747
1853
  // scripts/recall.ts
1748
1854
  var exports_recall = {};
1749
1855
  import { lstatSync as lstatSync2, readdirSync as readdirSync6, readFileSync as readFileSync11 } from "node:fs";
1750
- import { basename as basename3, join as join12, relative as relative4 } from "node:path";
1856
+ import { basename as basename4, join as join12, relative as relative4 } from "node:path";
1751
1857
  function walk2(dir2) {
1752
1858
  const out = [];
1753
1859
  for (const entry of readdirSync6(dir2)) {
@@ -1964,7 +2070,7 @@ var init_recall = __esm(() => {
1964
2070
  for (const t of tokens)
1965
2071
  tf.set(t, (tf.get(t) ?? 0) + weight);
1966
2072
  };
1967
- add([...tokenize(titleText), ...tokenize(basename3(path, ".md"))], TITLE_BOOST);
2073
+ add([...tokenize(titleText), ...tokenize(basename4(path, ".md"))], TITLE_BOOST);
1968
2074
  add(tokenize(aliases), TITLE_BOOST);
1969
2075
  add(tags.flatMap(tokenize), TAG_BOOST);
1970
2076
  add(tokenize(summary), SUMMARY_BOOST);
@@ -2029,7 +2135,7 @@ var init_recall = __esm(() => {
2029
2135
  var exports_snapshot = {};
2030
2136
  import { readdirSync as readdirSync7, readFileSync as readFileSync12, copyFileSync as copyFileSync2, mkdirSync as mkdirSync4, existsSync as existsSync11, statSync as statSync7, lstatSync as lstatSync3 } from "node:fs";
2031
2137
  import { createHash as createHash2 } from "node:crypto";
2032
- import { join as join13, relative as relative5, basename as basename4, extname as extname2, resolve as resolve5, sep as sep3 } from "node:path";
2138
+ import { join as join13, relative as relative5, basename as basename5, extname as extname2, resolve as resolve5, sep as sep3 } from "node:path";
2033
2139
  function destWithinRaw(rawRoot, dest) {
2034
2140
  const rootResolved = resolve5(rawRoot);
2035
2141
  const destResolved = resolve5(rootResolved, dest);
@@ -2041,7 +2147,7 @@ function collect(p, base) {
2041
2147
  let skippedLinks = 0;
2042
2148
  const st = statSync7(p);
2043
2149
  if (st.isFile())
2044
- return { files: [{ abs: p, rel: basename4(p) }], skippedLinks };
2150
+ return { files: [{ abs: p, rel: basename5(p) }], skippedLinks };
2045
2151
  const out = [];
2046
2152
  const walk3 = (dir2) => {
2047
2153
  for (const entry of readdirSync7(dir2)) {
@@ -2519,10 +2625,10 @@ all plugin checks passed.`);
2519
2625
  var exports_cli = {};
2520
2626
  import { cpSync as cpSync3, mkdirSync as mkdirSync5, chmodSync, existsSync as existsSync13, readFileSync as readFileSync14, lstatSync as lstatSync4, statSync as statSync9, realpathSync as realpathSync2 } from "node:fs";
2521
2627
  import { spawnSync as spawnSync4 } from "node:child_process";
2522
- import { join as join15, dirname as dirname4, resolve as resolve6, basename as basename5 } from "node:path";
2628
+ import { join as join15, dirname as dirname4, resolve as resolve6, basename as basename6 } from "node:path";
2523
2629
  import { homedir as homedir4 } from "node:os";
2524
2630
  import { fileURLToPath } from "node:url";
2525
- import { createInterface } from "node:readline/promises";
2631
+ import { createInterface as createInterface2 } from "node:readline/promises";
2526
2632
  function pluginRoot() {
2527
2633
  const local = projectRoot();
2528
2634
  if (process.env.IMPRNT_ROOT || process.env.IMPRINT_ROOT)
@@ -2569,7 +2675,7 @@ function physicalTarget(target) {
2569
2675
  const parent = dirname4(existing);
2570
2676
  if (parent === existing)
2571
2677
  return target;
2572
- tail.unshift(basename5(existing));
2678
+ tail.unshift(basename6(existing));
2573
2679
  existing = parent;
2574
2680
  }
2575
2681
  try {
@@ -2647,7 +2753,8 @@ var init_cli = __esm(async () => {
2647
2753
  case "lair": {
2648
2754
  const home = requireVaultHome();
2649
2755
  const { backend, skipPermissions, passthrough } = resolveLaunch(rest, { agent: readDefaultAgent(), yolo: readSkipPermissions() });
2650
- const spec = assembleSession({ cwd: home, vaultProject: home, pkgRoot, passthrough, skipPermissions, model: readDefaultModel() });
2756
+ const resumed = backend.resolveResume ? await backend.resolveResume(passthrough, home) : passthrough;
2757
+ const spec = assembleSession({ cwd: home, vaultProject: home, pkgRoot, passthrough: resumed, skipPermissions, model: readDefaultModel() });
2651
2758
  process.exit(launchBackend(backend, home, backend.renderArgs(spec), spec.env));
2652
2759
  }
2653
2760
  case "context": {
@@ -2670,8 +2777,8 @@ var init_cli = __esm(async () => {
2670
2777
  console.log("set: imprnt agent <claude|gemini> override one session: imp --gemini | imp --claude");
2671
2778
  break;
2672
2779
  }
2673
- if (name !== "claude" && name !== "gemini") {
2674
- console.error(`unknown agent "${name}" — valid: claude, gemini`);
2780
+ if (!(name in backends)) {
2781
+ console.error(`unknown agent "${name}" — valid: ${Object.keys(backends).join(", ")}`);
2675
2782
  process.exit(1);
2676
2783
  }
2677
2784
  const r = setDefaultAgent(name);
@@ -2709,7 +2816,7 @@ var init_cli = __esm(async () => {
2709
2816
  const m = readDefaultModel();
2710
2817
  console.log(`default model: ${m ?? "(agent's own default)"}`);
2711
2818
  console.log("set: imprnt model <alias|id> clear: imprnt model off");
2712
- console.log("gemini aliases: pro=gemini-3.1-pro-preview, flash=gemini-3.5-flash, pro25=gemini-2.5-pro, lite=gemini-3.1-flash-lite, gemma31, gemma26");
2819
+ console.log(`gemini aliases: ${Object.entries(GEMINI_MODEL_ALIASES).map(([k, v]) => `${k}=${v}`).join(", ")}`);
2713
2820
  break;
2714
2821
  }
2715
2822
  if (arg === "off" || arg === "default" || arg === "none") {
@@ -2934,7 +3041,7 @@ enable: imprnt plugin add <name> disable: imprnt plugin rm <name> [--purge]`);
2934
3041
  const inPlace = isVaultProject(process.cwd());
2935
3042
  const display = inPlace ? process.cwd() : "~/imprnt";
2936
3043
  const fallback = inPlace ? process.cwd() : join15(homedir4(), "imprnt");
2937
- const rl = createInterface({ input: process.stdin, output: process.stdout });
3044
+ const rl = createInterface2({ input: process.stdin, output: process.stdout });
2938
3045
  const answer = (await rl.question(`vault location [${display}]: `)).trim();
2939
3046
  rl.close();
2940
3047
  target = answer ? resolvePath(answer) : fallback;
@@ -3046,7 +3153,8 @@ enable: imprnt plugin add <name> disable: imprnt plugin rm <name> [--purge]`);
3046
3153
  }
3047
3154
  const raw = bare ? [] : [cmd, ...rest];
3048
3155
  const { backend, skipPermissions, passthrough } = resolveLaunch(raw, { agent: readDefaultAgent(), yolo: readSkipPermissions() });
3049
- const spec = assembleSession({ cwd: process.cwd(), vaultProject: home, pkgRoot, passthrough, skipPermissions, model: readDefaultModel() });
3156
+ const resumed = backend.resolveResume ? await backend.resolveResume(passthrough, process.cwd()) : passthrough;
3157
+ const spec = assembleSession({ cwd: process.cwd(), vaultProject: home, pkgRoot, passthrough: resumed, skipPermissions, model: readDefaultModel() });
3050
3158
  process.exit(launchBackend(backend, process.cwd(), backend.renderArgs(spec), spec.env));
3051
3159
  }
3052
3160
  console.log(`imprnt — deterministic-first markdown knowledge vault
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "imprnt",
3
- "version": "0.1.3-edge.59",
3
+ "version": "0.1.3-edge.61",
4
4
  "description": "Deterministic-first, plain-markdown knowledge vault. Code does the bulk transform. The LLM only touches the irreducibly-semantic 20%. Native grep plus BM25 retrieval, zero MCP on the vault.",
5
5
  "type": "module",
6
6
  "bin": {