specweave 0.32.2 → 0.32.5

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 (244) hide show
  1. package/CLAUDE.md +51 -9
  2. package/bin/specweave.js +34 -0
  3. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts +100 -0
  4. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts.map +1 -0
  5. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js +291 -0
  6. package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js.map +1 -0
  7. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts +103 -0
  8. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts.map +1 -0
  9. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js +310 -0
  10. package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js.map +1 -0
  11. package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts +126 -0
  12. package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts.map +1 -0
  13. package/dist/plugins/specweave-jira/lib/jira-permission-gate.js +207 -0
  14. package/dist/plugins/specweave-jira/lib/jira-permission-gate.js.map +1 -0
  15. package/dist/src/adapters/codex/README.md +1 -1
  16. package/dist/src/adapters/codex/adapter.js +1 -1
  17. package/dist/src/cli/commands/archive.d.ts +2 -0
  18. package/dist/src/cli/commands/archive.d.ts.map +1 -1
  19. package/dist/src/cli/commands/archive.js +33 -0
  20. package/dist/src/cli/commands/archive.js.map +1 -1
  21. package/dist/src/cli/commands/context.d.ts +92 -0
  22. package/dist/src/cli/commands/context.d.ts.map +1 -0
  23. package/dist/src/cli/commands/context.js +205 -0
  24. package/dist/src/cli/commands/context.js.map +1 -0
  25. package/dist/src/cli/commands/init-multiproject.js +1 -1
  26. package/dist/src/cli/commands/init-multiproject.js.map +1 -1
  27. package/dist/src/cli/commands/init.d.ts.map +1 -1
  28. package/dist/src/cli/commands/init.js +111 -69
  29. package/dist/src/cli/commands/init.js.map +1 -1
  30. package/dist/src/cli/commands/migrate-to-multiproject.js +2 -2
  31. package/dist/src/cli/commands/migrate-to-multiproject.js.map +1 -1
  32. package/dist/src/cli/helpers/init/external-import.d.ts +3 -0
  33. package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
  34. package/dist/src/cli/helpers/init/external-import.js +17 -4
  35. package/dist/src/cli/helpers/init/external-import.js.map +1 -1
  36. package/dist/src/cli/helpers/init/index.d.ts +1 -0
  37. package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
  38. package/dist/src/cli/helpers/init/index.js +2 -0
  39. package/dist/src/cli/helpers/init/index.js.map +1 -1
  40. package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts +70 -0
  41. package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts.map +1 -1
  42. package/dist/src/cli/helpers/init/jira-ado-auto-detect.js +214 -4
  43. package/dist/src/cli/helpers/init/jira-ado-auto-detect.js.map +1 -1
  44. package/dist/src/cli/helpers/init/living-docs-preflight.d.ts +4 -0
  45. package/dist/src/cli/helpers/init/living-docs-preflight.d.ts.map +1 -1
  46. package/dist/src/cli/helpers/init/living-docs-preflight.js +34 -3
  47. package/dist/src/cli/helpers/init/living-docs-preflight.js.map +1 -1
  48. package/dist/src/cli/helpers/init/testing-config.d.ts +3 -0
  49. package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -1
  50. package/dist/src/cli/helpers/init/testing-config.js +9 -2
  51. package/dist/src/cli/helpers/init/testing-config.js.map +1 -1
  52. package/dist/src/cli/helpers/init/translation-config.d.ts +3 -0
  53. package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -1
  54. package/dist/src/cli/helpers/init/translation-config.js +21 -4
  55. package/dist/src/cli/helpers/init/translation-config.js.map +1 -1
  56. package/dist/src/cli/helpers/init/wizard-navigation.d.ts +45 -0
  57. package/dist/src/cli/helpers/init/wizard-navigation.d.ts.map +1 -0
  58. package/dist/src/cli/helpers/init/wizard-navigation.js +97 -0
  59. package/dist/src/cli/helpers/init/wizard-navigation.js.map +1 -0
  60. package/dist/src/core/increment/increment-archiver.d.ts +25 -4
  61. package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
  62. package/dist/src/core/increment/increment-archiver.js +64 -20
  63. package/dist/src/core/increment/increment-archiver.js.map +1 -1
  64. package/dist/src/core/increment/increment-utils.d.ts +65 -0
  65. package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
  66. package/dist/src/core/increment/increment-utils.js +114 -0
  67. package/dist/src/core/increment/increment-utils.js.map +1 -1
  68. package/dist/src/core/living-docs/cross-project-sync.d.ts +97 -0
  69. package/dist/src/core/living-docs/cross-project-sync.d.ts.map +1 -0
  70. package/dist/src/core/living-docs/cross-project-sync.js +135 -0
  71. package/dist/src/core/living-docs/cross-project-sync.js.map +1 -0
  72. package/dist/src/core/living-docs/external-sync-orchestrator.d.ts +106 -0
  73. package/dist/src/core/living-docs/external-sync-orchestrator.d.ts.map +1 -0
  74. package/dist/src/core/living-docs/external-sync-orchestrator.js +146 -0
  75. package/dist/src/core/living-docs/external-sync-orchestrator.js.map +1 -0
  76. package/dist/src/core/living-docs/feature-archiver.d.ts +4 -0
  77. package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
  78. package/dist/src/core/living-docs/feature-archiver.js +32 -10
  79. package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
  80. package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
  81. package/dist/src/core/living-docs/feature-id-manager.js +7 -3
  82. package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
  83. package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts +38 -0
  84. package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts.map +1 -0
  85. package/dist/src/core/living-docs/governance/ecosystem-detector.js +325 -0
  86. package/dist/src/core/living-docs/governance/ecosystem-detector.js.map +1 -0
  87. package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts +74 -0
  88. package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts.map +1 -0
  89. package/dist/src/core/living-docs/governance/frontend-standards-parser.js +366 -0
  90. package/dist/src/core/living-docs/governance/frontend-standards-parser.js.map +1 -0
  91. package/dist/src/core/living-docs/governance/go-standards-parser.d.ts +64 -0
  92. package/dist/src/core/living-docs/governance/go-standards-parser.d.ts.map +1 -0
  93. package/dist/src/core/living-docs/governance/go-standards-parser.js +229 -0
  94. package/dist/src/core/living-docs/governance/go-standards-parser.js.map +1 -0
  95. package/dist/src/core/living-docs/governance/index.d.ts +50 -0
  96. package/dist/src/core/living-docs/governance/index.d.ts.map +1 -0
  97. package/dist/src/core/living-docs/governance/index.js +56 -0
  98. package/dist/src/core/living-docs/governance/index.js.map +1 -0
  99. package/dist/src/core/living-docs/governance/java-standards-parser.d.ts +89 -0
  100. package/dist/src/core/living-docs/governance/java-standards-parser.d.ts.map +1 -0
  101. package/dist/src/core/living-docs/governance/java-standards-parser.js +356 -0
  102. package/dist/src/core/living-docs/governance/java-standards-parser.js.map +1 -0
  103. package/dist/src/core/living-docs/governance/python-standards-parser.d.ts +83 -0
  104. package/dist/src/core/living-docs/governance/python-standards-parser.d.ts.map +1 -0
  105. package/dist/src/core/living-docs/governance/python-standards-parser.js +347 -0
  106. package/dist/src/core/living-docs/governance/python-standards-parser.js.map +1 -0
  107. package/dist/src/core/living-docs/governance/standards-generator.d.ts +38 -0
  108. package/dist/src/core/living-docs/governance/standards-generator.d.ts.map +1 -0
  109. package/dist/src/core/living-docs/governance/standards-generator.js +476 -0
  110. package/dist/src/core/living-docs/governance/standards-generator.js.map +1 -0
  111. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -1
  112. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +54 -2
  113. package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -1
  114. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +5 -1
  115. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -1
  116. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +358 -30
  117. package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -1
  118. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +44 -0
  119. package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -1
  120. package/dist/src/core/living-docs/living-docs-sync.d.ts +7 -3
  121. package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
  122. package/dist/src/core/living-docs/living-docs-sync.js +94 -10
  123. package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
  124. package/dist/src/core/living-docs/module-analyzer.d.ts +22 -0
  125. package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
  126. package/dist/src/core/living-docs/module-analyzer.js +123 -19
  127. package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
  128. package/dist/src/core/living-docs/sync-helpers/generators.d.ts +8 -1
  129. package/dist/src/core/living-docs/sync-helpers/generators.d.ts.map +1 -1
  130. package/dist/src/core/living-docs/sync-helpers/generators.js +18 -1
  131. package/dist/src/core/living-docs/sync-helpers/generators.js.map +1 -1
  132. package/dist/src/core/living-docs/sync-helpers/index.d.ts +1 -1
  133. package/dist/src/core/living-docs/sync-helpers/index.d.ts.map +1 -1
  134. package/dist/src/core/living-docs/sync-helpers/index.js.map +1 -1
  135. package/dist/src/core/living-docs/sync-helpers/parsers.d.ts +3 -1
  136. package/dist/src/core/living-docs/sync-helpers/parsers.d.ts.map +1 -1
  137. package/dist/src/core/living-docs/sync-helpers/parsers.js +24 -2
  138. package/dist/src/core/living-docs/sync-helpers/parsers.js.map +1 -1
  139. package/dist/src/core/living-docs/types.d.ts +6 -0
  140. package/dist/src/core/living-docs/types.d.ts.map +1 -1
  141. package/dist/src/core/living-docs/validators/index.d.ts +7 -0
  142. package/dist/src/core/living-docs/validators/index.d.ts.map +1 -0
  143. package/dist/src/core/living-docs/validators/index.js +7 -0
  144. package/dist/src/core/living-docs/validators/index.js.map +1 -0
  145. package/dist/src/core/living-docs/validators/project-validator.d.ts +92 -0
  146. package/dist/src/core/living-docs/validators/project-validator.d.ts.map +1 -0
  147. package/dist/src/core/living-docs/validators/project-validator.js +142 -0
  148. package/dist/src/core/living-docs/validators/project-validator.js.map +1 -0
  149. package/dist/src/core/llm/provider-factory.js +2 -2
  150. package/dist/src/core/llm/provider-factory.js.map +1 -1
  151. package/dist/src/core/llm/providers/anthropic-provider.js +1 -1
  152. package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
  153. package/dist/src/core/llm/providers/bedrock-provider.js +8 -4
  154. package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
  155. package/dist/src/core/project/project-manager.d.ts.map +1 -1
  156. package/dist/src/core/project/project-manager.js +19 -17
  157. package/dist/src/core/project/project-manager.js.map +1 -1
  158. package/dist/src/core/types/config.d.ts +4 -2
  159. package/dist/src/core/types/config.d.ts.map +1 -1
  160. package/dist/src/core/types/config.js.map +1 -1
  161. package/dist/src/core/types/increment-metadata.d.ts +34 -0
  162. package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
  163. package/dist/src/importers/jira-importer.d.ts +14 -0
  164. package/dist/src/importers/jira-importer.d.ts.map +1 -1
  165. package/dist/src/importers/jira-importer.js +75 -0
  166. package/dist/src/importers/jira-importer.js.map +1 -1
  167. package/dist/src/integrations/jira/jira-token-provider.d.ts +93 -0
  168. package/dist/src/integrations/jira/jira-token-provider.d.ts.map +1 -0
  169. package/dist/src/integrations/jira/jira-token-provider.js +160 -0
  170. package/dist/src/integrations/jira/jira-token-provider.js.map +1 -0
  171. package/dist/src/sync/ado-reconciler.d.ts +92 -0
  172. package/dist/src/sync/ado-reconciler.d.ts.map +1 -0
  173. package/dist/src/sync/ado-reconciler.js +335 -0
  174. package/dist/src/sync/ado-reconciler.js.map +1 -0
  175. package/dist/src/sync/jira-reconciler.d.ts +106 -0
  176. package/dist/src/sync/jira-reconciler.d.ts.map +1 -0
  177. package/dist/src/sync/jira-reconciler.js +405 -0
  178. package/dist/src/sync/jira-reconciler.js.map +1 -0
  179. package/dist/src/types/model-selection.d.ts +6 -4
  180. package/dist/src/types/model-selection.d.ts.map +1 -1
  181. package/dist/src/types/model-selection.js +3 -1
  182. package/dist/src/types/model-selection.js.map +1 -1
  183. package/dist/src/utils/cross-cutting-detector.d.ts +66 -0
  184. package/dist/src/utils/cross-cutting-detector.d.ts.map +1 -0
  185. package/dist/src/utils/cross-cutting-detector.js +179 -0
  186. package/dist/src/utils/cross-cutting-detector.js.map +1 -0
  187. package/dist/src/utils/external-tool-drift-detector.d.ts +1 -1
  188. package/dist/src/utils/external-tool-drift-detector.d.ts.map +1 -1
  189. package/dist/src/utils/external-tool-drift-detector.js +5 -4
  190. package/dist/src/utils/external-tool-drift-detector.js.map +1 -1
  191. package/dist/src/utils/feature-id-derivation.d.ts +8 -3
  192. package/dist/src/utils/feature-id-derivation.d.ts.map +1 -1
  193. package/dist/src/utils/feature-id-derivation.js +14 -6
  194. package/dist/src/utils/feature-id-derivation.js.map +1 -1
  195. package/dist/src/utils/model-selection.d.ts +3 -4
  196. package/dist/src/utils/model-selection.d.ts.map +1 -1
  197. package/dist/src/utils/model-selection.js +3 -4
  198. package/dist/src/utils/model-selection.js.map +1 -1
  199. package/dist/src/utils/project-detection.d.ts +12 -8
  200. package/dist/src/utils/project-detection.d.ts.map +1 -1
  201. package/dist/src/utils/project-detection.js +13 -19
  202. package/dist/src/utils/project-detection.js.map +1 -1
  203. package/package.json +1 -1
  204. package/plugins/specweave/agents/code-standards-detective/AGENT.md +48 -0
  205. package/plugins/specweave/commands/specweave-costs.md +4 -4
  206. package/plugins/specweave/commands/specweave-do.md +9 -9
  207. package/plugins/specweave/commands/specweave-done.md +13 -0
  208. package/plugins/specweave/commands/specweave-status.md +64 -0
  209. package/plugins/specweave/commands/specweave-validate.md +27 -1
  210. package/plugins/specweave/hooks/hooks.json +11 -1
  211. package/plugins/specweave/hooks/spec-project-validator.sh +81 -25
  212. package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +135 -0
  213. package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +34 -0
  214. package/plugins/specweave/scripts/read-costs.sh +3 -3
  215. package/plugins/specweave/skills/code-standards-analyzer/SKILL.md +58 -6
  216. package/plugins/specweave/skills/increment-planner/SKILL.md +135 -29
  217. package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +4 -2
  218. package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +2 -1
  219. package/plugins/specweave/skills/increment-planner/templates/tasks-multi-project.md +1 -1
  220. package/plugins/specweave/skills/increment-planner/templates/tasks-single-project.md +1 -1
  221. package/plugins/specweave/skills/spec-generator/SKILL.md +78 -7
  222. package/plugins/specweave-ado/commands/cleanup-duplicates.md +212 -0
  223. package/plugins/specweave-ado/commands/reconcile.md +120 -0
  224. package/plugins/specweave-ado/lib/ado-duplicate-detector.js +279 -0
  225. package/plugins/specweave-ado/lib/ado-duplicate-detector.ts +407 -0
  226. package/plugins/specweave-github/agents/github-manager/AGENT.md +2 -2
  227. package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
  228. package/plugins/specweave-jira/agents/jira-manager/AGENT.md +1 -1
  229. package/plugins/specweave-jira/agents/jira-multi-project-mapper/AGENT.md +530 -0
  230. package/plugins/specweave-jira/agents/jira-sync-judge/AGENT.md +438 -0
  231. package/plugins/specweave-jira/commands/cleanup-duplicates.md +219 -0
  232. package/plugins/specweave-jira/commands/close.md +297 -0
  233. package/plugins/specweave-jira/commands/create.md +198 -0
  234. package/plugins/specweave-jira/commands/reconcile.md +123 -0
  235. package/plugins/specweave-jira/commands/status.md +215 -0
  236. package/plugins/specweave-jira/lib/jira-duplicate-detector.js +296 -0
  237. package/plugins/specweave-jira/lib/jira-duplicate-detector.ts +434 -0
  238. package/plugins/specweave-jira/lib/jira-permission-gate.js +160 -0
  239. package/plugins/specweave-jira/lib/jira-permission-gate.ts +276 -0
  240. package/plugins/specweave-jira/lib/jira-profile-resolver.js +222 -0
  241. package/plugins/specweave-jira/lib/jira-profile-resolver.ts +427 -0
  242. package/plugins/specweave-jira/reference/jira-specweave-mapping.md +16 -11
  243. package/plugins/specweave-release/commands/specweave-release-npm.md +140 -14
  244. package/plugins/specweave/commands/specweave-switch-project.md +0 -168
@@ -408,9 +408,15 @@ Full standards: .specweave/docs/internal/governance/coding-standards.md"
408
408
  ### Supported Languages
409
409
  - ✅ TypeScript (primary)
410
410
  - ✅ JavaScript (ES6+)
411
- - 🔜 Python (future)
412
- - 🔜 Java (future)
413
- - 🔜 Go (future)
411
+ - Python (pyproject.toml, .pylintrc, ruff.toml, .flake8, mypy.ini)
412
+ - Java/Kotlin (checkstyle.xml, pmd.xml, spotbugs.xml, detekt.yml)
413
+ - Go (go.mod, .golangci.yml, staticcheck.conf)
414
+ - ✅ C#/.NET (.editorconfig, StyleCop.json, Directory.Build.props)
415
+ - ✅ Rust (rustfmt.toml, clippy.toml, Cargo.toml)
416
+ - ✅ React (package.json, ESLint plugin:react/*)
417
+ - ✅ Angular (angular.json, ESLint @angular-eslint)
418
+ - ✅ Vue (package.json, ESLint plugin:vue/*)
419
+ - ✅ Svelte (package.json, svelte.config.js)
414
420
 
415
421
  ### Detection Algorithms
416
422
 
@@ -439,14 +445,60 @@ Full standards: .specweave/docs/internal/governance/coding-standards.md"
439
445
 
440
446
  1. **Implicit Standards**: Requires representative codebase sample
441
447
  2. **False Positives**: Anti-pattern detection may flag intentional code
442
- 3. **Language Support**: Currently TypeScript/JavaScript only
443
- 4. **Context**: Can't understand business rationale for patterns
448
+ 3. **Context**: Can't understand business rationale for patterns
449
+
450
+ ---
451
+
452
+ ## Multi-Technology Support
453
+
454
+ **Status**: ✅ Implemented (increment 0122-multi-technology-governance)
455
+
456
+ | Technology | Config Files | Status |
457
+ |------------|--------------|--------|
458
+ | TypeScript/JavaScript | `.eslintrc.*`, `.prettierrc`, `tsconfig.json` | ✅ Implemented |
459
+ | Python | `pyproject.toml`, `.pylintrc`, `ruff.toml`, `.flake8`, `mypy.ini` | ✅ Implemented |
460
+ | Go | `go.mod`, `.golangci.yml`, `staticcheck.conf` | ✅ Implemented |
461
+ | Java/Kotlin | `checkstyle.xml`, `pmd.xml`, `spotbugs.xml`, `detekt.yml` | ✅ Implemented |
462
+ | C#/.NET | `.editorconfig`, `StyleCop.json`, `Directory.Build.props` | ✅ Implemented |
463
+ | Rust | `rustfmt.toml`, `clippy.toml`, `Cargo.toml` | ✅ Implemented |
464
+ | React | ESLint + `plugin:react/*`, `package.json` | ✅ Implemented |
465
+ | Angular | `angular.json`, `.eslintrc` | ✅ Implemented |
466
+ | Vue | ESLint + `plugin:vue/*`, `vite.config.*` | ✅ Implemented |
467
+ | Svelte | `svelte.config.js`, `package.json` | ✅ Implemented |
468
+
469
+ **Output Structure:**
470
+ ```
471
+ .specweave/docs/internal/governance/
472
+ ├── coding-standards.md # Unified summary of ALL technologies
473
+ ├── shared-conventions.md # EditorConfig, Git conventions
474
+ └── standards/
475
+ ├── typescript.md
476
+ ├── python.md
477
+ ├── golang.md
478
+ ├── java.md
479
+ ├── react.md
480
+ ├── angular.md
481
+ ├── vue.md
482
+ └── svelte.md
483
+ ```
484
+
485
+ **Usage**:
486
+ ```typescript
487
+ import {
488
+ detectEcosystems,
489
+ parsePythonStandards,
490
+ parseGoStandards,
491
+ parseJavaStandards,
492
+ parseFrontendStandards,
493
+ generateStandardsMarkdown,
494
+ generateUnifiedSummary
495
+ } from 'src/core/living-docs/governance/index.js';
496
+ ```
444
497
 
445
498
  ---
446
499
 
447
500
  ## Future Enhancements
448
501
 
449
- - [ ] Multi-language support (Python, Java, Go)
450
502
  - [ ] Auto-generate ESLint rules from detected patterns
451
503
  - [ ] AI-powered suggestions from top OSS projects
452
504
  - [ ] Team-specific standards in multi-project mode
@@ -176,39 +176,68 @@ echo "Using coverageTarget: $coverageTarget"
176
176
 
177
177
  **Store these values for use in STEP 4 and STEP 7!**
178
178
 
179
- ### STEP 0B: Detect Structure Level & Select Project/Board (MANDATORY!)
179
+ ### STEP 0B: Get Project Context (MANDATORY - BLOCKING!)
180
180
 
181
- **⚠️ CRITICAL: Before generating spec.md, you MUST know the target project (and board for 2-level structures)!**
181
+ **⛔ DO NOT PROCEED TO STEP 1 WITHOUT COMPLETING THIS STEP!**
182
182
 
183
- **Structure Levels:**
184
- - **1-Level**: `internal/specs/{project}/FS-XXX/` - requires `project` in spec.md
185
- - **2-Level**: `internal/specs/{project}/{board}/FS-XXX/` - requires BOTH `project` AND `board`
183
+ Before generating ANY spec.md content, you MUST run this CLI command:
184
+
185
+ ```bash
186
+ specweave context projects
187
+ ```
186
188
 
187
- **Detection Logic** (use `src/utils/structure-level-detector.ts`):
189
+ This returns JSON with available projects and structure level:
188
190
 
189
- ```typescript
190
- import { detectStructureLevel, getRequiredSpecFields } from './utils/structure-level-detector.js';
191
-
192
- const structureConfig = detectStructureLevel(projectRoot);
193
- console.log(`Structure level: ${structureConfig.level}`);
194
- console.log(`Detection reason: ${structureConfig.detectionReason}`);
195
- console.log(`Available projects: ${structureConfig.projects.map(p => p.id).join(', ')}`);
196
-
197
- if (structureConfig.level === 2 && structureConfig.boardsByProject) {
198
- console.log('Available boards by project:');
199
- for (const [projectId, boards] of Object.entries(structureConfig.boardsByProject)) {
200
- console.log(` ${projectId}: ${boards.map(b => b.id).join(', ')}`);
201
- }
191
+ ```json
192
+ {
193
+ "level": 1,
194
+ "projects": [{"id": "my-app", "name": "My App"}],
195
+ "detectionReason": "multiProject configuration",
196
+ "source": "multi-project"
202
197
  }
203
198
  ```
204
199
 
205
- **Manual Detection:**
200
+ **For 2-level structures**, output includes boards:
201
+ ```json
202
+ {
203
+ "level": 2,
204
+ "projects": [{"id": "acme-corp", "name": "ACME Corporation"}],
205
+ "boardsByProject": {
206
+ "acme-corp": [
207
+ {"id": "digital-ops", "name": "Digital Operations"},
208
+ {"id": "mobile-team", "name": "Mobile Team"}
209
+ ]
210
+ },
211
+ "detectionReason": "ADO area path mapping configured",
212
+ "source": "ado-area-path"
213
+ }
214
+ ```
215
+
216
+ **VALIDATION RULES:**
217
+
218
+ ```
219
+ ✅ REQUIRED: Parse the JSON output and use ONLY those project/board values
220
+ ✅ REQUIRED: project field MUST match one of the returned projects[].id
221
+ ✅ REQUIRED: board field (2-level) MUST match one of boardsByProject[project].id
222
+ ❌ FORBIDDEN: Inventing or guessing project names
223
+ ❌ FORBIDDEN: Using folder name as project (e.g., "sw-olysense")
224
+ ❌ FORBIDDEN: Creating spec.md with {{PROJECT_ID}} placeholder
225
+ ❌ FORBIDDEN: Creating spec.md for 2-level without board: field
226
+ ```
227
+
228
+ **Structure Levels:**
229
+ - **1-Level**: `internal/specs/{project}/FS-XXX/` - requires `project` in spec.md
230
+ - **2-Level**: `internal/specs/{project}/{board}/FS-XXX/` - requires BOTH `project` AND `board`
231
+
232
+ **Alternative: Interactive Selection:**
206
233
  ```bash
207
- # Check if 2-level (ADO area paths or JIRA boards)
208
- jq '.sync.profiles | to_entries[] | select(.value.provider == "ado") | .value.config.areaPathMapping' .specweave/config.json
234
+ specweave context select
235
+ # Returns auto-selected or prompts for selection
236
+ ```
209
237
 
210
- # Check existing folder structure
211
- ls -la .specweave/docs/internal/specs/*/ # If sub-folders exist (not FS-XXX) → 2-level
238
+ **Get boards for a specific project (2-level):**
239
+ ```bash
240
+ specweave context boards --project=acme-corp
212
241
  ```
213
242
 
214
243
  **Project/Board Selection - ULTRA-SMART LOGIC (MANDATORY BEFORE STEP 4!):**
@@ -217,6 +246,70 @@ ls -la .specweave/docs/internal/specs/*/ # If sub-folders exist (not FS-XXX)
217
246
 
218
247
  ---
219
248
 
249
+ ### RULE 0: LEVERAGE ALL AVAILABLE CONTEXT (v0.33.0+ CRITICAL!)
250
+
251
+ **🧠 YOU ARE AN LLM WITH FULL CONTEXT ACCESS - USE IT!**
252
+
253
+ Before asking the user ANYTHING about project/board, you MUST analyze:
254
+
255
+ **1. Living Docs Structure** (`.specweave/docs/internal/specs/`):
256
+ ```bash
257
+ # List existing project folders
258
+ ls -la .specweave/docs/internal/specs/
259
+ # Example output: frontend-app/, backend-api/, mobile-app/, shared-lib/
260
+ ```
261
+ → These ARE the actual project IDs! Use them directly.
262
+
263
+ **2. Existing Increment Patterns** (`.specweave/increments/`):
264
+ ```bash
265
+ # Read recent increments to see project assignments
266
+ grep -r "^\*\*Project\*\*:" .specweave/increments/*/spec.md | tail -20
267
+ ```
268
+ → Learn from how past USs were assigned to projects.
269
+
270
+ **3. Config projectMappings** (`.specweave/config.json`):
271
+ ```bash
272
+ cat .specweave/config.json | jq '.projectMappings'
273
+ ```
274
+ → Use ACTUAL project IDs from config, not generic keywords.
275
+
276
+ **4. Git Remotes** (for repo-based projects):
277
+ ```bash
278
+ git remote -v | head -2
279
+ ```
280
+ → If repo is `myorg/frontend-app`, that's likely the project.
281
+
282
+ **5. Feature Description + US Content**:
283
+ - Analyze the feature user is describing
284
+ - Match against project patterns from above sources
285
+ - Map generic terms to actual project IDs
286
+
287
+ **MAPPING EXAMPLE:**
288
+ ```
289
+ User says: "Add login form to the frontend"
290
+ You detect: "frontend" keyword
291
+
292
+ WRONG: Assign project = "frontend" (generic, may not exist!)
293
+ RIGHT: Check living docs → find "frontend-app" folder → Assign project = "frontend-app"
294
+ ```
295
+
296
+ **RESOLUTION PRIORITY:**
297
+ ```
298
+ 1. Exact match in projectMappings keys → USE IT
299
+ 2. Exact match in living docs folders → USE IT
300
+ 3. Pattern match in recent increment specs → USE SAME PROJECT
301
+ 4. Keyword → Map to closest projectMappings/folder
302
+ 5. ONLY IF ALL ABOVE FAIL → Ask user with dropdown of valid options
303
+ ```
304
+
305
+ **FORBIDDEN:**
306
+ - ❌ Inventing project names not in config/folders
307
+ - ❌ Using generic keywords ("frontend") when actual ID exists ("frontend-app")
308
+ - ❌ Asking user when context provides clear answer
309
+ - ❌ Assigning `{{PROJECT_ID}}` placeholder
310
+
311
+ ---
312
+
220
313
  ### SMART SELECTION DECISION TREE
221
314
 
222
315
  **RULE 1: NO QUESTION IF ONLY 1 OPTION**
@@ -225,9 +318,20 @@ IF 1-level AND only 1 project → AUTO-SELECT silently
225
318
  IF 2-level AND only 1 project AND only 1 board → AUTO-SELECT silently
226
319
  ```
227
320
 
228
- **RULE 2: KEYWORD-BASED AUTO-DETECTION**
321
+ **RULE 2: KEYWORD-BASED AUTO-DETECTION (v0.33.0+)**
229
322
 
230
- Analyze feature description and US content for keywords:
323
+ Use `CrossCuttingDetector` utility for programmatic detection:
324
+
325
+ ```typescript
326
+ import { detectCrossCutting } from 'src/utils/cross-cutting-detector.js';
327
+
328
+ const result = detectCrossCutting("OAuth with React frontend and Node backend");
329
+ // result.isCrossCutting = true
330
+ // result.suggestedProjects = ["frontend", "backend"]
331
+ // result.confidence = "high"
332
+ ```
333
+
334
+ Or analyze feature description and US content for keywords:
231
335
 
232
336
  **Project-Level Keywords (1-level and 2-level):**
233
337
  ```
@@ -766,19 +870,21 @@ When creating tasks, assign optimal models:
766
870
  - Simple CRUD, configuration, setup
767
871
  - Mechanical work with defined approach
768
872
 
769
- **🧠 Sonnet** (thinking, balanced):
873
+ **💎 Opus** (best quality, default):
770
874
  - Architecture decisions
771
875
  - Multiple valid approaches
772
876
  - Integration between components
773
877
  - Complex business logic
774
878
  - Error handling strategies
775
-
776
- **💎 Opus** (critical, expensive):
777
879
  - Critical system architecture
778
880
  - Security-critical decisions
779
881
  - Performance-critical algorithms
780
882
  - Novel problem-solving
781
883
 
884
+ **🧠 Sonnet** (legacy, rarely needed):
885
+ - Use only for backwards compatibility
886
+ - Prefer Opus or Haiku instead
887
+
782
888
  ---
783
889
 
784
890
  ## Validation Checklist
@@ -8,8 +8,10 @@ created: {{DATE}}
8
8
  structure: user-stories
9
9
  test_mode: {{TEST_MODE}}
10
10
  coverage_target: {{COVERAGE_TARGET}}
11
- default_project: {{PROJECT_ID}}
12
- default_board: {{BOARD_ID}}
11
+ # MANDATORY: Run "specweave context projects" to get valid project/board IDs
12
+ # For 2-level structures: BOTH project AND board are REQUIRED
13
+ project: {{PROJECT_ID}}
14
+ board: {{BOARD_ID}}
13
15
  multi_project: true
14
16
  projects:
15
17
  - id: {{PROJECT_FE_ID}}
@@ -8,7 +8,8 @@ created: {{DATE}}
8
8
  structure: user-stories
9
9
  test_mode: {{TEST_MODE}}
10
10
  coverage_target: {{COVERAGE_TARGET}}
11
- default_project: {{PROJECT_ID}}
11
+ # MANDATORY: Run "specweave context projects" to get valid project ID
12
+ project: {{PROJECT_ID}}
12
13
  ---
13
14
 
14
15
  # Feature: {{FEATURE_TITLE}}
@@ -6,7 +6,7 @@
6
6
  - `[P]`: Parallelizable
7
7
  - `[ ]`: Not started
8
8
  - `[x]`: Completed
9
- - Model hints: ⚡ haiku, 🧠 sonnet, 💎 opus
9
+ - Model hints: ⚡ haiku (simple), 💎 opus (default)
10
10
 
11
11
  ## Phase 1: Foundation & Setup
12
12
 
@@ -6,7 +6,7 @@
6
6
  - `[P]`: Parallelizable
7
7
  - `[ ]`: Not started
8
8
  - `[x]`: Completed
9
- - Model hints: ⚡ haiku, 🧠 sonnet, 💎 opus
9
+ - Model hints: ⚡ haiku (simple), 💎 opus (default)
10
10
 
11
11
  ## Phase 1: Setup
12
12
 
@@ -66,18 +66,53 @@ board: my-board # REQUIRED for 2-level structures (ADO area paths,
66
66
  ## User Stories & Acceptance Criteria
67
67
 
68
68
  <!--
69
- ⚠️ MULTI-PROJECT MODE: If umbrella.enabled=true in config.json,
70
- user stories MUST be project-scoped! See section below.
69
+ ⚠️ PER-US PROJECT TARGETING (v0.33.0+):
70
+ Each user story MUST have **Project**: (and **Board**: for 2-level) fields.
71
+ The LLM MUST resolve these from context - see RULE 0 in increment-planner.
71
72
  -->
72
73
 
73
74
  ### US-001: [Title]
75
+ **Project**: [resolved-from-context] <!-- REQUIRED - actual project ID from config/folders -->
76
+ **Board**: [resolved-from-context] <!-- REQUIRED for 2-level structures -->
77
+
74
78
  **As a** [user type]
75
79
  **I want** [goal]
76
80
  **So that** [benefit]
77
81
 
78
82
  **Acceptance Criteria**:
79
- - [Criterion 1]
80
- - [Criterion 2]
83
+ - [ ] **AC-US1-01**: [Criterion 1]
84
+ - [ ] **AC-US1-02**: [Criterion 2]
85
+
86
+ ---
87
+
88
+ ### Per-US Project Resolution (v0.33.0+ MANDATORY)
89
+
90
+ **🧠 USE ALL AVAILABLE CONTEXT TO RESOLVE PROJECT/BOARD:**
91
+
92
+ Before generating spec.md, analyze:
93
+ 1. **Living docs folders**: `ls .specweave/docs/internal/specs/` → actual project IDs
94
+ 2. **Recent increment patterns**: `grep "**Project**:" .specweave/increments/*/spec.md`
95
+ 3. **Config projectMappings**: Exact project IDs from config
96
+ 4. **Feature keywords**: Map to actual projects (not generic terms)
97
+
98
+ **Resolution Example:**
99
+ ```
100
+ Feature: "Add OAuth login to React frontend"
101
+ Detected: "React", "frontend", "login"
102
+
103
+ Step 1: Check living docs → folders: frontend-app/, backend-api/, shared/
104
+ Step 2: "frontend" keyword → matches "frontend-app" folder
105
+ Step 3: Assign **Project**: frontend-app (NOT "frontend"!)
106
+
107
+ If cross-cutting ("OAuth" = both frontend + backend):
108
+ US-001 (Login UI) → **Project**: frontend-app
109
+ US-002 (Auth API) → **Project**: backend-api
110
+ ```
111
+
112
+ **NEVER:**
113
+ - ❌ Use generic keywords as project names ("frontend", "backend")
114
+ - ❌ Ask user when context provides the answer
115
+ - ❌ Leave `{{PROJECT_ID}}` placeholders
81
116
 
82
117
  ## Success Metrics
83
118
  [How we'll measure success]
@@ -392,9 +427,45 @@ spec_generator:
392
427
  - Multiple project folders exist in `specs/` (e.g., `sw-app-fe/`, `sw-app-be/`, `sw-app-shared/`)
393
428
  - User prompt mentions: "3 repos", "frontend repo", "backend API", "shared library"
394
429
 
395
- ### Project-Scoped User Story Format (MANDATORY in Multi-Project Mode)
430
+ ### Per-User-Story Project Targeting (v0.33.0+ PREFERRED)
431
+
432
+ **v0.33.0+ introduces per-US project targeting** - each user story specifies its target project inline:
433
+
434
+ ```markdown
435
+ ## User Stories
436
+
437
+ ### US-001: Thumbnail Upload & Comparison (P1)
438
+ **Project**: frontend-app
439
+ **Board**: ui-team <!-- 2-level structures only -->
440
+ **As a** content creator
441
+ **I want** to upload multiple thumbnail variants
442
+ **So that** I can visually evaluate my options
443
+
444
+ **Acceptance Criteria**:
445
+ - [ ] **AC-US1-01**: User can drag-and-drop up to 5 images
446
+
447
+ ---
448
+
449
+ ### US-002: CTR Prediction API (P1)
450
+ **Project**: backend-api
451
+ **Board**: ml-team <!-- 2-level structures only -->
452
+ **As a** frontend application
453
+ **I want** to call POST /predict-ctr endpoint
454
+ **So that** I can get AI-powered predictions
455
+
456
+ **Acceptance Criteria**:
457
+ - [ ] **AC-US2-01**: POST /predict-ctr accepts thumbnail image
458
+ ```
459
+
460
+ **Benefits of per-US targeting:**
461
+ - Each US syncs to correct project/repo
462
+ - Single increment can span multiple projects
463
+ - Living docs auto-grouped by project
464
+ - External tools (GitHub/JIRA/ADO) receive issues in correct project
465
+
466
+ ### Legacy Project-Scoped User Story Format (Pre-v0.33.0)
396
467
 
397
- **❌ WRONG (Single-Project Format - DO NOT USE in multi-project!):**
468
+ **❌ LEGACY (Project prefixes - still works but per-US targeting preferred):**
398
469
  ```markdown
399
470
  ## User Stories
400
471
 
@@ -405,7 +476,7 @@ As a content creator, I want to upload thumbnails...
405
476
  As a system, I want to predict click-through rates...
406
477
  ```
407
478
 
408
- **✅ CORRECT (Multi-Project Format - ALWAYS USE when umbrella detected!):**
479
+ **✅ LEGACY (Multi-Project Format with prefixes - use per-US targeting instead):**
409
480
  ```markdown
410
481
  ## User Stories by Project
411
482
 
@@ -0,0 +1,212 @@
1
+ ---
2
+ name: specweave-ado:cleanup-duplicates
3
+ description: Clean up duplicate Azure DevOps work items for a Feature. Finds work items with duplicate titles and closes all except the first created item.
4
+ justification: |
5
+ CRITICAL INCIDENT RESPONSE TOOL - DO NOT DELETE!
6
+
7
+ Why This Command Exists:
8
+ - Prevention systems work for single-process execution
9
+ - Multiple parallel Claude Code instances bypass all prevention (file-based cache, no distributed locking)
10
+ - ADO API race conditions: Time gap between "check exists" and "create work item" allows duplicates
11
+ - Historical duplicates from pre-v0.33.0 users (before prevention was added)
12
+
13
+ Evidence of Need:
14
+ - GitHub had 123 duplicate issues incident (cleaned to 29 unique) - same risk exists for ADO
15
+ - Parallel execution creates race conditions that prevention CANNOT solve
16
+ - Industry standard: Prevention + Detection + Cleanup (defense in depth)
17
+
18
+ When to Delete:
19
+ - ONLY if distributed locking implemented
20
+ - AND parallel execution tested (100+ concurrent syncs with zero duplicates)
21
+ - AND zero duplicates for 6+ months in production
22
+ ---
23
+
24
+ # Clean Up Duplicate ADO Work Items
25
+
26
+ **CRITICAL**: This command detects and closes duplicate ADO work items created by multiple syncs.
27
+
28
+ ## Usage
29
+
30
+ ```bash
31
+ /specweave-ado:cleanup-duplicates <feature-id> [--dry-run]
32
+ ```
33
+
34
+ ## What It Does
35
+
36
+ **Duplicate Detection & Cleanup**:
37
+
38
+ 1. **Find all work items** for the Feature (searches by Feature ID in title)
39
+ 2. **Group by title** (detect duplicates)
40
+ 3. **For each duplicate group**:
41
+ - Keep the **FIRST created** work item (lowest ID)
42
+ - Close all **LATER** work items with comment: "Duplicate of #XXX"
43
+ 4. **Update Feature README** with correct work item IDs
44
+
45
+ ## Examples
46
+
47
+ ### Dry Run (No Changes)
48
+
49
+ ```bash
50
+ /specweave-ado:cleanup-duplicates FS-031 --dry-run
51
+ ```
52
+
53
+ **Output**:
54
+ ```
55
+ Scanning for duplicates in Feature FS-031...
56
+ Found 25 total work items
57
+ Detected 10 duplicate groups:
58
+
59
+ Group 1: "[FS-031] External Tool Status Synchronization"
60
+ - #1250 (KEEP) - Created 2025-11-10
61
+ - #1255 (CLOSE) - Created 2025-11-11 - DUPLICATE
62
+ - #1260 (CLOSE) - Created 2025-11-12 - DUPLICATE
63
+
64
+ Group 2: "[FS-031] Multi-Project ADO Sync"
65
+ - #1251 (KEEP) - Created 2025-11-10
66
+ - #1256 (CLOSE) - Created 2025-11-11 - DUPLICATE
67
+
68
+ ...
69
+
70
+ Dry run complete!
71
+ Total work items: 25
72
+ Duplicate groups: 10
73
+ Work items to close: 15
74
+
75
+ This was a DRY RUN - no changes made.
76
+ Run without --dry-run to actually close duplicates.
77
+ ```
78
+
79
+ ### Actual Cleanup
80
+
81
+ ```bash
82
+ /specweave-ado:cleanup-duplicates FS-031
83
+ ```
84
+
85
+ **Output**:
86
+ ```
87
+ Scanning for duplicates in Feature FS-031...
88
+ Found 25 total work items
89
+ Detected 10 duplicate groups
90
+
91
+ CONFIRM: Close 15 duplicate work items? [y/N]
92
+ > y
93
+
94
+ Closing duplicates...
95
+ Closed #1255 (duplicate of #1250)
96
+ Closed #1256 (duplicate of #1251)
97
+ Closed #1260 (duplicate of #1250)
98
+ ...
99
+
100
+ Updating Feature README frontmatter...
101
+ Updated frontmatter with correct work item IDs
102
+
103
+ Cleanup complete!
104
+ Closed: 15 duplicates
105
+ Kept: 10 original work items
106
+ ```
107
+
108
+ ## Arguments
109
+
110
+ - `<feature-id>` - Feature ID (e.g., `FS-031` or just `031`)
111
+ - `--dry-run` - Preview changes without actually closing work items (optional)
112
+
113
+ ## Safety Features
114
+
115
+ - **Confirmation prompt**: Asks before closing work items (unless --dry-run)
116
+ - **Dry run mode**: Preview changes safely
117
+ - **Keeps oldest work item**: Preserves the first created item
118
+ - **Adds closure comment**: Links to the original work item
119
+ - **Updates metadata**: Fixes Feature README frontmatter
120
+
121
+ ## What Gets Closed
122
+
123
+ **Closed work items**:
124
+ - Duplicate titles (second, third, etc. occurrences)
125
+ - Closed with comment: "Duplicate of #XXX"
126
+ - Original work item kept open (or maintains its status)
127
+
128
+ **Example comment on closed duplicate**:
129
+ ```markdown
130
+ ## Duplicate of #1250
131
+
132
+ This work item was automatically closed by SpecWeave cleanup because it is a duplicate.
133
+
134
+ The original work item (#1250) contains the same content and should be used for tracking instead.
135
+
136
+ Auto-closed by SpecWeave Duplicate Cleanup
137
+ ```
138
+
139
+ ## Requirements
140
+
141
+ 1. **Azure DevOps PAT** configured (`AZURE_DEVOPS_PAT`)
142
+ 2. **Organization** configured (`AZURE_DEVOPS_ORG`)
143
+ 3. **Project** configured (`AZURE_DEVOPS_PROJECT`)
144
+ 4. **Write access** to project (for closing work items)
145
+ 5. **Feature folder exists** at `.specweave/docs/internal/specs/FS-XXX-name/`
146
+
147
+ ## When to Use
148
+
149
+ **Use this command when**:
150
+ - You see multiple work items with the same title in ADO
151
+ - Feature sync ran multiple times and created duplicates
152
+ - Feature README frontmatter got corrupted and reset
153
+ - Post-sync validation warns about duplicates
154
+
155
+ **Example warning that triggers this**:
156
+ ```
157
+ WARNING: 10 duplicate(s) detected!
158
+ Run cleanup command to resolve:
159
+ /specweave-ado:cleanup-duplicates FS-031
160
+ ```
161
+
162
+ ## Architecture
163
+
164
+ **Duplicate Detection Logic**:
165
+ 1. Query WIQL for work items with Feature ID in title
166
+ 2. Group work items by **exact title match**
167
+ 3. Within each group, sort by **work item ID** (ascending)
168
+ 4. Keep **first work item** (lowest ID = oldest)
169
+ 5. Close **all others** as duplicates via state transition
170
+
171
+ **Why lowest ID?**:
172
+ - Lower work item IDs were created first
173
+ - Preserves chronological order
174
+ - Maintains links from old documentation
175
+
176
+ ## Related Commands
177
+
178
+ - `/specweave-ado:sync` - Sync Feature to ADO (with duplicate detection)
179
+ - `/specweave-ado:reconcile` - Reconcile work item states
180
+ - `/specweave:validate` - Validate increment completeness
181
+
182
+ ## Implementation
183
+
184
+ **File**: `plugins/specweave-ado/lib/ado-duplicate-detector.ts`
185
+
186
+ **Class**: `AdoDuplicateDetector`
187
+
188
+ **Algorithm** (3-phase protection):
189
+ 1. **Detection**: WIQL query for existing work items matching pattern
190
+ 2. **Verification**: Count check to detect duplicates after creation
191
+ 3. **Reflection**: Auto-close duplicates automatically
192
+
193
+ For manual cleanup:
194
+ 1. WIQL query for all work items with Feature ID
195
+ 2. Group by title (Map<string, number[]>)
196
+ 3. Filter groups with >1 item (duplicates)
197
+ 4. For each duplicate group:
198
+ - Keep first work item (lowest ID)
199
+ - Close others via ADO REST API
200
+
201
+ ## Next Steps
202
+
203
+ After cleanup:
204
+
205
+ 1. **Verify cleanup**: Check ADO for remaining work items
206
+ 2. **Check Feature FEATURE.md**: Verify frontmatter has correct work item IDs
207
+ 3. **Re-run sync**: `/specweave-ado:sync` (should show no duplicates)
208
+ 4. **Duplicate detection**: Automatically enabled via AdoDuplicateDetector
209
+
210
+ ---
211
+
212
+ **SAFE TO USE**: This command is idempotent and safe to run multiple times.