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.
- package/CLAUDE.md +51 -9
- package/bin/specweave.js +34 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts +100 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js +291 -0
- package/dist/plugins/specweave-ado/lib/ado-duplicate-detector.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts +103 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js +310 -0
- package/dist/plugins/specweave-jira/lib/jira-duplicate-detector.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts +126 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.js +207 -0
- package/dist/plugins/specweave-jira/lib/jira-permission-gate.js.map +1 -0
- package/dist/src/adapters/codex/README.md +1 -1
- package/dist/src/adapters/codex/adapter.js +1 -1
- package/dist/src/cli/commands/archive.d.ts +2 -0
- package/dist/src/cli/commands/archive.d.ts.map +1 -1
- package/dist/src/cli/commands/archive.js +33 -0
- package/dist/src/cli/commands/archive.js.map +1 -1
- package/dist/src/cli/commands/context.d.ts +92 -0
- package/dist/src/cli/commands/context.d.ts.map +1 -0
- package/dist/src/cli/commands/context.js +205 -0
- package/dist/src/cli/commands/context.js.map +1 -0
- package/dist/src/cli/commands/init-multiproject.js +1 -1
- package/dist/src/cli/commands/init-multiproject.js.map +1 -1
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +111 -69
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/migrate-to-multiproject.js +2 -2
- package/dist/src/cli/commands/migrate-to-multiproject.js.map +1 -1
- package/dist/src/cli/helpers/init/external-import.d.ts +3 -0
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/external-import.js +17 -4
- package/dist/src/cli/helpers/init/external-import.js.map +1 -1
- package/dist/src/cli/helpers/init/index.d.ts +1 -0
- package/dist/src/cli/helpers/init/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/index.js +2 -0
- package/dist/src/cli/helpers/init/index.js.map +1 -1
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts +70 -0
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.js +214 -4
- package/dist/src/cli/helpers/init/jira-ado-auto-detect.js.map +1 -1
- package/dist/src/cli/helpers/init/living-docs-preflight.d.ts +4 -0
- package/dist/src/cli/helpers/init/living-docs-preflight.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/living-docs-preflight.js +34 -3
- package/dist/src/cli/helpers/init/living-docs-preflight.js.map +1 -1
- package/dist/src/cli/helpers/init/testing-config.d.ts +3 -0
- package/dist/src/cli/helpers/init/testing-config.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/testing-config.js +9 -2
- package/dist/src/cli/helpers/init/testing-config.js.map +1 -1
- package/dist/src/cli/helpers/init/translation-config.d.ts +3 -0
- package/dist/src/cli/helpers/init/translation-config.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/translation-config.js +21 -4
- package/dist/src/cli/helpers/init/translation-config.js.map +1 -1
- package/dist/src/cli/helpers/init/wizard-navigation.d.ts +45 -0
- package/dist/src/cli/helpers/init/wizard-navigation.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/wizard-navigation.js +97 -0
- package/dist/src/cli/helpers/init/wizard-navigation.js.map +1 -0
- package/dist/src/core/increment/increment-archiver.d.ts +25 -4
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +64 -20
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/increment/increment-utils.d.ts +65 -0
- package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
- package/dist/src/core/increment/increment-utils.js +114 -0
- package/dist/src/core/increment/increment-utils.js.map +1 -1
- package/dist/src/core/living-docs/cross-project-sync.d.ts +97 -0
- package/dist/src/core/living-docs/cross-project-sync.d.ts.map +1 -0
- package/dist/src/core/living-docs/cross-project-sync.js +135 -0
- package/dist/src/core/living-docs/cross-project-sync.js.map +1 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.d.ts +106 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.d.ts.map +1 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.js +146 -0
- package/dist/src/core/living-docs/external-sync-orchestrator.js.map +1 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts +4 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.js +32 -10
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +7 -3
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts +38 -0
- package/dist/src/core/living-docs/governance/ecosystem-detector.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/ecosystem-detector.js +325 -0
- package/dist/src/core/living-docs/governance/ecosystem-detector.js.map +1 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts +74 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.js +366 -0
- package/dist/src/core/living-docs/governance/frontend-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.d.ts +64 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.js +229 -0
- package/dist/src/core/living-docs/governance/go-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/index.d.ts +50 -0
- package/dist/src/core/living-docs/governance/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/index.js +56 -0
- package/dist/src/core/living-docs/governance/index.js.map +1 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.d.ts +89 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.js +356 -0
- package/dist/src/core/living-docs/governance/java-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.d.ts +83 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.js +347 -0
- package/dist/src/core/living-docs/governance/python-standards-parser.js.map +1 -0
- package/dist/src/core/living-docs/governance/standards-generator.d.ts +38 -0
- package/dist/src/core/living-docs/governance/standards-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/governance/standards-generator.js +476 -0
- package/dist/src/core/living-docs/governance/standards-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +54 -2
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +5 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +358 -30
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +44 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +7 -3
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +94 -10
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/module-analyzer.d.ts +22 -0
- package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -1
- package/dist/src/core/living-docs/module-analyzer.js +123 -19
- package/dist/src/core/living-docs/module-analyzer.js.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/generators.d.ts +8 -1
- package/dist/src/core/living-docs/sync-helpers/generators.d.ts.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/generators.js +18 -1
- package/dist/src/core/living-docs/sync-helpers/generators.js.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/index.d.ts +1 -1
- package/dist/src/core/living-docs/sync-helpers/index.d.ts.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/index.js.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/parsers.d.ts +3 -1
- package/dist/src/core/living-docs/sync-helpers/parsers.d.ts.map +1 -1
- package/dist/src/core/living-docs/sync-helpers/parsers.js +24 -2
- package/dist/src/core/living-docs/sync-helpers/parsers.js.map +1 -1
- package/dist/src/core/living-docs/types.d.ts +6 -0
- package/dist/src/core/living-docs/types.d.ts.map +1 -1
- package/dist/src/core/living-docs/validators/index.d.ts +7 -0
- package/dist/src/core/living-docs/validators/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/validators/index.js +7 -0
- package/dist/src/core/living-docs/validators/index.js.map +1 -0
- package/dist/src/core/living-docs/validators/project-validator.d.ts +92 -0
- package/dist/src/core/living-docs/validators/project-validator.d.ts.map +1 -0
- package/dist/src/core/living-docs/validators/project-validator.js +142 -0
- package/dist/src/core/living-docs/validators/project-validator.js.map +1 -0
- package/dist/src/core/llm/provider-factory.js +2 -2
- package/dist/src/core/llm/provider-factory.js.map +1 -1
- package/dist/src/core/llm/providers/anthropic-provider.js +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.js +8 -4
- package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
- package/dist/src/core/project/project-manager.d.ts.map +1 -1
- package/dist/src/core/project/project-manager.js +19 -17
- package/dist/src/core/project/project-manager.js.map +1 -1
- package/dist/src/core/types/config.d.ts +4 -2
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +34 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/importers/jira-importer.d.ts +14 -0
- package/dist/src/importers/jira-importer.d.ts.map +1 -1
- package/dist/src/importers/jira-importer.js +75 -0
- package/dist/src/importers/jira-importer.js.map +1 -1
- package/dist/src/integrations/jira/jira-token-provider.d.ts +93 -0
- package/dist/src/integrations/jira/jira-token-provider.d.ts.map +1 -0
- package/dist/src/integrations/jira/jira-token-provider.js +160 -0
- package/dist/src/integrations/jira/jira-token-provider.js.map +1 -0
- package/dist/src/sync/ado-reconciler.d.ts +92 -0
- package/dist/src/sync/ado-reconciler.d.ts.map +1 -0
- package/dist/src/sync/ado-reconciler.js +335 -0
- package/dist/src/sync/ado-reconciler.js.map +1 -0
- package/dist/src/sync/jira-reconciler.d.ts +106 -0
- package/dist/src/sync/jira-reconciler.d.ts.map +1 -0
- package/dist/src/sync/jira-reconciler.js +405 -0
- package/dist/src/sync/jira-reconciler.js.map +1 -0
- package/dist/src/types/model-selection.d.ts +6 -4
- package/dist/src/types/model-selection.d.ts.map +1 -1
- package/dist/src/types/model-selection.js +3 -1
- package/dist/src/types/model-selection.js.map +1 -1
- package/dist/src/utils/cross-cutting-detector.d.ts +66 -0
- package/dist/src/utils/cross-cutting-detector.d.ts.map +1 -0
- package/dist/src/utils/cross-cutting-detector.js +179 -0
- package/dist/src/utils/cross-cutting-detector.js.map +1 -0
- package/dist/src/utils/external-tool-drift-detector.d.ts +1 -1
- package/dist/src/utils/external-tool-drift-detector.d.ts.map +1 -1
- package/dist/src/utils/external-tool-drift-detector.js +5 -4
- package/dist/src/utils/external-tool-drift-detector.js.map +1 -1
- package/dist/src/utils/feature-id-derivation.d.ts +8 -3
- package/dist/src/utils/feature-id-derivation.d.ts.map +1 -1
- package/dist/src/utils/feature-id-derivation.js +14 -6
- package/dist/src/utils/feature-id-derivation.js.map +1 -1
- package/dist/src/utils/model-selection.d.ts +3 -4
- package/dist/src/utils/model-selection.d.ts.map +1 -1
- package/dist/src/utils/model-selection.js +3 -4
- package/dist/src/utils/model-selection.js.map +1 -1
- package/dist/src/utils/project-detection.d.ts +12 -8
- package/dist/src/utils/project-detection.d.ts.map +1 -1
- package/dist/src/utils/project-detection.js +13 -19
- package/dist/src/utils/project-detection.js.map +1 -1
- package/package.json +1 -1
- package/plugins/specweave/agents/code-standards-detective/AGENT.md +48 -0
- package/plugins/specweave/commands/specweave-costs.md +4 -4
- package/plugins/specweave/commands/specweave-do.md +9 -9
- package/plugins/specweave/commands/specweave-done.md +13 -0
- package/plugins/specweave/commands/specweave-status.md +64 -0
- package/plugins/specweave/commands/specweave-validate.md +27 -1
- package/plugins/specweave/hooks/hooks.json +11 -1
- package/plugins/specweave/hooks/spec-project-validator.sh +81 -25
- package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +135 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +34 -0
- package/plugins/specweave/scripts/read-costs.sh +3 -3
- package/plugins/specweave/skills/code-standards-analyzer/SKILL.md +58 -6
- package/plugins/specweave/skills/increment-planner/SKILL.md +135 -29
- package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +4 -2
- package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +2 -1
- package/plugins/specweave/skills/increment-planner/templates/tasks-multi-project.md +1 -1
- package/plugins/specweave/skills/increment-planner/templates/tasks-single-project.md +1 -1
- package/plugins/specweave/skills/spec-generator/SKILL.md +78 -7
- package/plugins/specweave-ado/commands/cleanup-duplicates.md +212 -0
- package/plugins/specweave-ado/commands/reconcile.md +120 -0
- package/plugins/specweave-ado/lib/ado-duplicate-detector.js +279 -0
- package/plugins/specweave-ado/lib/ado-duplicate-detector.ts +407 -0
- package/plugins/specweave-github/agents/github-manager/AGENT.md +2 -2
- package/plugins/specweave-infrastructure/skills/hetzner-provisioner/README.md +1 -1
- package/plugins/specweave-jira/agents/jira-manager/AGENT.md +1 -1
- package/plugins/specweave-jira/agents/jira-multi-project-mapper/AGENT.md +530 -0
- package/plugins/specweave-jira/agents/jira-sync-judge/AGENT.md +438 -0
- package/plugins/specweave-jira/commands/cleanup-duplicates.md +219 -0
- package/plugins/specweave-jira/commands/close.md +297 -0
- package/plugins/specweave-jira/commands/create.md +198 -0
- package/plugins/specweave-jira/commands/reconcile.md +123 -0
- package/plugins/specweave-jira/commands/status.md +215 -0
- package/plugins/specweave-jira/lib/jira-duplicate-detector.js +296 -0
- package/plugins/specweave-jira/lib/jira-duplicate-detector.ts +434 -0
- package/plugins/specweave-jira/lib/jira-permission-gate.js +160 -0
- package/plugins/specweave-jira/lib/jira-permission-gate.ts +276 -0
- package/plugins/specweave-jira/lib/jira-profile-resolver.js +222 -0
- package/plugins/specweave-jira/lib/jira-profile-resolver.ts +427 -0
- package/plugins/specweave-jira/reference/jira-specweave-mapping.md +16 -11
- package/plugins/specweave-release/commands/specweave-release-npm.md +140 -14
- 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
|
-
-
|
|
412
|
-
-
|
|
413
|
-
-
|
|
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. **
|
|
443
|
-
|
|
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:
|
|
179
|
+
### STEP 0B: Get Project Context (MANDATORY - BLOCKING!)
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
**⛔ DO NOT PROCEED TO STEP 1 WITHOUT COMPLETING THIS STEP!**
|
|
182
182
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
Before generating ANY spec.md content, you MUST run this CLI command:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
specweave context projects
|
|
187
|
+
```
|
|
186
188
|
|
|
187
|
-
|
|
189
|
+
This returns JSON with available projects and structure level:
|
|
188
190
|
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
208
|
-
|
|
234
|
+
specweave context select
|
|
235
|
+
# Returns auto-selected or prompts for selection
|
|
236
|
+
```
|
|
209
237
|
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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
|
-
|
|
11
|
+
# MANDATORY: Run "specweave context projects" to get valid project ID
|
|
12
|
+
project: {{PROJECT_ID}}
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
# Feature: {{FEATURE_TITLE}}
|
|
@@ -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
|
-
⚠️
|
|
70
|
-
|
|
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
|
-
-
|
|
80
|
-
-
|
|
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
|
-
###
|
|
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
|
-
**❌
|
|
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
|
-
**✅
|
|
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.
|