@mindfoldhq/trellis 0.1.0 → 0.1.2

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.
Files changed (140) hide show
  1. package/README.md +58 -11
  2. package/dist/.claude/agents/check.md +98 -0
  3. package/dist/.claude/agents/debug.md +109 -0
  4. package/dist/{templates/agents/dispatch.txt → .claude/agents/dispatch.md} +20 -12
  5. package/dist/.claude/agents/implement.md +101 -0
  6. package/dist/.claude/agents/plan.md +396 -0
  7. package/dist/.claude/agents/research.md +120 -0
  8. package/dist/{templates/commands/common/check-cross-layer.txt → .claude/commands/check-cross-layer.md} +29 -29
  9. package/dist/{templates/commands/common/onboard-developer.txt → .claude/commands/onboard-developer.md} +2 -2
  10. package/dist/.claude/commands/parallel.md +199 -0
  11. package/dist/{templates/commands/common/record-agent-flow.txt → .claude/commands/record-agent-flow.md} +1 -1
  12. package/dist/.claude/commands/start.md +192 -0
  13. package/dist/{templates → .claude}/hooks/inject-subagent-context.py +63 -0
  14. package/dist/.cursor/commands/before-backend-dev.md +13 -0
  15. package/dist/.cursor/commands/before-frontend-dev.md +13 -0
  16. package/dist/.cursor/commands/break-loop.md +107 -0
  17. package/dist/.cursor/commands/check-backend.md +13 -0
  18. package/dist/.cursor/commands/check-cross-layer.md +153 -0
  19. package/dist/.cursor/commands/check-frontend.md +13 -0
  20. package/dist/.cursor/commands/create-command.md +154 -0
  21. package/dist/.cursor/commands/finish-work.md +129 -0
  22. package/dist/.cursor/commands/integrate-skill.md +219 -0
  23. package/dist/.cursor/commands/onboard-developer.md +355 -0
  24. package/dist/.cursor/commands/record-agent-flow.md +62 -0
  25. package/dist/.cursor/commands/start.md +157 -0
  26. package/dist/{templates/markdown/agent-traces-index.md.txt → .trellis/agent-traces/index.md} +8 -9
  27. package/dist/{templates/scripts/add-session.sh.txt → .trellis/scripts/add-session.sh} +14 -14
  28. package/dist/{templates/scripts/common/developer.sh.txt → .trellis/scripts/common/developer.sh} +13 -13
  29. package/dist/{templates/scripts/common/git-context.sh.txt → .trellis/scripts/common/git-context.sh} +8 -8
  30. package/dist/{templates/scripts/common/paths.sh.txt → .trellis/scripts/common/paths.sh} +4 -4
  31. package/dist/.trellis/scripts/common/phase.sh +150 -0
  32. package/dist/.trellis/scripts/common/worktree.sh +138 -0
  33. package/dist/{templates/scripts/feature.sh.txt → .trellis/scripts/feature.sh} +297 -0
  34. package/dist/.trellis/scripts/multi-agent/cleanup.sh +416 -0
  35. package/dist/.trellis/scripts/multi-agent/create-pr.sh +241 -0
  36. package/dist/.trellis/scripts/multi-agent/plan.sh +232 -0
  37. package/dist/.trellis/scripts/multi-agent/start.sh +344 -0
  38. package/dist/.trellis/scripts/multi-agent/status.sh +695 -0
  39. package/dist/.trellis/structure/backend/database-guidelines.md +51 -0
  40. package/dist/.trellis/structure/backend/directory-structure.md +209 -0
  41. package/dist/.trellis/structure/backend/error-handling.md +278 -0
  42. package/dist/.trellis/structure/backend/index.md +38 -0
  43. package/dist/.trellis/structure/backend/logging-guidelines.md +266 -0
  44. package/dist/.trellis/structure/backend/quality-guidelines.md +313 -0
  45. package/dist/.trellis/structure/frontend/component-guidelines.md +59 -0
  46. package/dist/.trellis/structure/frontend/directory-structure.md +54 -0
  47. package/dist/.trellis/structure/frontend/hook-guidelines.md +51 -0
  48. package/dist/.trellis/structure/frontend/index.md +39 -0
  49. package/dist/.trellis/structure/frontend/quality-guidelines.md +51 -0
  50. package/dist/.trellis/structure/frontend/state-management.md +51 -0
  51. package/dist/.trellis/structure/frontend/type-safety.md +51 -0
  52. package/dist/.trellis/structure/guides/code-reuse-thinking-guide.md +92 -0
  53. package/dist/.trellis/structure/guides/cross-layer-thinking-guide.md +94 -0
  54. package/dist/.trellis/structure/guides/index.md +79 -0
  55. package/dist/{templates/markdown/workflow.md.txt → .trellis/workflow.md} +6 -6
  56. package/dist/.trellis/worktree.yaml +49 -0
  57. package/dist/cli/index.js +1 -0
  58. package/dist/cli/index.js.map +1 -1
  59. package/dist/commands/init.d.ts.map +1 -1
  60. package/dist/commands/init.js +29 -15
  61. package/dist/commands/init.js.map +1 -1
  62. package/dist/configurators/claude.d.ts +17 -17
  63. package/dist/configurators/claude.d.ts.map +1 -1
  64. package/dist/configurators/claude.js +29 -59
  65. package/dist/configurators/claude.js.map +1 -1
  66. package/dist/configurators/cursor.d.ts +3 -3
  67. package/dist/configurators/cursor.d.ts.map +1 -1
  68. package/dist/configurators/cursor.js +11 -15
  69. package/dist/configurators/cursor.js.map +1 -1
  70. package/dist/configurators/opencode.d.ts +25 -0
  71. package/dist/configurators/opencode.d.ts.map +1 -0
  72. package/dist/configurators/opencode.js +54 -0
  73. package/dist/configurators/opencode.js.map +1 -0
  74. package/dist/configurators/workflow.d.ts +9 -0
  75. package/dist/configurators/workflow.d.ts.map +1 -1
  76. package/dist/configurators/workflow.js +32 -72
  77. package/dist/configurators/workflow.js.map +1 -1
  78. package/dist/templates/extract.d.ts +73 -8
  79. package/dist/templates/extract.d.ts.map +1 -1
  80. package/dist/templates/extract.js +149 -10
  81. package/dist/templates/extract.js.map +1 -1
  82. package/dist/templates/markdown/{agents.md.txt → agents.md} +1 -1
  83. package/dist/templates/markdown/index.d.ts +5 -1
  84. package/dist/templates/markdown/index.d.ts.map +1 -1
  85. package/dist/templates/markdown/index.js +54 -26
  86. package/dist/templates/markdown/index.js.map +1 -1
  87. package/dist/templates/markdown/{init-agent.md.txt → init-agent.md} +8 -8
  88. package/dist/templates/markdown/structure/backend/directory-structure.md.txt +6 -6
  89. package/dist/templates/markdown/structure/backend/error-handling.md.txt +8 -8
  90. package/dist/templates/markdown/structure/backend/index.md.txt +5 -5
  91. package/dist/templates/markdown/structure/backend/logging-guidelines.md.txt +8 -8
  92. package/dist/templates/markdown/structure/frontend/index.md.txt +6 -6
  93. package/dist/templates/markdown/structure/guides/cross-layer-thinking-guide.md.txt +5 -5
  94. package/dist/templates/markdown/structure/guides/index.md.txt +7 -7
  95. package/dist/templates/markdown/worktree.yaml.txt +58 -0
  96. package/dist/types/ai-tools.d.ts +2 -2
  97. package/dist/types/ai-tools.d.ts.map +1 -1
  98. package/dist/types/ai-tools.js +4 -0
  99. package/dist/types/ai-tools.js.map +1 -1
  100. package/package.json +1 -1
  101. package/dist/configurators/templates.d.ts +0 -40
  102. package/dist/configurators/templates.d.ts.map +0 -1
  103. package/dist/configurators/templates.js +0 -67
  104. package/dist/configurators/templates.js.map +0 -1
  105. package/dist/templates/agents/check.txt +0 -120
  106. package/dist/templates/agents/debug.txt +0 -121
  107. package/dist/templates/agents/implement.txt +0 -114
  108. package/dist/templates/agents/index.d.ts +0 -35
  109. package/dist/templates/agents/index.d.ts.map +0 -1
  110. package/dist/templates/agents/index.js +0 -71
  111. package/dist/templates/agents/index.js.map +0 -1
  112. package/dist/templates/agents/research.txt +0 -258
  113. package/dist/templates/commands/claude/start.md.txt +0 -127
  114. package/dist/templates/commands/cursor/start.md.txt +0 -94
  115. package/dist/templates/commands/index.d.ts +0 -46
  116. package/dist/templates/commands/index.d.ts.map +0 -1
  117. package/dist/templates/commands/index.js +0 -151
  118. package/dist/templates/commands/index.js.map +0 -1
  119. package/dist/templates/hooks/index.d.ts +0 -33
  120. package/dist/templates/hooks/index.d.ts.map +0 -1
  121. package/dist/templates/hooks/index.js +0 -53
  122. package/dist/templates/hooks/index.js.map +0 -1
  123. package/dist/templates/markdown/gitignore.txt +0 -3
  124. package/dist/templates/scripts/index.d.ts +0 -25
  125. package/dist/templates/scripts/index.d.ts.map +0 -1
  126. package/dist/templates/scripts/index.js +0 -28
  127. package/dist/templates/scripts/index.js.map +0 -1
  128. /package/dist/{templates/commands/common/before-backend-dev.txt → .claude/commands/before-backend-dev.md} +0 -0
  129. /package/dist/{templates/commands/common/before-frontend-dev.txt → .claude/commands/before-frontend-dev.md} +0 -0
  130. /package/dist/{templates/commands/common/break-loop.txt → .claude/commands/break-loop.md} +0 -0
  131. /package/dist/{templates/commands/common/check-backend.txt → .claude/commands/check-backend.md} +0 -0
  132. /package/dist/{templates/commands/common/check-frontend.txt → .claude/commands/check-frontend.md} +0 -0
  133. /package/dist/{templates/commands/common/create-command.txt → .claude/commands/create-command.md} +0 -0
  134. /package/dist/{templates/commands/common/finish-work.txt → .claude/commands/finish-work.md} +0 -0
  135. /package/dist/{templates/commands/common/integrate-skill.txt → .claude/commands/integrate-skill.md} +0 -0
  136. /package/dist/{templates/hooks → .claude}/settings.json +0 -0
  137. /package/dist/{templates/scripts/create-bootstrap.sh.txt → .trellis/scripts/create-bootstrap.sh} +0 -0
  138. /package/dist/{templates/scripts/get-context.sh.txt → .trellis/scripts/get-context.sh} +0 -0
  139. /package/dist/{templates/scripts/get-developer.sh.txt → .trellis/scripts/get-developer.sh} +0 -0
  140. /package/dist/{templates/scripts/init-developer.sh.txt → .trellis/scripts/init-developer.sh} +0 -0
@@ -0,0 +1,695 @@
1
+ #!/bin/bash
2
+ # =============================================================================
3
+ # Multi-Agent Pipeline: Status Monitor
4
+ # =============================================================================
5
+ # Usage:
6
+ # ./status.sh Show summary of all features (default)
7
+ # ./status.sh --list List all worktrees and agents
8
+ # ./status.sh --detail <feature> Detailed feature status
9
+ # ./status.sh --watch <feature> Watch agent log in real-time
10
+ # ./status.sh --log <feature> Show recent log entries
11
+ # ./status.sh --registry Show agent registry
12
+ # =============================================================================
13
+
14
+ set -e
15
+
16
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17
+ source "$SCRIPT_DIR/../common/paths.sh"
18
+ source "$SCRIPT_DIR/../common/worktree.sh"
19
+ source "$SCRIPT_DIR/../common/developer.sh"
20
+ source "$SCRIPT_DIR/../common/phase.sh"
21
+
22
+ # Colors
23
+ RED='\033[0;31m'
24
+ GREEN='\033[0;32m'
25
+ YELLOW='\033[1;33m'
26
+ BLUE='\033[0;34m'
27
+ CYAN='\033[0;36m'
28
+ DIM='\033[2m'
29
+ NC='\033[0m'
30
+
31
+ PROJECT_ROOT=$(get_repo_root)
32
+
33
+ # =============================================================================
34
+ # Parse Arguments
35
+ # =============================================================================
36
+ ACTION="summary"
37
+ TARGET=""
38
+
39
+ while [[ $# -gt 0 ]]; do
40
+ case $1 in
41
+ --list)
42
+ ACTION="list"
43
+ shift
44
+ ;;
45
+ --detail)
46
+ ACTION="detail"
47
+ TARGET="$2"
48
+ shift 2
49
+ ;;
50
+ --watch)
51
+ ACTION="watch"
52
+ TARGET="$2"
53
+ shift 2
54
+ ;;
55
+ --log)
56
+ ACTION="log"
57
+ TARGET="$2"
58
+ shift 2
59
+ ;;
60
+ --progress)
61
+ ACTION="progress"
62
+ TARGET="$2"
63
+ shift 2
64
+ ;;
65
+ --registry)
66
+ ACTION="registry"
67
+ shift
68
+ ;;
69
+ -h|--help)
70
+ ACTION="help"
71
+ shift
72
+ ;;
73
+ *)
74
+ TARGET="$1"
75
+ shift
76
+ ;;
77
+ esac
78
+ done
79
+
80
+ # =============================================================================
81
+ # Helper Functions
82
+ # =============================================================================
83
+
84
+ # Check if PID is running
85
+ is_running() {
86
+ local pid="$1"
87
+ [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null
88
+ }
89
+
90
+ # Get status color
91
+ status_color() {
92
+ local status="$1"
93
+ case "$status" in
94
+ completed) echo "${GREEN}" ;;
95
+ in_progress) echo "${BLUE}" ;;
96
+ planning) echo "${YELLOW}" ;;
97
+ *) echo "${DIM}" ;;
98
+ esac
99
+ }
100
+
101
+ # Find agent by feature name or ID
102
+ find_agent() {
103
+ local search="$1"
104
+ AGENTS_DIR=$(get_agents_dir)
105
+ REGISTRY_FILE="${AGENTS_DIR}/registry.json"
106
+
107
+ if [ ! -f "$REGISTRY_FILE" ]; then
108
+ return 1
109
+ fi
110
+
111
+ # Try exact ID match first
112
+ local agent=$(jq -r --arg id "$search" '.agents[] | select(.id == $id)' "$REGISTRY_FILE" 2>/dev/null)
113
+
114
+ # Try partial match on feature_dir
115
+ if [ -z "$agent" ] || [ "$agent" = "null" ]; then
116
+ agent=$(jq -r --arg search "$search" '.agents[] | select(.feature_dir | contains($search))' "$REGISTRY_FILE" 2>/dev/null | head -1)
117
+ fi
118
+
119
+ echo "$agent"
120
+ }
121
+
122
+ # Get the last tool call from agent log
123
+ get_last_tool() {
124
+ local log_file="$1"
125
+ if [ ! -f "$log_file" ]; then
126
+ echo ""
127
+ return
128
+ fi
129
+ # Use tail -r on macOS, tac on Linux
130
+ if command -v tac &>/dev/null; then
131
+ tac "$log_file" 2>/dev/null | head -100 | jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use") | .name' 2>/dev/null | head -1
132
+ else
133
+ tail -r "$log_file" 2>/dev/null | head -100 | jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use") | .name' 2>/dev/null | head -1
134
+ fi
135
+ }
136
+
137
+ # Get the last assistant text from agent log
138
+ get_last_message() {
139
+ local log_file="$1"
140
+ local max_len="${2:-100}"
141
+ if [ ! -f "$log_file" ]; then
142
+ echo ""
143
+ return
144
+ fi
145
+ local text
146
+ # Use tail -r on macOS, tac on Linux
147
+ if command -v tac &>/dev/null; then
148
+ text=$(tac "$log_file" 2>/dev/null | head -100 | jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="text") | .text' 2>/dev/null | head -1)
149
+ else
150
+ text=$(tail -r "$log_file" 2>/dev/null | head -100 | jq -r 'select(.type=="assistant") | .message.content[]? | select(.type=="text") | .text' 2>/dev/null | head -1)
151
+ fi
152
+ if [ -n "$text" ] && [ "$text" != "null" ]; then
153
+ echo "${text:0:$max_len}"
154
+ fi
155
+ }
156
+
157
+ # Get recent task notifications from agent log
158
+ # Looks for async_launched tasks and infers completion from current_phase
159
+ get_recent_tasks() {
160
+ local log_file="$1"
161
+ local count="${2:-5}"
162
+ local current_phase="${3:-0}"
163
+ if [ ! -f "$log_file" ]; then
164
+ return
165
+ fi
166
+ # Get async_launched tasks with phase number extracted from description
167
+ tail -500 "$log_file" 2>/dev/null | jq -r --argjson current_phase "$current_phase" '
168
+ select(.type=="user" and .tool_use_result.status == "async_launched" and .tool_use_result.description != null) |
169
+ .tool_use_result.description as $desc |
170
+ # Extract phase number from "Phase N:" pattern
171
+ ($desc | capture("Phase (?<num>[0-9]+)") | .num | tonumber) as $phase_num |
172
+ # If current_phase > this phase, it is completed
173
+ (if $phase_num < $current_phase then "completed" else "async_launched" end) as $status |
174
+ "\($status)|\($desc)"
175
+ ' 2>/dev/null | tail -"$count"
176
+ }
177
+
178
+ # =============================================================================
179
+ # Commands
180
+ # =============================================================================
181
+
182
+ cmd_help() {
183
+ cat << EOF
184
+ Multi-Agent Pipeline: Status Monitor
185
+
186
+ Usage:
187
+ $0 Show summary of all features
188
+ $0 --list List all worktrees and agents
189
+ $0 --detail <feature> Detailed feature status
190
+ $0 --progress <feature> Quick progress view with recent activity
191
+ $0 --watch <feature> Watch agent log in real-time
192
+ $0 --log <feature> Show recent log entries
193
+ $0 --registry Show agent registry
194
+
195
+ Examples:
196
+ $0 --detail my-feature
197
+ $0 --progress my-feature
198
+ $0 --watch 16-worktree-support
199
+ $0 --log worktree-support
200
+ EOF
201
+ }
202
+
203
+ cmd_list() {
204
+ echo -e "${BLUE}=== Git Worktrees ===${NC}"
205
+ echo ""
206
+ cd "$PROJECT_ROOT"
207
+ git worktree list
208
+ echo ""
209
+
210
+ echo -e "${BLUE}=== Registered Agents ===${NC}"
211
+ echo ""
212
+
213
+ AGENTS_DIR=$(get_agents_dir)
214
+ REGISTRY_FILE="${AGENTS_DIR}/registry.json"
215
+
216
+ if [ ! -f "$REGISTRY_FILE" ]; then
217
+ echo " (no registry found)"
218
+ return
219
+ fi
220
+
221
+ local agents=$(jq -r '.agents[]' "$REGISTRY_FILE" 2>/dev/null)
222
+ if [ -z "$agents" ]; then
223
+ echo " (no agents registered)"
224
+ return
225
+ fi
226
+
227
+ jq -r '.agents[] | "\(.id)|\(.pid)|\(.worktree_path)|\(.started_at)"' "$REGISTRY_FILE" 2>/dev/null | while IFS='|' read -r id pid wt started; do
228
+ local status_icon
229
+ if is_running "$pid"; then
230
+ status_icon="${GREEN}●${NC}"
231
+ else
232
+ status_icon="${RED}○${NC}"
233
+ fi
234
+ echo -e " $status_icon $id (PID: $pid)"
235
+ echo -e " ${DIM}Worktree: $wt${NC}"
236
+ echo -e " ${DIM}Started: $started${NC}"
237
+ echo ""
238
+ done
239
+ }
240
+
241
+ # Calculate elapsed time from ISO timestamp
242
+ calc_elapsed() {
243
+ local started="$1"
244
+ if [ -z "$started" ] || [ "$started" = "null" ]; then
245
+ echo "N/A"
246
+ return
247
+ fi
248
+
249
+ # Parse started time (handle both formats: with and without timezone)
250
+ local start_epoch
251
+ if command -v gdate &>/dev/null; then
252
+ start_epoch=$(gdate -d "$started" +%s 2>/dev/null)
253
+ else
254
+ # Try to parse ISO format
255
+ start_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%S" "${started%%+*}" +%s 2>/dev/null || date -d "$started" +%s 2>/dev/null)
256
+ fi
257
+
258
+ if [ -z "$start_epoch" ]; then
259
+ echo "N/A"
260
+ return
261
+ fi
262
+
263
+ local now_epoch=$(date +%s)
264
+ local elapsed=$((now_epoch - start_epoch))
265
+
266
+ if [ $elapsed -lt 60 ]; then
267
+ echo "${elapsed}s"
268
+ elif [ $elapsed -lt 3600 ]; then
269
+ echo "$((elapsed / 60))m $((elapsed % 60))s"
270
+ else
271
+ echo "$((elapsed / 3600))h $((elapsed % 3600 / 60))m"
272
+ fi
273
+ }
274
+
275
+ # Note: get_phase_info is now in common/phase.sh
276
+
277
+ # Count modified files in worktree
278
+ count_modified_files() {
279
+ local worktree="$1"
280
+ if [ -d "$worktree" ]; then
281
+ cd "$worktree" && git status --short 2>/dev/null | wc -l | tr -d ' '
282
+ else
283
+ echo "0"
284
+ fi
285
+ }
286
+
287
+ cmd_summary() {
288
+ ensure_developer
289
+
290
+ local features_dir=$(get_features_dir)
291
+ if [ ! -d "$features_dir" ]; then
292
+ echo "No features directory found"
293
+ exit 0
294
+ fi
295
+
296
+ AGENTS_DIR=$(get_agents_dir)
297
+ REGISTRY_FILE="${AGENTS_DIR}/registry.json"
298
+
299
+ # Count running agents
300
+ local running_count=0
301
+ local total_agents=0
302
+ if [ -f "$REGISTRY_FILE" ]; then
303
+ total_agents=$(jq -r '.agents | length' "$REGISTRY_FILE" 2>/dev/null || echo "0")
304
+ while read -r pid; do
305
+ is_running "$pid" && ((running_count++))
306
+ done < <(jq -r '.agents[].pid' "$REGISTRY_FILE" 2>/dev/null)
307
+ fi
308
+
309
+ echo -e "${BLUE}=== Multi-Agent Status ===${NC}"
310
+ echo -e " Agents: ${GREEN}${running_count}${NC} running / ${total_agents} registered"
311
+ echo ""
312
+
313
+ # Check if any agents are running and show detailed view
314
+ local has_running_agent=false
315
+
316
+ for d in "$features_dir"/*/; do
317
+ [ ! -d "$d" ] && continue
318
+ [[ "$(basename "$d")" == "archive" ]] && continue
319
+
320
+ local name=$(basename "$d")
321
+ local feature_json="$d/feature.json"
322
+ local status="unknown"
323
+
324
+ if [ -f "$feature_json" ]; then
325
+ status=$(jq -r '.status // "unknown"' "$feature_json")
326
+ fi
327
+
328
+ # Check agent status
329
+ local agent_info=""
330
+ local pid=""
331
+ local worktree=""
332
+ local started=""
333
+ local is_agent_running=false
334
+
335
+ if [ -f "$REGISTRY_FILE" ]; then
336
+ agent_info=$(jq -r --arg name "$name" '.agents[] | select(.feature_dir | contains($name))' "$REGISTRY_FILE" 2>/dev/null)
337
+ if [ -n "$agent_info" ] && [ "$agent_info" != "null" ]; then
338
+ pid=$(echo "$agent_info" | jq -r '.pid')
339
+ worktree=$(echo "$agent_info" | jq -r '.worktree_path')
340
+ started=$(echo "$agent_info" | jq -r '.started_at')
341
+ if is_running "$pid"; then
342
+ is_agent_running=true
343
+ has_running_agent=true
344
+ fi
345
+ fi
346
+ fi
347
+
348
+ local color=$(status_color "$status")
349
+
350
+ if [ "$is_agent_running" = true ]; then
351
+ # Detailed view for running agents
352
+ # Read feature.json from worktree (has live phase info)
353
+ local feature_dir_rel=$(echo "$agent_info" | jq -r '.feature_dir')
354
+ local worktree_feature_json="$worktree/$feature_dir_rel/feature.json"
355
+ local phase_source="$feature_json"
356
+ [ -f "$worktree_feature_json" ] && phase_source="$worktree_feature_json"
357
+
358
+ local phase_info=$(get_phase_info "$phase_source")
359
+ local elapsed=$(calc_elapsed "$started")
360
+ local modified=$(count_modified_files "$worktree")
361
+ local branch=$(jq -r '.branch // "N/A"' "$phase_source" 2>/dev/null)
362
+
363
+ # Get recent activity from log
364
+ local log_file="$worktree/.agent-log"
365
+ local last_tool=$(get_last_tool "$log_file")
366
+
367
+ echo -e "${GREEN}▶${NC} ${CYAN}${name}${NC} ${GREEN}[running]${NC}"
368
+ echo -e " Phase: ${phase_info}"
369
+ echo -e " Elapsed: ${elapsed}"
370
+ echo -e " Branch: ${DIM}${branch}${NC}"
371
+ echo -e " Modified: ${modified} file(s)"
372
+ if [ -n "$last_tool" ]; then
373
+ echo -e " Activity: ${YELLOW}${last_tool}${NC}"
374
+ fi
375
+ echo -e " PID: ${DIM}${pid}${NC}"
376
+ echo ""
377
+ elif [ -n "$agent_info" ] && [ "$agent_info" != "null" ]; then
378
+ # Stopped agent
379
+ echo -e "${RED}○${NC} ${name} ${RED}[stopped]${NC}"
380
+ echo -e " ${DIM}PID ${pid} is no longer running${NC}"
381
+ echo ""
382
+ else
383
+ # No agent, just show status
384
+ echo -e " ${color}●${NC} ${name} (${status})"
385
+ fi
386
+ done
387
+
388
+ if [ "$has_running_agent" = true ]; then
389
+ echo -e "${DIM}─────────────────────────────────────${NC}"
390
+ echo -e "${DIM}Use --progress <name> for quick activity view${NC}"
391
+ echo -e "${DIM}Use --detail <name> for more info${NC}"
392
+ fi
393
+ echo ""
394
+ }
395
+
396
+ cmd_progress() {
397
+ if [ -z "$TARGET" ]; then
398
+ echo "Usage: $0 --progress <feature>"
399
+ exit 1
400
+ fi
401
+
402
+ local agent=$(find_agent "$TARGET")
403
+ if [ -z "$agent" ] || [ "$agent" = "null" ]; then
404
+ echo "Agent not found: $TARGET"
405
+ exit 1
406
+ fi
407
+
408
+ local id=$(echo "$agent" | jq -r '.id')
409
+ local pid=$(echo "$agent" | jq -r '.pid')
410
+ local worktree=$(echo "$agent" | jq -r '.worktree_path')
411
+ local feature_dir=$(echo "$agent" | jq -r '.feature_dir')
412
+ local started=$(echo "$agent" | jq -r '.started_at')
413
+ local log_file="$worktree/.agent-log"
414
+
415
+ if [ ! -f "$log_file" ]; then
416
+ echo "Log file not found: $log_file"
417
+ exit 1
418
+ fi
419
+
420
+ # Get phase info from worktree's feature.json
421
+ local worktree_feature_json="$worktree/$feature_dir/feature.json"
422
+ local phase_info="N/A"
423
+ local current_phase=0
424
+ if [ -f "$worktree_feature_json" ]; then
425
+ phase_info=$(get_phase_info "$worktree_feature_json")
426
+ current_phase=$(jq -r '.current_phase // 0' "$worktree_feature_json")
427
+ fi
428
+
429
+ local elapsed=$(calc_elapsed "$started")
430
+ local modified=$(count_modified_files "$worktree")
431
+
432
+ # Check if running
433
+ local status_str
434
+ if is_running "$pid"; then
435
+ status_str="${GREEN}running${NC}"
436
+ else
437
+ status_str="${RED}stopped${NC}"
438
+ fi
439
+
440
+ echo ""
441
+ echo -e "${BLUE}=== Progress: ${id} ===${NC}"
442
+ echo ""
443
+
444
+ # Basic info (like summary)
445
+ echo -e "${CYAN}Status:${NC}"
446
+ echo -e " State: ${status_str}"
447
+ echo -e " Phase: ${phase_info}"
448
+ echo -e " Elapsed: ${elapsed}"
449
+ echo -e " Modified: ${modified} file(s)"
450
+ echo ""
451
+
452
+ # Recent task notifications
453
+ echo -e "${CYAN}Recent Tasks:${NC}"
454
+ local has_tasks=false
455
+ while IFS='|' read -r status summary; do
456
+ [ -z "$status" ] && continue
457
+ has_tasks=true
458
+ local icon
459
+ case "$status" in
460
+ completed) icon="${GREEN}✓${NC}" ;;
461
+ failed) icon="${RED}✗${NC}" ;;
462
+ async_launched) icon="${BLUE}▶${NC}" ;;
463
+ *) icon="${YELLOW}○${NC}" ;;
464
+ esac
465
+ echo -e " ${icon} ${summary}"
466
+ done < <(get_recent_tasks "$log_file" 5 "$current_phase")
467
+
468
+ if [ "$has_tasks" = false ]; then
469
+ echo -e " ${DIM}(no task notifications yet)${NC}"
470
+ fi
471
+ echo ""
472
+
473
+ # Current activity
474
+ echo -e "${CYAN}Current Activity:${NC}"
475
+ local last_tool=$(get_last_tool "$log_file")
476
+ if [ -n "$last_tool" ]; then
477
+ echo -e " Tool: ${YELLOW}${last_tool}${NC}"
478
+ else
479
+ echo -e " ${DIM}(no recent tool calls)${NC}"
480
+ fi
481
+ echo ""
482
+
483
+ # Last message
484
+ echo -e "${CYAN}Last Message:${NC}"
485
+ local last_msg=$(get_last_message "$log_file" 200)
486
+ if [ -n "$last_msg" ]; then
487
+ echo -e " \"${last_msg}...\""
488
+ else
489
+ echo -e " ${DIM}(no recent messages)${NC}"
490
+ fi
491
+ echo ""
492
+ }
493
+
494
+ cmd_detail() {
495
+ if [ -z "$TARGET" ]; then
496
+ echo "Usage: $0 --detail <feature>"
497
+ exit 1
498
+ fi
499
+
500
+ local agent=$(find_agent "$TARGET")
501
+ if [ -z "$agent" ] || [ "$agent" = "null" ]; then
502
+ echo "Agent not found: $TARGET"
503
+ exit 1
504
+ fi
505
+
506
+ local id=$(echo "$agent" | jq -r '.id')
507
+ local pid=$(echo "$agent" | jq -r '.pid')
508
+ local worktree=$(echo "$agent" | jq -r '.worktree_path')
509
+ local feature_dir=$(echo "$agent" | jq -r '.feature_dir')
510
+ local started=$(echo "$agent" | jq -r '.started_at')
511
+
512
+ echo -e "${BLUE}=== Agent Detail: $id ===${NC}"
513
+ echo ""
514
+ echo " ID: $id"
515
+ echo " PID: $pid"
516
+ echo " Worktree: $worktree"
517
+ echo " Feature Dir: $feature_dir"
518
+ echo " Started: $started"
519
+ echo ""
520
+
521
+ # Status
522
+ if is_running "$pid"; then
523
+ echo -e " Status: ${GREEN}Running${NC}"
524
+ else
525
+ echo -e " Status: ${RED}Stopped${NC}"
526
+ fi
527
+
528
+ # Feature info
529
+ local feature_json="$PROJECT_ROOT/$feature_dir/feature.json"
530
+ if [ -f "$feature_json" ]; then
531
+ echo ""
532
+ echo -e "${BLUE}=== Feature Info ===${NC}"
533
+ echo ""
534
+ local status=$(jq -r '.status // "unknown"' "$feature_json")
535
+ local branch=$(jq -r '.branch // "N/A"' "$feature_json")
536
+ local base=$(jq -r '.base_branch // "N/A"' "$feature_json")
537
+ echo " Status: $status"
538
+ echo " Branch: $branch"
539
+ echo " Base Branch: $base"
540
+ fi
541
+
542
+ # Git changes
543
+ if [ -d "$worktree" ]; then
544
+ echo ""
545
+ echo -e "${BLUE}=== Git Changes ===${NC}"
546
+ echo ""
547
+ cd "$worktree"
548
+ local changes=$(git status --short 2>/dev/null | head -10)
549
+ if [ -n "$changes" ]; then
550
+ echo "$changes" | sed 's/^/ /'
551
+ local total=$(git status --short 2>/dev/null | wc -l | tr -d ' ')
552
+ if [ "$total" -gt 10 ]; then
553
+ echo " ... and $((total - 10)) more"
554
+ fi
555
+ else
556
+ echo " (no changes)"
557
+ fi
558
+ fi
559
+
560
+ echo ""
561
+ }
562
+
563
+ cmd_watch() {
564
+ if [ -z "$TARGET" ]; then
565
+ echo "Usage: $0 --watch <feature>"
566
+ exit 1
567
+ fi
568
+
569
+ local agent=$(find_agent "$TARGET")
570
+ if [ -z "$agent" ] || [ "$agent" = "null" ]; then
571
+ echo "Agent not found: $TARGET"
572
+ exit 1
573
+ fi
574
+
575
+ local worktree=$(echo "$agent" | jq -r '.worktree_path')
576
+ local log_file="$worktree/.agent-log"
577
+
578
+ if [ ! -f "$log_file" ]; then
579
+ echo "Log file not found: $log_file"
580
+ exit 1
581
+ fi
582
+
583
+ echo -e "${BLUE}Watching:${NC} $log_file"
584
+ echo -e "${DIM}Press Ctrl+C to stop${NC}"
585
+ echo ""
586
+
587
+ tail -f "$log_file"
588
+ }
589
+
590
+ cmd_log() {
591
+ if [ -z "$TARGET" ]; then
592
+ echo "Usage: $0 --log <feature>"
593
+ exit 1
594
+ fi
595
+
596
+ local agent=$(find_agent "$TARGET")
597
+ if [ -z "$agent" ] || [ "$agent" = "null" ]; then
598
+ echo "Agent not found: $TARGET"
599
+ exit 1
600
+ fi
601
+
602
+ local worktree=$(echo "$agent" | jq -r '.worktree_path')
603
+ local log_file="$worktree/.agent-log"
604
+
605
+ if [ ! -f "$log_file" ]; then
606
+ echo "Log file not found: $log_file"
607
+ exit 1
608
+ fi
609
+
610
+ echo -e "${BLUE}=== Recent Log: $TARGET ===${NC}"
611
+ echo ""
612
+
613
+ # Parse and format JSON log entries
614
+ tail -50 "$log_file" | while IFS= read -r line; do
615
+ local type=$(echo "$line" | jq -r '.type // empty' 2>/dev/null)
616
+ [ -z "$type" ] && continue
617
+
618
+ case "$type" in
619
+ system)
620
+ local subtype=$(echo "$line" | jq -r '.subtype // ""' 2>/dev/null)
621
+ echo -e "${CYAN}[SYSTEM]${NC} $subtype"
622
+ ;;
623
+ user)
624
+ local content=$(echo "$line" | jq -r '.message.content // empty' 2>/dev/null)
625
+ if [ -n "$content" ] && [ "$content" != "null" ]; then
626
+ echo -e "${GREEN}[USER]${NC} ${content:0:200}"
627
+ fi
628
+ ;;
629
+ assistant)
630
+ # Extract text or tool use
631
+ local text=$(echo "$line" | jq -r '.message.content[0].text // empty' 2>/dev/null)
632
+ local tool=$(echo "$line" | jq -r '.message.content[0].name // empty' 2>/dev/null)
633
+
634
+ if [ -n "$text" ] && [ "$text" != "null" ]; then
635
+ # Truncate long text
636
+ local display="${text:0:300}"
637
+ [ ${#text} -gt 300 ] && display="$display..."
638
+ echo -e "${BLUE}[ASSISTANT]${NC} $display"
639
+ elif [ -n "$tool" ] && [ "$tool" != "null" ]; then
640
+ echo -e "${YELLOW}[TOOL]${NC} $tool"
641
+ fi
642
+ ;;
643
+ result)
644
+ local tool_name=$(echo "$line" | jq -r '.tool // "unknown"' 2>/dev/null)
645
+ echo -e "${DIM}[RESULT]${NC} $tool_name completed"
646
+ ;;
647
+ esac
648
+ done
649
+ }
650
+
651
+ cmd_registry() {
652
+ AGENTS_DIR=$(get_agents_dir)
653
+ REGISTRY_FILE="${AGENTS_DIR}/registry.json"
654
+
655
+ echo -e "${BLUE}=== Agent Registry ===${NC}"
656
+ echo ""
657
+ echo "File: $REGISTRY_FILE"
658
+ echo ""
659
+
660
+ if [ -f "$REGISTRY_FILE" ]; then
661
+ jq '.' "$REGISTRY_FILE"
662
+ else
663
+ echo "(registry not found)"
664
+ fi
665
+ }
666
+
667
+ # =============================================================================
668
+ # Main
669
+ # =============================================================================
670
+ case "$ACTION" in
671
+ help)
672
+ cmd_help
673
+ ;;
674
+ list)
675
+ cmd_list
676
+ ;;
677
+ summary)
678
+ cmd_summary
679
+ ;;
680
+ progress)
681
+ cmd_progress
682
+ ;;
683
+ detail)
684
+ cmd_detail
685
+ ;;
686
+ watch)
687
+ cmd_watch
688
+ ;;
689
+ log)
690
+ cmd_log
691
+ ;;
692
+ registry)
693
+ cmd_registry
694
+ ;;
695
+ esac