@plinth-music/cli 0.3.0 → 0.5.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,136 @@
1
+ # Changelog
2
+
3
+ Notable changes to `@plinth-music/cli`. Grouped by what a user notices, not by PR.
4
+
5
+ ## 0.5.0 — 2026-08-14
6
+
7
+ Seven PRs since `0.4.0` (`v0.4.0..846b996`). Three new commands, and the generated
8
+ context an agent reads at session start stops making claims that were not true.
9
+
10
+ ### Three new commands
11
+
12
+ - **`plinth backlinks <entity>`** — answers "what points at this?" from the terminal,
13
+ and says what it left out rather than returning a confident partial answer. Resolves
14
+ by slug **and** display name: the corpus links artists as `[[Tors]]`, not
15
+ `[[tors]]`, so a slug-only resolver would have answered for the name nobody types.
16
+ An ambiguous query returns both candidates and says why the first is first.
17
+ - **`plinth declare`** — lets an agent declare a work product, so the cockpit panel has
18
+ something to render instead of inferring it.
19
+ - **`plinth review-tier`** — computes the code-review tier from the diff rather than
20
+ from whatever the operator remembered.
21
+
22
+ ### The generated workspace map stops lying
23
+
24
+ The map is injected into every agent session in a workspace, so a false line there
25
+ produces confident wrong answers rather than a visible failure. It now **names
26
+ `files/`** — contract lookups had been routed to `documents/`, which holds 31 notes,
27
+ while `files/` holds 193 documents including every executed agreement. The three
28
+ **render-only regions** (`## Contacts`, `## Recent activity`, `## Tasks`) now say so
29
+ at render time, having silently discarded edits across 182 mirror files. And the
30
+ `claude plugin add plinth-ai` line is gone; it pointed at a package that exists in no
31
+ registry and no repo.
32
+
33
+ ### Over-cap files fail loudly instead of vanishing
34
+
35
+ A file too large to sync was dropped while `plinth status` reported "No writes
36
+ rejected". Over-cap now routes into `rejected` in `state.json`, so `status` reports it.
37
+
38
+ ⚠️ **Behaviour change, worth reading before upgrading.** The client size ceiling drops
39
+ from 25 MiB to the largest size measured to succeed against the platform. **Files
40
+ between roughly 4 MB and 25 MiB that previously appeared to sync are now refused,
41
+ loudly.** They were not arriving before either — the platform rejected them ahead of
42
+ the route, and the log printed the client's own constant as though it had caused the
43
+ rejection. The number is now the measured platform ceiling, labelled as the platform's
44
+ rather than Plinth's. **This path has not been exercised against production; the
45
+ measurement is inherited from 12 August.**
46
+
47
+ ### Also
48
+
49
+ - Memory indexes state their own age, so silence stops reading like settledness.
50
+ - The grounding block tells an agent that other MCP servers may exist, and how to find
51
+ out.
52
+
53
+ ## 0.4.0 — 2026-08-06
54
+
55
+ 56 commits of product work since `0.3.0` (`v0.3.0..8c921e4`). `0.3.0` shipped four
56
+ commands — `login`, `sync`, `start`, `version` — and synced a single entity type,
57
+ documents. This release is most of a working daemon.
58
+
59
+ ### Five new commands
60
+
61
+ - **`plinth status`** — daemon liveness, last sync and per-type counts, and how many
62
+ destructive batches are being held. Also warns when `dist/` is behind the checkout,
63
+ so a stale bundle can't be mistaken for the merged code (source-install only; a
64
+ registry install has no checkout to compare against and stays silent).
65
+ - **`plinth confirm`** — review and release the destructive batches the daemon
66
+ quarantines. Apply, or `--discard`. `--all` is gated behind rendering every batch
67
+ first and a final default-No.
68
+ - **`plinth refresh-context`** — regenerate the workspace-root `CLAUDE.md` from the
69
+ current schema and workspace. Your block between the `<!-- BEGIN: user-customisable -->`
70
+ markers is preserved verbatim; `CLAUDE.local.md` is never touched.
71
+ - **`plinth grounding`** — print the session-start grounding block (current date,
72
+ entity resolution, write confirmation, workspace rules, workspace memory, user
73
+ memory). Invoked by the generated Claude Code SessionStart hook.
74
+ - **`plinth voice-gate`** — gate agent-originated copy against the workspace voice
75
+ rubric. `--hook` runs it as a Claude Code PreToolUse hook that blocks
76
+ non-compliant Gmail drafts; direct mode gates a file or stdin and can print the
77
+ raw verdict as JSON.
78
+
79
+ ### Sync covers the workspace, not just documents
80
+
81
+ `0.3.0` synced documents only — `plinth sync` was a one-shot pull, and `plinth start`
82
+ carried a watcher that pushed local edits for that one type. `0.4.0` syncs
83
+ **documents, projects, tasks, artists, meetings and threads**, each on its own entity
84
+ strategy, in both directions. Alongside that:
85
+
86
+ - **Ambient pull** — `plinth start` now pulls continuously rather than once at boot.
87
+ - **A user-writable `files/` subtree** — drop any file into the mirror and it syncs.
88
+ - **Rendered read-only blocks** in the mirror: artist contacts in `_artist.md`, a
89
+ bounded "Recent activity" comment tail on tasks and projects, and project-as-rollup
90
+ task lists in `projects/<slug>.md`.
91
+ - **Documents round-trip raw markdown** — the HTML conversion layer is gone. Frontmatter
92
+ (`category`, `is_context_doc`) round-trips faithfully.
93
+ - **`~/.plinth/daemon.log`** — live push/pull is visible instead of silent.
94
+
95
+ ### Your local edits are harder to lose
96
+
97
+ Most of this release's fixes are one shape: the daemon must never silently discard
98
+ work you did on disk.
99
+
100
+ - Diverged local edits are reconciled at boot instead of being overwritten.
101
+ - A singleton pull no longer clobbers un-pushed local edits.
102
+ - Bulk deletes and gutting overwrites are quarantined for `plinth confirm` rather
103
+ than pushed.
104
+ - Task-mirror conflicts are field-typed, and validation failures are written back
105
+ into the file as a `# sync-error` block instead of vanishing.
106
+ - Rate-limit bursts (429) are throttled and retried, and anything still unsynced is
107
+ recorded rather than dropped.
108
+ - Renames are classified against a refreshed inode at boot, so a stale one can't turn
109
+ a rename into a delete-plus-create.
110
+ - Push failures surface the server's own error message instead of a bare 400.
111
+ - Untracked files already on disk at daemon boot are discovered rather than ignored,
112
+ and the `files/` subtree is scaffolded at boot instead of deadlocking on its own
113
+ absence.
114
+
115
+ ### Context and grounding for agents
116
+
117
+ - A workspace-root `CLAUDE.md` and per-artist `CLAUDE.md` / `memory.md` /
118
+ `daily-log.md` are generated on sync.
119
+ - The workspace and per-artist maps are a content index, not just a folder structure.
120
+ - `workspace-rules.md`, `workspace-memory.md` and a member-private user-memory lane
121
+ sync bidirectionally.
122
+ - Dates ground to the mapped calendar rather than the retired `key_dates` table.
123
+
124
+ ### Notes
125
+
126
+ - Requires Node >= 20. The keychain integration (`@napi-rs/keyring`) installs a
127
+ native prebuild for your platform: macOS Keychain, Windows Credential Manager, or
128
+ Linux Secret Service.
129
+ - `dist/build-stamp.json` ships in the tarball and records the git SHA the bundle was
130
+ built from.
131
+
132
+ ## 0.3.0 — 2026-05-20
133
+
134
+ First published release. `plinth login` with OS-keychain PAT storage, `plinth sync`
135
+ (documents, one-shot pull), an early `plinth start` with a push watcher, and
136
+ `plinth version`.
package/README.md CHANGED
@@ -2,35 +2,44 @@
2
2
 
3
3
  Plinth capstone sync daemon and CLI. Mirrors your Plinth workspace to `~/Plinth/<workspace>/` and keeps it bidirectionally synced. AI-native: pair with Claude Code or any LLM agent for context-aware artist management.
4
4
 
5
- **Status: early access. `login` and `sync` (pull-only, documents) are implemented; the watcher and other entity types land in subsequent PRs. See V1_SPEC §5 M3 in the plinth monorepo for the full milestone plan.**
5
+ **Status: early access.** Two-way sync runs as a daemon across documents, projects, tasks, artists, meetings, threads and a user-writable `files/` subtree. See `V1_SPEC` §5 M3 in the plinth monorepo for the full milestone plan, and [`CHANGELOG.md`](CHANGELOG.md) for what landed when.
6
6
 
7
- ## Commands
7
+ ## Install
8
8
 
9
- Implemented today:
9
+ ```sh
10
+ npm i -g @plinth-music/cli
11
+ ```
10
12
 
11
- - `plinth login --workspace <slug>` — issue a PAT in the browser, paste it back, store in the OS keychain (macOS Keychain / Linux Secret Service / Windows Credential Manager).
12
- - `plinth sync [--workspace <slug>]` — one-shot pull of documents into `~/Plinth/<workspace>/`. Defaults to the active workspace if `--workspace` is omitted.
13
+ Requires Node >= 20. A Homebrew tap (signed + notarised) is planned; npm is the only install path today.
13
14
 
14
- Planned (not yet implemented):
15
+ ## Getting started
15
16
 
16
- - `plinth start` — run the sync daemon (file watcher + cloud subscription).
17
- - `plinth status` — print last-synced-at per entity type and pending changes.
18
- - `plinth refresh-context` — regenerate `CLAUDE.md` from the current Plinth schema + workspace.
19
- - `plinth export workspace` — generate an export bundle.
20
- - `plinth update` — detect install method (brew vs npm-global) and upgrade in place.
21
- - `plinth logout --workspace <slug>` — revoke local PAT reference, retain mirror files.
17
+ ```sh
18
+ plinth login --workspace <slug> # issue a PAT in the browser, paste it back
19
+ plinth sync # one-shot pull into ~/Plinth/<slug>/
20
+ plinth start # run the daemon: continuous pull + watch + push
21
+ ```
22
22
 
23
- ## Install (once published)
23
+ ## Commands
24
24
 
25
- Neither path is published yet.
25
+ - `plinth login --workspace <slug>` — issue a personal access token in the browser, paste it back, store it in the OS keychain (macOS Keychain / Linux Secret Service / Windows Credential Manager).
26
+ - `plinth sync [--workspace <slug>]` — one-shot pull into `~/Plinth/<workspace>/`. Also generates the workspace-root `CLAUDE.md` (a thin TOC + entity model + skill pointers) and an empty `CLAUDE.local.md` stub on first sync, and silently refreshes `CLAUDE.md` on a schema-version change. Defaults to the active workspace if `--workspace` is omitted.
27
+ - `plinth start` — run the long-running sync daemon: pull the latest, then watch the mirror for local edits and push them. Logs to `~/.plinth/daemon.log`.
28
+ - `plinth status` — local sync state: daemon liveness, last sync and per-type counts, and any destructive batches being held. Warns when a source install's `dist/` is behind its checkout.
29
+ - `plinth confirm` — review and release destructive batches the daemon has quarantined (apply, or `--discard`).
30
+ - `plinth refresh-context [--workspace <slug>]` — force-regenerate the workspace-root `CLAUDE.md` from the current Plinth schema + workspace. The user-customisable block between the `<!-- BEGIN: user-customisable -->` / `<!-- END -->` markers is always preserved verbatim; `CLAUDE.local.md` is never touched.
31
+ - `plinth grounding` — print the session-start grounding block (current date, entity resolution, write confirmation, workspace rules, workspace memory, user memory). Invoked by the generated Claude Code SessionStart hook.
32
+ - `plinth voice-gate` — gate agent-originated copy against the workspace voice rubric. `--hook` runs it as a Claude Code PreToolUse hook that blocks non-compliant Gmail drafts; direct mode takes `--file <path>` or stdin and prints the verdict (`--json` for the raw response).
33
+ - `plinth backlinks <target>` — report what points at a target, by reading the local mirror rather than making a network call. `<target>` can be a mirror path (`projects/breadcrumb-trail.md` — including a mirror-root file like `CLAUDE.md`), a bare name (`breadcrumb-trail`), or a wikilink target as written (`Aligned Timeline - 4 June 2026`). Output is file paths with line numbers and the link as written; `--paths-only` emits deduped paths for piping, and stdout carries the answer ALONE — withheld rows never reach the pipe, whatever the display flags say. **Every narrowing is disclosed, and the counts print even when they are zero**, because a filter the caller cannot see is indistinguishable from an empty corpus, and a disclosure that only appears when it bites gives a reader no baseline to judge it against. Two footers carry them: links withheld from the answer (daemon-rendered marker blocks, code spans / HTML comments, and links to a bare name several files answer to), and the corpus line — which workspace was searched, how much of the mirror was read against its full size, and what went unread: `this-fiction · 859 of 880 files scanned (21 non-markdown, 0 unreadable) in 34ms`. `--unfiltered` shows the withheld rows, each tagged with the narrowing that hid it. Non-markdown files are not scanned for links but **do** count as existing, so asking about a PDF in `files/` answers rather than denying it. Exit codes: `0` results found or the target file exists, `1` no such target and nothing links to that name, `2` a bare name several files answer to (it lists them rather than guessing — and every candidate it prints resolves when pasted back), `3` no active workspace, an unknown or malformed workspace slug, or a mirror with nothing to search.
34
+ - `plinth declare <path> --scratchpad <dir> [--label <text>]` — declare a file in the session scratchpad as a work product, so it appears in the cockpit's work-products panel instead of being lost with the session. Appends one line to an append-only `.plinth-deliverables.jsonl` manifest inside `<dir>`; the manifest records the **path, never the content**, so the panel always points at the live file rather than a snapshot that can go stale. Grounding primitive (j) instructs the agent to run this the moment it writes a deliverable whose only home is the scratchpad. **The scratchpad directory is required and never inferred** (`--scratchpad`, or `PLINTH_SCRATCHPAD_DIR`): this repo learns it from neither the app that spawns the terminal nor the harness that told the agent, so a guessed root would silently widen the containment check every refusal rests on. Refuses, with exit 1, anything outside that directory — including a symlink whose target is outside it — plus a directory, a file that does not exist yet, and a missing root.
35
+ - `plinth review-tier [--repo <path>] [--base <ref>]` — print the code-review tier the current diff earns, `low` or `high`, for use as `/code-review $(plinth review-tier)`. Reads the diff against the merge base — committed, uncommitted **and untracked**, since a brand-new never-added file is invisible to `git diff` and would otherwise be classified as absent — and routes `high` on the risk classes the review rubric names: auth/RLS, optimistic concurrency/CAS, financial math, data-moving migrations, and large **and** multi-subsystem together. **It is a router, not a ceiling**: size alone never escalates, because a blanket cap would kill the concurrency reviews that earn their keep. **The output contract is the safety story.** It is invoked inside `$( )`, where an empty stdout or a non-zero exit would collapse the caller to an unqualified `/code-review` that silently inherits whatever global effort is configured — safe by accident, and indistinguishable from this working. So stdout carries **exactly one token and nothing else**, the exit code is **always 0**, and the reasoning goes **unconditionally to stderr** on both tiers. Anything it cannot classify — not a git repo, no merge base, no default branch, an empty diff — prints `high` and says why on stderr.
36
+ - `plinth version` — print the installed version.
26
37
 
27
- ```sh
28
- # npm (cross-platform)
29
- npm i -g @plinth-music/cli
38
+ Planned (not yet implemented):
30
39
 
31
- # Homebrew (macOS, signed + notarised)
32
- brew install plinth-music/tap/plinth-cli
33
- ```
40
+ - `plinth export workspace` — generate an export bundle.
41
+ - `plinth update` — detect install method (brew vs npm-global) and upgrade in place.
42
+ - `plinth logout --workspace <slug>` — revoke the local PAT reference, retain mirror files.
34
43
 
35
44
  ## Develop
36
45
 
@@ -39,7 +48,7 @@ Requires [Bun](https://bun.sh/) (latest).
39
48
  ```sh
40
49
  bun install
41
50
  bun run build # produces dist/cli.js
42
- bun test # builds, then runs the smoke test
51
+ bun test # builds, then runs the suite
43
52
  bun run typecheck # strict tsc, no emit
44
53
  ```
45
54
 
@@ -50,6 +59,8 @@ The built CLI is a standard Node-compatible ESM bundle with a `#!/usr/bin/env no
50
59
  ./dist/cli.js --help
51
60
  ```
52
61
 
62
+ Releasing is documented in [`docs/RELEASING.md`](docs/RELEASING.md).
63
+
53
64
  ## License
54
65
 
55
66
  MIT — see `LICENSE`.
@@ -0,0 +1,5 @@
1
+ {
2
+ "sha": "aa7af2b93debdba13e6abbbc8689c54d66a2c8d5",
3
+ "dirty": false,
4
+ "built_at": "2026-08-14T14:09:40.708Z"
5
+ }