spexcode 0.1.5 → 0.2.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.
Files changed (70) hide show
  1. package/README.md +86 -25
  2. package/package.json +5 -6
  3. package/spec-cli/README.md +86 -0
  4. package/spec-cli/bin/spex.mjs +15 -3
  5. package/spec-cli/hooks/dispatch.sh +20 -8
  6. package/spec-cli/hooks/harness.sh +18 -11
  7. package/spec-cli/src/board.ts +47 -18
  8. package/spec-cli/src/boardCache.ts +70 -0
  9. package/spec-cli/src/boardDelta.ts +90 -0
  10. package/spec-cli/src/boardStream.ts +178 -0
  11. package/spec-cli/src/cli.ts +172 -119
  12. package/spec-cli/src/client.ts +6 -4
  13. package/spec-cli/src/gateway.ts +60 -19
  14. package/spec-cli/src/git.ts +105 -92
  15. package/spec-cli/src/guide.ts +175 -12
  16. package/spec-cli/src/harness-select.ts +63 -0
  17. package/spec-cli/src/harness.ts +506 -100
  18. package/spec-cli/src/help.ts +360 -0
  19. package/spec-cli/src/hooks.ts +0 -14
  20. package/spec-cli/src/index.ts +272 -32
  21. package/spec-cli/src/init.ts +41 -1
  22. package/spec-cli/src/issues.ts +250 -0
  23. package/spec-cli/src/layout.ts +70 -28
  24. package/spec-cli/src/lint.ts +12 -10
  25. package/spec-cli/src/listen.ts +28 -0
  26. package/spec-cli/src/localIssues.ts +683 -0
  27. package/spec-cli/src/materialize.ts +182 -27
  28. package/spec-cli/src/mentions.ts +192 -0
  29. package/spec-cli/src/plugin-harness.ts +145 -0
  30. package/spec-cli/src/pty-bridge.ts +378 -81
  31. package/spec-cli/src/self.ts +123 -20
  32. package/spec-cli/src/sessions.ts +461 -298
  33. package/spec-cli/src/specs.ts +55 -14
  34. package/spec-cli/src/supervise.ts +23 -3
  35. package/spec-cli/src/tsx-bin.ts +14 -5
  36. package/spec-cli/src/uninstall.ts +146 -0
  37. package/spec-cli/templates/hooks/post-merge +27 -0
  38. package/spec-cli/templates/hooks/pre-commit +51 -31
  39. package/spec-cli/templates/hooks/prepare-commit-msg +31 -8
  40. package/spec-cli/templates/presets/careful/.config/clarify-before-code/spec.md +11 -0
  41. package/spec-cli/templates/spec/project/.config/core/spec-of-file/spec-of-file.sh +26 -3
  42. package/spec-cli/templates/spec/project/.config/core/spec.md +4 -0
  43. package/spec-cli/templates/spec/project/.config/core/stop-gate/stop-gate.sh +16 -4
  44. package/spec-cli/templates/spec/project/.config/extract/spec.md +1 -1
  45. package/spec-cli/templates/spec/project/.config/regroup/spec.md +1 -1
  46. package/spec-cli/templates/spec/project/.config/reproduce-before-fix/spec.md +18 -0
  47. package/spec-cli/templates/spec/project/.config/spec.md +3 -3
  48. package/spec-cli/templates/spec/project/.config/supervisor/spec.md +2 -2
  49. package/spec-cli/templates/spec/project/.config/tidy/spec.md +1 -1
  50. package/spec-cli/templates/spec/project/spec.md +2 -2
  51. package/spec-dashboard/dist/assets/index-B0tgHeEQ.js +145 -0
  52. package/spec-dashboard/dist/assets/index-BTU-44Os.css +32 -0
  53. package/spec-dashboard/dist/index.html +17 -5
  54. package/spec-forge/src/cache.ts +16 -0
  55. package/spec-forge/src/drivers/github.ts +74 -4
  56. package/spec-forge/src/port.ts +25 -0
  57. package/spec-forge/src/resident.ts +40 -6
  58. package/spec-yatsu/src/cli.ts +227 -38
  59. package/spec-yatsu/src/evaltab.ts +169 -19
  60. package/spec-yatsu/src/filing.ts +48 -0
  61. package/spec-yatsu/src/freshness.ts +55 -20
  62. package/spec-yatsu/src/proof.ts +89 -3
  63. package/spec-yatsu/src/scenariofresh.ts +92 -0
  64. package/spec-yatsu/src/sidecar.ts +75 -11
  65. package/spec-yatsu/src/timeline.ts +47 -0
  66. package/spec-yatsu/src/yatsu.ts +47 -3
  67. package/spec-cli/src/relay.ts +0 -28
  68. package/spec-cli/templates/spec/project/.config/scenario/spec.md +0 -32
  69. package/spec-dashboard/dist/assets/index-Bk4E1EQy.js +0 -139
  70. package/spec-dashboard/dist/assets/index-Cq7hwngj.css +0 -32
@@ -0,0 +1,360 @@
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]
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\`.`,
283
+ see: 'spex serve (must be running first)',
284
+ },
285
+
286
+ // ── plumbing ──────────────────────────────────────────────────────────────
287
+ internal: {
288
+ line: '', // deliberately not on the map
289
+ body: `Usage: spex internal <trunk | codex-launch | codex-turn>
290
+
291
+ Machine plumbing — called by generated hooks and launch scripts, never typed by a human or agent:
292
+ trunk print the resolved source-of-truth branch (the pre-commit main-guard captures it)
293
+ codex-launch <sock> <cwd> [prompt…] backend-owned codex thread/start + first turn (launch script)
294
+ codex-turn <sock> <threadId> <text…> fire a follow-up turn on an owned thread (tests/scripts)
295
+
296
+ If you reached for one of these by hand, the porcelain you want is probably elsewhere: the trunk
297
+ name also lives at GET /api/layout; sessions are driven with spex new / session send.`,
298
+ see: 'spex help (the porcelain map)',
299
+ },
300
+ help: {
301
+ line: '',
302
+ body: `Usage: spex help the command map, grouped by the loop each verb serves
303
+ spex help <command> one command's usage (same as spex <command> --help)
304
+ spex guide [topic] the skill layer: workflows, file formats, best practice`,
305
+ },
306
+ }
307
+
308
+ // `spex <cmd> --help` must meet the user wherever they typed it: sub-namespace tokens map to their
309
+ // canonical entry, so \`spex session send --help\` and \`spex help session\` print the same text.
310
+ export function commandHelp(name: string): string | null {
311
+ const key = ALIAS[name] ?? (name === 'resolve' || name === 'retract' ? 'remark' : name)
312
+ const e = ENTRIES[key]
313
+ if (!e) return null
314
+ const oneLiner = e.line.replace(/^\S+(\s+\S+)*?\s{2,}/, '') // the map line minus its "cmd args" column
315
+ const header = oneLiner ? `spex ${key} — ${oneLiner}\n\n` : '' // unlisted entries (internal, help) lead with their own Usage
316
+ return `${header}${e.body}${e.see ? `\n\nsee also: ${e.see}` : ''}\n\nmap: spex help · skills: spex guide`
317
+ }
318
+
319
+ export function overviewHelp(): string {
320
+ return `spex — SpexCode CLI (spec↔code graph + worktree session state machine)
321
+
322
+ Usage: spex <command> [args] one command's usage: spex help <command> (or spex <command> --help)
323
+
324
+ Find & read the graph
325
+ ${ENTRIES.search.line}
326
+ ${ENTRIES.owner.line}
327
+ ${ENTRIES.board.line}
328
+ ${ENTRIES.guide.line}
329
+
330
+ Author & verify (the worker loop)
331
+ ${ENTRIES.lint.line}
332
+ ${ENTRIES.ack.line}
333
+ ${ENTRIES.yatsu.line}
334
+ ${ENTRIES.blob.line}
335
+ ${ENTRIES.issues.line}
336
+ ${ENTRIES.remark.line}
337
+ ${ENTRIES.forge.line}
338
+ ${ENTRIES.self.line}
339
+
340
+ Dispatch & manage sessions (the manager loop)
341
+ ${ENTRIES.new.line}
342
+ ${ENTRIES.ls.line}
343
+ ${ENTRIES.watch.line}
344
+ ${ENTRIES.wait.line}
345
+ ${ENTRIES.review.line}
346
+ ${ENTRIES.merge.line}
347
+ ${ENTRIES.session.line}
348
+
349
+ Install & serve (the operator loop)
350
+ ${ENTRIES.init.line}
351
+ ${ENTRIES.uninstall.line}
352
+ ${ENTRIES.materialize.line}
353
+ ${ENTRIES.serve.line}
354
+ ${ENTRIES.dashboard.line}
355
+
356
+ ${SEL_NOTE}
357
+
358
+ Concepts & best practice live in the guide: spex guide (setup) · guide spec · guide yatsu · guide config.
359
+ Machine plumbing (hook/launch-script callees) lives under \`spex internal\` — not part of your vocabulary.`
360
+ }
@@ -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
- }