@cyperx/clawforge 1.4.0 → 1.5.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/VERSION +1 -1
- package/bin/clawforge +2 -0
- package/bin/clawforge-dashboard +0 -0
- package/bin/deps.sh +70 -0
- package/bin/spawn-agent.sh +19 -10
- package/bin/sprint.sh +14 -2
- package/bin/swarm.sh +42 -2
- package/package.json +1 -1
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.
|
|
1
|
+
1.5.0
|
package/bin/clawforge
CHANGED
|
@@ -83,6 +83,7 @@ Power Features (v1.2):
|
|
|
83
83
|
|
|
84
84
|
Web Dashboard (v1.4):
|
|
85
85
|
web Launch web dashboard (accessible from phone/browser)
|
|
86
|
+
deps Show task dependency graph / blocked tasks
|
|
86
87
|
|
|
87
88
|
Developer Experience (v1.3):
|
|
88
89
|
profile Manage reusable agent profiles (presets)
|
|
@@ -250,6 +251,7 @@ doctor) exec "${BIN_DIR}/doctor.sh" "$@" ;;
|
|
|
250
251
|
export) exec "${BIN_DIR}/export.sh" "$@" ;;
|
|
251
252
|
completions) exec "${BIN_DIR}/completions.sh" "$@" ;;
|
|
252
253
|
web) exec "${BIN_DIR}/web.sh" "$@" ;;
|
|
254
|
+
deps) exec "${BIN_DIR}/deps.sh" "$@" ;;
|
|
253
255
|
logs) exec "${BIN_DIR}/logs.sh" "$@" ;;
|
|
254
256
|
on-complete) exec "${BIN_DIR}/on-complete.sh" "$@" ;;
|
|
255
257
|
|
package/bin/clawforge-dashboard
CHANGED
|
Binary file
|
package/bin/deps.sh
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# deps.sh — Show task dependency graph and blocked tasks
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
5
|
+
source "${SCRIPT_DIR}/../lib/common.sh"
|
|
6
|
+
|
|
7
|
+
usage(){ cat <<EOF
|
|
8
|
+
Usage: clawforge deps [options]
|
|
9
|
+
|
|
10
|
+
Show dependency graph for active tasks.
|
|
11
|
+
|
|
12
|
+
Options:
|
|
13
|
+
--json Output JSON graph
|
|
14
|
+
--blocked Show only blocked tasks
|
|
15
|
+
--help Show help
|
|
16
|
+
EOF
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
JSON_OUTPUT=false
|
|
20
|
+
BLOCKED_ONLY=false
|
|
21
|
+
while [[ $# -gt 0 ]]; do
|
|
22
|
+
case "$1" in
|
|
23
|
+
--json) JSON_OUTPUT=true; shift ;;
|
|
24
|
+
--blocked) BLOCKED_ONLY=true; shift ;;
|
|
25
|
+
--help|-h) usage; exit 0 ;;
|
|
26
|
+
*) log_error "Unknown option: $1"; usage; exit 1 ;;
|
|
27
|
+
esac
|
|
28
|
+
done
|
|
29
|
+
|
|
30
|
+
_ensure_registry
|
|
31
|
+
tasks=$(jq '.tasks' "$REGISTRY_FILE" 2>/dev/null || echo '[]')
|
|
32
|
+
|
|
33
|
+
if $JSON_OUTPUT; then
|
|
34
|
+
jq -n --argjson tasks "$tasks" '
|
|
35
|
+
{
|
|
36
|
+
nodes: ($tasks | map({id:.id, short_id:.short_id, description:.description, status:.status})),
|
|
37
|
+
edges: ($tasks | map(select(.depends_on != null) | {from:.depends_on, to:.id}))
|
|
38
|
+
}'
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
echo "Dependency Graph"
|
|
43
|
+
echo ""
|
|
44
|
+
count=$(echo "$tasks" | jq 'length')
|
|
45
|
+
if [[ "$count" == "0" ]]; then
|
|
46
|
+
echo "(no active tasks)"
|
|
47
|
+
exit 0
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo "$tasks" | jq -r '.[] | [.id, (.short_id//0|tostring), (.description//"—"), (.status//"—"), (.depends_on//"")] | @tsv' | while IFS=$' ' read -r id sid desc status dep; do
|
|
51
|
+
if $BLOCKED_ONLY; then
|
|
52
|
+
[[ -z "$dep" ]] && continue
|
|
53
|
+
dep_status=$(echo "$tasks" | jq -r --arg d "$dep" '.[] | select(.id==$d) | .status' 2>/dev/null || true)
|
|
54
|
+
[[ "$dep_status" == "done" ]] && continue
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
if [[ -n "$dep" ]]; then
|
|
58
|
+
dep_sid=$(echo "$tasks" | jq -r --arg d "$dep" '.[] | select(.id==$d) | (.short_id//0|tostring)' 2>/dev/null || echo "?")
|
|
59
|
+
dep_status=$(echo "$tasks" | jq -r --arg d "$dep" '.[] | select(.id==$d) | .status' 2>/dev/null || echo "?")
|
|
60
|
+
blocked=""
|
|
61
|
+
[[ "$dep_status" != "done" ]] && blocked=" [blocked]"
|
|
62
|
+
echo " #$sid ($status)$blocked"
|
|
63
|
+
echo " └─ waits for #$dep_sid ($dep_status)"
|
|
64
|
+
echo " $desc"
|
|
65
|
+
else
|
|
66
|
+
echo " #$sid ($status)"
|
|
67
|
+
echo " $desc"
|
|
68
|
+
fi
|
|
69
|
+
echo ""
|
|
70
|
+
done
|
package/bin/spawn-agent.sh
CHANGED
|
@@ -24,7 +24,7 @@ EOF
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
# ── Parse args ─────────────────────────────────────────────────────────
|
|
27
|
-
REPO="" BRANCH="" TASK="" AGENT="" MODEL="" EFFORT="" DRY_RUN=false AFTER=""
|
|
27
|
+
REPO="" BRANCH="" TASK="" AGENT="" MODEL="" EFFORT="" DRY_RUN=false AFTER="" DEP_ID=""
|
|
28
28
|
|
|
29
29
|
while [[ $# -gt 0 ]]; do
|
|
30
30
|
case "$1" in
|
|
@@ -49,26 +49,27 @@ done
|
|
|
49
49
|
|
|
50
50
|
# ── Wait for dependency ──────────────────────────────────────────────
|
|
51
51
|
if [[ -n "$AFTER" ]]; then
|
|
52
|
-
|
|
52
|
+
DEP_ID=$(resolve_task_id "$AFTER")
|
|
53
|
+
[[ -z "$DEP_ID" ]] && { log_error "Dependency '$AFTER' not found"; exit 1; }
|
|
54
|
+
log_info "Waiting for task $AFTER ($DEP_ID) to complete before spawning..."
|
|
53
55
|
WAIT_TIMEOUT=${CLAWFORGE_DEP_TIMEOUT:-3600} # 1 hour default
|
|
54
56
|
ELAPSED=0
|
|
55
57
|
INTERVAL=5
|
|
56
58
|
while [[ $ELAPSED -lt $WAIT_TIMEOUT ]]; do
|
|
57
|
-
DEP_STATUS
|
|
58
|
-
if [[ "$AFTER" =~ ^[0-9]+$ ]]; then
|
|
59
|
-
DEP_STATUS=$(jq -r --argjson sid "$AFTER" '.tasks[] | select(.short_id == $sid) | .status' "$REGISTRY_FILE" 2>/dev/null || true)
|
|
60
|
-
else
|
|
61
|
-
DEP_STATUS=$(jq -r --arg id "$AFTER" '.tasks[] | select(.id == $id) | .status' "$REGISTRY_FILE" 2>/dev/null || true)
|
|
62
|
-
fi
|
|
59
|
+
DEP_STATUS=$(jq -r --arg id "$DEP_ID" '.tasks[] | select(.id == $id) | .status' "$REGISTRY_FILE" 2>/dev/null || true)
|
|
63
60
|
case "$DEP_STATUS" in
|
|
64
61
|
done)
|
|
65
62
|
log_info "Dependency $AFTER completed. Spawning..."
|
|
66
63
|
break
|
|
67
64
|
;;
|
|
68
|
-
failed|timeout|cancelled)
|
|
65
|
+
failed|timeout|cancelled|stopped)
|
|
69
66
|
log_error "Dependency $AFTER ended with status: $DEP_STATUS. Aborting spawn."
|
|
70
67
|
exit 1
|
|
71
68
|
;;
|
|
69
|
+
"")
|
|
70
|
+
log_error "Dependency $AFTER not found in registry."
|
|
71
|
+
exit 1
|
|
72
|
+
;;
|
|
72
73
|
*)
|
|
73
74
|
sleep $INTERVAL
|
|
74
75
|
ELAPSED=$((ELAPSED + INTERVAL))
|
|
@@ -82,7 +83,15 @@ if [[ -n "$AFTER" ]]; then
|
|
|
82
83
|
fi
|
|
83
84
|
|
|
84
85
|
# ── Resolve settings ──────────────────────────────────────────────────
|
|
85
|
-
RESOLVED_AGENT=$(detect_agent "${AGENT:-}")
|
|
86
|
+
if ! RESOLVED_AGENT=$(detect_agent "${AGENT:-}" 2>/dev/null); then
|
|
87
|
+
if $DRY_RUN; then
|
|
88
|
+
RESOLVED_AGENT="${AGENT:-claude}"
|
|
89
|
+
log_warn "No local agent binary found; using '$RESOLVED_AGENT' for dry-run preview"
|
|
90
|
+
else
|
|
91
|
+
log_error "No coding agent found (need claude or codex)"
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
fi
|
|
86
95
|
EFFORT="${EFFORT:-$(config_get default_effort high)}"
|
|
87
96
|
|
|
88
97
|
if [[ -z "$MODEL" ]]; then
|
package/bin/sprint.sh
CHANGED
|
@@ -21,6 +21,7 @@ Arguments:
|
|
|
21
21
|
Flags:
|
|
22
22
|
--quick Patch mode: auto-branch, auto-merge, skip review, targeted tests
|
|
23
23
|
--branch <name> Override auto-generated branch name
|
|
24
|
+
--after <id> Wait for task <id> to complete before starting
|
|
24
25
|
--agent <name> Agent to use: claude or codex (default: auto-detect)
|
|
25
26
|
--model <model> Model override
|
|
26
27
|
--routing <strategy> Model routing: auto, cheap, or quality (--model overrides)
|
|
@@ -47,7 +48,7 @@ EOF
|
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
# ── Parse args ────────────────────────────────────────────────────────
|
|
50
|
-
REPO="" TASK="" BRANCH="" AGENT="" MODEL="" QUICK=false AUTO_MERGE=false DRY_RUN=false
|
|
51
|
+
REPO="" TASK="" BRANCH="" AGENT="" MODEL="" QUICK=false AUTO_MERGE=false DRY_RUN=false AFTER=""
|
|
51
52
|
TEMPLATE="" CI_LOOP=false MAX_CI_RETRIES=3 BUDGET="" JSON_OUTPUT=false NOTIFY=false WEBHOOK="" ROUTING=""
|
|
52
53
|
AUTO_CLEAN=false
|
|
53
54
|
TIMEOUT_MIN=""
|
|
@@ -57,6 +58,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
57
58
|
case "$1" in
|
|
58
59
|
--quick) QUICK=true; shift ;;
|
|
59
60
|
--branch) BRANCH="$2"; shift 2 ;;
|
|
61
|
+
--after) AFTER="$2"; shift 2 ;;
|
|
60
62
|
--agent) AGENT="$2"; shift 2 ;;
|
|
61
63
|
--model) MODEL="$2"; shift 2 ;;
|
|
62
64
|
--routing) ROUTING="$2"; shift 2 ;;
|
|
@@ -127,7 +129,15 @@ if $QUICK; then
|
|
|
127
129
|
fi
|
|
128
130
|
|
|
129
131
|
# ── Resolve agent + model ────────────────────────────────────────────
|
|
130
|
-
RESOLVED_AGENT=$(detect_agent "${AGENT:-}")
|
|
132
|
+
if ! RESOLVED_AGENT=$(detect_agent "${AGENT:-}" 2>/dev/null); then
|
|
133
|
+
if $DRY_RUN; then
|
|
134
|
+
RESOLVED_AGENT="${AGENT:-claude}"
|
|
135
|
+
log_warn "No local agent binary found; using '$RESOLVED_AGENT' for dry-run preview"
|
|
136
|
+
else
|
|
137
|
+
log_error "No coding agent found (need claude or codex)"
|
|
138
|
+
exit 1
|
|
139
|
+
fi
|
|
140
|
+
fi
|
|
131
141
|
MODEL_OVERRIDE="$MODEL" # preserve explicit --model
|
|
132
142
|
if [[ -z "$MODEL" ]]; then
|
|
133
143
|
if [[ "$RESOLVED_AGENT" == "claude" ]]; then
|
|
@@ -169,6 +179,7 @@ if $DRY_RUN; then
|
|
|
169
179
|
echo " Auto-merge: $AUTO_MERGE"
|
|
170
180
|
echo " Quick: $QUICK"
|
|
171
181
|
[[ -n "$ROUTING" ]] && echo " Routing: $ROUTING"
|
|
182
|
+
[[ -n "$AFTER" ]] && echo " After: $AFTER"
|
|
172
183
|
echo ""
|
|
173
184
|
echo "Would execute:"
|
|
174
185
|
echo " 1. Scope task"
|
|
@@ -215,6 +226,7 @@ fi
|
|
|
215
226
|
SPAWN_ARGS=(--repo "$REPO_ABS" --branch "$BRANCH" --task "$PROMPT")
|
|
216
227
|
[[ -n "${AGENT:-}" ]] && SPAWN_ARGS+=(--agent "$AGENT")
|
|
217
228
|
[[ -n "${SPAWN_MODEL:-}" ]] && SPAWN_ARGS+=(--model "$SPAWN_MODEL")
|
|
229
|
+
[[ -n "${AFTER:-}" ]] && SPAWN_ARGS+=(--after "$AFTER")
|
|
218
230
|
|
|
219
231
|
TASK_JSON=$("${SCRIPT_DIR}/spawn-agent.sh" "${SPAWN_ARGS[@]}" 2>/dev/null || true)
|
|
220
232
|
|
package/bin/swarm.sh
CHANGED
|
@@ -22,6 +22,7 @@ Flags:
|
|
|
22
22
|
--repos <paths> Comma-separated repo paths (one agent per repo, skips decomposition)
|
|
23
23
|
--repos-file <path> File with repo paths, one per line
|
|
24
24
|
--routing <strategy> Model routing: auto, cheap, or quality
|
|
25
|
+
--after <id> Wait for task <id> to complete before starting swarm
|
|
25
26
|
--max-agents <N> Cap parallel agents (default: 3)
|
|
26
27
|
--agent <name> Force specific agent for all sub-tasks
|
|
27
28
|
--auto-merge Merge each PR automatically after CI + review
|
|
@@ -48,7 +49,7 @@ EOF
|
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
# ── Parse args ────────────────────────────────────────────────────────
|
|
51
|
-
REPO="" TASK="" MAX_AGENTS=3 AGENT="" AUTO_MERGE=false DRY_RUN=false SKIP_CONFIRM=false
|
|
52
|
+
REPO="" TASK="" MAX_AGENTS=3 AGENT="" AUTO_MERGE=false DRY_RUN=false SKIP_CONFIRM=false AFTER=""
|
|
52
53
|
TEMPLATE="" CI_LOOP=false MAX_CI_RETRIES=3 BUDGET="" JSON_OUTPUT=false NOTIFY=false WEBHOOK=""
|
|
53
54
|
REPOS="" REPOS_FILE="" ROUTING="" MULTI_REPO=false AUTO_CLEAN=false TIMEOUT_MIN=""
|
|
54
55
|
POSITIONAL=()
|
|
@@ -58,6 +59,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
58
59
|
--repos) REPOS="$2"; shift 2 ;;
|
|
59
60
|
--repos-file) REPOS_FILE="$2"; shift 2 ;;
|
|
60
61
|
--routing) ROUTING="$2"; shift 2 ;;
|
|
62
|
+
--after) AFTER="$2"; shift 2 ;;
|
|
61
63
|
--max-agents) MAX_AGENTS="$2"; shift 2 ;;
|
|
62
64
|
--agent) AGENT="$2"; shift 2 ;;
|
|
63
65
|
--auto-merge) AUTO_MERGE=true; shift ;;
|
|
@@ -137,6 +139,36 @@ if $MULTI_REPO; then
|
|
|
137
139
|
REPO="${REPO_LIST[0]}"
|
|
138
140
|
fi
|
|
139
141
|
|
|
142
|
+
|
|
143
|
+
# ── Dependency wait (optional) ──────────────────────────────────────
|
|
144
|
+
if [[ -n "$AFTER" ]]; then
|
|
145
|
+
DEP_ID=$(resolve_task_id "$AFTER")
|
|
146
|
+
[[ -z "$DEP_ID" ]] && { log_error "Dependency '$AFTER' not found"; exit 1; }
|
|
147
|
+
log_info "Waiting for task $AFTER ($DEP_ID) to complete before swarm starts..."
|
|
148
|
+
WAIT_TIMEOUT=${CLAWFORGE_DEP_TIMEOUT:-3600}
|
|
149
|
+
ELAPSED=0
|
|
150
|
+
INTERVAL=5
|
|
151
|
+
while [[ $ELAPSED -lt $WAIT_TIMEOUT ]]; do
|
|
152
|
+
DEP_STATUS=$(jq -r --arg id "$DEP_ID" '.tasks[] | select(.id == $id) | .status' "$REGISTRY_FILE" 2>/dev/null || true)
|
|
153
|
+
case "$DEP_STATUS" in
|
|
154
|
+
done) break ;;
|
|
155
|
+
failed|timeout|cancelled|stopped)
|
|
156
|
+
log_error "Dependency $AFTER ended with status: $DEP_STATUS. Aborting swarm."
|
|
157
|
+
exit 1
|
|
158
|
+
;;
|
|
159
|
+
"")
|
|
160
|
+
log_error "Dependency $AFTER not found in registry."
|
|
161
|
+
exit 1
|
|
162
|
+
;;
|
|
163
|
+
*) sleep $INTERVAL; ELAPSED=$((ELAPSED + INTERVAL)) ;;
|
|
164
|
+
esac
|
|
165
|
+
done
|
|
166
|
+
if [[ $ELAPSED -ge $WAIT_TIMEOUT ]]; then
|
|
167
|
+
log_error "Dependency wait timed out after ${WAIT_TIMEOUT}s"
|
|
168
|
+
exit 1
|
|
169
|
+
fi
|
|
170
|
+
fi
|
|
171
|
+
|
|
140
172
|
# ── Resolve repo (single-repo mode) ─────────────────────────────────
|
|
141
173
|
if [[ -z "$REPO" ]]; then
|
|
142
174
|
REPO=$(detect_repo) || { log_error "No --repo and no git repo found from cwd"; exit 1; }
|
|
@@ -147,7 +179,15 @@ REPO_ABS=$(cd "$REPO" && pwd)
|
|
|
147
179
|
disk_check "$REPO_ABS" || { log_error "Aborting due to low disk space"; exit 1; }
|
|
148
180
|
|
|
149
181
|
# ── Resolve agent ─────────────────────────────────────────────────────
|
|
150
|
-
RESOLVED_AGENT=$(detect_agent "${AGENT:-}")
|
|
182
|
+
if ! RESOLVED_AGENT=$(detect_agent "${AGENT:-}" 2>/dev/null); then
|
|
183
|
+
if $DRY_RUN; then
|
|
184
|
+
RESOLVED_AGENT="${AGENT:-claude}"
|
|
185
|
+
log_warn "No local agent binary found; using '$RESOLVED_AGENT' for dry-run preview"
|
|
186
|
+
else
|
|
187
|
+
log_error "No coding agent found (need claude or codex)"
|
|
188
|
+
exit 1
|
|
189
|
+
fi
|
|
190
|
+
fi
|
|
151
191
|
if [[ "$RESOLVED_AGENT" == "claude" ]]; then
|
|
152
192
|
MODEL=$(config_get default_model_claude "claude-sonnet-4-5")
|
|
153
193
|
else
|