@vitrinka/cli 3.3.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/CHANGELOG.md ADDED
@@ -0,0 +1,525 @@
1
+ # Changelog
2
+
3
+ `vitrinka update` prints the sections newer than your previous version after
4
+ updating — keep entries short and user-facing.
5
+
6
+ ## 3.3.0 — unreleased
7
+
8
+ ### Changed
9
+ - **Package renamed: `@lovinka/vitrinka` → `@vitrinka/cli`** (platform packages
10
+ `@vitrinka/cli-<os>-<arch>`). Same CLI, same `vitrinka` bin, now under the
11
+ product's own npm scope alongside `@vitrinka/expo`. `vitrinka update` on an
12
+ old-scope install migrates automatically (removes the legacy package before
13
+ installing this one); `@lovinka/vitrinka` is deprecated with a pointer here.
14
+
15
+ ## 3.2.0 — 2026-08-23
16
+
17
+ ### Added
18
+ - **vitrinka now works from ANY directory.** `vitrinka install` registers the
19
+ MCP forwarder at user scope everywhere (a bound repo also keeps its
20
+ committed project-scope entry, which stays the preferred mechanism and
21
+ always wins), and a new machine-level **default workspace** answers for
22
+ directories no binding covers. Onboarding asks you to pick one; later it's
23
+ `vitrinka config default`.
24
+ - **Path-prefix workspace rules** — map a folder subtree to a workspace
25
+ (`vitrinka config prefix ~/Work/ClientA acme`); the longest matching rule
26
+ wins, the default workspace is the fallback behind them.
27
+ - **A confirm gate on defaulted writes.** A write from a directory that
28
+ resolved through a prefix rule or the default asks once per directory
29
+ (per workspace) before landing — as a y/N in the CLI, and as a structured
30
+ `workspace_confirm_required` re-call for MCP agents. `vitrinka config
31
+ writes auto` turns the asking off; explicit bindings never ask.
32
+ - `vitrinka doctor` shows a `default workspace` row, and the dashboard shows
33
+ the resolved workspace with its provenance.
34
+
35
+ ### Changed
36
+ - Re-running `install` no longer removes a healthy registration at a scope it
37
+ is not rewriting — committed `.mcp.json` entries survive the global-first
38
+ migration untouched.
39
+
40
+ ## 3.1.0 — 2026-08-23
41
+
42
+ ### Added
43
+ - **`vitrinka mcp` — MCP registrations no longer carry your token.** The entry
44
+ every client now gets is the same three words in every repo
45
+ (`command: vitrinka, args: ["mcp"]`), with no URL and no credential in it.
46
+ The command resolves the deployment, workspace, token and operator at
47
+ request time, from the repo's committed binding and your OS keychain. That
48
+ makes `.mcp.json` safe to commit — so a clone is born registered — and it
49
+ gives Codex per-repo workspace routing its global, header-less registry
50
+ could never express.
51
+
52
+ ### Changed
53
+ - **`vitrinka install` rewrites a legacy token-bearing registration** wherever
54
+ it finds one — either Claude scope, or Codex's `config.toml` — and tells you
55
+ to commit the now secret-free `.mcp.json` alongside `project.json`.
56
+ - **`vitrinka doctor` names a credential in a config file for what it is**,
57
+ per file (`.mcp.json`, `.claude.json`, `config.toml`), with `vitrinka
58
+ install` as the repair. It also names a registration that predates the
59
+ forwarder instead of showing it green.
60
+
61
+ ### Fixed
62
+ - A repo whose `.vitrinka/project.json` cannot be read no longer falls back to
63
+ the default deployment — it refuses and names the file to repair, instead of
64
+ quietly publishing to the wrong install.
65
+ - A locked or unreadable credential store is reported as itself, not as a
66
+ generic 401 from the server, and unlocking it heals the running session
67
+ without relaunching the client.
68
+ - The forwarder no longer outlives the client that launched it: closing the
69
+ pipe ends in-flight work after a short grace, and a stalled handshake can no
70
+ longer hold the process open.
71
+
72
+ ## 3.0.2 — 2026-08-22
73
+
74
+ ### Added
75
+ - **Workspace bindings travel with the repo.** `vitrinka config bind` now
76
+ writes a committed `.vitrinka/project.json` (per deployment, so on-prem
77
+ coexists) — clone a bound repo on any machine and it is bound at checkout.
78
+ The machine config remains as credentials + fallback.
79
+ - **`vitrinka install` self-heals multi-workspace setups**: writes the
80
+ committed binding from a machine-only one, narrows an old wholesale
81
+ `.vitrinka/` ignore so the binding can reach git, and re-registers the
82
+ Claude MCP entry project-scope when it predates workspace baking.
83
+ - **`vitrinka doctor` explains multi-workspace problems**: binding source
84
+ (committed vs machine-only), ignore rules hiding the binding, and stale MCP
85
+ registrations — each row names the repair.
86
+
87
+ ### Changed
88
+ - Working in several workspaces on one machine no longer needs per-repo
89
+ header surgery: the server now also resolves the workspace from the
90
+ project a call names, and refuses (with the fix spelled out) instead of
91
+ guessing when the answer is ambiguous.
92
+
93
+ ## 3.0.1 — 2026-08-22
94
+
95
+ ### Changed
96
+ - **Hosted Vitrinka now lives at `vitrinka.ai`.** New installs, MCP setup,
97
+ desktop/Snap defaults, share links, and generated config schemas use the new
98
+ domain. Existing credentials and workspace bindings stored for
99
+ `vitrinka.in` continue to work during the compatibility window.
100
+
101
+ ## 3.0.0 — 2026-08-18
102
+
103
+ The CLI is now a **compiled Go binary**. `@lovinka/vitrinka` is a thin npm
104
+ launcher: it resolves the per-platform binary package for your machine and
105
+ execs it. Same commands, same flags, same config files — no Node runtime
106
+ needed to run vitrinka, and startup is instant.
107
+
108
+ ### Changed
109
+ - **`vitrinka` is Go.** Source moved from `pkg/src/cli.ts` to `cmd/vitrinka` +
110
+ `internal/cli/*` in the vitrinka repo. The npm package ships `bin/vitrinka.js`,
111
+ which launches the binary from `@lovinka/vitrinka-<platform>-<arch>`
112
+ (declared as optionalDependencies, resolved by npm from whatever registry
113
+ you already use — no postinstall download, works offline and behind proxies).
114
+ - Installing with `--omit=optional` / `--no-optional` skips the binary by
115
+ design; the launcher says exactly which platform package is missing.
116
+
117
+ ### Removed
118
+ - **The `vitrinka-mcp` bin is gone.** The stdio MCP server is retired in favor
119
+ of the server's remote endpoint. Re-register once:
120
+
121
+ ```bash
122
+ claude mcp remove vitrinka
123
+ claude mcp add --scope user --transport http vitrinka https://vitrinka.ai/mcp \
124
+ --header "Authorization: Bearer $(vitrinka token)"
125
+ ```
126
+
127
+ `vitrinka install` / `vitrinka doctor --fix` do this for you (Claude Code and
128
+ Codex both).
129
+ - **The unattended fallback worker (`vitrinka-mcp work`) is gone.** `vitrinka
130
+ watch` plus the native background monitor armed by the `listen` skill is the
131
+ one listening lane now.
132
+ - The `mcp/server.ts`, `mcp/work.ts` and `mcp/index.ts` repo shims are deleted —
133
+ a repo checkout no longer registers an stdio MCP; point at `/mcp` instead.
134
+
135
+ ## Unreleased (pre-3.0.0 — TypeScript CLI, never published)
136
+
137
+ ### Removed
138
+ - **Claude Code UI wiring is gone.** The `install-claude` command, the
139
+ `[Y/n]` install step and the `--claude`/`--no-claude` flags were removed —
140
+ the statusline extension and the 🧷 board / ⧉ app footer badges never worked
141
+ well. `install`/`update`/`uninstall` now actively strip the old wiring from
142
+ `~/.claude/settings.json` (restoring your original `statusLine.command`).
143
+
144
+ ### Added
145
+ - **Consent-gated project indexes.** `setup-project` and `index configure` now
146
+ create a repo-owned `vitrinka.config.json`, with extension presets, a recursive
147
+ tri-state directory picker, strict ignore layers, exact-manifest preview, and
148
+ per-machine approval. `index status`, `--dry-run`, and `--explain <path>` make
149
+ the resulting policy auditable.
150
+ - **Workspaces follow the project, not the token.** `vitrinka login` now
151
+ mints a USER-LEVEL token that acts as you in every workspace you're a
152
+ member of; each repo binds to its own workspace (`vitrinka use`, an
153
+ indexed table you answer by number — or automatically when exactly one of
154
+ your workspaces has the project). Commands in an unbound repo stop with
155
+ the same table and the fix command, so an agent asks you instead of
156
+ writing into the wrong workspace. Workspace-pinned tokens keep working
157
+ but are deprecated — doctor and `vitrinka update` nag to re-login.
158
+ Per-project Claude MCP registrations bake the workspace in as an
159
+ `X-Vitrinka-Workspace` header.
160
+ - **`vitrinka logout`** revokes this machine's token server-side
161
+ (`DELETE /api/v1/me/tokens/current`) and removes the local file; your
162
+ user-level tokens are listable and individually revocable via
163
+ `GET`/`DELETE /api/v1/me/tokens[/{id}]` — a lost laptop has an answer.
164
+ - **Semantic artifacts.** `artifact-init` now scaffolds a `doc.json` you author
165
+ plus a fixed shell rendered by the server-owned kit-3 — palette, type,
166
+ spacing, light/dark and the design direction (editorial · dossier · terminal
167
+ · gallery) come from the kit, and artifacts follow the viewer's theme
168
+ automatically. `artifact-from-set` composes the doc (sections + shot
169
+ figures) the same way. The full-HTML escape hatch lives on as
170
+ `artifact-init --custom`, now themed by default.
171
+ - `push` warns when a hand-authored `index.html` carries HTML entities inside
172
+ template literals (`&rarr;` renders literally under htm — write `→`).
173
+ - Findings carry their proof: `status` (verification chip), `cause`, `summary`
174
+ (the bold conclusion) and `evidence` (mono receipt footer citing the exact
175
+ log/file/check) joined the finding block.
176
+ - **Codex MCP registration.** `vitrinka install` now offers to register the
177
+ remote MCP for Codex too (writes `[mcp_servers.vitrinka]` +
178
+ `http_headers` into `$CODEX_HOME/config.toml`), `vitrinka doctor --fix`
179
+ repairs it, and `vitrinka uninstall` removes it. Doctor/install rows are now
180
+ `mcp·claude` / `mcp·codex`. Skills already shipped to Codex via the plugin;
181
+ the MCP was the missing half.
182
+
183
+ ### Fixed
184
+ - `vitrinka tag` read option VALUES as positionals, so
185
+ `tag add b1 auth --actor alice` sent `["auth", "alice"]` as tag names — and
186
+ tags autocreate, so routine invocations silently minted junk tags. A flag
187
+ placed before the verb (`tag --actor x add …`) also fell through to the `ls`
188
+ default. Both now come from the shared `positionals()` parse the rest of the
189
+ CLI already uses.
190
+
191
+ ### Changed
192
+ - Project indexes are path-only v2 manifests. The CLI no longer reads or sends
193
+ source excerpts, absolute paths, origin remotes, home-directory commands, or
194
+ command descriptions. Missing/disabled/changed policies fail closed; tracked
195
+ `.gitignore` matches, credential/key names, and binary/generated paths are
196
+ denied client-side and again by the server. Deploying this release purges all
197
+ legacy index rows once.
198
+ - **`tag merge` and `tag drop` now REFUSE without a TTY unless `--yes` is
199
+ given** (exit 2). They previously treated "no TTY to ask on" as approval, so
200
+ they ran unconfirmed in scripts, CI and any redirected shell — `drop`
201
+ detaches the tag from every board, card and session. **If you script either
202
+ verb, add `--yes`.**
203
+
204
+ ## 1.21.2 — 2026-07-26
205
+
206
+ ### Added
207
+ - `vitrinka doctor` reports listener leases held by dead watch processes on this
208
+ machine, and `vitrinka doctor --fix` releases them.
209
+ - `vitrinka extension setup | update | doctor` — install the journey-recorder
210
+ browser extension from the CLI and keep it current. Updates now happen in
211
+ place: the popup's "update available" banner is a button that has the CLI
212
+ download, checksum-verify and swap the release, then reloads the extension
213
+ into it. `--check` reports without installing; `doctor --fix` re-registers the
214
+ native-messaging host after a CLI reinstall moves `node` or the CLI.
215
+ - The extension takes its base URL and token from this machine's CLI config on
216
+ first load, so a fresh install needs no pasting (the options page gains a
217
+ "Fill from the vitrinka CLI" override). Existing settings are never replaced.
218
+ - **Migrating a hand-unzipped copy:** the extension now pins its id, so the
219
+ CLI-managed folder is a *different* extension to Chrome. Run
220
+ `vitrinka extension setup`, load `~/.config/vitrinka/extension`, and remove
221
+ the old card — a token you pasted by hand does not carry over.
222
+
223
+ ### Changed
224
+ - `vitrinka install` now detects the Chromium browsers on the machine and offers
225
+ the recorder as a step (`--extension` / `--no-extension`), so re-running it on
226
+ an already-onboarded machine is how you backfill the extension. An install
227
+ that already has it silently re-registers the update host, which is also how a
228
+ browser added since the last run starts working. `vitrinka update` keeps an
229
+ installed extension current, and the update host is registered for the
230
+ browsers detected on the machine (falling back to all of them when none is
231
+ detected, so a fresh box still gets a working host) — so `extension doctor`
232
+ can now tell you the browser you *use* is unregistered instead of counting
233
+ four blind writes.
234
+
235
+ ### Fixed
236
+ - A listener could outlive the session that armed it and hold its board's lease
237
+ **forever**. Claude Code signals the wrapper shell it spawned, so the watch
238
+ underneath never got the SIGTERM — it was adopted by init and kept renewing
239
+ its lease, which the TTL cannot reap (the TTL only reaps leases that stop
240
+ heartbeating). Annotations dispatched on that board then vanished into a
241
+ process nobody was reading. Three fixes: `/vitrinka:listen` now arms
242
+ `exec vitrinka watch` so the watch *is* the signalled process; `vitrinka
243
+ watch` self-terminates if it is ever orphaned, covering exits that deliver no
244
+ signal at all (agent SIGKILLed, crashed, terminal closed); and it now handles
245
+ SIGHUP alongside SIGINT/SIGTERM.
246
+ - Release integrity is fail-closed: a feed without a usable SHA-256, or an
247
+ artifact larger than it advertised, is refused before anything is downloaded
248
+ or swapped. Previously the checksum was only verified when the field happened
249
+ to be present, and the whole body was buffered unbounded.
250
+
251
+ ## 1.21.1 — 2026-07-25
252
+
253
+ ### Fixed
254
+ - `/vitrinka:brainstorming` sometimes skipped the decision map — the map was
255
+ reasoned out but never written, so the round opened straight into a "anything
256
+ to cut, add, or reorder?" picker whose options referenced decisions you could
257
+ not see anywhere, expanded output included. The map is now printed as its own
258
+ message before any question is asked, and the board-mode exemption from
259
+ printing it only applies once a board actually exists.
260
+
261
+ ## 1.21.0 — 2026-07-25
262
+
263
+ ### Added
264
+ - MCP `get_session` — one recorded testing session as a compact digest (the
265
+ screen walk, issues deduped across steps with live board status, per-route
266
+ web vitals, and facets to group them into fix batches). Address it by session
267
+ id or by the session's board slug. Use it instead of walking raw `/events`.
268
+
269
+ ### Changed
270
+ - Closing a session no longer waits for its board. The server builds the board
271
+ on a worker and reports `projection` state, so a stop returns immediately —
272
+ and a recording session's board is now kept live as you test, rather than
273
+ only existing once the session ends. Anything reading `projectionError` off a
274
+ stop response should read `projection.state` instead.
275
+
276
+ ## 1.20.0 — 2026-07-23
277
+
278
+ ### Changed
279
+ - All output now lives under one `.vitrinka/` home in the target repo:
280
+ `.vitrinka/screenshots/` (was `.screenshots/`), `.vitrinka/artifacts/<slug>/`
281
+ (was `.artifacts/`), plus `.vitrinka/scratch/<topic>/` as the sanctioned spot
282
+ for ad-hoc session output. Legacy roots auto-migrate the first time a command
283
+ touches them; explicit `--root`/`--from` paths are respected as given.
284
+
285
+ ### Added
286
+ - `vitrinka tidy [--yes] [--all]` — report-first sweep of legacy roots and
287
+ shot-shaped repo-root litter (`.screenshots-<topic>/`, loose `shot-*.png`)
288
+ into `.vitrinka/`; `--all` also moves loose images and `.aud_*` text litter.
289
+ Git-tracked files are never touched.
290
+ - Plugin skills `/vitrinka:annotations` + `/vitrinka:answers` — manual MCP
291
+ fallback drains for when a "Send to Claude" dispatch doesn't reach the
292
+ session (annotation work queue / durable question answers).
293
+
294
+ ## 1.19.0 — 2026-07-23
295
+
296
+ ### Added
297
+ - `vitrinka setup-project` — the repo onboarding wizard (clack-styled TUI, the
298
+ pkg's first runtime deps: `@clack/prompts` + `picocolors`). One front door for
299
+ everything a repo needs before the editor and board @ autocomplete work:
300
+ machine-install gate (offers `install` inline when the machine isn't
301
+ onboarded), project name + registry record, file/route index push (verified),
302
+ component-index with auto-detected candidate dirs, desktop-app check, and an
303
+ optional hello board. Status-first and idempotent — re-runs refresh the cheap
304
+ bits and only prompt for what's missing; `--yes`/non-TTY takes every default.
305
+ - `edit` and `status` print a one-line hint toward `vitrinka setup-project`
306
+ while the repo has never been indexed.
307
+
308
+ ## 1.18.0 — 2026-07-21
309
+
310
+ ### Added
311
+ - `vitrinka edit [path]` — focus the resident Vitrinka.app editor on a file or
312
+ project via the `vitrinka://edit?path=…` deep link (`--print` emits only the
313
+ URL; when the app isn't installed it prints an install hint). The instant
314
+ editor's CLI entry point.
315
+ - Automatic project registry: `edit`, `status`, `watch`, and `board-from-set`
316
+ now record `{project → main-worktree path}` to
317
+ `~/.config/vitrinka/projects.json` as a side effect, so the desktop editor
318
+ auto-discovers your live checkouts with zero extra UX. Best-effort — a write
319
+ failure never breaks the command.
320
+ - `compose_board` accepts kind `"artifact"` — a sandboxed self-contained HTML
321
+ card straight from a compose batch: `{html}` full document or
322
+ `{body, runtime: "tw4"}` markup-only (server inlines the Tailwind v4
323
+ runtime; dramatically cheaper). Up to 8 MiB inline.
324
+
325
+ ### Changed
326
+ - `compose_board`'s card schema is slim: the tool description now carries the
327
+ kind index + quick shapes only; per-kind payload contracts live in the
328
+ vitrinka plugin skills (the publish skill's `references/card-kinds.md` is
329
+ the index). Unknown kinds still 400 with the full allowed list.
330
+ - `vitrinka import` (and `POST /import`) replies with a compact per-card
331
+ summary (`{id, elemNo, kind, title, counts, section?}`); pass `--verbose`
332
+ (API: `?verbose=1`) for the full card JSON.
333
+
334
+ ## 1.17.0 — 2026-07-20
335
+
336
+ ### Added
337
+ - `get_questions` MCP tool — durable post-send retrieval of a board's answered
338
+ decisions (options, notes, ⌖ refs). Choices ride the work wire exactly once,
339
+ so a send with no listening session used to look unrecoverable; now any
340
+ session can re-read the full answer record at any time.
341
+ - `scrape_board` digest now carries a compact `questions[]`
342
+ (`{id, prompt, answer?, note?, staged?}`) — one call reads the decision
343
+ state alongside cards/flow/sections; section scopes keep only their own.
344
+ - `vitrinka watch` keepalive: while a human actually has the board open, the
345
+ leased watch emits a quiet `· keepalive` heartbeat (default every 3000 s,
346
+ `--keepalive 0` off) so the listening session's prompt cache stays warm and
347
+ the next annotation lands cheap. An abandoned board costs nothing.
348
+
349
+ ## 1.16.0 — 2026-07-19
350
+
351
+ ### Added
352
+ - Listener takeover is automatic on the same machine — arming `vitrinka watch`
353
+ for a scope another of YOUR sessions already holds displaces the older
354
+ listener (its in-flight items go back to the queue) instead of failing with
355
+ a 409 and a manual handoff. The displaced watch prints one stand-down line
356
+ and exits cleanly. Live leases on a *different* machine still refuse the
357
+ claim; `--takeover` still steals expired leases only.
358
+
359
+ ### Fixed
360
+ - `vitrinka watch` and the background daemon no longer swallow answered
361
+ brainstorm choices — a pure choice batch used to be drained by the notifier
362
+ and marked delivered while the listening session never woke. Notifier lanes
363
+ now peek without consuming, and watch announces each answer as a
364
+ `№<id> [choice]` line; the acting lane keeps exactly-once delivery.
365
+
366
+ ## 1.15.1 — 2026-07-18
367
+
368
+ ### Added
369
+ - `vitrinka version` (and `--version`/`-V` for the bare number) — the installed
370
+ version, where it runs from (repo checkout / bun / pnpm / npm install), and
371
+ the last known update state from the notifier cache. No network, instant.
372
+
373
+ ### Fixed
374
+ - `vitrinka update` now updates through the package manager that OWNS the
375
+ running copy (bun / pnpm / npm, detected from the executable's path) and
376
+ verifies the running file actually changed — a bun-installed CLI used to
377
+ `npm i -g` into a shadowed prefix and stay stale forever, and update warns
378
+ loudly when another install still shadows it on PATH.
379
+
380
+ ## 1.15.0 — 2026-07-18
381
+
382
+ ### Added
383
+ - Update notifier v2 — the daily detached check now asks YOUR vitrinka server
384
+ first (new `GET /api/v1/version`: a deploy announces the version, works on
385
+ the mesh with npm unreachable) and falls back to the npm registry. Agent
386
+ shells (non-TTY — an AI session driving the CLI) see the
387
+ `update available … · run: vitrinka update` line on every run so the session
388
+ can offer the update; interactive terminals see it at most once a day.
389
+
390
+ ## 1.14.0 — 2026-07-18
391
+
392
+ ### Added
393
+ - `compose_board` question options accept **`cardRef`** — trace an option to a
394
+ card created in the SAME compose batch (template + inline cards share one ref
395
+ space), so a decision map and its per-option architecture diagrams land in
396
+ ONE call. `cardId` still traces to existing cards; picking flies only on
397
+ ⌘-click now (plain click just stages the answer).
398
+ - The built-in **`decision-map`** template is documented on `compose_board`:
399
+ structured params `{title, context, decisions:[{key, title, stakes, options,
400
+ multiSelect?, kind?: "text"}]}` render the whole brainstorm map — a
401
+ width-filling grid of merged decision tiles — deterministically server-side.
402
+
403
+ ## 1.13.0 — 2026-07-17
404
+
405
+ ### Added
406
+ - `vitrinka import <file>` + `vitrinka schema push` — refreshable ground-truth
407
+ diagrams from docker-compose / OpenAPI / SQL DDL / a live Postgres;
408
+ `--section` lands them inside a journey frame, `--rev` stamps the git SHA.
409
+ - Journey branch capture: `snap --next/--target` groups + journey-from-set.
410
+ - Unified **publish** skill (session · journey · docs · board · artifact).
411
+ - `compose_board` edges accept `fromRegion`/`toRegion`; `arrange` gains a
412
+ journey mode.
413
+
414
+ ### Fixed
415
+ - `add --file` hardened (out-of-root copies, symlinks, non-regular files);
416
+ `push` guards against a huge `--root` and reports tar failures legibly.
417
+ - `doctor` no longer health-checks every Claude MCP server.
418
+
419
+ ## 1.11.0 — 2026-07-15
420
+
421
+ ### Added
422
+ - `vitrinka upload <files…> --board <slug>` — put PDFs, documents, and images
423
+ on a board as cards straight from disk (the bytes never pass through an AI
424
+ context). PDFs land as live embedded document cards, other files as download
425
+ chips. Placement is intent-based: `--section "Name"` lands inside a journey
426
+ frame (grows to fit), `--anchor <cardId> [--side right|below]` docks beside a
427
+ card, and no flag = server free placement (never a 0,0 pile).
428
+
429
+ ## 1.10.1 — 2026-07-13
430
+
431
+ ### Changed
432
+ - Canonical domain is now **vitrinka.in** — the CLI/MCP default base URL,
433
+ skills and docs all point there. vitrinka.lovinka.com keeps working as an
434
+ alias; override per-machine with `VITRINKA_URL` as before. Re-run
435
+ `vitrinka install` (or `doctor --fix`) to re-register MCP on the new host.
436
+
437
+ ## 1.10.0 — 2026-07-13
438
+
439
+ ### Added
440
+ - `compose_board` question options accept `cardId` — the board draws a trace
441
+ wire from the option to the card it names, hovering glows it, and picking
442
+ flies the camera there. Pair it with the new `POST /artifact` params
443
+ (`section`, `device`, `anchor`/`side`): mockups land inside their take's
444
+ section frame, sized by device intent, and scale to fit their card
445
+ automatically (server-measured natural size).
446
+
447
+ ## 1.9.0 — 2026-07-12
448
+
449
+ ### Changed
450
+ - MCP registration moved to the remote `/mcp` endpoint (streamable HTTP) —
451
+ no local stdio process per session; `vitrinka install`/`doctor --fix`
452
+ re-register automatically. The old stdio bin is deprecated.
453
+
454
+ ## 1.8.3 — 2026-07-11
455
+
456
+ ### Fixed
457
+ - Interactive prompts (`install`'s operator question, any `promptLine`) strip
458
+ ANSI escape sequences and control characters — arrow-key edits no longer
459
+ persist raw `ESC[D`/`ESC[C` bytes into the operator name (which every fresh
460
+ browser adopted as its board identity). `vitrinka operator <name>` sanitizes
461
+ the same way, and the server now rejects control characters with 422.
462
+
463
+ ## 1.8.2 — 2026-07-11
464
+
465
+ ### Added
466
+ - Desktop-app flag: `~/.config/vitrinka/desktop-app` is the one canonical
467
+ "is Vitrinka.app installed" answer (content = app path). Stamped by
468
+ `apps/desktop make install`, re-synced by `install-claude` and `doctor`.
469
+ - `install-claude` adds a second **⧉ app** footer badge (only when the app is
470
+ installed) whose `vitrinka://` deep link opens the board in Vitrinka.app.
471
+ - `vitrinka open` opens the board in Vitrinka.app when installed;
472
+ `--browser` forces the browser.
473
+
474
+ ## 1.8.1 — 2026-07-11
475
+
476
+ ### Added
477
+ - `install-claude` now also wires a `SessionStart` hook
478
+ (`~/.claude/hooks/vitrinka-board-link.sh`) that puts the repo's live board
479
+ URL into session context at start — the clickable 🧷 footer badge exists
480
+ from message one instead of waiting for a board URL to be mentioned.
481
+ `vitrinka doctor` reports (and `--fix` repairs) the hook; `uninstall`
482
+ removes it.
483
+
484
+ ## 1.8.0 — 2026-07-11
485
+
486
+ ### Changed
487
+ - Skills now distribute EXCLUSIVELY as the vitrinka plugin — for Claude Code
488
+ (`claude plugin install vitrinka@lovinka`) AND Codex (`codex plugin add
489
+ vitrinka`), both from the `LEFTEQ/vitrinka` marketplace. `vitrinka install`,
490
+ `doctor --fix` and `update` install/refresh the plugin in every runtime CLI
491
+ they find; the npm package no longer bundles the skills.
492
+ - Skills layout flattened: `listen` is a first-class skill
493
+ (`/vitrinka:listen` in Claude Code, `$listen` in Codex).
494
+
495
+ ### Removed
496
+ - `vitrinka install-skills` — superseded by the plugin. `vitrinka uninstall`
497
+ still clears legacy `~/.claude/skills` copies from pre-plugin machines.
498
+
499
+ ## 1.6.0 — 2026-07-08
500
+
501
+ ### Added
502
+ - `vitrinka update` — updates the CLI (git pull in a checkout, `npm i -g` when
503
+ behind the registry), prints what's new, and refreshes the installed skills
504
+ and Claude UI wiring.
505
+ - Status-first onboarding: `vitrinka install` now prints a ✓/✗ setup table and
506
+ handles everything install.sh used to (MCP registration, write token,
507
+ operator persona, env checks) — asking only for what's missing.
508
+ - `vitrinka uninstall [--purge]` — clean offboarding (skills, shim, completion,
509
+ Claude wiring, MCP registration; `--purge` also removes token + operator).
510
+ - `vitrinka doctor --fix` — repairs stale skills, a stale/missing shim, a lost
511
+ MCP registration, and the Claude UI wiring.
512
+ - `vitrinka open [--qr]` — opens the capture root's live board; `--qr` renders
513
+ a terminal QR code to scan with the iPad.
514
+ - `vitrinka status` — session dashboard: live board, open work queue, and the
515
+ listener lease for the current repo+branch.
516
+ - Passive update notifier (one dim line, cached daily, npm installs only) and a
517
+ first-run hint on fully unconfigured machines.
518
+
519
+ ### Removed
520
+ - `install.sh` — the CLI is the installer now: `vitrinka install` (or
521
+ `node pkg/src/cli.ts install` from a checkout).
522
+
523
+ ## 1.5.0 — 2026-07-08
524
+
525
+ - project-memory MCP tools + link/board compose vocabulary (pre-changelog release).
package/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # @vitrinka/cli
2
+
3
+ The [vitrinka](https://github.com/FixIt-Technologies/vitrinka) CLI — capture
4
+ screenshots, publish artifact **sets**, scaffold interactive artifacts, and arm
5
+ the annotation-board `watch` monitor that feeds work to a listening AI session.
6
+
7
+ Since **3.0.0** the CLI is a compiled **Go binary**. This npm package is the
8
+ launcher: `bin/vitrinka.js` resolves the binary for your platform and execs it.
9
+ The binary arrives through per-platform packages declared as
10
+ `optionalDependencies` (`@vitrinka/cli-darwin-arm64` and friends), so npm
11
+ fetches it from whatever registry your machine already uses — no postinstall
12
+ download, no network surprise in sandboxed CI or behind a corporate proxy.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ npm i -g @vitrinka/cli
18
+ vitrinka install # one-command machine setup
19
+ ```
20
+
21
+ `vitrinka install` IS the onboarding: it prints a ✓/✗ table of every component,
22
+ silently installs the harmless ones (the skills plugin into each runtime CLI it
23
+ finds, a `vitrinka` shim on PATH, shell completion — all reversible), then asks
24
+ `[Y/n]` only for the config-touchers: MCP registration, the write token (silent
25
+ input, → the OS keyring) and the operator name.
26
+
27
+ ```bash
28
+ vitrinka doctor # server, token, operator, skills, shim, MCP
29
+ vitrinka doctor --fix # repairs the repairable
30
+ vitrinka update # update the CLI and everything install put here
31
+ vitrinka uninstall # remove it all (--purge: token too)
32
+ ```
33
+
34
+ Installing with `--omit=optional` / `--no-optional` skips the binary by design.
35
+ The launcher then tells you which platform package is missing rather than
36
+ failing as "command not found".
37
+
38
+ ## MCP
39
+
40
+ The MCP server is **remote** — it runs inside the vitrinka server, so there is
41
+ nothing to install and nothing to keep up to date. Register it once:
42
+
43
+ ```bash
44
+ claude mcp add --scope user --transport http vitrinka https://vitrinka.ai/mcp \
45
+ --header "Authorization: Bearer $(vitrinka token)"
46
+ ```
47
+
48
+ For Claude Desktop or any other MCP client, add the equivalent HTTP entry:
49
+
50
+ ```json
51
+ {
52
+ "mcpServers": {
53
+ "vitrinka": {
54
+ "type": "http",
55
+ "url": "https://vitrinka.ai/mcp",
56
+ "headers": { "Authorization": "Bearer …" }
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ > The stdio `vitrinka-mcp` bin was **removed in 3.0.0**. If you have a
63
+ > registration pointing at `npx -y --package=@vitrinka/cli vitrinka-mcp`
64
+ > (or at a `mcp/server.ts` repo shim), replace it with the HTTP form above —
65
+ > `vitrinka install` and `vitrinka doctor --fix` will do it for you.
66
+
67
+ vitrinka is reachable over the WireGuard mesh — bring the VPN up (or point
68
+ `VITRINKA_BASE_URL` at any reachable host) before use.
69
+
70
+ ## Configuration (env)
71
+
72
+ | Var | Default | Purpose |
73
+ |---|---|---|
74
+ | `VITRINKA_URL` / `VITRINKA_BASE_URL` | `https://vitrinka.ai` | vitrinka server base URL. `VITRINKA_URL` wins, then `VITRINKA_BASE_URL`; the CLI's `--base` flag overrides both. |
75
+ | `VITRINKA_TOKEN` | — | Bearer write token. Falls back to the OS keyring / `~/.config/vitrinka/`. Required only by the **mutating** calls; read calls work unauthenticated. |
76
+ | `VITRINKA_OPERATOR` | — | Operator persona name. When set, write calls carry `X-Board-Actor: <name>` so the board credits the operator — agent-authored content keeps its explicit `claude` attribution. |
77
+
78
+ ## Trustworthy project index
79
+
80
+ `vitrinka setup-project` or `vitrinka index configure` creates the
81
+ repository-owned `vitrinka.config.json`. The interactive picker chooses
82
+ extension groups and any depth of directory tree, then shows the exact file
83
+ manifest before approval. Choosing "later" writes an explicit disabled policy
84
+ and uploads nothing.
85
+
86
+ The index contains repository-relative paths, derived routes, and repository
87
+ command names only — never source bytes, absolute paths, remotes, command
88
+ descriptions, or files from `~/.claude`. `.gitignore` is an unconditional deny
89
+ layer even for tracked files; detected `.claudeignore` is offered as another;
90
+ untracked files require an explicit advanced opt-in; credential/key filenames
91
+ and binary/generated assets are blocked by both client and server safety floors.
92
+
93
+ ```bash
94
+ vitrinka index configure # edit, preview, approve, then refresh
95
+ vitrinka index status # policy + local approval/upload receipt
96
+ vitrinka index --dry-run # exact paths, no network request
97
+ vitrinka index --explain path/to/file # winning selection or deny rule
98
+ ```
99
+
100
+ The config schema is served by the deployment at
101
+ `https://vitrinka.ai/static/vitrinka.config.schema.json` — reference it from
102
+ `$schema` in your `vitrinka.config.json` for editor completion.
103
+
104
+ ## Desktop app
105
+
106
+ `~/.config/vitrinka/desktop-app` is the ONE canonical "is Vitrinka.app installed
107
+ here" answer (content = the app path). `apps/desktop`'s `make install` stamps it;
108
+ `doctor` and `setup-project` re-sync it to reality. `vitrinka open` uses it to
109
+ open boards in the app (pass `--browser` to force the browser), and
110
+ `vitrinka edit [path]` focuses the resident app on a file or project.
111
+
112
+ ## Development
113
+
114
+ The CLI source lives in the vitrinka repo — `cmd/vitrinka` + `internal/cli/`:
115
+
116
+ ```bash
117
+ go build -o /tmp/vitrinka ./cmd/vitrinka
118
+ go test ./internal/cli/...
119
+ ```
120
+
121
+ This package carries no implementation; it is the npm front door only.
122
+
123
+ ## License
124
+
125
+ MIT
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ // The npm front door for the Go binary (decisions D7 and D12).
3
+ //
4
+ // `npm i -g @vitrinka/cli` and `npx @vitrinka/cli` must keep working
5
+ // exactly as they do today — it is currently the ONLY documented way to install
6
+ // this tool, and every skill, doc and agent instruction says so. So the npm
7
+ // package survives the port; what changes is that it now launches a compiled
8
+ // binary instead of being the implementation.
9
+ //
10
+ // The binary arrives through per-platform packages declared as
11
+ // optionalDependencies (esbuild's pattern), NOT through a postinstall script
12
+ // that downloads one. That distinction is the whole design:
13
+ //
14
+ // - A postinstall download needs network access at install time, which is
15
+ // blocked in sandboxed CI, in air-gapped environments, and behind exactly
16
+ // the corporate proxies decision D13 exists for.
17
+ // - optionalDependencies are resolved by npm itself, so they come from
18
+ // whatever registry the machine is already configured to use — including
19
+ // the bank's internal mirror (D12) — with no extra machinery.
20
+ // - The lockfile records them, so an install is reproducible.
21
+ //
22
+ // npm installs only the optional dependency matching the host platform and
23
+ // silently skips the rest, which is why all of them can be declared at once.
24
+
25
+ const { spawnSync } = require('node:child_process');
26
+
27
+ const WINDOWS = process.platform === 'win32';
28
+ const PKG = `@vitrinka/cli-${process.platform}-${process.arch}`;
29
+ const BIN = `vitrinka${WINDOWS ? '.exe' : ''}`;
30
+
31
+ function resolveBinary() {
32
+ try {
33
+ return require.resolve(`${PKG}/bin/${BIN}`);
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ const binary = resolveBinary();
40
+
41
+ if (!binary) {
42
+ // Say which platform package is missing and why it might be. "command not
43
+ // found" here would send someone to debug their PATH, when the real cause is
44
+ // almost always an --omit=optional install or an unsupported platform.
45
+ process.stderr.write(
46
+ `\n vitrinka: no binary for ${process.platform}-${process.arch}\n\n` +
47
+ ` The platform package ${PKG} is not installed.\n\n` +
48
+ ` Reinstall without omitting optional dependencies\n` +
49
+ ` npm install -g @vitrinka/cli\n\n` +
50
+ ` If your installer is configured with --omit=optional or\n` +
51
+ ` --no-optional, the binary is skipped by design; allow optional\n` +
52
+ ` dependencies, or install the platform package directly\n` +
53
+ ` npm install -g ${PKG}\n\n`,
54
+ );
55
+ process.exit(1);
56
+ }
57
+
58
+ // stdio: 'inherit' is LOAD-BEARING, not a default worth changing.
59
+ //
60
+ // The Go CLI decides what to do by asking whether stdin and stdout are
61
+ // terminals: bare `vitrinka` opens the dashboard on a TTY and prints usage
62
+ // otherwise, and every prompt and spinner branches the same way. Piping the
63
+ // child's streams here would make the binary see pipes in every case — so the
64
+ // dashboard would never open for anyone who installed through npm, which is
65
+ // everyone. Inheriting hands the real terminal straight through.
66
+ const result = spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' });
67
+
68
+ if (result.error) {
69
+ process.stderr.write(`\n vitrinka: could not run ${binary}\n ${result.error.message}\n\n`);
70
+ process.exit(1);
71
+ }
72
+
73
+ // A child killed by a signal has a null status. Reporting the conventional
74
+ // 128+signal keeps `vitrinka ... ; echo $?` and CI's failure detection honest;
75
+ // exiting 0 here would make a SIGKILLed run look successful.
76
+ if (result.signal) {
77
+ const SIGNALS = { SIGINT: 2, SIGQUIT: 3, SIGKILL: 9, SIGTERM: 15 };
78
+ process.exit(128 + (SIGNALS[result.signal] || 0));
79
+ }
80
+
81
+ process.exit(result.status === null ? 1 : result.status);
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@vitrinka/cli",
3
+ "version": "3.3.0",
4
+ "description": "vitrinka CLI — capture and publish artifact sets, drive the annotation-board work queue. Thin npm launcher for the single-binary Go CLI.",
5
+ "bin": {
6
+ "vitrinka": "bin/vitrinka.js"
7
+ },
8
+ "files": [
9
+ "bin",
10
+ "README.md",
11
+ "CHANGELOG.md"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "optionalDependencies": {
17
+ "@vitrinka/cli-darwin-arm64": "3.3.0",
18
+ "@vitrinka/cli-darwin-x64": "3.3.0",
19
+ "@vitrinka/cli-linux-arm64": "3.3.0",
20
+ "@vitrinka/cli-linux-x64": "3.3.0",
21
+ "@vitrinka/cli-win32-arm64": "3.3.0",
22
+ "@vitrinka/cli-win32-x64": "3.3.0"
23
+ },
24
+ "keywords": [
25
+ "vitrinka",
26
+ "lovinka",
27
+ "cli",
28
+ "mcp",
29
+ "model-context-protocol",
30
+ "screenshots",
31
+ "ai"
32
+ ],
33
+ "author": "Lovinka",
34
+ "license": "MIT",
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/FixIt-Technologies/vitrinka.git",
38
+ "directory": "npm/vitrinka"
39
+ }
40
+ }