biotonomy 0.2.4 → 0.2.6

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/bt.sh CHANGED
@@ -1,7 +1,14 @@
1
1
  #!/usr/bin/env bash
2
2
  set -euo pipefail
3
3
 
4
- BT_VERSION="0.1.0"
4
+ bt_package_version() {
5
+ local pkg="$BT_ROOT/package.json"
6
+ if [[ -f "$pkg" ]]; then
7
+ awk -F '"' '/"version"[[:space:]]*:/ { print $4; exit }' "$pkg"
8
+ return 0
9
+ fi
10
+ return 1
11
+ }
5
12
 
6
13
  bt_script_dir() {
7
14
  local src="${BASH_SOURCE[0]}"
@@ -15,6 +22,8 @@ bt_script_dir() {
15
22
  }
16
23
 
17
24
  BT_ROOT="$(bt_script_dir)"
25
+ BT_VERSION="$(bt_package_version 2>/dev/null || true)"
26
+ BT_VERSION="${BT_VERSION:-0.1.0}"
18
27
 
19
28
  # shellcheck source=/dev/null
20
29
  source "$BT_ROOT/lib/log.sh"
@@ -41,7 +50,7 @@ Usage:
41
50
  bt [--target <path>] <command> [args]
42
51
 
43
52
  Commands:
44
- bootstrap spec research implement review fix loop compound design status gates reset pr ship
53
+ bootstrap spec research plan-review implement review fix loop compound design status gates reset pr ship
45
54
 
46
55
  Global options:
47
56
  -h, --help Show help
@@ -93,7 +102,26 @@ bt_dispatch() {
93
102
  shift || true
94
103
 
95
104
  case "$cmd" in
96
- -h|--help|help) bt_usage; return 0 ;;
105
+ -h|--help|help)
106
+ if [[ $# -gt 0 ]]; then
107
+ # bt help <cmd>
108
+ cmd="$1"
109
+ shift
110
+ local cmd_file="$BT_ROOT/commands/$cmd.sh"
111
+ if [[ "$cmd" == "ship" ]]; then cmd_file="$BT_ROOT/commands/pr.sh"; fi
112
+ if [[ -f "$cmd_file" ]]; then
113
+ # shellcheck source=/dev/null
114
+ source "$cmd_file"
115
+ local safe_cmd="${cmd//-/_}"
116
+ local fn="bt_${safe_cmd}_usage"
117
+ if [[ "$cmd" == "ship" ]]; then fn="bt_pr_usage"; fi
118
+ if declare -F "$fn" >/dev/null 2>&1; then
119
+ "$fn"
120
+ return 0
121
+ fi
122
+ fi
123
+ fi
124
+ bt_usage; return 0 ;;
97
125
  esac
98
126
 
99
127
  bt_env_load || true
package/commands/loop.sh CHANGED
@@ -56,6 +56,8 @@ bt_cmd_loop() {
56
56
  return 2
57
57
  fi
58
58
 
59
+ feature="$(bt_require_feature "$feature")"
60
+
59
61
  bt_env_load || true
60
62
  bt_ensure_dirs
61
63
 
@@ -70,14 +72,9 @@ bt_cmd_loop() {
70
72
 
71
73
  bt_info "starting loop for: $feature (max iterations: $max_iter)"
72
74
 
73
- local -a gate_args=()
74
- if [[ "${BT_LOOP_REQUIRE_GATES:-0}" == "1" ]]; then
75
- gate_args=(--require-any)
76
- fi
77
-
78
75
  bt_info "running preflight gates..."
79
- if (( ${#gate_args[@]} > 0 )); then
80
- if ! bt_run_gates "${gate_args[@]}"; then
76
+ if [[ "${BT_LOOP_REQUIRE_GATES:-0}" == "1" ]]; then
77
+ if ! bt_run_gates --require-any; then
81
78
  bt_err "preflight gates failed (or none configured); aborting before implement/review"
82
79
  return 1
83
80
  fi
@@ -164,6 +161,7 @@ EOF
164
161
  # Ensure subcommands return non-zero instead of exiting the entire loop process.
165
162
  export BT_DIE_MODE="return"
166
163
 
164
+
167
165
  while [[ "$iter" -lt "$max_iter" ]]; do
168
166
  iter=$((iter + 1))
169
167
  bt_info "--- Iteration $iter / $max_iter ---"
@@ -221,20 +219,11 @@ PY
221
219
  # bt_cmd_implement/fix return non-zero if gates fail, but we capture the status.
222
220
  # We call bt_run_gates here just to be sure of the final state post-review.
223
221
  local gates_ok=1
224
- if (( ${#gate_args[@]} > 0 )); then
225
- if ! bt_run_gates "${gate_args[@]}"; then
226
- gates_ok=0
227
- bt_info "gates: FAIL"
228
- else
229
- bt_info "gates: PASS"
230
- fi
222
+ if ! bt_run_gates --require-any; then
223
+ gates_ok=0
224
+ bt_info "gates: FAIL"
231
225
  else
232
- if ! bt_run_gates; then
233
- gates_ok=0
234
- bt_info "gates: FAIL"
235
- else
236
- bt_info "gates: PASS"
237
- fi
226
+ bt_info "gates: PASS"
238
227
  fi
239
228
 
240
229
  local fix_status="SKIP"
@@ -29,26 +29,20 @@ EOF
29
29
 
30
30
  local out="$dir/PLAN_REVIEW.md"
31
31
 
32
- if bt_codex_available; then
33
- bt_info "running codex (full-auto) using prompts/plan-review.md"
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
40
- :
41
- else
42
- bt_die "codex failed (plan-review)"
43
- fi
44
- else
45
- # v0.1.0 stub
46
- cat <<'EOF' > "$out"
47
- # Plan Review: Stub Approved
32
+ if ! bt_codex_available; then
33
+ bt_die "codex required for plan-review (set BT_CODEX_BIN to a valid codex executable or install codex)"
34
+ fi
48
35
 
49
- Verdict: APPROVED_PLAN
50
- EOF
51
- bt_info "wrote $out"
36
+ bt_info "running codex (full-auto) using prompts/plan-review.md"
37
+ local artifacts_dir codex_logf
38
+ artifacts_dir="$dir/.artifacts"
39
+ mkdir -p "$artifacts_dir"
40
+ codex_logf="$artifacts_dir/codex-plan-review.log"
41
+ : >"$codex_logf"
42
+ if BT_FEATURE="$feature" BT_CODEX_LOG_FILE="$codex_logf" bt_codex_exec_full_auto "$BT_ROOT/prompts/plan-review.md" "$out"; then
43
+ :
44
+ else
45
+ bt_die "codex failed (plan-review)"
52
46
  fi
53
47
 
54
48
  if [[ ! -f "$out" ]]; then
package/commands/pr.sh CHANGED
@@ -161,6 +161,7 @@ bt_cmd_pr() {
161
161
  bt_err "feature name is required"
162
162
  return 2
163
163
  fi
164
+ feature="$(bt_require_feature "$feature")"
164
165
 
165
166
  # Ensure BT_PROJECT_ROOT reflects BT_TARGET_DIR / BT_ENV_FILE, and operate within it.
166
167
  bt_env_load || true
package/commands/spec.sh CHANGED
@@ -159,13 +159,19 @@ EOF
159
159
  bt_env_load || true
160
160
  bt_ensure_dirs
161
161
 
162
- local feature issue
162
+ local feature issue url_slug
163
163
  issue=""
164
+ url_slug=""
164
165
  if [[ "$arg" =~ ^[0-9]+$ ]]; then
165
166
  issue="$arg"
166
167
  feature="issue-$arg"
168
+ elif [[ "$arg" =~ ^https?://github.com/([^/]+/[^/]+)/issues/([0-9]+) ]]; then
169
+ # support URL format
170
+ issue="${BASH_REMATCH[2]}"
171
+ url_slug="${BASH_REMATCH[1]}"
172
+ feature="issue-$issue"
167
173
  else
168
- feature="$arg"
174
+ feature="$(bt_require_feature "$arg")"
169
175
  fi
170
176
 
171
177
  local dir
@@ -186,7 +192,11 @@ EOF
186
192
  bt__require_cmd gh
187
193
 
188
194
  local repo
189
- repo="$(bt_repo_resolve "$BT_PROJECT_ROOT")"
195
+ if [[ -n "$url_slug" ]]; then
196
+ repo="$url_slug"
197
+ else
198
+ repo="$(bt_repo_resolve "$BT_PROJECT_ROOT")"
199
+ fi
190
200
 
191
201
  local -a gh_cmd
192
202
  gh_cmd=(gh issue view "$issue" -R "$repo" --json "title,body,url")
@@ -75,7 +75,7 @@ EOF
75
75
 
76
76
  bt_env_load || true
77
77
 
78
- echo "bt v0.1.0"
78
+ echo "bt v${BT_VERSION:-unknown}"
79
79
  echo "project_root: $BT_PROJECT_ROOT"
80
80
  echo "env_file: ${BT_ENV_FILE:-<none>}"
81
81
  echo "specs_dir: $BT_SPECS_DIR"
package/lib/codex.sh CHANGED
@@ -11,6 +11,7 @@ bt_codex_available() {
11
11
 
12
12
  bt_codex_exec_full_auto() {
13
13
  local prompt_file="$1"
14
+ local out_file="${2:-}"
14
15
  if ! bt_codex_available; then
15
16
  bt_warn "codex not found; skipping (set BT_CODEX_BIN or install codex)"
16
17
  return 0
@@ -19,7 +20,15 @@ bt_codex_exec_full_auto() {
19
20
  bin="$(bt_codex_bin)"
20
21
  local log_file
21
22
  log_file="${BT_CODEX_LOG_FILE:-/dev/null}"
22
- "$bin" exec --full-auto -C "$BT_PROJECT_ROOT" "$(cat "$prompt_file")" 2>&1 | tee -a "$log_file"
23
+
24
+ local -a args
25
+ args=(exec --full-auto -C "$BT_PROJECT_ROOT")
26
+ if [[ -n "$out_file" ]]; then
27
+ args+=(-o "$out_file")
28
+ fi
29
+ args+=("$(cat "$prompt_file")")
30
+
31
+ "$bin" "${args[@]}" 2>&1 | tee -a "$log_file"
23
32
  return "${PIPESTATUS[0]}"
24
33
  }
25
34
 
package/lib/state.sh CHANGED
@@ -14,10 +14,29 @@ bt_ensure_dirs() {
14
14
  mkdir -p "$(bt_specs_path)" "$BT_PROJECT_ROOT/$BT_STATE_DIR"
15
15
  }
16
16
 
17
+ bt_sanitize_feature() {
18
+ local s="${1:-}"
19
+ # Replace characters not in [A-Za-z0-9._-] with underscore
20
+ s="${s//[^A-Za-z0-9._-]/_}"
21
+ # Ensure it doesn't start with a dot or dash and isn't empty
22
+ if [[ "$s" =~ ^[._-] ]]; then
23
+ s="f$s"
24
+ fi
25
+ if [[ -z "$s" ]]; then
26
+ s="feature"
27
+ fi
28
+ printf '%s\n' "$s"
29
+ }
30
+
17
31
  bt_require_feature() {
18
32
  local feature="${1:-${BT_FEATURE:-}}"
19
33
  [[ -n "$feature" ]] || bt_die "feature required (pass as first arg or set BT_FEATURE)"
20
34
 
35
+ # Apply sanitization if it doesn't already pass validation
36
+ if [[ "$feature" == *"/"* || "$feature" == *".."* || ! "$feature" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then
37
+ feature="$(bt_sanitize_feature "$feature")"
38
+ fi
39
+
21
40
  # Prevent path traversal and keep on-disk state predictable.
22
41
  [[ "$feature" != *"/"* ]] || bt_die "invalid feature (must not contain '/'): $feature"
23
42
  [[ "$feature" != *".."* ]] || bt_die "invalid feature (must not contain '..'): $feature"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "biotonomy",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Codex-native autonomous development loop CLI",
5
5
  "license": "MIT",
6
6
  "repository": {