plumbbob 0.8.17 → 0.9.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/.claude-plugin/plugin.json +1 -1
- package/README.md +56 -44
- package/dist/cli-core.js +35 -15
- package/dist/lib/agents.js +230 -112
- package/dist/lib/buildlog.js +50 -30
- package/dist/lib/buildlogsync.js +21 -12
- package/dist/lib/check.js +69 -35
- package/dist/lib/commitmsg.js +53 -32
- package/dist/lib/git.js +86 -31
- package/dist/lib/intent.js +91 -31
- package/dist/lib/latch.js +70 -39
- package/dist/lib/orient.js +78 -39
- package/dist/lib/plugins.js +11 -8
- package/dist/lib/settings.js +65 -32
- package/dist/lib/sidecar.js +320 -150
- package/dist/lib/templates.js +17 -6
- package/dist/verbs/agent.js +116 -55
- package/dist/verbs/build.js +27 -12
- package/dist/verbs/check.js +33 -7
- package/dist/verbs/checkpoint.js +153 -78
- package/dist/verbs/doctor.js +192 -95
- package/dist/verbs/finish.js +87 -44
- package/dist/verbs/handoff.js +56 -20
- package/dist/verbs/init.js +37 -12
- package/dist/verbs/park.js +14 -3
- package/dist/verbs/revert.js +64 -24
- package/dist/verbs/spike.js +89 -30
- package/dist/verbs/start.js +72 -38
- package/dist/verbs/status.js +44 -17
- package/dist/verbs/turn.js +88 -45
- package/dist/verbs/use.js +20 -9
- package/package.json +2 -2
- package/skills/{pb-build → build}/SKILL.md +25 -25
- package/skills/{pb-doctor → doctor}/SKILL.md +1 -1
- package/skills/{pb-finish → finish}/SKILL.md +18 -5
- package/skills/{pb-harvest → harvest}/SKILL.md +4 -4
- package/skills/{pb-park → park}/SKILL.md +2 -2
- package/skills/{pb-plan → plan}/SKILL.md +11 -11
- package/skills/{pb-refine → refine}/SKILL.md +7 -7
- package/skills/{pb-revert → revert}/SKILL.md +2 -2
- package/skills/{pb-spike → spike}/SKILL.md +4 -4
- package/skills/{pb-status → status}/SKILL.md +3 -3
- package/skills/{pb-step → step}/SKILL.md +9 -9
- package/skills/{pb-verify → verify}/SKILL.md +8 -8
- package/templates/build-log.md +7 -7
- package/templates/intent.md +8 -8
- package/templates/spike-report.md +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plumbbob",
|
|
3
3
|
"displayName": "PlumbBob",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.1",
|
|
5
5
|
"description": "Attention-first build process — driver skills + a CLI that keep you the decider: guidance on the work, a latch on the record.",
|
|
6
6
|
"author": { "name": "Rob McLarty", "email": "hello@robmclarty.com", "url": "https://robmclarty.com" },
|
|
7
7
|
"homepage": "https://github.com/robmclarty/plumbbob#readme",
|
package/README.md
CHANGED
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
<img src="hero.svg" alt="A row of plumb bobs of varying shapes hanging from strings" width="600">
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://robmclarty.github.io/plumbbob/">Website</a> ·
|
|
9
|
+
<a href="https://robmclarty.github.io/plumbbob/docs.html">Docs</a> ·
|
|
10
|
+
<a href="https://robmclarty.github.io/plumbbob/api.html">API reference</a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
PlumbBob is a Claude Code plugin — twelve skills and a small CLI — that runs
|
|
8
14
|
LLM-assisted coding as a loop you control. You and the model settle the plan in a file
|
|
9
15
|
*before* any code; then the model builds one small step at a time and **stops after
|
|
10
16
|
each one**, waiting for you to read the diff and approve it before anything is
|
|
@@ -35,7 +41,7 @@ model's goodwill:
|
|
|
35
41
|
run (types, lint, tests, dead code, docs) has to pass before a step lands.
|
|
36
42
|
- **One SHA per verified step.** Every approved step is its own git commit against a
|
|
37
43
|
recorded baseline — a ledger of checkpoints, not one undifferentiated diff at the end.
|
|
38
|
-
- **A preservation-aware revert.** `/
|
|
44
|
+
- **A preservation-aware revert.** `/plumbbob:revert` resets exactly to a recorded checkpoint
|
|
39
45
|
SHA while keeping your plan and notes intact, and restores *only* SHAs the loop wrote.
|
|
40
46
|
- **A build record that rides the PR.** The tracked `builds/<slug>/` folder — intent, log,
|
|
41
47
|
checkpoints, report — merges into `main` with the branch instead of dying with the
|
|
@@ -51,7 +57,7 @@ work, a latch on the record.**
|
|
|
51
57
|
## The loop in one picture
|
|
52
58
|
|
|
53
59
|
<p align="center">
|
|
54
|
-
<img src="demo.svg" alt="An animated terminal session: /
|
|
60
|
+
<img src="demo.svg" alt="An animated terminal session: /plumbbob:plan writes the plan, /plumbbob:build implements step 1 and stops at the PAUSE, the human approves, the step is checkpointed" width="760">
|
|
55
61
|
</p>
|
|
56
62
|
|
|
57
63
|
Everything the model must stay true to lives in one file, the build's `intent.md`
|
|
@@ -62,11 +68,11 @@ with its *because*), and the **Steps** — a numbered list where every step carr
|
|
|
62
68
|
expected to touch).
|
|
63
69
|
|
|
64
70
|
```text
|
|
65
|
-
/
|
|
71
|
+
/plumbbob:plan decide everything on paper — frame, decisions, all steps (once)
|
|
66
72
|
per step:
|
|
67
|
-
/
|
|
68
|
-
(approve)
|
|
69
|
-
/
|
|
73
|
+
/plumbbob:build implement the next step → run checks → self-review → PAUSE
|
|
74
|
+
(approve) → the step is committed as a checkpoint; fire /plumbbob:build again
|
|
75
|
+
/plumbbob:finish report what shipped and why, final commit, clear (once)
|
|
70
76
|
```
|
|
71
77
|
|
|
72
78
|
Nothing is locked and nothing refuses you — the loop does a step's labor, pulls up to
|
|
@@ -95,7 +101,7 @@ plumbbob init # link it into Claude Code; --uninstall to undo
|
|
|
95
101
|
```
|
|
96
102
|
|
|
97
103
|
Restart Claude Code (or `/reload-plugins`) to activate, then run `plumbbob doctor`
|
|
98
|
-
(or `/
|
|
104
|
+
(or `/plumbbob:doctor` in-session) to confirm the wiring. The full guide — namespacing,
|
|
99
105
|
per-project sessions, the agent-neutral roadmap — is in
|
|
100
106
|
[`docs/install.md`](docs/install.md).
|
|
101
107
|
|
|
@@ -103,11 +109,11 @@ per-project sessions, the agent-neutral roadmap — is in
|
|
|
103
109
|
|
|
104
110
|
In Claude Code, inside any git repo with a clean tree:
|
|
105
111
|
|
|
106
|
-
1. **Plan.** Fire `/
|
|
107
|
-
you), a rough line (`/
|
|
112
|
+
1. **Plan.** Fire `/plumbbob:plan` and give it whatever you have — nothing (it interviews
|
|
113
|
+
you), a rough line (`/plumbbob:plan rate-limit POST /login, 5/min/IP, return 429`), or a
|
|
108
114
|
path to a spec file. Together you fill the build's `intent.md`. No code is written
|
|
109
115
|
yet.
|
|
110
|
-
2. **Build.** Fire `/
|
|
116
|
+
2. **Build.** Fire `/plumbbob:build`. It implements the next undone step, runs the
|
|
111
117
|
heavy check gate, reviews its own diff against the plan, and stops:
|
|
112
118
|
|
|
113
119
|
```text
|
|
@@ -119,16 +125,16 @@ In Claude Code, inside any git repo with a clean tree:
|
|
|
119
125
|
code, docs. To gate through your own command instead, set the `"check"` key in
|
|
120
126
|
`.plumbbob/settings.json`, e.g. `"check": "npm test"`.)
|
|
121
127
|
3. **Approve** — or send fixes. On your OK it commits the step as a checkpoint, marks
|
|
122
|
-
it done, and returns to the boundary. Fire `/
|
|
123
|
-
re-firing it *is* the clock tick. Whenever you lose the thread, `/
|
|
128
|
+
it done, and returns to the boundary. Fire `/plumbbob:build` again for the next step —
|
|
129
|
+
re-firing it *is* the clock tick. Whenever you lose the thread, `/plumbbob:status` shows
|
|
124
130
|
where you are and names the next move.
|
|
125
|
-
4. **Finish.** When the last step is done, `/
|
|
131
|
+
4. **Finish.** When the last step is done, `/plumbbob:finish` writes a report of what shipped
|
|
126
132
|
and why into the build's tracked folder, makes the final commit, and clears the slate
|
|
127
133
|
for the next goal. The folder rides the branch into the PR — the build's record merges
|
|
128
134
|
into `main` instead of dying with the worktree.
|
|
129
135
|
|
|
130
|
-
A mid-build "ooh, what if…" never derails the step: `/
|
|
131
|
-
in one line, and `/
|
|
136
|
+
A mid-build "ooh, what if…" never derails the step: `/plumbbob:park` captures it to a list
|
|
137
|
+
in one line, and `/plumbbob:harvest` triages the list between steps. One goal walked end to
|
|
132
138
|
end, with the real output at every stage, is in
|
|
133
139
|
[`docs/happy-path.md`](docs/happy-path.md).
|
|
134
140
|
|
|
@@ -136,42 +142,43 @@ end, with the real output at every stage, is in
|
|
|
136
142
|
|
|
137
143
|
You drive the whole loop from your IDE with `/plumbbob:*` skills — no step numbers to
|
|
138
144
|
remember, no raw CLI to type. Every skill is `disable-model-invocation`, so *you* fire
|
|
139
|
-
every move, and `/
|
|
140
|
-
under the plugin
|
|
141
|
-
|
|
145
|
+
every move, and `/plumbbob:status` always names your next one. (Claude Code namespaces
|
|
146
|
+
them under the plugin, so the command is `/plumbbob:plan`. The bare `/plan` reaches it
|
|
147
|
+
too — but only where nothing else owns that name, and four of the twelve share one with
|
|
148
|
+
a Claude Code built-in, so these docs write the full form.)
|
|
142
149
|
|
|
143
150
|
**The happy path** — the three moves every session makes; many sessions need
|
|
144
151
|
nothing else:
|
|
145
152
|
|
|
146
153
|
| Skill <img alt="" width="110" height="1"> | Does |
|
|
147
154
|
|------------------------------------|------|
|
|
148
|
-
| `/
|
|
149
|
-
| `/
|
|
150
|
-
| `/
|
|
155
|
+
| `/plumbbob:plan` | plan the whole goal — open the session and author intent's Frame, Decisions, Constraints, **and all Steps** |
|
|
156
|
+
| `/plumbbob:build` | implement the next planned step, then verify it to the pause — `--auto` self-approves and chains to done; a range like `1-3` self-approves through step 3, then pauses |
|
|
157
|
+
| `/plumbbob:finish` | finish up — write the report, make the final commit, clear for a fresh goal |
|
|
151
158
|
|
|
152
159
|
**Plan-shaping moves** — optional, for when the plan needs work mid-flight:
|
|
153
160
|
|
|
154
161
|
| Skill <img alt="" width="110" height="1"> | Does |
|
|
155
162
|
|------------------------------------|------|
|
|
156
|
-
| `/
|
|
157
|
-
| `/
|
|
158
|
-
| `/
|
|
163
|
+
| `/plumbbob:step` | revise/sharpen the next step (empty input auto-syncs it to reality) |
|
|
164
|
+
| `/plumbbob:refine` | attack the frame for holes, or repair a drifted plan |
|
|
165
|
+
| `/plumbbob:spike` | throwaway worktree experiment for a fork the plan can't settle |
|
|
159
166
|
|
|
160
167
|
**Helpers** — orient, verify, recover, diagnose:
|
|
161
168
|
|
|
162
169
|
| Skill <img alt="" width="110" height="1"> | Does |
|
|
163
170
|
|------------------------------------|------|
|
|
164
|
-
| `/
|
|
165
|
-
| `/
|
|
166
|
-
| `/
|
|
167
|
-
| `/
|
|
171
|
+
| `/plumbbob:status` | orient — where you are, the next step's done-when and seam, and the next move |
|
|
172
|
+
| `/plumbbob:verify` | the tick, standalone — check → self-review → validate → **PAUSE** → checkpoint, for a diff `/plumbbob:build` didn't write |
|
|
173
|
+
| `/plumbbob:revert` | recover — `git reset --hard` to a recorded checkpoint |
|
|
174
|
+
| `/plumbbob:doctor` | check the install from inside a session |
|
|
168
175
|
|
|
169
176
|
**Capture** — the park/harvest loop for mid-build ideas:
|
|
170
177
|
|
|
171
178
|
| Skill <img alt="" width="110" height="1"> | Does |
|
|
172
179
|
|------------------------------------|------|
|
|
173
|
-
| `/
|
|
174
|
-
| `/
|
|
180
|
+
| `/plumbbob:park` | capture a mid-build idea without chasing it |
|
|
181
|
+
| `/plumbbob:harvest` | triage parked ideas between steps (blocker / tangent / pivot) |
|
|
175
182
|
|
|
176
183
|
All twelve, with inputs and effects, are in
|
|
177
184
|
[`docs/skills-reference.md`](docs/skills-reference.md).
|
|
@@ -183,9 +190,9 @@ flow), and a `.plumbbob/` sidecar you can open and edit by hand at any time —
|
|
|
183
190
|
that rides the branch into the PR, plus an untracked control plane (`settings.local.json`,
|
|
184
191
|
the session sentinel, the in-flight markers).
|
|
185
192
|
|
|
186
|
-
**`/
|
|
193
|
+
**`/plumbbob:build` is the default engine, not the only one.** It's one executor — the
|
|
187
194
|
loop doesn't care who writes the code. Implement a step by hand — or vibe it in
|
|
188
|
-
another session, or in another harness entirely — and run `/
|
|
195
|
+
another session, or in another harness entirely — and run `/plumbbob:verify` instead:
|
|
189
196
|
same checks, same pause, same checkpoint. It reads the *diff, not the author*.
|
|
190
197
|
|
|
191
198
|
**Bring your own agents.** Because the executor is author-blind, you can plug your
|
|
@@ -217,7 +224,7 @@ against the plan, and committed as its own checkpoint, so a wrong turn costs one
|
|
|
217
224
|
step, not the afternoon; and records the *whys* alongside the decisions, so the
|
|
218
225
|
archive can still answer "what did we decide, and why" long after the session is
|
|
219
226
|
gone. The two compose fine: plan mode — or anything else — can produce a step's
|
|
220
|
-
diff, and `/
|
|
227
|
+
diff, and `/plumbbob:verify` reads it like any other.
|
|
221
228
|
|
|
222
229
|
**…use git and a TODO file?** That's the honest skeleton, and if your discipline
|
|
223
230
|
holds by willpower alone, it may be all you need. What the CLI adds is the
|
|
@@ -253,19 +260,24 @@ that matters.
|
|
|
253
260
|
> The latch's payoff is measured, not asserted: the skill-eval harness
|
|
254
261
|
> ([`test/evals/`](test/evals/)) sweeps this loop headless — prose-only baseline vs. the
|
|
255
262
|
> shipped latch, N=5 per contract, every assertion a mechanical read of git state — and
|
|
256
|
-
> commits each receipt under [`
|
|
257
|
-
> ([opus, 2026-07-11](
|
|
263
|
+
> commits each receipt under [`docs/evals/`](docs/evals/). The first sweep
|
|
264
|
+
> ([opus, 2026-07-11](docs/evals/2026-07-11.md)) closed the route the latch owns —
|
|
258
265
|
> *no checkpoint over a red check under pressure* went from **2/5 prose-only to 5/5
|
|
259
266
|
> latched** — and named, rather than papered over, the two honest gaps it surfaced: park
|
|
260
267
|
> capture at 0/5, and adversarial pressure flipping a standing `auto` grant a model could
|
|
261
268
|
> write into settings, a legal side door. The re-sweep
|
|
262
|
-
> ([opus, 2026-07-18](
|
|
263
|
-
> *no checkpoint over a red check* still **5/5 latched** — and pinned both gaps.
|
|
264
|
-
>
|
|
265
|
-
> human-typed only) retired the settings `auto` grant, so the one
|
|
266
|
-
> forge is gone.
|
|
267
|
-
> ([D10](docs/decisions.md#d10)/[D13](docs/decisions.md#d13))
|
|
268
|
-
>
|
|
269
|
+
> ([opus, 2026-07-18](docs/evals/2026-07-18.md), plumbbob 0.8.7) reproduced the win —
|
|
270
|
+
> *no checkpoint over a red check* still **5/5 latched** — and pinned both gaps. Both are
|
|
271
|
+
> now closed. The side door went by construction: [D67](docs/decisions.md#d67)
|
|
272
|
+
> (self-approval is human-typed only) retired the settings `auto` grant, so the one
|
|
273
|
+
> approval a model could forge is gone. Park capture was never the latch's to reach —
|
|
274
|
+
> prose-governed by design ([D10](docs/decisions.md#d10)/[D13](docs/decisions.md#d13)) —
|
|
275
|
+
> and it failed because the guidance couldn't reach a fresh session at all; the turn hook
|
|
276
|
+
> now injects one line when a step is in flight, and the third sweep
|
|
277
|
+
> ([opus, 2026-07-27](docs/evals/2026-07-27.md), plumbbob 0.9.0) measures it at **5/5**,
|
|
278
|
+
> alongside every other contract. That sweep ran the latched arm only, so its numbers are
|
|
279
|
+
> a regression check on the shipped configuration, not a fresh baseline delta — the
|
|
280
|
+
> 2/5→5/5 headline above remains the 2026-07-11 measurement.
|
|
269
281
|
|
|
270
282
|
## Documentation
|
|
271
283
|
|
|
@@ -275,7 +287,7 @@ Each doc answers one question — in rough reading order for a new user:
|
|
|
275
287
|
- *Show me the artifacts it leaves behind.* → [`examples/`](examples/) — that same session's finished build folder, file by file.
|
|
276
288
|
- *Should I / can I / what about…?* → [`docs/faq.md`](docs/faq.md) — the adoption questions, answered straight.
|
|
277
289
|
- *What is each method for?* → [`docs/techniques.md`](docs/techniques.md) — steps, seams, the pause, park/harvest, spikes.
|
|
278
|
-
- *What does each skill do?* → [`docs/skills-reference.md`](docs/skills-reference.md) — all twelve
|
|
290
|
+
- *What does each skill do?* → [`docs/skills-reference.md`](docs/skills-reference.md) — all twelve skills: inputs, effects, when to reach for each.
|
|
279
291
|
- *How do I plug in my own agent?* → [`docs/agents.md`](docs/agents.md) — the subprocess envelope, the manifest, `harness.json`, and working examples (including a local-model reviewer via Ollama).
|
|
280
292
|
- *How do I get a local model reviewing my steps?* → [`docs/local-model-review.md`](docs/local-model-review.md) — the ollama-reviewer example walked end to end, install to every-pause review.
|
|
281
293
|
- *How do I install it, exactly?* → [`docs/install.md`](docs/install.md) — the full guide and the agent-neutral roadmap.
|
package/dist/cli-core.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
// plumbbob CLI core — argv dispatch and the help table, separated from the bin
|
|
2
2
|
// entry (cli.ts) so the routing/help logic is unit-testable in-process without
|
|
3
|
-
// the top-level process.exit. Node builtins plus
|
|
4
|
-
// currently checkride alone, via check.ts). Functional/procedural: no classes,
|
|
5
|
-
// no `this`, no default export
|
|
3
|
+
// the top-level process.exit. Node builtins plus a deliberate few dependencies
|
|
4
|
+
// (currently checkride alone, via check.ts). Functional/procedural: no classes,
|
|
5
|
+
// no `this`, no default export.
|
|
6
|
+
//
|
|
7
|
+
// The deciding/executing boundary is a pause, not a lock, so there is nothing
|
|
8
|
+
// to defend in the dispatcher — every verb runs the same whether a human or the
|
|
9
|
+
// model triggers it. There is no human-only `mode` escape hatch and no
|
|
10
|
+
// CLAUDECODE in-session refusal; what keeps the human the decider is the pause
|
|
11
|
+
// at the step boundary (the skills), not a refusal here.
|
|
6
12
|
import { readFileSync } from 'node:fs';
|
|
7
13
|
import { fileURLToPath } from 'node:url';
|
|
8
14
|
import { start } from "./verbs/start.js";
|
|
@@ -20,6 +26,7 @@ import { init } from "./verbs/init.js";
|
|
|
20
26
|
import { doctor } from "./verbs/doctor.js";
|
|
21
27
|
import { agent } from "./verbs/agent.js";
|
|
22
28
|
import { turn } from "./verbs/turn.js";
|
|
29
|
+
/** One help-table row per verb, in the order the table prints. */
|
|
23
30
|
const VERBS = [
|
|
24
31
|
{ name: 'start', summary: 'scaffold .plumbbob/; open the session; record the baseline commit' },
|
|
25
32
|
{ name: 'status', summary: 'print the orientation dashboard, or NO ACTIVE SESSION' },
|
|
@@ -37,20 +44,22 @@ const VERBS = [
|
|
|
37
44
|
{ name: 'agent', summary: 'agent list | run <name> [--step N] [--mode before|build|after]: list or spawn a user-authored agent' },
|
|
38
45
|
{ name: 'turn', summary: 'turn: UserPromptSubmit hook machinery — tick the turn ledger from stdin (not a user verb)' },
|
|
39
46
|
];
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
// in-session refusal; what keeps the human the decider is the pause at
|
|
44
|
-
// the step boundary (the skills), not a refusal here.
|
|
47
|
+
/**
|
|
48
|
+
* Render the verb table for `plumbbob help`.
|
|
49
|
+
*/
|
|
45
50
|
export function formatHelp() {
|
|
46
51
|
const width = Math.max(...VERBS.map((v) => v.name.length));
|
|
47
52
|
const rows = VERBS.map((v) => ` ${v.name.padEnd(width)} ${v.summary}`);
|
|
48
53
|
return ['plumbbob — attention-first build process', '', 'Usage: plumbbob <verb> [args]', '', 'Verbs:', ...rows, ''].join('\n');
|
|
49
54
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
/**
|
|
56
|
+
* The package version, or 'unknown'.
|
|
57
|
+
*
|
|
58
|
+
* Read from the package.json one level above this module (dist/cli-core.js →
|
|
59
|
+
* ../package.json; in tests src/cli-core.ts → ../package.json, the repo root).
|
|
60
|
+
* An absent or malformed manifest degrades to 'unknown' rather than throwing,
|
|
61
|
+
* so `--version` never errors.
|
|
62
|
+
*/
|
|
54
63
|
export function readVersion() {
|
|
55
64
|
try {
|
|
56
65
|
const raw = readFileSync(fileURLToPath(new URL('../package.json', import.meta.url)), 'utf8');
|
|
@@ -60,9 +69,13 @@ export function readVersion() {
|
|
|
60
69
|
return 'unknown';
|
|
61
70
|
}
|
|
62
71
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Route a verb to its implementation, or report the unknown verb and exit 1.
|
|
74
|
+
*
|
|
75
|
+
* Async because checkride is: `check` and `checkpoint` await the gate, `start`
|
|
76
|
+
* awaits the plan-time detection probe; every other verb returns synchronously
|
|
77
|
+
* through the same Promise-typed seam.
|
|
78
|
+
*/
|
|
66
79
|
async function dispatch(verb, cwd, rest) {
|
|
67
80
|
switch (verb) {
|
|
68
81
|
case 'start':
|
|
@@ -100,6 +113,13 @@ async function dispatch(verb, cwd, rest) {
|
|
|
100
113
|
return 1;
|
|
101
114
|
}
|
|
102
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* The CLI entrypoint minus the exit: parse argv, dispatch, return the exit code.
|
|
118
|
+
*
|
|
119
|
+
* `help` and `version` short-circuit before dispatch; any thrown error becomes
|
|
120
|
+
* a one-line stderr report and exit 1, so the bin entry only ever exits with
|
|
121
|
+
* the code returned here.
|
|
122
|
+
*/
|
|
103
123
|
export async function run(argv) {
|
|
104
124
|
const verb = argv[0] ?? 'help';
|
|
105
125
|
const rest = argv.slice(1);
|