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.
- package/CLAUDE.md +215 -2
- package/README.md +22 -0
- package/bin/specweave.js +52 -1
- 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/cache.d.ts +17 -0
- package/dist/src/cli/commands/cache.d.ts.map +1 -0
- package/dist/src/cli/commands/cache.js +126 -0
- package/dist/src/cli/commands/cache.js.map +1 -0
- 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.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +112 -70
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/plan/increment-detector.js +2 -2
- package/dist/src/cli/commands/plan/increment-detector.js.map +1 -1
- package/dist/src/cli/commands/sync-spec-commits.js +1 -1
- package/dist/src/cli/commands/sync-spec-commits.js.map +1 -1
- package/dist/src/cli/commands/sync-specs.js +2 -2
- package/dist/src/cli/commands/sync-specs.js.map +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.js +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.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/cli/workers/living-docs-worker.js +66 -1
- package/dist/src/cli/workers/living-docs-worker.js.map +1 -1
- package/dist/src/config/types.d.ts +203 -1208
- package/dist/src/config/types.d.ts.map +1 -1
- package/dist/src/core/discrepancy/increment-generator.d.ts.map +1 -1
- package/dist/src/core/discrepancy/increment-generator.js +5 -2
- package/dist/src/core/discrepancy/increment-generator.js.map +1 -1
- package/dist/src/core/increment/duplicate-detector.js +2 -2
- package/dist/src/core/increment/duplicate-detector.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +49 -4
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +123 -22
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/increment/increment-status.js +2 -2
- package/dist/src/core/increment/increment-status.js.map +1 -1
- package/dist/src/core/increment/increment-utils.d.ts +150 -0
- package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
- package/dist/src/core/increment/increment-utils.js +216 -4
- package/dist/src/core/increment/increment-utils.js.map +1 -1
- package/dist/src/core/increment/metadata-validator.js +1 -1
- package/dist/src/core/increment/metadata-validator.js.map +1 -1
- 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 +8 -4
- 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/hierarchy-mapper.js +3 -3
- package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts +18 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +299 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts +15 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +138 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts +24 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js +198 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts +17 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js +241 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts +28 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.js +197 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +22 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +482 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts +42 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js +343 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +190 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.js +7 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.js.map +1 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts +11 -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 +53 -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/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/sync/spec-increment-mapper.js +3 -3
- package/dist/src/core/sync/spec-increment-mapper.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +25 -0
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +135 -5
- package/dist/src/importers/item-converter.js.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/init/architecture/types.d.ts +33 -140
- package/dist/src/init/architecture/types.d.ts.map +1 -1
- package/dist/src/init/compliance/types.d.ts +30 -27
- package/dist/src/init/compliance/types.d.ts.map +1 -1
- package/dist/src/init/repo/types.d.ts +11 -34
- package/dist/src/init/repo/types.d.ts.map +1 -1
- package/dist/src/init/research/src/config/types.d.ts +15 -82
- package/dist/src/init/research/src/config/types.d.ts.map +1 -1
- package/dist/src/init/research/types.d.ts +38 -93
- package/dist/src/init/research/types.d.ts.map +1 -1
- package/dist/src/init/team/types.d.ts +4 -42
- package/dist/src/init/team/types.d.ts.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/dashboard-cache.d.ts +181 -0
- package/dist/src/types/dashboard-cache.d.ts.map +1 -0
- package/dist/src/types/dashboard-cache.js +65 -0
- package/dist/src/types/dashboard-cache.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/docs-validator.d.ts +131 -0
- package/dist/src/utils/docs-validator.d.ts.map +1 -0
- package/dist/src/utils/docs-validator.js +529 -0
- package/dist/src/utils/docs-validator.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-collision.js +1 -1
- package/dist/src/utils/feature-id-collision.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/html-to-mdx.d.ts +1 -0
- package/dist/src/utils/html-to-mdx.d.ts.map +1 -1
- package/dist/src/utils/html-to-mdx.js +43 -5
- package/dist/src/utils/html-to-mdx.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/package.json +1 -1
- package/plugins/specweave/agents/code-standards-detective/AGENT.md +48 -0
- package/plugins/specweave/agents/pm/AGENT.md +10 -7
- package/plugins/specweave/commands/specweave-archive-features.md +5 -7
- package/plugins/specweave/commands/specweave-archive.md +2 -1
- package/plugins/specweave/commands/specweave-costs.md +4 -4
- package/plugins/specweave/commands/specweave-do.md +44 -10
- package/plugins/specweave/commands/specweave-done.md +109 -0
- package/plugins/specweave/commands/specweave-import-external.md +45 -18
- package/plugins/specweave/commands/specweave-increment.md +331 -33
- package/plugins/specweave/commands/specweave-jobs.md +2 -2
- package/plugins/specweave/commands/specweave-progress.md +4 -4
- package/plugins/specweave/commands/specweave-restore-feature.md +5 -4
- package/plugins/specweave/commands/specweave-sync-docs.md +1 -1
- package/plugins/specweave/commands/specweave-sync-specs.md +216 -322
- package/plugins/specweave/commands/specweave-validate-features.md +13 -8
- package/plugins/specweave/commands/specweave-validate.md +27 -1
- package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
- package/plugins/specweave/hooks/hooks.json +43 -4
- package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
- package/plugins/specweave/hooks/lib/common-setup.sh +375 -0
- package/plugins/specweave/hooks/lib/crash-prevention.sh +336 -0
- package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
- package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
- package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
- package/plugins/specweave/hooks/post-task-completion.sh +4 -23
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh +1 -6
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
- package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
- package/plugins/specweave/hooks/pre-task-completion.sh +8 -37
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
- package/plugins/specweave/hooks/pre-tool-use.sh +2 -11
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
- package/plugins/specweave/hooks/spec-project-validator.sh +80 -25
- package/plugins/specweave/hooks/universal/dispatcher.mjs +135 -42
- package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +183 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +140 -38
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +12 -0
- package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +89 -0
- package/plugins/specweave/hooks/v2/guards/bash-file-guard.sh +211 -0
- package/plugins/specweave/hooks/v2/guards/bash-file-guard.test.sh +163 -0
- package/plugins/specweave/hooks/v2/guards/completion-guard.sh +26 -28
- package/plugins/specweave/hooks/v2/guards/features-folder-guard.sh +50 -0
- package/plugins/specweave/hooks/v2/guards/increment-duplicate-guard.sh +135 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js +2 -2
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js.map +1 -1
- package/plugins/specweave/scripts/README.md +166 -0
- package/plugins/specweave/scripts/cleanup-state.sh +142 -0
- package/plugins/specweave/scripts/force-kill.sh +142 -0
- package/plugins/specweave/scripts/jobs.js +171 -0
- package/plugins/specweave/scripts/progress.js +170 -0
- package/plugins/specweave/scripts/read-costs.sh +132 -0
- package/plugins/specweave/scripts/read-jobs.sh +324 -0
- package/plugins/specweave/scripts/read-progress.sh +185 -0
- package/plugins/specweave/scripts/read-status.sh +146 -0
- package/plugins/specweave/scripts/read-workflow.sh +173 -0
- package/plugins/specweave/scripts/rebuild-dashboard-cache.sh +327 -0
- package/plugins/specweave/scripts/session-watchdog.sh +192 -0
- package/plugins/specweave/scripts/status.js +154 -0
- package/plugins/specweave/scripts/update-dashboard-cache.sh +281 -0
- package/plugins/specweave/skills/code-standards-analyzer/SKILL.md +58 -6
- package/plugins/specweave/skills/increment-planner/SKILL.md +388 -48
- package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +17 -7
- package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +6 -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/instant-status/SKILL.md +70 -0
- package/plugins/specweave-ado/commands/cleanup-duplicates.md +212 -0
- package/plugins/specweave-ado/commands/reconcile.md +120 -0
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -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-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-docs/commands/build.md +32 -4
- package/plugins/specweave-docs/commands/preview.md +43 -1
- package/plugins/specweave-docs/commands/validate.md +250 -0
- package/plugins/specweave-github/agents/github-manager/AGENT.md +2 -2
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1262 -0
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
- package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
- 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/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -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-release/hooks/.specweave/logs/dora-tracking.log +1254 -0
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
- package/plugins/specweave/hooks/post-edit-spec.sh +0 -265
- package/plugins/specweave/hooks/post-write-spec.sh +0 -267
- package/plugins/specweave/hooks/pre-edit-spec.sh +0 -151
- package/plugins/specweave/hooks/pre-write-spec.sh +0 -151
|
@@ -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.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specweave-ado:reconcile
|
|
3
|
+
description: Reconcile Azure DevOps work item states with increment statuses. Fixes drift by closing work items for completed increments and reactivating work items for resumed increments.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Azure DevOps Status Reconciliation
|
|
7
|
+
|
|
8
|
+
Scan all increments and fix any drift between local metadata.json status and ADO work item states.
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
/specweave-ado:reconcile [options]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Options
|
|
17
|
+
|
|
18
|
+
- `--dry-run`: Preview changes without making them
|
|
19
|
+
- `--verbose`: Show detailed output for each work item checked
|
|
20
|
+
|
|
21
|
+
## What It Does
|
|
22
|
+
|
|
23
|
+
1. **Scans** all non-archived increments
|
|
24
|
+
2. **Compares** metadata.json status with ADO work item state
|
|
25
|
+
3. **Fixes** mismatches:
|
|
26
|
+
- `metadata=completed` + `ADO=Active` → **Close** the work item
|
|
27
|
+
- `metadata=in-progress` + `ADO=Closed` → **Reactivate** the work item
|
|
28
|
+
|
|
29
|
+
## When to Use
|
|
30
|
+
|
|
31
|
+
- After manual metadata.json edits
|
|
32
|
+
- After git pulls that changed increment statuses
|
|
33
|
+
- When you notice active work items for completed work
|
|
34
|
+
- As a periodic health check
|
|
35
|
+
|
|
36
|
+
## Implementation
|
|
37
|
+
|
|
38
|
+
Run the reconciliation using the AdoReconciler:
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { AdoReconciler } from '../../../src/sync/ado-reconciler.js';
|
|
42
|
+
|
|
43
|
+
const reconciler = new AdoReconciler({
|
|
44
|
+
projectRoot: process.cwd(),
|
|
45
|
+
dryRun: args.includes('--dry-run'),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const result = await reconciler.reconcile();
|
|
49
|
+
|
|
50
|
+
// Report results
|
|
51
|
+
console.log(`\nReconciliation complete:`);
|
|
52
|
+
console.log(` Scanned: ${result.scanned} increments`);
|
|
53
|
+
console.log(` Fixed: ${result.closed} closed, ${result.reopened} reopened`);
|
|
54
|
+
if (result.errors.length > 0) {
|
|
55
|
+
console.log(` Errors: ${result.errors.length}`);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Example Output
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
📊 Scanning 5 increment(s) for ADO state drift...
|
|
63
|
+
|
|
64
|
+
✅ Work Item #1234 (0056-plugin-fix/US-001): State matches (Active)
|
|
65
|
+
❌ Work Item #1240 (0066-import-wizard/US-003): Active but should be CLOSED (status=completed)
|
|
66
|
+
✅ Closed work item #1240
|
|
67
|
+
❌ Work Item #1238 (0063-multi-repo/US-001): CLOSED but should be ACTIVE (status=in-progress)
|
|
68
|
+
✅ Reactivated work item #1238
|
|
69
|
+
|
|
70
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
71
|
+
📊 ADO RECONCILIATION SUMMARY
|
|
72
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
73
|
+
Increments scanned: 5
|
|
74
|
+
Mismatches found: 2
|
|
75
|
+
Work items closed: 1
|
|
76
|
+
Work items reopened: 1
|
|
77
|
+
Errors: 0
|
|
78
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Dry Run Mode
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
/specweave-ado:reconcile --dry-run
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Shows what would be changed without making any modifications:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
❌ Work Item #1240 (0066-import-wizard/US-003): Active but should be CLOSED
|
|
91
|
+
[DRY RUN] Would close work item #1240
|
|
92
|
+
|
|
93
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
94
|
+
📊 ADO RECONCILIATION SUMMARY
|
|
95
|
+
⚠️ DRY RUN - No changes were made
|
|
96
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Requirements
|
|
100
|
+
|
|
101
|
+
- Azure DevOps PAT configured (`AZURE_DEVOPS_PAT`)
|
|
102
|
+
- `sync.ado.enabled = true` in config.json
|
|
103
|
+
- `sync.settings.canUpdateExternalItems = true` in config.json
|
|
104
|
+
|
|
105
|
+
## ADO Status Mapping
|
|
106
|
+
|
|
107
|
+
| SpecWeave Status | Expected ADO State |
|
|
108
|
+
|-----------------|-------------------|
|
|
109
|
+
| `completed` | Closed, Done, Resolved |
|
|
110
|
+
| `abandoned` | Closed, Removed |
|
|
111
|
+
| `in-progress` | Active, In Progress |
|
|
112
|
+
| `active` | Active, New |
|
|
113
|
+
| `planning` | New |
|
|
114
|
+
|
|
115
|
+
## Related Commands
|
|
116
|
+
|
|
117
|
+
- `/specweave-ado:status`: View sync status for increments
|
|
118
|
+
- `/specweave-ado:sync`: Manual sync to ADO
|
|
119
|
+
- `/specweave:done`: Close increment (triggers auto-close)
|
|
120
|
+
- `/specweave:resume`: Resume increment (now triggers auto-reopen)
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# ============================================================================
|
|
4
|
+
# Post Living Docs Update Hook - Azure DevOps Sync
|
|
5
|
+
# ============================================================================
|
|
6
|
+
#
|
|
7
|
+
# Triggered after living docs are updated to sync with Azure DevOps.
|
|
8
|
+
# CRITICAL: External tool status ALWAYS wins in conflicts!
|
|
9
|
+
#
|
|
10
|
+
# Triggers:
|
|
11
|
+
# 1. After /specweave:done (increment completion)
|
|
12
|
+
# 2. After /specweave:sync-docs update
|
|
13
|
+
# 3. After manual spec edits
|
|
14
|
+
# 4. After webhook from ADO
|
|
15
|
+
#
|
|
16
|
+
# ============================================================================
|
|
17
|
+
|
|
18
|
+
set -e
|
|
19
|
+
|
|
20
|
+
# Configuration
|
|
21
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
22
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
|
23
|
+
LIVING_DOCS_DIR="$PROJECT_ROOT/.specweave/docs/internal/specs"
|
|
24
|
+
LOG_FILE="$PROJECT_ROOT/.specweave/logs/ado-sync.log"
|
|
25
|
+
DEBUG=${DEBUG:-0}
|
|
26
|
+
|
|
27
|
+
# Ensure log directory exists
|
|
28
|
+
mkdir -p "$(dirname "$LOG_FILE")"
|
|
29
|
+
|
|
30
|
+
# ============================================================================
|
|
31
|
+
# Logging
|
|
32
|
+
# ============================================================================
|
|
33
|
+
|
|
34
|
+
log() {
|
|
35
|
+
local level=$1
|
|
36
|
+
shift
|
|
37
|
+
local message="$@"
|
|
38
|
+
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
|
39
|
+
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
|
|
40
|
+
[ "$DEBUG" -eq 1 ] && echo "[$level] $message" >&2
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
log_info() {
|
|
44
|
+
log "INFO" "$@"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
log_error() {
|
|
48
|
+
log "ERROR" "$@"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
log_debug() {
|
|
52
|
+
[ "$DEBUG" -eq 1 ] && log "DEBUG" "$@"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# ============================================================================
|
|
56
|
+
# External Tool Detection
|
|
57
|
+
# ============================================================================
|
|
58
|
+
|
|
59
|
+
detect_external_tool() {
|
|
60
|
+
local spec_path=$1
|
|
61
|
+
|
|
62
|
+
# Check for external links in spec metadata
|
|
63
|
+
if grep -q "externalLinks:" "$spec_path"; then
|
|
64
|
+
if grep -q "ado:" "$spec_path"; then
|
|
65
|
+
echo "ado"
|
|
66
|
+
elif grep -q "jira:" "$spec_path"; then
|
|
67
|
+
echo "jira"
|
|
68
|
+
elif grep -q "github:" "$spec_path"; then
|
|
69
|
+
echo "github"
|
|
70
|
+
fi
|
|
71
|
+
fi
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# ============================================================================
|
|
75
|
+
# Status Mapping
|
|
76
|
+
# ============================================================================
|
|
77
|
+
|
|
78
|
+
map_ado_status_to_local() {
|
|
79
|
+
local ado_status=$1
|
|
80
|
+
|
|
81
|
+
case "$ado_status" in
|
|
82
|
+
"New")
|
|
83
|
+
echo "draft"
|
|
84
|
+
;;
|
|
85
|
+
"Active")
|
|
86
|
+
echo "in-progress"
|
|
87
|
+
;;
|
|
88
|
+
"Resolved")
|
|
89
|
+
echo "implemented"
|
|
90
|
+
;;
|
|
91
|
+
"Closed")
|
|
92
|
+
echo "complete"
|
|
93
|
+
;;
|
|
94
|
+
"In Review"|"In QA")
|
|
95
|
+
echo "in-qa"
|
|
96
|
+
;;
|
|
97
|
+
*)
|
|
98
|
+
echo "unknown"
|
|
99
|
+
;;
|
|
100
|
+
esac
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
map_local_status_to_ado() {
|
|
104
|
+
local local_status=$1
|
|
105
|
+
|
|
106
|
+
case "$local_status" in
|
|
107
|
+
"draft")
|
|
108
|
+
echo "New"
|
|
109
|
+
;;
|
|
110
|
+
"in-progress")
|
|
111
|
+
echo "Active"
|
|
112
|
+
;;
|
|
113
|
+
"implemented")
|
|
114
|
+
echo "Resolved"
|
|
115
|
+
;;
|
|
116
|
+
"complete")
|
|
117
|
+
echo "Closed"
|
|
118
|
+
;;
|
|
119
|
+
"in-qa")
|
|
120
|
+
echo "In Review"
|
|
121
|
+
;;
|
|
122
|
+
*)
|
|
123
|
+
echo "Active"
|
|
124
|
+
;;
|
|
125
|
+
esac
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# ============================================================================
|
|
129
|
+
# ADO API Functions
|
|
130
|
+
# ============================================================================
|
|
131
|
+
|
|
132
|
+
get_ado_work_item_status() {
|
|
133
|
+
local work_item_id=$1
|
|
134
|
+
local org="${AZURE_DEVOPS_ORG}"
|
|
135
|
+
local project="${AZURE_DEVOPS_PROJECT}"
|
|
136
|
+
local pat="${AZURE_DEVOPS_PAT}"
|
|
137
|
+
|
|
138
|
+
if [ -z "$org" ] || [ -z "$pat" ]; then
|
|
139
|
+
log_error "ADO credentials not configured"
|
|
140
|
+
return 1
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
local api_url="https://dev.azure.com/${org}/${project}/_apis/wit/workitems/${work_item_id}?api-version=7.0"
|
|
144
|
+
|
|
145
|
+
log_debug "Fetching ADO work item $work_item_id status"
|
|
146
|
+
|
|
147
|
+
local response=$(curl -s -u ":${pat}" \
|
|
148
|
+
-H "Content-Type: application/json" \
|
|
149
|
+
"$api_url")
|
|
150
|
+
|
|
151
|
+
if [ $? -ne 0 ]; then
|
|
152
|
+
log_error "Failed to fetch ADO work item status"
|
|
153
|
+
return 1
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# Extract status from response
|
|
157
|
+
local status=$(echo "$response" | jq -r '.fields["System.State"]')
|
|
158
|
+
|
|
159
|
+
if [ "$status" = "null" ] || [ -z "$status" ]; then
|
|
160
|
+
log_error "Could not extract status from ADO response"
|
|
161
|
+
return 1
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
echo "$status"
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
update_ado_work_item() {
|
|
168
|
+
local work_item_id=$1
|
|
169
|
+
local spec_content=$2
|
|
170
|
+
local org="${AZURE_DEVOPS_ORG}"
|
|
171
|
+
local project="${AZURE_DEVOPS_PROJECT}"
|
|
172
|
+
local pat="${AZURE_DEVOPS_PAT}"
|
|
173
|
+
|
|
174
|
+
if [ -z "$org" ] || [ -z "$pat" ]; then
|
|
175
|
+
log_error "ADO credentials not configured"
|
|
176
|
+
return 1
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# Extract current status from spec
|
|
180
|
+
local local_status=$(echo "$spec_content" | grep "^status:" | cut -d: -f2 | tr -d ' ')
|
|
181
|
+
local ado_status=$(map_local_status_to_ado "$local_status")
|
|
182
|
+
|
|
183
|
+
local api_url="https://dev.azure.com/${org}/${project}/_apis/wit/workitems/${work_item_id}?api-version=7.0"
|
|
184
|
+
|
|
185
|
+
# Create update payload
|
|
186
|
+
local payload=$(cat <<EOF
|
|
187
|
+
[
|
|
188
|
+
{
|
|
189
|
+
"op": "add",
|
|
190
|
+
"path": "/fields/System.State",
|
|
191
|
+
"value": "$ado_status"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"op": "add",
|
|
195
|
+
"path": "/fields/System.History",
|
|
196
|
+
"value": "Updated from SpecWeave living docs"
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
EOF
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
log_debug "Updating ADO work item $work_item_id with status: $ado_status"
|
|
203
|
+
|
|
204
|
+
curl -s -X PATCH \
|
|
205
|
+
-u ":${pat}" \
|
|
206
|
+
-H "Content-Type: application/json-patch+json" \
|
|
207
|
+
-d "$payload" \
|
|
208
|
+
"$api_url" > /dev/null
|
|
209
|
+
|
|
210
|
+
if [ $? -ne 0 ]; then
|
|
211
|
+
log_error "Failed to update ADO work item"
|
|
212
|
+
return 1
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
log_info "Updated ADO work item $work_item_id"
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
# ============================================================================
|
|
219
|
+
# Conflict Resolution - CRITICAL: External Wins!
|
|
220
|
+
# ============================================================================
|
|
221
|
+
|
|
222
|
+
resolve_status_conflict() {
|
|
223
|
+
local spec_path=$1
|
|
224
|
+
local local_status=$2
|
|
225
|
+
local external_status=$3
|
|
226
|
+
|
|
227
|
+
local mapped_external=$(map_ado_status_to_local "$external_status")
|
|
228
|
+
|
|
229
|
+
if [ "$local_status" != "$mapped_external" ]; then
|
|
230
|
+
log_info "Status conflict detected:"
|
|
231
|
+
log_info " Local: $local_status"
|
|
232
|
+
log_info " External: $external_status (mapped: $mapped_external)"
|
|
233
|
+
log_info " Resolution: EXTERNAL WINS - applying $mapped_external"
|
|
234
|
+
|
|
235
|
+
# Update local spec with external status
|
|
236
|
+
sed -i.bak "s/^status: .*/status: $mapped_external/" "$spec_path"
|
|
237
|
+
|
|
238
|
+
# Add sync metadata
|
|
239
|
+
local timestamp=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
|
|
240
|
+
|
|
241
|
+
# Check if syncedAt exists, update or add
|
|
242
|
+
if grep -q "syncedAt:" "$spec_path"; then
|
|
243
|
+
sed -i.bak "s/syncedAt: .*/syncedAt: \"$timestamp\"/" "$spec_path"
|
|
244
|
+
else
|
|
245
|
+
# Add after externalLinks section
|
|
246
|
+
sed -i.bak "/externalLinks:/a\\
|
|
247
|
+
syncedAt: \"$timestamp\"" "$spec_path"
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
# Clean up backup files
|
|
251
|
+
rm -f "${spec_path}.bak"
|
|
252
|
+
|
|
253
|
+
log_info "Local spec updated with external status: $mapped_external"
|
|
254
|
+
return 0
|
|
255
|
+
else
|
|
256
|
+
log_debug "No status conflict - local and external match: $local_status"
|
|
257
|
+
return 0
|
|
258
|
+
fi
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
# ============================================================================
|
|
262
|
+
# Main Sync Function
|
|
263
|
+
# ============================================================================
|
|
264
|
+
|
|
265
|
+
sync_spec_with_ado() {
|
|
266
|
+
local spec_path=$1
|
|
267
|
+
|
|
268
|
+
if [ ! -f "$spec_path" ]; then
|
|
269
|
+
log_error "Spec file not found: $spec_path"
|
|
270
|
+
return 1
|
|
271
|
+
fi
|
|
272
|
+
|
|
273
|
+
local spec_name=$(basename "$spec_path")
|
|
274
|
+
log_info "Syncing spec: $spec_name"
|
|
275
|
+
|
|
276
|
+
# Read spec content
|
|
277
|
+
local spec_content=$(cat "$spec_path")
|
|
278
|
+
|
|
279
|
+
# Extract ADO work item ID from metadata
|
|
280
|
+
local work_item_id=$(echo "$spec_content" | grep -A5 "externalLinks:" | grep -A3 "ado:" | grep "featureId:" | cut -d: -f2 | tr -d ' ')
|
|
281
|
+
|
|
282
|
+
if [ -z "$work_item_id" ]; then
|
|
283
|
+
log_debug "No ADO work item linked to spec, skipping sync"
|
|
284
|
+
return 0
|
|
285
|
+
fi
|
|
286
|
+
|
|
287
|
+
log_info "Found ADO work item ID: $work_item_id"
|
|
288
|
+
|
|
289
|
+
# Step 1: Push updates to ADO (content changes)
|
|
290
|
+
update_ado_work_item "$work_item_id" "$spec_content"
|
|
291
|
+
|
|
292
|
+
# Step 2: CRITICAL - Pull status from ADO (external wins!)
|
|
293
|
+
local external_status=$(get_ado_work_item_status "$work_item_id")
|
|
294
|
+
|
|
295
|
+
if [ -z "$external_status" ]; then
|
|
296
|
+
log_error "Could not fetch ADO status"
|
|
297
|
+
return 1
|
|
298
|
+
fi
|
|
299
|
+
|
|
300
|
+
log_info "ADO status: $external_status"
|
|
301
|
+
|
|
302
|
+
# Step 3: Extract local status
|
|
303
|
+
local local_status=$(echo "$spec_content" | grep "^status:" | cut -d: -f2 | tr -d ' ')
|
|
304
|
+
|
|
305
|
+
log_info "Local status: $local_status"
|
|
306
|
+
|
|
307
|
+
# Step 4: Resolve conflicts - EXTERNAL WINS
|
|
308
|
+
resolve_status_conflict "$spec_path" "$local_status" "$external_status"
|
|
309
|
+
|
|
310
|
+
log_info "Sync completed for $spec_name"
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
# ============================================================================
|
|
314
|
+
# Entry Point
|
|
315
|
+
# ============================================================================
|
|
316
|
+
|
|
317
|
+
main() {
|
|
318
|
+
log_info "=== Post Living Docs Update Hook Started ==="
|
|
319
|
+
|
|
320
|
+
# Get the spec path from arguments or environment
|
|
321
|
+
local spec_path="${1:-$SPECWEAVE_UPDATED_SPEC}"
|
|
322
|
+
|
|
323
|
+
if [ -z "$spec_path" ]; then
|
|
324
|
+
log_error "No spec path provided"
|
|
325
|
+
exit 1
|
|
326
|
+
fi
|
|
327
|
+
|
|
328
|
+
# Detect external tool
|
|
329
|
+
local tool=$(detect_external_tool "$spec_path")
|
|
330
|
+
|
|
331
|
+
if [ "$tool" != "ado" ]; then
|
|
332
|
+
log_debug "Not an ADO-linked spec, skipping"
|
|
333
|
+
exit 0
|
|
334
|
+
fi
|
|
335
|
+
|
|
336
|
+
log_info "Detected ADO integration for spec"
|
|
337
|
+
|
|
338
|
+
# Perform sync
|
|
339
|
+
sync_spec_with_ado "$spec_path"
|
|
340
|
+
|
|
341
|
+
local exit_code=$?
|
|
342
|
+
|
|
343
|
+
if [ $exit_code -eq 0 ]; then
|
|
344
|
+
log_info "=== Sync completed successfully ==="
|
|
345
|
+
else
|
|
346
|
+
log_error "=== Sync failed with exit code: $exit_code ==="
|
|
347
|
+
fi
|
|
348
|
+
|
|
349
|
+
exit $exit_code
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
# Run main function
|
|
353
|
+
main "$@"
|