specflow-cc 1.13.0 → 1.14.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.
@@ -0,0 +1,220 @@
1
+ ---
2
+ name: sf:health
3
+ description: Diagnose .specflow/ directory health and optionally repair issues
4
+ argument-hint: [--repair]
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - Write
10
+ - AskUserQuestion
11
+ ---
12
+
13
+ <purpose>
14
+ Validate `.specflow/` directory integrity and report actionable issues. Checks for missing files, invalid state, orphaned specs, and queue inconsistencies. Optionally repairs auto-fixable issues.
15
+ </purpose>
16
+
17
+ <context>
18
+ @.specflow/STATE.md
19
+ </context>
20
+
21
+ <workflow>
22
+
23
+ ## Step 1: Verify Initialization
24
+
25
+ ```bash
26
+ [ -d .specflow ] && echo "OK" || echo "NOT_INITIALIZED"
27
+ ```
28
+
29
+ **If NOT_INITIALIZED:**
30
+ ```
31
+ SpecFlow not initialized. Run `/sf:init` first.
32
+ ```
33
+ Exit.
34
+
35
+ ## Step 2: Parse Arguments
36
+
37
+ Check if `--repair` flag is present.
38
+
39
+ ## Step 3: Run Health Checks
40
+
41
+ Initialize collectors:
42
+ - `errors[]` — critical issues
43
+ - `warnings[]` — non-critical issues
44
+ - `info[]` — informational notes
45
+ - `repairs[]` — actions taken (if --repair)
46
+
47
+ ### 3.1 Core Files Check
48
+
49
+ | Check | File | Severity | Repairable |
50
+ |-------|------|----------|------------|
51
+ | E001 | `.specflow/STATE.md` missing | error | Yes — regenerate minimal STATE.md |
52
+ | E002 | `.specflow/STATE.md` missing `## Queue` section | error | No |
53
+ | W001 | `.specflow/todos/TODO.md` missing | warning | Yes — create empty TODO.md |
54
+ | W002 | `.specflow/specs/` directory missing | warning | Yes — create directory |
55
+ | W003 | `.specflow/archive/` directory missing | warning | Yes — create directory |
56
+ | W004 | `.specflow/execution/` directory missing | warning | Yes — create directory |
57
+
58
+ For each check:
59
+ 1. Test existence
60
+ 2. If missing and repairable and `--repair`: fix it, add to `repairs[]`
61
+ 3. If missing and not repairable: add to `errors[]` or `warnings[]`
62
+
63
+ ### 3.2 STATE.md Integrity
64
+
65
+ Read STATE.md and validate:
66
+
67
+ **E003: Active spec references non-existent file**
68
+ - Extract active spec ID from `## Active Specification`
69
+ - If not "—" or empty, check `.specflow/specs/{ID}.md` exists
70
+ - If missing: error (repairable — clear active spec to "—")
71
+
72
+ **W005: Queue references non-existent spec file**
73
+ - Parse queue table rows
74
+ - For each spec ID, verify `.specflow/specs/{ID}.md` or `.specflow/archive/{ID}.md` exists
75
+ - If missing: warning (not repairable — spec may have been manually deleted)
76
+
77
+ **W006: Queue has duplicate spec IDs**
78
+ - Parse all IDs from queue table
79
+ - If duplicates found: warning (not repairable)
80
+
81
+ **W007: STATUS.md malformed — missing required sections**
82
+ - Check for: `## Active Specification`, `## Queue`
83
+ - If missing: warning
84
+
85
+ ### 3.3 Orphaned Specs Check
86
+
87
+ **I001: Spec file exists but not in queue or archive**
88
+ - List all files in `.specflow/specs/`
89
+ - For each, check if its ID appears in STATE.md queue
90
+ - If not: info (may be work-in-progress)
91
+
92
+ ### 3.4 Archive Consistency
93
+
94
+ **I002: Spec in queue marked as completed but not archived**
95
+ - Parse queue for specs with status containing "done" or "complete"
96
+ - Check if file exists in `.specflow/archive/`
97
+ - If not: info
98
+
99
+ ### 3.5 Execution State
100
+
101
+ **W008: Stale execution state files**
102
+ - List `.specflow/execution/*.json`
103
+ - For each, check if the spec ID is the currently active spec
104
+ - If not active: warning (repairable — delete stale files)
105
+
106
+ ## Step 4: Calculate Status
107
+
108
+ ```
109
+ HEALTHY = 0 errors, 0 warnings
110
+ DEGRADED = 0 errors, 1+ warnings
111
+ BROKEN = 1+ errors
112
+ ```
113
+
114
+ ## Step 5: Display Results
115
+
116
+ **IMPORTANT:** Output the following directly as formatted text, NOT wrapped in a markdown code block:
117
+
118
+ ```
119
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
120
+ SpecFlow Health Check
121
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
122
+
123
+ **Status:** HEALTHY | DEGRADED | BROKEN
124
+ **Errors:** N | **Warnings:** N | **Info:** N
125
+ ```
126
+
127
+ **If repairs were performed:**
128
+ ```
129
+ ### Repairs Performed
130
+
131
+ - Repaired: {description}
132
+ - Repaired: {description}
133
+ ```
134
+
135
+ **If errors exist:**
136
+ ```
137
+ ### Errors
138
+
139
+ - [{code}] {message}
140
+ Fix: {suggested fix}
141
+ ```
142
+
143
+ **If warnings exist:**
144
+ ```
145
+ ### Warnings
146
+
147
+ - [{code}] {message}
148
+ Fix: {suggested fix}
149
+ ```
150
+
151
+ **If info exists:**
152
+ ```
153
+ ### Info
154
+
155
+ - [{code}] {message}
156
+ ```
157
+
158
+ **Footer (if repairable issues exist and --repair was NOT used):**
159
+ ```
160
+ ---
161
+ {N} issues can be auto-repaired. Run: `/sf:health --repair`
162
+ ```
163
+
164
+ ## Step 6: Offer Repair (if applicable)
165
+
166
+ If repairable issues found and `--repair` was NOT passed:
167
+ - Ask user if they want to run repairs
168
+ - If yes, execute repairs and re-run checks to verify
169
+
170
+ ## Step 7: Verify Repairs (if --repair was used)
171
+
172
+ Re-run all checks without repair to confirm resolution.
173
+ Display final status.
174
+
175
+ </workflow>
176
+
177
+ <error_codes>
178
+
179
+ | Code | Severity | Description | Repairable |
180
+ |------|----------|-------------|------------|
181
+ | E001 | error | STATE.md not found | Yes |
182
+ | E002 | error | STATE.md missing Queue section | No |
183
+ | E003 | error | Active spec references non-existent file | Yes |
184
+ | W001 | warning | TODO.md not found | Yes |
185
+ | W002 | warning | specs/ directory missing | Yes |
186
+ | W003 | warning | archive/ directory missing | Yes |
187
+ | W004 | warning | execution/ directory missing | Yes |
188
+ | W005 | warning | Queue references non-existent spec | No |
189
+ | W006 | warning | Queue has duplicate spec IDs | No |
190
+ | W007 | warning | STATE.md missing required sections | No |
191
+ | W008 | warning | Stale execution state files | Yes |
192
+ | I001 | info | Spec not in queue (may be WIP) | No |
193
+ | I002 | info | Completed spec not archived | No |
194
+
195
+ </error_codes>
196
+
197
+ <repair_actions>
198
+
199
+ | Action | Effect | Risk |
200
+ |--------|--------|------|
201
+ | Create STATE.md | Minimal template with empty queue | None |
202
+ | Create TODO.md | Empty TODO template | None |
203
+ | Create directories | specs/, archive/, execution/ | None |
204
+ | Clear active spec | Set to "—" if spec file missing | Loses active reference |
205
+ | Delete stale execution | Remove orphaned .json state files | None |
206
+
207
+ **Not repairable (too risky):**
208
+ - STATE.md content/queue entries
209
+ - Spec file contents
210
+ - Archive decisions
211
+
212
+ </repair_actions>
213
+
214
+ <success_criteria>
215
+ - [ ] All health checks executed
216
+ - [ ] Clear status reported (HEALTHY/DEGRADED/BROKEN)
217
+ - [ ] Each issue has error code and suggested fix
218
+ - [ ] --repair only fixes safe, non-destructive issues
219
+ - [ ] Repairs verified by re-running checks
220
+ </success_criteria>
@@ -226,6 +226,7 @@ Workflow: Spec → Audit → Revise → Run → Review → Fix → Done
226
226
  | /sf:revise | Revise spec based on audit feedback |
227
227
  | /sf:run | Execute specification |
228
228
  | /sf:review | Review implementation (fresh context) |
229
+ | /sf:validate | Run validation checklist from spec |
229
230
  | /sf:verify | Interactive human verification |
230
231
  | /sf:fix | Fix implementation based on review |
231
232
  | /sf:done | Finalize, commit, and archive |
@@ -288,6 +289,7 @@ Workflow: Spec → Audit → Revise → Run → Review → Fix → Done
288
289
  | Command | Description |
289
290
  |--------------|-----------------------------------------|
290
291
  | /sf:help | This help (or detailed: /sf:help new) |
292
+ | /sf:health | Diagnose .specflow/ integrity (--repair)|
291
293
  | /sf:history | View completed specifications |
292
294
  | /sf:metrics | Project statistics and insights |
293
295
 
@@ -201,9 +201,20 @@ Your choice [1]:
201
201
 
202
202
  **If 1 (Accept):**
203
203
  - Agent creates child specifications
204
- - Agent archives parent
205
- - Agent updates STATE.md
206
- - Continue to Step 7
204
+ - Agent archives parent and updates STATE.md
205
+ - **Verify archival:** After agent completes, check if parent was moved:
206
+
207
+ ```bash
208
+ if [ -f ".specflow/specs/{ID}.md" ]; then
209
+ mkdir -p .specflow/archive
210
+ mv ".specflow/specs/{ID}.md" ".specflow/archive/{ID}.md"
211
+ echo "ARCHIVED"
212
+ else
213
+ echo "ALREADY_ARCHIVED"
214
+ fi
215
+ ```
216
+
217
+ - Continue to Step 8
207
218
 
208
219
  **If 2 (Modify):**
209
220
  - Use AskUserQuestion to get modifications
@@ -0,0 +1,154 @@
1
+ ---
2
+ name: sf:validate
3
+ description: Validate implementation against spec's validation checklist
4
+ argument-hint: [SPEC-XXX]
5
+ allowed-tools:
6
+ - Read
7
+ - Bash
8
+ - Glob
9
+ - Grep
10
+ - Write
11
+ - AskUserQuestion
12
+ ---
13
+
14
+ <purpose>
15
+ Run the validation checklist from a specification after implementation. Executes automated checks (test commands, grep verifications) and prompts for manual checks. Reports pass/fail per item and overall validation status.
16
+ </purpose>
17
+
18
+ <context>
19
+ @.specflow/STATE.md
20
+ </context>
21
+
22
+ <workflow>
23
+
24
+ ## Step 1: Verify Initialization
25
+
26
+ ```bash
27
+ [ -d .specflow ] && echo "OK" || echo "NOT_INITIALIZED"
28
+ ```
29
+
30
+ **If NOT_INITIALIZED:**
31
+ ```
32
+ SpecFlow not initialized. Run `/sf:init` first.
33
+ ```
34
+ Exit.
35
+
36
+ ## Step 2: Resolve Specification
37
+
38
+ **If SPEC-XXX argument provided:** Use that spec.
39
+ **If no argument:** Use active spec from STATE.md.
40
+
41
+ Read the spec file from `.specflow/specs/SPEC-XXX.md`.
42
+
43
+ **If spec not found:** Check `.specflow/archive/SPEC-XXX.md`.
44
+
45
+ **If still not found:**
46
+ ```
47
+ Specification {ID} not found.
48
+ ```
49
+ Exit.
50
+
51
+ ## Step 3: Extract Validation Checklist
52
+
53
+ Look for `## Validation Checklist` section in the spec.
54
+
55
+ **If section not found:**
56
+ ```
57
+ No validation checklist found in {ID}.
58
+
59
+ The spec was created without a validation checklist.
60
+ You can:
61
+ 1. Add one manually to the spec
62
+ 2. Use `/sf:verify` for interactive human verification
63
+ 3. Use `/sf:review` for AI-powered code review
64
+ ```
65
+ Exit.
66
+
67
+ Parse checklist items. Each item should have:
68
+ - **Action:** What to do (command to run, endpoint to hit, UI to check)
69
+ - **Expected:** What should happen
70
+
71
+ ## Step 4: Display Plan
72
+
73
+ **IMPORTANT:** Output the following directly as formatted text, NOT wrapped in a markdown code block:
74
+
75
+ ```
76
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
77
+ VALIDATION: {SPEC-XXX}
78
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
79
+
80
+ **Spec:** {title}
81
+ **Checklist items:** {count}
82
+
83
+ Running validation...
84
+ ```
85
+
86
+ ## Step 5: Execute Checks
87
+
88
+ For each checklist item:
89
+
90
+ ### 5.1 Automated Checks
91
+
92
+ If the item contains a runnable command (backtick-wrapped command, `npm test`, `curl`, etc.):
93
+ 1. Execute the command
94
+ 2. Check exit code and output against expected result
95
+ 3. Record: PASS or FAIL with output
96
+
97
+ ### 5.2 Code Verification Checks
98
+
99
+ If the item references code behavior (file exists, function exists, pattern present):
100
+ 1. Use Glob/Grep/Read to verify
101
+ 2. Record: PASS or FAIL
102
+
103
+ ### 5.3 Manual Checks
104
+
105
+ If the item requires manual/visual verification (UI behavior, browser check):
106
+ 1. Ask user via AskUserQuestion: "Did this pass? {item description}"
107
+ 2. Record user's response
108
+
109
+ ### 5.4 Track Results
110
+
111
+ For each item, record:
112
+ - Item description
113
+ - Type: automated / code / manual
114
+ - Result: PASS / FAIL / SKIP
115
+ - Details: output or user note
116
+
117
+ ## Step 6: Display Results
118
+
119
+ **IMPORTANT:** Output the following directly as formatted text, NOT wrapped in a markdown code block:
120
+
121
+ ```
122
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
123
+ VALIDATION RESULTS: {SPEC-XXX}
124
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
125
+
126
+ | # | Check | Type | Result |
127
+ |---|-------|------|--------|
128
+ | 1 | {description} | automated | PASS |
129
+ | 2 | {description} | code | PASS |
130
+ | 3 | {description} | manual | FAIL |
131
+
132
+ ---
133
+
134
+ **Result:** {passed}/{total} checks passed
135
+
136
+ {If all passed:}
137
+ Validation PASSED. Ready for `/sf:done`.
138
+
139
+ {If any failed:}
140
+ Validation FAILED. Fix issues and re-run `/sf:validate`.
141
+ ```
142
+
143
+ </workflow>
144
+
145
+ <success_criteria>
146
+ - [ ] Spec resolved (argument or active)
147
+ - [ ] Validation checklist extracted from spec
148
+ - [ ] Missing checklist handled gracefully
149
+ - [ ] Automated commands executed and verified
150
+ - [ ] Code checks performed via tools
151
+ - [ ] Manual checks prompted to user
152
+ - [ ] Clear pass/fail report displayed
153
+ - [ ] Guidance on next step provided
154
+ </success_criteria>
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+ // Context Monitor - PostToolUse hook
3
+ // Reads context metrics from the statusline bridge file and injects
4
+ // warnings when context usage is high. Makes the AGENT aware of
5
+ // context limits (the statusline only shows the user).
6
+ //
7
+ // How it works:
8
+ // 1. The statusline hook writes metrics to /tmp/claude-ctx-{session_id}.json
9
+ // 2. This hook reads those metrics after each tool use
10
+ // 3. When remaining context drops below thresholds, it injects a warning
11
+ // as additionalContext, which the agent sees in its conversation
12
+ //
13
+ // Thresholds:
14
+ // WARNING (remaining <= 35%): Agent should wrap up current task
15
+ // CRITICAL (remaining <= 25%): Agent should stop immediately and save state
16
+ //
17
+ // Debounce: 5 tool uses between warnings to avoid spam
18
+ // Severity escalation bypasses debounce (WARNING -> CRITICAL fires immediately)
19
+
20
+ const fs = require('fs');
21
+ const os = require('os');
22
+ const path = require('path');
23
+
24
+ const WARNING_THRESHOLD = 35;
25
+ const CRITICAL_THRESHOLD = 25;
26
+ const STALE_SECONDS = 60;
27
+ const DEBOUNCE_CALLS = 5;
28
+
29
+ let input = '';
30
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
31
+ process.stdin.setEncoding('utf8');
32
+ process.stdin.on('data', chunk => input += chunk);
33
+ process.stdin.on('end', () => {
34
+ clearTimeout(stdinTimeout);
35
+ try {
36
+ const data = JSON.parse(input);
37
+ const sessionId = data.session_id;
38
+
39
+ if (!sessionId) {
40
+ process.exit(0);
41
+ }
42
+
43
+ const tmpDir = os.tmpdir();
44
+ const metricsPath = path.join(tmpDir, `claude-ctx-${sessionId}.json`);
45
+
46
+ if (!fs.existsSync(metricsPath)) {
47
+ process.exit(0);
48
+ }
49
+
50
+ const metrics = JSON.parse(fs.readFileSync(metricsPath, 'utf8'));
51
+ const now = Math.floor(Date.now() / 1000);
52
+
53
+ if (metrics.timestamp && (now - metrics.timestamp) > STALE_SECONDS) {
54
+ process.exit(0);
55
+ }
56
+
57
+ const remaining = metrics.remaining_percentage;
58
+ const usedPct = metrics.used_pct;
59
+
60
+ if (remaining > WARNING_THRESHOLD) {
61
+ process.exit(0);
62
+ }
63
+
64
+ // Debounce logic
65
+ const warnPath = path.join(tmpDir, `claude-ctx-${sessionId}-warned.json`);
66
+ let warnData = { callsSinceWarn: 0, lastLevel: null };
67
+ let firstWarn = true;
68
+
69
+ if (fs.existsSync(warnPath)) {
70
+ try {
71
+ warnData = JSON.parse(fs.readFileSync(warnPath, 'utf8'));
72
+ firstWarn = false;
73
+ } catch (e) {}
74
+ }
75
+
76
+ warnData.callsSinceWarn = (warnData.callsSinceWarn || 0) + 1;
77
+
78
+ const isCritical = remaining <= CRITICAL_THRESHOLD;
79
+ const currentLevel = isCritical ? 'critical' : 'warning';
80
+
81
+ const severityEscalated = currentLevel === 'critical' && warnData.lastLevel === 'warning';
82
+ if (!firstWarn && warnData.callsSinceWarn < DEBOUNCE_CALLS && !severityEscalated) {
83
+ fs.writeFileSync(warnPath, JSON.stringify(warnData));
84
+ process.exit(0);
85
+ }
86
+
87
+ warnData.callsSinceWarn = 0;
88
+ warnData.lastLevel = currentLevel;
89
+ fs.writeFileSync(warnPath, JSON.stringify(warnData));
90
+
91
+ // Detect if SpecFlow is active
92
+ const cwd = data.cwd || process.cwd();
93
+ const isSfActive = fs.existsSync(path.join(cwd, '.specflow', 'STATE.md'));
94
+
95
+ let message;
96
+ if (isCritical) {
97
+ message = isSfActive
98
+ ? `CONTEXT CRITICAL: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
99
+ 'Context is nearly exhausted. Do NOT start new complex work. ' +
100
+ 'Inform the user so they can run /sf:pause at the next natural stopping point.'
101
+ : `CONTEXT CRITICAL: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
102
+ 'Context is nearly exhausted. Inform the user that context is low and ask how they want to proceed.';
103
+ } else {
104
+ message = isSfActive
105
+ ? `CONTEXT WARNING: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
106
+ 'Context is getting limited. Avoid starting new complex work. ' +
107
+ 'Inform the user so they can prepare to pause.'
108
+ : `CONTEXT WARNING: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
109
+ 'Be aware that context is getting limited. Avoid unnecessary exploration or starting new complex work.';
110
+ }
111
+
112
+ process.stdout.write(JSON.stringify({
113
+ hookSpecificOutput: {
114
+ hookEventName: "PostToolUse",
115
+ additionalContext: message
116
+ }
117
+ }));
118
+ } catch (e) {
119
+ process.exit(0);
120
+ }
121
+ });
@@ -4,16 +4,20 @@
4
4
 
5
5
  const fs = require('fs');
6
6
  const path = require('path');
7
+ const os = require('os');
7
8
 
8
9
  // Read JSON from stdin (Claude Code protocol)
9
10
  let input = '';
11
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
10
12
  process.stdin.setEncoding('utf8');
11
13
  process.stdin.on('data', chunk => input += chunk);
12
14
  process.stdin.on('end', () => {
15
+ clearTimeout(stdinTimeout);
13
16
  try {
14
17
  const data = JSON.parse(input);
15
18
  const model = data.model?.display_name || 'Claude';
16
19
  const dir = data.workspace?.current_dir || process.cwd();
20
+ const session = data.session_id || '';
17
21
  const remaining = data.context_window?.remaining_percentage;
18
22
 
19
23
  // Context window display (shows USED percentage scaled to 80% limit)
@@ -25,6 +29,19 @@ process.stdin.on('end', () => {
25
29
  // Scale: 80% real usage = 100% displayed
26
30
  const used = Math.min(100, Math.round((rawUsed / 80) * 100));
27
31
 
32
+ // Write context metrics to bridge file for the context-monitor hook
33
+ if (session) {
34
+ try {
35
+ const bridgePath = path.join(os.tmpdir(), `claude-ctx-${session}.json`);
36
+ fs.writeFileSync(bridgePath, JSON.stringify({
37
+ session_id: session,
38
+ remaining_percentage: remaining,
39
+ used_pct: used,
40
+ timestamp: Math.floor(Date.now() / 1000)
41
+ }));
42
+ } catch (e) {}
43
+ }
44
+
28
45
  // Build progress bar (10 segments)
29
46
  const filled = Math.floor(used / 10);
30
47
  const bar = '█'.repeat(filled) + '░'.repeat(10 - filled);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "specflow-cc",
3
- "version": "1.13.0",
3
+ "version": "1.14.0",
4
4
  "description": "Spec-driven development system for Claude Code — quality-first workflow with explicit audit cycles",
5
5
  "bin": {
6
6
  "specflow-cc": "bin/install.js"