@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 +136 -0
- package/README.md +32 -21
- package/dist/build-stamp.json +5 -0
- package/dist/cli.js +19976 -78938
- package/package.json +5 -8
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
|
|
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
|
-
##
|
|
7
|
+
## Install
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
```sh
|
|
10
|
+
npm i -g @plinth-music/cli
|
|
11
|
+
```
|
|
10
12
|
|
|
11
|
-
|
|
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
|
-
|
|
15
|
+
## Getting started
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
##
|
|
23
|
+
## Commands
|
|
24
24
|
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
# npm (cross-platform)
|
|
29
|
-
npm i -g @plinth-music/cli
|
|
38
|
+
Planned (not yet implemented):
|
|
30
39
|
|
|
31
|
-
|
|
32
|
-
|
|
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
|
|
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`.
|