@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 CHANGED
@@ -1 +1 @@
1
- 1.4.0
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
 
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
@@ -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
- log_info "Waiting for task $AFTER to complete before spawning..."
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyperx/clawforge",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Multi-mode coding workflow CLI for orchestrating AI coding agents",
5
5
  "bin": {
6
6
  "@cyperx/clawforge": "./bin/clawforge"