specweave 0.32.10 → 0.33.3
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/CLAUDE.md +162 -1
- package/dist/plugins/specweave-ado/lib/per-us-sync.d.ts +120 -0
- package/dist/plugins/specweave-ado/lib/per-us-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/per-us-sync.js +276 -0
- package/dist/plugins/specweave-ado/lib/per-us-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +4 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +13 -3
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/plugins/specweave-github/lib/per-us-sync.d.ts +97 -0
- package/dist/plugins/specweave-github/lib/per-us-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/per-us-sync.js +274 -0
- package/dist/plugins/specweave-github/lib/per-us-sync.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/per-us-sync.d.ts +113 -0
- package/dist/plugins/specweave-jira/lib/per-us-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/per-us-sync.js +254 -0
- package/dist/plugins/specweave-jira/lib/per-us-sync.js.map +1 -0
- package/dist/src/cli/add-child-pid.d.ts +11 -0
- package/dist/src/cli/add-child-pid.d.ts.map +1 -0
- package/dist/src/cli/add-child-pid.js +42 -0
- package/dist/src/cli/add-child-pid.js.map +1 -0
- package/dist/src/cli/add-child-process.d.ts +15 -0
- package/dist/src/cli/add-child-process.d.ts.map +1 -0
- package/dist/src/cli/add-child-process.js +40 -0
- package/dist/src/cli/add-child-process.js.map +1 -0
- package/dist/src/cli/check-watchdog.d.ts +15 -0
- package/dist/src/cli/check-watchdog.d.ts.map +1 -0
- package/dist/src/cli/check-watchdog.js +47 -0
- package/dist/src/cli/check-watchdog.js.map +1 -0
- package/dist/src/cli/cleanup-zombies.d.ts +14 -0
- package/dist/src/cli/cleanup-zombies.d.ts.map +1 -0
- package/dist/src/cli/cleanup-zombies.js +268 -0
- package/dist/src/cli/cleanup-zombies.js.map +1 -0
- package/dist/src/cli/find-session-by-pid.d.ts +14 -0
- package/dist/src/cli/find-session-by-pid.d.ts.map +1 -0
- package/dist/src/cli/find-session-by-pid.js +45 -0
- package/dist/src/cli/find-session-by-pid.js.map +1 -0
- package/dist/src/cli/get-stale-sessions.d.ts +17 -0
- package/dist/src/cli/get-stale-sessions.d.ts.map +1 -0
- package/dist/src/cli/get-stale-sessions.js +36 -0
- package/dist/src/cli/get-stale-sessions.js.map +1 -0
- package/dist/src/cli/register-session.d.ts +16 -0
- package/dist/src/cli/register-session.d.ts.map +1 -0
- package/dist/src/cli/register-session.js +48 -0
- package/dist/src/cli/register-session.js.map +1 -0
- package/dist/src/cli/remove-session.d.ts +11 -0
- package/dist/src/cli/remove-session.d.ts.map +1 -0
- package/dist/src/cli/remove-session.js +36 -0
- package/dist/src/cli/remove-session.js.map +1 -0
- package/dist/src/cli/update-heartbeat.d.ts +11 -0
- package/dist/src/cli/update-heartbeat.d.ts.map +1 -0
- package/dist/src/cli/update-heartbeat.js +36 -0
- package/dist/src/cli/update-heartbeat.js.map +1 -0
- package/dist/src/config/types.d.ts +1208 -203
- package/dist/src/config/types.d.ts.map +1 -1
- package/dist/src/core/background/job-manager.d.ts +16 -0
- package/dist/src/core/background/job-manager.d.ts.map +1 -1
- package/dist/src/core/background/job-manager.js +110 -15
- package/dist/src/core/background/job-manager.js.map +1 -1
- package/dist/src/core/config/config-manager.d.ts.map +1 -1
- package/dist/src/core/config/config-manager.js +58 -0
- package/dist/src/core/config/config-manager.js.map +1 -1
- package/dist/src/core/config/types.d.ts +80 -0
- package/dist/src/core/config/types.d.ts.map +1 -1
- package/dist/src/core/config/types.js.map +1 -1
- package/dist/src/core/increment/increment-utils.d.ts +26 -1
- package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
- package/dist/src/core/increment/increment-utils.js +66 -4
- package/dist/src/core/increment/increment-utils.js.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.d.ts +3 -1
- package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.js +5 -2
- package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
- package/dist/src/core/living-docs/cross-project-sync.d.ts +87 -15
- package/dist/src/core/living-docs/cross-project-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/cross-project-sync.js +147 -28
- package/dist/src/core/living-docs/cross-project-sync.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +48 -12
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.d.ts +70 -0
- package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.js +188 -0
- package/dist/src/core/living-docs/intelligent-analyzer/cache-manager.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.d.ts +33 -0
- package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.js +290 -0
- package/dist/src/core/living-docs/intelligent-analyzer/dashboard-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +114 -11
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.d.ts +23 -0
- package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.js +283 -0
- package/dist/src/core/living-docs/intelligent-analyzer/graph-visualizer.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.d.ts +44 -0
- package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.js +61 -0
- package/dist/src/core/living-docs/intelligent-analyzer/mermaid-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.d.ts +126 -0
- package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.js +378 -0
- package/dist/src/core/living-docs/intelligent-analyzer/orchestrator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +57 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.d.ts +82 -0
- package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.js +430 -0
- package/dist/src/core/living-docs/intelligent-analyzer/pattern-analyzer.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.d.ts +84 -0
- package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.js +387 -0
- package/dist/src/core/living-docs/intelligent-analyzer/repo-scanner.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/report-writer.d.ts +61 -0
- package/dist/src/core/living-docs/intelligent-analyzer/report-writer.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/report-writer.js +174 -0
- package/dist/src/core/living-docs/intelligent-analyzer/report-writer.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +26 -22
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/module-analyzer.d.ts +3 -0
- package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
- package/dist/src/core/living-docs/module-analyzer.js +40 -1
- package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
- package/dist/src/core/living-docs/types.d.ts +24 -3
- package/dist/src/core/living-docs/types.d.ts.map +1 -1
- package/dist/src/core/qa/qa-runner.js +1 -1
- package/dist/src/core/qa/qa-runner.js.map +1 -1
- package/dist/src/core/scheduler/session-sync-executor.js +1 -1
- package/dist/src/core/scheduler/session-sync-executor.js.map +1 -1
- package/dist/src/core/status-line/status-line-updater.d.ts +1 -1
- package/dist/src/core/status-line/status-line-updater.d.ts.map +1 -1
- package/dist/src/core/status-line/status-line-updater.js +4 -3
- package/dist/src/core/status-line/status-line-updater.js.map +1 -1
- package/dist/src/core/types/config.d.ts +79 -0
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/importers/jira-importer.d.ts.map +1 -1
- package/dist/src/importers/jira-importer.js +18 -9
- package/dist/src/importers/jira-importer.js.map +1 -1
- package/dist/src/init/architecture/types.d.ts +140 -33
- package/dist/src/init/architecture/types.d.ts.map +1 -1
- package/dist/src/init/compliance/types.d.ts +27 -30
- package/dist/src/init/compliance/types.d.ts.map +1 -1
- package/dist/src/init/repo/types.d.ts +34 -11
- package/dist/src/init/repo/types.d.ts.map +1 -1
- package/dist/src/init/research/src/config/types.d.ts +82 -15
- package/dist/src/init/research/src/config/types.d.ts.map +1 -1
- package/dist/src/init/research/types.d.ts +93 -38
- package/dist/src/init/research/types.d.ts.map +1 -1
- package/dist/src/init/team/types.d.ts +42 -4
- package/dist/src/init/team/types.d.ts.map +1 -1
- package/dist/src/sync/ado-reconciler.js +1 -1
- package/dist/src/sync/ado-reconciler.js.map +1 -1
- package/dist/src/sync/github-reconciler.js +1 -1
- package/dist/src/sync/github-reconciler.js.map +1 -1
- package/dist/src/sync/jira-reconciler.js +1 -1
- package/dist/src/sync/jira-reconciler.js.map +1 -1
- package/dist/src/sync/sync-coordinator.d.ts +20 -0
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
- package/dist/src/sync/sync-coordinator.js +258 -33
- package/dist/src/sync/sync-coordinator.js.map +1 -1
- package/dist/src/types/session.d.ts +65 -0
- package/dist/src/types/session.d.ts.map +1 -0
- package/dist/src/types/session.js +8 -0
- package/dist/src/types/session.js.map +1 -0
- package/dist/src/utils/lock-manager.d.ts +48 -0
- package/dist/src/utils/lock-manager.d.ts.map +1 -0
- package/dist/src/utils/lock-manager.js +195 -0
- package/dist/src/utils/lock-manager.js.map +1 -0
- package/dist/src/utils/notification-manager.d.ts +45 -0
- package/dist/src/utils/notification-manager.d.ts.map +1 -0
- package/dist/src/utils/notification-manager.js +130 -0
- package/dist/src/utils/notification-manager.js.map +1 -0
- package/dist/src/utils/platform-utils.d.ts +136 -0
- package/dist/src/utils/platform-utils.d.ts.map +1 -0
- package/dist/src/utils/platform-utils.js +366 -0
- package/dist/src/utils/platform-utils.js.map +1 -0
- package/dist/src/utils/project-resolver.d.ts +156 -0
- package/dist/src/utils/project-resolver.d.ts.map +1 -0
- package/dist/src/utils/project-resolver.js +587 -0
- package/dist/src/utils/project-resolver.js.map +1 -0
- package/dist/src/utils/session-registry.d.ts +142 -0
- package/dist/src/utils/session-registry.d.ts.map +1 -0
- package/dist/src/utils/session-registry.js +480 -0
- package/dist/src/utils/session-registry.js.map +1 -0
- package/package.json +5 -2
- package/plugins/specweave/commands/specweave-living-docs.md +42 -0
- package/plugins/specweave/hooks/hooks.json +20 -0
- package/plugins/specweave/hooks/lib/update-active-increment.sh +2 -2
- package/plugins/specweave/hooks/lib/update-status-line.sh +1 -1
- package/plugins/specweave/hooks/post-increment-status-change.sh +3 -3
- package/plugins/specweave/hooks/post-metadata-change.sh +1 -1
- package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -26
- package/plugins/specweave/hooks/universal/session-start.cmd +16 -16
- package/plugins/specweave/hooks/universal/session-start.ps1 +16 -16
- package/plugins/specweave/hooks/user-prompt-submit.sh +107 -5
- package/plugins/specweave/hooks/v2/guards/increment-root-guard.sh +61 -0
- package/plugins/specweave/hooks/v2/guards/per-us-project-validator.sh +281 -0
- package/plugins/specweave/hooks/v2/handlers/living-specs-handler.sh +29 -0
- package/plugins/specweave/hooks/v2/session-end.sh +69 -0
- package/plugins/specweave/hooks/v2/session-start.sh +81 -0
- package/plugins/specweave/lib/vendor/sync/github-reconciler.js +1 -1
- package/plugins/specweave/lib/vendor/sync/github-reconciler.js.map +1 -1
- package/plugins/specweave/scripts/heartbeat.sh +110 -0
- package/plugins/specweave/scripts/progress.js +34 -4
- package/plugins/specweave/scripts/read-jobs.sh +1 -1
- package/plugins/specweave/scripts/read-progress.sh +50 -5
- package/plugins/specweave/scripts/read-workflow.sh +1 -1
- package/plugins/specweave/scripts/session-watchdog.sh +65 -0
- package/plugins/specweave/scripts/status.js +28 -11
- package/plugins/specweave-ado/lib/per-us-sync.js +247 -0
- package/plugins/specweave-ado/lib/per-us-sync.ts +410 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +738 -0
- package/plugins/specweave-github/lib/github-client-v2.js +10 -3
- package/plugins/specweave-github/lib/github-client-v2.ts +15 -3
- package/plugins/specweave-github/lib/per-us-sync.js +241 -0
- package/plugins/specweave-github/lib/per-us-sync.ts +375 -0
- package/plugins/specweave-jira/lib/per-us-sync.js +224 -0
- package/plugins/specweave-jira/lib/per-us-sync.ts +366 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1107 -0
|
@@ -31,6 +31,7 @@ Launch the Living Docs Builder independently of `specweave init`. This is essent
|
|
|
31
31
|
| `--sources <folders>` | Additional doc folders (comma-separated): `docs/,wiki/` |
|
|
32
32
|
| `--depends-on <jobIds>` | Wait for jobs before starting (comma-separated) |
|
|
33
33
|
| `--foreground` | Run in current session instead of background |
|
|
34
|
+
| `--full` | Force full rebuild by clearing cache and checkpoints (bypasses incremental mode) |
|
|
34
35
|
|
|
35
36
|
---
|
|
36
37
|
|
|
@@ -73,6 +74,9 @@ Launch the Living Docs Builder independently of `specweave init`. This is essent
|
|
|
73
74
|
|
|
74
75
|
# AI-powered deep analysis (FREE with MAX subscription)
|
|
75
76
|
/specweave:living-docs --depth deep-native --priority core,api
|
|
77
|
+
|
|
78
|
+
# Force full rebuild (clears cache and checkpoints)
|
|
79
|
+
/specweave:living-docs --full --depth standard
|
|
76
80
|
```
|
|
77
81
|
|
|
78
82
|
---
|
|
@@ -220,6 +224,44 @@ The job will:
|
|
|
220
224
|
|
|
221
225
|
---
|
|
222
226
|
|
|
227
|
+
## Update Summary (v0.33.0+)
|
|
228
|
+
|
|
229
|
+
After completion, you'll see a detailed summary showing:
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
✅ LIVING DOCS UPDATE COMPLETE
|
|
233
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
234
|
+
|
|
235
|
+
📊 SUMMARY:
|
|
236
|
+
|
|
237
|
+
Discovery: Discovered 3 repos (2,845 files)
|
|
238
|
+
Duration: 5s
|
|
239
|
+
|
|
240
|
+
Analysis: Analyzed 3 repos
|
|
241
|
+
Duration: 127s
|
|
242
|
+
|
|
243
|
+
Synthesis: Generated 12 ADRs, 4 teams
|
|
244
|
+
Duration: 43s
|
|
245
|
+
|
|
246
|
+
Files Created: 47
|
|
247
|
+
• .specweave/docs/internal/repos/main/overview.md
|
|
248
|
+
• .specweave/docs/internal/repos/main/api-surface.md
|
|
249
|
+
• .specweave/docs/internal/architecture/system-architecture.md
|
|
250
|
+
• .specweave/docs/internal/architecture/adr/0001-typescript-migration.md
|
|
251
|
+
• .specweave/docs/internal/architecture/adr/0002-plugin-system.md
|
|
252
|
+
... and 42 more
|
|
253
|
+
|
|
254
|
+
Files Updated: 8
|
|
255
|
+
• .specweave/docs/internal/modules/auth.md
|
|
256
|
+
• .specweave/docs/internal/modules/payments.md
|
|
257
|
+
... and 6 more
|
|
258
|
+
|
|
259
|
+
Total Duration: 175s
|
|
260
|
+
Mode: INCREMENTAL (cache used)
|
|
261
|
+
|
|
262
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
263
|
+
```
|
|
264
|
+
|
|
223
265
|
## Output Files
|
|
224
266
|
|
|
225
267
|
After completion:
|
|
@@ -50,6 +50,16 @@
|
|
|
50
50
|
}
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
|
+
{
|
|
54
|
+
"matcher": "Write",
|
|
55
|
+
"matcher_content": "\\.specweave/increments/\\d{3,4}E?-[^/]+/spec\\.md",
|
|
56
|
+
"hooks": [
|
|
57
|
+
{
|
|
58
|
+
"type": "command",
|
|
59
|
+
"command": "bash -c 'W=\"${CLAUDE_PLUGIN_ROOT}/hooks/universal/fail-fast-wrapper.sh\"; S=\"${CLAUDE_PLUGIN_ROOT}/hooks/v2/guards/per-us-project-validator.sh\"; [[ -x \"$W\" ]] && exec \"$W\" \"$S\" || (cat >/dev/null && printf \"{\\\"decision\\\":\\\"allow\\\"}\")'"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
53
63
|
{
|
|
54
64
|
"matcher": "Write|Edit",
|
|
55
65
|
"matcher_content": "\\.specweave/docs/internal/specs/_features/",
|
|
@@ -69,6 +79,16 @@
|
|
|
69
79
|
"command": "bash -c 'W=\"${CLAUDE_PLUGIN_ROOT}/hooks/universal/fail-fast-wrapper.sh\"; S=\"${CLAUDE_PLUGIN_ROOT}/hooks/v2/guards/increment-duplicate-guard.sh\"; [[ -x \"$W\" ]] && exec \"$W\" \"$S\" || (cat >/dev/null && printf \"{\\\"decision\\\":\\\"allow\\\"}\")'"
|
|
70
80
|
}
|
|
71
81
|
]
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"matcher": "Write",
|
|
85
|
+
"matcher_content": "\\.specweave/increments/\\d{3,4}E?-[^/]+/[^/]+$",
|
|
86
|
+
"hooks": [
|
|
87
|
+
{
|
|
88
|
+
"type": "command",
|
|
89
|
+
"command": "bash -c 'W=\"${CLAUDE_PLUGIN_ROOT}/hooks/universal/fail-fast-wrapper.sh\"; S=\"${CLAUDE_PLUGIN_ROOT}/hooks/v2/guards/increment-root-guard.sh\"; [[ -x \"$W\" ]] && exec \"$W\" \"$S\" || (cat >/dev/null && printf \"{\\\"decision\\\":\\\"allow\\\"}\")'"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
72
92
|
}
|
|
73
93
|
],
|
|
74
94
|
"PostToolUse": [
|
|
@@ -37,7 +37,7 @@ mkdir -p "$STATE_DIR" 2>/dev/null || true
|
|
|
37
37
|
# ============================================================================
|
|
38
38
|
# SCAN ALL INCREMENTS FOR ACTIVE STATUS
|
|
39
39
|
# ============================================================================
|
|
40
|
-
# Strategy: Scan metadata.json files for status=active|planning|
|
|
40
|
+
# Strategy: Scan metadata.json files for status=active|planning|backlog|ready_for_review
|
|
41
41
|
# This matches what ActiveIncrementManager.smartUpdate() does in TypeScript
|
|
42
42
|
|
|
43
43
|
ACTIVE_IDS=()
|
|
@@ -54,7 +54,7 @@ while IFS= read -r metadata_file; do
|
|
|
54
54
|
fi
|
|
55
55
|
|
|
56
56
|
# Check if status is active-like
|
|
57
|
-
if [[ "$status" == "active" ]] || [[ "$status" == "planning" ]] || [[ "$status" == "
|
|
57
|
+
if [[ "$status" == "active" ]] || [[ "$status" == "planning" ]] || [[ "$status" == "backlog" ]] || [[ "$status" == "ready_for_review" ]]; then
|
|
58
58
|
increment_id=$(basename "$(dirname "$metadata_file")")
|
|
59
59
|
ACTIVE_IDS+=("$increment_id")
|
|
60
60
|
echo "[$(date)] update-active-increment: Found active: $increment_id (status: $status)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
@@ -129,7 +129,7 @@ while IFS= read -r metadata_file; do
|
|
|
129
129
|
fi
|
|
130
130
|
|
|
131
131
|
# Check if active
|
|
132
|
-
if [[ "$status" == "active" || "$status" == "planning" || "$status" == "
|
|
132
|
+
if [[ "$status" == "active" || "$status" == "planning" || "$status" == "backlog" || "$status" == "ready_for_review" ]]; then
|
|
133
133
|
OPEN_COUNT=$((OPEN_COUNT + 1))
|
|
134
134
|
increment_id=$(basename "$(dirname "$metadata_file")")
|
|
135
135
|
|
|
@@ -62,7 +62,7 @@ echo "[$(date)] 📊 Status changed: $NEW_STATUS" >> "$DEBUG_LOG" 2>/dev/null ||
|
|
|
62
62
|
|
|
63
63
|
# Validate status
|
|
64
64
|
case "$NEW_STATUS" in
|
|
65
|
-
paused|
|
|
65
|
+
paused|abandoned|active|planning|backlog|ready_for_review|completed)
|
|
66
66
|
;;
|
|
67
67
|
*)
|
|
68
68
|
echo "[$(date)] ⚠️ Unknown status: $NEW_STATUS (skipping sync)" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
@@ -107,11 +107,11 @@ fi
|
|
|
107
107
|
# ============================================================================
|
|
108
108
|
|
|
109
109
|
case "$NEW_STATUS" in
|
|
110
|
-
|
|
110
|
+
active|planning|backlog|ready_for_review)
|
|
111
111
|
# ========================================================================
|
|
112
112
|
# REOPEN GitHub Issues (NEW)
|
|
113
113
|
# ========================================================================
|
|
114
|
-
# When increment
|
|
114
|
+
# When increment becomes active (including resumed from pause), reopen all closed GitHub issues
|
|
115
115
|
echo "[$(date)] ▶️ Status is $NEW_STATUS - checking if issues need reopening" >> "$DEBUG_LOG" 2>/dev/null || true
|
|
116
116
|
|
|
117
117
|
if command -v node &> /dev/null; then
|
|
@@ -224,7 +224,7 @@ case "$CURRENT_STATUS" in
|
|
|
224
224
|
bash "$HOOK_DIR/lib/update-status-line.sh" --force 2>/dev/null || true
|
|
225
225
|
;;
|
|
226
226
|
|
|
227
|
-
active|planning|
|
|
227
|
+
active|planning|backlog|ready_for_review)
|
|
228
228
|
# Increment became active - MUST register in active-increment.json!
|
|
229
229
|
# CRITICAL FIX (v0.26.15): post-task-completion.sh depends on this file
|
|
230
230
|
# Without registration, ALL sync operations are skipped!
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
@echo off
|
|
2
|
-
REM hook-wrapper.cmd - Windows resilient hook launcher
|
|
3
|
-
REM Prevents crashes when dispatcher.mjs is temporarily unavailable
|
|
4
|
-
|
|
5
|
-
setlocal enabledelayedexpansion
|
|
6
|
-
|
|
7
|
-
set "HOOK_TYPE=%~1"
|
|
8
|
-
if "%HOOK_TYPE%"=="" set "HOOK_TYPE=unknown"
|
|
9
|
-
|
|
10
|
-
set "SCRIPT_DIR=%~dp0"
|
|
11
|
-
set "DISPATCHER=%SCRIPT_DIR%dispatcher.mjs"
|
|
12
|
-
|
|
13
|
-
REM Check if dispatcher exists
|
|
14
|
-
if not exist "%DISPATCHER%" (
|
|
15
|
-
echo {"continue":true,"systemMessage":"Hook skipped: dispatcher.mjs not found"}
|
|
16
|
-
exit /b 0
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
REM Run dispatcher with error suppression
|
|
20
|
-
node "%DISPATCHER%" "%HOOK_TYPE%" 2>nul
|
|
21
|
-
if errorlevel 1 (
|
|
22
|
-
echo {"continue":true,"systemMessage":"Hook error, continuing"}
|
|
23
|
-
exit /b 0
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
exit /b 0
|
|
1
|
+
@echo off
|
|
2
|
+
REM hook-wrapper.cmd - Windows resilient hook launcher
|
|
3
|
+
REM Prevents crashes when dispatcher.mjs is temporarily unavailable
|
|
4
|
+
|
|
5
|
+
setlocal enabledelayedexpansion
|
|
6
|
+
|
|
7
|
+
set "HOOK_TYPE=%~1"
|
|
8
|
+
if "%HOOK_TYPE%"=="" set "HOOK_TYPE=unknown"
|
|
9
|
+
|
|
10
|
+
set "SCRIPT_DIR=%~dp0"
|
|
11
|
+
set "DISPATCHER=%SCRIPT_DIR%dispatcher.mjs"
|
|
12
|
+
|
|
13
|
+
REM Check if dispatcher exists
|
|
14
|
+
if not exist "%DISPATCHER%" (
|
|
15
|
+
echo {"continue":true,"systemMessage":"Hook skipped: dispatcher.mjs not found"}
|
|
16
|
+
exit /b 0
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
REM Run dispatcher with error suppression
|
|
20
|
+
node "%DISPATCHER%" "%HOOK_TYPE%" 2>nul
|
|
21
|
+
if errorlevel 1 (
|
|
22
|
+
echo {"continue":true,"systemMessage":"Hook error, continuing"}
|
|
23
|
+
exit /b 0
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
exit /b 0
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
@echo off
|
|
2
|
-
:: Universal Session Start Hook for Windows
|
|
3
|
-
:: Calls the Node.js dispatcher
|
|
4
|
-
|
|
5
|
-
:: Find node.exe
|
|
6
|
-
where node >nul 2>&1
|
|
7
|
-
if %ERRORLEVEL% neq 0 (
|
|
8
|
-
echo {"continue": true, "error": "Node.js not found"}
|
|
9
|
-
exit /b 0
|
|
10
|
-
)
|
|
11
|
-
|
|
12
|
-
:: Get the directory of this script
|
|
13
|
-
set "SCRIPT_DIR=%~dp0"
|
|
14
|
-
|
|
15
|
-
:: Run the dispatcher
|
|
16
|
-
node "%SCRIPT_DIR%dispatcher.mjs" session-start
|
|
1
|
+
@echo off
|
|
2
|
+
:: Universal Session Start Hook for Windows
|
|
3
|
+
:: Calls the Node.js dispatcher
|
|
4
|
+
|
|
5
|
+
:: Find node.exe
|
|
6
|
+
where node >nul 2>&1
|
|
7
|
+
if %ERRORLEVEL% neq 0 (
|
|
8
|
+
echo {"continue": true, "error": "Node.js not found"}
|
|
9
|
+
exit /b 0
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
:: Get the directory of this script
|
|
13
|
+
set "SCRIPT_DIR=%~dp0"
|
|
14
|
+
|
|
15
|
+
:: Run the dispatcher
|
|
16
|
+
node "%SCRIPT_DIR%dispatcher.mjs" session-start
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
# Universal Session Start Hook for Windows PowerShell
|
|
2
|
-
# Calls the Node.js dispatcher for cross-platform compatibility
|
|
3
|
-
|
|
4
|
-
# Find node.exe
|
|
5
|
-
$nodePath = Get-Command node -ErrorAction SilentlyContinue
|
|
6
|
-
|
|
7
|
-
if (-not $nodePath) {
|
|
8
|
-
Write-Host '{"continue": true, "error": "Node.js not found"}'
|
|
9
|
-
exit 0
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
# Get script directory
|
|
13
|
-
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
14
|
-
|
|
15
|
-
# Run the dispatcher
|
|
16
|
-
& node "$scriptDir\dispatcher.mjs" session-start
|
|
1
|
+
# Universal Session Start Hook for Windows PowerShell
|
|
2
|
+
# Calls the Node.js dispatcher for cross-platform compatibility
|
|
3
|
+
|
|
4
|
+
# Find node.exe
|
|
5
|
+
$nodePath = Get-Command node -ErrorAction SilentlyContinue
|
|
6
|
+
|
|
7
|
+
if (-not $nodePath) {
|
|
8
|
+
Write-Host '{"continue": true, "error": "Node.js not found"}'
|
|
9
|
+
exit 0
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
# Get script directory
|
|
13
|
+
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
14
|
+
|
|
15
|
+
# Run the dispatcher
|
|
16
|
+
& node "$scriptDir\dispatcher.mjs" session-start
|
|
@@ -151,7 +151,7 @@ if echo "$PROMPT" | grep -qE "^/specweave:do($| )"; then
|
|
|
151
151
|
else
|
|
152
152
|
status=$(grep -oP '"status"\s*:\s*"\K[^"]*' "$meta" 2>/dev/null || echo "unknown")
|
|
153
153
|
fi
|
|
154
|
-
if [[ "$status" == "active" || "$status" == "
|
|
154
|
+
if [[ "$status" == "active" || "$status" == "planning" || "$status" == "backlog" || "$status" == "ready_for_review" ]]; then
|
|
155
155
|
DO_INCREMENT_ID=$(basename "$(dirname "$meta")")
|
|
156
156
|
break
|
|
157
157
|
fi
|
|
@@ -191,7 +191,7 @@ if [[ -d "$SPECWEAVE_DIR/increments" ]]; then
|
|
|
191
191
|
inc_type=$(grep -oP '"type"\s*:\s*"\K[^"]*' "$metadata_file" 2>/dev/null || echo "feature")
|
|
192
192
|
fi
|
|
193
193
|
|
|
194
|
-
if [[ "$status" == "active" || "$status" == "planning" || "$status" == "
|
|
194
|
+
if [[ "$status" == "active" || "$status" == "planning" || "$status" == "backlog" || "$status" == "ready_for_review" ]]; then
|
|
195
195
|
inc_id=$(basename "$(dirname "$metadata_file")")
|
|
196
196
|
ACTIVE_COUNT=$((ACTIVE_COUNT + 1))
|
|
197
197
|
ACTIVE_LIST="${ACTIVE_LIST} - $inc_id [$inc_type]\n"
|
|
@@ -204,7 +204,91 @@ fi
|
|
|
204
204
|
# DISCIPLINE VALIDATION: Warn about WIP limits (configurable, not hard block!)
|
|
205
205
|
# ==============================================================================
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
# ==============================================================================
|
|
208
|
+
# PROJECT CONTEXT + WIP LIMITS FOR /specweave:increment (v0.34.0)
|
|
209
|
+
# ==============================================================================
|
|
210
|
+
# CRITICAL: Inject project/board context BEFORE Claude generates spec.md
|
|
211
|
+
# This ensures Claude knows available projects and uses correct IDs
|
|
212
|
+
# ALSO: Check WIP limits in same block to avoid duplicate command detection
|
|
213
|
+
|
|
214
|
+
if echo "$PROMPT" | grep -qE "^/specweave:increment"; then
|
|
215
|
+
# Get project context (uses specweave CLI if available)
|
|
216
|
+
PROJECT_CONTEXT=""
|
|
217
|
+
|
|
218
|
+
if command -v specweave >/dev/null 2>&1; then
|
|
219
|
+
# Use CLI for accurate project/board detection
|
|
220
|
+
CONTEXT_JSON=$(specweave context projects 2>/dev/null || echo '{}')
|
|
221
|
+
|
|
222
|
+
# Validate JSON before parsing (defensive coding)
|
|
223
|
+
if [[ -n "$CONTEXT_JSON" ]] && [[ "$CONTEXT_JSON" != "{}" ]]; then
|
|
224
|
+
if command -v jq >/dev/null 2>&1; then
|
|
225
|
+
# Verify JSON is parseable before extracting fields
|
|
226
|
+
if ! echo "$CONTEXT_JSON" | jq empty 2>/dev/null; then
|
|
227
|
+
CONTEXT_JSON='{}' # Invalid JSON - reset to empty
|
|
228
|
+
fi
|
|
229
|
+
fi
|
|
230
|
+
fi
|
|
231
|
+
|
|
232
|
+
if [[ -n "$CONTEXT_JSON" ]] && [[ "$CONTEXT_JSON" != "{}" ]]; then
|
|
233
|
+
# Parse JSON with jq
|
|
234
|
+
if command -v jq >/dev/null 2>&1; then
|
|
235
|
+
LEVEL=$(echo "$CONTEXT_JSON" | jq -r '.level // 1')
|
|
236
|
+
PROJECTS=$(echo "$CONTEXT_JSON" | jq -r '.projects | map(.id) | join(", ")' 2>/dev/null || echo "")
|
|
237
|
+
|
|
238
|
+
if [[ "$LEVEL" == "2" ]]; then
|
|
239
|
+
# 2-level structure: include boards
|
|
240
|
+
BOARDS_JSON=$(echo "$CONTEXT_JSON" | jq -r '.boardsByProject // {}' 2>/dev/null)
|
|
241
|
+
if [[ -n "$BOARDS_JSON" ]] && [[ "$BOARDS_JSON" != "{}" ]]; then
|
|
242
|
+
PROJECT_CONTEXT="\\n\\n📦 PROJECT CONTEXT (2-LEVEL STRUCTURE)\\n\\n"
|
|
243
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}⚠️ MANDATORY: Each User Story MUST have both:\\n"
|
|
244
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT} - **Project**: <project_id>\\n"
|
|
245
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT} - **Board**: <board_id>\\n\\n"
|
|
246
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}Available projects: ${PROJECTS}\\n"
|
|
247
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}Boards by project:\\n"
|
|
248
|
+
|
|
249
|
+
# Format boards
|
|
250
|
+
for proj in $(echo "$CONTEXT_JSON" | jq -r '.projects[].id' 2>/dev/null); do
|
|
251
|
+
PROJ_BOARDS=$(echo "$CONTEXT_JSON" | jq -r ".boardsByProject[\"$proj\"] | map(.id) | join(\", \")" 2>/dev/null || echo "")
|
|
252
|
+
[[ -n "$PROJ_BOARDS" ]] && PROJECT_CONTEXT="${PROJECT_CONTEXT} - ${proj}: ${PROJ_BOARDS}\\n"
|
|
253
|
+
done
|
|
254
|
+
|
|
255
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}\\n❌ FORBIDDEN: Comma-separated values (e.g., **Project**: fe, be)\\n"
|
|
256
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}✅ REQUIRED: One project + one board per User Story"
|
|
257
|
+
fi
|
|
258
|
+
elif [[ -n "$PROJECTS" ]]; then
|
|
259
|
+
# 1-level structure: projects only
|
|
260
|
+
PROJECT_COUNT=$(echo "$CONTEXT_JSON" | jq '.projects | length' 2>/dev/null || echo "0")
|
|
261
|
+
|
|
262
|
+
if [[ "$PROJECT_COUNT" -gt 1 ]]; then
|
|
263
|
+
PROJECT_CONTEXT="\\n\\n📦 PROJECT CONTEXT (MULTI-PROJECT)\\n\\n"
|
|
264
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}⚠️ MANDATORY: Each User Story MUST have:\\n"
|
|
265
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT} - **Project**: <project_id>\\n\\n"
|
|
266
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}Available projects: ${PROJECTS}\\n"
|
|
267
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}\\n❌ FORBIDDEN: Comma-separated values\\n"
|
|
268
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}✅ REQUIRED: One project per User Story"
|
|
269
|
+
elif [[ "$PROJECT_COUNT" -eq 1 ]]; then
|
|
270
|
+
# Single project: auto-select
|
|
271
|
+
SINGLE_PROJECT=$(echo "$CONTEXT_JSON" | jq -r '.projects[0].id' 2>/dev/null)
|
|
272
|
+
PROJECT_CONTEXT="\\n\\n📦 PROJECT CONTEXT\\n"
|
|
273
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}Single project detected: ${SINGLE_PROJECT} (auto-selected)"
|
|
274
|
+
fi
|
|
275
|
+
fi
|
|
276
|
+
fi
|
|
277
|
+
fi
|
|
278
|
+
else
|
|
279
|
+
# Fallback: Check for multi-project folders
|
|
280
|
+
if [[ -d "$SPECWEAVE_DIR/docs/internal/specs" ]]; then
|
|
281
|
+
PROJ_COUNT=$(find "$SPECWEAVE_DIR/docs/internal/specs" -maxdepth 1 -type d | wc -l)
|
|
282
|
+
if [[ "$PROJ_COUNT" -gt 2 ]]; then
|
|
283
|
+
PROJ_LIST=$(ls -1 "$SPECWEAVE_DIR/docs/internal/specs" 2>/dev/null | grep -v "_" | tr '\n' ', ' | sed 's/,$//')
|
|
284
|
+
PROJECT_CONTEXT="\\n\\n📦 PROJECT CONTEXT (MULTI-PROJECT)\\n"
|
|
285
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}⚠️ MANDATORY: Each User Story MUST have **Project**: field\\n"
|
|
286
|
+
PROJECT_CONTEXT="${PROJECT_CONTEXT}Available folders: ${PROJ_LIST}"
|
|
287
|
+
fi
|
|
288
|
+
fi
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
# WIP LIMITS CHECK (inside same block - no duplicate command detection)
|
|
208
292
|
# Read limits from config.json (respect user's settings!)
|
|
209
293
|
CONFIG_FILE="$SPECWEAVE_DIR/config.json"
|
|
210
294
|
SOFT_LIMIT=1
|
|
@@ -226,13 +310,31 @@ if echo "$PROMPT" | grep -q "/specweave:increment"; then
|
|
|
226
310
|
|
|
227
311
|
# Above hard cap: strong warning but NOT a block (user decides!)
|
|
228
312
|
if [[ "$ACTIVE_COUNT" -ge "$HARD_CAP" ]]; then
|
|
229
|
-
|
|
313
|
+
WIP_MSG="⚠️ WIP LIMIT EXCEEDED (${ACTIVE_COUNT}/${HARD_CAP})\\n\\nYou have ${ACTIVE_COUNT} active increments (configured maximum: ${HARD_CAP})\\n\\nActive increments:\\n${ACTIVE_LIST}\\n\\n🧠 Research shows 3+ concurrent tasks = 40%% slower + more bugs\\n\\n💡 Options:\\n 1️⃣ Complete an increment: /specweave:done <id>\\n 2️⃣ Pause an increment: /specweave:pause <id>\\n 3️⃣ Increase limit: Edit .specweave/config.json limits.hardCap\\n 4️⃣ Continue anyway (not recommended)\\n\\n📝 To proceed anyway, just confirm your intent."
|
|
314
|
+
# Prepend project context if available
|
|
315
|
+
if [[ -n "$PROJECT_CONTEXT" ]]; then
|
|
316
|
+
printf '{"decision":"approve","systemMessage":"%s%s"}\n' "$PROJECT_CONTEXT" "$WIP_MSG"
|
|
317
|
+
else
|
|
318
|
+
printf '{"decision":"approve","systemMessage":"%s"}\n' "$WIP_MSG"
|
|
319
|
+
fi
|
|
230
320
|
exit 0
|
|
231
321
|
fi
|
|
232
322
|
|
|
233
323
|
# At soft limit: mild warning, approve
|
|
234
324
|
if [[ "$ACTIVE_COUNT" -ge "$SOFT_LIMIT" ]]; then
|
|
235
|
-
|
|
325
|
+
WIP_MSG="⚠️ WIP LIMIT REACHED (${ACTIVE_COUNT}/${SOFT_LIMIT})\\n\\nYou have ${ACTIVE_COUNT} active increment(s) (recommended limit: ${SOFT_LIMIT})\\n\\nActive increments:\\n${ACTIVE_LIST}\\n\\n🧠 Focus Principle: Fewer active increments = maximum productivity\\n\\n💡 Consider:\\n 1️⃣ Complete current work (recommended)\\n 2️⃣ Pause current work (/specweave:pause)\\n 3️⃣ Continue anyway\\n\\n⚠️ Emergency hotfix/bug? Use --type=hotfix or --type=bug"
|
|
326
|
+
# Prepend project context if available
|
|
327
|
+
if [[ -n "$PROJECT_CONTEXT" ]]; then
|
|
328
|
+
printf '{"decision":"approve","systemMessage":"%s%s"}\n' "$PROJECT_CONTEXT" "$WIP_MSG"
|
|
329
|
+
else
|
|
330
|
+
printf '{"decision":"approve","systemMessage":"%s"}\n' "$WIP_MSG"
|
|
331
|
+
fi
|
|
332
|
+
exit 0
|
|
333
|
+
fi
|
|
334
|
+
|
|
335
|
+
# No WIP limit warning, but we may have project context to inject
|
|
336
|
+
if [[ -n "$PROJECT_CONTEXT" ]]; then
|
|
337
|
+
printf '{"decision":"approve","systemMessage":"%s"}\n' "$PROJECT_CONTEXT"
|
|
236
338
|
exit 0
|
|
237
339
|
fi
|
|
238
340
|
fi
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# increment-root-guard.sh - Block files at increment root (except allowed)
|
|
3
|
+
#
|
|
4
|
+
# ROOT CAUSE: Agents sometimes create files like COMPLETION_REPORT.md,
|
|
5
|
+
# COMPLETION_SUMMARY.md, or other .md files at increment root instead of
|
|
6
|
+
# placing them in appropriate subfolders (reports/, scripts/, logs/, etc.)
|
|
7
|
+
#
|
|
8
|
+
# SOLUTION: Block Write operations to increment root for non-standard files.
|
|
9
|
+
# Only allow: metadata.json, spec.md, plan.md, tasks.md
|
|
10
|
+
# Everything else MUST go in subfolders: reports/, scripts/, logs/, backups/, docs/
|
|
11
|
+
#
|
|
12
|
+
# PreToolUse hook for Write command - exit 0 allows, exit 2 blocks
|
|
13
|
+
#
|
|
14
|
+
# v0.33.0 - Initial implementation based on bug analysis from 2025-12-09
|
|
15
|
+
|
|
16
|
+
set +e
|
|
17
|
+
|
|
18
|
+
[[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
|
|
19
|
+
|
|
20
|
+
# Read stdin for tool input
|
|
21
|
+
INPUT=$(cat)
|
|
22
|
+
|
|
23
|
+
# Extract the file_path being written
|
|
24
|
+
if command -v jq &> /dev/null; then
|
|
25
|
+
FILE_PATH=$(echo "$INPUT" | jq -r '.file_path // empty' 2>/dev/null)
|
|
26
|
+
else
|
|
27
|
+
FILE_PATH=$(echo "$INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"file_path"[[:space:]]*:[[:space:]]*"\(.*\)"/\1/')
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
# If no file_path found, allow (safety)
|
|
31
|
+
if [[ -z "$FILE_PATH" ]]; then
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
# === PATTERN DETECTION ===
|
|
36
|
+
# Block files at increment root that should be in subfolders
|
|
37
|
+
|
|
38
|
+
# Pattern: .specweave/increments/####-name/FILE.md (at root, not in subfolder)
|
|
39
|
+
# Allowed at root: metadata.json, spec.md, plan.md, tasks.md
|
|
40
|
+
if [[ "$FILE_PATH" =~ \.specweave/increments/[0-9]{3,4}E?-[^/]+/([^/]+)$ ]]; then
|
|
41
|
+
FILENAME="${BASH_REMATCH[1]}"
|
|
42
|
+
|
|
43
|
+
# Allow standard increment files at root
|
|
44
|
+
if [[ "$FILENAME" =~ ^(metadata\.json|spec\.md|plan\.md|tasks\.md)$ ]]; then
|
|
45
|
+
printf '{"decision":"allow"}'
|
|
46
|
+
exit 0
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# Block everything else at increment root
|
|
50
|
+
cat << EOF
|
|
51
|
+
{
|
|
52
|
+
"decision": "block",
|
|
53
|
+
"reason": "🚫 BLOCKED: File '$FILENAME' should be in a subfolder, not at increment root\n\n⚠️ CLAUDE.md Folder Structure Rule:\n Inside increment folders - ONLY at root: spec.md, plan.md, tasks.md, metadata.json\n Everything else → subfolders: reports/, scripts/, logs/, backups/, docs/\n\n📋 CORRECT structure:\n .specweave/increments/####-name/reports/COMPLETION_REPORT.md ✅\n .specweave/increments/####-name/reports/COMPLETION_SUMMARY.md ✅\n .specweave/increments/####-name/scripts/analyze.sh ✅\n\n❌ WRONG structure:\n .specweave/increments/####-name/COMPLETION_REPORT.md ❌\n .specweave/increments/####-name/COMPLETION_SUMMARY.md ❌\n\n🔧 To fix: Create file in reports/ subfolder instead.\nUse: Write({ file_path: \".specweave/increments/####-name/reports/$FILENAME\", ... })\n\nSee: CLAUDE.md section 'Folder Structure'"
|
|
54
|
+
}
|
|
55
|
+
EOF
|
|
56
|
+
exit 2
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Allow all other writes (files in subfolders, or outside increments)
|
|
60
|
+
printf '{"decision":"allow"}'
|
|
61
|
+
exit 0
|