@oneie/claude 0.2.0 → 0.3.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/commands/do.md +4 -2
- package/package.json +1 -1
- package/scripts/do-auto.sh +97 -6
package/commands/do.md
CHANGED
|
@@ -122,7 +122,7 @@ For each **enabled** stop (per the pruned spine), in order: check if its artifac
|
|
|
122
122
|
| ↳ *ANALYZE* | — | `do-analyze.sh plans/<slug>-todo.md` — CRITICAL exit 1 blocks BUILD | bash · none |
|
|
123
123
|
| **code** | survey verdict = `build` (≥70% match → `expose`/`extend` instead) | the BUILD engine (Step 3) | sonnet · low–medium |
|
|
124
124
|
| **tests** | test file in the repo folder | test-first, one assertion per deliverable | sonnet · low |
|
|
125
|
-
| **proof** | proof artifact captured | `do-prove.sh` (browser / curl / contract / sync) + `accessibility`; **promise-check** the shipped thing against `text/<slug>.md
|
|
125
|
+
| **proof** | proof artifact captured | `do-prove.sh` (browser / curl / contract / sync) + `accessibility`; **promise-check** the shipped thing against `text/<slug>.md`. A multi-cycle plan already built on its own `do/<slug>` branch (worktree isolation — see Step 2); PROVE is the gate that branch must clear before a human merges it to trunk | sonnet · low |
|
|
126
126
|
| **docs** | feature doc + runbook exist | `tutorial` + `writer` — written against the *proven* behavior | sonnet · medium |
|
|
127
127
|
| **release** | changelog / README row | `/release` + adoption signal | sonnet · low |
|
|
128
128
|
|
|
@@ -163,6 +163,8 @@ bun .claude/scripts/do-auto.sh <slug>
|
|
|
163
163
|
|
|
164
164
|
`do-auto.sh` loops: each iteration spawns a clean `/do <slug> --next-cycle` that runs exactly one batch (W1→W4), ticks its boxes, writes state, and exits. Because each cycle starts from near-zero context, prior-cycle recon/edit/verify chatter never accumulates. The main session just kicks off the loop and reports the close.
|
|
165
165
|
|
|
166
|
+
**Worktree isolation comes free with the loop.** The loop's existence *is* the trigger — `do-auto.sh` only runs for multi-cycle plans, which is exactly the FEATURE/SCHEMA work that must not land half-built on trunk. So before the first cycle it cuts a worktree `.do-worktrees/<slug>` on branch `do/<slug>` (reusing it on resume), syncs the plan's spine artifacts into it, and runs **every cycle inside it** — each cycle's edits and box-ticks commit to that branch. Trunk never moves while the loop runs; a halt (trust `cautious` / stall / max-cycles) leaves a clean, inspectable WIP branch, and re-running `/do <slug>` resumes in the same worktree. On plan-complete the loop **reports** the merge (`git merge --no-ff do/<slug>`) rather than running it — landing to trunk is a human decision (commit only when asked), and PROVE is the gate that branch cleared to earn the merge. PATCH/FIX never reach the loop, so they run inline with no worktree.
|
|
167
|
+
|
|
166
168
|
A **single** incomplete cycle (or a PATCH/FIX) runs inline — there's nothing to isolate from, and spawning a subprocess would cost more than it saves.
|
|
167
169
|
|
|
168
170
|
**`--next-cycle` is internal.** It means "run one batch, tick boxes, exit — do **not** loop." Only `do-auto.sh` passes it; it is the recursion guard that keeps a fresh `/do` from re-entering the loop. A human never types it.
|
|
@@ -266,7 +268,7 @@ PATCH clears {1,2,3,8}. FEATURE clears all eight.
|
|
|
266
268
|
|
|
267
269
|
## Available to /do — the toolbox
|
|
268
270
|
|
|
269
|
-
**Scripts** (`.claude/scripts/`): `do-auto.sh` (*internal* — the context-isolated loop `/do` drives for multi-cycle plans) · `do-tier.sh` (tier + pruned spine + classifier + ceiling) · `do-folder.sh` (folder-aware verify/build) · `do-survey.sh` (reuse verdict) · `do-reconcile.sh` (substrate dim/verb/dead-name gate) · `do-analyze.sh` (deliverable↔cycle coverage gate) · `do-prove.sh` (surface-detect proof) · `do-smoke.sh` (deterministic outcome) · `w1-recon.ts` (prompt-cached recon) · `w4-rubric.ts` (cached parallel rubric).
|
|
271
|
+
**Scripts** (`.claude/scripts/`): `do-auto.sh` (*internal* — the context-isolated, worktree-isolated loop `/do` drives for multi-cycle plans; builds on branch `do/<slug>`, merges to trunk only on a human's say-so) · `do-tier.sh` (tier + pruned spine + classifier + ceiling) · `do-folder.sh` (folder-aware verify/build) · `do-survey.sh` (reuse verdict) · `do-reconcile.sh` (substrate dim/verb/dead-name gate) · `do-analyze.sh` (deliverable↔cycle coverage gate) · `do-prove.sh` (surface-detect proof) · `do-smoke.sh` (deterministic outcome) · `w1-recon.ts` (prompt-cached recon) · `w4-rubric.ts` (cached parallel rubric).
|
|
270
272
|
|
|
271
273
|
**Templates**: `text/template-frame.md` (promise) · `plans/template-spec.md` (design + pre-mortem + decisions) · `plans/template-todo.md` (plan + parallel budget + testing policy) · `plans/agent-template.md` (agent definition).
|
|
272
274
|
|
package/package.json
CHANGED
package/scripts/do-auto.sh
CHANGED
|
@@ -29,15 +29,84 @@ done
|
|
|
29
29
|
|
|
30
30
|
[ -z "$SLUG" ] && { echo "usage: do-auto.sh <slug> [--max-cycles N] [--dry-run]" >&2; exit 1; }
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
# Validate slug is safe (kebab-case only) before it touches any shell string.
|
|
33
|
+
# Prevents command injection if the slug ever contains metacharacters.
|
|
34
|
+
if ! printf '%s' "$SLUG" | grep -qE '^[a-zA-Z0-9][a-zA-Z0-9_-]*$'; then
|
|
35
|
+
echo "[do-auto] unsafe slug (must be alphanumeric + hyphens/underscores): $SLUG" >&2; exit 1
|
|
36
|
+
fi
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
# Trust boundary: this script runs in the developer's own workspace, invoked by /do
|
|
39
|
+
# which resolves the slug from a plans/ file the developer controls. The spawned
|
|
40
|
+
# claude subprocess uses --dangerously-skip-permissions because it is non-interactive
|
|
41
|
+
# — it cannot prompt the human for tool approvals. The workspace is the isolation
|
|
42
|
+
# boundary. Do not expose this script to untrusted input or run it in shared environments.
|
|
43
|
+
[ -f "plans/${SLUG}-todo.md" ] || { echo "[do-auto] plans/${SLUG}-todo.md not found — run /do $SLUG first" >&2; exit 1; }
|
|
44
|
+
|
|
45
|
+
# ── Worktree isolation (one per plan) ────────────────────────────────────────
|
|
46
|
+
# The loop's existence IS the trigger: do-auto only runs for multi-cycle plans
|
|
47
|
+
# (>=2 incomplete cycles) = exactly the FEATURE/SCHEMA work that must not land
|
|
48
|
+
# half-built on trunk. So every loop builds in its own worktree on branch
|
|
49
|
+
# do/<slug>, leaving trunk green until a human merges. No tier plumbing, no flag.
|
|
50
|
+
#
|
|
51
|
+
# Why a worktree and not just a branch: the main session keeps observing trunk
|
|
52
|
+
# while the loop's subprocesses build in a separate checkout — they never fight
|
|
53
|
+
# over HEAD or the working tree. A halt leaves a clean, inspectable WIP branch.
|
|
54
|
+
#
|
|
55
|
+
# trunk (BASE) ── never moves during the loop
|
|
56
|
+
# └─ do/<slug> (worktree .do-worktrees/<slug>) ── every cycle commits here
|
|
57
|
+
# plan complete → report `git merge do/<slug>` (human lands it — never auto)
|
|
58
|
+
# halt → worktree persists → re-run /do <slug> resumes in place
|
|
59
|
+
BASE="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo HEAD)"
|
|
60
|
+
BR="do/${SLUG}"
|
|
61
|
+
WT=".do-worktrees/${SLUG}"
|
|
62
|
+
|
|
63
|
+
_setup_worktree() {
|
|
64
|
+
# Idempotent: reuse an existing worktree (resume), else attach one to an
|
|
65
|
+
# existing branch (prior halt), else create branch+worktree fresh from HEAD.
|
|
66
|
+
if git -C "$WT" rev-parse --git-dir >/dev/null 2>&1; then
|
|
67
|
+
echo "[do-auto] resuming worktree $WT on $BR"
|
|
68
|
+
elif git show-ref --verify --quiet "refs/heads/$BR"; then
|
|
69
|
+
echo "[do-auto] re-attaching worktree $WT to existing branch $BR"
|
|
70
|
+
git worktree add "$WT" "$BR" >/dev/null
|
|
71
|
+
else
|
|
72
|
+
echo "[do-auto] creating worktree $WT on new branch $BR (from $BASE)"
|
|
73
|
+
git worktree add -b "$BR" "$WT" HEAD >/dev/null
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Carry the plan's own artifacts into the worktree. The spine walk may have
|
|
77
|
+
# just written promise/spec/todo uncommitted in the main tree; a worktree cut
|
|
78
|
+
# from HEAD wouldn't have them. Copy only this slug's files — never unrelated
|
|
79
|
+
# working-tree changes — then commit them as the branch baseline.
|
|
80
|
+
local f changed=0
|
|
81
|
+
for f in "plans/${SLUG}.md" "plans/${SLUG}-todo.md" "text/${SLUG}.md" ".w4-improvements.json"; do
|
|
82
|
+
if [ -f "$f" ]; then
|
|
83
|
+
mkdir -p "$WT/$(dirname "$f")"
|
|
84
|
+
if ! cmp -s "$f" "$WT/$f" 2>/dev/null; then cp "$f" "$WT/$f"; changed=1; fi
|
|
85
|
+
fi
|
|
86
|
+
done
|
|
87
|
+
if [ "$changed" -eq 1 ]; then
|
|
88
|
+
git -C "$WT" add -A
|
|
89
|
+
git -C "$WT" commit -q -m "do(${SLUG}): sync spine artifacts" 2>/dev/null || true
|
|
90
|
+
fi
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if ! $DRY_RUN; then
|
|
94
|
+
_setup_worktree
|
|
95
|
+
# All loop state now lives in the worktree — read the boxes the subprocess ticks.
|
|
96
|
+
TODO="$WT/plans/${SLUG}-todo.md"
|
|
97
|
+
TRUST="$WT/.do-trust.json"
|
|
98
|
+
else
|
|
99
|
+
TODO="plans/${SLUG}-todo.md"
|
|
100
|
+
TRUST=".do-trust.json"
|
|
101
|
+
fi
|
|
36
102
|
|
|
37
103
|
_remaining() {
|
|
38
104
|
# Count cycles in the Status section that are open ([ ]) or in-flight ([~]) — i.e. not [x].
|
|
39
105
|
# Pattern starts with '\[' (not '-') so grep never mistakes it for an option flag.
|
|
40
|
-
grep -
|
|
106
|
+
# grep -c already prints a count (0 on no match) but exits 1 then — capture it so
|
|
107
|
+
# the `|| true` swallows the exit without appending a second "0" to the output.
|
|
108
|
+
local n; n=$(grep -cE '\[[ ~]\] C[0-9]+' "$TODO" 2>/dev/null) || true
|
|
109
|
+
echo "${n:-0}"
|
|
41
110
|
}
|
|
42
111
|
|
|
43
112
|
_trust() {
|
|
@@ -71,6 +140,7 @@ while [ "$i" -lt "$MAX_CYCLES" ]; do
|
|
|
71
140
|
if [ "$stall" -ge 2 ]; then
|
|
72
141
|
echo "[do-auto] no progress for 2 iterations (${remaining} cycle(s) stuck) — halting." >&2
|
|
73
142
|
echo "[do-auto] The last cycle ticked no checkbox. Inspect $TODO, fix the blocker, then re-run /do $SLUG." >&2
|
|
143
|
+
echo "[do-auto] WIP preserved on branch $BR (worktree $WT)." >&2
|
|
74
144
|
exit 1
|
|
75
145
|
fi
|
|
76
146
|
else
|
|
@@ -81,6 +151,7 @@ while [ "$i" -lt "$MAX_CYCLES" ]; do
|
|
|
81
151
|
trust=$(_trust)
|
|
82
152
|
if [ "$trust" = "cautious" ]; then
|
|
83
153
|
echo "[do-auto] trust=cautious — halting. Fix the issue, then re-run /do $SLUG."
|
|
154
|
+
echo "[do-auto] WIP preserved on branch $BR (worktree $WT)."
|
|
84
155
|
exit 1
|
|
85
156
|
fi
|
|
86
157
|
|
|
@@ -96,11 +167,31 @@ while [ "$i" -lt "$MAX_CYCLES" ]; do
|
|
|
96
167
|
break
|
|
97
168
|
fi
|
|
98
169
|
|
|
99
|
-
# Fresh context
|
|
100
|
-
|
|
170
|
+
# Fresh context, isolated tree: the subprocess runs INSIDE the worktree, so
|
|
171
|
+
# every edit/box-tick/state-write lands on branch $BR — trunk is never touched.
|
|
172
|
+
( cd "$WT" && claude --dangerously-skip-permissions -p "/do $SLUG --next-cycle" )
|
|
173
|
+
|
|
174
|
+
# Commit the cycle on its branch. A cycle closes with a passing rubric, so it
|
|
175
|
+
# is the natural commit unit — and committed progress survives a later halt.
|
|
176
|
+
if [ -n "$(git -C "$WT" status --porcelain)" ]; then
|
|
177
|
+
git -C "$WT" add -A
|
|
178
|
+
git -C "$WT" commit -q -m "do(${SLUG}): cycle ${i}" || true
|
|
179
|
+
fi
|
|
101
180
|
done
|
|
102
181
|
|
|
182
|
+
if $DRY_RUN; then exit 0; fi
|
|
183
|
+
|
|
103
184
|
if [ "$i" -ge "$MAX_CYCLES" ]; then
|
|
104
185
|
echo "[do-auto] hit --max-cycles $MAX_CYCLES — halting"
|
|
186
|
+
echo "[do-auto] WIP preserved on branch $BR (worktree $WT)."
|
|
105
187
|
exit 1
|
|
106
188
|
fi
|
|
189
|
+
|
|
190
|
+
# Plan complete. The branch holds every cycle, proven and committed; trunk is
|
|
191
|
+
# untouched. Landing it is a human decision (commit/push only when asked), so we
|
|
192
|
+
# report the merge instead of running it — the worktree stays for inspection.
|
|
193
|
+
echo ""
|
|
194
|
+
echo "[do-auto] ✓ plan complete on branch $BR — trunk ($BASE) untouched."
|
|
195
|
+
echo "[do-auto] land: git merge --no-ff $BR # from $BASE"
|
|
196
|
+
echo "[do-auto] inspect: git -C $WT log --oneline $BASE..$BR"
|
|
197
|
+
echo "[do-auto] discard: git worktree remove $WT && git branch -D $BR"
|