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.
- package/README.md +86 -25
- 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 +172 -119
- package/spec-cli/src/client.ts +6 -4
- package/spec-cli/src/gateway.ts +60 -19
- package/spec-cli/src/git.ts +105 -92
- package/spec-cli/src/guide.ts +175 -12
- package/spec-cli/src/harness-select.ts +63 -0
- package/spec-cli/src/harness.ts +506 -100
- package/spec-cli/src/help.ts +360 -0
- package/spec-cli/src/hooks.ts +0 -14
- package/spec-cli/src/index.ts +272 -32
- package/spec-cli/src/init.ts +41 -1
- package/spec-cli/src/issues.ts +250 -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 +683 -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-B0tgHeEQ.js +145 -0
- package/spec-dashboard/dist/assets/index-BTU-44Os.css +32 -0
- package/spec-dashboard/dist/index.html +17 -5
- package/spec-forge/src/cache.ts +16 -0
- package/spec-forge/src/drivers/github.ts +74 -4
- 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
|
@@ -45,13 +45,23 @@ cont=$(printf '%s' "$input" | sed -n 's/.*"stop_hook_active"[[:space:]]*:[[:spac
|
|
|
45
45
|
# (NEVER a block decision: a gap is a heads-up, not a wall). FIRES ONCE: the additionalContext itself forces
|
|
46
46
|
# one continuation, so the CALLER guards it on stop_hook_active — re-emitting on the forced re-stop is what
|
|
47
47
|
# looped 31 turns and tripped the Stop-hook block cap. Called only on ALLOW paths, never alongside a block.
|
|
48
|
+
#
|
|
49
|
+
# SURFACE-NEUTRAL: a stale/unmeasured score is refreshed only by PRODUCING the measurement on the scenario's
|
|
50
|
+
# OWN surface — a real run, never a desk check and never deferring to review a recording after the fact. The
|
|
51
|
+
# nudge privileges NO surface: `scan --changed` carries each drift/missing scenario's tag on its finding line
|
|
52
|
+
# ([[yatsu-core]]'s lint.scenarioTags — frontend-e2e / backend-api / cli / desktop / mobile), so the agent
|
|
53
|
+
# reads there WHICH surface to run. One line covers all five surfaces; there is no per-surface branch.
|
|
48
54
|
yatsu_advisory() {
|
|
49
55
|
local out ids n msg esc
|
|
56
|
+
# Codex Stop hooks reject the Claude-family `hookSpecificOutput.additionalContext` shape on allow paths.
|
|
57
|
+
# Keep Codex Stop stdout empty unless it is a real block decision; the dispatcher still bridges block
|
|
58
|
+
# reasons to Codex stderr.
|
|
59
|
+
[ "${SPEXCODE_HARNESS:-claude}" = codex ] && return 0
|
|
50
60
|
out=$($S yatsu scan --changed 2>&1)
|
|
51
61
|
n=$(printf '%s\n' "$out" | grep -cE 'yatsu-(drift|missing|uncovered):')
|
|
52
62
|
[ "${n:-0}" -gt 0 ] || return 0 # no gap in what you changed (or scan unavailable) -> nothing to nudge
|
|
53
63
|
ids=$(printf '%s\n' "$out" | sed -n "s/.*yatsu-[a-z]*: '\([^']*\)'.*/\1/p" | awk '!seen[$0]++' | head -6 | paste -sd' ' -)
|
|
54
|
-
msg="yatsu — the loss signal the optimizer reads — flags ${n} gap(s) in nodes you changed: ${ids}. A node whose score went stale/unmeasured: re-measure it
|
|
64
|
+
msg="yatsu — the loss signal the optimizer reads — flags ${n} gap(s) in nodes you changed: ${ids}. A node whose score went stale/unmeasured: re-measure it — PRODUCE the measurement YOURSELF with a real run of the scenario's actual surface (its tag on the \`spex yatsu scan --changed\` line tells you WHICH surface to run), compare to expected, and file it with \`spex yatsu eval <node>\`; don't desk-check it, and don't defer to reviewing a recording after the fact. A FRONTEND node with no yatsu.md: give it one (a scenario — description + expected), since an obvious UI change should carry a loss signal. \`spex yatsu scan --changed\` lists them. (Advisory — fires once, not a gate.)"
|
|
55
65
|
esc=$(printf '%s' "$msg" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
56
66
|
printf '{"hookSpecificOutput":{"hookEventName":"Stop","additionalContext":"%s"}}\n' "$esc"
|
|
57
67
|
}
|
|
@@ -99,10 +109,12 @@ if [ "$cont" = true ]; then
|
|
|
99
109
|
exit 0
|
|
100
110
|
fi
|
|
101
111
|
|
|
102
|
-
# first stop in an undeclared state -> nudge exactly once
|
|
103
|
-
#
|
|
112
|
+
# first stop in an undeclared state -> nudge exactly once. The reason names the PATH-independent CLI ($S)
|
|
113
|
+
# ONCE as a shared `<CLI> session <choice>` prefix, then lists the five choices as a compact newline menu of
|
|
114
|
+
# bare subcommands — so the terminal output stays legible instead of repeating the long abs path per option.
|
|
115
|
+
# It EMPHASIZES that each state is a CLAIM others act on (not a box to tick to end the turn) and gives the
|
|
104
116
|
# precise APPLICATION CONDITION for each — so the agent picks the TRUE one. park is policed hardest because
|
|
105
117
|
# a false park (no real background task) reads on the board as "fine, self-resuming" when the agent actually
|
|
106
118
|
# needs the human, which is the most damaging mislabel.
|
|
107
|
-
printf '{"decision":"block","reason":"Your session state is a CLAIM the board, your supervisor, and other agents act on — not a box to tick to end the turn. Stopping undeclared makes your outcome a guess. Pick the ONE that is TRUE right now
|
|
119
|
+
printf '{"decision":"block","reason":"Your session state is a CLAIM the board, your supervisor, and other agents act on — not a box to tick to end the turn. Stopping undeclared makes your outcome a guess. Pick the ONE that is TRUE right now and run `%s session <choice>`, choosing the <choice> whose condition holds:\\n • done --propose merge — spec+code COMMITTED on the branch and genuinely ready for a human to review/merge (not just probably-done).\\n • done --propose nothing — committed, but you are NOT proposing a merge; paused for the human to look.\\n • park --note <what-you-await> — ONLY when a real BACKGROUND TASK will wake you (a spex wait you backgrounded, a running build/job). If nothing is actually running to resume you, you are NOT parked — you are waiting on the human, so use ask; never use park as a default to clear this gate.\\n • done --propose close — you propose discarding this worktree.\\n • ask --note <your-question> — you need the human: a real question, or you are simply stopped awaiting direction; you resume only when they reply."}\n' "$S"
|
|
108
120
|
exit 0
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: reproduce-before-fix
|
|
3
|
+
surface: system
|
|
4
|
+
status: active
|
|
5
|
+
hue: 140
|
|
6
|
+
desc: A config plugin — a bug fix must first REPRODUCE the failure as a failing eval, then fix, then file the passing eval. The fail→pass pair on one scenario is the fix's proof (the A/B).
|
|
7
|
+
code:
|
|
8
|
+
---
|
|
9
|
+
## Reproduce before you fix — the fix's proof is a fail→pass pair
|
|
10
|
+
|
|
11
|
+
If your task is to FIX A BUG, reproduce it *first*, as a measurement — before you touch the fix. A claim that something is broken is worth nothing until the loss signal shows it broken; a claim that you fixed it is worth nothing until the same signal shows it passing. So a bug fix is bracketed by two readings of ONE scenario:
|
|
12
|
+
|
|
13
|
+
- **A — reproduce (fail).** Find the yatsu scenario whose expected the bug violates (if none fits, ADD one to the node's `yatsu.md` — a description + the expected correct behaviour), run it, and file the failing reading with evidence that SHOWS the bug: `spex yatsu eval <node> --scenario <s> --fail --note "<what's wrong>"` plus an `--image`/`--video` of the actual broken behaviour. This is not ceremony — reproducing is how you learn what actually breaks, and a fix aimed at an unreproduced bug aims at a guess.
|
|
14
|
+
- **B — fix, then re-measure (pass).** Make the code honor the spec, run the SAME scenario again, and file the passing reading with evidence of the corrected behaviour: `spex yatsu eval <node> --scenario <s> --pass`.
|
|
15
|
+
|
|
16
|
+
The two readings on the same scenario are the **A/B** — the error→correct transition, the fix's proof-of-work. yatsu keeps per-scenario reading history, so the pair is durable and navigable end to end.
|
|
17
|
+
|
|
18
|
+
Don't skip A because the fix looks obvious — an obvious fix with no reproduced failure leaves the loss signal blind to exactly the regression you just closed. This does not apply to building new intent (there is no prior failure to reproduce) — it is the discipline for **repair**: keep the loss signal honest across a bug's whole lifecycle, not just at the end.
|
|
@@ -6,10 +6,10 @@ desc: The instance home — this repo's DIY dev-flow plugins live here as skill-
|
|
|
6
6
|
---
|
|
7
7
|
`.config/` is the **instance** of the config system: the concrete dev-flow plugins this repo ships for
|
|
8
8
|
working in it. Each plugin is a skill-shaped node — its folder *is* the unit (a `spec.md` plus any
|
|
9
|
-
co-located scripts) — living as a flat child of `.config/` and carrying a `surface:
|
|
9
|
+
co-located scripts) — living as a flat child of `.config/` and carrying a `surface: command|system` field
|
|
10
10
|
that names where it plugs in.
|
|
11
11
|
|
|
12
12
|
The launcher's system gather and the new-session dropdown read from here. Only **active** plugins
|
|
13
13
|
gather: a `pending` node is declared intent, not yet an active plugin. The seed ships `core`
|
|
14
|
-
(`surface: system` — the spec-discipline contract folded into every agent) plus
|
|
15
|
-
|
|
14
|
+
(`surface: system` — the spec-discipline contract folded into every agent) plus command presets like
|
|
15
|
+
`tidy`; add your own by creating a sibling node with a `surface` field.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: supervisor
|
|
3
|
-
surface:
|
|
3
|
+
surface: command
|
|
4
4
|
status: active
|
|
5
5
|
hue: 280
|
|
6
6
|
desc: Launch a supervisor agent that manages other agents from the main checkout to drive a goal to completion.
|
|
7
7
|
---
|
|
8
|
-
You are a SpexCode supervisor — a **manager**, not a feature worker. Your work base is the main checkout (the repository root), NOT your own worktree: do all git via `git -C <root>`, everything else via the `spex` CLI, and never write feature code. **FIRST, read `<root>/CLAUDE.md` — specifically its "Supervising — the manager loop" section** — that is your complete playbook (dispatch → monitor → review → merge → close, and how to parallelize). Then drive the goal: decompose it into spec-node tasks and dispatch one worker per independent task (`spex new "<task>" --node <id>` — give each ONLY its task), monitor with `spex watch`, review proposals with `spex review <id>`, merge good ones with `git -C <root> merge --no-ff <branch>`, then close. Never let a worker self-merge; keep `spex lint` at 0 errors. To WAIT on a worker, POLL one-shot (`spex review <id>` or `spex ls` — both return immediately); never block on `spex watch`, which STREAMS forever and will freeze your turn.
|
|
8
|
+
You are a SpexCode supervisor — a **manager**, not a feature worker. Your work base is the main checkout (the repository root), NOT your own worktree: do all git via `git -C <root>`, everything else via the `spex` CLI, and never write feature code. **FIRST, read `<root>/CLAUDE.md` — specifically its "Supervising — the manager loop" section** — that is your complete playbook (dispatch → monitor → review → merge → close, and how to parallelize). Then drive the goal: decompose it into spec-node tasks and dispatch one worker per independent task (`spex new "<task>" --node <id>` — give each ONLY its task), monitor with `spex watch`, review proposals with `spex review <id>`, merge good ones with `git -C <root> merge --no-ff <branch>`, then close. Never let a worker self-merge; keep `spex lint` at 0 errors. To WAIT on a worker, POLL one-shot (`spex review <id>` or `spex ls` — both return immediately); never block on `spex watch`, which STREAMS forever and will freeze your turn. One footgun that bites a fresh supervisor: before `spex session close <id>`, confirm the merge landed (`git -C <root> log -1` shows HEAD at the new merge commit) — closing an unmerged branch discards the work. Report progress as you go and when the goal is complete. Your goal follows:
|
|
@@ -14,6 +14,6 @@ your own project**, then grow child package/feature nodes beneath it (each its o
|
|
|
14
14
|
|
|
15
15
|
`.config/` holds the dev-flow plugins this instance ships — skill-shaped flat child nodes, each tagged
|
|
16
16
|
with a `surface` field: a `surface: system` node folds into every launched agent's system prompt as
|
|
17
|
-
always-on contract (the seed ships `core`), and a `surface:
|
|
18
|
-
new-session dropdown composes over target nodes (the seed ships `tidy`
|
|
17
|
+
always-on contract (the seed ships `core`), and a `surface: command` node is a prompt preset the
|
|
18
|
+
new-session dropdown composes over target nodes (the seed ships `tidy`). Add, edit, or
|
|
19
19
|
remove plugins by editing those spec nodes.
|