@djolex999/vir-cli 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,7 @@ developer-tools, mcp, local-first, cross-platform, llm-wiki
18
18
  <a href="https://www.npmjs.com/package/@djolex999/vir-cli"><img src="https://img.shields.io/npm/v/@djolex999/vir-cli?color=7c6af7&label=npm" alt="npm version"></a>
19
19
  <a href="https://www.npmjs.com/package/@djolex999/vir-cli"><img src="https://img.shields.io/npm/dw/@djolex999/vir-cli?color=4fd1a0" alt="npm downloads"></a>
20
20
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-22d3ee" alt="license"></a>
21
- <a href="#project-status"><img src="https://img.shields.io/badge/tests-110%20passing-22c55e" alt="tests"></a>
21
+ <a href="#project-status"><img src="https://img.shields.io/badge/tests-147%20passing-22c55e" alt="tests"></a>
22
22
  <a href="#project-status"><img src="https://img.shields.io/badge/platforms-macOS%20%7C%20Linux-lightgrey" alt="platforms"></a>
23
23
  <a href="https://modelcontextprotocol.io"><img src="https://img.shields.io/badge/MCP-server-c084fc" alt="mcp"></a>
24
24
  <a href="#"><img src="https://img.shields.io/badge/local--first-yes-f59e0b" alt="local-first"></a>
@@ -71,8 +71,6 @@ Vir is actively developed. In the next 30–60 days:
71
71
  - **Obsidian plugin v1** — sidebar, command palette, canvas integration,
72
72
  submitted to the community plugin marketplace
73
73
  - **Multi-agent support** — Codex CLI, Cursor, Aider, Cline (one per release)
74
- - **Topic synthesis** — `vir compose` generates LLM Wiki-style topic pages that
75
- merge insights across sessions
76
74
  - **PDF/paper ingestion** — broaden beyond developer workflows
77
75
 
78
76
  Track progress via [GitHub issues](https://github.com/djolex999/vir/issues) or
@@ -104,6 +102,10 @@ results, not better."_ Fair. Vir addresses it in layers:
104
102
  - **MMR-diverse retrieval**. Queries return notes covering different aspects of
105
103
  the topic, not 5 similar duplicates. The retrieval algorithm balances
106
104
  relevance against diversity automatically.
105
+ - **Topic synthesis** via `vir compose "<topic>"`. Embedding-searches the vault
106
+ for related session notes and articles, then synthesizes them into a single
107
+ topic page under `topics/`, with each source wikilinked so it backlinks in
108
+ Obsidian's graph. `--dry-run` previews the sources and cost for free.
107
109
  - **Cost transparency.** `vir run --dry-run` estimates per-session cost _before_
108
110
  you spend a cent; `vir cost` reports the actuals (total, median, p90, top
109
111
  sessions) from a local `~/.vir/cost.log`; and `--force-model haiku|sonnet`
@@ -111,6 +113,14 @@ results, not better."_ Fair. Vir addresses it in layers:
111
113
  list rates + Kie's discount), so the numbers reflect _your_ bill — not a
112
114
  blended guess. Kie rates are approximate; override them in `config.pricing` if
113
115
  a report looks off.
116
+ - **Reliable failures (v0.8.0).** Every command now exits non-zero on failure —
117
+ no more silent successes hiding broken distills. `vir reconcile --dry-run`
118
+ reports any pre-0.8.0 sessions that landed with empty content (e.g. via the
119
+ v0.7.1 Kie-200-with-body-error bug); `vir reconcile` retries them, bypassing
120
+ the SHA-256 processed-cache for just those rows. Retries that fail again
121
+ leave the row untouched so a second pass can catch them once the underlying
122
+ cause is fixed. Kie 404s carrying an `api_error` body envelope (transient
123
+ service hiccups) are now retried alongside 429/5xx.
114
124
 
115
125
  The bet: with these controls, signal-to-noise stays high enough that the vault
116
126
  is a net positive. If your discipline is strong enough to maintain `CLAUDE.md`
@@ -327,6 +337,8 @@ with your distro, init system, and Node version.
327
337
  | `vir cost --by-session` | free | Full per-session cost distribution |
328
338
  | `vir query "<question>"` | cheap | Semantic search your vault |
329
339
  | `vir query … --json` | cheap | Machine-readable results for tooling |
340
+ | `vir compose "<topic>"` | $$ | Synthesize a topic page from related notes |
341
+ | `vir compose … --dry-run` | free | Preview sources + cost, exit before LLM |
330
342
  | `vir summarize <project>` | cheap | Cross-session project synthesis |
331
343
  | `vir summarize --all` | $$ | Summarize all projects |
332
344
  | `vir lint` | cheap | Find orphans, stale notes, contradictions |
@@ -347,6 +359,8 @@ with your distro, init system, and Node version.
347
359
  | `vir status` | free | Knowledge heatmap + daemon status |
348
360
  | `vir doctor` | cheap | Diagnose installation issues |
349
361
  | `vir doctor --json` | cheap | Machine-readable install/health snapshot |
362
+ | `vir reconcile --dry-run` | free | Report sessions that silently failed pre-0.7.2 |
363
+ | `vir reconcile` | $$ | Retry those sessions — bypasses cache for them only |
350
364
 
351
365
  Both `vir query` and `vir doctor` accept `--json` for programmatic consumers
352
366
  (e.g. the [vir-obsidian](https://github.com/djolex999/vir) plugin). `query --json`
@@ -453,7 +467,7 @@ vault/vir/
453
467
 
454
468
  | | |
455
469
  | -------------- | ----------------------------------------- |
456
- | Tests | 110 passing |
470
+ | Tests | 147 passing |
457
471
  | Platforms | macOS (launchd), Linux (systemd/cron) |
458
472
  | Node | 20+ |
459
473
  | First-run cost | $1–5 (Kie.ai recommended for 72% savings) |
@@ -0,0 +1,223 @@
1
+ import chalk from "chalk";
2
+ import { existsSync } from "node:fs";
3
+ import { createInterface } from "node:readline/promises";
4
+ import { stdin, stdout } from "node:process";
5
+ import { readCostLog } from "../cost/log.js";
6
+ import { computeCost } from "../cost/pricing.js";
7
+ import { Distiller, normalizeModelName, resolveModelShorthand } from "../pipeline/distiller.js";
8
+ import { scoreSession } from "../pipeline/filter.js";
9
+ import { parseSession } from "../pipeline/parser.js";
10
+ import { scrub } from "../pipeline/scrubber.js";
11
+ import { filterToolCalls } from "../pipeline/toolCallFilter.js";
12
+ import { VaultWriter } from "../pipeline/writer.js";
13
+ import { deriveSessionId, StateDb } from "../state/db.js";
14
+ import * as ui from "../ui/display.js";
15
+ // Cost-estimate constants must stay in sync with run.ts's dry-run estimator —
16
+ // transcripts tokenize denser than the chars/4 house heuristic, ~chars/3, and
17
+ // classify/distill output medians come from real cost.log calibration.
18
+ const CHARS_PER_TOKEN = 3;
19
+ const CLASSIFY_OUTPUT_TOKENS = 350;
20
+ const DISTILL_OUTPUT_TOKENS = 4500;
21
+ // Pure selector for unit tests. Mirrors the SQL filter in
22
+ // db.listReconcileTargets exactly: skipped=0 (we tried to distill) AND
23
+ // content is null-or-empty (no usable output landed).
24
+ //
25
+ // Both shapes share one cause — pre-0.7.2 the Kie-200-with-body-error path
26
+ // silently produced an empty distill string; errored runs landed as null.
27
+ // Reconcile retries either.
28
+ export function selectReconcileTargets(rows) {
29
+ return rows.filter((r) => r.skipped === 0 && (r.content === null || r.content === ""));
30
+ }
31
+ // Build the per-target summary (cost estimate + collateral flag) without doing
32
+ // any network work. Used by both the dry-run report and the live confirmation.
33
+ export function summarizeReconcileTargets(cfg, targets, costSessionIds, forceDistillModel) {
34
+ const classifyModel = normalizeModelName(cfg.models.classify, cfg.provider);
35
+ const distillModel = normalizeModelName(resolveModelShorthand(forceDistillModel ?? cfg.models.distill), cfg.provider);
36
+ let totalCost = 0;
37
+ let collateralCount = 0;
38
+ const rows = [];
39
+ for (const t of targets) {
40
+ const sessionId = deriveSessionId(t.path);
41
+ const hadCostRecord = costSessionIds.has(sessionId);
42
+ if (hadCostRecord)
43
+ collateralCount += 1;
44
+ let estimatedCost = 0;
45
+ if (existsSync(t.path)) {
46
+ try {
47
+ const parsed = parseSession(t.path, t.hash);
48
+ const classifyIn = Math.ceil(scrub(parsed.rawSummary).length / CHARS_PER_TOKEN);
49
+ const distillIn = Math.ceil(scrub(filterToolCalls(parsed.transcriptText, cfg.filterToolCalls).filtered).length / CHARS_PER_TOKEN);
50
+ estimatedCost =
51
+ computeCost(cfg.provider, classifyModel, classifyIn, CLASSIFY_OUTPUT_TOKENS, cfg.pricing) +
52
+ computeCost(cfg.provider, distillModel, distillIn, DISTILL_OUTPUT_TOKENS, cfg.pricing);
53
+ }
54
+ catch {
55
+ // Bad jsonl now — we'll still attempt retry, but skip the estimate.
56
+ }
57
+ }
58
+ totalCost += estimatedCost;
59
+ rows.push({
60
+ path: t.path,
61
+ sessionId,
62
+ hadCostRecord,
63
+ estimatedCost,
64
+ });
65
+ }
66
+ return { rows, totalCost, collateralCount };
67
+ }
68
+ async function confirmReconcile(targetCount, totalCost) {
69
+ ui.box([
70
+ `${ui.text(String(targetCount))} ${ui.dim("sessions to retry")}`,
71
+ `${ui.dim("estimated:")} ${ui.warn(ui.formatUsd(totalCost))}`,
72
+ ], { title: "reconcile cost estimate" });
73
+ const rl = createInterface({ input: stdin, output: stdout });
74
+ const ans = (await rl.question(ui.muted("continue? (y/n) ")))
75
+ .trim()
76
+ .toLowerCase();
77
+ rl.close();
78
+ return ans === "y" || ans === "yes";
79
+ }
80
+ export async function runReconcile(cfg, opts = {}) {
81
+ const db = new StateDb();
82
+ try {
83
+ ui.header(opts.dryRun ? "reconcile --dry-run" : "reconcile");
84
+ ui.blank();
85
+ const targets = db.listReconcileTargets();
86
+ if (targets.length === 0) {
87
+ ui.row(ui.success(ui.CHECK), ui.text("nothing to reconcile — every session has content"));
88
+ return;
89
+ }
90
+ // Build the set of session IDs that already have any distill cost record,
91
+ // so we can report "false-cost collateral" — sessions we paid for but got
92
+ // no content from.
93
+ const costSessionIds = new Set();
94
+ for (const r of readCostLog()) {
95
+ if (r.stage === "distill" && r.session && r.estimated_cost_usd > 0) {
96
+ costSessionIds.add(r.session);
97
+ }
98
+ }
99
+ const { rows, totalCost, collateralCount } = summarizeReconcileTargets(cfg, targets, costSessionIds);
100
+ for (const r of rows) {
101
+ const id = r.sessionId.slice(0, 8);
102
+ const marker = r.hadCostRecord ? ui.warn("$") : ui.dim(" ");
103
+ ui.line(` ${ui.dim(ui.BULLET)} ${marker} ${ui.text(id.padEnd(10))} ${ui.dim(`est ${ui.formatUsd(r.estimatedCost)}`)}`);
104
+ }
105
+ ui.blank();
106
+ ui.divider();
107
+ ui.summary({
108
+ recoverable: { value: rows.length, color: ui.info },
109
+ "est. retry cost": { value: ui.formatUsd(totalCost), color: ui.warn },
110
+ "false-cost collateral": {
111
+ value: collateralCount,
112
+ color: collateralCount > 0 ? ui.warn : ui.dim,
113
+ },
114
+ });
115
+ ui.divider();
116
+ if (opts.dryRun) {
117
+ ui.line(ui.dim(" dry run — nothing retried. Collateral count = sessions we paid for but got no content from."));
118
+ return;
119
+ }
120
+ if (opts.yes !== true) {
121
+ const proceed = await confirmReconcile(rows.length, totalCost);
122
+ if (!proceed) {
123
+ ui.line(ui.dim("aborted"));
124
+ return;
125
+ }
126
+ }
127
+ const writer = new VaultWriter(cfg, db);
128
+ const distiller = new Distiller(cfg);
129
+ let recovered = 0;
130
+ let stillFailed = 0;
131
+ let missingFile = 0;
132
+ for (const t of targets) {
133
+ if (!existsSync(t.path)) {
134
+ missingFile += 1;
135
+ ui.row(ui.warn(ui.WARN_GLYPH), ui.text(`missing on disk — skipped: ${t.path.slice(-60)}`));
136
+ continue;
137
+ }
138
+ // Bypass the SHA-256 processed-cache check intentionally — these rows
139
+ // are cached but we know their stored content is empty, so we want a
140
+ // forced retry. Parse, score, distill, then update the row in place.
141
+ try {
142
+ const parsed = parseSession(t.path, t.hash);
143
+ const score = scoreSession(parsed, cfg.filterThreshold);
144
+ if (!score.passes) {
145
+ // The filter rejects this now — record as skipped so a future
146
+ // reconcile pass doesn't keep retrying it.
147
+ db.record({
148
+ path: t.path,
149
+ hash: t.hash,
150
+ skipped: true,
151
+ notePaths: [],
152
+ });
153
+ continue;
154
+ }
155
+ const scrubbedSummary = scrub(parsed.rawSummary);
156
+ const toolFilter = filterToolCalls(parsed.transcriptText, cfg.filterToolCalls);
157
+ const scrubbedContent = scrub(toolFilter.filtered);
158
+ const note = await distiller.run(parsed, scrubbedSummary, scrubbedContent);
159
+ if (!note) {
160
+ // Low confidence — record as skipped so we don't keep retrying.
161
+ db.record({
162
+ path: t.path,
163
+ hash: t.hash,
164
+ skipped: true,
165
+ notePaths: [],
166
+ });
167
+ continue;
168
+ }
169
+ const written = await writer.write(parsed, note);
170
+ db.record({
171
+ path: t.path,
172
+ hash: t.hash,
173
+ skipped: false,
174
+ notePaths: written,
175
+ content: note.markdown,
176
+ category: note.classification.category,
177
+ topic: note.classification.topic,
178
+ project: note.classification.project,
179
+ confidence: note.classification.confidence,
180
+ startedAt: parsed.startedAt,
181
+ });
182
+ recovered += 1;
183
+ ui.categoryRow(note.classification.category, note.classification.topic);
184
+ // Same pacing as run.ts — let the provider breathe between calls.
185
+ await new Promise((r) => setTimeout(r, 2000));
186
+ }
187
+ catch (err) {
188
+ // A retry that fails again must leave the row as-is (content still
189
+ // null/empty) so the next reconcile pass can catch it. Do NOT mark
190
+ // it processed-with-empty.
191
+ stillFailed += 1;
192
+ const msg = err.message ?? String(err);
193
+ ui.row(ui.errorColor(ui.CROSS), ui.text(`retry failed: ${deriveSessionId(t.path).slice(0, 8)} — ${msg}`));
194
+ }
195
+ }
196
+ ui.blank();
197
+ ui.divider();
198
+ ui.summary({
199
+ recovered: { value: recovered, color: ui.success },
200
+ "still failed": {
201
+ value: stillFailed,
202
+ color: stillFailed > 0 ? ui.errorColor : ui.dim,
203
+ },
204
+ "missing file": {
205
+ value: missingFile,
206
+ color: missingFile > 0 ? ui.warn : ui.dim,
207
+ },
208
+ });
209
+ ui.divider();
210
+ // Surface "still failed" via a non-zero exit so the caller (or a CI
211
+ // harness running reconcile periodically) knows recovery is incomplete.
212
+ // The wrapper in cli.ts treats `process.exitCode = 1` as the failure
213
+ // signal; we DON'T throw because the partial recovery is real progress.
214
+ if (stillFailed > 0) {
215
+ process.exitCode = 1;
216
+ ui.line(chalk.dim(` ${stillFailed} session(s) still failed — re-run \`vir reconcile\` after the underlying cause is fixed`));
217
+ }
218
+ }
219
+ finally {
220
+ db.close();
221
+ }
222
+ }
223
+ //# sourceMappingURL=reconcile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../src/cli/reconcile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import chalk from "chalk";
2
+ export function runAction(fn, opts = {}) {
3
+ const logError = opts.logError ?? ((m) => console.error(chalk.red(m)));
4
+ return async (...args) => {
5
+ try {
6
+ await fn(...args);
7
+ }
8
+ catch (err) {
9
+ const msg = err instanceof Error
10
+ ? err.message
11
+ : typeof err === "string"
12
+ ? err
13
+ : JSON.stringify(err);
14
+ logError(msg);
15
+ process.exitCode = 1;
16
+ }
17
+ };
18
+ }
19
+ //# sourceMappingURL=runAction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runAction.js","sourceRoot":"","sources":["../../src/cli/runAction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAuB1B,MAAM,UAAU,SAAS,CACvB,EAAuC,EACvC,OAAyB,EAAE;IAE3B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,OAAO,KAAK,EAAE,GAAG,IAAU,EAAiB,EAAE;QAC5C,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACpB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GACP,GAAG,YAAY,KAAK;gBAClB,CAAC,CAAC,GAAG,CAAC,OAAO;gBACb,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ;oBACvB,CAAC,CAAC,GAAG;oBACL,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC5B,QAAQ,CAAC,GAAG,CAAC,CAAC;YACd,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}