specweave 0.32.0 → 0.32.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.
Files changed (347) hide show
  1. package/CLAUDE.md +215 -2
  2. package/README.md +22 -0
  3. package/bin/specweave.js +52 -1
  4. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts +100 -0
  5. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts.map +1 -0
  6. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js +291 -0
  7. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js.map +1 -0
  8. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts +103 -0
  9. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts.map +1 -0
  10. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js +310 -0
  11. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js.map +1 -0
  12. package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts +126 -0
  13. package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts.map +1 -0
  14. package/dist/plugins/specweave-jira/lib/jira-permission-gate.js +207 -0
  15. package/dist/plugins/specweave-jira/lib/jira-permission-gate.js.map +1 -0
  16. package/dist/src/adapters/codex/README.md +1 -1
  17. package/dist/src/adapters/codex/adapter.js +1 -1
  18. package/dist/src/cli/commands/archive.d.ts +2 -0
  19. package/dist/src/cli/commands/archive.d.ts.map +1 -1
  20. package/dist/src/cli/commands/archive.js +33 -0
  21. package/dist/src/cli/commands/archive.js.map +1 -1
  22. package/dist/src/cli/commands/cache.d.ts +17 -0
  23. package/dist/src/cli/commands/cache.d.ts.map +1 -0
  24. package/dist/src/cli/commands/cache.js +126 -0
  25. package/dist/src/cli/commands/cache.js.map +1 -0
  26. package/dist/src/cli/commands/context.d.ts +92 -0
  27. package/dist/src/cli/commands/context.d.ts.map +1 -0
  28. package/dist/src/cli/commands/context.js +205 -0
  29. package/dist/src/cli/commands/context.js.map +1 -0
  30. package/dist/src/cli/commands/init.d.ts.map +1 -1
  31. package/dist/src/cli/commands/init.js +112 -70
  32. package/dist/src/cli/commands/init.js.map +1 -1
  33. package/dist/src/cli/commands/plan/increment-detector.js +2 -2
  34. package/dist/src/cli/commands/plan/increment-detector.js.map +1 -1
  35. package/dist/src/cli/commands/sync-spec-commits.js +1 -1
  36. package/dist/src/cli/commands/sync-spec-commits.js.map +1 -1
  37. package/dist/src/cli/commands/sync-specs.js +2 -2
  38. package/dist/src/cli/commands/sync-specs.js.map +1 -1
  39. package/dist/src/cli/helpers/github/increment-profile-selector.js +1 -1
  40. package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
  41. package/dist/src/cli/helpers/init/external-import.d.ts +3 -0
  42. package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
  43. package/dist/src/cli/helpers/init/external-import.js +17 -4
  44. package/dist/src/cli/helpers/init/external-import.js.map +1 -1
  45. package/dist/src/cli/helpers/init/index.d.ts +1 -0
  46. package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
  47. package/dist/src/cli/helpers/init/index.js +2 -0
  48. package/dist/src/cli/helpers/init/index.js.map +1 -1
  49. package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts +70 -0
  50. package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts.map +1 -1
  51. package/dist/src/cli/helpers/init/jira-ado-auto-detect.js +214 -4
  52. package/dist/src/cli/helpers/init/jira-ado-auto-detect.js.map +1 -1
  53. package/dist/src/cli/helpers/init/living-docs-preflight.d.ts +4 -0
  54. package/dist/src/cli/helpers/init/living-docs-preflight.d.ts.map +1 -1
  55. package/dist/src/cli/helpers/init/living-docs-preflight.js +34 -3
  56. package/dist/src/cli/helpers/init/living-docs-preflight.js.map +1 -1
  57. package/dist/src/cli/helpers/init/testing-config.d.ts +3 -0
  58. package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -1
  59. package/dist/src/cli/helpers/init/testing-config.js +9 -2
  60. package/dist/src/cli/helpers/init/testing-config.js.map +1 -1
  61. package/dist/src/cli/helpers/init/translation-config.d.ts +3 -0
  62. package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -1
  63. package/dist/src/cli/helpers/init/translation-config.js +21 -4
  64. package/dist/src/cli/helpers/init/translation-config.js.map +1 -1
  65. package/dist/src/cli/helpers/init/wizard-navigation.d.ts +45 -0
  66. package/dist/src/cli/helpers/init/wizard-navigation.d.ts.map +1 -0
  67. package/dist/src/cli/helpers/init/wizard-navigation.js +97 -0
  68. package/dist/src/cli/helpers/init/wizard-navigation.js.map +1 -0
  69. package/dist/src/cli/workers/living-docs-worker.js +66 -1
  70. package/dist/src/cli/workers/living-docs-worker.js.map +1 -1
  71. package/dist/src/config/types.d.ts +203 -1208
  72. package/dist/src/config/types.d.ts.map +1 -1
  73. package/dist/src/core/discrepancy/increment-generator.d.ts.map +1 -1
  74. package/dist/src/core/discrepancy/increment-generator.js +5 -2
  75. package/dist/src/core/discrepancy/increment-generator.js.map +1 -1
  76. package/dist/src/core/increment/duplicate-detector.js +2 -2
  77. package/dist/src/core/increment/duplicate-detector.js.map +1 -1
  78. package/dist/src/core/increment/increment-archiver.d.ts +49 -4
  79. package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
  80. package/dist/src/core/increment/increment-archiver.js +123 -22
  81. package/dist/src/core/increment/increment-archiver.js.map +1 -1
  82. package/dist/src/core/increment/increment-status.js +2 -2
  83. package/dist/src/core/increment/increment-status.js.map +1 -1
  84. package/dist/src/core/increment/increment-utils.d.ts +150 -0
  85. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  86. package/dist/src/core/increment/increment-utils.js +216 -4
  87. package/dist/src/core/increment/increment-utils.js.map +1 -1
  88. package/dist/src/core/increment/metadata-validator.js +1 -1
  89. package/dist/src/core/increment/metadata-validator.js.map +1 -1
  90. package/dist/src/core/living-docs/feature-archiver.d.ts +4 -0
  91. package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
  92. package/dist/src/core/living-docs/feature-archiver.js +32 -10
  93. package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
  94. package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
  95. package/dist/src/core/living-docs/feature-id-manager.js +8 -4
  96. package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
  97. package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts +38 -0
  98. package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts.map +1 -0
  99. package/dist/src/core/living-docs/governance/ecosystem-detector.js +325 -0
  100. package/dist/src/core/living-docs/governance/ecosystem-detector.js.map +1 -0
  101. package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts +74 -0
  102. package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts.map +1 -0
  103. package/dist/src/core/living-docs/governance/frontend-standards-parser.js +366 -0
  104. package/dist/src/core/living-docs/governance/frontend-standards-parser.js.map +1 -0
  105. package/dist/src/core/living-docs/governance/go-standards-parser.d.ts +64 -0
  106. package/dist/src/core/living-docs/governance/go-standards-parser.d.ts.map +1 -0
  107. package/dist/src/core/living-docs/governance/go-standards-parser.js +229 -0
  108. package/dist/src/core/living-docs/governance/go-standards-parser.js.map +1 -0
  109. package/dist/src/core/living-docs/governance/index.d.ts +50 -0
  110. package/dist/src/core/living-docs/governance/index.d.ts.map +1 -0
  111. package/dist/src/core/living-docs/governance/index.js +56 -0
  112. package/dist/src/core/living-docs/governance/index.js.map +1 -0
  113. package/dist/src/core/living-docs/governance/java-standards-parser.d.ts +89 -0
  114. package/dist/src/core/living-docs/governance/java-standards-parser.d.ts.map +1 -0
  115. package/dist/src/core/living-docs/governance/java-standards-parser.js +356 -0
  116. package/dist/src/core/living-docs/governance/java-standards-parser.js.map +1 -0
  117. package/dist/src/core/living-docs/governance/python-standards-parser.d.ts +83 -0
  118. package/dist/src/core/living-docs/governance/python-standards-parser.d.ts.map +1 -0
  119. package/dist/src/core/living-docs/governance/python-standards-parser.js +347 -0
  120. package/dist/src/core/living-docs/governance/python-standards-parser.js.map +1 -0
  121. package/dist/src/core/living-docs/governance/standards-generator.d.ts +38 -0
  122. package/dist/src/core/living-docs/governance/standards-generator.d.ts.map +1 -0
  123. package/dist/src/core/living-docs/governance/standards-generator.js +476 -0
  124. package/dist/src/core/living-docs/governance/standards-generator.js.map +1 -0
  125. package/dist/src/core/living-docs/hierarchy-mapper.js +3 -3
  126. package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
  127. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts +18 -0
  128. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -0
  129. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +299 -0
  130. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -0
  131. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts +15 -0
  132. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -0
  133. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +138 -0
  134. package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -0
  135. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts +24 -0
  136. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts.map +1 -0
  137. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js +198 -0
  138. package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js.map +1 -0
  139. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts +17 -0
  140. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts.map +1 -0
  141. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js +241 -0
  142. package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js.map +1 -0
  143. package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts +28 -0
  144. package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts.map +1 -0
  145. package/dist/src/core/living-docs/intelligent-analyzer/index.js +197 -0
  146. package/dist/src/core/living-docs/intelligent-analyzer/index.js.map +1 -0
  147. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +22 -0
  148. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -0
  149. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +482 -0
  150. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -0
  151. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts +42 -0
  152. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts.map +1 -0
  153. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js +343 -0
  154. package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js.map +1 -0
  155. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +190 -0
  156. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -0
  157. package/dist/src/core/living-docs/intelligent-analyzer/types.js +7 -0
  158. package/dist/src/core/living-docs/intelligent-analyzer/types.js.map +1 -0
  159. package/dist/src/core/living-docs/living-docs-sync.d.ts +11 -3
  160. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  161. package/dist/src/core/living-docs/living-docs-sync.js +53 -10
  162. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  163. package/dist/src/core/living-docs/module-analyzer.d.ts +22 -0
  164. package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
  165. package/dist/src/core/living-docs/module-analyzer.js +123 -19
  166. package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
  167. package/dist/src/core/llm/provider-factory.js +2 -2
  168. package/dist/src/core/llm/provider-factory.js.map +1 -1
  169. package/dist/src/core/llm/providers/anthropic-provider.js +1 -1
  170. package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
  171. package/dist/src/core/llm/providers/bedrock-provider.js +8 -4
  172. package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
  173. package/dist/src/core/sync/spec-increment-mapper.js +3 -3
  174. package/dist/src/core/sync/spec-increment-mapper.js.map +1 -1
  175. package/dist/src/importers/item-converter.d.ts +25 -0
  176. package/dist/src/importers/item-converter.d.ts.map +1 -1
  177. package/dist/src/importers/item-converter.js +135 -5
  178. package/dist/src/importers/item-converter.js.map +1 -1
  179. package/dist/src/importers/jira-importer.d.ts +14 -0
  180. package/dist/src/importers/jira-importer.d.ts.map +1 -1
  181. package/dist/src/importers/jira-importer.js +75 -0
  182. package/dist/src/importers/jira-importer.js.map +1 -1
  183. package/dist/src/init/architecture/types.d.ts +33 -140
  184. package/dist/src/init/architecture/types.d.ts.map +1 -1
  185. package/dist/src/init/compliance/types.d.ts +30 -27
  186. package/dist/src/init/compliance/types.d.ts.map +1 -1
  187. package/dist/src/init/repo/types.d.ts +11 -34
  188. package/dist/src/init/repo/types.d.ts.map +1 -1
  189. package/dist/src/init/research/src/config/types.d.ts +15 -82
  190. package/dist/src/init/research/src/config/types.d.ts.map +1 -1
  191. package/dist/src/init/research/types.d.ts +38 -93
  192. package/dist/src/init/research/types.d.ts.map +1 -1
  193. package/dist/src/init/team/types.d.ts +4 -42
  194. package/dist/src/init/team/types.d.ts.map +1 -1
  195. package/dist/src/integrations/jira/jira-token-provider.d.ts +93 -0
  196. package/dist/src/integrations/jira/jira-token-provider.d.ts.map +1 -0
  197. package/dist/src/integrations/jira/jira-token-provider.js +160 -0
  198. package/dist/src/integrations/jira/jira-token-provider.js.map +1 -0
  199. package/dist/src/sync/ado-reconciler.d.ts +92 -0
  200. package/dist/src/sync/ado-reconciler.d.ts.map +1 -0
  201. package/dist/src/sync/ado-reconciler.js +335 -0
  202. package/dist/src/sync/ado-reconciler.js.map +1 -0
  203. package/dist/src/sync/jira-reconciler.d.ts +106 -0
  204. package/dist/src/sync/jira-reconciler.d.ts.map +1 -0
  205. package/dist/src/sync/jira-reconciler.js +405 -0
  206. package/dist/src/sync/jira-reconciler.js.map +1 -0
  207. package/dist/src/types/dashboard-cache.d.ts +181 -0
  208. package/dist/src/types/dashboard-cache.d.ts.map +1 -0
  209. package/dist/src/types/dashboard-cache.js +65 -0
  210. package/dist/src/types/dashboard-cache.js.map +1 -0
  211. package/dist/src/types/model-selection.d.ts +6 -4
  212. package/dist/src/types/model-selection.d.ts.map +1 -1
  213. package/dist/src/types/model-selection.js +3 -1
  214. package/dist/src/types/model-selection.js.map +1 -1
  215. package/dist/src/utils/docs-validator.d.ts +131 -0
  216. package/dist/src/utils/docs-validator.d.ts.map +1 -0
  217. package/dist/src/utils/docs-validator.js +529 -0
  218. package/dist/src/utils/docs-validator.js.map +1 -0
  219. package/dist/src/utils/external-tool-drift-detector.d.ts +1 -1
  220. package/dist/src/utils/external-tool-drift-detector.d.ts.map +1 -1
  221. package/dist/src/utils/external-tool-drift-detector.js +5 -4
  222. package/dist/src/utils/external-tool-drift-detector.js.map +1 -1
  223. package/dist/src/utils/feature-id-collision.js +1 -1
  224. package/dist/src/utils/feature-id-collision.js.map +1 -1
  225. package/dist/src/utils/feature-id-derivation.d.ts +8 -3
  226. package/dist/src/utils/feature-id-derivation.d.ts.map +1 -1
  227. package/dist/src/utils/feature-id-derivation.js +14 -6
  228. package/dist/src/utils/feature-id-derivation.js.map +1 -1
  229. package/dist/src/utils/html-to-mdx.d.ts +1 -0
  230. package/dist/src/utils/html-to-mdx.d.ts.map +1 -1
  231. package/dist/src/utils/html-to-mdx.js +43 -5
  232. package/dist/src/utils/html-to-mdx.js.map +1 -1
  233. package/dist/src/utils/model-selection.d.ts +3 -4
  234. package/dist/src/utils/model-selection.d.ts.map +1 -1
  235. package/dist/src/utils/model-selection.js +3 -4
  236. package/dist/src/utils/model-selection.js.map +1 -1
  237. package/package.json +1 -1
  238. package/plugins/specweave/agents/code-standards-detective/AGENT.md +48 -0
  239. package/plugins/specweave/agents/pm/AGENT.md +10 -7
  240. package/plugins/specweave/commands/specweave-archive-features.md +5 -7
  241. package/plugins/specweave/commands/specweave-archive.md +2 -1
  242. package/plugins/specweave/commands/specweave-costs.md +4 -4
  243. package/plugins/specweave/commands/specweave-do.md +44 -10
  244. package/plugins/specweave/commands/specweave-done.md +109 -0
  245. package/plugins/specweave/commands/specweave-import-external.md +45 -18
  246. package/plugins/specweave/commands/specweave-increment.md +331 -33
  247. package/plugins/specweave/commands/specweave-jobs.md +2 -2
  248. package/plugins/specweave/commands/specweave-progress.md +4 -4
  249. package/plugins/specweave/commands/specweave-restore-feature.md +5 -4
  250. package/plugins/specweave/commands/specweave-sync-docs.md +1 -1
  251. package/plugins/specweave/commands/specweave-sync-specs.md +216 -322
  252. package/plugins/specweave/commands/specweave-validate-features.md +13 -8
  253. package/plugins/specweave/commands/specweave-validate.md +27 -1
  254. package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
  255. package/plugins/specweave/hooks/hooks.json +43 -4
  256. package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
  257. package/plugins/specweave/hooks/lib/common-setup.sh +375 -0
  258. package/plugins/specweave/hooks/lib/crash-prevention.sh +336 -0
  259. package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
  260. package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
  261. package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
  262. package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
  263. package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
  264. package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
  265. package/plugins/specweave/hooks/post-task-completion.sh +4 -23
  266. package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
  267. package/plugins/specweave/hooks/pre-command-deduplication.sh +1 -6
  268. package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
  269. package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
  270. package/plugins/specweave/hooks/pre-task-completion.sh +8 -37
  271. package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
  272. package/plugins/specweave/hooks/pre-tool-use.sh +2 -11
  273. package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
  274. package/plugins/specweave/hooks/spec-project-validator.sh +80 -25
  275. package/plugins/specweave/hooks/universal/dispatcher.mjs +135 -42
  276. package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +183 -0
  277. package/plugins/specweave/hooks/user-prompt-submit.sh +140 -38
  278. package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
  279. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +12 -0
  280. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +89 -0
  281. package/plugins/specweave/hooks/v2/guards/bash-file-guard.sh +211 -0
  282. package/plugins/specweave/hooks/v2/guards/bash-file-guard.test.sh +163 -0
  283. package/plugins/specweave/hooks/v2/guards/completion-guard.sh +26 -28
  284. package/plugins/specweave/hooks/v2/guards/features-folder-guard.sh +50 -0
  285. package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +135 -0
  286. package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js +2 -2
  287. package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js.map +1 -1
  288. package/plugins/specweave/scripts/README.md +166 -0
  289. package/plugins/specweave/scripts/cleanup-state.sh +142 -0
  290. package/plugins/specweave/scripts/force-kill.sh +142 -0
  291. package/plugins/specweave/scripts/jobs.js +171 -0
  292. package/plugins/specweave/scripts/progress.js +170 -0
  293. package/plugins/specweave/scripts/read-costs.sh +132 -0
  294. package/plugins/specweave/scripts/read-jobs.sh +324 -0
  295. package/plugins/specweave/scripts/read-progress.sh +185 -0
  296. package/plugins/specweave/scripts/read-status.sh +146 -0
  297. package/plugins/specweave/scripts/read-workflow.sh +173 -0
  298. package/plugins/specweave/scripts/rebuild-dashboard-cache.sh +327 -0
  299. package/plugins/specweave/scripts/session-watchdog.sh +192 -0
  300. package/plugins/specweave/scripts/status.js +154 -0
  301. package/plugins/specweave/scripts/update-dashboard-cache.sh +281 -0
  302. package/plugins/specweave/skills/code-standards-analyzer/SKILL.md +58 -6
  303. package/plugins/specweave/skills/increment-planner/SKILL.md +388 -48
  304. package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +17 -7
  305. package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +6 -1
  306. package/plugins/specweave/skills/increment-planner/templates/tasks-multi-project.md +1 -1
  307. package/plugins/specweave/skills/increment-planner/templates/tasks-single-project.md +1 -1
  308. package/plugins/specweave/skills/instant-status/SKILL.md +70 -0
  309. package/plugins/specweave-ado/commands/cleanup-duplicates.md +212 -0
  310. package/plugins/specweave-ado/commands/reconcile.md +120 -0
  311. package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
  312. package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
  313. package/plugins/specweave-ado/lib/ado-duplicate-detector.js +279 -0
  314. package/plugins/specweave-ado/lib/ado-duplicate-detector.ts +407 -0
  315. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  316. package/plugins/specweave-docs/commands/build.md +32 -4
  317. package/plugins/specweave-docs/commands/preview.md +43 -1
  318. package/plugins/specweave-docs/commands/validate.md +250 -0
  319. package/plugins/specweave-github/agents/github-manager/AGENT.md +2 -2
  320. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1262 -0
  321. package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
  322. package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
  323. package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
  324. package/plugins/specweave-jira/agents/jira-manager/AGENT.md +1 -1
  325. package/plugins/specweave-jira/agents/jira-multi-project-mapper/AGENT.md +530 -0
  326. package/plugins/specweave-jira/agents/jira-sync-judge/AGENT.md +438 -0
  327. package/plugins/specweave-jira/commands/cleanup-duplicates.md +219 -0
  328. package/plugins/specweave-jira/commands/close.md +297 -0
  329. package/plugins/specweave-jira/commands/create.md +198 -0
  330. package/plugins/specweave-jira/commands/reconcile.md +123 -0
  331. package/plugins/specweave-jira/commands/status.md +215 -0
  332. package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
  333. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
  334. package/plugins/specweave-jira/lib/jira-duplicate-detector.js +296 -0
  335. package/plugins/specweave-jira/lib/jira-duplicate-detector.ts +434 -0
  336. package/plugins/specweave-jira/lib/jira-permission-gate.js +160 -0
  337. package/plugins/specweave-jira/lib/jira-permission-gate.ts +276 -0
  338. package/plugins/specweave-jira/lib/jira-profile-resolver.js +222 -0
  339. package/plugins/specweave-jira/lib/jira-profile-resolver.ts +427 -0
  340. package/plugins/specweave-jira/reference/jira-specweave-mapping.md +16 -11
  341. package/plugins/specweave-release/commands/specweave-release-npm.md +140 -14
  342. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1254 -0
  343. package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
  344. package/plugins/specweave/hooks/post-edit-spec.sh +0 -265
  345. package/plugins/specweave/hooks/post-write-spec.sh +0 -267
  346. package/plugins/specweave/hooks/pre-edit-spec.sh +0 -151
  347. package/plugins/specweave/hooks/pre-write-spec.sh +0 -151
@@ -0,0 +1,211 @@
1
+ #!/bin/bash
2
+ # bash-file-guard.sh - CRITICAL: Block Bash file creation patterns that cause infinite hangs
3
+ #
4
+ # ROOT CAUSE: When Claude uses heredoc (cat << EOF ... EOF) to create files and the
5
+ # content gets truncated due to token limits, the shell waits FOREVER for the EOF
6
+ # terminator that will never come. This causes Claude Code to hang indefinitely
7
+ # (2+ hours observed in production crashes).
8
+ #
9
+ # SOLUTION: Block ALL bash file creation patterns and force use of Write/Edit tools.
10
+ # Write/Edit tools are:
11
+ # - Atomic (no intermediate states)
12
+ # - Token-safe (handled by Claude Code, not shell)
13
+ # - Recoverable (no zombie processes)
14
+ #
15
+ # PreToolUse hook for Bash commands - exit 0 allows, exit 2 blocks
16
+ #
17
+ # v0.32.1 - Initial implementation based on crash analysis from 2025-12-06
18
+
19
+ set +e
20
+
21
+ [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
22
+
23
+ # Read stdin for tool input
24
+ INPUT=$(cat)
25
+
26
+ # Extract the command being executed
27
+ # The Bash tool has a "command" parameter
28
+ # Use jq for proper JSON parsing (handles escaped quotes correctly)
29
+ if command -v jq &> /dev/null; then
30
+ COMMAND=$(echo "$INPUT" | jq -r '.command // empty' 2>/dev/null)
31
+ else
32
+ # Fallback: simple regex (may fail on complex JSON with escaped quotes)
33
+ COMMAND=$(echo "$INPUT" | grep -o '"command"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"command"[[:space:]]*:[[:space:]]*"\(.*\)"/\1/')
34
+ fi
35
+
36
+ # If no command found or empty, allow (safety)
37
+ if [[ -z "$COMMAND" ]]; then
38
+ exit 0
39
+ fi
40
+
41
+ # === PATTERN DETECTION ===
42
+ # These patterns WILL cause infinite hangs or truncation issues
43
+
44
+ BLOCKED=0
45
+ PATTERN_NAME=""
46
+
47
+ # === HEREDOC PATTERNS (MOST DANGEROUS - infinite hang!) ===
48
+
49
+ # Pattern 1a: Standard heredoc with any delimiter
50
+ # Matches: cat << EOF, cat << 'EOF', cat << "EOF", cat <<EOF (no space)
51
+ if echo "$COMMAND" | grep -qE "(cat|tee).*<<-?[[:space:]]*['\"]?[A-Za-z]+" 2>/dev/null; then
52
+ BLOCKED=1
53
+ PATTERN_NAME="heredoc (cat << DELIMITER)"
54
+ fi
55
+
56
+ # Pattern 1b: Heredoc with escaped quotes in JSON (\"EOF\")
57
+ # JSON escapes double quotes, so << "EOF" becomes << \"EOF\"
58
+ if echo "$COMMAND" | grep -qE "(cat|tee).*<<-?[[:space:]]*\\\\\"[A-Za-z]+" 2>/dev/null; then
59
+ BLOCKED=1
60
+ PATTERN_NAME="heredoc with quoted delimiter"
61
+ fi
62
+
63
+ # Pattern 1c: SUPER AGGRESSIVE - block ANY heredoc-like pattern
64
+ # Catches edge cases where content has << followed by word boundary
65
+ # This is the NUCLEAR option - heredocs are NEVER safe in Claude context
66
+ if echo "$COMMAND" | grep -qE "<<[[:space:]]*['\"]?[A-Za-z_]+" 2>/dev/null; then
67
+ BLOCKED=1
68
+ PATTERN_NAME="heredoc pattern (any form)"
69
+ fi
70
+
71
+ # Pattern 1d: Multiline content in the command itself
72
+ # If the command contains literal newlines, it might be a heredoc in disguise
73
+ if echo "$COMMAND" | grep -qE $'\n' 2>/dev/null; then
74
+ # Commands with newlines are suspicious - check for file redirects
75
+ if echo "$COMMAND" | grep -qE '>' 2>/dev/null; then
76
+ BLOCKED=1
77
+ PATTERN_NAME="multiline command with redirect (heredoc variant)"
78
+ fi
79
+ fi
80
+
81
+ # === CAT STDIN REDIRECT (VERY DANGEROUS!) ===
82
+ # Pattern 2: Plain cat with output redirect but no input
83
+ # Matches: cat > file.txt (waits forever for stdin!)
84
+ # This is just as dangerous as heredoc - shell waits for input
85
+ if echo "$COMMAND" | grep -qE "^[[:space:]]*cat[[:space:]]+>[[:space:]]*[^>]" 2>/dev/null; then
86
+ BLOCKED=1
87
+ PATTERN_NAME="cat > file (stdin redirect - waits forever!)"
88
+ fi
89
+
90
+ # === DD COMMAND (EQUALLY DANGEROUS!) ===
91
+ # Pattern 2b: dd with stdin or output file
92
+ # Matches: dd if=/dev/stdin of=file, dd of=file bs=1024
93
+ # dd waits for input EXACTLY like cat > file
94
+ if echo "$COMMAND" | grep -qE "^[[:space:]]*dd[[:space:]]" 2>/dev/null; then
95
+ if echo "$COMMAND" | grep -qE "of=" 2>/dev/null; then
96
+ BLOCKED=1
97
+ PATTERN_NAME="dd command (waits for stdin like cat)"
98
+ fi
99
+ fi
100
+
101
+ # === READ COMMAND (WAITS FOR INPUT) ===
102
+ # Pattern 2c: read with redirect
103
+ # Matches: read VAR > file (waits for input from user/stdin)
104
+ if echo "$COMMAND" | grep -qE "^[[:space:]]*read[[:space:]].*>" 2>/dev/null; then
105
+ BLOCKED=1
106
+ PATTERN_NAME="read command with redirect (waits for input)"
107
+ fi
108
+
109
+ # === STREAM REDIRECT EXCEPTION ===
110
+ # Allow redirects to /dev/stdout, /dev/stderr, /dev/null (safe stream operations)
111
+ if echo "$COMMAND" | grep -qE ">[[:space:]]*/dev/(stdout|stderr|null)" 2>/dev/null; then
112
+ exit 0 # Safe stream redirect, not file creation
113
+ fi
114
+
115
+ # === ECHO/PRINTF PATTERNS ===
116
+ # These can cause truncation issues and are bad practice
117
+ # NOTE: Match any echo/printf that writes to file (single > not >>)
118
+
119
+ # Pattern 3: Echo with redirect to file
120
+ # Matches: echo anything > file (but not >>)
121
+ # Use negative lookahead simulation: check for > but then verify not >>
122
+ if echo "$COMMAND" | grep -qE '^[[:space:]]*(echo)[[:space:]]' 2>/dev/null; then
123
+ if echo "$COMMAND" | grep -qE '>[[:space:]]*[^>]' 2>/dev/null; then
124
+ # Check it's not append (>>)
125
+ if ! echo "$COMMAND" | grep -qE '>>' 2>/dev/null; then
126
+ BLOCKED=1
127
+ PATTERN_NAME="echo > file"
128
+ fi
129
+ fi
130
+ fi
131
+
132
+ # Pattern 4: Printf with redirect to file
133
+ if echo "$COMMAND" | grep -qE '^[[:space:]]*(printf)[[:space:]]' 2>/dev/null; then
134
+ if echo "$COMMAND" | grep -qE '>[[:space:]]*[^>]' 2>/dev/null; then
135
+ # Check it's not append (>>)
136
+ if ! echo "$COMMAND" | grep -qE '>>' 2>/dev/null; then
137
+ BLOCKED=1
138
+ PATTERN_NAME="printf > file"
139
+ fi
140
+ fi
141
+ fi
142
+
143
+ # Pattern 5: Multi-line string with cat
144
+ # Matches: cat > file -e "multi\nline", etc.
145
+ if echo "$COMMAND" | grep -qE "cat[[:space:]]+-[a-z]*[[:space:]]+['\"].*\\\\n" 2>/dev/null; then
146
+ BLOCKED=1
147
+ PATTERN_NAME="cat with multi-line string"
148
+ fi
149
+
150
+ # === SAFE EXCEPTIONS ===
151
+ # Append operations (>>) are safe - echo/printf complete immediately
152
+ if echo "$COMMAND" | grep -qE "(echo|printf)[[:space:]].*>>[[:space:]]*" 2>/dev/null; then
153
+ BLOCKED=0
154
+ PATTERN_NAME=""
155
+ fi
156
+
157
+ # === EXCEPTION: Allow safe bash operations ===
158
+ # These are safe because they don't involve file content creation
159
+
160
+ # Exception 1: Simple redirects from commands (not content creation)
161
+ # Safe: curl ... > file, wget ... > file (command output, not content creation)
162
+ # These won't hang because the content comes from the command, not heredoc
163
+ if echo "$COMMAND" | grep -qE "^(curl|wget|git|npm|node|python|pip)[[:space:]].*>" 2>/dev/null; then
164
+ # These are downloading/generating content from commands, not creating from heredoc
165
+ # Only block if also contains heredoc/echo patterns
166
+ if [[ "$PATTERN_NAME" != "heredoc"* ]] && [[ "$PATTERN_NAME" != "echo"* ]] && [[ "$PATTERN_NAME" != "printf"* ]]; then
167
+ exit 0 # Allow
168
+ fi
169
+ fi
170
+
171
+ # === BLOCK DANGEROUS PATTERNS ===
172
+ if [[ $BLOCKED -eq 1 ]]; then
173
+ echo ""
174
+ echo "=============================================================================="
175
+ echo " 🛑 BLOCKED: Bash file creation detected (Infinite Hang Prevention)"
176
+ echo "=============================================================================="
177
+ echo ""
178
+ echo "Pattern detected: $PATTERN_NAME"
179
+ echo ""
180
+ echo "WHY THIS IS BLOCKED:"
181
+ echo " When using heredoc (cat << EOF) or echo/printf redirects, if the content"
182
+ echo " is truncated due to token limits, the shell waits FOREVER for input that"
183
+ echo " will never come. This causes Claude Code to hang for hours with no recovery."
184
+ echo ""
185
+ echo " Observed crash: 2+ hour session hang from truncated heredoc (2025-12-06)"
186
+ echo ""
187
+ echo "SAFE ALTERNATIVES:"
188
+ echo " ┌─────────────────────────────────────────────────────────────────────┐"
189
+ echo " │ Instead of: Use: │"
190
+ echo " ├─────────────────────────────────────────────────────────────────────┤"
191
+ echo " │ cat > file << EOF Write tool: Write(file_path, content) │"
192
+ echo " │ echo \"...\" > file Write tool: Write(file_path, content) │"
193
+ echo " │ printf ... > file Write tool: Write(file_path, content) │"
194
+ echo " │ Modify existing Edit tool: Edit(file_path, old, new) │"
195
+ echo " │ Append to file Read + Write tools │"
196
+ echo " └─────────────────────────────────────────────────────────────────────┘"
197
+ echo ""
198
+ echo "WHAT IS ALLOWED:"
199
+ echo " - mkdir -p /path/to/dir (directory creation)"
200
+ echo " - git commit, git push (version control)"
201
+ echo " - npm install, npm run (package management)"
202
+ echo " - curl URL > file (downloading, not content creation)"
203
+ echo " - rm, mv, cp (file operations)"
204
+ echo ""
205
+ echo "=============================================================================="
206
+
207
+ exit 2 # Block the tool call
208
+ fi
209
+
210
+ # All other bash commands are allowed
211
+ exit 0
@@ -0,0 +1,163 @@
1
+ #!/bin/bash
2
+ # Comprehensive test suite for bash-file-guard.sh
3
+ # Tests ALL dangerous patterns that could cause infinite hangs
4
+ #
5
+ # Usage: bash bash-file-guard.test.sh
6
+
7
+ set -e
8
+
9
+ GUARD="$(dirname "$0")/bash-file-guard.sh"
10
+ PASS=0
11
+ FAIL=0
12
+ TOTAL=0
13
+
14
+ # Colors for output
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ NC='\033[0m' # No Color
19
+
20
+ test_should_block() {
21
+ local name="$1"
22
+ local command="$2"
23
+ TOTAL=$((TOTAL + 1))
24
+
25
+ # Properly escape the command for JSON: " becomes \"
26
+ local escaped_command=$(echo "$command" | sed 's/"/\\"/g')
27
+ result=$(echo "{\"command\": \"$escaped_command\"}" | bash "$GUARD" 2>&1; echo "EXIT:$?")
28
+ exit_code=$(echo "$result" | grep -o 'EXIT:[0-9]*' | cut -d: -f2)
29
+
30
+ if [[ "$exit_code" == "2" ]]; then
31
+ echo -e "${GREEN}✓ BLOCKED${NC}: $name"
32
+ PASS=$((PASS + 1))
33
+ else
34
+ echo -e "${RED}✗ NOT BLOCKED${NC}: $name"
35
+ echo " Command: $command"
36
+ echo " Exit code: $exit_code (expected 2)"
37
+ FAIL=$((FAIL + 1))
38
+ fi
39
+ }
40
+
41
+ test_should_allow() {
42
+ local name="$1"
43
+ local command="$2"
44
+ TOTAL=$((TOTAL + 1))
45
+
46
+ # Properly escape the command for JSON: " becomes \"
47
+ local escaped_command=$(echo "$command" | sed 's/"/\\"/g')
48
+ result=$(echo "{\"command\": \"$escaped_command\"}" | bash "$GUARD" 2>&1; echo "EXIT:$?")
49
+ exit_code=$(echo "$result" | grep -o 'EXIT:[0-9]*' | cut -d: -f2)
50
+
51
+ if [[ "$exit_code" == "0" ]]; then
52
+ echo -e "${GREEN}✓ ALLOWED${NC}: $name"
53
+ PASS=$((PASS + 1))
54
+ else
55
+ echo -e "${RED}✗ WRONGLY BLOCKED${NC}: $name"
56
+ echo " Command: $command"
57
+ echo " Exit code: $exit_code (expected 0)"
58
+ FAIL=$((FAIL + 1))
59
+ fi
60
+ }
61
+
62
+ echo "========================================"
63
+ echo " BASH FILE GUARD - COMPREHENSIVE TESTS"
64
+ echo "========================================"
65
+ echo ""
66
+
67
+ echo -e "${YELLOW}=== HEREDOC PATTERNS (MOST DANGEROUS) ===${NC}"
68
+ test_should_block "Basic heredoc" "cat > file.txt << EOF"
69
+ test_should_block "Heredoc with quotes" "cat > file.txt << 'EOF'"
70
+ test_should_block "Heredoc double quotes" 'cat > file.txt << "EOF"'
71
+ test_should_block "Heredoc reversed order" "cat << EOF > file.txt"
72
+ test_should_block "Heredoc with END delimiter" "cat > file.txt << END"
73
+ test_should_block "Heredoc with CONTENT delimiter" "cat << CONTENT > out.md"
74
+ test_should_block "Heredoc with MARKER" "cat << MARKER"
75
+ test_should_block "Heredoc tab strip" "cat <<- EOF > file.txt"
76
+ test_should_block "Tee with heredoc" "tee file.txt << EOF"
77
+ test_should_block "Tee reversed" "tee << EOF > file.txt"
78
+ test_should_block "Heredoc with path" "cat > /tmp/test.md << EOF"
79
+ test_should_block "Heredoc with variable path" 'cat > $HOME/test.txt << EOF'
80
+
81
+ echo ""
82
+ echo -e "${YELLOW}=== ECHO PATTERNS ===${NC}"
83
+ test_should_block "Echo to file" "echo hello > file.txt"
84
+ test_should_block "Echo quoted string" 'echo "hello world" > file.txt'
85
+ test_should_block "Echo single quoted" "echo 'hello' > file.txt"
86
+ test_should_block "Echo with -e flag" "echo -e 'hello\\nworld' > file.txt"
87
+ test_should_block "Echo with -n flag" "echo -n 'hello' > file.txt"
88
+ test_should_block "Echo variable" 'echo $VAR > file.txt'
89
+ test_should_block "Echo to path" "echo content > /tmp/test.txt"
90
+
91
+ echo ""
92
+ echo -e "${YELLOW}=== PRINTF PATTERNS ===${NC}"
93
+ test_should_block "Printf to file" "printf hello > file.txt"
94
+ test_should_block "Printf format string" "printf '%s' hello > file.txt"
95
+ test_should_block "Printf with newline" "printf '%s\\n' hello > file.txt"
96
+ test_should_block "Printf quoted" 'printf "hello world" > file.txt'
97
+
98
+ echo ""
99
+ echo -e "${YELLOW}=== EDGE CASES - SHOULD BLOCK ===${NC}"
100
+ test_should_block "Cat stdin to file (dangerous!)" "cat > file.txt"
101
+ test_should_block "Bash -c with heredoc" "bash -c 'cat > f << EOF'"
102
+ test_should_block "Double redirect" "echo a > file.txt > backup.txt"
103
+ test_should_block "dd stdin to file" "dd if=/dev/stdin of=output.dat"
104
+ test_should_block "dd output file" "dd of=file.bin bs=1024"
105
+ test_should_block "dd with count" "dd of=output.img bs=512 count=100"
106
+ test_should_block "read to file" "read VAR > input.txt"
107
+ test_should_block "read prompt to file" 'read -p "Enter:" > log.txt'
108
+
109
+ echo ""
110
+ echo -e "${YELLOW}=== SAFE COMMANDS - SHOULD ALLOW ===${NC}"
111
+ test_should_allow "Git status" "git status"
112
+ test_should_allow "Git add" "git add ."
113
+ test_should_allow "Git commit" "git commit -m 'message'"
114
+ test_should_allow "Git push" "git push origin main"
115
+ test_should_allow "Git diff" "git diff HEAD"
116
+ test_should_allow "Npm install" "npm install"
117
+ test_should_allow "Npm run build" "npm run build"
118
+ test_should_allow "Npm test" "npm test"
119
+ test_should_allow "Mkdir" "mkdir -p /tmp/test"
120
+ test_should_allow "Ls" "ls -la"
121
+ test_should_allow "Pwd" "pwd"
122
+ test_should_allow "Cd" "cd /tmp"
123
+ test_should_allow "Rm file" "rm -f /tmp/test.txt"
124
+ test_should_allow "Mv file" "mv old.txt new.txt"
125
+ test_should_allow "Cp file" "cp source.txt dest.txt"
126
+ test_should_allow "Curl download" "curl -o file.txt https://example.com"
127
+ test_should_allow "Wget download" "wget -O file.txt https://example.com"
128
+ test_should_allow "Ps" "ps aux"
129
+ test_should_allow "Kill" "kill -9 1234"
130
+ test_should_allow "Grep" "grep pattern file.txt"
131
+ test_should_allow "Find" "find . -name '*.ts'"
132
+ test_should_allow "Chmod" "chmod +x script.sh"
133
+ test_should_allow "Node run" "node script.js"
134
+ test_should_allow "Python run" "python script.py"
135
+ test_should_allow "Read from file" "cat file.txt"
136
+ test_should_allow "Head" "head -n 10 file.txt"
137
+ test_should_allow "Tail" "tail -f log.txt"
138
+
139
+ echo ""
140
+ echo -e "${YELLOW}=== APPEND OPERATIONS (should allow) ===${NC}"
141
+ test_should_allow "Echo append" "echo hello >> file.txt"
142
+ test_should_allow "Printf append" "printf '%s' data >> file.txt"
143
+
144
+ echo ""
145
+ echo -e "${YELLOW}=== STREAM REDIRECTS (should allow) ===${NC}"
146
+ test_should_allow "Echo to stderr" "echo 'error' > /dev/stderr"
147
+ test_should_allow "Printf to stdout" "printf '%s' output > /dev/stdout"
148
+ test_should_allow "Echo to null" "echo 'discard' > /dev/null"
149
+
150
+ echo ""
151
+ echo "========================================"
152
+ echo " RESULTS"
153
+ echo "========================================"
154
+ echo -e "Total: $TOTAL"
155
+ echo -e "${GREEN}Passed: $PASS${NC}"
156
+ if [[ $FAIL -gt 0 ]]; then
157
+ echo -e "${RED}Failed: $FAIL${NC}"
158
+ exit 1
159
+ else
160
+ echo -e "Failed: 0"
161
+ echo ""
162
+ echo -e "${GREEN}ALL TESTS PASSED!${NC}"
163
+ fi
@@ -45,34 +45,32 @@ if echo "$NEW_CONTENT" | grep -q '"status"[[:space:]]*:[[:space:]]*"completed"';
45
45
  fi
46
46
 
47
47
  # BLOCK - trying to set completed without going through ready_for_review
48
- cat << 'EOF'
49
-
50
- ==============================================================================
51
- BLOCKED: Direct status change to "completed" is not allowed (v0.28.63+)
52
- ==============================================================================
53
-
54
- You cannot directly set status to "completed" in metadata.json.
55
-
56
- This prevents the auto-completion bug where increments get marked as
57
- completed without proper validation.
58
-
59
- CORRECT WORKFLOW:
60
- 1. All tasks completed -> status auto-transitions to "ready_for_review"
61
- 2. Run /specweave:done <increment-id> with explicit user confirmation
62
- 3. Only then does status become "completed"
63
-
64
- WHY THIS MATTERS:
65
- - Ensures all ACs are checked in spec.md before closure
66
- - Requires explicit user approval
67
- - Maintains audit trail (approvedAt timestamp)
68
-
69
- If you're implementing closure logic, use:
70
- MetadataManager.updateStatus(incrementId, IncrementStatus.COMPLETED)
71
-
72
- This will only succeed if current status is "ready_for_review".
73
-
74
- ==============================================================================
75
- EOF
48
+ echo ""
49
+ echo "=============================================================================="
50
+ echo " BLOCKED: Direct status change to \"completed\" is not allowed (v0.28.63+)"
51
+ echo "=============================================================================="
52
+ echo ""
53
+ echo "You cannot directly set status to \"completed\" in metadata.json."
54
+ echo ""
55
+ echo "This prevents the auto-completion bug where increments get marked as"
56
+ echo "completed without proper validation."
57
+ echo ""
58
+ echo "CORRECT WORKFLOW:"
59
+ echo "1. All tasks completed -> status auto-transitions to \"ready_for_review\""
60
+ echo "2. Run /specweave:done <increment-id> with explicit user confirmation"
61
+ echo "3. Only then does status become \"completed\""
62
+ echo ""
63
+ echo "WHY THIS MATTERS:"
64
+ echo "- Ensures all ACs are checked in spec.md before closure"
65
+ echo "- Requires explicit user approval"
66
+ echo "- Maintains audit trail (approvedAt timestamp)"
67
+ echo ""
68
+ echo "If you're implementing closure logic, use:"
69
+ echo " MetadataManager.updateStatus(incrementId, IncrementStatus.COMPLETED)"
70
+ echo ""
71
+ echo "This will only succeed if current status is \"ready_for_review\"."
72
+ echo ""
73
+ echo "=============================================================================="
76
74
 
77
75
  exit 2 # Block the tool call
78
76
  fi
@@ -0,0 +1,50 @@
1
+ #!/bin/bash
2
+ # features-folder-guard.sh - Block writes to obsolete _features/ folder
3
+ #
4
+ # ROOT CAUSE: The _features/ folder is OBSOLETE since v5.0.0. Features should
5
+ # live in {project}/FS-XXX/ folders. LLM agents sometimes create files in
6
+ # _features/ due to outdated documentation references.
7
+ #
8
+ # SOLUTION: Block all Write/Edit operations targeting _features/ folder.
9
+ # This forces proper project-based feature folder structure.
10
+ #
11
+ # PreToolUse hook for Write/Edit commands - exit 0 allows, exit 2 blocks
12
+ #
13
+ # v0.33.0 - Initial implementation based on bug analysis from 2025-12-06
14
+
15
+ set +e
16
+
17
+ [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
18
+
19
+ # Read stdin for tool input
20
+ INPUT=$(cat)
21
+
22
+ # Extract the file_path being written/edited
23
+ if command -v jq &> /dev/null; then
24
+ FILE_PATH=$(echo "$INPUT" | jq -r '.file_path // empty' 2>/dev/null)
25
+ else
26
+ FILE_PATH=$(echo "$INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"file_path"[[:space:]]*:[[:space:]]*"\(.*\)"/\1/')
27
+ fi
28
+
29
+ # If no file_path found, allow (safety)
30
+ if [[ -z "$FILE_PATH" ]]; then
31
+ exit 0
32
+ fi
33
+
34
+ # === PATTERN DETECTION ===
35
+ # Block any write to _features/ folder (obsolete since v5.0.0)
36
+
37
+ # Pattern: .specweave/docs/internal/specs/_features/
38
+ if [[ "$FILE_PATH" =~ \.specweave/docs/internal/specs/_features/ ]]; then
39
+ cat << 'EOF'
40
+ {
41
+ "decision": "block",
42
+ "reason": "🚫 BLOCKED: Writing to _features/ folder (OBSOLETE since v5.0.0)\n\n⚠️ The _features/ folder has been deprecated.\nFeatures must now live in project folders: .specweave/docs/internal/specs/{project}/FS-XXX/\n\n📋 CORRECT structure:\n .specweave/docs/internal/specs/specweave/FS-116/FEATURE.md ✅\n .specweave/docs/internal/specs/backend/FS-117/us-001.md ✅\n\n❌ OBSOLETE structure:\n .specweave/docs/internal/specs/_features/FS-116/FEATURE.md ❌\n\n🔧 To fix: Use spec.md `project:` field to determine target folder.\nSee: CLAUDE.md section '2c. spec.md MUST Have project:'"
43
+ }
44
+ EOF
45
+ exit 2
46
+ fi
47
+
48
+ # Allow all other writes
49
+ printf '{"decision":"allow"}'
50
+ exit 0
@@ -0,0 +1,135 @@
1
+ #!/bin/bash
2
+ # increment-duplicate-guard.sh - Block creation of duplicate increment IDs
3
+ #
4
+ # v0.33.0+: Prevents duplicate increment numbers (0121 and 0121 both existing)
5
+ # Also prevents 0001 and 0001E collisions (they share the same base number)
6
+ #
7
+ # PreToolUse hook for Write tool - BLOCKS the tool call if duplicate detected
8
+ #
9
+ # CRITICAL: This guards against the BUG where two increments get the same ID:
10
+ # - 0121-ado-jira-feature-parity-p2-p3
11
+ # - 0121-intelligent-living-docs-content
12
+ #
13
+ # Exit 0 = allow, Exit 2 = block
14
+ set +e
15
+
16
+ [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]] && exit 0
17
+
18
+ # Read stdin for tool input
19
+ INPUT=$(cat)
20
+
21
+ # Extract file_path from the tool call
22
+ FILE_PATH=$(echo "$INPUT" | grep -o '"file_path"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
23
+
24
+ # Only care about .specweave/increments/ paths
25
+ if [[ "$FILE_PATH" != *.specweave/increments/* ]]; then
26
+ exit 0 # Not an increment file - allow
27
+ fi
28
+
29
+ # Extract the increment folder name from the path
30
+ # Pattern: .specweave/increments/XXXX-name/file.md or .specweave/increments/XXXX-name/subfolder/file
31
+ # We need to extract "XXXX-name" part
32
+
33
+ # Remove the .specweave/increments/ prefix
34
+ AFTER_INCREMENTS=${FILE_PATH#*.specweave/increments/}
35
+
36
+ # Get the first path component (the increment folder)
37
+ INCREMENT_FOLDER=$(echo "$AFTER_INCREMENTS" | cut -d'/' -f1)
38
+
39
+ # Skip special folders
40
+ if [[ "$INCREMENT_FOLDER" == "_archive" ]] || [[ "$INCREMENT_FOLDER" == "_abandoned" ]] || [[ "$INCREMENT_FOLDER" == "_paused" ]] || [[ "$INCREMENT_FOLDER" == "README.md" ]]; then
41
+ exit 0
42
+ fi
43
+
44
+ # Extract the increment number from folder name (handles both 0121-name and 0121E-name)
45
+ INCREMENT_NUM=$(echo "$INCREMENT_FOLDER" | grep -oE '^[0-9]{3,4}' | head -1)
46
+
47
+ if [[ -z "$INCREMENT_NUM" ]]; then
48
+ exit 0 # Not a standard increment folder pattern - allow
49
+ fi
50
+
51
+ # Normalize to 4 digits (strip leading zeros to avoid octal interpretation)
52
+ INCREMENT_NUM=$(printf "%04d" "$((10#$INCREMENT_NUM))")
53
+
54
+ # Find the increments root directory
55
+ INCREMENTS_DIR=$(echo "$FILE_PATH" | grep -o '.*/\.specweave/increments' | head -1)
56
+
57
+ if [[ ! -d "$INCREMENTS_DIR" ]]; then
58
+ exit 0 # Increments directory doesn't exist yet - allow (first increment)
59
+ fi
60
+
61
+ # Scan ALL directories for existing increment with the same number
62
+ DIRS_TO_CHECK=(
63
+ "$INCREMENTS_DIR"
64
+ "$INCREMENTS_DIR/_archive"
65
+ "$INCREMENTS_DIR/_abandoned"
66
+ "$INCREMENTS_DIR/_paused"
67
+ )
68
+
69
+ FOUND_DUPLICATES=()
70
+
71
+ for DIR in "${DIRS_TO_CHECK[@]}"; do
72
+ if [[ ! -d "$DIR" ]]; then
73
+ continue
74
+ fi
75
+
76
+ # Find all folders matching this increment number (including E suffix variants)
77
+ while IFS= read -r -d '' EXISTING_FOLDER; do
78
+ EXISTING_NAME=$(basename "$EXISTING_FOLDER")
79
+
80
+ # Extract number from existing folder
81
+ EXISTING_NUM=$(echo "$EXISTING_NAME" | grep -oE '^[0-9]{3,4}' | head -1)
82
+
83
+ if [[ -z "$EXISTING_NUM" ]]; then
84
+ continue
85
+ fi
86
+
87
+ EXISTING_NUM=$(printf "%04d" "$((10#$EXISTING_NUM))")
88
+
89
+ # Check if same base number (0121 matches 0121, 0121E, etc.)
90
+ if [[ "$EXISTING_NUM" == "$INCREMENT_NUM" ]]; then
91
+ # Skip if it's the exact same folder we're creating
92
+ if [[ "$EXISTING_NAME" == "$INCREMENT_FOLDER" ]]; then
93
+ continue
94
+ fi
95
+
96
+ # Found a duplicate!
97
+ FOUND_DUPLICATES+=("$EXISTING_NAME (in $(basename "$DIR"))")
98
+ fi
99
+ done < <(find "$DIR" -maxdepth 1 -type d -name "${INCREMENT_NUM}*" -print0 2>/dev/null)
100
+ done
101
+
102
+ # If duplicates found, BLOCK the operation
103
+ if [[ ${#FOUND_DUPLICATES[@]} -gt 0 ]]; then
104
+ echo ""
105
+ echo "=============================================================================="
106
+ echo " BLOCKED: Duplicate increment ID detected (v0.33.0+)"
107
+ echo "=============================================================================="
108
+ echo ""
109
+ echo "You are trying to create increment: $INCREMENT_FOLDER"
110
+ echo "But increment number $INCREMENT_NUM already exists:"
111
+ echo ""
112
+ for DUP in "${FOUND_DUPLICATES[@]}"; do
113
+ echo " - $DUP"
114
+ done
115
+ echo ""
116
+ echo "IMPORTANT: Increment IDs MUST be unique across all directories:"
117
+ echo " - Active increments"
118
+ echo " - Archived increments (_archive/)"
119
+ echo " - Abandoned increments (_abandoned/)"
120
+ echo " - Paused increments (_paused/)"
121
+ echo ""
122
+ echo "NOTE: 0001 and 0001E share the SAME base number and cannot coexist!"
123
+ echo ""
124
+ echo "TO FIX:"
125
+ echo "1. Use a different increment number"
126
+ echo "2. Get the next available number:"
127
+ echo " node -e \"import('./dist/core/increment/increment-utils.js').then(m => console.log(m.IncrementNumberManager.getNextIncrementNumber()))\""
128
+ echo ""
129
+ echo "=============================================================================="
130
+
131
+ exit 2 # Block the tool call
132
+ fi
133
+
134
+ # No duplicates - allow
135
+ exit 0
@@ -184,8 +184,8 @@ async function scanDirectory(dir, throwOnError = false) {
184
184
  * Extract increment number from increment name (e.g., "0001-feature" → "0001")
185
185
  */
186
186
  function extractIncrementNumber(name) {
187
- const match = name.match(/^(\d{4})-/);
188
- return match ? match[1] : null;
187
+ const match = name.match(/^(\d{3,4})E?-/);
188
+ return match ? match[1].padStart(4, '0') : null;
189
189
  }
190
190
  /**
191
191
  * Select winning version based on priority rules