@djolex999/vir-cli 0.23.3 → 0.24.2

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 (54) hide show
  1. package/README.md +3 -2
  2. package/dist/claude/updater.js +24 -4
  3. package/dist/claude/updater.js.map +1 -1
  4. package/dist/cli/audit.js +136 -0
  5. package/dist/cli/audit.js.map +1 -0
  6. package/dist/cli/compose.js +101 -0
  7. package/dist/cli/compose.js.map +1 -0
  8. package/dist/cli/costLabel.js +14 -0
  9. package/dist/cli/costLabel.js.map +1 -0
  10. package/dist/cli/dedupe.js +92 -0
  11. package/dist/cli/dedupe.js.map +1 -0
  12. package/dist/cli/embed.js +183 -0
  13. package/dist/cli/embed.js.map +1 -0
  14. package/dist/cli/guards.js +40 -0
  15. package/dist/cli/guards.js.map +1 -0
  16. package/dist/cli/init.js +361 -0
  17. package/dist/cli/init.js.map +1 -0
  18. package/dist/cli/lint.js +160 -0
  19. package/dist/cli/lint.js.map +1 -0
  20. package/dist/cli/reconcile.js +110 -62
  21. package/dist/cli/reconcile.js.map +1 -1
  22. package/dist/cli/review.js +26 -5
  23. package/dist/cli/review.js.map +1 -1
  24. package/dist/cli/summarize.js +148 -0
  25. package/dist/cli/summarize.js.map +1 -0
  26. package/dist/cli.js +36 -1100
  27. package/dist/cli.js.map +1 -1
  28. package/dist/config.js +12 -6
  29. package/dist/config.js.map +1 -1
  30. package/dist/cost/report.js +5 -2
  31. package/dist/cost/report.js.map +1 -1
  32. package/dist/diagnostics/doctor.js +23 -0
  33. package/dist/diagnostics/doctor.js.map +1 -1
  34. package/dist/mcp/server.js +40 -28
  35. package/dist/mcp/server.js.map +1 -1
  36. package/dist/pipeline/claudeCli.js +41 -5
  37. package/dist/pipeline/claudeCli.js.map +1 -1
  38. package/dist/pipeline/composer.js +1 -0
  39. package/dist/pipeline/composer.js.map +1 -1
  40. package/dist/pipeline/distillSession.js +96 -0
  41. package/dist/pipeline/distillSession.js.map +1 -0
  42. package/dist/pipeline/distiller.js +12 -5
  43. package/dist/pipeline/distiller.js.map +1 -1
  44. package/dist/pipeline/embeddingSweep.js +9 -5
  45. package/dist/pipeline/embeddingSweep.js.map +1 -1
  46. package/dist/pipeline/run.js +53 -73
  47. package/dist/pipeline/run.js.map +1 -1
  48. package/dist/pipeline/scrubber.js +4 -4
  49. package/dist/pipeline/scrubber.js.map +1 -1
  50. package/dist/pipeline/writer.js +83 -10
  51. package/dist/pipeline/writer.js.map +1 -1
  52. package/dist/state/db.js +8 -8
  53. package/dist/state/db.js.map +1 -1
  54. package/package.json +2 -1
@@ -0,0 +1,183 @@
1
+ import { createInterface } from "node:readline/promises";
2
+ import { stdin, stdout } from "node:process";
3
+ import { join } from "node:path";
4
+ import { loadConfig } from "../config.js";
5
+ import { embedNoteWithProvider, resolveEmbeddingProvider, } from "../search/provider.js";
6
+ import { runEmbedSetup } from "./embedSetup.js";
7
+ import { StateDb } from "../state/db.js";
8
+ import * as ui from "../ui/display.js";
9
+ import { VaultWriter } from "../pipeline/writer.js";
10
+ export async function embedCommand(opts) {
11
+ if (opts.setup) {
12
+ await runEmbedSetup(opts.yes === true);
13
+ return;
14
+ }
15
+ const cfg = loadConfig();
16
+ ui.header("embed");
17
+ ui.blank();
18
+ const provider = await resolveEmbeddingProvider(cfg.embeddingProvider);
19
+ if (!provider) {
20
+ ui.row(ui.errorColor(ui.CROSS), ui.text("no embedding provider available"));
21
+ ui.line(ui.dim(" vir embed --setup # local provider, no Ollama needed (~233 MB)"));
22
+ ui.line(ui.dim(" or: brew install ollama && ollama pull nomic-embed-text && ollama serve"));
23
+ process.exitCode = 1;
24
+ return;
25
+ }
26
+ const provenance = provider.provenance();
27
+ const db = new StateDb();
28
+ try {
29
+ // Same text the writer embeds (note file minus generated sections),
30
+ // falling back to stored content when a file is gone.
31
+ const text = new VaultWriter(cfg, db).embeddingText;
32
+ const rows = db.listDistilled();
33
+ const root = join(cfg.vaultPath, cfg.outputDir);
34
+ const embeddedRows = [
35
+ ...db.getEmbeddings(root),
36
+ ...db.getArticleEmbeddings(),
37
+ ...db.getTopicEmbeddings(root, cfg.topicsDir),
38
+ ...db.getPdfEmbeddings(),
39
+ ];
40
+ // Crossing a model boundary is an index invalidation, not a gap fill —
41
+ // it needs --force AND explicit consent, with the cost stated first.
42
+ // Without --force, mismatched rows stay excluded from vector search
43
+ // (counted, reported) and only NULL-embedding gaps are filled.
44
+ const mismatched = embeddedRows.filter((r) => r.embeddingModel !== provider.modelName).length;
45
+ if (mismatched > 0 && !opts.force) {
46
+ ui.row(ui.warn(ui.WARN_GLYPH), ui.text(`${mismatched} note(s) are embedded under a different model than the active one (${provider.modelName})`));
47
+ ui.line(ui.dim("they are excluded from vector search until re-embedded"));
48
+ ui.line(ui.dim("run `vir embed --force` to re-embed the whole index"));
49
+ }
50
+ if (mismatched > 0 && opts.force) {
51
+ const estSecs = Math.max(1, Math.round(rows.length * 0.15));
52
+ ui.row(ui.warn(ui.WARN_GLYPH), ui.text(`model boundary: re-embedding ${rows.length} note(s) under ${provider.modelName} (~${estSecs}s), replacing vectors from other models`));
53
+ if (!opts.yes) {
54
+ const rl = createInterface({ input: stdin, output: stdout });
55
+ const answer = (await rl.question("Proceed? [y/N] ")).trim().toLowerCase();
56
+ rl.close();
57
+ if (answer !== "y" && answer !== "yes") {
58
+ ui.line(ui.dim("aborted — index unchanged"));
59
+ return;
60
+ }
61
+ }
62
+ }
63
+ const existing = new Set(db
64
+ .getEmbeddings(root)
65
+ .filter((r) => r.embeddingModel === provider.modelName)
66
+ .map((r) => r.sessionId));
67
+ const target = opts.force
68
+ ? rows
69
+ : rows.filter((r) => !existing.has(r.sessionId));
70
+ // Topics live in their own table, so backfill them here too — a compose
71
+ // while Ollama was down heals on a manual `vir embed`, not only the next
72
+ // `vir run` sweep. --force re-embeds all topics; otherwise just NULL ones.
73
+ const topicTargets = opts.force
74
+ ? db.listTopics().map((t) => ({ id: t.id, content: t.content }))
75
+ : db.listTopicEmbeddingTargets();
76
+ // Articles live in their own table too — back-fill them here so a clip
77
+ // distilled while Ollama was down heals on a manual `vir embed`, not only
78
+ // the next `vir run` sweep. --force re-embeds all embeddable articles
79
+ // (keyed by source path); otherwise just the NULL-embedding ones.
80
+ const articleTargets = opts.force
81
+ ? db.listArticles().map((a) => ({
82
+ path: a.path,
83
+ notePath: a.notePath,
84
+ content: a.content,
85
+ }))
86
+ : db.listArticleEmbeddingTargets();
87
+ // PDFs live in their own table too — same back-fill rationale as articles.
88
+ const pdfTargets = opts.force
89
+ ? db.listPdfs().map((p) => ({
90
+ path: p.path,
91
+ notePath: p.notePath,
92
+ content: p.content,
93
+ }))
94
+ : db.listPdfEmbeddingTargets();
95
+ const total = target.length +
96
+ topicTargets.length +
97
+ articleTargets.length +
98
+ pdfTargets.length;
99
+ if (total === 0) {
100
+ ui.row(ui.success(ui.CHECK), ui.text("all notes already embedded"));
101
+ return;
102
+ }
103
+ const sp = ui.spinner(`embedding notes (0/${total})`).start();
104
+ let embedded = 0;
105
+ let skipped = 0;
106
+ let errors = 0;
107
+ for (let i = 0; i < target.length; i += 1) {
108
+ const r = target[i];
109
+ if (!r)
110
+ continue;
111
+ if (r.content.trim().length === 0) {
112
+ skipped += 1;
113
+ continue;
114
+ }
115
+ const vec = await embedNoteWithProvider(provider, text.session(r.sessionId) ?? r.content);
116
+ if (!vec) {
117
+ errors += 1;
118
+ continue;
119
+ }
120
+ db.storeEmbedding(r.sessionId, vec, provenance);
121
+ embedded += 1;
122
+ sp.text = ui.dim(`embedding notes (${embedded}/${total})`);
123
+ }
124
+ for (const t of topicTargets) {
125
+ if (!t.content || t.content.trim().length === 0) {
126
+ skipped += 1;
127
+ continue;
128
+ }
129
+ const vec = await embedNoteWithProvider(provider, text.topic(t.id) ?? t.content);
130
+ if (!vec) {
131
+ errors += 1;
132
+ continue;
133
+ }
134
+ db.storeTopicEmbedding(t.id, vec, provenance);
135
+ embedded += 1;
136
+ sp.text = ui.dim(`embedding notes (${embedded}/${total})`);
137
+ }
138
+ for (const a of articleTargets) {
139
+ if (!a.content || a.content.trim().length === 0) {
140
+ skipped += 1;
141
+ continue;
142
+ }
143
+ const vec = await embedNoteWithProvider(provider, (a.notePath ? text.file(a.notePath) : null) ?? a.content);
144
+ if (!vec) {
145
+ errors += 1;
146
+ continue;
147
+ }
148
+ db.storeArticleEmbedding(a.path, vec, provenance);
149
+ embedded += 1;
150
+ sp.text = ui.dim(`embedding notes (${embedded}/${total})`);
151
+ }
152
+ for (const p of pdfTargets) {
153
+ if (!p.content || p.content.trim().length === 0) {
154
+ skipped += 1;
155
+ continue;
156
+ }
157
+ const vec = await embedNoteWithProvider(provider, (p.notePath ? text.file(p.notePath) : null) ?? p.content);
158
+ if (!vec) {
159
+ errors += 1;
160
+ continue;
161
+ }
162
+ db.storePdfEmbedding(p.path, vec, provenance);
163
+ embedded += 1;
164
+ sp.text = ui.dim(`embedding notes (${embedded}/${total})`);
165
+ }
166
+ sp.succeed(ui.text(`embedded ${embedded} notes`));
167
+ ui.blank();
168
+ ui.divider();
169
+ ui.summary({
170
+ embedded: { value: embedded, color: ui.success },
171
+ skipped: { value: skipped, color: ui.muted },
172
+ errors: {
173
+ value: errors,
174
+ color: errors > 0 ? ui.errorColor : ui.dim,
175
+ },
176
+ });
177
+ ui.divider();
178
+ }
179
+ finally {
180
+ db.close();
181
+ }
182
+ }
183
+ //# sourceMappingURL=embed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embed.js","sourceRoot":"","sources":["../../src/cli/embed.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import confirm from "@inquirer/confirm";
2
+ import { acquireLock, LOCK_PATH, LockHeldError, releaseLock, } from "../pipeline/lock.js";
3
+ import * as ui from "../ui/display.js";
4
+ // Runs a command that writes notes or the DB while holding the pipeline lock,
5
+ // so it cannot race a daemon `vir run`. A held lock is reported and exits 1,
6
+ // the same as `vir run` and `vir reconcile`.
7
+ export async function withPipelineLock(fn, lockPath = LOCK_PATH) {
8
+ try {
9
+ acquireLock(lockPath);
10
+ }
11
+ catch (err) {
12
+ if (err instanceof LockHeldError) {
13
+ ui.row(ui.warn(ui.WARN_GLYPH), ui.text(err.message));
14
+ process.exitCode = 1;
15
+ return;
16
+ }
17
+ throw err;
18
+ }
19
+ try {
20
+ await fn();
21
+ }
22
+ finally {
23
+ releaseLock(lockPath);
24
+ }
25
+ }
26
+ // Gate for a paid LLM step. --yes proceeds; a terminal asks; with no terminal
27
+ // (cron, scripts) the step is skipped with a note rather than hanging on a
28
+ // prompt or spending without consent.
29
+ export async function confirmPaidStep(message, opts = {}) {
30
+ if (opts.yes === true)
31
+ return true;
32
+ const interactive = opts.interactive ?? process.stdin.isTTY === true;
33
+ if (!interactive) {
34
+ ui.line(ui.dim(` skipped: ${message} (pass --yes to run without a prompt)`));
35
+ return false;
36
+ }
37
+ const ask = opts.ask ?? ((m) => confirm({ message: m, default: true }));
38
+ return ask(message);
39
+ }
40
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/cli/guards.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,mBAAmB,CAAC;AACxC,OAAO,EACL,WAAW,EACX,SAAS,EACT,aAAa,EACb,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAEvC,8EAA8E;AAC9E,6EAA6E;AAC7E,6CAA6C;AAC7C,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,EAAuB,EACvB,WAAmB,SAAS;IAE5B,IAAI,CAAC;QACH,WAAW,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;YACjC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YACrD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,CAAC;IACb,CAAC;YAAS,CAAC;QACT,WAAW,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,2EAA2E;AAC3E,sCAAsC;AACtC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAe,EACf,OAII,EAAE;IAEN,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACnC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC;IACrE,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,cAAc,OAAO,uCAAuC,CAAC,CAAC,CAAC;QAC9E,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,GAAG,GACP,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACtE,OAAO,GAAG,CAAC,OAAO,CAAC,CAAC;AACtB,CAAC"}
@@ -0,0 +1,361 @@
1
+ import confirm from "@inquirer/confirm";
2
+ import input from "@inquirer/input";
3
+ import select from "@inquirer/select";
4
+ import chalk from "chalk";
5
+ import { existsSync, mkdirSync } from "node:fs";
6
+ import { homedir } from "node:os";
7
+ import { join } from "node:path";
8
+ import { CONFIG_PATH, maskSecret, ConfigSchema, configExists, ensureVirDir, expandHome, loadConfig, saveConfig, } from "../config.js";
9
+ import { setupNotifications } from "./notificationsSetup.js";
10
+ import { categorizeTranscriptHead, classifyTranscript, estimateSessionCost, groupByProject, readTranscriptHead, } from "../pipeline/projects.js";
11
+ import { promptProjectDecisions } from "./projectSelect.js";
12
+ import { scanSessions } from "../pipeline/scanner.js";
13
+ import { normalizeModelName } from "../pipeline/distiller.js";
14
+ import { buildInitConfig } from "./initConfig.js";
15
+ import { installToClaudeCode } from "../mcp/install.js";
16
+ import * as ui from "../ui/display.js";
17
+ export async function cmdInit() {
18
+ ensureVirDir();
19
+ const existing = configExists() ? safeLoad() : null;
20
+ ui.header("init");
21
+ ui.blank();
22
+ // ── vault path ──────────────────────────────────────────────────────────
23
+ let vaultPath = "";
24
+ for (;;) {
25
+ vaultPath = await input({
26
+ message: "Obsidian vault path",
27
+ default: existing?.vaultPath ??
28
+ join(homedir(), "Documents", "Obsidian", "MyVault"),
29
+ });
30
+ const expanded = expandHome(vaultPath);
31
+ if (existsSync(expanded))
32
+ break;
33
+ const create = await confirm({
34
+ message: `Vault path does not exist (${expanded}). Create it?`,
35
+ default: true,
36
+ });
37
+ if (create) {
38
+ try {
39
+ mkdirSync(expanded, { recursive: true });
40
+ break;
41
+ }
42
+ catch (err) {
43
+ console.error(chalk.red(`failed to create: ${err.message}`));
44
+ }
45
+ }
46
+ }
47
+ const outputDir = await input({
48
+ message: "Output subdir inside vault",
49
+ default: existing?.outputDir ?? "vir",
50
+ });
51
+ // ── claude projects dir ─────────────────────────────────────────────────
52
+ let claudeProjectsDir = "";
53
+ for (;;) {
54
+ claudeProjectsDir = await input({
55
+ message: "Claude Code projects dir",
56
+ default: existing?.claudeProjectsDir ?? join(homedir(), ".claude", "projects"),
57
+ });
58
+ const expanded = expandHome(claudeProjectsDir);
59
+ if (existsSync(expanded))
60
+ break;
61
+ console.warn(chalk.yellow("directory not found — Claude Code sessions may not exist yet"));
62
+ const cont = await confirm({
63
+ message: "continue anyway?",
64
+ default: false,
65
+ });
66
+ if (cont)
67
+ break;
68
+ }
69
+ // ── web articles (optional second input source) ─────────────────────────
70
+ let articlesDir = existing?.articlesDir;
71
+ const wantsArticles = await confirm({
72
+ message: "Do you save web articles to a folder (e.g. Obsidian Web Clipper)?",
73
+ default: existing?.articlesDir !== undefined,
74
+ });
75
+ if (wantsArticles) {
76
+ for (;;) {
77
+ articlesDir = await input({
78
+ message: "Articles (raw/) directory",
79
+ default: existing?.articlesDir ??
80
+ join(homedir(), "Documents", "Obsidian", "raw"),
81
+ });
82
+ const expanded = expandHome(articlesDir);
83
+ if (existsSync(expanded))
84
+ break;
85
+ const create = await confirm({
86
+ message: `Path does not exist (${expanded}). Create it?`,
87
+ default: true,
88
+ });
89
+ if (create) {
90
+ try {
91
+ mkdirSync(expanded, { recursive: true });
92
+ break;
93
+ }
94
+ catch (err) {
95
+ console.error(chalk.red(`failed to create: ${err.message}`));
96
+ }
97
+ }
98
+ else {
99
+ break;
100
+ }
101
+ }
102
+ }
103
+ else {
104
+ articlesDir = undefined;
105
+ }
106
+ // ── PDFs / papers (optional third input source) ──────────────────────────
107
+ let pdfsDir = existing?.pdfsDir;
108
+ const wantsPdfs = await confirm({
109
+ message: "Do you keep PDFs / papers in a folder to ingest?",
110
+ default: existing?.pdfsDir !== undefined,
111
+ });
112
+ if (wantsPdfs) {
113
+ for (;;) {
114
+ pdfsDir = await input({
115
+ message: "PDFs directory",
116
+ default: existing?.pdfsDir ?? join(homedir(), "Documents", "papers"),
117
+ });
118
+ const expanded = expandHome(pdfsDir);
119
+ if (existsSync(expanded))
120
+ break;
121
+ const create = await confirm({
122
+ message: `Path does not exist (${expanded}). Create it?`,
123
+ default: true,
124
+ });
125
+ if (create) {
126
+ try {
127
+ mkdirSync(expanded, { recursive: true });
128
+ break;
129
+ }
130
+ catch (err) {
131
+ console.error(chalk.red(`failed to create: ${err.message}`));
132
+ }
133
+ }
134
+ else {
135
+ break;
136
+ }
137
+ }
138
+ }
139
+ else {
140
+ pdfsDir = undefined;
141
+ }
142
+ const cadenceHours = Number(await input({
143
+ message: "Cadence (hours)",
144
+ default: String(existing?.cadenceHours ?? 3),
145
+ validate: (v) => {
146
+ const n = Number(v);
147
+ return Number.isFinite(n) && n > 0 ? true : "must be a positive number";
148
+ },
149
+ }));
150
+ // ── provider picker ─────────────────────────────────────────────────────
151
+ const provider = (await select({
152
+ message: "Provider",
153
+ default: existing?.provider ?? "anthropic",
154
+ choices: [
155
+ {
156
+ name: "Anthropic (API key — predictable per-session cost, no effect on your Claude Code limits)",
157
+ value: "anthropic",
158
+ },
159
+ {
160
+ name: "Claude Code (subscription — free and keyless; distills consume your Claude Code usage limits)",
161
+ value: "claude-cli",
162
+ },
163
+ {
164
+ name: "Kie.ai (~72% cheaper API, third-party proxy — you trade reliability for cost)",
165
+ value: "kie",
166
+ },
167
+ ],
168
+ }));
169
+ // Secret prompt discipline: mask while typing, echo only a masked
170
+ // confirmation (maskSecret), and NEVER render the existing key as the
171
+ // visible inquirer default — that prints the full secret to the terminal
172
+ // before a single keystroke. Empty input keeps the existing/env key.
173
+ const promptSecret = async (message, keep, validate) => {
174
+ const value = await input({
175
+ message: keep
176
+ ? `${message} (Enter keeps ${maskSecret(keep)})`
177
+ : message,
178
+ transformer: (v, { isFinal }) => isFinal ? maskSecret(v || keep || "") : "•".repeat(v.length),
179
+ validate: (v) => (v === "" && keep ? true : validate(v)),
180
+ });
181
+ return value === "" && keep ? keep : value;
182
+ };
183
+ let anthropicApiKey;
184
+ let kieApiKey;
185
+ if (provider === "anthropic") {
186
+ anthropicApiKey = await promptSecret("Anthropic API key", existing?.anthropicApiKey ?? process.env.ANTHROPIC_API_KEY ?? undefined, (v) => (v.startsWith("sk-ant-") ? true : "key should start with sk-ant-"));
187
+ }
188
+ else if (provider === "kie") {
189
+ kieApiKey = await promptSecret("Kie.ai API key", existing?.kieApiKey ?? process.env.KIE_API_KEY ?? undefined, (v) => (v.length > 10 ? true : "enter a valid Kie.ai API key"));
190
+ }
191
+ // claude-cli: no credential of any kind — it uses the `claude` login.
192
+ // ── model pickers (provider-aware) ──────────────────────────────────────
193
+ // claude-cli accepts the same full Anthropic model ids (and pins them per
194
+ // invocation via --model), so it shares the anthropic id set.
195
+ const classifyChoices = provider !== "kie"
196
+ ? [
197
+ {
198
+ name: "claude-haiku-4-5-20251001 (recommended)",
199
+ value: "claude-haiku-4-5-20251001",
200
+ },
201
+ { name: "claude-sonnet-4-6", value: "claude-sonnet-4-6" },
202
+ ]
203
+ : [
204
+ {
205
+ name: "claude-haiku-4-5 (recommended)",
206
+ value: "claude-haiku-4-5",
207
+ },
208
+ { name: "claude-sonnet-4-6", value: "claude-sonnet-4-6" },
209
+ ];
210
+ const classifyModel = await select({
211
+ message: "Classify model (fast pass)",
212
+ choices: classifyChoices,
213
+ });
214
+ const distillChoices = provider !== "kie"
215
+ ? [
216
+ {
217
+ name: "claude-sonnet-5 (recommended)",
218
+ value: "claude-sonnet-5",
219
+ },
220
+ { name: "claude-sonnet-4-6", value: "claude-sonnet-4-6" },
221
+ {
222
+ name: "claude-haiku-4-5-20251001 (faster, cheaper)",
223
+ value: "claude-haiku-4-5-20251001",
224
+ },
225
+ ]
226
+ : [
227
+ {
228
+ name: "claude-sonnet-4-6 (recommended)",
229
+ value: "claude-sonnet-4-6",
230
+ },
231
+ {
232
+ name: "claude-haiku-4-5 (faster, cheaper)",
233
+ value: "claude-haiku-4-5",
234
+ },
235
+ ];
236
+ const distillModel = await select({
237
+ message: "Distill model (deep extraction)",
238
+ choices: distillChoices,
239
+ });
240
+ const filterThreshold = Number(await input({
241
+ message: "Filter threshold (0..1)",
242
+ default: String(existing?.filterThreshold ?? 0.4),
243
+ validate: (v) => {
244
+ const n = Number(v);
245
+ return Number.isFinite(n) && n >= 0 && n <= 1
246
+ ? true
247
+ : "must be between 0 and 1";
248
+ },
249
+ }));
250
+ // ── project triage (the primary decision point) ─────────────────────────
251
+ // Every project found under the Claude projects dir is shown once with its
252
+ // session count and rough cost; selected = include, unselected = exclude.
253
+ // Projects that appear later start undecided and trigger the run prompt.
254
+ let projectDecisions = {};
255
+ let agentTranscriptsAnswer;
256
+ try {
257
+ const projectsDirX = expandHome(claudeProjectsDir);
258
+ const allFound = scanSessions(projectsDirX);
259
+ // Triage counts + the agent-transcript question. Only top-level
260
+ // transcripts count (nested workflow/sidechain have their own filter),
261
+ // and agent transcripts are excluded from the per-project multi-select
262
+ // numbers so the costs shown reflect what would actually distill.
263
+ const topLevel = allFound.filter((s) => classifyTranscript(s.path, projectsDirX) === "session");
264
+ const counts = { interactive: 0, agent: 0, stub: 0 };
265
+ const agentPaths = new Set();
266
+ for (const s of topLevel) {
267
+ const cat = categorizeTranscriptHead(readTranscriptHead(s.path), s.size);
268
+ counts[cat] += 1;
269
+ if (cat === "agent")
270
+ agentPaths.add(s.path);
271
+ }
272
+ if (counts.agent > 0) {
273
+ ui.blank();
274
+ ui.line(ui.dim(` ${counts.interactive} interactive · ${counts.agent} SDK-launched · ${counts.stub} stubs`));
275
+ agentTranscriptsAnswer = (await select({
276
+ message: "SDK-launched agent transcripts (review/verify harness output) — distill them?",
277
+ default: existing?.agentTranscripts ?? "exclude",
278
+ choices: [
279
+ {
280
+ name: "Exclude (recommended — agent-internal execution, not your decisions)",
281
+ value: "exclude",
282
+ },
283
+ { name: "Include (distill them like any session)", value: "include" },
284
+ ],
285
+ }));
286
+ }
287
+ const found = agentTranscriptsAnswer !== "include"
288
+ ? topLevel.filter((s) => !agentPaths.has(s.path))
289
+ : topLevel;
290
+ const groups = [...groupByProject(found, projectsDirX).values()];
291
+ if (groups.length > 0) {
292
+ const classifyId = normalizeModelName(classifyModel, provider);
293
+ const distillId = normalizeModelName(distillModel, provider);
294
+ const infos = groups
295
+ .map((g) => ({
296
+ name: g.name,
297
+ sessionCount: g.sessions.length,
298
+ totalBytes: g.totalBytes,
299
+ estCost: g.sessions.reduce((sum, s) => sum +
300
+ estimateSessionCost(provider, classifyId, distillId, s.size), 0),
301
+ }))
302
+ .sort((a, b) => b.estCost - a.estCost);
303
+ ui.blank();
304
+ ui.line(ui.dim(" Which projects should vir distill? Costs are rough upper bounds."));
305
+ projectDecisions = await promptProjectDecisions(infos, existing?.projects ?? {}, "Projects to track");
306
+ }
307
+ }
308
+ catch (err) {
309
+ console.warn(chalk.yellow(`project scan failed (${err.message}) — you can decide later with vir projects`));
310
+ }
311
+ const parsed = ConfigSchema.safeParse(buildInitConfig(existing, {
312
+ vaultPath,
313
+ outputDir,
314
+ claudeProjectsDir,
315
+ cadenceHours,
316
+ provider,
317
+ anthropicApiKey,
318
+ kieApiKey,
319
+ filterThreshold,
320
+ articlesDir,
321
+ pdfsDir,
322
+ classifyModel,
323
+ distillModel,
324
+ projects: projectDecisions,
325
+ agentTranscripts: agentTranscriptsAnswer,
326
+ }));
327
+ if (!parsed.success) {
328
+ console.error(chalk.red("invalid config:"));
329
+ for (const issue of parsed.error.issues) {
330
+ console.error(` - ${issue.path.join(".")}: ${issue.message}`);
331
+ }
332
+ process.exitCode = 1;
333
+ return;
334
+ }
335
+ saveConfig(parsed.data);
336
+ ui.blank();
337
+ ui.row(ui.success(ui.CHECK), ui.text(`saved ${CONFIG_PATH}`));
338
+ ui.blank();
339
+ const wantsMcp = await confirm({
340
+ message: "Register Vir with Claude Code now? (recommended)",
341
+ default: true,
342
+ });
343
+ if (wantsMcp) {
344
+ await installToClaudeCode("user");
345
+ }
346
+ if (process.platform === "darwin" && parsed.data.notifications) {
347
+ ui.blank();
348
+ setupNotifications({ test: false });
349
+ }
350
+ ui.blank();
351
+ ui.line(ui.dim("next: `vir run` to test once, then `vir schedule install`"));
352
+ }
353
+ function safeLoad() {
354
+ try {
355
+ return loadConfig();
356
+ }
357
+ catch {
358
+ return null;
359
+ }
360
+ }
361
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"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"}