forge-pipeline 0.6.0 → 0.7.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.
- package/forge +24 -5
- package/lib/agent.sh +3 -33
- package/lib/phases/01_plan.sh +25 -2
- package/lib/prompts.sh +3 -1
- package/package.json +1 -1
package/forge
CHANGED
|
@@ -62,6 +62,7 @@ Usage:
|
|
|
62
62
|
forge clean Remove .forge/ directory and branches
|
|
63
63
|
|
|
64
64
|
Options:
|
|
65
|
+
-f FILE Read task description from a file
|
|
65
66
|
--auto Skip approval gate, fully autonomous
|
|
66
67
|
--max-workers N Max parallel workers per lead (default: 4)
|
|
67
68
|
--max-leads N Max parallel leads (default: 4)
|
|
@@ -74,7 +75,8 @@ Options:
|
|
|
74
75
|
Examples:
|
|
75
76
|
forge init my-app
|
|
76
77
|
forge start Add user authentication with JWT
|
|
77
|
-
forge start
|
|
78
|
+
forge start -f prompt.txt
|
|
79
|
+
cat feedback.txt | forge start
|
|
78
80
|
forge --auto start Build a REST API with CRUD endpoints
|
|
79
81
|
EOF
|
|
80
82
|
}
|
|
@@ -549,6 +551,7 @@ USER_PROMPT=""
|
|
|
549
551
|
SUBCOMMAND=""
|
|
550
552
|
INIT_PROJECT=""
|
|
551
553
|
LOGS_AGENT=""
|
|
554
|
+
PROMPT_FILE=""
|
|
552
555
|
PROMPT_ARGS=()
|
|
553
556
|
|
|
554
557
|
while [[ $# -gt 0 ]]; do
|
|
@@ -579,11 +582,18 @@ while [[ $# -gt 0 ]]; do
|
|
|
579
582
|
[ -n "$INIT_PROJECT" ] && shift
|
|
580
583
|
break
|
|
581
584
|
;;
|
|
585
|
+
-f)
|
|
586
|
+
PROMPT_FILE="$2"; shift 2 ;;
|
|
582
587
|
start|run)
|
|
583
588
|
SUBCOMMAND="$1"
|
|
584
589
|
shift
|
|
585
|
-
#
|
|
586
|
-
|
|
590
|
+
# Check for -f after start
|
|
591
|
+
if [[ "${1:-}" == "-f" ]]; then
|
|
592
|
+
PROMPT_FILE="$2"; shift 2
|
|
593
|
+
else
|
|
594
|
+
# Everything remaining is the prompt
|
|
595
|
+
PROMPT_ARGS+=("$@")
|
|
596
|
+
fi
|
|
587
597
|
break
|
|
588
598
|
;;
|
|
589
599
|
status)
|
|
@@ -611,9 +621,18 @@ while [[ $# -gt 0 ]]; do
|
|
|
611
621
|
esac
|
|
612
622
|
done
|
|
613
623
|
|
|
614
|
-
#
|
|
615
|
-
if [
|
|
624
|
+
# Resolve prompt from args, file, or stdin
|
|
625
|
+
if [ -n "$PROMPT_FILE" ]; then
|
|
626
|
+
if [ ! -f "$PROMPT_FILE" ]; then
|
|
627
|
+
log_error "Prompt file not found: $PROMPT_FILE"
|
|
628
|
+
exit 1
|
|
629
|
+
fi
|
|
630
|
+
USER_PROMPT="$(cat "$PROMPT_FILE")"
|
|
631
|
+
elif [ ${#PROMPT_ARGS[@]} -gt 0 ]; then
|
|
616
632
|
USER_PROMPT="${PROMPT_ARGS[*]}"
|
|
633
|
+
elif [ ! -t 0 ]; then
|
|
634
|
+
# stdin is piped — read from it
|
|
635
|
+
USER_PROMPT="$(cat)"
|
|
617
636
|
fi
|
|
618
637
|
|
|
619
638
|
# Re-export updated values after argument parsing
|
package/lib/agent.sh
CHANGED
|
@@ -56,40 +56,10 @@ spawn_agent_foreground() {
|
|
|
56
56
|
local done_file="${forge_root}/.forge/status/${name}.done"
|
|
57
57
|
|
|
58
58
|
cd "$worktree_path" && \
|
|
59
|
-
claude -p "$(cat /tmp/forge-prompt-"${name}".md)" --output-format
|
|
59
|
+
claude -p "$(cat /tmp/forge-prompt-"${name}".md)" --output-format text --allowedTools "$allowed_tools" 2>&1 | \
|
|
60
60
|
while IFS= read -r line; do
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
type="$(echo "$line" | jq -r '.type // empty' 2>/dev/null)"
|
|
64
|
-
case "$type" in
|
|
65
|
-
assistant)
|
|
66
|
-
echo "$line" >> "$log_file"
|
|
67
|
-
local content
|
|
68
|
-
content="$(echo "$line" | jq -r '.message.content[]? | select(.type=="text") | .text // empty' 2>/dev/null)"
|
|
69
|
-
if [ -n "$content" ]; then
|
|
70
|
-
printf '%s\n' "$content"
|
|
71
|
-
fi
|
|
72
|
-
;;
|
|
73
|
-
content_block_delta)
|
|
74
|
-
echo "$line" >> "$log_file"
|
|
75
|
-
local delta
|
|
76
|
-
delta="$(echo "$line" | jq -r '.delta.text // empty' 2>/dev/null)"
|
|
77
|
-
if [ -n "$delta" ]; then
|
|
78
|
-
printf '%s' "$delta"
|
|
79
|
-
fi
|
|
80
|
-
;;
|
|
81
|
-
result)
|
|
82
|
-
echo "$line" >> "$log_file"
|
|
83
|
-
local result_text
|
|
84
|
-
result_text="$(echo "$line" | jq -r '.result // empty' 2>/dev/null)"
|
|
85
|
-
if [ -n "$result_text" ]; then
|
|
86
|
-
printf '\n%s\n' "$result_text"
|
|
87
|
-
fi
|
|
88
|
-
;;
|
|
89
|
-
*)
|
|
90
|
-
echo "$line" >> "$log_file"
|
|
91
|
-
;;
|
|
92
|
-
esac
|
|
61
|
+
printf '%s\n' "$line"
|
|
62
|
+
echo "$line" >> "$log_file"
|
|
93
63
|
done
|
|
94
64
|
|
|
95
65
|
echo "done" > "$done_file"
|
package/lib/phases/01_plan.sh
CHANGED
|
@@ -62,8 +62,31 @@ IMPORTANT: Your previous attempt produced invalid JSON in plan.json. Please ensu
|
|
|
62
62
|
leads_count="$(json_get "${FORGE_ROOT}/.forge/plan.json" "leads | length")"
|
|
63
63
|
|
|
64
64
|
if [[ -z "$leads_count" || "$leads_count" -lt 1 ]]; then
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
log_warn "plan.json has no leads (found: ${leads_count:-0}). Retrying coordinator..."
|
|
66
|
+
|
|
67
|
+
local retry_prompt="${prompt}
|
|
68
|
+
|
|
69
|
+
CRITICAL ERROR: Your previous attempt did NOT write a valid plan.json file with a 'leads' array. The file either doesn't exist or has 0 leads.
|
|
70
|
+
|
|
71
|
+
You MUST:
|
|
72
|
+
1. Use the Write tool to create ${FORGE_ROOT}/.forge/plan.json
|
|
73
|
+
2. The JSON must have a top-level 'leads' array with at least 1 lead
|
|
74
|
+
3. Each lead must have a 'workers' array
|
|
75
|
+
4. Do NOT just describe the plan in text — actually write the JSON file"
|
|
76
|
+
|
|
77
|
+
spawn_agent_foreground "coordinator" "$FORGE_ROOT" "$retry_prompt" "$(build_allowed_tools coordinator)"
|
|
78
|
+
|
|
79
|
+
# Validate again
|
|
80
|
+
if [[ ! -f "${FORGE_ROOT}/.forge/plan.json" ]]; then
|
|
81
|
+
log_error "Coordinator did not produce plan.json on retry"
|
|
82
|
+
return 1
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
leads_count="$(json_get "${FORGE_ROOT}/.forge/plan.json" "leads | length")"
|
|
86
|
+
if [[ -z "$leads_count" || "$leads_count" -lt 1 ]]; then
|
|
87
|
+
log_error "plan.json still has no leads after retry (found: ${leads_count:-0})"
|
|
88
|
+
return 1
|
|
89
|
+
fi
|
|
67
90
|
fi
|
|
68
91
|
|
|
69
92
|
# ── Log plan summary ─────────────────────────────────────────────────
|
package/lib/prompts.sh
CHANGED
|
@@ -314,7 +314,9 @@ generate_coordinator_prompt() {
|
|
|
314
314
|
|
|
315
315
|
# Instruction
|
|
316
316
|
prompt+="## INSTRUCTION"$'\n\n'
|
|
317
|
-
prompt+="
|
|
317
|
+
prompt+="You MUST write the plan as valid JSON to this exact path: ${FORGE_ROOT}/.forge/plan.json"$'\n\n'
|
|
318
|
+
prompt+="Use the Write tool to create the file. The JSON MUST have a top-level \"leads\" array with at least 1 entry."$'\n'
|
|
319
|
+
prompt+="Do NOT just describe the plan in text. You MUST create the actual JSON file using the Write tool."$'\n'
|
|
318
320
|
|
|
319
321
|
prompt+="$ANTI_ATTRIBUTION_RULES"
|
|
320
322
|
|