@cyperx/clawforge 1.4.1 → 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.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
 
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))
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 ;;
@@ -177,6 +179,7 @@ if $DRY_RUN; then
177
179
  echo " Auto-merge: $AUTO_MERGE"
178
180
  echo " Quick: $QUICK"
179
181
  [[ -n "$ROUTING" ]] && echo " Routing: $ROUTING"
182
+ [[ -n "$AFTER" ]] && echo " After: $AFTER"
180
183
  echo ""
181
184
  echo "Would execute:"
182
185
  echo " 1. Scope task"
@@ -223,6 +226,7 @@ fi
223
226
  SPAWN_ARGS=(--repo "$REPO_ABS" --branch "$BRANCH" --task "$PROMPT")
224
227
  [[ -n "${AGENT:-}" ]] && SPAWN_ARGS+=(--agent "$AGENT")
225
228
  [[ -n "${SPAWN_MODEL:-}" ]] && SPAWN_ARGS+=(--model "$SPAWN_MODEL")
229
+ [[ -n "${AFTER:-}" ]] && SPAWN_ARGS+=(--after "$AFTER")
226
230
 
227
231
  TASK_JSON=$("${SCRIPT_DIR}/spawn-agent.sh" "${SPAWN_ARGS[@]}" 2>/dev/null || true)
228
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; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyperx/clawforge",
3
- "version": "1.4.1",
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"