biotonomy 0.2.6 → 0.2.7
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/loop.sh +17 -3
- package/lib/env.sh +8 -0
- package/lib/gates.sh +51 -3
- package/package.json +1 -1
package/commands/loop.sh
CHANGED
|
@@ -63,11 +63,25 @@ bt_cmd_loop() {
|
|
|
63
63
|
|
|
64
64
|
local feat_dir
|
|
65
65
|
feat_dir="$(bt_feature_dir "$feature")"
|
|
66
|
+
|
|
67
|
+
# Auto-run plan-review if PLAN_REVIEW.md is missing or unapproved
|
|
66
68
|
local plan_review="$feat_dir/PLAN_REVIEW.md"
|
|
67
69
|
if [[ ! -f "$plan_review" ]] || ! grep -qiE "Verdict:.*(APPROVE_PLAN|APPROVED_PLAN)" "$plan_review"; then
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
bt_info "PLAN_REVIEW missing or unapproved; auto-running plan-review..."
|
|
71
|
+
# shellcheck source=/dev/null
|
|
72
|
+
source "$BT_ROOT/commands/plan-review.sh"
|
|
73
|
+
if ! bt_cmd_plan_review "$feature"; then
|
|
74
|
+
bt_err "auto plan-review failed for $feature"
|
|
75
|
+
bt_err "manually run: bt plan-review $feature"
|
|
76
|
+
bt_die "loop hard-fails without approved PLAN_REVIEW verdict before implement/review"
|
|
77
|
+
fi
|
|
78
|
+
# Re-check after auto-run
|
|
79
|
+
if [[ ! -f "$plan_review" ]] || ! grep -qiE "Verdict:.*(APPROVE_PLAN|APPROVED_PLAN)" "$plan_review"; then
|
|
80
|
+
bt_err "plan-review ran but did not produce an approved verdict"
|
|
81
|
+
bt_err "check $plan_review and re-run: bt plan-review $feature"
|
|
82
|
+
bt_die "loop hard-fails without approved PLAN_REVIEW verdict before implement/review"
|
|
83
|
+
fi
|
|
84
|
+
bt_info "plan-review auto-approved; continuing loop"
|
|
71
85
|
fi
|
|
72
86
|
|
|
73
87
|
bt_info "starting loop for: $feature (max iterations: $max_iter)"
|
package/lib/env.sh
CHANGED
|
@@ -6,6 +6,14 @@ bt__export_kv() {
|
|
|
6
6
|
local val="$2"
|
|
7
7
|
|
|
8
8
|
[[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || return 0
|
|
9
|
+
|
|
10
|
+
# Respect process env: only set if not already present in environment.
|
|
11
|
+
# This ensures BT_GATE_TEST='echo hi' bt gates works even when .bt.env
|
|
12
|
+
# contains an empty BT_GATE_TEST= line. (#38)
|
|
13
|
+
if [[ -n "${!key+x}" ]]; then
|
|
14
|
+
return 0
|
|
15
|
+
fi
|
|
16
|
+
|
|
9
17
|
# Export without eval; keep value literal even if it contains spaces/symbols.
|
|
10
18
|
export "$key=$val"
|
|
11
19
|
}
|
package/lib/gates.sh
CHANGED
|
@@ -76,6 +76,33 @@ bt_get_gate_config() {
|
|
|
76
76
|
|
|
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
|
+
bt__gate_script_exists() {
|
|
80
|
+
# Check if an npm/pnpm/yarn script actually exists in package.json.
|
|
81
|
+
# Returns 0 if the script exists or if we can't determine (non-npm project).
|
|
82
|
+
local cmd="$1"
|
|
83
|
+
local script_name=""
|
|
84
|
+
|
|
85
|
+
# Extract script name from common patterns
|
|
86
|
+
case "$cmd" in
|
|
87
|
+
"npm run "*) script_name="${cmd#npm run }" ;;
|
|
88
|
+
"npm test") script_name="test" ;;
|
|
89
|
+
"pnpm "*) script_name="${cmd#pnpm }" ;;
|
|
90
|
+
"yarn "*) script_name="${cmd#yarn }" ;;
|
|
91
|
+
*) return 0 ;; # Not an npm-style command, assume exists
|
|
92
|
+
esac
|
|
93
|
+
script_name="${script_name%% *}" # Take first word only
|
|
94
|
+
|
|
95
|
+
local pkg="$BT_PROJECT_ROOT/package.json"
|
|
96
|
+
[[ -f "$pkg" ]] || return 0 # No package.json, can't check
|
|
97
|
+
|
|
98
|
+
# Check if script exists in package.json
|
|
99
|
+
if command -v node >/dev/null 2>&1; then
|
|
100
|
+
node -e "const p=require('$pkg'); process.exit(p.scripts && p.scripts['$script_name'] ? 0 : 1)" 2>/dev/null
|
|
101
|
+
return $?
|
|
102
|
+
fi
|
|
103
|
+
return 0 # Can't verify, assume exists
|
|
104
|
+
}
|
|
105
|
+
|
|
79
106
|
bt_run_gates() {
|
|
80
107
|
local require_any=0
|
|
81
108
|
if [[ "${1:-}" == "--require-any" ]]; then
|
|
@@ -93,14 +120,35 @@ bt_run_gates() {
|
|
|
93
120
|
|
|
94
121
|
while IFS= read -r line; do
|
|
95
122
|
[[ -n "$line" ]] || continue
|
|
96
|
-
any=1
|
|
97
123
|
k="${line%%=*}"
|
|
98
124
|
v="${line#*=}"
|
|
99
125
|
|
|
126
|
+
# Skip gates explicitly set to "skip" or "" (disabled)
|
|
127
|
+
if [[ "$v" == "skip" || -z "$v" ]]; then
|
|
128
|
+
bt_warn "gate disabled: $k"
|
|
129
|
+
local entry k_json v_json
|
|
130
|
+
k_json="$(bt__json_escape "$k")"
|
|
131
|
+
v_json="$(bt__json_escape "$v")"
|
|
132
|
+
printf -v entry '"%s": {"cmd": "%s", "status": -1, "skipped": true}' "$k_json" "$v_json"
|
|
133
|
+
if [[ -z "$results_json" ]]; then results_json="$entry"; else results_json="$results_json, $entry"; fi
|
|
134
|
+
continue
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
# Skip gates whose scripts don't exist
|
|
138
|
+
if ! bt__gate_script_exists "$v"; then
|
|
139
|
+
bt_warn "gate skipped (script missing): $k ($v)"
|
|
140
|
+
local entry k_json v_json
|
|
141
|
+
k_json="$(bt__json_escape "$k")"
|
|
142
|
+
v_json="$(bt__json_escape "$v")"
|
|
143
|
+
printf -v entry '"%s": {"cmd": "%s", "status": -1, "skipped": true}' "$k_json" "$v_json"
|
|
144
|
+
if [[ -z "$results_json" ]]; then results_json="$entry"; else results_json="$results_json, $entry"; fi
|
|
145
|
+
continue
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
any=1
|
|
149
|
+
|
|
100
150
|
bt_info "gate: $k ($v)"
|
|
101
151
|
local status=0
|
|
102
|
-
# Use bash -lc for interactivity if needed, but we typically want it non-interactive.
|
|
103
|
-
# The original used bash -lc "$v". We'll stick to that but capture status.
|
|
104
152
|
if ! (cd "$BT_PROJECT_ROOT" && bash -lc "$v"); then
|
|
105
153
|
bt_err "gate failed: $k"
|
|
106
154
|
status=1
|