spexcode 0.1.6 → 0.2.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/README.md +99 -35
- package/README.zh-CN.md +135 -0
- package/package.json +5 -6
- package/spec-cli/README.md +86 -0
- package/spec-cli/bin/spex.mjs +15 -3
- package/spec-cli/hooks/dispatch.sh +20 -8
- package/spec-cli/hooks/harness.sh +18 -11
- package/spec-cli/src/board.ts +47 -18
- package/spec-cli/src/boardCache.ts +70 -0
- package/spec-cli/src/boardDelta.ts +90 -0
- package/spec-cli/src/boardStream.ts +178 -0
- package/spec-cli/src/cli.ts +184 -122
- package/spec-cli/src/client.ts +6 -4
- package/spec-cli/src/gateway.ts +64 -24
- package/spec-cli/src/git.ts +105 -92
- package/spec-cli/src/guide.ts +186 -19
- package/spec-cli/src/harness-select.ts +63 -0
- package/spec-cli/src/harness.ts +506 -100
- package/spec-cli/src/help.ts +362 -0
- package/spec-cli/src/hooks.ts +0 -14
- package/spec-cli/src/index.ts +279 -32
- package/spec-cli/src/init.ts +41 -1
- package/spec-cli/src/issues.ts +301 -0
- package/spec-cli/src/layout.ts +70 -28
- package/spec-cli/src/lint.ts +12 -10
- package/spec-cli/src/listen.ts +28 -0
- package/spec-cli/src/localIssues.ts +700 -0
- package/spec-cli/src/materialize.ts +182 -27
- package/spec-cli/src/mentions.ts +192 -0
- package/spec-cli/src/plugin-harness.ts +145 -0
- package/spec-cli/src/pty-bridge.ts +378 -81
- package/spec-cli/src/self.ts +123 -20
- package/spec-cli/src/sessions.ts +461 -298
- package/spec-cli/src/specs.ts +55 -14
- package/spec-cli/src/supervise.ts +23 -3
- package/spec-cli/src/tsx-bin.ts +14 -5
- package/spec-cli/src/uninstall.ts +146 -0
- package/spec-cli/templates/hooks/post-merge +27 -0
- package/spec-cli/templates/hooks/pre-commit +51 -31
- package/spec-cli/templates/hooks/prepare-commit-msg +31 -8
- package/spec-cli/templates/presets/careful/.config/clarify-before-code/spec.md +11 -0
- package/spec-cli/templates/spec/project/.config/core/spec-of-file/spec-of-file.sh +26 -3
- package/spec-cli/templates/spec/project/.config/core/spec.md +4 -0
- package/spec-cli/templates/spec/project/.config/core/stop-gate/stop-gate.sh +16 -4
- package/spec-cli/templates/spec/project/.config/extract/spec.md +1 -1
- package/spec-cli/templates/spec/project/.config/regroup/spec.md +1 -1
- package/spec-cli/templates/spec/project/.config/reproduce-before-fix/spec.md +18 -0
- package/spec-cli/templates/spec/project/.config/spec.md +3 -3
- package/spec-cli/templates/spec/project/.config/supervisor/spec.md +2 -2
- package/spec-cli/templates/spec/project/.config/tidy/spec.md +1 -1
- package/spec-cli/templates/spec/project/spec.md +2 -2
- package/spec-dashboard/dist/assets/index-Ct_ubwrd.css +32 -0
- package/spec-dashboard/dist/assets/index-DehTZ-h9.js +145 -0
- package/spec-dashboard/dist/index.html +17 -5
- package/spec-forge/src/cache.ts +16 -0
- package/spec-forge/src/cli.ts +4 -10
- package/spec-forge/src/drivers/github.ts +74 -4
- package/spec-forge/src/drivers.ts +13 -0
- package/spec-forge/src/port.ts +25 -0
- package/spec-forge/src/resident.ts +40 -6
- package/spec-yatsu/src/cli.ts +227 -38
- package/spec-yatsu/src/evaltab.ts +169 -19
- package/spec-yatsu/src/filing.ts +48 -0
- package/spec-yatsu/src/freshness.ts +55 -20
- package/spec-yatsu/src/proof.ts +89 -3
- package/spec-yatsu/src/scenariofresh.ts +92 -0
- package/spec-yatsu/src/sidecar.ts +75 -11
- package/spec-yatsu/src/timeline.ts +47 -0
- package/spec-yatsu/src/yatsu.ts +47 -3
- package/spec-cli/src/relay.ts +0 -28
- package/spec-cli/templates/spec/project/.config/scenario/spec.md +0 -32
- package/spec-dashboard/dist/assets/index-Bk4E1EQy.js +0 -139
- package/spec-dashboard/dist/assets/index-Cq7hwngj.css +0 -32
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
// @@@ help journey - the CLI's three help layers, each pointing at the next so no probe dead-ends:
|
|
2
|
+
// 1. `spex help` → the MAP: every porcelain command, grouped by the loop it serves.
|
|
3
|
+
// 2. `spex help <cmd>` → ONE command's usage (also `spex <cmd> --help`, intercepted pre-verb).
|
|
4
|
+
// 3. `spex guide [topic]` → the SKILL layer: workflows, file formats, best practice (guide.ts).
|
|
5
|
+
// help answers "what do I type"; guide answers "how do I work". Machine plumbing (hook/launch-script
|
|
6
|
+
// callees) lives under `spex internal` and is deliberately absent from the map — an agent scanning
|
|
7
|
+
// `spex help` sees only verbs meant for it. Governed by the cli-surface spec node.
|
|
8
|
+
|
|
9
|
+
// One command's help entry. `see` renders as a trailing "see also:" journey pointer.
|
|
10
|
+
type Entry = { line: string; body: string; see?: string }
|
|
11
|
+
|
|
12
|
+
const SEL_NOTE = `SEL = session id (or unique id-prefix) | node id | branch — every session read/control verb
|
|
13
|
+
accepts any of the three; none (or @all) means every session.`
|
|
14
|
+
|
|
15
|
+
// aliases resolve to a canonical entry so `spex help session` and `spex session new --help` meet the same text.
|
|
16
|
+
const ALIAS: Record<string, string> = { 'review-proof': 'review', help: 'help' }
|
|
17
|
+
|
|
18
|
+
const ENTRIES: Record<string, Entry> = {
|
|
19
|
+
// ── find & read the graph ─────────────────────────────────────────────────
|
|
20
|
+
search: {
|
|
21
|
+
line: 'search <query> which spec node GOVERNS a topic — ranked by user-story, not grep',
|
|
22
|
+
body: `Usage: spex search <query…> [--limit N=10] [--json]
|
|
23
|
+
|
|
24
|
+
Finds the spec node(s) whose INTENT matches your topic — ranked by user-story relevance, which
|
|
25
|
+
surfaces user-facing behaviour a code-grep misses. Run it BEFORE touching code: the returned node's
|
|
26
|
+
spec.md body is the current contract for that area. Prints title, id, path, snippet per hit.`,
|
|
27
|
+
see: 'spex owner (file → node, the reverse edge) · spex guide spec (what a node is)',
|
|
28
|
+
},
|
|
29
|
+
owner: {
|
|
30
|
+
line: 'owner <path> the reverse edge: which spec node(s) claim a file',
|
|
31
|
+
body: `Usage: spex owner <path> [--actionable]
|
|
32
|
+
|
|
33
|
+
Maps a source file to the spec node(s) governing it, with the verdict spelled out: uncovered
|
|
34
|
+
("give it a home"), sanely governed (read/honor that spec), or over-owned (> maxOwners — split the
|
|
35
|
+
file). --actionable prints NOTHING for the sane case (hook use: only fires when action is needed).`,
|
|
36
|
+
see: 'spex search (topic → node) · spex lint (coverage over the whole tree)',
|
|
37
|
+
},
|
|
38
|
+
board: {
|
|
39
|
+
line: 'board dump the assembled board as JSON (tree · overlay · sessions)',
|
|
40
|
+
body: `Usage: spex board
|
|
41
|
+
|
|
42
|
+
Prints the full dashboard board state as JSON — the merged spec tree, per-worktree overlay, and the
|
|
43
|
+
session list. Identical to GET /api/board; needs the backend (spex serve) reachable.`,
|
|
44
|
+
see: 'spex ls (just the sessions, as a table) · spex search (find one node instead of dumping all)',
|
|
45
|
+
},
|
|
46
|
+
guide: {
|
|
47
|
+
line: 'guide [topic] the manuals: setup workflow · spec/yatsu file formats · spexcode.json',
|
|
48
|
+
body: `Usage: spex guide the human setup workflow (install once, adopt a repo, serve)
|
|
49
|
+
spex guide spec the spec.md file format + every lint rule
|
|
50
|
+
spex guide yatsu the yatsu.md scenario format + how loss is measured and filed
|
|
51
|
+
spex guide config every spexcode.json / spexcode.local.json field, and which file it belongs in
|
|
52
|
+
|
|
53
|
+
guide is the SKILL layer — workflows and formats. Command usage lives here in help
|
|
54
|
+
(\`spex help <cmd>\`); guide carries what the commands assume you know.`,
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// ── author & verify (worker loop) ─────────────────────────────────────────
|
|
58
|
+
lint: {
|
|
59
|
+
line: 'lint check the spec↔code graph (integrity·living·altitude·coverage·drift·owners)',
|
|
60
|
+
body: `Usage: spex lint
|
|
61
|
+
|
|
62
|
+
Checks the whole graph and exits non-zero on errors (or a blocked commit-local drift gate):
|
|
63
|
+
integrity (error) a code:/related: path doesn't exist
|
|
64
|
+
living (error) a body accretes a "## vN" changelog instead of staying current-state
|
|
65
|
+
altitude (warn) a body slid below contract altitude into a mechanics dump
|
|
66
|
+
coverage (warn) a governed source file no node claims yet
|
|
67
|
+
drift (warn) a governed file changed after its spec's last version
|
|
68
|
+
owners (warn) a file governed by more than maxOwners nodes — split it
|
|
69
|
+
When run from the pre-commit hook, a staged commit touching a heavily-drifted node BLOCKS
|
|
70
|
+
(bypass: SPEXCODE_SKIP_LINT=1); CI/manual runs are advisory beyond errors.`,
|
|
71
|
+
see: 'spex guide spec (each rule explained) · spex ack (drift that is mechanics-only)',
|
|
72
|
+
},
|
|
73
|
+
ack: {
|
|
74
|
+
line: 'ack <node>… --reason stamp Spec-OK on HEAD: this change keeps those specs valid',
|
|
75
|
+
body: `Usage: spex ack <node-id>… --reason "<why the contract still holds>"
|
|
76
|
+
|
|
77
|
+
Amends HEAD with a Spec-OK trailer per node — the drift remedy when only MECHANICS changed and the
|
|
78
|
+
spec's contract still holds. --reason is required (it forces the check) but NOT stored; git keeps
|
|
79
|
+
only the trailer. If the intent DID change, edit the spec instead — same commit as the code.`,
|
|
80
|
+
see: 'spex lint (where drift is reported) · spex guide spec (drift remedies)',
|
|
81
|
+
},
|
|
82
|
+
yatsu: {
|
|
83
|
+
line: 'yatsu <sub> measure a node’s scenarios & file the loss signal: scan | eval | retract | show | clean',
|
|
84
|
+
body: `Usage: spex yatsu scan [--changed] list nodes/scenarios missing readings
|
|
85
|
+
spex yatsu eval [.|<node>] [--scenario <name>] (--pass|--fail)
|
|
86
|
+
[--note <text>] [--image <png> | --result <path|->]
|
|
87
|
+
spex yatsu retract [.|<node>] [--scenario <name>] [--last | --ts <iso>] [--note <why>]
|
|
88
|
+
spex yatsu show [.|<node>] [--json] readings history for a node
|
|
89
|
+
spex yatsu clean [--keep-latest | --all] prune stored readings
|
|
90
|
+
|
|
91
|
+
Files a reading of a scenario against its expected — the loss signal the optimizer reads. Measure
|
|
92
|
+
through the REAL product surface (run it, drive a browser, screenshot), never by reasoning about
|
|
93
|
+
the code. A fix's proof is a fail→pass pair on the SAME scenario. \`retract\` is the sanctioned
|
|
94
|
+
undo for a botched filing: it APPENDS a retraction event (traceable, never deletes a line).`,
|
|
95
|
+
see: 'spex guide yatsu (yatsu.md format + evidence rules) · spex blob (stash evidence bytes)',
|
|
96
|
+
},
|
|
97
|
+
blob: {
|
|
98
|
+
line: 'blob put <file|-> stash evidence bytes in the content-addressed cache, print the hash',
|
|
99
|
+
body: `Usage: spex blob put <file|->
|
|
100
|
+
|
|
101
|
+
Writes bytes into the shared content-addressed evidence cache and prints the hash — transport only,
|
|
102
|
+
no reading filed. Use the hash with --evidence on issues/remarks; re-putting the same content
|
|
103
|
+
restores a pruned or cloned-away blob.`,
|
|
104
|
+
see: 'spex yatsu eval (file a reading with evidence) · spex issues open --evidence <hash>',
|
|
105
|
+
},
|
|
106
|
+
issues: {
|
|
107
|
+
line: 'issues … THE issue surface: one merged local+forge list, plus all write verbs',
|
|
108
|
+
body: `Usage: spex issues the merged read (local + forge, store-tagged)
|
|
109
|
+
[--node <id>] [--store local|github] [--all] [--json]
|
|
110
|
+
spex issues open "<concern>" [--node <id>…] [--evidence <hash>…] [--body -|<text>]
|
|
111
|
+
spex issues reply <id> --body -|<text> [--evidence <hash>…] (routes by the issue's store)
|
|
112
|
+
spex issues sign <id> co-sign a local issue
|
|
113
|
+
spex issues resolve <id> --as accepted|rejected|landed
|
|
114
|
+
spex issues promote <id> move an OPEN local issue to the forge (one recorded action)
|
|
115
|
+
spex issues on|off|status toggle/inspect the local-issue workflow
|
|
116
|
+
|
|
117
|
+
Bare \`spex issues\` is the drain view a supervisor reads. \`open\` welcomes taste, annotations, and
|
|
118
|
+
off-mainline smells — not only bugs. (\`nudge\` exists but is fired by the post-merge hook, not typed.)`,
|
|
119
|
+
see: 'spex remark (pin a resolvable concern to an issue or scenario) · spex forge (trace forge → nodes)',
|
|
120
|
+
},
|
|
121
|
+
remark: {
|
|
122
|
+
line: 'remark / resolve / retract pin a resolvable concern to a host; a peer resolves, the author retracts',
|
|
123
|
+
body: `Usage: spex remark <issue-id | <node> --scenario <name>> --body -|<text> [--code-sha <sha>] [--evidence <hash>…]
|
|
124
|
+
spex resolve <remark-ref> (the <thread-id>#<rid> that \`spex remark\` printed)
|
|
125
|
+
spex retract <remark-ref>
|
|
126
|
+
|
|
127
|
+
The resolvable interaction primitive: pin a concern to a HOST — a local issue or a yatsu scenario —
|
|
128
|
+
that a second agent can \`resolve\` and the author can \`retract\`. The whole loop is CLI-first; the
|
|
129
|
+
dashboard adds no capability.`,
|
|
130
|
+
see: 'spex issues (the hosts) · spex yatsu show (scenario hosts)',
|
|
131
|
+
},
|
|
132
|
+
forge: {
|
|
133
|
+
line: 'forge <sub> read-only trace of forge issues/PRs onto spec nodes: links | eval-pending',
|
|
134
|
+
body: `Usage: spex forge links [--host github] [--node <id>] [--json]
|
|
135
|
+
spex forge eval-pending [--host github] [--node <id>] [--json]
|
|
136
|
+
|
|
137
|
+
Resolves a forge's open issues/PRs to the spec nodes they serve (the Spec: marker in an issue body;
|
|
138
|
+
a node/<id> branch links its PR for free). Read-only — git/.spec stays the single source of truth.`,
|
|
139
|
+
see: 'spex issues (the merged read that includes forge threads)',
|
|
140
|
+
},
|
|
141
|
+
self: {
|
|
142
|
+
line: 'self <sub> diagnose whether the workflow actually reaches THIS agent: doctor | contract | conflicts',
|
|
143
|
+
body: `Usage: spex self [doctor] per-layer coverage report: preconditions · git-hook floor · contract ·
|
|
144
|
+
hooks + handler existence · backend — for every harness materialize renders
|
|
145
|
+
spex self contract print the composed surface:system text any agent here reads
|
|
146
|
+
spex self conflicts detect double-delivery (loose artifacts beside the managed ones)
|
|
147
|
+
|
|
148
|
+
Run it when a worker seems to be missing its contract or hooks — it names the broken layer and the
|
|
149
|
+
repair, instead of you diffing materialized files by hand.`,
|
|
150
|
+
see: 'spex materialize (re-render the artifacts doctor checks)',
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
// ── dispatch & manage sessions (manager loop) ─────────────────────────────
|
|
154
|
+
new: {
|
|
155
|
+
line: 'new "<prompt>" launch a worker session in its own node worktree [--node <id>]',
|
|
156
|
+
body: `Usage: spex new "<task prompt>" [--node <id>] [--harness <name>] [--launcher <cmd>]
|
|
157
|
+
|
|
158
|
+
Creates a session: node branch + worktree + a launched agent carrying your prompt (= session new).
|
|
159
|
+
Give it ONLY its task — the dev-flow contract reaches it through the materialized system prompt.
|
|
160
|
+
Routes through the running backend (auth env + concurrency cap); prints the created session JSON.
|
|
161
|
+
Then MONITOR it: background \`spex wait <id>\`, or \`spex watch\` for the whole stream.`,
|
|
162
|
+
see: 'spex wait / spex watch (monitor) · spex review (when it proposes) · ' + SEL_NOTE.split('\n')[0],
|
|
163
|
+
},
|
|
164
|
+
ls: {
|
|
165
|
+
line: 'ls [SEL…] living-sessions table [--status a,b] [--json]',
|
|
166
|
+
body: `Usage: spex ls [SEL…] [--status a,b] [--json]
|
|
167
|
+
|
|
168
|
+
One-shot table of living sessions and their states, from whatever backend SPEXCODE_API_URL points
|
|
169
|
+
at (including a remote machine's). ${SEL_NOTE}`,
|
|
170
|
+
see: 'spex watch (the live stream) · spex wait (block on one session)',
|
|
171
|
+
},
|
|
172
|
+
watch: {
|
|
173
|
+
line: 'watch [SEL…] stream actionable transitions — NEVER EXITS; background it, never block on it',
|
|
174
|
+
body: `Usage: spex watch [SEL…] [--as NAME] [--status a,b] [--idle] [--interval N=5]
|
|
175
|
+
|
|
176
|
+
Streams session lifecycle transitions (launched → review/done/offline/error/needs-input → closed)
|
|
177
|
+
until killed. It NEVER EXITS — it is the human's forever stream. An agent must background it or use
|
|
178
|
+
\`spex wait <SEL>\` (one-shot) instead; blocking a turn on watch freezes you. Watching draws a
|
|
179
|
+
supervision edge on the session graph and greets the watched sessions once.
|
|
180
|
+
${SEL_NOTE}`,
|
|
181
|
+
see: 'spex wait (the one-shot, guaranteed-to-exit counterpart)',
|
|
182
|
+
},
|
|
183
|
+
wait: {
|
|
184
|
+
line: 'wait <SEL> block until <SEL> is actionable, print the status, exit',
|
|
185
|
+
body: `Usage: spex wait <SEL> [--timeout S=1200] [--interval S=2] [--idle]
|
|
186
|
+
|
|
187
|
+
Blocks until the session reaches an actionable status, prints it, and EXITS — the supervisor's
|
|
188
|
+
per-worker monitor (background one wait per worker; the exit is your wake-up). Guaranteed to
|
|
189
|
+
terminate: --timeout is the hard wall (exit 1); a vanished session exits 2; a down backend fails
|
|
190
|
+
loud (exit 1), never a false timeout. Draws the watcher→worker edge for the whole wait.
|
|
191
|
+
${SEL_NOTE}`,
|
|
192
|
+
see: 'spex watch (the forever stream) · spex review (what to run when it prints review/done)',
|
|
193
|
+
},
|
|
194
|
+
review: {
|
|
195
|
+
line: 'review <SEL> manager cockpit: ahead · merge-base diff · gates · proposal [--json]',
|
|
196
|
+
body: `Usage: spex review <SEL> [--json]
|
|
197
|
+
spex review proof <SEL> [--open | --out <path> | --json]
|
|
198
|
+
|
|
199
|
+
The ONE review payload for a session: commits ahead of the trunk, uncommitted files, its proposal,
|
|
200
|
+
the gates (conflicts with the trunk, lint), and the merge-base diff — decide from this, don't
|
|
201
|
+
hand-run git. \`review proof\` renders the session's proof-of-work as self-contained HTML (diff ·
|
|
202
|
+
measured yatsu loss · gates), fully derived from git + readings.
|
|
203
|
+
${SEL_NOTE}`,
|
|
204
|
+
see: 'spex merge (act on an approved review)',
|
|
205
|
+
},
|
|
206
|
+
merge: {
|
|
207
|
+
line: 'merge <SEL> gated merge into the trunk — dispatched to the session’s own agent',
|
|
208
|
+
body: `Usage: spex merge <SEL>
|
|
209
|
+
|
|
210
|
+
Dispatches the merge to the session's OWN agent (it knows the work's intent and resolves conflicts);
|
|
211
|
+
the server never touches the trunk's tree. Gates re-check first. After it lands, confirm HEAD
|
|
212
|
+
advanced before closing the session — closing an unmerged branch discards the work.
|
|
213
|
+
${SEL_NOTE}`,
|
|
214
|
+
see: 'spex review (before) · spex session close (after the merge is confirmed)',
|
|
215
|
+
},
|
|
216
|
+
session: {
|
|
217
|
+
line: 'session <sub> the state machine: new·reopen·done·park·ask·exit·close·send·capture·prompt',
|
|
218
|
+
body: `Worker verbs (declare YOUR OWN state — a claim the board and your supervisor act on):
|
|
219
|
+
spex session done --propose merge|nothing|close [--note T] committed and stopping; merge = ready for review
|
|
220
|
+
spex session park --note <what-you-await> a real background task will wake you
|
|
221
|
+
spex session ask --note <your-question> stopped on the human; resumes when they reply
|
|
222
|
+
|
|
223
|
+
Manager verbs (control another session; all take SEL):
|
|
224
|
+
spex session send <SEL> "<msg>" deliver a message (fail-loud: a dead dispatch exits non-zero)
|
|
225
|
+
spex session capture <SEL> the live pane as text
|
|
226
|
+
spex session prompt <SEL> the session's originating prompt
|
|
227
|
+
spex session reopen <SEL> [--force] relaunch ONLY if confirmed offline (--force for a wedged live one)
|
|
228
|
+
spex session exit <SEL> soft stop: kill the agent, KEEP the worktree (resumable)
|
|
229
|
+
spex session close <SEL> retire the session and its worktree
|
|
230
|
+
spex session new "<prompt>" = spex new
|
|
231
|
+
|
|
232
|
+
(state · fail · idle · commit-gate also exist but are hook-driven — the lifecycle hooks call them;
|
|
233
|
+
never type them.) ${SEL_NOTE}`,
|
|
234
|
+
see: 'spex new (launch) · spex wait/watch (monitor) · spex review/merge (land)',
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
// ── install & serve (operator) ────────────────────────────────────────────
|
|
238
|
+
init: {
|
|
239
|
+
line: 'init [dir] adopt SpexCode on a repo: seed .spec + hooks + materialize [--preset name]',
|
|
240
|
+
body: `Usage: spex init [dir=cwd] [--preset default|careful]
|
|
241
|
+
|
|
242
|
+
Scaffolds adoption in one shot: seeds a starter .spec tree (project root + .config plugins), plants
|
|
243
|
+
spexcode.json, installs the git hooks, and materializes the harness artifacts (contract block +
|
|
244
|
+
shims). Additive — never overwrites your files. --preset picks the .config plugin tier (cumulative).`,
|
|
245
|
+
see: 'spex guide (the full setup workflow) · spex uninstall (the inverse) · spex lint (adoption TODO)',
|
|
246
|
+
},
|
|
247
|
+
uninstall: {
|
|
248
|
+
line: 'uninstall [dir] surgical inverse of init — removes generated artifacts, keeps your .spec [--hooks]',
|
|
249
|
+
body: `Usage: spex uninstall [dir=cwd] [--hooks]
|
|
250
|
+
|
|
251
|
+
Removes every SpexCode-GENERATED artifact (harness shims · contract blocks · trust entries ·
|
|
252
|
+
.gitignore block · global store · plugin bundle) and never your .spec/.config data or your own
|
|
253
|
+
prose. Git hooks are preserved unless --hooks.`,
|
|
254
|
+
see: 'spex init (re-adopt later — your .spec survives)',
|
|
255
|
+
},
|
|
256
|
+
materialize: {
|
|
257
|
+
line: 'materialize re-render the harness artifacts (contract block · shims) for cwd’s project',
|
|
258
|
+
body: `Usage: spex materialize
|
|
259
|
+
|
|
260
|
+
Renders the surface:system config nodes into the managed <!-- spexcode --> block of
|
|
261
|
+
CLAUDE.md/AGENTS.md plus the .claude/.codex shims, and prints the content hash. Run it after a
|
|
262
|
+
toolchain update or any .config edit that the automatic dispatch gate hasn't picked up — these
|
|
263
|
+
artifacts are generated and gitignored, so they never arrive via git.`,
|
|
264
|
+
see: 'spex self doctor (verify the render actually reaches an agent)',
|
|
265
|
+
},
|
|
266
|
+
serve: {
|
|
267
|
+
line: 'serve run the API backend (default :8787) [--port N] [--public --password pw]',
|
|
268
|
+
body: `Usage: spex serve [--port N=8787]
|
|
269
|
+
spex serve --public --password <pw> [--tls-cert F --tls-key F] [--http]
|
|
270
|
+
|
|
271
|
+
Runs the backend for the repo at cwd behind a zero-downtime supervisor (hot-reloads on source
|
|
272
|
+
change; the public port never gaps). --port pairs with \`spex dashboard --api-port\`, so many
|
|
273
|
+
projects coexist on one host. --public exposes it on a public IP behind a password + self-signed
|
|
274
|
+
TLS (own cert via --tls-cert/--tls-key; --http drops TLS).`,
|
|
275
|
+
see: 'spex dashboard (the UI on top) · GET /health (liveness probe)',
|
|
276
|
+
},
|
|
277
|
+
dashboard: {
|
|
278
|
+
line: 'dashboard serve the dashboard UI (default :5173), proxying /api to a running serve',
|
|
279
|
+
body: `Usage: spex dashboard [--port N=5173] [--api-port N=8787] [--host H=127.0.0.1]
|
|
280
|
+
|
|
281
|
+
Serves the bundled dashboard on its own port and proxies /api + the terminal socket to a running
|
|
282
|
+
\`spex serve\`. The installed replacement for the dev-only \`npm run web\`. Loopback-only by default;
|
|
283
|
+
--host 0.0.0.0 (or a specific interface) opens it to a LAN/tailnet — still plain HTTP with no gate,
|
|
284
|
+
so bind wide only on a network you trust (for the internet, use \`spex serve --public\`).`,
|
|
285
|
+
see: 'spex serve (must be running first)',
|
|
286
|
+
},
|
|
287
|
+
|
|
288
|
+
// ── plumbing ──────────────────────────────────────────────────────────────
|
|
289
|
+
internal: {
|
|
290
|
+
line: '', // deliberately not on the map
|
|
291
|
+
body: `Usage: spex internal <trunk | codex-launch | codex-turn>
|
|
292
|
+
|
|
293
|
+
Machine plumbing — called by generated hooks and launch scripts, never typed by a human or agent:
|
|
294
|
+
trunk print the resolved source-of-truth branch (the pre-commit main-guard captures it)
|
|
295
|
+
codex-launch <sock> <cwd> [prompt…] backend-owned codex thread/start + first turn (launch script)
|
|
296
|
+
codex-turn <sock> <threadId> <text…> fire a follow-up turn on an owned thread (tests/scripts)
|
|
297
|
+
|
|
298
|
+
If you reached for one of these by hand, the porcelain you want is probably elsewhere: the trunk
|
|
299
|
+
name also lives at GET /api/layout; sessions are driven with spex new / session send.`,
|
|
300
|
+
see: 'spex help (the porcelain map)',
|
|
301
|
+
},
|
|
302
|
+
help: {
|
|
303
|
+
line: '',
|
|
304
|
+
body: `Usage: spex help the command map, grouped by the loop each verb serves
|
|
305
|
+
spex help <command> one command's usage (same as spex <command> --help)
|
|
306
|
+
spex guide [topic] the skill layer: workflows, file formats, best practice`,
|
|
307
|
+
},
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// `spex <cmd> --help` must meet the user wherever they typed it: sub-namespace tokens map to their
|
|
311
|
+
// canonical entry, so \`spex session send --help\` and \`spex help session\` print the same text.
|
|
312
|
+
export function commandHelp(name: string): string | null {
|
|
313
|
+
const key = ALIAS[name] ?? (name === 'resolve' || name === 'retract' ? 'remark' : name)
|
|
314
|
+
const e = ENTRIES[key]
|
|
315
|
+
if (!e) return null
|
|
316
|
+
const oneLiner = e.line.replace(/^\S+(\s+\S+)*?\s{2,}/, '') // the map line minus its "cmd args" column
|
|
317
|
+
const header = oneLiner ? `spex ${key} — ${oneLiner}\n\n` : '' // unlisted entries (internal, help) lead with their own Usage
|
|
318
|
+
return `${header}${e.body}${e.see ? `\n\nsee also: ${e.see}` : ''}\n\nmap: spex help · skills: spex guide`
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function overviewHelp(): string {
|
|
322
|
+
return `spex — SpexCode CLI (spec↔code graph + worktree session state machine)
|
|
323
|
+
|
|
324
|
+
Usage: spex <command> [args] one command's usage: spex help <command> (or spex <command> --help)
|
|
325
|
+
|
|
326
|
+
Find & read the graph
|
|
327
|
+
${ENTRIES.search.line}
|
|
328
|
+
${ENTRIES.owner.line}
|
|
329
|
+
${ENTRIES.board.line}
|
|
330
|
+
${ENTRIES.guide.line}
|
|
331
|
+
|
|
332
|
+
Author & verify (the worker loop)
|
|
333
|
+
${ENTRIES.lint.line}
|
|
334
|
+
${ENTRIES.ack.line}
|
|
335
|
+
${ENTRIES.yatsu.line}
|
|
336
|
+
${ENTRIES.blob.line}
|
|
337
|
+
${ENTRIES.issues.line}
|
|
338
|
+
${ENTRIES.remark.line}
|
|
339
|
+
${ENTRIES.forge.line}
|
|
340
|
+
${ENTRIES.self.line}
|
|
341
|
+
|
|
342
|
+
Dispatch & manage sessions (the manager loop)
|
|
343
|
+
${ENTRIES.new.line}
|
|
344
|
+
${ENTRIES.ls.line}
|
|
345
|
+
${ENTRIES.watch.line}
|
|
346
|
+
${ENTRIES.wait.line}
|
|
347
|
+
${ENTRIES.review.line}
|
|
348
|
+
${ENTRIES.merge.line}
|
|
349
|
+
${ENTRIES.session.line}
|
|
350
|
+
|
|
351
|
+
Install & serve (the operator loop)
|
|
352
|
+
${ENTRIES.init.line}
|
|
353
|
+
${ENTRIES.uninstall.line}
|
|
354
|
+
${ENTRIES.materialize.line}
|
|
355
|
+
${ENTRIES.serve.line}
|
|
356
|
+
${ENTRIES.dashboard.line}
|
|
357
|
+
|
|
358
|
+
${SEL_NOTE}
|
|
359
|
+
|
|
360
|
+
Concepts & best practice live in the guide: spex guide (setup) · guide spec · guide yatsu · guide config.
|
|
361
|
+
Machine plumbing (hook/launch-script callees) lives under \`spex internal\` — not part of your vocabulary.`
|
|
362
|
+
}
|
package/spec-cli/src/hooks.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { writeFileSync } from 'node:fs'
|
|
2
1
|
import { loadHookConfig } from './specs.js'
|
|
3
2
|
|
|
4
3
|
// @@@ hook manifest - the harness-agnostic hook system has THREE parts: (1) the discovered handlers —
|
|
@@ -26,16 +25,3 @@ export function compileManifest(cfgs = loadHookConfig()): string {
|
|
|
26
25
|
return lines.length ? lines.join('\n') + '\n' : ''
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
// `spex hooks compile [--out <file>]` — write the manifest (SessionStart) or print it (debug/test).
|
|
30
|
-
export async function runHooks(argv: string[]): Promise<number> {
|
|
31
|
-
const sub = argv[0]
|
|
32
|
-
if (sub === 'compile') {
|
|
33
|
-
const i = argv.indexOf('--out')
|
|
34
|
-
const manifest = compileManifest()
|
|
35
|
-
if (i >= 0 && argv[i + 1]) writeFileSync(argv[i + 1], manifest)
|
|
36
|
-
else process.stdout.write(manifest)
|
|
37
|
-
return 0
|
|
38
|
-
}
|
|
39
|
-
console.error('spex hooks: compile [--out <file>]')
|
|
40
|
-
return 2
|
|
41
|
-
}
|