chiefwiggum 1.2.9 → 1.3.1

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/chiefwiggum DELETED
@@ -1,903 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- ###########################################
5
- # ░█▀▀░█░█░▀█▀░█▀▀░█▀▀░░░█░█░▀█▀░█▀▀░█▀▀░█░█░█▄█
6
- # ░█░░░█▀█░░█░░█▀▀░█▀▀░░░█▄█░░█░░█░█░█░█░█░█░█░█
7
- # ░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀░░░░░▀░▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀░▀
8
- #
9
- # Autonomous coding agent CLI
10
- ###########################################
11
-
12
- VERSION="$(grep '"version"' "$(dirname "$(realpath "$0")")/package.json" 2>/dev/null | sed 's/.*"version": "\([^"]*\)".*/\1/' || echo "dev")"
13
-
14
- # =========================================
15
- # COLORS
16
- # =========================================
17
- GREEN='\033[0;32m'
18
- YELLOW='\033[1;33m'
19
- RED='\033[0;31m'
20
- BLUE='\033[0;34m'
21
- CYAN='\033[0;36m'
22
- BOLD='\033[1m'
23
- NC='\033[0m'
24
-
25
- # =========================================
26
- # CONFIGURATION
27
- # =========================================
28
- SCRIPT_DIR="$(dirname "$(realpath "$0")")"
29
- CHIEFWIGGUM_HOME="${CHIEFWIGGUM_HOME:-$HOME/.chiefwiggum}"
30
- TEMPLATES_DIR="${CHIEFWIGGUM_HOME}/templates"
31
- BUNDLED_TEMPLATES="${SCRIPT_DIR}/templates"
32
- TODO_FILE="${TODO_FILE:-TODO.md}"
33
- COOLDOWN_SECONDS="${COOLDOWN_SECONDS:-5}"
34
-
35
- # Guardrails
36
- ITERATION_TIMEOUT_MINUTES="${ITERATION_TIMEOUT_MINUTES:-60}"
37
- MAX_CONSECUTIVE_FAILURES="${MAX_CONSECUTIVE_FAILURES:-3}"
38
- MAX_NO_COMMIT_CYCLES="${MAX_NO_COMMIT_CYCLES:-5}"
39
- MAX_CLAUDE_ATTEMPTS="${MAX_CLAUDE_ATTEMPTS:-3}"
40
-
41
- # Claude Code reliability hardening
42
- export CLAUDE_CODE_EXIT_AFTER_STOP_DELAY="${CLAUDE_CODE_EXIT_AFTER_STOP_DELAY:-30000}"
43
- export NODE_OPTIONS="--unhandled-rejections=strict${NODE_OPTIONS:+ $NODE_OPTIONS}"
44
-
45
- # =========================================
46
- # BANNER
47
- # =========================================
48
- show_banner() {
49
- echo ""
50
- echo -e "${YELLOW}░█▀▀░█░█░▀█▀░█▀▀░█▀▀░░░█░█░▀█▀░█▀▀░█▀▀░█░█░█▄█${NC}"
51
- echo -e "${YELLOW}░█░░░█▀█░░█░░█▀▀░█▀▀░░░█▄█░░█░░█░█░█░█░█░█░█░█${NC}"
52
- echo -e "${YELLOW}░▀▀▀░▀░▀░▀▀▀░▀▀▀░▀░░░░░▀░▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀░▀${NC}"
53
- echo -e "${YELLOW} Autonomous Coding Agent v${VERSION}${NC}"
54
- echo ""
55
-
56
- # Check for updates (non-blocking, 2s timeout)
57
- check_for_updates
58
- }
59
-
60
- check_for_updates() {
61
- local latest
62
- latest=$(timeout 2s npm view chiefwiggum version 2>/dev/null || echo "")
63
-
64
- if [ -n "$latest" ] && [ "$latest" != "$VERSION" ]; then
65
- echo -e "${CYAN} ✨ Update available: v${VERSION} → v${latest}${NC}"
66
- echo -e "${CYAN} Run: npx chiefwiggum@latest${NC}"
67
- echo ""
68
- fi
69
- }
70
-
71
- # =========================================
72
- # HELP
73
- # =========================================
74
- show_help() {
75
- show_banner
76
- echo "Usage: chiefwiggum [command] [options]"
77
- echo ""
78
- echo "Commands:"
79
- echo " new [plan.md] Initialize project (interactive or from plan file)"
80
- echo " loop Run the build loop on existing TODO.md"
81
- echo " status Show current project status"
82
- echo " help Show this help message"
83
- echo ""
84
- echo "Examples:"
85
- echo " chiefwiggum new # Interactive setup"
86
- echo " chiefwiggum new plans/myplan.md # Setup from plan file"
87
- echo " chiefwiggum loop # Start build loop"
88
- echo " chiefwiggum # Same as 'loop'"
89
- echo ""
90
- echo "Templates:"
91
- echo -e " ${CYAN}${TEMPLATES_DIR}${NC}"
92
- echo " Edit these to customize how specs are generated."
93
- echo ""
94
- }
95
-
96
- # =========================================
97
- # PROMPT HELPERS
98
- # =========================================
99
- ask_choice() {
100
- local prompt="$1"
101
- shift
102
- local options=("$@")
103
- local selected=0
104
- local key
105
-
106
- echo ""
107
- echo -e "${BOLD}${prompt}${NC}"
108
- echo ""
109
-
110
- # Hide cursor
111
- tput civis 2>/dev/null
112
-
113
- # Draw menu with current selection highlighted
114
- draw_menu() {
115
- for i in "${!options[@]}"; do
116
- tput el 2>/dev/null # Clear line
117
- if [ "$i" -eq "$selected" ]; then
118
- echo -e " ${CYAN}▸${NC} ${BOLD}${options[$i]}${NC}"
119
- else
120
- echo -e " ${options[$i]}"
121
- fi
122
- done
123
- }
124
-
125
- draw_menu
126
-
127
- while true; do
128
- read -rsn1 key
129
-
130
- case "$key" in
131
- $'\x1b') # Escape sequence (arrow keys)
132
- read -rsn2 key
133
- case "$key" in
134
- '[A'|'OA') # Up arrow
135
- ((selected > 0)) && ((selected--))
136
- ;;
137
- '[B'|'OB') # Down arrow
138
- ((selected < ${#options[@]} - 1)) && ((selected++))
139
- ;;
140
- esac
141
- ;;
142
- 'k') # Vim up
143
- ((selected > 0)) && ((selected--))
144
- ;;
145
- 'j') # Vim down
146
- ((selected < ${#options[@]} - 1)) && ((selected++))
147
- ;;
148
- '') # Enter key
149
- break
150
- ;;
151
- esac
152
-
153
- # Move cursor back up and redraw
154
- tput cuu ${#options[@]} 2>/dev/null
155
- draw_menu
156
- done
157
-
158
- # Show cursor again
159
- tput cnorm 2>/dev/null
160
- echo ""
161
-
162
- return $selected
163
- }
164
-
165
- ask_text() {
166
- local prompt="$1"
167
- local default="${2:-}"
168
-
169
- echo ""
170
- if [ -n "$default" ]; then
171
- read -rp "${prompt} [${default}]: " response
172
- echo "${response:-$default}"
173
- else
174
- read -rp "${prompt}: " response
175
- echo "$response"
176
- fi
177
- }
178
-
179
- ask_confirm() {
180
- local prompt="$1"
181
- local default="${2:-y}"
182
-
183
- if [ "$default" = "y" ]; then
184
- read -rp "${prompt} [Y/n]: " response
185
- [[ ! "$response" =~ ^[Nn] ]]
186
- else
187
- read -rp "${prompt} [y/N]: " response
188
- [[ "$response" =~ ^[Yy] ]]
189
- fi
190
- }
191
-
192
- # =========================================
193
- # STATUS COMMAND
194
- # =========================================
195
- cmd_status() {
196
- show_banner
197
-
198
- echo -e "${BOLD}Project Status${NC}"
199
- echo ""
200
-
201
- # Check for key files
202
- local has_todo=false
203
- local has_specs=false
204
- local has_claude_md=false
205
-
206
- [ -f "$TODO_FILE" ] && has_todo=true
207
- [ -d "specs" ] && has_specs=true
208
- [ -f "CLAUDE.md" ] && has_claude_md=true
209
-
210
- echo -e " TODO.md: $([ "$has_todo" = true ] && echo -e "${GREEN}✓${NC}" || echo -e "${RED}✗${NC}")"
211
- echo -e " specs/: $([ "$has_specs" = true ] && echo -e "${GREEN}✓${NC}" || echo -e "${RED}✗${NC}")"
212
- echo -e " CLAUDE.md: $([ "$has_claude_md" = true ] && echo -e "${GREEN}✓${NC}" || echo -e "${RED}✗${NC}")"
213
- echo ""
214
-
215
- if [ "$has_todo" = true ]; then
216
- local total=$(grep -c "^\s*- \[" "$TODO_FILE" 2>/dev/null || echo "0")
217
- local done=$(grep -c "^\s*- \[x\]" "$TODO_FILE" 2>/dev/null || echo "0")
218
- local remaining=$((total - done))
219
-
220
- echo -e "${BOLD}Tasks${NC}"
221
- echo -e " Total: ${total}"
222
- echo -e " Completed: ${GREEN}${done}${NC}"
223
- echo -e " Remaining: ${YELLOW}${remaining}${NC}"
224
- echo ""
225
- fi
226
-
227
- # Git status
228
- if git rev-parse --git-dir &>/dev/null; then
229
- local branch=$(git branch --show-current 2>/dev/null || echo "unknown")
230
- local commits=$(git rev-list --count HEAD 2>/dev/null || echo "0")
231
- echo -e "${BOLD}Git${NC}"
232
- echo -e " Branch: ${branch}"
233
- echo -e " Commits: ${commits}"
234
- fi
235
- echo ""
236
- }
237
-
238
- # =========================================
239
- # NEW COMMAND - INTERACTIVE SETUP
240
- # =========================================
241
- cmd_new() {
242
- local plan_file="${1:-}"
243
-
244
- show_banner
245
-
246
- echo -e "${BOLD}Project Setup${NC}"
247
- echo ""
248
-
249
- # Show current directory
250
- echo -e "Working directory: ${CYAN}$(pwd)${NC}"
251
- echo ""
252
-
253
- if ! ask_confirm "Initialize Chief Wiggum in this directory?"; then
254
- echo -e "${YELLOW}Aborted.${NC}"
255
- exit 0
256
- fi
257
-
258
- # Check for existing chiefwiggum files (not CLAUDE.md - that's project-specific)
259
- local existing_files=()
260
- [ -f "$TODO_FILE" ] && existing_files+=("TODO.md")
261
- [ -d "specs" ] && existing_files+=("specs/")
262
-
263
- if [ ${#existing_files[@]} -gt 0 ]; then
264
- echo ""
265
- echo -e "${YELLOW}Existing files found:${NC}"
266
- for f in "${existing_files[@]}"; do
267
- echo " - $f"
268
- done
269
- echo ""
270
- if ! ask_confirm "Overwrite these files?" "n"; then
271
- echo -e "${YELLOW}Aborted.${NC}"
272
- exit 0
273
- fi
274
- fi
275
-
276
- # Note if CLAUDE.md exists (we'll preserve it)
277
- local has_claude_md=false
278
- [ -f "CLAUDE.md" ] && has_claude_md=true
279
-
280
- # If plan file provided, use it directly
281
- if [ -n "$plan_file" ]; then
282
- if [ ! -f "$plan_file" ]; then
283
- echo -e "${RED}Plan file not found: ${plan_file}${NC}"
284
- exit 1
285
- fi
286
- generate_from_plan "$plan_file"
287
- start_loop
288
- return
289
- fi
290
-
291
- # Interactive setup
292
- ask_choice "How would you like to set up this project?" \
293
- "From a plan file - I have a plan.md ready" \
294
- "Describe it - I'll tell you what to build" \
295
- "Existing TODO - Just start the loop with current TODO.md"
296
- local setup_choice=$?
297
-
298
- case $setup_choice in
299
- 0)
300
- # From plan file
301
- echo ""
302
- # Show available plans
303
- if [ -d "plans" ] && [ "$(ls -A plans/*.md 2>/dev/null)" ]; then
304
- echo -e "${BOLD}Available plans:${NC}"
305
- for f in plans/*.md; do
306
- echo -e " ${CYAN}${f}${NC}"
307
- done
308
- echo ""
309
- fi
310
- # Use read -e for tab completion
311
- local plan_path
312
- read -e -p "Path to plan file [plans/plan.md]: " plan_path
313
- plan_path="${plan_path:-plans/plan.md}"
314
- if [ ! -f "$plan_path" ]; then
315
- echo -e "${RED}Plan file not found: ${plan_path}${NC}"
316
- exit 1
317
- fi
318
- generate_from_plan "$plan_path"
319
- ;;
320
- 1)
321
- # Describe project
322
- interactive_describe
323
- ;;
324
- 2)
325
- # Existing TODO
326
- if [ ! -f "$TODO_FILE" ]; then
327
- echo -e "${RED}No TODO.md found. Run 'chiefwiggum new' to set up first.${NC}"
328
- exit 1
329
- fi
330
- ;;
331
- esac
332
-
333
- # Ask about starting the loop
334
- echo ""
335
- ask_choice "Ready to start. What would you like to do?" \
336
- "Start the build loop now" \
337
- "Review files first, then start manually with 'chiefwiggum loop'" \
338
- "Exit"
339
- local start_choice=$?
340
-
341
- case $start_choice in
342
- 0) start_loop ;;
343
- 1)
344
- echo ""
345
- echo -e "${GREEN}Setup complete!${NC} Review your files, then run:"
346
- echo -e " ${CYAN}chiefwiggum loop${NC}"
347
- ;;
348
- 2)
349
- echo -e "${YELLOW}Exiting.${NC}"
350
- ;;
351
- esac
352
- }
353
-
354
- # =========================================
355
- # INTERACTIVE PROJECT DESCRIPTION
356
- # =========================================
357
- interactive_describe() {
358
- echo ""
359
- echo -e "${BOLD}Tell me about your project${NC}"
360
- echo ""
361
-
362
- # Project name
363
- local project_name
364
- project_name=$(ask_text "Project name")
365
-
366
- # Project type
367
- ask_choice "What type of project is this?" \
368
- "Web application (Next.js, React, etc.)" \
369
- "API / Backend service" \
370
- "CLI tool" \
371
- "Library / Package" \
372
- "Mobile app" \
373
- "Other"
374
- local project_type=$?
375
- local project_type_names=("web" "api" "cli" "library" "mobile" "other")
376
- local project_type_name="${project_type_names[$project_type]}"
377
-
378
- # Tech stack
379
- local tech_stack
380
- tech_stack=$(ask_text "Tech stack (e.g., Next.js, TypeScript, Convex)")
381
-
382
- # Description
383
- echo ""
384
- echo -e "${BOLD}Describe what you're building:${NC}"
385
- echo "(Enter description, then press Enter twice to finish)"
386
- echo ""
387
- local description=""
388
- local empty_lines=0
389
- while IFS= read -r line; do
390
- if [ -z "$line" ]; then
391
- ((empty_lines++))
392
- [ $empty_lines -ge 1 ] && break
393
- else
394
- empty_lines=0
395
- fi
396
- description+="$line"$'\n'
397
- done
398
-
399
- # Key features
400
- echo ""
401
- echo -e "${BOLD}List key features (one per line, empty line to finish):${NC}"
402
- local features=""
403
- while IFS= read -r line; do
404
- [ -z "$line" ] && break
405
- features+="- $line"$'\n'
406
- done
407
-
408
- # Generate plan content
409
- local plan_content="# ${project_name}
410
-
411
- ## Overview
412
- ${description}
413
-
414
- ## Project Type
415
- ${project_type_name}
416
-
417
- ## Tech Stack
418
- ${tech_stack}
419
-
420
- ## Key Features
421
- ${features}
422
- "
423
-
424
- # Save plan
425
- mkdir -p plans
426
- local plan_file="plans/plan.md"
427
- echo "$plan_content" > "$plan_file"
428
- echo ""
429
- echo -e "${GREEN}Plan saved to ${plan_file}${NC}"
430
-
431
- # Generate specs from plan
432
- generate_from_plan "$plan_file"
433
- }
434
-
435
- # =========================================
436
- # GENERATE SPECS FROM PLAN
437
- # =========================================
438
- generate_from_plan() {
439
- local plan_file="$1"
440
- local plan_content
441
- plan_content="$(cat "$plan_file")"
442
-
443
- echo ""
444
- echo -e "${GREEN}════════════════════════════════════════${NC}"
445
- echo -e "${GREEN} Generating specs from: ${plan_file}${NC}"
446
- echo -e "${GREEN}════════════════════════════════════════${NC}"
447
-
448
- # Check templates exist
449
- if [ ! -d "$TEMPLATES_DIR" ]; then
450
- echo -e "${RED}Templates not found at: ${TEMPLATES_DIR}${NC}"
451
- echo ""
452
- echo "Run this to set up templates:"
453
- echo -e " ${CYAN}npx chiefwiggum@latest${NC}"
454
- exit 1
455
- fi
456
-
457
- mkdir -p specs
458
-
459
- # Load templates
460
- local prd_template=$(cat "$TEMPLATES_DIR/specs/prd.md")
461
- local tech_template=$(cat "$TEMPLATES_DIR/specs/technical.md")
462
- local todo_template=$(cat "$TEMPLATES_DIR/TODO.md")
463
- local claude_template=$(cat "$TEMPLATES_DIR/CLAUDE.md")
464
-
465
- # Step 1: Generate PRD
466
- echo ""
467
- echo -e "${YELLOW}[1/4] Generating specs/prd.md...${NC}"
468
-
469
- local prd_prompt="You are filling in a PRD template based on a project plan.
470
-
471
- Here is the plan:
472
- <plan>
473
- ${plan_content}
474
- </plan>
475
-
476
- Here is the template to fill in:
477
- <template>
478
- ${prd_template}
479
- </template>
480
-
481
- Fill in the template with specific details from the plan.
482
- Replace all placeholder text in [brackets] with real content.
483
- Write the completed PRD directly to specs/prd.md.
484
- Do NOT ask questions — infer everything from the plan."
485
-
486
- echo "$prd_prompt" | claude -p --dangerously-skip-permissions 2>/dev/null
487
- echo -e "${GREEN} ✓ specs/prd.md${NC}"
488
-
489
- # Step 2: Generate Technical Spec
490
- echo ""
491
- echo -e "${YELLOW}[2/4] Generating specs/technical.md...${NC}"
492
- local prd_generated
493
- prd_generated="$(cat specs/prd.md 2>/dev/null || echo "")"
494
-
495
- local tech_prompt="You are filling in a Technical Specification template based on a PRD.
496
-
497
- Here is the PRD:
498
- <prd>
499
- ${prd_generated}
500
- </prd>
501
-
502
- Here is the template to fill in:
503
- <template>
504
- ${tech_template}
505
- </template>
506
-
507
- Fill in the template with specific technical details.
508
- Replace all placeholder text in [brackets] with real content.
509
- Write the completed spec directly to specs/technical.md.
510
- Do NOT ask questions — infer everything from the PRD."
511
-
512
- echo "$tech_prompt" | claude -p --dangerously-skip-permissions 2>/dev/null
513
- echo -e "${GREEN} ✓ specs/technical.md${NC}"
514
-
515
- # Step 3: Generate CLAUDE.md (skip if exists)
516
- echo ""
517
- if [ -f "CLAUDE.md" ]; then
518
- echo -e "${YELLOW}[3/4] Skipping CLAUDE.md (already exists)${NC}"
519
- else
520
- echo -e "${YELLOW}[3/4] Generating CLAUDE.md...${NC}"
521
-
522
- local claude_prompt="You are filling in a CLAUDE.md template for a project.
523
-
524
- Here is the PRD:
525
- <prd>
526
- ${prd_generated}
527
- </prd>
528
-
529
- Here is the Technical Spec:
530
- <technical>
531
- $(cat specs/technical.md 2>/dev/null || echo "")
532
- </technical>
533
-
534
- Here is the template to fill in:
535
- <template>
536
- ${claude_template}
537
- </template>
538
-
539
- Fill in the template with project-specific details.
540
- Replace all placeholder text in [brackets] with real content.
541
- Keep it concise - this is a quick reference for AI agents.
542
- Write directly to CLAUDE.md."
543
-
544
- echo "$claude_prompt" | claude -p --dangerously-skip-permissions 2>/dev/null
545
- echo -e "${GREEN} ✓ CLAUDE.md${NC}"
546
- fi
547
-
548
- # Step 4: Generate TODO
549
- echo ""
550
- echo -e "${YELLOW}[4/4] Generating TODO.md...${NC}"
551
-
552
- local todo_prompt="You are filling in a TODO template based on specs.
553
-
554
- Here is the PRD:
555
- <prd>
556
- ${prd_generated}
557
- </prd>
558
-
559
- Here is the Technical Specification:
560
- <technical>
561
- $(cat specs/technical.md 2>/dev/null || echo "")
562
- </technical>
563
-
564
- Here is the template to follow:
565
- <template>
566
- ${todo_template}
567
- </template>
568
-
569
- Create a phased TODO.md following the template structure.
570
- Use checkbox format: - [ ] Task description
571
- Keep tasks granular (1-2 hours max each).
572
- End each phase with: - [ ] Phase N review
573
- Write directly to TODO.md."
574
-
575
- echo "$todo_prompt" | claude -p --dangerously-skip-permissions 2>/dev/null
576
- echo -e "${GREEN} ✓ TODO.md${NC}"
577
-
578
- echo ""
579
- echo -e "${GREEN}Specs generated:${NC}"
580
- echo " - specs/prd.md"
581
- echo " - specs/technical.md"
582
- if [ ! -f "CLAUDE.md" ]; then
583
- echo " - CLAUDE.md"
584
- fi
585
- echo " - TODO.md"
586
-
587
- # Commit specs
588
- if git rev-parse --git-dir &>/dev/null; then
589
- git add specs/ TODO.md CLAUDE.md 2>/dev/null || true
590
- git commit -m "chore: generate specs from plan" 2>/dev/null || true
591
- fi
592
- }
593
-
594
- # =========================================
595
- # BUILD LOOP
596
- # =========================================
597
- start_loop() {
598
- [ -f "$TODO_FILE" ] || { echo -e "${RED}Missing $TODO_FILE${NC}"; exit 1; }
599
-
600
- local max_iterations
601
- max_iterations=$(grep -c "\[ \]" "$TODO_FILE" 2>/dev/null) || max_iterations=0
602
-
603
- if [ "$max_iterations" -eq 0 ]; then
604
- echo -e "${GREEN}No unchecked tasks in $TODO_FILE. All done!${NC}"
605
- exit 0
606
- fi
607
-
608
- echo ""
609
- echo -e "${GREEN}════════════════════════════════════════${NC}"
610
- echo -e "${GREEN} Starting Build Loop${NC}"
611
- echo -e "${GREEN} Tasks remaining: ${max_iterations}${NC}"
612
- echo -e "${GREEN} Timeout: ${ITERATION_TIMEOUT_MINUTES}m per task${NC}"
613
- echo -e "${GREEN}════════════════════════════════════════${NC}"
614
-
615
- local consecutive_failures=0
616
- local no_commit_cycles=0
617
- local last_commit
618
- last_commit="$(git rev-parse HEAD 2>/dev/null || echo "none")"
619
-
620
- for i in $(seq 1 "$max_iterations"); do
621
- echo ""
622
- echo -e "${YELLOW}══════════ Task $i of $max_iterations ══════════${NC}"
623
-
624
- cleanup_stale_processes
625
-
626
- local start_time
627
- start_time="$(date +%s)"
628
-
629
- set +e
630
- run_task_iteration "$i"
631
- local claude_exit=$?
632
- set -e
633
-
634
- local duration=$(($(date +%s) - start_time))
635
- echo ""
636
- echo -e "Completed in ${duration}s (exit: ${claude_exit})"
637
-
638
- # Track failures
639
- if [ "$claude_exit" -ne 0 ]; then
640
- consecutive_failures=$((consecutive_failures + 1))
641
- echo -e "${RED}Failure ${consecutive_failures}/${MAX_CONSECUTIVE_FAILURES}${NC}"
642
- sleep 30
643
- else
644
- consecutive_failures=0
645
- fi
646
-
647
- # Track commits
648
- local current_commit
649
- current_commit="$(git rev-parse HEAD 2>/dev/null || echo "none")"
650
- if [ "$current_commit" = "$last_commit" ]; then
651
- if [ "$claude_exit" -eq 0 ]; then
652
- no_commit_cycles=$((no_commit_cycles + 1))
653
- echo -e "${YELLOW}No commit (${no_commit_cycles}/${MAX_NO_COMMIT_CYCLES})${NC}"
654
- fi
655
- else
656
- no_commit_cycles=0
657
- last_commit="$current_commit"
658
- echo -e "${GREEN}New commit: ${current_commit:0:7}${NC}"
659
- git push origin HEAD 2>/dev/null && echo "Pushed to origin" || true
660
- fi
661
-
662
- # Guardrails
663
- if [ "$consecutive_failures" -ge "$MAX_CONSECUTIVE_FAILURES" ]; then
664
- echo -e "${RED}Stopping: ${MAX_CONSECUTIVE_FAILURES} consecutive failures${NC}"
665
- exit 1
666
- fi
667
-
668
- if [ "$no_commit_cycles" -ge "$MAX_NO_COMMIT_CYCLES" ]; then
669
- echo -e "${RED}Stopping: No commits for ${MAX_NO_COMMIT_CYCLES} cycles${NC}"
670
- exit 1
671
- fi
672
-
673
- # Check if done
674
- if ! grep -q "\[ \]" "$TODO_FILE"; then
675
- echo ""
676
- echo -e "${GREEN}════════════════════════════════════════${NC}"
677
- echo -e "${GREEN} All tasks completed!${NC}"
678
- echo -e "${GREEN}════════════════════════════════════════${NC}"
679
- git push origin HEAD 2>/dev/null || true
680
- exit 0
681
- fi
682
-
683
- sleep "$COOLDOWN_SECONDS"
684
- done
685
-
686
- echo -e "${YELLOW}Reached max iterations (${max_iterations})${NC}"
687
- git push origin HEAD 2>/dev/null || true
688
- }
689
-
690
- run_task_iteration() {
691
- local iteration="$1"
692
- local log_file="/tmp/chiefwiggum-iter${iteration}.log"
693
-
694
- local task_prompt='You are an autonomous coding agent. Complete ONE task from TODO.md.
695
-
696
- ## Before Starting
697
- Read these files to understand the project:
698
- - CLAUDE.md — Project context and conventions
699
- - specs/prd.md — What we are building
700
- - specs/technical.md — How we are building it
701
- - TODO.md — Task list
702
-
703
- ## Workflow
704
- 1. Find the FIRST unchecked task (- [ ]) in TODO.md
705
- 2. Plan: Understand what needs to be done
706
- 3. Implement: Write the code
707
- 4. Review: Verify it works
708
- 5. Mark complete: Change - [ ] to - [x] in TODO.md
709
- 6. Commit: git add . && git commit -m "type(scope): description"
710
-
711
- ## Rules
712
- - ONE task per iteration
713
- - Follow existing code patterns
714
- - Use conventional commits (feat, fix, docs, refactor, test, chore)
715
- - If blocked after 3 attempts, output RALPH_BLOCKED: <reason>
716
-
717
- ## When Done
718
- Output: RALPH_COMPLETE
719
- If no tasks remain: RALPH_ALL_DONE'
720
-
721
- local claude_exit=1
722
-
723
- for attempt in $(seq 1 "$MAX_CLAUDE_ATTEMPTS"); do
724
- echo -e "${YELLOW}Attempt ${attempt}/${MAX_CLAUDE_ATTEMPTS}${NC}"
725
-
726
- echo "$task_prompt" \
727
- | timeout --kill-after=10s "${ITERATION_TIMEOUT_MINUTES}m" \
728
- claude -p --dangerously-skip-permissions --no-session-persistence \
729
- --verbose --output-format stream-json \
730
- 2>&1 \
731
- | tee "$log_file" \
732
- | jq -r '
733
- if .type == "assistant" then
734
- (.message.content[]? | select(.type=="text") | .text? // empty),
735
- (.message.content[]? | select(.type=="tool_use") | "🔧 " + .name)
736
- elif .type == "result" then
737
- "✅ " + (.subtype // "done")
738
- else empty end
739
- ' 2>/dev/null || true &
740
- local claude_pid=$!
741
-
742
- # Monitor for freeze
743
- while kill -0 $claude_pid 2>/dev/null; do
744
- if grep -q "No messages returned" "$log_file" 2>/dev/null; then
745
- echo -e "${RED}Freeze detected, killing...${NC}"
746
- kill -9 $claude_pid 2>/dev/null || true
747
- sleep 2
748
- break
749
- fi
750
- sleep 1
751
- done
752
-
753
- wait $claude_pid 2>/dev/null
754
- claude_exit=$?
755
-
756
- # Check for transient errors
757
- if [ "$claude_exit" -ne 0 ]; then
758
- if grep -qE "(No messages returned|ECONNRESET|ETIMEDOUT)" "$log_file" 2>/dev/null; then
759
- echo -e "${YELLOW}Transient error, retrying...${NC}"
760
- sleep $((attempt * 5))
761
- continue
762
- fi
763
- fi
764
-
765
- break
766
- done
767
-
768
- rm -f "$log_file"
769
- return $claude_exit
770
- }
771
-
772
- cleanup_stale_processes() {
773
- pkill -f playwright 2>/dev/null || true
774
- pkill -f chromium 2>/dev/null || true
775
- if command -v lsof &>/dev/null; then
776
- lsof -ti:3000 | xargs kill -9 2>/dev/null || true
777
- fi
778
- sleep 1
779
- }
780
-
781
- # =========================================
782
- # SETUP TEMPLATES
783
- # =========================================
784
- setup_templates() {
785
- # Copy bundled templates to ~/.chiefwiggum/templates
786
- if [ -d "$BUNDLED_TEMPLATES" ]; then
787
- mkdir -p "$CHIEFWIGGUM_HOME"
788
- cp -r "$BUNDLED_TEMPLATES" "$CHIEFWIGGUM_HOME/"
789
- echo -e "${GREEN}✓ Templates installed to: ${TEMPLATES_DIR}${NC}"
790
- fi
791
- }
792
-
793
- # =========================================
794
- # INSTALL COMMAND
795
- # =========================================
796
- cmd_install() {
797
- show_banner
798
-
799
- echo -e "${BOLD}Installing Chief Wiggum...${NC}"
800
- echo ""
801
-
802
- # Check if already installed globally
803
- if command -v chiefwiggum &>/dev/null; then
804
- local installed_path=$(which chiefwiggum)
805
- if [[ "$installed_path" != *"npx"* ]] && [[ "$installed_path" != *".npm/_npx"* ]]; then
806
- echo -e "${GREEN}✓ Already installed at: ${installed_path}${NC}"
807
- # Still set up templates in case they're missing
808
- setup_templates
809
- echo ""
810
- echo "Run 'chiefwiggum new' to get started."
811
- return 0
812
- fi
813
- fi
814
-
815
- # Install globally
816
- echo "Running: npm install -g chiefwiggum@latest"
817
- echo ""
818
-
819
- if npm install -g chiefwiggum@latest; then
820
- echo ""
821
- # Set up templates after install
822
- # Need to get the installed location
823
- local installed_dir=$(dirname "$(realpath "$(which chiefwiggum)")")
824
- if [ -d "${installed_dir}/templates" ]; then
825
- mkdir -p "$CHIEFWIGGUM_HOME"
826
- cp -r "${installed_dir}/templates" "$CHIEFWIGGUM_HOME/"
827
- echo -e "${GREEN}✓ Templates installed to: ${TEMPLATES_DIR}${NC}"
828
- fi
829
-
830
- echo ""
831
- echo -e "${GREEN}════════════════════════════════════════${NC}"
832
- echo -e "${GREEN} ✓ Installation complete!${NC}"
833
- echo -e "${GREEN}════════════════════════════════════════${NC}"
834
- echo ""
835
- echo -e "Templates: ${CYAN}${TEMPLATES_DIR}${NC}"
836
- echo ""
837
- echo "Get started:"
838
- echo -e " ${CYAN}chiefwiggum new${NC} # Set up a new project"
839
- echo -e " ${CYAN}chiefwiggum loop${NC} # Run the build loop"
840
- echo -e " ${CYAN}chiefwiggum help${NC} # See all commands"
841
- echo ""
842
- else
843
- echo ""
844
- echo -e "${RED}Installation failed.${NC}"
845
- echo "Try running with sudo: sudo npm install -g chiefwiggum"
846
- exit 1
847
- fi
848
- }
849
-
850
- # =========================================
851
- # MAIN
852
- # =========================================
853
- main() {
854
- local cmd="${1:-}"
855
-
856
- case "$cmd" in
857
- install)
858
- cmd_install
859
- ;;
860
- new)
861
- shift
862
- cmd_new "$@"
863
- ;;
864
- loop)
865
- show_banner
866
- start_loop
867
- ;;
868
- status)
869
- cmd_status
870
- ;;
871
- help|--help|-h)
872
- show_help
873
- ;;
874
- "")
875
- # No command: if running via npx, install. Otherwise run loop.
876
- if [[ "${0}" == *"npx"* ]] || [[ "${0}" == *".npm/_npx"* ]]; then
877
- cmd_install
878
- else
879
- show_banner
880
- if [ -f "$TODO_FILE" ]; then
881
- start_loop
882
- else
883
- echo -e "${YELLOW}No TODO.md found. Run 'chiefwiggum new' to get started.${NC}"
884
- exit 1
885
- fi
886
- fi
887
- ;;
888
- *)
889
- # Check if it's a file path (for backward compat with ralph.sh)
890
- if [ -f "$cmd" ]; then
891
- show_banner
892
- generate_from_plan "$cmd"
893
- start_loop
894
- else
895
- echo -e "${RED}Unknown command: ${cmd}${NC}"
896
- echo "Run 'chiefwiggum help' for usage."
897
- exit 1
898
- fi
899
- ;;
900
- esac
901
- }
902
-
903
- main "$@"