@djolex999/vir-cli 0.7.2 → 0.8.1

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
@@ -113,6 +113,14 @@ results, not better."_ Fair. Vir addresses it in layers:
113
113
  list rates + Kie's discount), so the numbers reflect _your_ bill — not a
114
114
  blended guess. Kie rates are approximate; override them in `config.pricing` if
115
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.
116
124
 
117
125
  The bet: with these controls, signal-to-noise stays high enough that the vault
118
126
  is a net positive. If your discipline is strong enough to maintain `CLAUDE.md`
@@ -293,9 +301,21 @@ Distill output dominates. A multi-hour Claude Code epic with hundreds of tool ca
293
301
  - `vir cost --top 5` shows your most expensive sessions.
294
302
  - `vir run --dry-run` previews per-session cost projections before the live run. Estimates are recalibrated from real v0.7.0 token data and run as a rough projection; actual cost varies with session content.
295
303
 
296
- ### Reducing cost further
304
+ ### Hybrid routing
297
305
 
298
- Set `models.distill` to `claude-haiku-4-5` in `~/.vir/config.json` for ~3× cost reduction. Quality is comparable on routine sessions and tool-heavy work; degrades on decision-heavy and very large sessions (calibration data shows Haiku misses architectural/judgment lessons that Sonnet catches). Hybrid routing (Haiku default + Sonnet on decision category and large sessions) is planned for v0.8.0.
306
+ Haiku is ~3× cheaper than Sonnet and captures equal-or-more concrete detail on routine and tool-heavy sessions. Calibration data shows it only misses higher-order judgment/architectural lessons on **decision-heavy** and **very large** sessions. Hybrid routing exploits that: route routine sessions to Haiku, reserve Sonnet for where it matters.
307
+
308
+ When `models.distillFast` is set, each session is routed after classification:
309
+
310
+ - `category === "decision"` → `models.distill` (Sonnet)
311
+ - `inputTokens > models.distillThreshold` (default `100000`) → `models.distill`
312
+ - otherwise → `models.distillFast` (Haiku)
313
+
314
+ **New installs** (`vir init`) enable hybrid by default — `distillFast` is set to the Haiku model. **Existing installs** are unaffected on upgrade: with `distillFast` unset, `models.distill` is used for every session exactly as before. Opt in by adding `"distillFast": "claude-haiku-4-5"` (Kie) or `"claude-haiku-4-5-20251001"` (Anthropic) to `models` in `~/.vir/config.json`.
315
+
316
+ `vir run --force-model haiku|sonnet` **bypasses hybrid routing entirely** and forces every session to the named model for that run — useful for A/B comparison. Force-model wins over hybrid.
317
+
318
+ To go all-cheap instead, set `models.distill` itself to the Haiku model (quality degrades on decision-heavy and very large sessions).
299
319
 
300
320
  ## Platform support
301
321
 
@@ -351,6 +371,8 @@ with your distro, init system, and Node version.
351
371
  | `vir status` | free | Knowledge heatmap + daemon status |
352
372
  | `vir doctor` | cheap | Diagnose installation issues |
353
373
  | `vir doctor --json` | cheap | Machine-readable install/health snapshot |
374
+ | `vir reconcile --dry-run` | free | Report sessions that silently failed pre-0.7.2 |
375
+ | `vir reconcile` | $$ | Retry those sessions — bypasses cache for them only |
354
376
 
355
377
  Both `vir query` and `vir doctor` accept `--json` for programmatic consumers
356
378
  (e.g. the [vir-obsidian](https://github.com/djolex999/vir) plugin). `query --json`
@@ -427,7 +449,9 @@ Located at `~/.vir/config.json`.
427
449
  | `filterToolCalls` | `moderate` | Tool-output filtering: `aggressive` \| `moderate` \| `off` |
428
450
  | `retrievalDiversity`| `0.3` | MMR diversity (0..1): 0.0 = pure relevance, 1.0 = pure diversity |
429
451
  | `models.classify` | `claude-haiku-4-5-20251001` | Classify model |
430
- | `models.distill` | `claude-sonnet-4-6` | Distill model |
452
+ | `models.distill` | `claude-sonnet-4-6` | Distill model — the "smart" model for decision/large sessions |
453
+ | `models.distillFast`| _(unset)_ | Cheap model for routine sessions. Set → hybrid routing on; unset → `distill` used for everything |
454
+ | `models.distillThreshold`| `100000` | Input-token ceiling above which a session is forced to `distill` |
431
455
  | `pricing` | _(built-in)_ | Optional per-provider `$/1M` overrides (`inputPer1M`/`outputPer1M`). Anthropic defaults track list rates; Kie defaults are approximate — verify on your Kie dashboard |
432
456
 
433
457
  ## Vault structure
@@ -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"}