biotonomy 0.2.1 → 0.2.3
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 +63 -176
- package/bt +12 -1
- package/commands/loop.sh +34 -13
- package/commands/plan-review.sh +6 -1
- package/commands/pr.sh +14 -22
- package/commands/spec.sh +81 -30
- package/lib/gates.sh +9 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,211 +1,98 @@
|
|
|
1
1
|
# Biotonomy
|
|
2
2
|
|
|
3
|
-
Biotonomy is a
|
|
3
|
+
Biotonomy (`bt`) is a CLI for running a Codex-driven development workflow in a repo:
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- Who it is for: Developers who want a structured way to ship small changes fast.
|
|
7
|
-
- What problem it solves: Keeps work organized in files, runs quality checks, and reduces "what do I do next?" during AI-assisted coding.
|
|
5
|
+
`spec -> research -> plan-review -> implement -> review -> fix -> pr`
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
It supports both:
|
|
8
|
+
- manual stage-by-stage execution
|
|
9
|
+
- a one-command iterative loop with `bt loop`
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## Quickstart
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
npm i -g biotonomy
|
|
15
|
-
# then use: bt ...
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npx biotonomy ...
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Minimal demo in a fresh repo:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
mkdir biotonomy-demo && cd biotonomy-demo
|
|
26
|
-
git init
|
|
27
|
-
npm init -y
|
|
28
|
-
|
|
29
|
-
npx biotonomy bootstrap
|
|
30
|
-
npx biotonomy spec hello-world
|
|
31
|
-
npx biotonomy review hello-world
|
|
32
|
-
npx biotonomy status
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Expected files after the demo:
|
|
36
|
-
|
|
37
|
-
- `.bt.env`
|
|
38
|
-
- `.bt/`
|
|
39
|
-
- `specs/hello-world/SPEC.md`
|
|
40
|
-
- `specs/hello-world/REVIEW.md`
|
|
41
|
-
- `specs/hello-world/progress.txt`
|
|
42
|
-
- `specs/hello-world/history/001-spec.md`
|
|
43
|
-
- `specs/hello-world/history/002-review.md`
|
|
44
|
-
- `specs/hello-world/.artifacts/codex-review.log`
|
|
45
|
-
|
|
46
|
-
Notes:
|
|
47
|
-
|
|
48
|
-
- `review` still creates `REVIEW.md` even if Codex is not installed.
|
|
49
|
-
- `research` requires Codex.
|
|
50
|
-
|
|
51
|
-
## Ship A Small Change
|
|
52
|
-
|
|
53
|
-
Use this for a real change from idea to PR.
|
|
54
|
-
|
|
55
|
-
1. `spec` (define the change)
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
bt spec my-change
|
|
59
|
-
# or from GitHub issue:
|
|
60
|
-
# bt spec 123
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
- Automated today: creates `specs/<feature>/SPEC.md`, history, and progress logs.
|
|
64
|
-
- Manual today: fill in/clean up stories and acceptance criteria in `SPEC.md`.
|
|
65
|
-
|
|
66
|
-
2. `research` (gather context)
|
|
13
|
+
Prereqs: Node.js >= 18, `git`, Codex CLI available as `codex` (or set `BT_CODEX_BIN`).
|
|
67
14
|
|
|
68
15
|
```bash
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- Automated today: runs Codex in read-only mode and writes `RESEARCH.md`.
|
|
73
|
-
- Manual today: confirm research quality and adjust plan if needed.
|
|
74
|
-
|
|
75
|
-
3. `implement` (make the change)
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
bt implement my-change
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
- Automated today: runs Codex in full-auto and then runs quality gates.
|
|
82
|
-
- Manual today: if Codex is unavailable, this stage is a stub and you implement changes yourself.
|
|
83
|
-
|
|
84
|
-
4. `review` (check what changed)
|
|
85
|
-
|
|
86
|
-
```bash
|
|
87
|
-
bt review my-change
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
- Automated today: writes `REVIEW.md` (with a fallback stub if Codex fails).
|
|
91
|
-
- Manual today: decide whether findings are acceptable for your team.
|
|
92
|
-
|
|
93
|
-
5. `fix` (address findings)
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
bt fix my-change
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
- Automated today: runs Codex fix pass and re-runs quality gates.
|
|
100
|
-
- Manual today: rerun until you are satisfied; no built-in auto-loop to "done" yet.
|
|
101
|
-
|
|
102
|
-
6. `pr` (open pull request)
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
bt pr my-change --dry-run
|
|
106
|
-
bt pr my-change --run
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
- Automated today: runs tests/lint, creates branch, optionally commits, pushes, opens PR via `gh`.
|
|
110
|
-
- Manual today: choose reviewers/labels, final PR polish, and merge strategy.
|
|
111
|
-
|
|
112
|
-
## Current Limitations
|
|
113
|
-
|
|
114
|
-
- No one-command autonomous loop yet (you run each stage yourself).
|
|
115
|
-
- `research` needs Codex installed and available.
|
|
116
|
-
- `implement`/`fix` can run as stubs without Codex (gates still run, code may not change).
|
|
117
|
-
- PR flow depends on `gh` and repository permissions.
|
|
118
|
-
|
|
119
|
-
## Troubleshooting
|
|
120
|
-
|
|
121
|
-
`gh` auth fails (`bt spec 123` or `bt pr ...`):
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
gh auth status
|
|
125
|
-
gh auth login
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Codex missing (`codex required` or `codex not found`):
|
|
129
|
-
|
|
130
|
-
- Install Codex and make sure `codex` is on your `PATH`.
|
|
131
|
-
- Or set a custom binary in `.bt.env`: `BT_CODEX_BIN=/path/to/codex`.
|
|
132
|
-
|
|
133
|
-
Quality gate failures on `implement`/`fix`:
|
|
134
|
-
|
|
135
|
-
```bash
|
|
136
|
-
bt gates my-change
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
- Fix failing lint/typecheck/test commands.
|
|
140
|
-
- Override gate commands in `.bt.env` if auto-detection is wrong:
|
|
141
|
-
- `BT_GATE_LINT=...`
|
|
142
|
-
- `BT_GATE_TYPECHECK=...`
|
|
143
|
-
- `BT_GATE_TEST=...`
|
|
144
|
-
|
|
145
|
-
## Release Publish Steps
|
|
146
|
-
|
|
147
|
-
Use this when preparing an npm release. This workflow validates readiness but does not publish automatically.
|
|
148
|
-
|
|
149
|
-
1. Confirm clean main branch and pull latest changes.
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
git checkout main
|
|
153
|
-
git pull --ff-only
|
|
154
|
-
```
|
|
16
|
+
# Install
|
|
17
|
+
npm i -g biotonomy
|
|
155
18
|
|
|
156
|
-
|
|
19
|
+
# In your project repo
|
|
20
|
+
bt bootstrap
|
|
157
21
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
22
|
+
# Create a feature scaffold
|
|
23
|
+
FEATURE=hello-world
|
|
24
|
+
bt spec "$FEATURE"
|
|
161
25
|
|
|
162
|
-
|
|
26
|
+
# Loop requires an approved plan review verdict first
|
|
27
|
+
cat > "specs/$FEATURE/PLAN_REVIEW.md" <<'MD'
|
|
28
|
+
Verdict: APPROVED_PLAN
|
|
29
|
+
MD
|
|
163
30
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
# if needed:
|
|
167
|
-
npm login
|
|
31
|
+
# Run autonomous implement/review/fix iterations (with gates)
|
|
32
|
+
bt loop "$FEATURE" --max-iterations 3
|
|
168
33
|
```
|
|
169
34
|
|
|
170
|
-
|
|
35
|
+
## `bt loop`
|
|
171
36
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
37
|
+
`bt loop <feature> [--max-iterations N]` runs:
|
|
38
|
+
1. preflight quality gates
|
|
39
|
+
2. `implement`
|
|
40
|
+
3. `review`
|
|
41
|
+
4. `fix` only when review verdict is `NEEDS_CHANGES`
|
|
42
|
+
5. repeat until verdict is `APPROVE`/`APPROVED` and gates pass, or max iterations is reached
|
|
176
43
|
|
|
177
|
-
|
|
44
|
+
Loop hard-requires an approved `specs/<feature>/PLAN_REVIEW.md` verdict (`APPROVE_PLAN` or `APPROVED_PLAN`).
|
|
178
45
|
|
|
179
|
-
|
|
180
|
-
git push --follow-tags
|
|
181
|
-
```
|
|
46
|
+
## Artifacts And State
|
|
182
47
|
|
|
183
|
-
|
|
48
|
+
Biotonomy writes feature state under `specs/<feature>/`:
|
|
49
|
+
- `SPEC.md`
|
|
50
|
+
- `RESEARCH.md`
|
|
51
|
+
- `PLAN_REVIEW.md`
|
|
52
|
+
- `REVIEW.md`
|
|
53
|
+
- `history/` stage snapshots (`###-<stage>.md`) and loop iteration snapshots (`*-loop-iter-###.md`)
|
|
54
|
+
- `loop-progress.json` loop summary and per-iteration status
|
|
55
|
+
- `progress.txt` append-only stage log
|
|
56
|
+
- `.artifacts/` Codex logs and command artifacts (for example `codex-implement.log`, `codex-review.log`, `codex-fix.log`)
|
|
57
|
+
- `gates.json` feature gate results when running `bt gates <feature>`
|
|
184
58
|
|
|
185
|
-
|
|
186
|
-
npm publish --access public
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
- If your npm account uses 2FA for publish, npm will require a one-time code during `npm publish`.
|
|
59
|
+
Global gate state is written to `.bt/state/gates.json` when running `bt gates` without a feature.
|
|
190
60
|
|
|
191
|
-
## Commands
|
|
61
|
+
## Manual Commands
|
|
192
62
|
|
|
193
63
|
```bash
|
|
194
64
|
bt bootstrap
|
|
195
65
|
bt spec <feature|issue#>
|
|
196
66
|
bt research <feature>
|
|
67
|
+
bt plan-review <feature>
|
|
197
68
|
bt implement <feature>
|
|
198
69
|
bt review <feature>
|
|
199
70
|
bt fix <feature>
|
|
71
|
+
bt loop <feature> [--max-iterations N]
|
|
200
72
|
bt gates [feature]
|
|
201
73
|
bt status
|
|
202
|
-
bt pr <feature> [--
|
|
203
|
-
|
|
74
|
+
bt pr <feature> [--run]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Configuration
|
|
78
|
+
|
|
79
|
+
Project config lives in `.bt.env` (created by `bt bootstrap`). Common overrides:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
BT_SPECS_DIR=specs
|
|
83
|
+
BT_STATE_DIR=.bt
|
|
84
|
+
BT_GATE_LINT="npm run lint"
|
|
85
|
+
BT_GATE_TYPECHECK="tsc --noEmit"
|
|
86
|
+
BT_GATE_TEST="npm test"
|
|
87
|
+
BT_CODEX_BIN="/path/to/codex"
|
|
204
88
|
```
|
|
205
89
|
|
|
206
|
-
##
|
|
90
|
+
## Release
|
|
91
|
+
|
|
92
|
+
Run the release readiness checks:
|
|
207
93
|
|
|
208
94
|
```bash
|
|
209
|
-
npm
|
|
210
|
-
npm run lint
|
|
95
|
+
npm run release:ready
|
|
211
96
|
```
|
|
97
|
+
|
|
98
|
+
That script runs tests, lint, pack verification, and `npm pack --dry-run`.
|
package/bt
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
bt_script_dir() {
|
|
5
|
+
local src="${BASH_SOURCE[0]}"
|
|
6
|
+
while [ -h "$src" ]; do
|
|
7
|
+
local dir
|
|
8
|
+
dir="$(cd -P "$(dirname "$src")" && pwd)"
|
|
9
|
+
src="$(readlink "$src")"
|
|
10
|
+
[[ "$src" != /* ]] && src="$dir/$src"
|
|
11
|
+
done
|
|
12
|
+
cd -P "$(dirname "$src")" && pwd
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
SCRIPT_DIR="$(bt_script_dir)"
|
|
5
16
|
exec "$SCRIPT_DIR/bt.sh" "$@"
|
package/commands/loop.sh
CHANGED
|
@@ -59,15 +59,6 @@ bt_cmd_loop() {
|
|
|
59
59
|
bt_env_load || true
|
|
60
60
|
bt_ensure_dirs
|
|
61
61
|
|
|
62
|
-
bt_info "starting loop for: $feature (max iterations: $max_iter)"
|
|
63
|
-
|
|
64
|
-
bt_info "running preflight gates..."
|
|
65
|
-
if ! bt_run_gates; then
|
|
66
|
-
bt_err "preflight gates failed; aborting before implement/review"
|
|
67
|
-
return 1
|
|
68
|
-
fi
|
|
69
|
-
bt_info "preflight gates: PASS"
|
|
70
|
-
|
|
71
62
|
local feat_dir
|
|
72
63
|
feat_dir="$(bt_feature_dir "$feature")"
|
|
73
64
|
local plan_review="$feat_dir/PLAN_REVIEW.md"
|
|
@@ -77,6 +68,27 @@ bt_cmd_loop() {
|
|
|
77
68
|
bt_die "loop hard-fails without approved PLAN_REVIEW verdict before implement/review"
|
|
78
69
|
fi
|
|
79
70
|
|
|
71
|
+
bt_info "starting loop for: $feature (max iterations: $max_iter)"
|
|
72
|
+
|
|
73
|
+
local -a gate_args=()
|
|
74
|
+
if [[ "${BT_LOOP_REQUIRE_GATES:-0}" == "1" ]]; then
|
|
75
|
+
gate_args=(--require-any)
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
bt_info "running preflight gates..."
|
|
79
|
+
if (( ${#gate_args[@]} > 0 )); then
|
|
80
|
+
if ! bt_run_gates "${gate_args[@]}"; then
|
|
81
|
+
bt_err "preflight gates failed (or none configured); aborting before implement/review"
|
|
82
|
+
return 1
|
|
83
|
+
fi
|
|
84
|
+
else
|
|
85
|
+
if ! bt_run_gates; then
|
|
86
|
+
bt_err "preflight gates failed (or none configured); aborting before implement/review"
|
|
87
|
+
return 1
|
|
88
|
+
fi
|
|
89
|
+
fi
|
|
90
|
+
bt_info "preflight gates: PASS"
|
|
91
|
+
|
|
80
92
|
# Source required commands so we can call them directly
|
|
81
93
|
# shellcheck source=/dev/null
|
|
82
94
|
source "$BT_ROOT/commands/implement.sh"
|
|
@@ -165,11 +177,20 @@ PY
|
|
|
165
177
|
# bt_cmd_implement/fix return non-zero if gates fail, but we capture the status.
|
|
166
178
|
# We call bt_run_gates here just to be sure of the final state post-review.
|
|
167
179
|
local gates_ok=1
|
|
168
|
-
if
|
|
169
|
-
|
|
170
|
-
|
|
180
|
+
if (( ${#gate_args[@]} > 0 )); then
|
|
181
|
+
if ! bt_run_gates "${gate_args[@]}"; then
|
|
182
|
+
gates_ok=0
|
|
183
|
+
bt_info "gates: FAIL"
|
|
184
|
+
else
|
|
185
|
+
bt_info "gates: PASS"
|
|
186
|
+
fi
|
|
171
187
|
else
|
|
172
|
-
|
|
188
|
+
if ! bt_run_gates; then
|
|
189
|
+
gates_ok=0
|
|
190
|
+
bt_info "gates: FAIL"
|
|
191
|
+
else
|
|
192
|
+
bt_info "gates: PASS"
|
|
193
|
+
fi
|
|
173
194
|
fi
|
|
174
195
|
|
|
175
196
|
local fix_status="SKIP"
|
package/commands/plan-review.sh
CHANGED
|
@@ -31,7 +31,12 @@ EOF
|
|
|
31
31
|
|
|
32
32
|
if bt_codex_available; then
|
|
33
33
|
bt_info "running codex (full-auto) using prompts/plan-review.md"
|
|
34
|
-
|
|
34
|
+
local artifacts_dir codex_logf
|
|
35
|
+
artifacts_dir="$dir/.artifacts"
|
|
36
|
+
mkdir -p "$artifacts_dir"
|
|
37
|
+
codex_logf="$artifacts_dir/codex-plan-review.log"
|
|
38
|
+
: >"$codex_logf"
|
|
39
|
+
if BT_FEATURE="$feature" BT_CODEX_LOG_FILE="$codex_logf" bt_codex_exec_full_auto "$BT_ROOT/prompts/plan-review.md"; then
|
|
35
40
|
:
|
|
36
41
|
else
|
|
37
42
|
bt_die "codex failed (plan-review)"
|
package/commands/pr.sh
CHANGED
|
@@ -189,20 +189,19 @@ bt_cmd_pr() {
|
|
|
189
189
|
fi
|
|
190
190
|
|
|
191
191
|
# 2. Fail-loud preflight for unstaged expected files (before tests/commit flow).
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
fi
|
|
192
|
+
# P0 #18: fail-loud even with --no-commit
|
|
193
|
+
local unstaged=""
|
|
194
|
+
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
195
|
+
# Protect all repo files, not only a fixed allowlist of directories.
|
|
196
|
+
unstaged="$(git ls-files --others --modified --exclude-standard 2>/dev/null || true)"
|
|
197
|
+
else
|
|
198
|
+
# Outside a git repo, treat present files (except .git internals) as unstaged by definition.
|
|
199
|
+
unstaged="$(find . -path './.git' -prune -o -type f -print 2>/dev/null | sed 's#^\./##' | LC_ALL=C sort || true)"
|
|
200
|
+
fi
|
|
201
|
+
if [[ -n "$unstaged" ]]; then
|
|
202
|
+
bt_err "Found unstaged files that might be required for this feature:"
|
|
203
|
+
printf '%s\n' "$unstaged" >&2
|
|
204
|
+
bt_die "Abort: ship requires all feature files to be staged. Use git add and try again."
|
|
206
205
|
fi
|
|
207
206
|
|
|
208
207
|
if [[ "$run_mode" == "dry-run" ]]; then
|
|
@@ -255,14 +254,7 @@ bt_cmd_pr() {
|
|
|
255
254
|
# 4. Commit changes if requested
|
|
256
255
|
if [[ "$commit" == "1" ]]; then
|
|
257
256
|
bt_info "committing changes..."
|
|
258
|
-
|
|
259
|
-
local check_paths=(tests lib commands scripts specs prompts)
|
|
260
|
-
unstaged="$(git status --porcelain -- "${check_paths[@]}" 2>/dev/null || true)"
|
|
261
|
-
if [[ -n "$unstaged" ]]; then
|
|
262
|
-
bt_err "Found unstaged files that might be required for this feature:"
|
|
263
|
-
printf '%s\n' "$unstaged" >&2
|
|
264
|
-
bt_die "Abort: ship requires all feature files to be staged. Use git add and try again."
|
|
265
|
-
fi
|
|
257
|
+
# (Unstaged check removed here as it is now redundant with global T0 check)
|
|
266
258
|
|
|
267
259
|
if ! git diff --cached --quiet; then
|
|
268
260
|
git commit -m "feat($feature): ship implementation"
|
package/commands/spec.sh
CHANGED
|
@@ -38,6 +38,84 @@ NODE
|
|
|
38
38
|
)"
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
bt__stories_from_issue_json() {
|
|
42
|
+
bt__require_cmd node
|
|
43
|
+
node -e "$(
|
|
44
|
+
cat <<'NODE'
|
|
45
|
+
const fs = require("fs");
|
|
46
|
+
const j = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
|
|
47
|
+
|
|
48
|
+
function clean(s) {
|
|
49
|
+
return String(s || "").replace(/\s+/g, " ").trim();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const title = clean(j.title);
|
|
53
|
+
const body = String(j.body || "").replace(/\r/g, "");
|
|
54
|
+
const lines = body.split("\n");
|
|
55
|
+
|
|
56
|
+
let inAcceptance = false;
|
|
57
|
+
const acceptanceBullets = [];
|
|
58
|
+
const allBullets = [];
|
|
59
|
+
for (const rawLine of lines) {
|
|
60
|
+
const line = rawLine || "";
|
|
61
|
+
if (/^\s*#{1,6}\s*acceptance\b/i.test(line) || /^\s*acceptance criteria\s*:?\s*$/i.test(line)) {
|
|
62
|
+
inAcceptance = true;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (/^\s*#{1,6}\s+/.test(line) && inAcceptance) {
|
|
66
|
+
inAcceptance = false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const m = line.match(/^\s*[-*]\s+(?:\[[ xX]\]\s*)?(.+?)\s*$/);
|
|
70
|
+
if (!m) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const bullet = clean(m[1]);
|
|
74
|
+
if (!bullet) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
allBullets.push(bullet);
|
|
78
|
+
if (inAcceptance) {
|
|
79
|
+
acceptanceBullets.push(bullet);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const selectedBullets = acceptanceBullets.length > 0 ? acceptanceBullets : allBullets;
|
|
84
|
+
const storyTitles = [];
|
|
85
|
+
if (title) {
|
|
86
|
+
storyTitles.push(title);
|
|
87
|
+
}
|
|
88
|
+
for (const bullet of selectedBullets) {
|
|
89
|
+
if (storyTitles.length >= 5) {
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
storyTitles.push(bullet);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (storyTitles.length === 0) {
|
|
96
|
+
const fallback = clean(body).slice(0, 120);
|
|
97
|
+
if (fallback) {
|
|
98
|
+
storyTitles.push(fallback);
|
|
99
|
+
} else {
|
|
100
|
+
storyTitles.push("Capture issue requirements");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let out = "";
|
|
105
|
+
for (let i = 0; i < storyTitles.length; i += 1) {
|
|
106
|
+
const id = i + 1;
|
|
107
|
+
const titleText = storyTitles[i];
|
|
108
|
+
out += "## [ID:S" + id + "] " + titleText + "\n";
|
|
109
|
+
out += "- **status:** draft\n";
|
|
110
|
+
out += "- **priority:** " + (id <= 3 ? 1 : 2) + "\n";
|
|
111
|
+
out += "- **acceptance:** " + titleText + "\n";
|
|
112
|
+
out += "- **tests:**\n\n";
|
|
113
|
+
}
|
|
114
|
+
process.stdout.write(out);
|
|
115
|
+
NODE
|
|
116
|
+
)"
|
|
117
|
+
}
|
|
118
|
+
|
|
41
119
|
bt_cmd_spec() {
|
|
42
120
|
local force=0
|
|
43
121
|
local arg=""
|
|
@@ -132,8 +210,9 @@ EOF
|
|
|
132
210
|
[[ -n "$title" ]] || title="(untitled)"
|
|
133
211
|
[[ -n "$url" ]] || url="https://github.com/$repo/issues/$issue"
|
|
134
212
|
|
|
135
|
-
local summary
|
|
213
|
+
local summary stories
|
|
136
214
|
summary="$(bt__summarize_body "$body")"
|
|
215
|
+
stories="$(printf '%s' "$json" | bt__stories_from_issue_json)"
|
|
137
216
|
|
|
138
217
|
cat >"$spec" <<EOF
|
|
139
218
|
---
|
|
@@ -154,35 +233,7 @@ $summary
|
|
|
154
233
|
|
|
155
234
|
# Stories
|
|
156
235
|
|
|
157
|
-
|
|
158
|
-
- **status:** draft
|
|
159
|
-
- **priority:** 1
|
|
160
|
-
- **acceptance:** bt can determine repo slug from git remote origin; otherwise requires BT_REPO
|
|
161
|
-
- **tests:**
|
|
162
|
-
|
|
163
|
-
## [ID:S2] Fetch issue details via gh
|
|
164
|
-
- **status:** draft
|
|
165
|
-
- **priority:** 1
|
|
166
|
-
- **acceptance:** bt spec <issue#> uses gh to retrieve title/body/url and handles errors clearly
|
|
167
|
-
- **tests:**
|
|
168
|
-
|
|
169
|
-
## [ID:S3] Generate a SPEC.md with frontmatter + problem summary
|
|
170
|
-
- **status:** draft
|
|
171
|
-
- **priority:** 1
|
|
172
|
-
- **acceptance:** SPEC includes required frontmatter, a Problem section, and a Stories section (3-7 stories)
|
|
173
|
-
- **tests:**
|
|
174
|
-
|
|
175
|
-
## [ID:S4] Record exact gh commands used in SPEC footer
|
|
176
|
-
- **status:** draft
|
|
177
|
-
- **priority:** 2
|
|
178
|
-
- **acceptance:** SPEC footer includes the exact gh command(s) executed
|
|
179
|
-
- **tests:**
|
|
180
|
-
|
|
181
|
-
## [ID:S5] Add tests stubbing gh via PATH
|
|
182
|
-
- **status:** draft
|
|
183
|
-
- **priority:** 1
|
|
184
|
-
- **acceptance:** tests run offline and validate SPEC content generation
|
|
185
|
-
- **tests:**
|
|
236
|
+
${stories}
|
|
186
237
|
|
|
187
238
|
---
|
|
188
239
|
|
package/lib/gates.sh
CHANGED
|
@@ -77,6 +77,12 @@ bt_get_gate_config() {
|
|
|
77
77
|
# Runs gates and returns a JSON string fragment with results.
|
|
78
78
|
# Writes logs to stderr. Returns 0 if all gates passed, 1 otherwise.
|
|
79
79
|
bt_run_gates() {
|
|
80
|
+
local require_any=0
|
|
81
|
+
if [[ "${1:-}" == "--require-any" ]]; then
|
|
82
|
+
require_any=1
|
|
83
|
+
shift
|
|
84
|
+
fi
|
|
85
|
+
|
|
80
86
|
local config
|
|
81
87
|
config="$(bt_get_gate_config)"
|
|
82
88
|
|
|
@@ -115,6 +121,9 @@ bt_run_gates() {
|
|
|
115
121
|
if [[ "$any" == "0" ]]; then
|
|
116
122
|
bt_warn "no gates ran"
|
|
117
123
|
printf '{"ts": "%s", "results": {}}\n' "$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
|
|
124
|
+
if [[ "$require_any" == "1" ]]; then
|
|
125
|
+
return 1
|
|
126
|
+
fi
|
|
118
127
|
return 0
|
|
119
128
|
fi
|
|
120
129
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "biotonomy",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Codex-native autonomous development loop CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"homepage": "https://github.com/archive-dot-com/biotonomy#readme",
|
|
14
14
|
"bin": {
|
|
15
|
-
"bt": "bt"
|
|
15
|
+
"bt": "bt",
|
|
16
|
+
"biotonomy": "bt"
|
|
16
17
|
},
|
|
17
18
|
"files": [
|
|
18
19
|
"bt",
|