@djolex999/vir-cli 0.2.2 → 0.2.3
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/package.json +1 -1
- package/CLAUDE.md +0 -152
package/package.json
CHANGED
package/CLAUDE.md
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
# vir
|
|
2
|
-
|
|
3
|
-
Local macOS daemon that distills Claude Code session transcripts into an
|
|
4
|
-
Obsidian vault.
|
|
5
|
-
|
|
6
|
-
Published to npm as `@djolex999/vir-cli` (scoped). Install:
|
|
7
|
-
`npm install -g @djolex999/vir-cli`. Repo: https://github.com/djolex999/vir. Reads `~/.claude/projects/**/*.jsonl`, filters by heuristic,
|
|
8
|
-
classifies with Haiku, extracts durable knowledge with Sonnet, writes typed
|
|
9
|
-
notes to the vault, maintains an index, and syncs back into CLAUDE.md files.
|
|
10
|
-
|
|
11
|
-
## Stack
|
|
12
|
-
|
|
13
|
-
- Node.js ≥ 20, TypeScript strict (`noImplicitAny`, `noUncheckedIndexedAccess`)
|
|
14
|
-
- `commander` for CLI, `chalk` for output, `zod` for config validation
|
|
15
|
-
- `better-sqlite3` for state (synchronous — no async complexity)
|
|
16
|
-
- `@anthropic-ai/sdk` for the Anthropic path; native `fetch` for the Kie path
|
|
17
|
-
- macOS `launchd` for the daemon, `osascript` for notifications
|
|
18
|
-
|
|
19
|
-
## Structure
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
src/
|
|
23
|
-
cli.ts # commander entry — every subcommand wired here
|
|
24
|
-
config.ts # ~/.vir/config.json schema + helpers
|
|
25
|
-
pipeline/
|
|
26
|
-
run.ts # orchestrator (scan → filter → scrub → distill → write)
|
|
27
|
-
scanner.ts # walk ~/.claude/projects, SHA-256 each .jsonl
|
|
28
|
-
parser.ts # extract assistant/user text, tool calls, files touched
|
|
29
|
-
filter.ts # heuristic scorer (length, tools, files, signal words)
|
|
30
|
-
scrubber.ts # strip API keys, bearer tokens, absolute paths, emails
|
|
31
|
-
distiller.ts # callLLM helper, Haiku classify + Sonnet extract,
|
|
32
|
-
# withRateLimitRetry, buildAnthropicClient,
|
|
33
|
-
# normalizeModelName
|
|
34
|
-
writer.ts # frontmatter + body, wikilink injection, index/log
|
|
35
|
-
summarizer.ts # per-project knowledge summaries
|
|
36
|
-
types.ts # ParsedSession, Classification, DistilledNote, Category
|
|
37
|
-
search/
|
|
38
|
-
retriever.ts # unified async search: embeddings → TF-IDF fallback
|
|
39
|
-
embedder.ts # Ollama integration (nomic-embed-text), cosine sim
|
|
40
|
-
synthesizer.ts # Claude synthesis for `vir query`
|
|
41
|
-
lint/
|
|
42
|
-
linter.ts # orphans, staleness, contradictions
|
|
43
|
-
dedupe/
|
|
44
|
-
detector.ts # candidate pairs + LLM judgment
|
|
45
|
-
merger.ts # archive / keep / Sonnet-merge
|
|
46
|
-
claude/
|
|
47
|
-
updater.ts # VIR:START / VIR:END block management
|
|
48
|
-
state/
|
|
49
|
-
db.ts # better-sqlite3, idempotent migrations
|
|
50
|
-
daemon/
|
|
51
|
-
launchd.ts # plist render + load/unload via spawnSync('launchctl')
|
|
52
|
-
ui/
|
|
53
|
-
display.ts # the ONE place console.log lives — palette, glyphs,
|
|
54
|
-
# header(), divider(), box(), spinner(), summary(),
|
|
55
|
-
# wrap(), sourceRow(), categoryRow()
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Key conventions
|
|
59
|
-
|
|
60
|
-
- **Path expansion.** All paths from config (`vaultPath`, `claudeProjectsDir`)
|
|
61
|
-
must run through `expandHome()` (or `os.homedir()` directly) before use.
|
|
62
|
-
Never assume `~/` works in `fs.*`.
|
|
63
|
-
- **Per-session try/catch.** The daemon must never die on a single bad
|
|
64
|
-
transcript. `pipeline/run.ts` wraps every session iteration and records the
|
|
65
|
-
error in the DB so it doesn't keep retrying.
|
|
66
|
-
- **Provider routing.**
|
|
67
|
-
- `provider: 'anthropic'` → `@anthropic-ai/sdk` (`buildAnthropicClient`).
|
|
68
|
-
- `provider: 'kie'` → native `fetch` to `https://api.kie.ai/claude/v1/messages`
|
|
69
|
-
with `Authorization: Bearer <kieApiKey>`. The SDK is **not** used for Kie
|
|
70
|
-
even with a `baseURL` override — its `x-api-key` header conflicts.
|
|
71
|
-
- Both flow through `callLLM(config, client, opts)`.
|
|
72
|
-
- **Model names.** `normalizeModelName(model, provider)` collapses any model
|
|
73
|
-
that *starts with* a Kie canonical id (`claude-haiku-4-5`,
|
|
74
|
-
`claude-sonnet-4-6`) back to the bare id. Fallback strips trailing
|
|
75
|
-
`-YYYYMMDD`. Anthropic path passes through untouched.
|
|
76
|
-
- **Rate limits.** Every LLM call is wrapped in `withRateLimitRetry()` — three
|
|
77
|
-
attempts with `60s / 120s / 240s` backoff on `429` (Anthropic SDK
|
|
78
|
-
`APIError.status === 429` and our `HttpError.status === 429` both detected).
|
|
79
|
-
Sessions are processed sequentially with a `2s` delay after each successful
|
|
80
|
-
distill.
|
|
81
|
-
- **State is the source of truth.** `~/.vir/vir.db` records every session by
|
|
82
|
-
path with its SHA-256 hash. Reruns are idempotent; a session is only
|
|
83
|
-
re-distilled if its file content changes. Migrations are additive only
|
|
84
|
-
(`PRAGMA table_info(sessions)` + `ALTER TABLE ADD COLUMN`).
|
|
85
|
-
- **VIR:START / VIR:END markers are sacred.** `sync-claude` only mutates bytes
|
|
86
|
-
between those markers. When a CLAUDE.md has no block, the new one is
|
|
87
|
-
appended; the rest of the file is preserved verbatim.
|
|
88
|
-
- **No comments explaining obvious things.** Comment WHY a non-obvious
|
|
89
|
-
invariant exists — never WHAT the code does.
|
|
90
|
-
- **All user-facing output goes through `ui/display.ts`.** Other modules
|
|
91
|
-
must not call `console.log` directly. The pipeline's `fileLog()` writes
|
|
92
|
-
to `~/.vir/daemon.log` in plain text regardless of UI mode; the
|
|
93
|
-
display module renders only when `!opts.quiet`.
|
|
94
|
-
- **Ollama is best-effort.** `writer.maybeEmbed()` and the search path
|
|
95
|
-
both probe via `isOllamaAvailableCached()` and silently fall back
|
|
96
|
-
(TF-IDF for query; no-op for writer). An embedding failure must never
|
|
97
|
-
fail a write.
|
|
98
|
-
- **Cost prompts respect intent.** `--yes`, `--daemon`, and
|
|
99
|
-
`--rewrite-only` all skip the > 20 new-session confirmation. The
|
|
100
|
-
daemon path *never* prompts (it has no tty).
|
|
101
|
-
- **`vir init` is an @inquirer/* wizard.** Arrow-key `select` for
|
|
102
|
-
provider and models, `input` with `validate` for keys/numbers,
|
|
103
|
-
`confirm` for the "create missing path?" flow. Don't fall back to
|
|
104
|
-
raw readline here — the rest of the file already imports it for
|
|
105
|
-
dedupe/sync-claude/cost prompts, but the init UX is the wizard.
|
|
106
|
-
- **`vir run` prints a preflight line.** `N files found · M cached · K
|
|
107
|
-
new` shows after the scan in dim text, and the same triple goes to
|
|
108
|
-
the daemon log. Diagnoses "fresh DB looks stale" misconfigurations
|
|
109
|
-
in one line.
|
|
110
|
-
|
|
111
|
-
## Commands
|
|
112
|
-
|
|
113
|
-
```
|
|
114
|
-
vir init # interactive setup
|
|
115
|
-
vir run # one pass (used by daemon)
|
|
116
|
-
vir run --full # ignore state cache, re-process everything
|
|
117
|
-
vir run --rewrite-only # re-render notes from stored content
|
|
118
|
-
# (no scan, no LLM, free)
|
|
119
|
-
vir run --yes # skip the > 20 sessions cost prompt
|
|
120
|
-
vir schedule install # write + load ~/Library/LaunchAgents plist
|
|
121
|
-
vir schedule uninstall # unload + remove plist
|
|
122
|
-
vir status # daemon state + knowledge base breakdown
|
|
123
|
-
vir query "<question>" # embeddings (Ollama) → TF-IDF fallback
|
|
124
|
-
# → Claude synthesis
|
|
125
|
-
vir embed # generate Ollama embeddings for notes
|
|
126
|
-
vir embed --force # regenerate all embeddings
|
|
127
|
-
vir summarize <project> # generate per-project summary
|
|
128
|
-
vir summarize --all # all projects with notes
|
|
129
|
-
vir lint # orphans + stale + contradictions
|
|
130
|
-
vir lint --orphans # orphans only (free)
|
|
131
|
-
vir lint --stale # staleness only (free)
|
|
132
|
-
vir lint --contradictions # contradictions only (Haiku tokens)
|
|
133
|
-
vir dedupe # interactive duplicate review + merge
|
|
134
|
-
vir sync-claude # diff then confirm CLAUDE.md updates
|
|
135
|
-
vir sync-claude --dry-run # diff only, never write
|
|
136
|
-
vir sync-claude --force # apply without confirmation
|
|
137
|
-
vir sync-claude <project> # specific project only
|
|
138
|
-
vir sync-claude --global # only ~/.claude/CLAUDE.md
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## File locations
|
|
142
|
-
|
|
143
|
-
- Config: `~/.vir/config.json`
|
|
144
|
-
- State: `~/.vir/vir.db` (better-sqlite3 with WAL). A one-shot rename in
|
|
145
|
-
`StateDb`'s constructor moves the pre-rename `~/.vir/state.db` over to
|
|
146
|
-
`~/.vir/vir.db` if it's still around — preserves cache, hides the
|
|
147
|
-
history of the doc/code mismatch.
|
|
148
|
-
- Daemon log: `~/.vir/daemon.log`
|
|
149
|
-
- launchd plist: `~/Library/LaunchAgents/lab.growthq.vir.plist`
|
|
150
|
-
- Vault notes: `<vaultPath>/<outputDir>/{patterns,gotchas,decisions,tools,projects,archived}/`
|
|
151
|
-
- Vault index: `<vaultPath>/<outputDir>/index.md`
|
|
152
|
-
- Vault run log: `<vaultPath>/<outputDir>/log.md`
|