specweave 0.32.9 → 0.33.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 (179) hide show
  1. package/CLAUDE.md +106 -1
  2. package/dist/src/cli/add-child-pid.d.ts +11 -0
  3. package/dist/src/cli/add-child-pid.d.ts.map +1 -0
  4. package/dist/src/cli/add-child-pid.js +42 -0
  5. package/dist/src/cli/add-child-pid.js.map +1 -0
  6. package/dist/src/cli/add-child-process.d.ts +15 -0
  7. package/dist/src/cli/add-child-process.d.ts.map +1 -0
  8. package/dist/src/cli/add-child-process.js +40 -0
  9. package/dist/src/cli/add-child-process.js.map +1 -0
  10. package/dist/src/cli/check-watchdog.d.ts +15 -0
  11. package/dist/src/cli/check-watchdog.d.ts.map +1 -0
  12. package/dist/src/cli/check-watchdog.js +47 -0
  13. package/dist/src/cli/check-watchdog.js.map +1 -0
  14. package/dist/src/cli/cleanup-zombies.d.ts +14 -0
  15. package/dist/src/cli/cleanup-zombies.d.ts.map +1 -0
  16. package/dist/src/cli/cleanup-zombies.js +268 -0
  17. package/dist/src/cli/cleanup-zombies.js.map +1 -0
  18. package/dist/src/cli/commands/jobs.js +9 -2
  19. package/dist/src/cli/commands/jobs.js.map +1 -1
  20. package/dist/src/cli/find-session-by-pid.d.ts +14 -0
  21. package/dist/src/cli/find-session-by-pid.d.ts.map +1 -0
  22. package/dist/src/cli/find-session-by-pid.js +45 -0
  23. package/dist/src/cli/find-session-by-pid.js.map +1 -0
  24. package/dist/src/cli/get-stale-sessions.d.ts +17 -0
  25. package/dist/src/cli/get-stale-sessions.d.ts.map +1 -0
  26. package/dist/src/cli/get-stale-sessions.js +36 -0
  27. package/dist/src/cli/get-stale-sessions.js.map +1 -0
  28. package/dist/src/cli/register-session.d.ts +16 -0
  29. package/dist/src/cli/register-session.d.ts.map +1 -0
  30. package/dist/src/cli/register-session.js +48 -0
  31. package/dist/src/cli/register-session.js.map +1 -0
  32. package/dist/src/cli/remove-session.d.ts +11 -0
  33. package/dist/src/cli/remove-session.d.ts.map +1 -0
  34. package/dist/src/cli/remove-session.js +36 -0
  35. package/dist/src/cli/remove-session.js.map +1 -0
  36. package/dist/src/cli/update-heartbeat.d.ts +11 -0
  37. package/dist/src/cli/update-heartbeat.d.ts.map +1 -0
  38. package/dist/src/cli/update-heartbeat.js +36 -0
  39. package/dist/src/cli/update-heartbeat.js.map +1 -0
  40. package/dist/src/cli/workers/living-docs-worker.js +6 -0
  41. package/dist/src/cli/workers/living-docs-worker.js.map +1 -1
  42. package/dist/src/config/types.d.ts +1208 -203
  43. package/dist/src/config/types.d.ts.map +1 -1
  44. package/dist/src/core/background/job-launcher.d.ts.map +1 -1
  45. package/dist/src/core/background/job-launcher.js +7 -4
  46. package/dist/src/core/background/job-launcher.js.map +1 -1
  47. package/dist/src/core/background/job-manager.d.ts +25 -0
  48. package/dist/src/core/background/job-manager.d.ts.map +1 -1
  49. package/dist/src/core/background/job-manager.js +136 -15
  50. package/dist/src/core/background/job-manager.js.map +1 -1
  51. package/dist/src/core/increment/increment-utils.d.ts +26 -1
  52. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  53. package/dist/src/core/increment/increment-utils.js +66 -4
  54. package/dist/src/core/increment/increment-utils.js.map +1 -1
  55. package/dist/src/core/increment/status-change-sync-trigger.d.ts +3 -1
  56. package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
  57. package/dist/src/core/increment/status-change-sync-trigger.js +5 -2
  58. package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
  59. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -1
  60. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +48 -12
  61. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -1
  62. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.d.ts +70 -0
  63. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.d.ts.map +1 -0
  64. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.js +188 -0
  65. package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.js.map +1 -0
  66. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.d.ts +33 -0
  67. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.d.ts.map +1 -0
  68. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.js +290 -0
  69. package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.js.map +1 -0
  70. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -1
  71. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +114 -11
  72. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -1
  73. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.d.ts +23 -0
  74. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.d.ts.map +1 -0
  75. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.js +283 -0
  76. package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.js.map +1 -0
  77. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.d.ts +44 -0
  78. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.d.ts.map +1 -0
  79. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.js +61 -0
  80. package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.js.map +1 -0
  81. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.d.ts +126 -0
  82. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.d.ts.map +1 -0
  83. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.js +378 -0
  84. package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.js.map +1 -0
  85. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -1
  86. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +57 -0
  87. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -1
  88. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.d.ts +82 -0
  89. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.d.ts.map +1 -0
  90. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.js +430 -0
  91. package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.js.map +1 -0
  92. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.d.ts +84 -0
  93. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.d.ts.map +1 -0
  94. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.js +387 -0
  95. package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.js.map +1 -0
  96. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.d.ts +61 -0
  97. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.d.ts.map +1 -0
  98. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.js +174 -0
  99. package/dist/src/core/living-docs/intelligent-analyzer/report-writer.js.map +1 -0
  100. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +1 -1
  101. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -1
  102. package/dist/src/core/living-docs/module-analyzer.d.ts +3 -0
  103. package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
  104. package/dist/src/core/living-docs/module-analyzer.js +40 -1
  105. package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
  106. package/dist/src/core/qa/qa-runner.js +1 -1
  107. package/dist/src/core/qa/qa-runner.js.map +1 -1
  108. package/dist/src/core/scheduler/session-sync-executor.js +1 -1
  109. package/dist/src/core/scheduler/session-sync-executor.js.map +1 -1
  110. package/dist/src/core/status-line/status-line-updater.d.ts +1 -1
  111. package/dist/src/core/status-line/status-line-updater.d.ts.map +1 -1
  112. package/dist/src/core/status-line/status-line-updater.js +4 -3
  113. package/dist/src/core/status-line/status-line-updater.js.map +1 -1
  114. package/dist/src/importers/jira-importer.d.ts.map +1 -1
  115. package/dist/src/importers/jira-importer.js +26 -10
  116. package/dist/src/importers/jira-importer.js.map +1 -1
  117. package/dist/src/init/architecture/types.d.ts +140 -33
  118. package/dist/src/init/architecture/types.d.ts.map +1 -1
  119. package/dist/src/init/compliance/types.d.ts +27 -30
  120. package/dist/src/init/compliance/types.d.ts.map +1 -1
  121. package/dist/src/init/repo/types.d.ts +34 -11
  122. package/dist/src/init/repo/types.d.ts.map +1 -1
  123. package/dist/src/init/research/src/config/types.d.ts +82 -15
  124. package/dist/src/init/research/src/config/types.d.ts.map +1 -1
  125. package/dist/src/init/research/types.d.ts +93 -38
  126. package/dist/src/init/research/types.d.ts.map +1 -1
  127. package/dist/src/init/team/types.d.ts +42 -4
  128. package/dist/src/init/team/types.d.ts.map +1 -1
  129. package/dist/src/sync/ado-reconciler.js +1 -1
  130. package/dist/src/sync/ado-reconciler.js.map +1 -1
  131. package/dist/src/sync/github-reconciler.js +1 -1
  132. package/dist/src/sync/github-reconciler.js.map +1 -1
  133. package/dist/src/sync/jira-reconciler.js +1 -1
  134. package/dist/src/sync/jira-reconciler.js.map +1 -1
  135. package/dist/src/types/session.d.ts +65 -0
  136. package/dist/src/types/session.d.ts.map +1 -0
  137. package/dist/src/types/session.js +8 -0
  138. package/dist/src/types/session.js.map +1 -0
  139. package/dist/src/utils/lock-manager.d.ts +48 -0
  140. package/dist/src/utils/lock-manager.d.ts.map +1 -0
  141. package/dist/src/utils/lock-manager.js +195 -0
  142. package/dist/src/utils/lock-manager.js.map +1 -0
  143. package/dist/src/utils/notification-manager.d.ts +45 -0
  144. package/dist/src/utils/notification-manager.d.ts.map +1 -0
  145. package/dist/src/utils/notification-manager.js +130 -0
  146. package/dist/src/utils/notification-manager.js.map +1 -0
  147. package/dist/src/utils/platform-utils.d.ts +136 -0
  148. package/dist/src/utils/platform-utils.d.ts.map +1 -0
  149. package/dist/src/utils/platform-utils.js +366 -0
  150. package/dist/src/utils/platform-utils.js.map +1 -0
  151. package/dist/src/utils/session-registry.d.ts +142 -0
  152. package/dist/src/utils/session-registry.d.ts.map +1 -0
  153. package/dist/src/utils/session-registry.js +480 -0
  154. package/dist/src/utils/session-registry.js.map +1 -0
  155. package/package.json +5 -2
  156. package/plugins/specweave/commands/specweave-living-docs.md +42 -0
  157. package/plugins/specweave/hooks/hooks.json +10 -0
  158. package/plugins/specweave/hooks/lib/update-active-increment.sh +2 -2
  159. package/plugins/specweave/hooks/lib/update-status-line.sh +1 -1
  160. package/plugins/specweave/hooks/post-increment-status-change.sh +3 -3
  161. package/plugins/specweave/hooks/post-metadata-change.sh +1 -1
  162. package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -26
  163. package/plugins/specweave/hooks/universal/session-start.cmd +16 -16
  164. package/plugins/specweave/hooks/universal/session-start.ps1 +16 -16
  165. package/plugins/specweave/hooks/user-prompt-submit.sh +2 -2
  166. package/plugins/specweave/hooks/v2/guards/increment-root-guard.sh +61 -0
  167. package/plugins/specweave/hooks/v2/session-end.sh +69 -0
  168. package/plugins/specweave/hooks/v2/session-start.sh +81 -0
  169. package/plugins/specweave/lib/vendor/sync/github-reconciler.js +1 -1
  170. package/plugins/specweave/lib/vendor/sync/github-reconciler.js.map +1 -1
  171. package/plugins/specweave/scripts/heartbeat.sh +110 -0
  172. package/plugins/specweave/scripts/progress.js +34 -4
  173. package/plugins/specweave/scripts/read-jobs.sh +1 -1
  174. package/plugins/specweave/scripts/read-progress.sh +50 -5
  175. package/plugins/specweave/scripts/read-workflow.sh +1 -1
  176. package/plugins/specweave/scripts/session-watchdog.sh +65 -0
  177. package/plugins/specweave/scripts/status.js +28 -11
  178. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +738 -0
  179. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1107 -0
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Heartbeat Background Process
4
+ #
5
+ # Purpose:
6
+ # - Updates session heartbeat timestamp every 5 seconds
7
+ # - Polls parent process existence
8
+ # - Self-terminates when parent dies
9
+ # - Removes session from registry on exit
10
+ #
11
+ # Usage:
12
+ # bash heartbeat.sh <session-id>
13
+ #
14
+ # Background Usage:
15
+ # nohup bash heartbeat.sh <session-id> > .specweave/logs/heartbeat-<session-id>.log 2>&1 &
16
+
17
+ set -euo pipefail
18
+
19
+ # ============================================================================
20
+ # Configuration
21
+ # ============================================================================
22
+
23
+ SESSION_ID="${1:-}"
24
+ INTERVAL=5 # Heartbeat interval in seconds
25
+ PROJECT_ROOT="${PWD}"
26
+ REGISTRY_FILE="${PROJECT_ROOT}/.specweave/state/.session-registry.json"
27
+ LOG_FILE="${PROJECT_ROOT}/.specweave/logs/heartbeat-${SESSION_ID}.log"
28
+
29
+ # ============================================================================
30
+ # Validation
31
+ # ============================================================================
32
+
33
+ if [[ -z "$SESSION_ID" ]]; then
34
+ echo "āŒ ERROR: SESSION_ID required"
35
+ echo "Usage: bash heartbeat.sh <session-id>"
36
+ exit 1
37
+ fi
38
+
39
+ # Ensure logs directory exists
40
+ mkdir -p "$(dirname "$LOG_FILE")"
41
+
42
+ # ============================================================================
43
+ # Helper Functions
44
+ # ============================================================================
45
+
46
+ log() {
47
+ local level="$1"
48
+ shift
49
+ echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] [$level] [${SESSION_ID}] $*" >> "$LOG_FILE"
50
+ }
51
+
52
+ # Cross-platform parent process existence check
53
+ check_parent_alive() {
54
+ local ppid="$PPID"
55
+
56
+ if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]]; then
57
+ # Windows: Use tasklist
58
+ tasklist /FI "PID eq $ppid" 2>/dev/null | grep -q "$ppid"
59
+ return $?
60
+ else
61
+ # macOS/Linux: Use kill -0
62
+ kill -0 "$ppid" 2>/dev/null
63
+ return $?
64
+ fi
65
+ }
66
+
67
+ # Update heartbeat timestamp via Node.js CLI
68
+ update_heartbeat() {
69
+ node "${PROJECT_ROOT}/dist/src/cli/update-heartbeat.js" "$SESSION_ID" 2>&1 | \
70
+ grep -v "^$" | head -5 >> "$LOG_FILE" || true
71
+ }
72
+
73
+ # Cleanup session on exit
74
+ cleanup_session() {
75
+ log "INFO" "Parent process died, cleaning up session..."
76
+
77
+ # Remove session from registry
78
+ node "${PROJECT_ROOT}/dist/src/cli/remove-session.js" "$SESSION_ID" 2>&1 | \
79
+ grep -v "^$" | head -5 >> "$LOG_FILE" || true
80
+
81
+ log "INFO" "Session cleanup complete, exiting"
82
+ exit 0
83
+ }
84
+
85
+ # ============================================================================
86
+ # Main Loop
87
+ # ============================================================================
88
+
89
+ log "INFO" "Heartbeat process started (parent PID: $PPID, interval: ${INTERVAL}s)"
90
+
91
+ # Trap signals for graceful shutdown
92
+ trap cleanup_session SIGTERM SIGINT
93
+
94
+ while true; do
95
+ # Check if parent process still exists
96
+ if ! check_parent_alive; then
97
+ log "WARN" "Parent process (PID: $PPID) no longer exists"
98
+ cleanup_session
99
+ fi
100
+
101
+ # Update heartbeat timestamp
102
+ if update_heartbeat; then
103
+ log "DEBUG" "Heartbeat updated"
104
+ else
105
+ log "ERROR" "Failed to update heartbeat"
106
+ fi
107
+
108
+ # Sleep for interval
109
+ sleep "$INTERVAL"
110
+ done
@@ -118,11 +118,24 @@ if (specificId) {
118
118
 
119
119
  // Show all active increments
120
120
  const increments = incrementFolders.map(parseIncrement);
121
- const active = increments.filter(i => ['active', 'planning', 'in-progress'].includes(i.status));
121
+ const readyForReview = increments.filter(i => i.status === 'ready_for_review');
122
+ const active = increments.filter(i => ['active', 'planning', 'backlog'].includes(i.status));
122
123
  const paused = increments.filter(i => i.status === 'paused');
123
124
 
124
125
  console.log('\nšŸ“Š Increment Progress\n');
125
126
 
127
+ // Show ready_for_review FIRST (needs attention!)
128
+ if (readyForReview.length > 0) {
129
+ console.log(`šŸ‘€ Ready for Review (${readyForReview.length}):`);
130
+ for (const inc of readyForReview) {
131
+ const bar = createProgressBar(inc.percentage, 15);
132
+ console.log(` ${inc.id}`);
133
+ console.log(` ${bar} ${inc.completedTasks}/${inc.totalTasks} (${inc.percentage}%)`);
134
+ console.log(` → /specweave:done ${inc.id}`);
135
+ }
136
+ console.log('');
137
+ }
138
+
126
139
  if (active.length > 0) {
127
140
  console.log(`šŸ”„ Active (${active.length}):`);
128
141
  for (const inc of active) {
@@ -141,16 +154,31 @@ if (paused.length > 0) {
141
154
  console.log('');
142
155
  }
143
156
 
144
- if (active.length === 0 && paused.length === 0) {
157
+ // Summary section
158
+ if (readyForReview.length > 0 || active.length > 0 || paused.length > 0) {
159
+ console.log('─'.repeat(40));
160
+ const parts = [];
161
+ if (readyForReview.length > 0) parts.push(`${readyForReview.length} ready for review`);
162
+ if (active.length > 0) parts.push(`${active.length} active`);
163
+ if (paused.length > 0) parts.push(`${paused.length} paused`);
164
+ console.log(`Summary: ${parts.join(', ')}`);
165
+ console.log('');
166
+
167
+ if (readyForReview.length > 0) {
168
+ console.log('šŸ’” Run /specweave:done <id> to close reviewed increments');
169
+ } else {
170
+ console.log('šŸ’” For details: /specweave:progress <incrementId>');
171
+ }
172
+ } else {
145
173
  console.log('No active increments.');
146
174
  const completed = increments.filter(i => i.status === 'completed');
147
175
  if (completed.length > 0) {
148
176
  console.log(`${completed.length} completed increment(s).`);
149
177
  }
178
+ console.log('');
179
+ console.log('šŸ’” Run /specweave:increment to start new work');
150
180
  }
151
181
 
152
- console.log('šŸ’” For details: /specweave:progress <incrementId>');
153
-
154
182
  // Helpers
155
183
  function createProgressBar(pct, width = 20) {
156
184
  const filled = Math.round((pct / 100) * width);
@@ -162,6 +190,8 @@ function formatStatus(status) {
162
190
  const icons = {
163
191
  'active': 'šŸ”„ active',
164
192
  'planning': 'šŸ“ planning',
193
+ 'backlog': 'šŸ“‹ backlog',
194
+ 'ready_for_review': 'šŸ‘€ ready for review',
165
195
  'paused': 'āøļø paused',
166
196
  'completed': 'āœ… completed',
167
197
  'abandoned': 'āŒ abandoned'
@@ -110,7 +110,7 @@ if [[ -f "$CACHE_FILE" ]] && jq -e '.' "$CACHE_FILE" >/dev/null 2>&1; then
110
110
  # Show active increments
111
111
  ACTIVE=$(jq -r '
112
112
  .increments | to_entries[] |
113
- select(.value.status == "active" or .value.status == "planning" or .value.status == "in-progress") |
113
+ select(.value.status == "active" or .value.status == "planning" or .value.status == "backlog" or .value.status == "ready_for_review") |
114
114
  "\(.key)|\(.value.status)|\(.value.tasks.completed)|\(.value.tasks.total)"
115
115
  ' "$CACHE_FILE" 2>/dev/null)
116
116
 
@@ -126,10 +126,36 @@ echo ""
126
126
  echo "šŸ“Š Increment Progress"
127
127
  echo ""
128
128
 
129
- # Get active increments
129
+ # Get ready_for_review increments FIRST (needs attention!)
130
+ READY_FOR_REVIEW=$(jq -r '
131
+ .increments | to_entries[] |
132
+ select(.value.status == "ready_for_review") |
133
+ "\(.key)|\(.value.tasks.completed)|\(.value.tasks.total)"
134
+ ' "$CACHE_FILE" 2>/dev/null)
135
+
136
+ REVIEW_COUNT=0
137
+ if [[ -n "$READY_FOR_REVIEW" ]]; then
138
+ echo "šŸ‘€ Ready for Review:"
139
+ while IFS='|' read -r id completed total; do
140
+ [[ -z "$id" ]] && continue
141
+ REVIEW_COUNT=$((REVIEW_COUNT + 1))
142
+ if [[ "$total" -gt 0 ]]; then
143
+ pct=$((completed * 100 / total))
144
+ else
145
+ pct=0
146
+ fi
147
+ bar=$(progress_bar "$pct" 15)
148
+ echo " $id"
149
+ echo " $bar $completed/$total ($pct%)"
150
+ echo " → /specweave:done $id"
151
+ done <<< "$READY_FOR_REVIEW"
152
+ echo ""
153
+ fi
154
+
155
+ # Get active increments (excluding ready_for_review)
130
156
  ACTIVE=$(jq -r '
131
157
  .increments | to_entries[] |
132
- select(.value.status == "active" or .value.status == "planning" or .value.status == "in-progress") |
158
+ select(.value.status == "active" or .value.status == "planning" or .value.status == "backlog") |
133
159
  "\(.key)|\(.value.tasks.completed)|\(.value.tasks.total)"
134
160
  ' "$CACHE_FILE" 2>/dev/null)
135
161
 
@@ -173,8 +199,20 @@ if [[ -n "$PAUSED" ]]; then
173
199
  echo ""
174
200
  fi
175
201
 
176
- # If no active/paused
177
- if [[ "$ACTIVE_COUNT" -eq 0 ]] && [[ -z "$PAUSED" ]]; then
202
+ # Summary section
203
+ if [[ "$REVIEW_COUNT" -gt 0 ]] || [[ "$ACTIVE_COUNT" -gt 0 ]] || [[ -n "$PAUSED" ]]; then
204
+ # Has work - show summary
205
+ echo "────────────────────────────────────────"
206
+ SUMMARY_PARTS=()
207
+ [[ "$REVIEW_COUNT" -gt 0 ]] && SUMMARY_PARTS+=("$REVIEW_COUNT ready for review")
208
+ [[ "$ACTIVE_COUNT" -gt 0 ]] && SUMMARY_PARTS+=("$ACTIVE_COUNT active")
209
+ PAUSED_COUNT=0
210
+ [[ -n "$PAUSED" ]] && PAUSED_COUNT=$(echo "$PAUSED" | grep -c '|' || echo 0)
211
+ [[ "$PAUSED_COUNT" -gt 0 ]] && SUMMARY_PARTS+=("$PAUSED_COUNT paused")
212
+
213
+ IFS=', '; echo "Summary: ${SUMMARY_PARTS[*]}"
214
+ else
215
+ # No work in progress
178
216
  echo "No active increments."
179
217
  COMPLETED_COUNT=$(jq '.summary.completed // 0' "$CACHE_FILE")
180
218
  if [[ "$COMPLETED_COUNT" -gt 0 ]]; then
@@ -182,4 +220,11 @@ if [[ "$ACTIVE_COUNT" -eq 0 ]] && [[ -z "$PAUSED" ]]; then
182
220
  fi
183
221
  fi
184
222
 
185
- echo "šŸ’” For details: /specweave:progress <incrementId>"
223
+ echo ""
224
+ if [[ "$REVIEW_COUNT" -gt 0 ]]; then
225
+ echo "šŸ’” Run /specweave:done <id> to close reviewed increments"
226
+ elif [[ "$ACTIVE_COUNT" -eq 0 ]]; then
227
+ echo "šŸ’” Run /specweave:increment to start new work"
228
+ else
229
+ echo "šŸ’” For details: /specweave:progress <incrementId>"
230
+ fi
@@ -64,7 +64,7 @@ else
64
64
  # Find first active increment
65
65
  ACTIVE_ID=$(jq -r '
66
66
  .increments | to_entries[] |
67
- select(.value.status == "active" or .value.status == "in-progress") |
67
+ select(.value.status == "active" or .value.status == "planning" or .value.status == "backlog" or .value.status == "ready_for_review") |
68
68
  .key
69
69
  ' "$CACHE_FILE" 2>/dev/null | head -1)
70
70
  fi
@@ -12,6 +12,9 @@ SPECWEAVE_ROOT="${SPECWEAVE_ROOT:-.specweave}"
12
12
  SIGNAL_FILE="${SPECWEAVE_ROOT}/state/.session-stuck"
13
13
  HEARTBEAT_FILE="${SPECWEAVE_ROOT}/state/.heartbeat"
14
14
  DAEMON_MODE=false
15
+ PROJECT_ROOT="${PWD}"
16
+ SESSION_ID="watchdog-$$-$(date +%s)"
17
+ COORDINATION_THRESHOLD=30 # Heartbeat threshold for active watchdog detection
15
18
 
16
19
  # Colors
17
20
  RED='\033[0;31m'
@@ -176,15 +179,77 @@ check_session_health() {
176
179
  fi
177
180
  }
178
181
 
182
+ # Coordination Functions
183
+ check_active_watchdog() {
184
+ # Check if another watchdog is running via session registry
185
+ node "${PROJECT_ROOT}/dist/src/cli/check-watchdog.js" 2>/dev/null || echo ""
186
+ }
187
+
188
+ register_watchdog() {
189
+ # Register this watchdog in session registry
190
+ node "${PROJECT_ROOT}/dist/src/cli/register-session.js" "$SESSION_ID" $$ "watchdog" 2>&1 | \
191
+ grep -v "^$" | head -3
192
+ }
193
+
194
+ update_watchdog_heartbeat() {
195
+ # Update watchdog heartbeat
196
+ node "${PROJECT_ROOT}/dist/src/cli/update-heartbeat.js" "$SESSION_ID" 2>/dev/null || true
197
+ }
198
+
199
+ cleanup_watchdog() {
200
+ # Remove watchdog from registry on exit
201
+ node "${PROJECT_ROOT}/dist/src/cli/remove-session.js" "$SESSION_ID" 2>&1 | \
202
+ grep -v "^$" | head -3
203
+ log "Watchdog cleanup complete"
204
+ }
205
+
206
+ run_cleanup_service() {
207
+ # Run zombie process cleanup
208
+ node "${PROJECT_ROOT}/dist/src/cli/cleanup-zombies.js" 60 2>&1 | \
209
+ grep -v "^$" | head -10 || true
210
+ }
211
+
179
212
  # Main execution
180
213
  if [[ "$DAEMON_MODE" == "true" ]]; then
214
+ # Coordination check before starting daemon
215
+ active_watchdog=$(check_active_watchdog)
216
+
217
+ if [[ -n "$active_watchdog" ]]; then
218
+ log "${YELLOW}Watchdog already active (PID: $active_watchdog)${NC}"
219
+ log "Exiting to avoid duplicate watchdogs"
220
+ exit 0
221
+ fi
222
+
223
+ # Register as watchdog
224
+ register_watchdog
225
+
226
+ # Trap signals for graceful shutdown
227
+ trap cleanup_watchdog SIGTERM SIGINT EXIT
228
+
181
229
  log "Starting session watchdog daemon (interval: ${CHECK_INTERVAL}s, threshold: ${STUCK_THRESHOLD_SECONDS}s)"
230
+ log "Watchdog session: $SESSION_ID (PID: $$)"
182
231
  log "Press Ctrl+C to stop"
183
232
 
184
233
  while true; do
234
+ # Update own heartbeat
235
+ update_watchdog_heartbeat
236
+
237
+ # Check session health
185
238
  check_session_health || true
239
+
240
+ # Run cleanup service
241
+ run_cleanup_service
242
+
243
+ # Check if parent process still exists (if we have a parent session)
244
+ if ! kill -0 $PPID 2>/dev/null; then
245
+ log "${YELLOW}Parent process died, exiting watchdog${NC}"
246
+ break
247
+ fi
248
+
186
249
  sleep "$CHECK_INTERVAL"
187
250
  done
251
+
252
+ cleanup_watchdog
188
253
  else
189
254
  log "Running single health check..."
190
255
  check_session_health
@@ -86,7 +86,7 @@ for (const folder of incrementFolders) {
86
86
  // Display
87
87
  console.log('\nšŸ“‹ SpecWeave Status Overview\n');
88
88
 
89
- const statusOrder = ['active', 'planning', 'in-progress', 'ready_for_review', 'paused', 'backlog', 'completed', 'abandoned'];
89
+ const statusOrder = ['ready_for_review', 'active', 'planning', 'in-progress', 'paused', 'backlog', 'completed', 'abandoned'];
90
90
  const statusIcons = {
91
91
  'active': 'šŸ”„',
92
92
  'planning': 'šŸ“',
@@ -105,12 +105,16 @@ for (const status of statusOrder) {
105
105
  if (items && items.length > 0) {
106
106
  hasOutput = true;
107
107
  const icon = statusIcons[status] || '•';
108
- console.log(`${icon} ${status.replace('_', ' ')} (${items.length}):`);
109
-
108
+ console.log(`${icon} ${status.replace(/_/g, ' ')} (${items.length}):`);
109
+
110
110
  // Show first 5, summarize rest
111
111
  const toShow = items.slice(0, 5);
112
112
  for (const item of toShow) {
113
113
  console.log(` ${item}`);
114
+ // Add action hint for ready_for_review
115
+ if (status === 'ready_for_review') {
116
+ console.log(` → /specweave:done ${item}`);
117
+ }
114
118
  }
115
119
  if (items.length > 5) {
116
120
  console.log(` ... and ${items.length - 5} more`);
@@ -140,15 +144,28 @@ if (!hasOutput) {
140
144
 
141
145
  // Summary line
142
146
  const total = incrementFolders.length;
143
- const activeCount = (byStatus['active']?.length || 0) +
144
- (byStatus['planning']?.length || 0) +
145
- (byStatus['in-progress']?.length || 0);
147
+ const reviewCount = byStatus['ready_for_review']?.length || 0;
148
+ const activeCount = (byStatus['active']?.length || 0) +
149
+ (byStatus['planning']?.length || 0) +
150
+ (byStatus['backlog']?.length || 0);
146
151
  const completedCount = byStatus['completed']?.length || 0;
147
152
 
148
153
  console.log('─'.repeat(40));
149
- console.log(`Total: ${total} increment(s) | Active: ${activeCount} | Completed: ${completedCount} | Archived: ${archivedCount}`);
154
+ const summaryParts = [`Total: ${total}`];
155
+ if (reviewCount > 0) summaryParts.push(`Review: ${reviewCount}`);
156
+ summaryParts.push(`Active: ${activeCount}`);
157
+ summaryParts.push(`Completed: ${completedCount}`);
158
+ if (archivedCount > 0) summaryParts.push(`Archived: ${archivedCount}`);
159
+ console.log(summaryParts.join(' | '));
150
160
  console.log('');
151
- console.log('šŸ’” Commands:');
152
- console.log(' /specweave:progress Show task progress');
153
- console.log(' /specweave:do Execute current tasks');
154
- console.log(' /specweave:done <id> Close increment');
161
+
162
+ // Context-aware command hints
163
+ if (reviewCount > 0) {
164
+ console.log('šŸ’” Next step: /specweave:done <id> to close reviewed increment(s)');
165
+ } else if (activeCount > 0) {
166
+ console.log('šŸ’” Commands:');
167
+ console.log(' /specweave:progress Show task progress');
168
+ console.log(' /specweave:do Execute current tasks');
169
+ } else {
170
+ console.log('šŸ’” Run /specweave:increment to start new work');
171
+ }