specweave 0.22.13 → 0.23.0
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-plugin/README.md +2 -2
- package/CLAUDE.md +447 -52
- package/README.md +33 -10
- package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.d.ts +1 -1
- package/dist/plugins/specweave-github/lib/ThreeLayerSyncManager.js +1 -1
- package/dist/plugins/specweave-github/lib/enhanced-github-sync.js +1 -1
- package/dist/plugins/specweave-github/lib/enhanced-github-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-content-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-content-sync.js +4 -1
- package/dist/plugins/specweave-github/lib/github-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-sync.d.ts +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-sync.js +1 -1
- package/dist/plugins/specweave-github/lib/github-sync-bidirectional.d.ts +9 -0
- package/dist/plugins/specweave-github/lib/github-sync-bidirectional.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-sync-bidirectional.js +10 -1
- package/dist/plugins/specweave-github/lib/github-sync-bidirectional.js.map +1 -1
- package/dist/plugins/specweave-github/lib/progress-comment-builder.js +2 -2
- package/dist/plugins/specweave-github/lib/progress-comment-builder.js.map +1 -1
- package/dist/plugins/specweave-github/lib/types.d.ts +1 -1
- package/dist/src/cli/commands/import-external.d.ts +22 -0
- package/dist/src/cli/commands/import-external.d.ts.map +1 -0
- package/dist/src/cli/commands/import-external.js +282 -0
- package/dist/src/cli/commands/import-external.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -1
- package/dist/src/cli/commands/init.js +359 -1
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/helpers/github-repo-selector.d.ts +59 -0
- package/dist/src/cli/helpers/github-repo-selector.d.ts.map +1 -0
- package/dist/src/cli/helpers/github-repo-selector.js +265 -0
- package/dist/src/cli/helpers/github-repo-selector.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +41 -24
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/config/import-config.d.ts +69 -0
- package/dist/src/config/import-config.d.ts.map +1 -0
- package/dist/src/config/import-config.js +136 -0
- package/dist/src/config/import-config.js.map +1 -0
- package/dist/src/config/types.d.ts +26 -26
- package/dist/src/core/increment/ac-status-manager.d.ts.map +1 -1
- package/dist/src/core/increment/ac-status-manager.js +4 -2
- package/dist/src/core/increment/ac-status-manager.js.map +1 -1
- package/dist/src/core/increment/completion-validator.d.ts +30 -1
- package/dist/src/core/increment/completion-validator.d.ts.map +1 -1
- package/dist/src/core/increment/completion-validator.js +151 -3
- package/dist/src/core/increment/completion-validator.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +25 -0
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +130 -3
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.d.ts +37 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.js +262 -18
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.d.ts +17 -0
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +25 -0
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.d.ts +16 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +56 -1
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/task-project-specific-generator.d.ts +2 -2
- package/dist/src/core/living-docs/task-project-specific-generator.js +2 -2
- package/dist/src/core/repo-structure/prompt-consolidator.d.ts +2 -2
- package/dist/src/core/repo-structure/prompt-consolidator.d.ts.map +1 -1
- package/dist/src/core/repo-structure/prompt-consolidator.js +3 -15
- package/dist/src/core/repo-structure/prompt-consolidator.js.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
- package/dist/src/core/repo-structure/repo-structure-manager.js +3 -6
- package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
- package/dist/src/core/spec-content-sync.d.ts +4 -1
- package/dist/src/core/spec-content-sync.d.ts.map +1 -1
- package/dist/src/core/spec-content-sync.js +139 -4
- package/dist/src/core/spec-content-sync.js.map +1 -1
- package/dist/src/core/spec-task-mapper.d.ts.map +1 -1
- package/dist/src/core/spec-task-mapper.js +9 -8
- package/dist/src/core/spec-task-mapper.js.map +1 -1
- package/dist/src/core/status-line-validator.d.ts +63 -0
- package/dist/src/core/status-line-validator.d.ts.map +1 -0
- package/dist/src/core/status-line-validator.js +253 -0
- package/dist/src/core/status-line-validator.js.map +1 -0
- package/dist/src/core/sync/bidirectional-engine.d.ts +10 -1
- package/dist/src/core/sync/bidirectional-engine.d.ts.map +1 -1
- package/dist/src/core/sync/bidirectional-engine.js +10 -1
- package/dist/src/core/sync/bidirectional-engine.js.map +1 -1
- package/dist/src/core/sync/profile-manager.d.ts.map +1 -1
- package/dist/src/core/sync/profile-manager.js +3 -0
- package/dist/src/core/sync/profile-manager.js.map +1 -1
- package/dist/src/core/sync/project-context.d.ts.map +1 -1
- package/dist/src/core/sync/project-context.js +3 -0
- package/dist/src/core/sync/project-context.js.map +1 -1
- package/dist/src/core/sync/status-sync-engine.d.ts +1 -1
- package/dist/src/core/sync/status-sync-engine.js +1 -1
- package/dist/src/core/sync/sync-event-logger.d.ts +15 -1
- package/dist/src/core/sync/sync-event-logger.d.ts.map +1 -1
- package/dist/src/core/sync/sync-event-logger.js +39 -1
- package/dist/src/core/sync/sync-event-logger.js.map +1 -1
- package/dist/src/core/types/origin-metadata.d.ts +153 -0
- package/dist/src/core/types/origin-metadata.d.ts.map +1 -0
- package/dist/src/core/types/origin-metadata.js +166 -0
- package/dist/src/core/types/origin-metadata.js.map +1 -0
- package/dist/src/core/types/sync-config-validator.d.ts +57 -0
- package/dist/src/core/types/sync-config-validator.d.ts.map +1 -0
- package/dist/src/core/types/sync-config-validator.js +116 -0
- package/dist/src/core/types/sync-config-validator.js.map +1 -0
- package/dist/src/core/types/sync-profile.d.ts +8 -2
- package/dist/src/core/types/sync-profile.d.ts.map +1 -1
- package/dist/src/core/types/sync-profile.js.map +1 -1
- package/dist/src/core/types/sync-settings.d.ts +73 -0
- package/dist/src/core/types/sync-settings.d.ts.map +1 -0
- package/dist/src/core/types/sync-settings.js +90 -0
- package/dist/src/core/types/sync-settings.js.map +1 -0
- package/dist/src/core/utils/permission-checker.d.ts +100 -0
- package/dist/src/core/utils/permission-checker.d.ts.map +1 -0
- package/dist/src/core/utils/permission-checker.js +166 -0
- package/dist/src/core/utils/permission-checker.js.map +1 -0
- package/dist/src/generators/spec/spec-parser.js +3 -3
- package/dist/src/generators/spec/spec-parser.js.map +1 -1
- package/dist/src/generators/spec/task-parser.js +4 -4
- package/dist/src/generators/spec/task-parser.js.map +1 -1
- package/dist/src/id-generators/task-id-generator.d.ts +96 -0
- package/dist/src/id-generators/task-id-generator.d.ts.map +1 -0
- package/dist/src/id-generators/task-id-generator.js +143 -0
- package/dist/src/id-generators/task-id-generator.js.map +1 -0
- package/dist/src/id-generators/us-id-generator.d.ts +96 -0
- package/dist/src/id-generators/us-id-generator.d.ts.map +1 -0
- package/dist/src/id-generators/us-id-generator.js +143 -0
- package/dist/src/id-generators/us-id-generator.js.map +1 -0
- package/dist/src/importers/ado-importer.d.ts +43 -0
- package/dist/src/importers/ado-importer.d.ts.map +1 -0
- package/dist/src/importers/ado-importer.js +234 -0
- package/dist/src/importers/ado-importer.js.map +1 -0
- package/dist/src/importers/duplicate-detector.d.ts +107 -0
- package/dist/src/importers/duplicate-detector.d.ts.map +1 -0
- package/dist/src/importers/duplicate-detector.js +189 -0
- package/dist/src/importers/duplicate-detector.js.map +1 -0
- package/dist/src/importers/external-importer.d.ts +96 -0
- package/dist/src/importers/external-importer.d.ts.map +1 -0
- package/dist/src/importers/external-importer.js +13 -0
- package/dist/src/importers/external-importer.js.map +1 -0
- package/dist/src/importers/github-importer.d.ts +37 -0
- package/dist/src/importers/github-importer.d.ts.map +1 -0
- package/dist/src/importers/github-importer.js +161 -0
- package/dist/src/importers/github-importer.js.map +1 -0
- package/dist/src/importers/import-coordinator.d.ts +105 -0
- package/dist/src/importers/import-coordinator.d.ts.map +1 -0
- package/dist/src/importers/import-coordinator.js +224 -0
- package/dist/src/importers/import-coordinator.js.map +1 -0
- package/dist/src/importers/item-converter.d.ts +96 -0
- package/dist/src/importers/item-converter.d.ts.map +1 -0
- package/dist/src/importers/item-converter.js +246 -0
- package/dist/src/importers/item-converter.js.map +1 -0
- package/dist/src/importers/jira-importer.d.ts +42 -0
- package/dist/src/importers/jira-importer.d.ts.map +1 -0
- package/dist/src/importers/jira-importer.js +221 -0
- package/dist/src/importers/jira-importer.js.map +1 -0
- package/dist/src/importers/rate-limiter.d.ts +128 -0
- package/dist/src/importers/rate-limiter.d.ts.map +1 -0
- package/dist/src/importers/rate-limiter.js +200 -0
- package/dist/src/importers/rate-limiter.js.map +1 -0
- package/dist/src/init/compliance/types.d.ts +2 -2
- package/dist/src/init/repo/types.d.ts +2 -2
- package/dist/src/integrations/ado/ado-client.d.ts +6 -0
- package/dist/src/integrations/ado/ado-client.d.ts.map +1 -1
- package/dist/src/integrations/ado/ado-client.js +23 -0
- package/dist/src/integrations/ado/ado-client.js.map +1 -1
- package/dist/src/integrations/jira/jira-client.d.ts +6 -0
- package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-client.js +38 -0
- package/dist/src/integrations/jira/jira-client.js.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.d.ts +1 -1
- package/dist/src/integrations/jira/jira-mapper.js +1 -1
- package/dist/src/living-docs/fs-id-allocator.d.ts +149 -0
- package/dist/src/living-docs/fs-id-allocator.d.ts.map +1 -0
- package/dist/src/living-docs/fs-id-allocator.js +325 -0
- package/dist/src/living-docs/fs-id-allocator.js.map +1 -0
- package/dist/src/living-docs/id-registry.d.ts +124 -0
- package/dist/src/living-docs/id-registry.d.ts.map +1 -0
- package/dist/src/living-docs/id-registry.js +230 -0
- package/dist/src/living-docs/id-registry.js.map +1 -0
- package/dist/src/progress/us-progress-tracker.d.ts +68 -0
- package/dist/src/progress/us-progress-tracker.d.ts.map +1 -0
- package/dist/src/progress/us-progress-tracker.js +120 -0
- package/dist/src/progress/us-progress-tracker.js.map +1 -0
- package/dist/src/sync/external-item-sync-service.d.ts +150 -0
- package/dist/src/sync/external-item-sync-service.d.ts.map +1 -0
- package/dist/src/sync/external-item-sync-service.js +241 -0
- package/dist/src/sync/external-item-sync-service.js.map +1 -0
- package/dist/src/sync/format-preservation-sync.d.ts +90 -0
- package/dist/src/sync/format-preservation-sync.d.ts.map +1 -0
- package/dist/src/sync/format-preservation-sync.js +173 -0
- package/dist/src/sync/format-preservation-sync.js.map +1 -0
- package/dist/src/sync/index.d.ts +8 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/index.js +6 -0
- package/dist/src/sync/index.js.map +1 -0
- package/dist/src/sync/sync-coordinator.d.ts +49 -0
- package/dist/src/sync/sync-coordinator.d.ts.map +1 -0
- package/dist/src/sync/sync-coordinator.js +248 -0
- package/dist/src/sync/sync-coordinator.js.map +1 -0
- package/dist/src/sync/sync-metadata.d.ts +75 -0
- package/dist/src/sync/sync-metadata.d.ts.map +1 -0
- package/dist/src/sync/sync-metadata.js +100 -0
- package/dist/src/sync/sync-metadata.js.map +1 -0
- package/dist/src/types/living-docs-us-file.d.ts +63 -0
- package/dist/src/types/living-docs-us-file.d.ts.map +1 -0
- package/dist/src/types/living-docs-us-file.js +27 -0
- package/dist/src/types/living-docs-us-file.js.map +1 -0
- package/dist/src/validators/format-preservation-validator.d.ts +127 -0
- package/dist/src/validators/format-preservation-validator.d.ts.map +1 -0
- package/dist/src/validators/format-preservation-validator.js +187 -0
- package/dist/src/validators/format-preservation-validator.js.map +1 -0
- package/package.json +3 -2
- package/plugins/specweave/.claude-plugin/plugin.json +36 -2
- package/plugins/specweave/agents/architect/AGENT.md +11 -2
- package/plugins/specweave/agents/test-aware-planner/AGENT.md +81 -25
- package/plugins/specweave/commands/specweave-archive-features.md +11 -1
- package/plugins/specweave/commands/specweave-import-external.md +407 -0
- package/plugins/specweave/commands/specweave-progress.md +45 -97
- package/plugins/specweave/hooks/post-edit-spec.sh +41 -0
- package/plugins/specweave/hooks/post-increment-completion.sh +168 -26
- package/plugins/specweave/hooks/post-increment-planning.sh +148 -4
- package/plugins/specweave/hooks/post-spec-update.sh +0 -0
- package/plugins/specweave/hooks/post-task-completion.sh +75 -5
- package/plugins/specweave/hooks/post-write-spec.sh +37 -0
- package/plugins/specweave/lib/hooks/auto-transition.js +1 -1
- package/plugins/specweave/lib/hooks/auto-transition.ts +1 -1
- package/plugins/specweave/lib/hooks/invoke-translator-skill.js +1 -1
- package/plugins/specweave/lib/hooks/invoke-translator-skill.ts +1 -1
- package/plugins/specweave/lib/hooks/sync-cache.js +294 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.js +67 -2
- package/plugins/specweave/lib/hooks/sync-us-tasks.js +200 -14
- package/plugins/specweave/lib/hooks/translate-file.js +1 -1
- package/plugins/specweave/lib/hooks/translate-file.ts +1 -1
- package/plugins/specweave/lib/hooks/update-ac-status.js +1 -1
- package/plugins/specweave/lib/hooks/update-ac-status.ts +1 -1
- package/plugins/specweave/lib/vendor/core/increment/ac-status-manager.d.ts +115 -0
- package/plugins/specweave/lib/vendor/core/increment/ac-status-manager.js +345 -0
- package/plugins/specweave/lib/vendor/core/increment/ac-status-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/active-increment-manager.d.ts +106 -0
- package/plugins/specweave/lib/vendor/core/increment/active-increment-manager.js +220 -0
- package/plugins/specweave/lib/vendor/core/increment/active-increment-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.d.ts +60 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js +192 -0
- package/plugins/specweave/lib/vendor/core/increment/auto-transition-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.d.ts +52 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js +276 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.d.ts +163 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js +541 -0
- package/plugins/specweave/lib/vendor/core/increment/metadata-manager.js.map +1 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.d.ts +157 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.js +191 -0
- package/plugins/specweave/lib/vendor/core/types/increment-metadata.js.map +1 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.d.ts +95 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js +301 -0
- package/plugins/specweave/lib/vendor/generators/spec/task-parser.js.map +1 -0
- package/plugins/specweave/lib/vendor/utils/logger.d.ts +48 -0
- package/plugins/specweave/lib/vendor/utils/logger.js +53 -0
- package/plugins/specweave/lib/vendor/utils/logger.js.map +1 -0
- package/plugins/specweave/lib/vendor/utils/translation.d.ts +187 -0
- package/plugins/specweave/lib/vendor/utils/translation.js +414 -0
- package/plugins/specweave/lib/vendor/utils/translation.js.map +1 -0
- package/plugins/specweave-ado/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
- package/plugins/specweave-ado/lib/conflict-resolver.ts +1 -1
- package/plugins/specweave-alternatives/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-backend/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-confluent/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-cost-optimizer/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-diagrams/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-docs/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-docs-preview/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-figma/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-frontend/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-github/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-github/commands/specweave-github-update-user-story.md +1 -1
- package/plugins/specweave-github/hooks/post-task-completion.sh +37 -22
- package/plugins/specweave-github/lib/ThreeLayerSyncManager.ts +1 -1
- package/plugins/specweave-github/lib/enhanced-github-sync.js +1 -1
- package/plugins/specweave-github/lib/enhanced-github-sync.ts +1 -1
- package/plugins/specweave-github/lib/github-spec-content-sync.js +2 -1
- package/plugins/specweave-github/lib/github-spec-content-sync.ts +4 -1
- package/plugins/specweave-github/lib/github-spec-sync.js +1 -1
- package/plugins/specweave-github/lib/github-spec-sync.ts +1 -1
- package/plugins/specweave-github/lib/github-sync-bidirectional.js +1 -1
- package/plugins/specweave-github/lib/github-sync-bidirectional.ts +10 -1
- package/plugins/specweave-github/lib/progress-comment-builder.js +1 -1
- package/plugins/specweave-github/lib/progress-comment-builder.ts +2 -2
- package/plugins/specweave-github/lib/types.ts +1 -1
- package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +1 -1
- package/plugins/specweave-infrastructure/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-jira/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
- package/plugins/specweave-kafka/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-kubernetes/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-ml/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-mobile/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-n8n/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-payments/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-release/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-testing/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-tooling/.claude-plugin/plugin.json +1 -1
- package/plugins/specweave-ui/.claude-plugin/plugin.json +1 -1
- package/src/templates/.env.example +5 -0
- package/src/templates/config-permissions-guide.md +413 -0
- package/src/templates/config.json.template +68 -0
- package/src/templates/tasks.md.template +180 -201
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -5442
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Active Increment Manager
|
|
3
|
+
*
|
|
4
|
+
* Manages the `.specweave/state/active-increment.json` file which tracks
|
|
5
|
+
* the currently active increment for status line display.
|
|
6
|
+
*
|
|
7
|
+
* **Critical**: This file MUST be updated whenever increment status changes:
|
|
8
|
+
* - When new increment is created → Set as active
|
|
9
|
+
* - When increment is completed → Clear or set to next active
|
|
10
|
+
* - When increment is paused → Set to next active (or clear if none)
|
|
11
|
+
* - When increment is resumed → Set as active
|
|
12
|
+
*
|
|
13
|
+
* Part of increment 0021: Fix Active Increment Tracking
|
|
14
|
+
*/
|
|
15
|
+
import fs from 'fs-extra';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { IncrementStatus } from '../types/increment-metadata.js';
|
|
18
|
+
import { MetadataManager } from './metadata-manager.js';
|
|
19
|
+
/**
|
|
20
|
+
* Active Increment Manager
|
|
21
|
+
*
|
|
22
|
+
* Central authority for managing which increment is currently active.
|
|
23
|
+
*/
|
|
24
|
+
export class ActiveIncrementManager {
|
|
25
|
+
constructor(rootDir = process.cwd()) {
|
|
26
|
+
this.rootDir = rootDir;
|
|
27
|
+
this.stateFile = path.join(rootDir, '.specweave/state/active-increment.json');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get all currently active increment IDs
|
|
31
|
+
* Returns empty array if no increments are active
|
|
32
|
+
*
|
|
33
|
+
* **NEW**: Returns array of ALL active increments (max 2)
|
|
34
|
+
*/
|
|
35
|
+
getActive() {
|
|
36
|
+
try {
|
|
37
|
+
if (!fs.existsSync(this.stateFile)) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const content = fs.readFileSync(this.stateFile, 'utf-8');
|
|
41
|
+
const state = JSON.parse(content);
|
|
42
|
+
// Backwards compatibility: Support old format
|
|
43
|
+
if (state.id && !state.ids) {
|
|
44
|
+
return [state.id];
|
|
45
|
+
}
|
|
46
|
+
return state.ids || [];
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
// File read/parse error = no active increments
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Get the primary active increment (first in list)
|
|
55
|
+
* Returns null if no increments are active
|
|
56
|
+
*
|
|
57
|
+
* This maintains backwards compatibility with code expecting a single ID
|
|
58
|
+
*/
|
|
59
|
+
getPrimary() {
|
|
60
|
+
const active = this.getActive();
|
|
61
|
+
return active.length > 0 ? active[0] : null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Add an increment to the active list
|
|
65
|
+
* Validates that the increment exists and is actually active
|
|
66
|
+
*
|
|
67
|
+
* **NEW**: Adds to list instead of replacing (max 2)
|
|
68
|
+
* @param skipValidation - Skip validation (used during lazy initialization to prevent circular dependency)
|
|
69
|
+
*/
|
|
70
|
+
addActive(incrementId, skipValidation = false) {
|
|
71
|
+
// Validate increment exists and is active (unless skipValidation is true)
|
|
72
|
+
if (!skipValidation) {
|
|
73
|
+
const metadata = MetadataManager.read(incrementId);
|
|
74
|
+
// Validate increment is actually active
|
|
75
|
+
if (metadata.status !== IncrementStatus.ACTIVE) {
|
|
76
|
+
throw new Error(`Cannot add ${incrementId} as active: status is ${metadata.status}, not active`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Get current active list
|
|
80
|
+
const currentActive = this.getActive();
|
|
81
|
+
// Don't add if already in list
|
|
82
|
+
if (currentActive.includes(incrementId)) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Add to list (max 2)
|
|
86
|
+
const newActive = [...currentActive, incrementId].slice(0, 2);
|
|
87
|
+
// Write state
|
|
88
|
+
const state = {
|
|
89
|
+
ids: newActive,
|
|
90
|
+
lastUpdated: new Date().toISOString()
|
|
91
|
+
};
|
|
92
|
+
this.writeState(state);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Remove an increment from the active list
|
|
96
|
+
*/
|
|
97
|
+
removeActive(incrementId) {
|
|
98
|
+
const currentActive = this.getActive();
|
|
99
|
+
const newActive = currentActive.filter(id => id !== incrementId);
|
|
100
|
+
const state = {
|
|
101
|
+
ids: newActive,
|
|
102
|
+
lastUpdated: new Date().toISOString()
|
|
103
|
+
};
|
|
104
|
+
this.writeState(state);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Set the active increment (legacy method for backwards compatibility)
|
|
108
|
+
* Now delegates to addActive()
|
|
109
|
+
* @param skipValidation - Skip validation (used during lazy initialization to prevent circular dependency)
|
|
110
|
+
*/
|
|
111
|
+
setActive(incrementId, skipValidation = false) {
|
|
112
|
+
this.addActive(incrementId, skipValidation);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Clear all active increments
|
|
116
|
+
*/
|
|
117
|
+
clearActive() {
|
|
118
|
+
const state = {
|
|
119
|
+
ids: [],
|
|
120
|
+
lastUpdated: new Date().toISOString()
|
|
121
|
+
};
|
|
122
|
+
this.writeState(state);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Smart update: Rebuild active list from metadata
|
|
126
|
+
*
|
|
127
|
+
* This is called when:
|
|
128
|
+
* - An increment is completed
|
|
129
|
+
* - An increment is paused
|
|
130
|
+
* - An increment is abandoned
|
|
131
|
+
*
|
|
132
|
+
* Logic:
|
|
133
|
+
* 1. Scan all increments for status=active
|
|
134
|
+
* 2. Update cache to match reality
|
|
135
|
+
* 3. Max 2 increments (sorted by lastActivity)
|
|
136
|
+
*/
|
|
137
|
+
smartUpdate() {
|
|
138
|
+
const activeIncrements = MetadataManager.getActive();
|
|
139
|
+
if (activeIncrements.length > 0) {
|
|
140
|
+
// Sort by lastActivity (most recent first)
|
|
141
|
+
const sorted = activeIncrements.sort((a, b) => {
|
|
142
|
+
const aTime = new Date(a.lastActivity).getTime();
|
|
143
|
+
const bTime = new Date(b.lastActivity).getTime();
|
|
144
|
+
return bTime - aTime; // Descending
|
|
145
|
+
});
|
|
146
|
+
// Take max 2
|
|
147
|
+
const activeIds = sorted.slice(0, 2).map(m => m.id);
|
|
148
|
+
const state = {
|
|
149
|
+
ids: activeIds,
|
|
150
|
+
lastUpdated: new Date().toISOString()
|
|
151
|
+
};
|
|
152
|
+
this.writeState(state);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// No active increments
|
|
156
|
+
this.clearActive();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Validate that all active increment pointers are correct
|
|
161
|
+
* Does NOT fix stale pointers - caller should call smartUpdate() if needed
|
|
162
|
+
*
|
|
163
|
+
* Returns true if all valid, false if any invalid
|
|
164
|
+
*/
|
|
165
|
+
validate() {
|
|
166
|
+
const currentActive = this.getActive();
|
|
167
|
+
// No active increments = valid (nothing to validate)
|
|
168
|
+
if (currentActive.length === 0) {
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
let hasStale = false;
|
|
172
|
+
for (const incrementId of currentActive) {
|
|
173
|
+
try {
|
|
174
|
+
// Check if increment still exists
|
|
175
|
+
const metadata = MetadataManager.read(incrementId);
|
|
176
|
+
// Check if increment is actually active
|
|
177
|
+
if (metadata.status !== IncrementStatus.ACTIVE) {
|
|
178
|
+
// Stale pointer! Mark for fix
|
|
179
|
+
console.warn(`⚠️ Active increment pointer is stale: ${incrementId} is ${metadata.status}`);
|
|
180
|
+
hasStale = true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
// Increment doesn't exist = stale pointer
|
|
185
|
+
console.warn(`⚠️ Active increment pointer is invalid: ${incrementId} not found`);
|
|
186
|
+
hasStale = true;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Return false if stale found, but DON'T auto-fix (prevents circular dependency)
|
|
190
|
+
// Caller should call smartUpdate() if needed
|
|
191
|
+
return !hasStale;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Write state file atomically (temp file → rename)
|
|
195
|
+
*/
|
|
196
|
+
writeState(state) {
|
|
197
|
+
// Ensure state directory exists
|
|
198
|
+
const stateDir = path.dirname(this.stateFile);
|
|
199
|
+
if (!fs.existsSync(stateDir)) {
|
|
200
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
201
|
+
}
|
|
202
|
+
// Atomic write: temp file → rename
|
|
203
|
+
const tempFile = `${this.stateFile}.tmp`;
|
|
204
|
+
fs.writeFileSync(tempFile, JSON.stringify(state, null, 2), 'utf-8');
|
|
205
|
+
fs.renameSync(tempFile, this.stateFile);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get state file path (for testing)
|
|
209
|
+
*/
|
|
210
|
+
getStateFilePath() {
|
|
211
|
+
return this.stateFile;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Check if state file exists (for testing)
|
|
215
|
+
*/
|
|
216
|
+
exists() {
|
|
217
|
+
return fs.existsSync(this.stateFile);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=active-increment-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"active-increment-manager.js","sourceRoot":"","sources":["../../../../src/core/increment/active-increment-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-Transition Manager
|
|
3
|
+
*
|
|
4
|
+
* Automatically transitions increment status based on lifecycle events:
|
|
5
|
+
* - spec.md created → BACKLOG → PLANNING
|
|
6
|
+
* - tasks.md created → PLANNING/BACKLOG → ACTIVE
|
|
7
|
+
* - first task started → PLANNING → ACTIVE
|
|
8
|
+
*
|
|
9
|
+
* Part of increment 0039: Ultra-Smart Next Command
|
|
10
|
+
*/
|
|
11
|
+
import { IncrementStatus } from '../types/increment-metadata.js';
|
|
12
|
+
export interface TransitionEvent {
|
|
13
|
+
incrementId: string;
|
|
14
|
+
from: IncrementStatus;
|
|
15
|
+
to: IncrementStatus;
|
|
16
|
+
trigger: 'spec-created' | 'tasks-created' | 'task-started' | 'auto-correct';
|
|
17
|
+
timestamp: string;
|
|
18
|
+
}
|
|
19
|
+
export interface AutoTransitionResult {
|
|
20
|
+
transitioned: boolean;
|
|
21
|
+
from?: IncrementStatus;
|
|
22
|
+
to?: IncrementStatus;
|
|
23
|
+
reason: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Manages automatic status transitions based on increment artifacts
|
|
27
|
+
*/
|
|
28
|
+
export declare class AutoTransitionManager {
|
|
29
|
+
private projectRoot;
|
|
30
|
+
constructor(projectRoot: string);
|
|
31
|
+
/**
|
|
32
|
+
* Handle spec.md creation event
|
|
33
|
+
* BACKLOG → PLANNING
|
|
34
|
+
*/
|
|
35
|
+
handleSpecCreated(incrementId: string): Promise<AutoTransitionResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Handle tasks.md creation event
|
|
38
|
+
* PLANNING/BACKLOG → ACTIVE
|
|
39
|
+
*/
|
|
40
|
+
handleTasksCreated(incrementId: string): Promise<AutoTransitionResult>;
|
|
41
|
+
/**
|
|
42
|
+
* Handle first task started event
|
|
43
|
+
* PLANNING → ACTIVE
|
|
44
|
+
*/
|
|
45
|
+
handleTaskStarted(incrementId: string): Promise<AutoTransitionResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Detect increment phase based on artifacts (spec.md, plan.md, tasks.md)
|
|
48
|
+
*/
|
|
49
|
+
detectPhase(incrementId: string): Promise<IncrementStatus>;
|
|
50
|
+
/**
|
|
51
|
+
* Auto-correct status based on artifacts
|
|
52
|
+
* Useful for fixing increments with invalid "planned"/"planning" statuses
|
|
53
|
+
*/
|
|
54
|
+
autoCorrect(incrementId: string, force?: boolean): Promise<AutoTransitionResult>;
|
|
55
|
+
/**
|
|
56
|
+
* Get transition event for logging
|
|
57
|
+
*/
|
|
58
|
+
createTransitionEvent(incrementId: string, from: IncrementStatus, to: IncrementStatus, trigger: TransitionEvent['trigger']): TransitionEvent;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=auto-transition-manager.d.ts.map
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-Transition Manager
|
|
3
|
+
*
|
|
4
|
+
* Automatically transitions increment status based on lifecycle events:
|
|
5
|
+
* - spec.md created → BACKLOG → PLANNING
|
|
6
|
+
* - tasks.md created → PLANNING/BACKLOG → ACTIVE
|
|
7
|
+
* - first task started → PLANNING → ACTIVE
|
|
8
|
+
*
|
|
9
|
+
* Part of increment 0039: Ultra-Smart Next Command
|
|
10
|
+
*/
|
|
11
|
+
import { IncrementStatus, validateTransition } from '../types/increment-metadata.js';
|
|
12
|
+
import { MetadataManager } from './metadata-manager.js';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as path from 'path';
|
|
15
|
+
/**
|
|
16
|
+
* Manages automatic status transitions based on increment artifacts
|
|
17
|
+
*/
|
|
18
|
+
export class AutoTransitionManager {
|
|
19
|
+
constructor(projectRoot) {
|
|
20
|
+
this.projectRoot = projectRoot;
|
|
21
|
+
// Note: MetadataManager uses process.cwd() internally
|
|
22
|
+
// In production, this manager should be instantiated from the project root
|
|
23
|
+
// In tests, we use integration tests with real file system
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Handle spec.md creation event
|
|
27
|
+
* BACKLOG → PLANNING
|
|
28
|
+
*/
|
|
29
|
+
async handleSpecCreated(incrementId) {
|
|
30
|
+
try {
|
|
31
|
+
const metadata = MetadataManager.read(incrementId);
|
|
32
|
+
// Only transition from BACKLOG to PLANNING
|
|
33
|
+
if (metadata.status === IncrementStatus.BACKLOG) {
|
|
34
|
+
validateTransition(metadata.status, IncrementStatus.PLANNING);
|
|
35
|
+
MetadataManager.updateStatus(incrementId, IncrementStatus.PLANNING);
|
|
36
|
+
return {
|
|
37
|
+
transitioned: true,
|
|
38
|
+
from: IncrementStatus.BACKLOG,
|
|
39
|
+
to: IncrementStatus.PLANNING,
|
|
40
|
+
reason: 'spec.md created - planning phase started'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
transitioned: false,
|
|
45
|
+
reason: `Already in ${metadata.status} - no transition needed`
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return {
|
|
50
|
+
transitioned: false,
|
|
51
|
+
reason: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Handle tasks.md creation event
|
|
57
|
+
* PLANNING/BACKLOG → ACTIVE
|
|
58
|
+
*/
|
|
59
|
+
async handleTasksCreated(incrementId) {
|
|
60
|
+
try {
|
|
61
|
+
const metadata = MetadataManager.read(incrementId);
|
|
62
|
+
// Transition to ACTIVE from PLANNING or BACKLOG
|
|
63
|
+
if (metadata.status === IncrementStatus.PLANNING || metadata.status === IncrementStatus.BACKLOG) {
|
|
64
|
+
const from = metadata.status;
|
|
65
|
+
validateTransition(from, IncrementStatus.ACTIVE);
|
|
66
|
+
MetadataManager.updateStatus(incrementId, IncrementStatus.ACTIVE);
|
|
67
|
+
return {
|
|
68
|
+
transitioned: true,
|
|
69
|
+
from,
|
|
70
|
+
to: IncrementStatus.ACTIVE,
|
|
71
|
+
reason: 'tasks.md created - execution phase started'
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
transitioned: false,
|
|
76
|
+
reason: `Already in ${metadata.status} - no transition needed`
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
return {
|
|
81
|
+
transitioned: false,
|
|
82
|
+
reason: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Handle first task started event
|
|
88
|
+
* PLANNING → ACTIVE
|
|
89
|
+
*/
|
|
90
|
+
async handleTaskStarted(incrementId) {
|
|
91
|
+
try {
|
|
92
|
+
const metadata = MetadataManager.read(incrementId);
|
|
93
|
+
// Force transition to ACTIVE if still in PLANNING
|
|
94
|
+
if (metadata.status === IncrementStatus.PLANNING) {
|
|
95
|
+
validateTransition(metadata.status, IncrementStatus.ACTIVE);
|
|
96
|
+
MetadataManager.updateStatus(incrementId, IncrementStatus.ACTIVE);
|
|
97
|
+
return {
|
|
98
|
+
transitioned: true,
|
|
99
|
+
from: IncrementStatus.PLANNING,
|
|
100
|
+
to: IncrementStatus.ACTIVE,
|
|
101
|
+
reason: 'task execution started - moved to active'
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
transitioned: false,
|
|
106
|
+
reason: `Already in ${metadata.status} - no transition needed`
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
return {
|
|
111
|
+
transitioned: false,
|
|
112
|
+
reason: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Detect increment phase based on artifacts (spec.md, plan.md, tasks.md)
|
|
118
|
+
*/
|
|
119
|
+
async detectPhase(incrementId) {
|
|
120
|
+
const incrementPath = path.join(this.projectRoot, '.specweave/increments', incrementId);
|
|
121
|
+
const hasSpec = fs.existsSync(path.join(incrementPath, 'spec.md'));
|
|
122
|
+
const hasPlan = fs.existsSync(path.join(incrementPath, 'plan.md'));
|
|
123
|
+
const hasTasks = fs.existsSync(path.join(incrementPath, 'tasks.md'));
|
|
124
|
+
// Artifact-based phase detection
|
|
125
|
+
if (hasTasks) {
|
|
126
|
+
return IncrementStatus.ACTIVE; // Tasks exist → execution phase
|
|
127
|
+
}
|
|
128
|
+
else if (hasSpec || hasPlan) {
|
|
129
|
+
return IncrementStatus.PLANNING; // Spec/plan exist → planning phase
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
return IncrementStatus.BACKLOG; // Nothing exists → backlog
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Auto-correct status based on artifacts
|
|
137
|
+
* Useful for fixing increments with invalid "planned"/"planning" statuses
|
|
138
|
+
*/
|
|
139
|
+
async autoCorrect(incrementId, force = false) {
|
|
140
|
+
try {
|
|
141
|
+
const metadata = MetadataManager.read(incrementId);
|
|
142
|
+
const detectedPhase = await this.detectPhase(incrementId);
|
|
143
|
+
// Check for status mismatch
|
|
144
|
+
if (metadata.status !== detectedPhase) {
|
|
145
|
+
// Validate transition is allowed
|
|
146
|
+
try {
|
|
147
|
+
validateTransition(metadata.status, detectedPhase);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
if (!force) {
|
|
151
|
+
return {
|
|
152
|
+
transitioned: false,
|
|
153
|
+
reason: `Cannot auto-correct: ${error instanceof Error ? error.message : String(error)}`
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
// Force mode: skip validation
|
|
157
|
+
}
|
|
158
|
+
const from = metadata.status;
|
|
159
|
+
MetadataManager.updateStatus(incrementId, detectedPhase);
|
|
160
|
+
return {
|
|
161
|
+
transitioned: true,
|
|
162
|
+
from,
|
|
163
|
+
to: detectedPhase,
|
|
164
|
+
reason: `Auto-corrected based on artifacts (${force ? 'forced' : 'validated'})`
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
transitioned: false,
|
|
169
|
+
reason: `Status already correct (${metadata.status})`
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
return {
|
|
174
|
+
transitioned: false,
|
|
175
|
+
reason: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Get transition event for logging
|
|
181
|
+
*/
|
|
182
|
+
createTransitionEvent(incrementId, from, to, trigger) {
|
|
183
|
+
return {
|
|
184
|
+
incrementId,
|
|
185
|
+
from,
|
|
186
|
+
to,
|
|
187
|
+
trigger,
|
|
188
|
+
timestamp: new Date().toISOString()
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=auto-transition-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-transition-manager.js","sourceRoot":"","sources":["../../../../src/core/increment/auto-transition-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duplicate Detector - Scan filesystem and detect duplicate increments
|
|
3
|
+
*
|
|
4
|
+
* Detects increments that exist in multiple locations (active, archive, abandoned)
|
|
5
|
+
* or have the same increment number with different names.
|
|
6
|
+
*
|
|
7
|
+
* Part of increment 0033: Duplicate Increment Prevention System
|
|
8
|
+
*/
|
|
9
|
+
import { IncrementStatus } from '../types/increment-metadata.js';
|
|
10
|
+
/**
|
|
11
|
+
* Report of all duplicates found
|
|
12
|
+
*/
|
|
13
|
+
export interface DuplicateReport {
|
|
14
|
+
duplicates: Duplicate[];
|
|
15
|
+
totalChecked: number;
|
|
16
|
+
duplicateCount: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A duplicate increment (same number in multiple locations or with different names)
|
|
20
|
+
*/
|
|
21
|
+
export interface Duplicate {
|
|
22
|
+
incrementNumber: string;
|
|
23
|
+
locations: IncrementLocation[];
|
|
24
|
+
recommendedWinner: IncrementLocation;
|
|
25
|
+
losingVersions: IncrementLocation[];
|
|
26
|
+
resolutionReason: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Information about an increment location
|
|
30
|
+
*/
|
|
31
|
+
export interface IncrementLocation {
|
|
32
|
+
path: string;
|
|
33
|
+
name: string;
|
|
34
|
+
status: IncrementStatus;
|
|
35
|
+
lastActivity: string;
|
|
36
|
+
fileCount: number;
|
|
37
|
+
totalSize: number;
|
|
38
|
+
hasReports: boolean;
|
|
39
|
+
hasGitHubLink: boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Scan all increment folders and detect duplicates
|
|
43
|
+
*/
|
|
44
|
+
export declare function detectAllDuplicates(rootDir: string): Promise<DuplicateReport>;
|
|
45
|
+
/**
|
|
46
|
+
* Detect duplicates for a specific increment number
|
|
47
|
+
*
|
|
48
|
+
* Returns ALL increments that have the given number, even if there's only one.
|
|
49
|
+
* This is used for validation before creating a new increment.
|
|
50
|
+
*/
|
|
51
|
+
export declare function detectDuplicatesByNumber(incrementNumber: string, rootDir: string): Promise<IncrementLocation[]>;
|
|
52
|
+
//# sourceMappingURL=duplicate-detector.d.ts.map
|