get-shit-done-cc 1.10.0-experimental.0 → 1.10.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.
Files changed (61) hide show
  1. package/README.md +16 -17
  2. package/agents/gsd-executor.md +375 -37
  3. package/agents/gsd-planner.md +108 -15
  4. package/bin/install.js +163 -238
  5. package/commands/gsd/help.md +0 -43
  6. package/commands/gsd/new-project.md +8 -94
  7. package/commands/gsd/plan-phase.md +5 -35
  8. package/get-shit-done/references/verification-patterns.md +1 -1
  9. package/get-shit-done/templates/phase-prompt.md +4 -4
  10. package/get-shit-done/templates/state.md +0 -37
  11. package/get-shit-done/workflows/execute-phase.md +1 -44
  12. package/get-shit-done/workflows/execute-plan.md +856 -34
  13. package/hooks/dist/gsd-statusline.js +9 -6
  14. package/package.json +7 -10
  15. package/agents/design-specialist.md +0 -222
  16. package/commands/gsd/autopilot.md +0 -518
  17. package/commands/gsd/checkpoints.md +0 -229
  18. package/commands/gsd/design-system.md +0 -70
  19. package/commands/gsd/discuss-design.md +0 -77
  20. package/commands/gsd/extend.md +0 -80
  21. package/get-shit-done/references/ccr-integration.md +0 -468
  22. package/get-shit-done/references/checkpoint-execution.md +0 -369
  23. package/get-shit-done/references/checkpoint-types.md +0 -728
  24. package/get-shit-done/references/deviation-rules.md +0 -215
  25. package/get-shit-done/references/framework-patterns.md +0 -543
  26. package/get-shit-done/references/ui-principles.md +0 -258
  27. package/get-shit-done/skills/gsd-extend/SKILL.md +0 -154
  28. package/get-shit-done/skills/gsd-extend/references/agent-structure.md +0 -305
  29. package/get-shit-done/skills/gsd-extend/references/extension-anatomy.md +0 -123
  30. package/get-shit-done/skills/gsd-extend/references/reference-structure.md +0 -408
  31. package/get-shit-done/skills/gsd-extend/references/template-structure.md +0 -370
  32. package/get-shit-done/skills/gsd-extend/references/validation-rules.md +0 -140
  33. package/get-shit-done/skills/gsd-extend/references/workflow-structure.md +0 -253
  34. package/get-shit-done/skills/gsd-extend/templates/agent-template.md +0 -234
  35. package/get-shit-done/skills/gsd-extend/templates/reference-template.md +0 -239
  36. package/get-shit-done/skills/gsd-extend/templates/workflow-template.md +0 -169
  37. package/get-shit-done/skills/gsd-extend/workflows/create-approach.md +0 -332
  38. package/get-shit-done/skills/gsd-extend/workflows/list-extensions.md +0 -133
  39. package/get-shit-done/skills/gsd-extend/workflows/remove-extension.md +0 -93
  40. package/get-shit-done/skills/gsd-extend/workflows/validate-extension.md +0 -184
  41. package/get-shit-done/templates/autopilot-script-simple.sh +0 -181
  42. package/get-shit-done/templates/autopilot-script.sh +0 -1142
  43. package/get-shit-done/templates/autopilot-script.sh.backup +0 -1142
  44. package/get-shit-done/templates/design-system.md +0 -238
  45. package/get-shit-done/templates/phase-design.md +0 -205
  46. package/get-shit-done/templates/phase-models-template.json +0 -71
  47. package/get-shit-done/tui/App.tsx +0 -169
  48. package/get-shit-done/tui/README.md +0 -107
  49. package/get-shit-done/tui/build.js +0 -37
  50. package/get-shit-done/tui/components/ActivityFeed.tsx +0 -126
  51. package/get-shit-done/tui/components/PhaseCard.tsx +0 -86
  52. package/get-shit-done/tui/components/StatsBar.tsx +0 -147
  53. package/get-shit-done/tui/dist/index.js +0 -387
  54. package/get-shit-done/tui/index.tsx +0 -12
  55. package/get-shit-done/tui/package-lock.json +0 -1074
  56. package/get-shit-done/tui/package.json +0 -22
  57. package/get-shit-done/tui/utils/pipeReader.ts +0 -129
  58. package/get-shit-done/workflows/design-system.md +0 -245
  59. package/get-shit-done/workflows/discuss-design.md +0 -330
  60. package/get-shit-done/workflows/execute-plan-auth.md +0 -122
  61. package/get-shit-done/workflows/execute-plan-checkpoints.md +0 -541
@@ -1,1142 +0,0 @@
1
- #!/bin/bash
2
- # ═══════════════════════════════════════════════════════════════════════════════
3
- # GSD Autopilot Script
4
- # Generated: {{timestamp}}
5
- # Project: {{project_name}}
6
- # ═══════════════════════════════════════════════════════════════════════════════
7
- #
8
- # Autonomous execution of all remaining phases in the milestone.
9
- # Each phase gets fresh 200k context via claude -p.
10
- # State persists in .planning/ - safe to interrupt and resume.
11
- #
12
- # Features:
13
- # - Real-time activity display via hooks
14
- # - Stage tracking (research -> planning -> building -> verifying)
15
- # - Git safety checks (no uncommitted files left behind)
16
- # - Phase context display (what we're building and why)
17
- #
18
- # Usage:
19
- # bash .planning/autopilot.sh # Run attached
20
- # nohup bash .planning/autopilot.sh & # Run in background
21
- #
22
- # ═══════════════════════════════════════════════════════════════════════════════
23
-
24
- set -euo pipefail
25
-
26
- # Signal to GSD commands that we're in autopilot mode
27
- export GSD_AUTOPILOT=1
28
-
29
- # ─────────────────────────────────────────────────────────────────────────────
30
- # Configuration (filled by /gsd:autopilot)
31
- # ─────────────────────────────────────────────────────────────────────────────
32
-
33
- PROJECT_DIR="{{project_dir}}"
34
- PROJECT_NAME="{{project_name}}"
35
- PHASES=({{phases}})
36
- CHECKPOINT_MODE="{{checkpoint_mode}}"
37
- MAX_RETRIES={{max_retries}}
38
- BUDGET_LIMIT={{budget_limit}}
39
- WEBHOOK_URL="{{webhook_url}}"
40
-
41
- # Model selection (from config.json)
42
- AUTOPILOT_MODEL="default"
43
-
44
- # ─────────────────────────────────────────────────────────────────────────────
45
- # Derived paths
46
- # ─────────────────────────────────────────────────────────────────────────────
47
-
48
- LOG_DIR="$PROJECT_DIR/.planning/logs"
49
- CHECKPOINT_DIR="$PROJECT_DIR/.planning/checkpoints"
50
- STATE_FILE="$PROJECT_DIR/.planning/STATE.md"
51
- ACTIVITY_PIPE="$PROJECT_DIR/.planning/logs/activity.pipe"
52
-
53
- # Export for hooks
54
- export GSD_ACTIVITY_PIPE="$ACTIVITY_PIPE"
55
- export GSD_PROJECT_DIR="$PROJECT_DIR"
56
- export GSD_LOG_DIR="$LOG_DIR"
57
-
58
- # ─────────────────────────────────────────────────────────────────────────────
59
- # Setup
60
- # ─────────────────────────────────────────────────────────────────────────────
61
-
62
- cd "$PROJECT_DIR"
63
- mkdir -p "$LOG_DIR" "$CHECKPOINT_DIR/pending" "$CHECKPOINT_DIR/approved"
64
-
65
- # Create activity pipe for hook communication
66
- rm -f "$ACTIVITY_PIPE"
67
- mkfifo "$ACTIVITY_PIPE" 2>/dev/null || true
68
-
69
- # Try to start Ink TUI (fallback to bash TUI if not available)
70
- INK_TUI_AVAILABLE=false
71
- INK_TUI_PID=""
72
- INK_TUI_BIN=""
73
-
74
- if command -v node &> /dev/null; then
75
- # Check for Ink TUI in the project
76
- if [ -f "$PROJECT_DIR/node_modules/.bin/gsd-autopilot-tui" ]; then
77
- INK_TUI_BIN="$PROJECT_DIR/node_modules/.bin/gsd-autopilot-tui"
78
- INK_TUI_AVAILABLE=true
79
- elif [ -f "$HOME/.npm-global/bin/gsd-autopilot-tui" ]; then
80
- INK_TUI_BIN="$HOME/.npm-global/bin/gsd-autopilot-tui"
81
- INK_TUI_AVAILABLE=true
82
- elif command -v gsd-autopilot-tui &> /dev/null; then
83
- INK_TUI_BIN="gsd-autopilot-tui"
84
- INK_TUI_AVAILABLE=true
85
- fi
86
- fi
87
-
88
- if [ "$INK_TUI_AVAILABLE" = true ]; then
89
- log "INFO" "Starting Ink TUI: $INK_TUI_BIN"
90
- export GSD_ACTIVITY_PIPE="$ACTIVITY_PIPE"
91
- export GSD_PROJECT_DIR="$PROJECT_DIR"
92
- export GSD_LOG_DIR="$LOG_DIR"
93
- export GSD_PHASE="$CURRENT_PHASE"
94
- export GSD_PHASE_NAME="$CURRENT_PHASE_NAME"
95
- export GSD_TOTAL_PHASES="${#PHASES[@]}"
96
-
97
- # Start TUI in background
98
- if [ -n "$INK_TUI_BIN" ]; then
99
- setsid "$INK_TUI_BIN" > "$LOG_DIR/tui.log" 2>&1 &
100
- INK_TUI_PID=$!
101
- log "INFO" "Ink TUI started (PID: $INK_TUI_PID)"
102
-
103
- # Wait a moment for TUI to initialize
104
- sleep 1
105
-
106
- # Check if TUI is still running
107
- if ! kill -0 $INK_TUI_PID 2>/dev/null; then
108
- log "WARN" "Ink TUI failed to start, using bash fallback"
109
- INK_TUI_AVAILABLE=false
110
- INK_TUI_PID=""
111
- fi
112
- fi
113
- else
114
- log "INFO" "Ink TUI not available, using bash TUI"
115
- fi
116
-
117
- # Lock directory (atomic creation prevents race condition)
118
- LOCK_DIR="$PROJECT_DIR/.planning/autopilot.lock.d"
119
- if ! mkdir "$LOCK_DIR" 2>/dev/null; then
120
- echo "ERROR: Autopilot already running (lock exists: $LOCK_DIR)"
121
- echo "If previous run crashed, remove manually: rmdir '$LOCK_DIR'"
122
- exit 1
123
- fi
124
-
125
- cleanup() {
126
- # Kill background processes
127
- [ -n "${READER_PID:-}" ] && kill $READER_PID 2>/dev/null
128
- [ -n "${DISPLAY_PID:-}" ] && kill $DISPLAY_PID 2>/dev/null
129
-
130
- # Kill Ink TUI if running
131
- [ -n "${INK_TUI_PID:-}" ] && kill $INK_TUI_PID 2>/dev/null || true
132
-
133
- # Remove lock and pipe
134
- rmdir "$LOCK_DIR" 2>/dev/null || true
135
- rm -f "$ACTIVITY_PIPE" 2>/dev/null || true
136
-
137
- # Restore cursor
138
- printf "\033[?25h" 2>/dev/null
139
- }
140
- trap cleanup EXIT INT TERM
141
-
142
- # ─────────────────────────────────────────────────────────────────────────────
143
- # Cross-platform helpers
144
- # ─────────────────────────────────────────────────────────────────────────────
145
-
146
- iso_timestamp() {
147
- date '+%Y-%m-%dT%H:%M:%S%z'
148
- }
149
-
150
- elapsed_since() {
151
- local start=$1
152
- local now=$(date +%s)
153
- local elapsed=$((now - start))
154
- local min=$((elapsed / 60))
155
- local sec=$((elapsed % 60))
156
- printf "%d:%02d" $min $sec
157
- }
158
-
159
- # ─────────────────────────────────────────────────────────────────────────────
160
- # Terminal UI
161
- # ─────────────────────────────────────────────────────────────────────────────
162
-
163
- # Colors and formatting (auto-disabled if not a terminal)
164
- if [ -t 1 ]; then
165
- C_RESET='\033[0m'
166
- C_BOLD='\033[1m'
167
- C_DIM='\033[2m'
168
- C_RED='\033[31m'
169
- C_GREEN='\033[32m'
170
- C_YELLOW='\033[33m'
171
- C_BLUE='\033[34m'
172
- C_CYAN='\033[36m'
173
- C_WHITE='\033[37m'
174
- CURSOR_HOME='\033[H'
175
- CURSOR_CLEAR='\033[J'
176
- CURSOR_LINE_CLEAR='\033[K'
177
- CURSOR_HIDE='\033[?25l'
178
- CURSOR_SHOW='\033[?25h'
179
- else
180
- C_RESET='' C_BOLD='' C_DIM='' C_RED='' C_GREEN='' C_YELLOW=''
181
- C_BLUE='' C_CYAN='' C_WHITE=''
182
- CURSOR_HOME='' CURSOR_CLEAR='' CURSOR_LINE_CLEAR=''
183
- CURSOR_HIDE='' CURSOR_SHOW=''
184
- fi
185
-
186
- # ─────────────────────────────────────────────────────────────────────────────
187
- # Display State (shared via temp files for subprocess communication)
188
- # ─────────────────────────────────────────────────────────────────────────────
189
-
190
- DISPLAY_STATE_DIR="$LOG_DIR/.display"
191
- mkdir -p "$DISPLAY_STATE_DIR"
192
-
193
- # Initialize display state files
194
- echo "" > "$DISPLAY_STATE_DIR/current_stage"
195
- echo "" > "$DISPLAY_STATE_DIR/stage_desc"
196
- echo "0" > "$DISPLAY_STATE_DIR/stage_start"
197
- echo "" > "$DISPLAY_STATE_DIR/completed_stages"
198
- echo "" > "$DISPLAY_STATE_DIR/activity"
199
-
200
- MAX_ACTIVITY_LINES=8
201
-
202
- # ─────────────────────────────────────────────────────────────────────────────
203
- # Stage Management
204
- # ─────────────────────────────────────────────────────────────────────────────
205
-
206
- stage_display_name() {
207
- local subagent_type="$1"
208
- case "$subagent_type" in
209
- gsd-phase-researcher) echo "RESEARCH" ;;
210
- gsd-planner) echo "PLANNING" ;;
211
- gsd-plan-checker) echo "CHECKING" ;;
212
- gsd-executor) echo "BUILDING" ;;
213
- gsd-verifier) echo "VERIFYING" ;;
214
- gsd-integration-checker) echo "INTEGRATING" ;;
215
- *) echo "WORKING" ;;
216
- esac
217
- }
218
-
219
- set_stage() {
220
- local subagent_type="$1"
221
- local description="$2"
222
-
223
- # Complete previous stage if exists
224
- local prev_stage=$(cat "$DISPLAY_STATE_DIR/current_stage" 2>/dev/null)
225
- if [ -n "$prev_stage" ]; then
226
- local prev_start=$(cat "$DISPLAY_STATE_DIR/stage_start" 2>/dev/null)
227
- local elapsed=$(elapsed_since "$prev_start")
228
- echo "$prev_stage:$elapsed" >> "$DISPLAY_STATE_DIR/completed_stages"
229
- fi
230
-
231
- local stage_name=$(stage_display_name "$subagent_type")
232
- echo "$stage_name" > "$DISPLAY_STATE_DIR/current_stage"
233
- echo "$description" > "$DISPLAY_STATE_DIR/stage_desc"
234
- echo "$(date +%s)" > "$DISPLAY_STATE_DIR/stage_start"
235
-
236
- # Send to activity pipe for Ink TUI
237
- if [ -p "$ACTIVITY_PIPE" ]; then
238
- echo "STAGE:$subagent_type:$description" > "$ACTIVITY_PIPE"
239
- fi
240
- }
241
-
242
- complete_current_stage() {
243
- local curr_stage=$(cat "$DISPLAY_STATE_DIR/current_stage" 2>/dev/null)
244
- if [ -n "$curr_stage" ]; then
245
- local stage_start=$(cat "$DISPLAY_STATE_DIR/stage_start" 2>/dev/null)
246
- local elapsed=$(elapsed_since "$stage_start")
247
- echo "$curr_stage:$elapsed" >> "$DISPLAY_STATE_DIR/completed_stages"
248
- echo "" > "$DISPLAY_STATE_DIR/current_stage"
249
- echo "" > "$DISPLAY_STATE_DIR/stage_desc"
250
- fi
251
- }
252
-
253
- reset_stages() {
254
- echo "" > "$DISPLAY_STATE_DIR/current_stage"
255
- echo "" > "$DISPLAY_STATE_DIR/stage_desc"
256
- echo "0" > "$DISPLAY_STATE_DIR/stage_start"
257
- echo "" > "$DISPLAY_STATE_DIR/completed_stages"
258
- echo "" > "$DISPLAY_STATE_DIR/activity"
259
- }
260
-
261
- # ─────────────────────────────────────────────────────────────────────────────
262
- # Activity Feed
263
- # ─────────────────────────────────────────────────────────────────────────────
264
-
265
- add_activity() {
266
- local type="$1"
267
- local detail="$2"
268
-
269
- local prefix=""
270
- case "$type" in
271
- read) prefix="read " ;;
272
- write) prefix="write " ;;
273
- edit) prefix="edit " ;;
274
- commit) prefix="commit " ;;
275
- test) prefix="test " ;;
276
- *) prefix=" " ;;
277
- esac
278
-
279
- # Truncate long paths/messages
280
- if [ ${#detail} -gt 50 ]; then
281
- detail="${detail:0:47}..."
282
- fi
283
-
284
- # Append to activity file, keep last N lines
285
- echo "$prefix $detail" >> "$DISPLAY_STATE_DIR/activity"
286
- tail -n $MAX_ACTIVITY_LINES "$DISPLAY_STATE_DIR/activity" > "$DISPLAY_STATE_DIR/activity.tmp"
287
- mv "$DISPLAY_STATE_DIR/activity.tmp" "$DISPLAY_STATE_DIR/activity"
288
-
289
- # Also write to activity pipe for Ink TUI
290
- if [ -p "$ACTIVITY_PIPE" ]; then
291
- case "$type" in
292
- read) echo "FILE:read:$detail" > "$ACTIVITY_PIPE" ;;
293
- write) echo "FILE:write:$detail" > "$ACTIVITY_PIPE" ;;
294
- edit) echo "FILE:edit:$detail" > "$ACTIVITY_PIPE" ;;
295
- commit) echo "COMMIT:$detail" > "$ACTIVITY_PIPE" ;;
296
- test) echo "TEST:test" > "$ACTIVITY_PIPE" ;;
297
- *) echo "INFO:$detail" > "$ACTIVITY_PIPE" ;;
298
- esac
299
- fi
300
- }
301
-
302
- # ─────────────────────────────────────────────────────────────────────────────
303
- # Phase Context
304
- # ─────────────────────────────────────────────────────────────────────────────
305
-
306
- CURRENT_PHASE=""
307
- CURRENT_PHASE_NAME=""
308
- CURRENT_PHASE_CONTEXT=""
309
-
310
- load_phase_context() {
311
- local phase="$1"
312
- local roadmap=".planning/ROADMAP.md"
313
-
314
- [ ! -f "$roadmap" ] && return
315
-
316
- # Extract phase name
317
- CURRENT_PHASE_NAME=$(grep -E "Phase $phase:" "$roadmap" 2>/dev/null | head -1 | sed 's/.*Phase [0-9]*: //' | sed 's/ *$//' | sed 's/\*//g')
318
- [ -z "$CURRENT_PHASE_NAME" ] && CURRENT_PHASE_NAME="Phase $phase"
319
-
320
- # Extract goal and deliverables
321
- local in_phase=0
322
- local context=""
323
- local line_count=0
324
-
325
- while IFS= read -r line; do
326
- if echo "$line" | grep -qE "Phase $phase:"; then
327
- in_phase=1
328
- continue
329
- fi
330
-
331
- if [ $in_phase -eq 1 ]; then
332
- # Stop at next phase
333
- if echo "$line" | grep -qE "^###.*Phase [0-9]"; then
334
- break
335
- fi
336
-
337
- # Capture goal
338
- if echo "$line" | grep -q "Goal:"; then
339
- context=$(echo "$line" | sed 's/.*Goal:[[:space:]]*//' | sed 's/\*//g')
340
- fi
341
-
342
- # Capture must-haves (first few)
343
- if echo "$line" | grep -qE "^[[:space:]]*-[[:space:]]" && [ $line_count -lt 4 ]; then
344
- local item=$(echo "$line" | sed 's/^[[:space:]]*-[[:space:]]*//' | sed 's/\*//g')
345
- if [ -n "$item" ]; then
346
- context="$context
347
- $item"
348
- ((line_count++))
349
- fi
350
- fi
351
- fi
352
- done < "$roadmap"
353
-
354
- CURRENT_PHASE_CONTEXT="$context"
355
- }
356
-
357
- # ─────────────────────────────────────────────────────────────────────────────
358
- # Display Rendering
359
- # ─────────────────────────────────────────────────────────────────────────────
360
-
361
- render_display() {
362
- local total_phases=$1
363
- local current_idx=$2
364
-
365
- # Read current state from files
366
- local current_stage=$(cat "$DISPLAY_STATE_DIR/current_stage" 2>/dev/null)
367
- local stage_desc=$(cat "$DISPLAY_STATE_DIR/stage_desc" 2>/dev/null)
368
- local stage_start=$(cat "$DISPLAY_STATE_DIR/stage_start" 2>/dev/null)
369
-
370
- # Header
371
- printf "${C_BOLD}${C_CYAN}"
372
- printf "═══════════════════════════════════════════════════════════════\n"
373
- printf " GSD AUTOPILOT"
374
- printf "%*s" $((46 - ${#PROJECT_NAME})) ""
375
- printf "Phase %s/%s\n" "$((current_idx + 1))" "$total_phases"
376
- printf "═══════════════════════════════════════════════════════════════${C_RESET}\n"
377
- printf "\n"
378
-
379
- # Phase info
380
- printf " ${C_BOLD}${C_WHITE}PHASE %s: %s${C_RESET}\n" "$CURRENT_PHASE" "$CURRENT_PHASE_NAME"
381
- printf "\n"
382
-
383
- # Phase context (if available)
384
- if [ -n "$CURRENT_PHASE_CONTEXT" ]; then
385
- echo "$CURRENT_PHASE_CONTEXT" | head -5 | while IFS= read -r line; do
386
- printf "${C_DIM} %s${C_RESET}\n" "$line"
387
- done
388
- printf "\n"
389
- fi
390
-
391
- printf "${C_DIM}───────────────────────────────────────────────────────────────${C_RESET}\n"
392
- printf "\n"
393
-
394
- # Completed stages
395
- if [ -f "$DISPLAY_STATE_DIR/completed_stages" ]; then
396
- while IFS= read -r stage_entry; do
397
- [ -z "$stage_entry" ] && continue
398
- local stage_name="${stage_entry%%:*}"
399
- local stage_time="${stage_entry##*:}"
400
- printf " ${C_DIM}%-12s%47s${C_RESET}\n" "$stage_name" "done $stage_time"
401
- done < "$DISPLAY_STATE_DIR/completed_stages"
402
- fi
403
-
404
- # Current stage
405
- if [ -n "$current_stage" ]; then
406
- local elapsed=""
407
- if [ -n "$stage_start" ] && [ "$stage_start" != "0" ]; then
408
- elapsed=$(elapsed_since "$stage_start")
409
- fi
410
- printf " ${C_WHITE}${C_BOLD}%-12s${C_RESET}%47s\n" "$current_stage" "$elapsed"
411
-
412
- if [ -n "$stage_desc" ]; then
413
- # Truncate description if needed
414
- local desc="$stage_desc"
415
- if [ ${#desc} -gt 55 ]; then
416
- desc="${desc:0:52}..."
417
- fi
418
- printf "\n"
419
- printf "${C_DIM} %s${C_RESET}\n" "$desc"
420
- fi
421
- fi
422
-
423
- printf "\n"
424
- printf "${C_DIM}───────────────────────────────────────────────────────────────${C_RESET}\n"
425
- printf "\n"
426
-
427
- # Activity feed
428
- printf " ${C_DIM}Activity:${C_RESET}\n"
429
- printf "\n"
430
-
431
- local activity_count=0
432
- if [ -f "$DISPLAY_STATE_DIR/activity" ] && [ -s "$DISPLAY_STATE_DIR/activity" ]; then
433
- while IFS= read -r line; do
434
- [ -z "$line" ] && continue
435
- printf "${C_DIM} %s${C_RESET}\n" "$line"
436
- ((activity_count++))
437
- done < "$DISPLAY_STATE_DIR/activity"
438
- fi
439
-
440
- if [ $activity_count -eq 0 ]; then
441
- printf "${C_DIM} waiting...${C_RESET}\n"
442
- activity_count=1
443
- fi
444
-
445
- # Pad to consistent height
446
- local pad_lines=$((MAX_ACTIVITY_LINES - activity_count))
447
- for ((i=0; i<pad_lines; i++)); do
448
- printf "\n"
449
- done
450
-
451
- printf "\n"
452
- printf "${C_DIM}───────────────────────────────────────────────────────────────${C_RESET}\n"
453
- printf "\n"
454
-
455
- # Progress bar
456
- local completed=$current_idx
457
- local bar_width=50
458
- local filled=$((completed * bar_width / total_phases))
459
- local empty=$((bar_width - filled))
460
-
461
- printf " Progress ["
462
- printf "${C_CYAN}"
463
- for ((i=0; i<filled; i++)); do printf "="; done
464
- for ((i=0; i<empty; i++)); do printf " "; done
465
- printf "${C_RESET}"
466
- printf "] %d/%d phases\n" "$completed" "$total_phases"
467
-
468
- printf "\n"
469
- printf "${C_DIM}───────────────────────────────────────────────────────────────${C_RESET}\n"
470
- }
471
-
472
- # ─────────────────────────────────────────────────────────────────────────────
473
- # Activity Pipe Reader (runs in background)
474
- # ─────────────────────────────────────────────────────────────────────────────
475
-
476
- READER_PID=""
477
- DISPLAY_PID=""
478
-
479
- start_activity_reader() {
480
- local total_phases=$1
481
- local phase_idx=$2
482
-
483
- # Background process to read from pipe and update state
484
- (
485
- while true; do
486
- if read -r line < "$ACTIVITY_PIPE" 2>/dev/null; then
487
- case "$line" in
488
- STAGE:*)
489
- local type=$(echo "$line" | cut -d: -f2)
490
- local desc=$(echo "$line" | cut -d: -f3-)
491
- set_stage "$type" "$desc"
492
- ;;
493
- FILE:*)
494
- local op=$(echo "$line" | cut -d: -f2)
495
- local file=$(echo "$line" | cut -d: -f3-)
496
- add_activity "$op" "$file"
497
- ;;
498
- COMMIT:*)
499
- local msg=$(echo "$line" | cut -d: -f2-)
500
- add_activity "commit" "$msg"
501
- ;;
502
- TEST:*)
503
- add_activity "test" "running tests"
504
- ;;
505
- TODO:*)
506
- local task=$(echo "$line" | cut -d: -f2-)
507
- echo "$task" > "$DISPLAY_STATE_DIR/stage_desc"
508
- ;;
509
- esac
510
- fi
511
- done
512
- ) &
513
- READER_PID=$!
514
-
515
- # Background process to refresh display (only if Ink TUI not available)
516
- if [ -t 1 ] && [ "$INK_TUI_AVAILABLE" = false ]; then
517
- (
518
- while true; do
519
- printf "${CURSOR_HOME}${CURSOR_CLEAR}"
520
- render_display "$total_phases" "$phase_idx"
521
- sleep 0.5
522
- done
523
- ) &
524
- DISPLAY_PID=$!
525
- fi
526
- }
527
-
528
- stop_activity_reader() {
529
- if [ -n "$READER_PID" ]; then
530
- kill $READER_PID 2>/dev/null || true
531
- wait $READER_PID 2>/dev/null || true
532
- READER_PID=""
533
- fi
534
- if [ -n "$DISPLAY_PID" ]; then
535
- kill $DISPLAY_PID 2>/dev/null || true
536
- wait $DISPLAY_PID 2>/dev/null || true
537
- DISPLAY_PID=""
538
- fi
539
- }
540
-
541
- # ─────────────────────────────────────────────────────────────────────────────
542
- # Logging & Notifications
543
- # ─────────────────────────────────────────────────────────────────────────────
544
-
545
- log() {
546
- local level="$1"
547
- local message="$2"
548
- local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
549
-
550
- # Always write to log file
551
- echo "[$timestamp] [$level] $message" >> "$LOG_DIR/autopilot.log"
552
- }
553
-
554
- notify() {
555
- local message="$1"
556
- local status="${2:-info}"
557
-
558
- log "NOTIFY" "$message"
559
-
560
- # Terminal bell
561
- printf "\a"
562
-
563
- # Webhook if configured
564
- if [ -n "$WEBHOOK_URL" ]; then
565
- curl -s -X POST "$WEBHOOK_URL" \
566
- -H "Content-Type: application/json" \
567
- -d "{\"text\": \"GSD Autopilot [$PROJECT_NAME]: $message\", \"status\": \"$status\"}" \
568
- > /dev/null 2>&1 || true
569
- fi
570
- }
571
-
572
- # ─────────────────────────────────────────────────────────────────────────────
573
- # Git Safety
574
- # ─────────────────────────────────────────────────────────────────────────────
575
-
576
- check_uncommitted_files() {
577
- local context="$1"
578
-
579
- # Check for uncommitted changes
580
- if ! git diff --quiet HEAD 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then
581
- local uncommitted=$(git status --short 2>/dev/null)
582
-
583
- log "WARN" "Uncommitted files detected ($context)"
584
- log "WARN" "$uncommitted"
585
-
586
- # Create safety commit
587
- git add -A 2>/dev/null
588
- git commit -m "wip(autopilot): uncommitted files from $context
589
-
590
- Autopilot detected uncommitted files that would otherwise be lost.
591
- Review and squash/revert as appropriate.
592
- " 2>/dev/null || true
593
-
594
- log "INFO" "Created safety commit for orphaned files"
595
- add_activity "commit" "wip: safety commit"
596
- return 1
597
- fi
598
- return 0
599
- }
600
-
601
- ensure_clean_working_tree() {
602
- local context="$1"
603
- check_uncommitted_files "$context" || true
604
- }
605
-
606
- # ─────────────────────────────────────────────────────────────────────────────
607
- # State Management
608
- # ─────────────────────────────────────────────────────────────────────────────
609
-
610
- update_autopilot_state() {
611
- local mode="$1"
612
- local phase="$2"
613
- local remaining="$3"
614
- local error="${4:-none}"
615
-
616
- if grep -q "## Autopilot" "$STATE_FILE" 2>/dev/null; then
617
- awk -v mode="$mode" -v phase="$phase" -v remaining="$remaining" -v error="$error" -v ts="$(iso_timestamp)" '
618
- /^## Autopilot/,/^## / {
619
- if (/^- \*\*Mode:\*\*/) { print "- **Mode:** " mode; next }
620
- if (/^- \*\*Current Phase:\*\*/) { print "- **Current Phase:** " phase; next }
621
- if (/^- \*\*Phases Remaining:\*\*/) { print "- **Phases Remaining:** " remaining; next }
622
- if (/^- \*\*Last Error:\*\*/) { print "- **Last Error:** " error; next }
623
- if (/^- \*\*Updated:\*\*/) { print "- **Updated:** " ts; next }
624
- }
625
- { print }
626
- ' "$STATE_FILE" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
627
- else
628
- cat >> "$STATE_FILE" << EOF
629
-
630
- ## Autopilot
631
-
632
- - **Mode:** $mode
633
- - **Started:** $(iso_timestamp)
634
- - **Current Phase:** $phase
635
- - **Phases Remaining:** $remaining
636
- - **Checkpoints Pending:** (none)
637
- - **Last Error:** $error
638
- - **Updated:** $(iso_timestamp)
639
- EOF
640
- fi
641
- }
642
-
643
- # ─────────────────────────────────────────────────────────────────────────────
644
- # Cost Tracking
645
- # ─────────────────────────────────────────────────────────────────────────────
646
-
647
- TOTAL_TOKENS=0
648
- TOTAL_COST_CENTS=0
649
-
650
- track_cost() {
651
- local log_file="$1"
652
- local phase="$2"
653
-
654
- local tokens=$(grep -o 'tokens[: ]*[0-9,]*' "$log_file" 2>/dev/null | tail -1 | grep -o '[0-9]*' | tr -d ',' || echo "0")
655
-
656
- if [ "$tokens" -gt 0 ]; then
657
- TOTAL_TOKENS=$((TOTAL_TOKENS + tokens))
658
-
659
- local cost_cents=$((tokens / 100))
660
- TOTAL_COST_CENTS=$((TOTAL_COST_CENTS + cost_cents))
661
-
662
- local total_dollars=$((TOTAL_COST_CENTS / 100))
663
- local total_remainder=$((TOTAL_COST_CENTS % 100))
664
- local total_cost=$(printf "%d.%02d" $total_dollars $total_remainder)
665
-
666
- log "COST" "Phase $phase: ${tokens} tokens (~\$${total_cost} total)"
667
- fi
668
-
669
- # Budget check
670
- if [ "$BUDGET_LIMIT" -gt 0 ]; then
671
- local budget_cents=$((BUDGET_LIMIT * 100))
672
- if [ "$TOTAL_COST_CENTS" -gt "$budget_cents" ]; then
673
- local total_dollars=$((TOTAL_COST_CENTS / 100))
674
- local total_remainder=$((TOTAL_COST_CENTS % 100))
675
- local total_cost=$(printf "%d.%02d" $total_dollars $total_remainder)
676
- notify "Budget exceeded: \$${total_cost} / \$${BUDGET_LIMIT}" "error"
677
- update_autopilot_state "paused" "$phase" "${PHASES[*]}" "budget_exceeded"
678
- exit 0
679
- fi
680
-
681
- local warning_threshold=$((budget_cents * 80 / 100))
682
- if [ "$TOTAL_COST_CENTS" -gt "$warning_threshold" ]; then
683
- notify "Budget warning: 80% used" "warning"
684
- fi
685
- fi
686
- }
687
-
688
- # ─────────────────────────────────────────────────────────────────────────────
689
- # Model Selection & CCR Integration
690
- # ─────────────────────────────────────────────────────────────────────────────
691
-
692
- CLAUDE_CMD="claude"
693
- CCR_ACTIVATED=false
694
-
695
- # Load phase models configuration
696
- load_phase_models() {
697
- if [ ! -f "$PHASE_MODELS_CONFIG" ]; then
698
- log "INFO" "No phase models config found at $PHASE_MODELS_CONFIG"
699
- return 1
700
- fi
701
-
702
- # Parse JSON to extract model for a phase
703
- get_model_for_phase() {
704
- local phase="$1"
705
- local context="${2:-execution}"
706
-
707
- # Try to get model from phases section
708
- local model=$(grep -o "\"$phase\"[[:space:]]*:[[:space:]]*{" "$PHASE_MODELS_CONFIG" -A 5 2>/dev/null | grep -o '"model"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "")
709
-
710
- if [ -z "$model" ]; then
711
- # Fall back to context-specific model
712
- model=$(grep -o "\"$context\"[[:space:]]*:[[:space:]]*{" "$PHASE_MODELS_CONFIG" -A 5 2>/dev/null | grep -o '"model"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "")
713
- fi
714
-
715
- if [ -z "$model" ]; then
716
- # Final fallback to default model
717
- model=$(grep -o '"default_model"[[:space:]]*:[[:space:]]*"[^"]*"' "$PHASE_MODELS_CONFIG" | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "claude-3-5-sonnet-latest")
718
- fi
719
-
720
- echo "$model"
721
- }
722
-
723
- # Setup CCR environment for a specific model
724
- setup_model_for_phase() {
725
- local model="$1"
726
-
727
- # Check if CCR is available
728
- if ! command -v ccr &> /dev/null; then
729
- CLAUDE_CMD="claude"
730
- log "WARN" "CCR not found, using default claude command"
731
- return 1
732
- fi
733
-
734
- # Check if CCR is configured
735
- if [ ! -f "$HOME/.claude-code-router/config.json" ]; then
736
- CLAUDE_CMD="claude"
737
- log "WARN" "CCR config not found at ~/.claude-code-router/config.json"
738
- return 1
739
- fi
740
-
741
- # Parse provider routing from config
742
- local provider_info=$(grep -A 20 "\"provider_routing\"" "$PHASE_MODELS_CONFIG" 2>/dev/null | grep -A 5 "\"$model\"" | head -6 || echo "")
743
-
744
- if [ -n "$provider_info" ]; then
745
- local provider=$(echo "$provider_info" | grep -o '"provider"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "anthropic")
746
- local base_url=$(echo "$provider_info" | grep -o '"base_url"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*: *"\([^"]*\)".*/\1/' || echo "https://api.anthropic.com")
747
-
748
- # Export CCR environment variables
749
- export ANTHROPIC_BASE_URL="$base_url"
750
- export NO_PROXY="127.0.0.1"
751
-
752
- # Use ccr code wrapper
753
- CLAUDE_CMD="ccr code --model $model"
754
- CCR_ACTIVATED=true
755
-
756
- log "INFO" "Configured CCR for model: $model via $provider"
757
- return 0
758
- else
759
- # Model not in provider routing, try direct CCR routing
760
- CLAUDE_CMD="ccr code --model $model"
761
- CCR_ACTIVATED=true
762
- log "INFO" "Using CCR for model: $model"
763
- return 0
764
- fi
765
- }
766
- }
767
-
768
- # Execute claude command with model routing
769
- execute_claude() {
770
- local model="$1"
771
- local prompt="$2"
772
- shift 2
773
-
774
- # Setup model-specific environment
775
- setup_model_for_phase "$model"
776
-
777
- # Execute with appropriate command
778
- if [ "$CCR_ACTIVATED" = true ]; then
779
- echo "$prompt" | $CLAUDE_CMD -p "$@" 2>&1
780
- else
781
- echo "$prompt" | $CLAUDE_CMD -p --model "$model" "$@" 2>&1
782
- fi
783
- }
784
-
785
- # ─────────────────────────────────────────────────────────────────────────────
786
- # Checkpoint Handling
787
- # ─────────────────────────────────────────────────────────────────────────────
788
-
789
- queue_checkpoint() {
790
- local phase="$1"
791
- local plan="$2"
792
- local checkpoint_data="$3"
793
-
794
- local checkpoint_file="$CHECKPOINT_DIR/pending/phase-${phase}-plan-${plan}.json"
795
- echo "$checkpoint_data" > "$checkpoint_file"
796
-
797
- log "CHECKPOINT" "Queued: $checkpoint_file"
798
- notify "Checkpoint queued: Phase $phase, Plan $plan" "checkpoint"
799
- }
800
-
801
- process_approved_checkpoints() {
802
- mkdir -p "$CHECKPOINT_DIR/processed"
803
-
804
- for approval in "$CHECKPOINT_DIR/approved/"*.json; do
805
- [ -f "$approval" ] || continue
806
-
807
- if grep -q '"approved": false' "$approval" 2>/dev/null; then
808
- log "INFO" "Checkpoint rejected, skipping: $approval"
809
- mv "$approval" "$CHECKPOINT_DIR/processed/"
810
- continue
811
- fi
812
-
813
- local basename=$(basename "$approval" .json)
814
- local phase=$(echo "$basename" | sed -n 's/phase-\([0-9]*\)-.*/\1/p')
815
- local plan=$(echo "$basename" | sed -n 's/.*plan-\([0-9]*\)/\1/p')
816
-
817
- if [ -z "$phase" ] || [ -z "$plan" ]; then
818
- log "WARN" "Could not parse phase/plan from: $approval"
819
- mv "$approval" "$CHECKPOINT_DIR/processed/"
820
- continue
821
- fi
822
-
823
- log "INFO" "Processing approved checkpoint: Phase $phase, Plan $plan"
824
-
825
- local user_response=$(grep -o '"response"[[:space:]]*:[[:space:]]*"[^"]*"' "$approval" | sed 's/.*: *"//' | sed 's/"$//' || echo "")
826
- local continuation_log="$LOG_DIR/continuation-phase${phase}-plan${plan}-$(date +%Y%m%d-%H%M%S).log"
827
-
828
- add_activity "commit" "continuing from checkpoint"
829
-
830
- # Get model for checkpoint continuation
831
- local model=$(get_model_for_phase "$phase" "continuation")
832
- load_phase_models 2>/dev/null || true
833
-
834
- execute_claude "$model" "/gsd:execute-plan $phase $plan --continue --checkpoint-response \"$user_response\"" \
835
- --allowedTools "Read,Write,Edit,Glob,Grep,Bash,Task,TodoWrite,AskUserQuestion" \
836
- > "$continuation_log"
837
-
838
- if [ ${PIPESTATUS[1]} -ne 0 ]; then
839
- log "ERROR" "Continuation failed"
840
- else
841
- mv "$approval" "$CHECKPOINT_DIR/processed/"
842
- track_cost "$continuation_log" "$phase"
843
- fi
844
- done
845
- }
846
-
847
- # ─────────────────────────────────────────────────────────────────────────────
848
- # Phase Execution
849
- # ─────────────────────────────────────────────────────────────────────────────
850
-
851
- is_phase_complete() {
852
- local phase="$1"
853
- grep -qE "^- \[x\] \*\*Phase $phase" .planning/ROADMAP.md 2>/dev/null
854
- }
855
-
856
- execute_phase() {
857
- local phase="$1"
858
- local phase_idx="$2"
859
- local total_phases="$3"
860
- local attempt=1
861
- local phase_log="$LOG_DIR/phase-${phase}-$(date +%Y%m%d-%H%M%S).log"
862
-
863
- # Safety check before starting
864
- ensure_clean_working_tree "before phase $phase"
865
-
866
- # Skip completed phases
867
- if is_phase_complete "$phase"; then
868
- log "INFO" "Phase $phase already complete, skipping"
869
- return 0
870
- fi
871
-
872
- # Load phase context
873
- CURRENT_PHASE="$phase"
874
- load_phase_context "$phase"
875
- reset_stages
876
-
877
- # Start activity reader and display
878
- start_activity_reader "$total_phases" "$phase_idx"
879
-
880
- # Initial render (hide cursor for clean display)
881
- if [ -t 1 ]; then
882
- printf "${CURSOR_HIDE}${CURSOR_HOME}${CURSOR_CLEAR}"
883
- render_display "$total_phases" "$phase_idx"
884
- fi
885
-
886
- while [ $attempt -le $MAX_RETRIES ]; do
887
- if [ $attempt -gt 1 ]; then
888
- log "INFO" "Retry $attempt/$MAX_RETRIES for phase $phase"
889
- add_activity "retry" "attempt $attempt of $MAX_RETRIES"
890
- fi
891
-
892
- # Load phase models configuration
893
- load_phase_models 2>/dev/null || true
894
-
895
- # Check if phase needs planning
896
- local phase_dir=$(ls -d .planning/phases/$(printf "%02d" "$phase" 2>/dev/null || echo "$phase")-* 2>/dev/null | head -1)
897
-
898
- if [ -z "$phase_dir" ] || [ $(ls "$phase_dir"/*-PLAN.md 2>/dev/null | wc -l) -eq 0 ]; then
899
- log "INFO" "Planning phase $phase"
900
-
901
- # Get model for phase planning
902
- local model=$(get_model_for_phase "$phase" "planning")
903
-
904
- execute_claude "$model" "/gsd:plan-phase $phase" \
905
- --allowedTools "Read,Write,Edit,Glob,Grep,Bash,Task,TodoWrite,AskUserQuestion" \
906
- >> "$phase_log"
907
-
908
- if [ ${PIPESTATUS[0]} -ne 0 ]; then
909
- log "ERROR" "Planning failed for phase $phase"
910
- ((attempt++))
911
- sleep 5
912
- continue
913
- fi
914
-
915
- phase_dir=$(ls -d .planning/phases/$(printf "%02d" "$phase" 2>/dev/null || echo "$phase")-* 2>/dev/null | head -1)
916
- fi
917
-
918
- # Execution
919
- log "INFO" "Executing phase $phase"
920
-
921
- # Get model for phase execution
922
- local model=$(get_model_for_phase "$phase" "execution")
923
-
924
- execute_claude "$model" "/gsd:execute-phase $phase" \
925
- --allowedTools "Read,Write,Edit,Glob,Grep,Bash,Task,TodoWrite,AskUserQuestion" \
926
- >> "$phase_log"
927
-
928
- if [ ${PIPESTATUS[1]} -ne 0 ]; then
929
- log "ERROR" "Execution failed for phase $phase"
930
- ((attempt++))
931
- sleep 5
932
- continue
933
- fi
934
-
935
- track_cost "$phase_log" "$phase"
936
-
937
- # Check verification status
938
- local verification_file=$(ls "$phase_dir"/*-VERIFICATION.md 2>/dev/null | head -1)
939
- local status="passed"
940
-
941
- if [ -f "$verification_file" ]; then
942
- status=$(grep "^status:" "$verification_file" | head -1 | cut -d: -f2 | tr -d ' ')
943
- fi
944
-
945
- case "$status" in
946
- "passed")
947
- complete_current_stage
948
- stop_activity_reader
949
- ensure_clean_working_tree "after phase $phase"
950
- notify "Phase $phase complete" "success"
951
- return 0
952
- ;;
953
-
954
- "gaps_found")
955
- log "INFO" "Gaps found in phase $phase, planning closure"
956
-
957
- # Get model for gap closure
958
- local model=$(get_model_for_phase "$phase" "gaps")
959
-
960
- execute_claude "$model" "/gsd:plan-phase $phase --gaps" \
961
- --allowedTools "Read,Write,Edit,Glob,Grep,Bash,Task,TodoWrite,AskUserQuestion" \
962
- >> "$phase_log"
963
-
964
- if [ ${PIPESTATUS[0]} -ne 0 ]; then
965
- ((attempt++))
966
- continue
967
- fi
968
-
969
- execute_claude "$model" "/gsd:execute-phase $phase --gaps-only" \
970
- --allowedTools "Read,Write,Edit,Glob,Grep,Bash,Task,TodoWrite,AskUserQuestion" \
971
- >> "$phase_log"
972
-
973
- if [ ${PIPESTATUS[1]} -ne 0 ]; then
974
- ((attempt++))
975
- continue
976
- fi
977
-
978
- track_cost "$phase_log" "$phase"
979
-
980
- status=$(grep "^status:" "$verification_file" 2>/dev/null | tail -1 | cut -d: -f2 | tr -d ' ')
981
-
982
- if [ "$status" = "passed" ]; then
983
- complete_current_stage
984
- stop_activity_reader
985
- ensure_clean_working_tree "after phase $phase gap closure"
986
- notify "Phase $phase complete (after gap closure)" "success"
987
- return 0
988
- else
989
- ((attempt++))
990
- continue
991
- fi
992
- ;;
993
-
994
- "human_needed")
995
- if [ "$CHECKPOINT_MODE" = "queue" ]; then
996
- queue_checkpoint "$phase" "verification" "{\"type\": \"human_verification\", \"phase\": \"$phase\"}"
997
- fi
998
- complete_current_stage
999
- stop_activity_reader
1000
- ensure_clean_working_tree "after phase $phase (human verification queued)"
1001
- return 0
1002
- ;;
1003
-
1004
- *)
1005
- complete_current_stage
1006
- stop_activity_reader
1007
- ensure_clean_working_tree "after phase $phase"
1008
- return 0
1009
- ;;
1010
- esac
1011
- done
1012
-
1013
- # All retries exhausted
1014
- stop_activity_reader
1015
- ensure_clean_working_tree "after phase $phase failure"
1016
- notify "Phase $phase FAILED after $MAX_RETRIES attempts" "error"
1017
- return 1
1018
- }
1019
-
1020
- # ─────────────────────────────────────────────────────────────────────────────
1021
- # Main
1022
- # ─────────────────────────────────────────────────────────────────────────────
1023
-
1024
- main() {
1025
- local total_phases=${#PHASES[@]}
1026
- local start_time=$(date +%s)
1027
-
1028
- # Startup banner
1029
- clear 2>/dev/null || true
1030
-
1031
- printf "\n"
1032
- printf "${C_BOLD}${C_CYAN}"
1033
- printf " ██████╗ ███████╗██████╗ \n"
1034
- printf " ██╔════╝ ██╔════╝██╔══██╗\n"
1035
- printf " ██║ ███╗███████╗██║ ██║\n"
1036
- printf " ██║ ██║╚════██║██║ ██║\n"
1037
- printf " ╚██████╔╝███████║██████╔╝\n"
1038
- printf " ╚═════╝ ╚══════╝╚═════╝ \n"
1039
- printf "${C_RESET}\n"
1040
- printf "${C_BOLD}${C_WHITE} AUTOPILOT${C_RESET}\n"
1041
- printf "${C_DIM} %s${C_RESET}\n" "$PROJECT_NAME"
1042
- printf "\n"
1043
- printf "${C_DIM} Phases: %s${C_RESET}\n" "${PHASES[*]}"
1044
- printf "${C_DIM} Retries: %s per phase${C_RESET}\n" "$MAX_RETRIES"
1045
- printf "${C_DIM} Budget: \$%s${C_RESET}\n" "$BUDGET_LIMIT"
1046
- printf "${C_DIM} Checkpoints: %s${C_RESET}\n" "$CHECKPOINT_MODE"
1047
- printf "\n"
1048
- printf "${C_DIM} Starting in 3 seconds...${C_RESET}\n"
1049
-
1050
- sleep 3
1051
-
1052
- log "INFO" "Autopilot started for $PROJECT_NAME"
1053
- notify "Autopilot started" "info"
1054
-
1055
- local remaining_phases=("${PHASES[@]}")
1056
- local phase_idx=0
1057
-
1058
- for phase in "${PHASES[@]}"; do
1059
- process_approved_checkpoints
1060
-
1061
- remaining_phases=("${remaining_phases[@]:1}")
1062
- local remaining_str="${remaining_phases[*]:-none}"
1063
-
1064
- update_autopilot_state "running" "$phase" "$remaining_str"
1065
-
1066
- if ! execute_phase "$phase" "$phase_idx" "$total_phases"; then
1067
- update_autopilot_state "failed" "$phase" "$remaining_str" "phase_${phase}_failed"
1068
-
1069
- if [ -t 1 ]; then
1070
- printf "${CURSOR_SHOW}"
1071
- printf "\n${C_RED}${C_BOLD}Autopilot stopped at phase $phase${C_RESET}\n"
1072
- fi
1073
-
1074
- notify "Autopilot STOPPED at phase $phase" "error"
1075
- exit 1
1076
- fi
1077
-
1078
- ((phase_idx++))
1079
- done
1080
-
1081
- # Final checkpoint processing
1082
- process_approved_checkpoints
1083
-
1084
- # Final safety check
1085
- ensure_clean_working_tree "autopilot completion"
1086
-
1087
- # Completion
1088
- local total_time=$(($(date +%s) - start_time))
1089
- local total_min=$((total_time / 60))
1090
- local total_sec=$((total_time % 60))
1091
-
1092
- local total_dollars=$((TOTAL_COST_CENTS / 100))
1093
- local total_remainder=$((TOTAL_COST_CENTS % 100))
1094
- local total_cost=$(printf "%d.%02d" $total_dollars $total_remainder)
1095
-
1096
- update_autopilot_state "completed" "all" "none"
1097
-
1098
- if [ -t 1 ]; then
1099
- printf "${CURSOR_SHOW}"
1100
- clear
1101
-
1102
- printf "\n"
1103
- printf "${C_BOLD}${C_GREEN}"
1104
- printf " ╔═══════════════════════════════════════════════════╗\n"
1105
- printf " ║ MILESTONE COMPLETE ║\n"
1106
- printf " ╚═══════════════════════════════════════════════════╝\n"
1107
- printf "${C_RESET}\n"
1108
-
1109
- printf "${C_WHITE} Phases:${C_RESET} %d completed\n" "$total_phases"
1110
- printf "${C_WHITE} Time:${C_RESET} %dm %ds\n" "$total_min" "$total_sec"
1111
- printf "${C_WHITE} Tokens:${C_RESET} %s\n" "$TOTAL_TOKENS"
1112
- printf "${C_WHITE} Cost:${C_RESET} \$%s\n" "$total_cost"
1113
- printf "\n"
1114
- fi
1115
-
1116
- log "SUCCESS" "Milestone complete: $total_phases phases, ${total_min}m ${total_sec}s, \$$total_cost"
1117
-
1118
- # Complete milestone
1119
- echo "/gsd:complete-milestone" | claude -p \
1120
- --allowedTools "Read,Write,Edit,Glob,Grep,Bash,AskUserQuestion" \
1121
- 2>&1 | tee -a "$LOG_DIR/milestone-complete.log"
1122
-
1123
- notify "Milestone COMPLETE! $total_phases phases, \$$total_cost" "success"
1124
-
1125
- # Check for pending checkpoints
1126
- local pending_count=$(ls "$CHECKPOINT_DIR/pending/"*.json 2>/dev/null | wc -l | tr -d ' ')
1127
- if [ "$pending_count" -gt 0 ]; then
1128
- printf "\n"
1129
- printf "${C_YELLOW} Pending checkpoints: %d${C_RESET}\n" "$pending_count"
1130
- printf "${C_DIM} Run: /gsd:checkpoints${C_RESET}\n"
1131
- fi
1132
-
1133
- printf "\n"
1134
- printf "${C_DIM} Logs: %s/${C_RESET}\n" "$LOG_DIR"
1135
- printf "\n"
1136
- }
1137
-
1138
- # ─────────────────────────────────────────────────────────────────────────────
1139
- # Run
1140
- # ─────────────────────────────────────────────────────────────────────────────
1141
-
1142
- main "$@"