specweave 0.29.2 → 0.30.1
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/README.md +65 -16
- package/bin/specweave.js +16 -0
- package/dist/plugins/specweave-ado/lib/ado-spec-commit-sync.d.ts +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-commit-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-commit-sync.js +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-commit-sync.js.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.d.ts +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js +1 -1
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-ado/lib/conflict-resolver.d.ts +134 -0
- package/dist/plugins/specweave-ado/lib/conflict-resolver.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/conflict-resolver.js +423 -0
- package/dist/plugins/specweave-ado/lib/conflict-resolver.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +23 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +95 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-commit-sync.d.ts +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-commit-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-commit-sync.js +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-commit-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-content-sync.d.ts +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 +1 -1
- package/dist/plugins/specweave-github/lib/github-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/types.d.ts +20 -0
- package/dist/plugins/specweave-github/lib/types.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-spec-commit-sync.d.ts +1 -1
- package/dist/plugins/specweave-jira/lib/jira-spec-commit-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-spec-commit-sync.js +1 -1
- package/dist/plugins/specweave-jira/lib/jira-spec-commit-sync.js.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-spec-content-sync.d.ts +1 -1
- package/dist/plugins/specweave-jira/lib/jira-spec-content-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/jira-spec-content-sync.js +1 -1
- package/dist/plugins/specweave-jira/lib/jira-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-jira/lib/setup-wizard.d.ts +2 -2
- package/dist/plugins/specweave-jira/lib/setup-wizard.d.ts.map +1 -1
- package/dist/plugins/specweave-jira/lib/setup-wizard.js +1 -1
- package/dist/plugins/specweave-jira/lib/setup-wizard.js.map +1 -1
- package/dist/src/adapters/claude/adapter.js +1 -1
- package/dist/src/adapters/claude/adapter.js.map +1 -1
- package/dist/src/cli/commands/detect-project.js +1 -1
- package/dist/src/cli/commands/detect-project.js.map +1 -1
- package/dist/src/cli/commands/detect-specs.js +1 -1
- package/dist/src/cli/commands/detect-specs.js.map +1 -1
- package/dist/src/cli/commands/import-docs.js +1 -1
- package/dist/src/cli/commands/import-docs.js.map +1 -1
- 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 +31 -1
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/jobs.js +15 -1
- package/dist/src/cli/commands/jobs.js.map +1 -1
- package/dist/src/cli/commands/migrate-to-multiproject.js +1 -1
- package/dist/src/cli/commands/migrate-to-multiproject.js.map +1 -1
- package/dist/src/cli/commands/switch-project.js +1 -1
- package/dist/src/cli/commands/switch-project.js.map +1 -1
- package/dist/src/cli/commands/sync-scheduled.d.ts +38 -0
- package/dist/src/cli/commands/sync-scheduled.d.ts.map +1 -0
- package/dist/src/cli/commands/sync-scheduled.js +170 -0
- package/dist/src/cli/commands/sync-scheduled.js.map +1 -0
- package/dist/src/cli/helpers/init/external-import-grouping.d.ts +53 -0
- package/dist/src/cli/helpers/init/external-import-grouping.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/external-import-grouping.js +287 -0
- package/dist/src/cli/helpers/init/external-import-grouping.js.map +1 -0
- package/dist/src/cli/helpers/init/external-import.d.ts +1 -34
- package/dist/src/cli/helpers/init/external-import.d.ts.map +1 -1
- package/dist/src/cli/helpers/init/external-import.js +15 -486
- package/dist/src/cli/helpers/init/external-import.js.map +1 -1
- package/dist/src/cli/helpers/init/living-docs-preflight.d.ts +58 -0
- package/dist/src/cli/helpers/init/living-docs-preflight.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/living-docs-preflight.js +290 -0
- package/dist/src/cli/helpers/init/living-docs-preflight.js.map +1 -0
- package/dist/src/cli/helpers/init/sync-profile-helpers.d.ts +48 -0
- package/dist/src/cli/helpers/init/sync-profile-helpers.d.ts.map +1 -0
- package/dist/src/cli/helpers/init/sync-profile-helpers.js +238 -0
- package/dist/src/cli/helpers/init/sync-profile-helpers.js.map +1 -0
- package/dist/src/cli/helpers/init/types.d.ts +1 -0
- package/dist/src/cli/helpers/init/types.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/ado.js +113 -3
- package/dist/src/cli/helpers/issue-tracker/ado.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/index.js +2 -287
- package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.d.ts +25 -0
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.d.ts.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.js +306 -0
- package/dist/src/cli/helpers/issue-tracker/sync-config-writer.js.map +1 -0
- package/dist/src/cli/helpers/issue-tracker/types.d.ts +27 -0
- package/dist/src/cli/helpers/issue-tracker/types.d.ts.map +1 -1
- package/dist/src/cli/helpers/issue-tracker/types.js.map +1 -1
- package/dist/src/cli/workers/living-docs-worker.d.ts +16 -0
- package/dist/src/cli/workers/living-docs-worker.d.ts.map +1 -0
- package/dist/src/cli/workers/living-docs-worker.js +395 -0
- package/dist/src/cli/workers/living-docs-worker.js.map +1 -0
- package/dist/src/core/background/job-dependency.d.ts +45 -0
- package/dist/src/core/background/job-dependency.d.ts.map +1 -0
- package/dist/src/core/background/job-dependency.js +144 -0
- package/dist/src/core/background/job-dependency.js.map +1 -0
- package/dist/src/core/background/job-launcher.d.ts +21 -1
- package/dist/src/core/background/job-launcher.d.ts.map +1 -1
- package/dist/src/core/background/job-launcher.js +93 -0
- package/dist/src/core/background/job-launcher.js.map +1 -1
- package/dist/src/core/background/types.d.ts +73 -2
- package/dist/src/core/background/types.d.ts.map +1 -1
- package/dist/src/core/brownfield/importer.js +1 -1
- package/dist/src/core/brownfield/importer.js.map +1 -1
- package/dist/src/core/comment-builder.d.ts +1 -1
- package/dist/src/core/comment-builder.d.ts.map +1 -1
- package/dist/src/core/{cost-tracker.d.ts → cost/cost-tracker.d.ts} +2 -2
- package/dist/src/core/cost/cost-tracker.d.ts.map +1 -0
- package/dist/src/core/{cost-tracker.js → cost/cost-tracker.js} +2 -2
- package/dist/src/core/cost/cost-tracker.js.map +1 -0
- package/dist/src/core/credentials/credentials-manager.d.ts.map +1 -0
- package/dist/src/core/credentials/credentials-manager.js.map +1 -0
- package/dist/src/core/increment/discipline-checker.js +1 -1
- package/dist/src/core/increment/discipline-checker.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +9 -8
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +40 -42
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/increment/increment-status.d.ts.map +1 -0
- package/dist/src/core/{increment-status.js → increment/increment-status.js} +1 -1
- package/dist/src/core/increment/increment-status.js.map +1 -0
- package/dist/src/core/increment/increment-utils.d.ts.map +1 -0
- package/dist/src/core/increment/increment-utils.js.map +1 -0
- 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/checkpoint-manager.d.ts +120 -0
- package/dist/src/core/living-docs/checkpoint-manager.d.ts.map +1 -0
- package/dist/src/core/living-docs/checkpoint-manager.js +231 -0
- package/dist/src/core/living-docs/checkpoint-manager.js.map +1 -0
- package/dist/src/core/living-docs/discovery.d.ts +91 -0
- package/dist/src/core/living-docs/discovery.d.ts.map +1 -0
- package/dist/src/core/living-docs/discovery.js +656 -0
- package/dist/src/core/living-docs/discovery.js.map +1 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts +23 -4
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -1
- package/dist/src/core/living-docs/feature-archiver.js +133 -30
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -1
- package/dist/src/core/living-docs/foundation-builder.d.ts +37 -0
- package/dist/src/core/living-docs/foundation-builder.d.ts.map +1 -0
- package/dist/src/core/living-docs/foundation-builder.js +357 -0
- package/dist/src/core/living-docs/foundation-builder.js.map +1 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts +58 -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 +204 -7
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/living-docs/module-analyzer.d.ts +97 -0
- package/dist/src/core/living-docs/module-analyzer.d.ts.map +1 -0
- package/dist/src/core/living-docs/module-analyzer.js +427 -0
- package/dist/src/core/living-docs/module-analyzer.js.map +1 -0
- package/dist/src/core/living-docs/suggestions-generator.d.ts +112 -0
- package/dist/src/core/living-docs/suggestions-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/suggestions-generator.js +362 -0
- package/dist/src/core/living-docs/suggestions-generator.js.map +1 -0
- package/dist/src/core/living-docs/workitem-matcher.d.ts +116 -0
- package/dist/src/core/living-docs/workitem-matcher.d.ts.map +1 -0
- package/dist/src/core/living-docs/workitem-matcher.js +356 -0
- package/dist/src/core/living-docs/workitem-matcher.js.map +1 -0
- package/dist/src/core/{plugin-loader.d.ts → plugins/plugin-loader.d.ts} +1 -1
- package/dist/src/core/plugins/plugin-loader.d.ts.map +1 -0
- package/dist/src/core/{plugin-loader.js → plugins/plugin-loader.js} +2 -2
- package/dist/src/core/plugins/plugin-loader.js.map +1 -0
- package/dist/src/core/{project-manager.d.ts → project/project-manager.d.ts} +1 -1
- package/dist/src/core/project/project-manager.d.ts.map +1 -0
- package/dist/src/core/{project-manager.js → project/project-manager.js} +3 -3
- package/dist/src/core/project/project-manager.js.map +1 -0
- package/dist/src/core/project/project-structure-detector.d.ts.map +1 -0
- package/dist/src/core/project/project-structure-detector.js.map +1 -0
- package/dist/src/core/{rfc-generator-v2.d.ts → rfc/rfc-generator-v2.d.ts} +1 -1
- package/dist/src/core/rfc/rfc-generator-v2.d.ts.map +1 -0
- package/dist/src/core/{rfc-generator-v2.js → rfc/rfc-generator-v2.js} +1 -1
- package/dist/src/core/rfc/rfc-generator-v2.js.map +1 -0
- package/dist/src/core/scheduler/index.d.ts +1 -0
- package/dist/src/core/scheduler/index.d.ts.map +1 -1
- package/dist/src/core/scheduler/index.js +1 -0
- package/dist/src/core/scheduler/index.js.map +1 -1
- package/dist/src/core/scheduler/scheduled-job.d.ts +1 -1
- package/dist/src/core/scheduler/scheduled-job.d.ts.map +1 -1
- package/dist/src/core/scheduler/scheduled-job.js.map +1 -1
- package/dist/src/core/scheduler/session-sync-executor.d.ts +138 -0
- package/dist/src/core/scheduler/session-sync-executor.d.ts.map +1 -0
- package/dist/src/core/scheduler/session-sync-executor.js +333 -0
- package/dist/src/core/scheduler/session-sync-executor.js.map +1 -0
- package/dist/src/core/{spec-content-sync.d.ts → specs/spec-content-sync.d.ts} +2 -2
- package/dist/src/core/specs/spec-content-sync.d.ts.map +1 -0
- package/dist/src/core/{spec-content-sync.js → specs/spec-content-sync.js} +1 -1
- package/dist/src/core/specs/spec-content-sync.js.map +1 -0
- package/dist/src/core/{spec-detector.d.ts → specs/spec-detector.d.ts} +1 -1
- package/dist/src/core/specs/spec-detector.d.ts.map +1 -0
- package/dist/src/core/{spec-detector.js → specs/spec-detector.js} +1 -1
- package/dist/src/core/specs/spec-detector.js.map +1 -0
- package/dist/src/core/{spec-identifier-detector.d.ts → specs/spec-identifier-detector.d.ts} +2 -2
- package/dist/src/core/specs/spec-identifier-detector.d.ts.map +1 -0
- package/dist/src/core/{spec-identifier-detector.js → specs/spec-identifier-detector.js} +1 -1
- package/dist/src/core/specs/spec-identifier-detector.js.map +1 -0
- package/dist/src/core/specs/spec-metadata-manager.js +1 -1
- package/dist/src/core/specs/spec-metadata-manager.js.map +1 -1
- package/dist/src/core/specs/spec-task-mapper.d.ts.map +1 -0
- package/dist/src/core/specs/spec-task-mapper.js.map +1 -0
- package/dist/src/core/sync/sync-audit-logger.d.ts +62 -0
- package/dist/src/core/sync/sync-audit-logger.d.ts.map +1 -1
- package/dist/src/core/sync/sync-audit-logger.js +59 -0
- package/dist/src/core/sync/sync-audit-logger.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +51 -27
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +219 -179
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/importers/markdown-generator.d.ts +75 -0
- package/dist/src/importers/markdown-generator.d.ts.map +1 -0
- package/dist/src/importers/markdown-generator.js +250 -0
- package/dist/src/importers/markdown-generator.js.map +1 -0
- package/dist/src/integrations/ado/ado-client.d.ts +93 -0
- package/dist/src/integrations/ado/ado-client.d.ts.map +1 -1
- package/dist/src/integrations/ado/ado-client.js +172 -1
- package/dist/src/integrations/ado/ado-client.js.map +1 -1
- package/dist/src/integrations/jira/jira-client.d.ts +44 -0
- package/dist/src/integrations/jira/jira-client.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-client.js +119 -1
- package/dist/src/integrations/jira/jira-client.js.map +1 -1
- package/dist/src/integrations/jira/jira-incremental-mapper.js +2 -2
- package/dist/src/integrations/jira/jira-incremental-mapper.js.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.js +1 -1
- package/dist/src/integrations/jira/jira-mapper.js.map +1 -1
- package/dist/src/living-docs/epic-id-allocator.d.ts +177 -0
- package/dist/src/living-docs/epic-id-allocator.d.ts.map +1 -0
- package/dist/src/living-docs/epic-id-allocator.js +363 -0
- package/dist/src/living-docs/epic-id-allocator.js.map +1 -0
- package/dist/src/sync/external-change-puller.d.ts +94 -0
- package/dist/src/sync/external-change-puller.d.ts.map +1 -0
- package/dist/src/sync/external-change-puller.js +181 -0
- package/dist/src/sync/external-change-puller.js.map +1 -0
- package/dist/src/sync/index.d.ts +4 -0
- package/dist/src/sync/index.d.ts.map +1 -1
- package/dist/src/sync/index.js +2 -0
- package/dist/src/sync/index.js.map +1 -1
- package/dist/src/sync/living-docs-updater.d.ts +93 -0
- package/dist/src/sync/living-docs-updater.d.ts.map +1 -0
- package/dist/src/sync/living-docs-updater.js +218 -0
- package/dist/src/sync/living-docs-updater.js.map +1 -0
- package/dist/src/testing/test-generator.js +1 -1
- package/dist/src/testing/test-generator.js.map +1 -1
- package/dist/src/utils/cost-reporter.d.ts +1 -1
- package/dist/src/utils/cost-reporter.d.ts.map +1 -1
- package/dist/src/utils/model-selection.js +4 -4
- package/dist/src/utils/model-selection.js.map +1 -1
- package/dist/src/utils/pricing-constants.d.ts +2 -2
- package/dist/src/utils/pricing-constants.js +2 -2
- package/package.json +1 -1
- package/plugins/specweave/.claude-plugin/plugin.json +1 -28
- package/plugins/specweave/agents/code-standards-detective/AGENT.md +3 -3
- package/plugins/specweave/agents/infrastructure/AGENT.md +4 -0
- package/plugins/specweave/agents/performance/AGENT.md +2 -2
- package/plugins/specweave/agents/reflective-reviewer/AGENT.md +3 -3
- package/plugins/specweave/agents/translator/AGENT.md +2 -2
- package/plugins/specweave/commands/specweave-costs.md +2 -2
- package/plugins/specweave/commands/specweave-do.md +2 -2
- package/plugins/specweave/hooks/lib/scheduler-startup.sh +59 -8
- package/plugins/specweave/skills/code-reviewer/SKILL.md +1 -1
- package/plugins/specweave/skills/role-orchestrator/README.md +1 -1
- package/plugins/specweave-ado/agents/ado-manager/AGENT.md +8 -2
- package/plugins/specweave-ado/agents/ado-multi-project-mapper/AGENT.md +2 -2
- package/plugins/specweave-ado/agents/ado-sync-judge/AGENT.md +2 -2
- package/plugins/specweave-ado/lib/ado-spec-commit-sync.d.ts +1 -1
- package/plugins/specweave-ado/lib/ado-spec-commit-sync.js +1 -1
- package/plugins/specweave-ado/lib/ado-spec-commit-sync.ts +1 -1
- package/plugins/specweave-ado/lib/ado-spec-content-sync.js +1 -1
- package/plugins/specweave-ado/lib/ado-spec-content-sync.ts +1 -1
- package/plugins/specweave-ado/lib/conflict-resolver.js +87 -0
- package/plugins/specweave-ado/lib/conflict-resolver.ts +124 -0
- package/plugins/specweave-ado/skills/specweave-ado-mapper/SKILL.md +1 -1
- package/plugins/specweave-backend/agents/database-optimizer/AGENT.md +3 -3
- package/plugins/specweave-backend/skills/dotnet-backend/SKILL.md +1 -1
- package/plugins/specweave-backend/skills/nodejs-backend/SKILL.md +1 -1
- package/plugins/specweave-backend/skills/python-backend/SKILL.md +1 -1
- package/plugins/specweave-confluent/agents/confluent-architect/AGENT.md +6 -1
- package/plugins/specweave-diagrams/agents/diagrams-architect/AGENT.md +2 -2
- package/plugins/specweave-diagrams/skills/diagrams-architect/SKILL.md +1 -1
- package/plugins/specweave-frontend/agents/frontend-architect/AGENT.md +4 -0
- package/plugins/specweave-github/agents/github-manager/AGENT.md +1 -1
- package/plugins/specweave-github/agents/github-task-splitter/AGENT.md +11 -1
- package/plugins/specweave-github/agents/user-story-updater/AGENT.md +6 -1
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +90 -0
- package/plugins/specweave-github/lib/github-client-v2.js +97 -0
- package/plugins/specweave-github/lib/github-client-v2.ts +115 -1
- package/plugins/specweave-github/lib/github-spec-commit-sync.d.ts +1 -1
- package/plugins/specweave-github/lib/github-spec-commit-sync.js +1 -1
- package/plugins/specweave-github/lib/github-spec-commit-sync.ts +1 -1
- package/plugins/specweave-github/lib/github-spec-content-sync.js +1 -1
- package/plugins/specweave-github/lib/github-spec-content-sync.ts +1 -1
- package/plugins/specweave-github/lib/types.ts +21 -0
- package/plugins/specweave-infrastructure/agents/devops/AGENT.md +1 -1
- package/plugins/specweave-infrastructure/agents/network-engineer/AGENT.md +3 -3
- package/plugins/specweave-infrastructure/agents/observability-engineer/AGENT.md +2 -2
- package/plugins/specweave-infrastructure/agents/performance-engineer/AGENT.md +3 -3
- package/plugins/specweave-infrastructure/agents/sre/AGENT.md +2 -2
- package/plugins/specweave-jira/agents/jira-manager/AGENT.md +11 -1
- package/plugins/specweave-jira/commands/import-projects.js +1 -1
- package/plugins/specweave-jira/commands/import-projects.ts +1 -1
- package/plugins/specweave-jira/lib/jira-spec-commit-sync.d.ts +1 -1
- package/plugins/specweave-jira/lib/jira-spec-commit-sync.js +1 -1
- package/plugins/specweave-jira/lib/jira-spec-commit-sync.ts +1 -1
- package/plugins/specweave-jira/lib/jira-spec-content-sync.js +1 -1
- package/plugins/specweave-jira/lib/jira-spec-content-sync.ts +1 -1
- package/plugins/specweave-jira/lib/setup-wizard.js +2 -2
- package/plugins/specweave-jira/lib/setup-wizard.ts +2 -2
- package/plugins/specweave-jira/skills/specweave-jira-mapper/SKILL.md +1 -1
- package/plugins/specweave-kafka/agents/kafka-architect/AGENT.md +5 -1
- package/plugins/specweave-kafka/agents/kafka-devops/AGENT.md +6 -1
- package/plugins/specweave-kafka/agents/kafka-observability/AGENT.md +6 -1
- package/plugins/specweave-kubernetes/agents/kubernetes-architect/AGENT.md +3 -3
- package/plugins/specweave-ml/agents/data-scientist/AGENT.md +2 -1
- package/plugins/specweave-ml/agents/ml-engineer/AGENT.md +2 -1
- package/plugins/specweave-ml/agents/mlops-engineer/AGENT.md +3 -3
- package/plugins/specweave-mobile/agents/mobile-architect/AGENT.md +6 -1
- package/plugins/specweave-payments/agents/payment-integration/AGENT.md +3 -3
- package/plugins/specweave-release/agents/release-manager/AGENT.md +6 -1
- package/plugins/specweave-release/commands/specweave-release-npm.md +8 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +135 -0
- package/plugins/specweave-testing/agents/qa-engineer/AGENT.md +5 -0
- package/src/templates/AGENTS.md.template +97 -0
- package/dist/src/core/cost-tracker.d.ts.map +0 -1
- package/dist/src/core/cost-tracker.js.map +0 -1
- package/dist/src/core/credentials-manager.d.ts.map +0 -1
- package/dist/src/core/credentials-manager.js.map +0 -1
- package/dist/src/core/increment-status.d.ts.map +0 -1
- package/dist/src/core/increment-status.js.map +0 -1
- package/dist/src/core/increment-utils.d.ts.map +0 -1
- package/dist/src/core/increment-utils.js.map +0 -1
- package/dist/src/core/plugin-loader.d.ts.map +0 -1
- package/dist/src/core/plugin-loader.js.map +0 -1
- package/dist/src/core/project-manager.d.ts.map +0 -1
- package/dist/src/core/project-manager.js.map +0 -1
- package/dist/src/core/project-structure-detector.d.ts.map +0 -1
- package/dist/src/core/project-structure-detector.js.map +0 -1
- package/dist/src/core/rfc-generator-v2.d.ts.map +0 -1
- package/dist/src/core/rfc-generator-v2.js.map +0 -1
- package/dist/src/core/spec-content-sync.d.ts.map +0 -1
- package/dist/src/core/spec-content-sync.js.map +0 -1
- package/dist/src/core/spec-detector.d.ts.map +0 -1
- package/dist/src/core/spec-detector.js.map +0 -1
- package/dist/src/core/spec-identifier-detector.d.ts.map +0 -1
- package/dist/src/core/spec-identifier-detector.js.map +0 -1
- package/dist/src/core/spec-task-mapper.d.ts.map +0 -1
- package/dist/src/core/spec-task-mapper.js.map +0 -1
- package/dist/src/utils/spec-parser.d.ts +0 -145
- package/dist/src/utils/spec-parser.d.ts.map +0 -1
- package/dist/src/utils/spec-parser.js +0 -640
- package/dist/src/utils/spec-parser.js.map +0 -1
- package/plugins/specweave/agents/pm/AGENT.md.bak2 +0 -1754
- package/plugins/specweave/hooks/hooks.json.bak +0 -72
- package/plugins/specweave/hooks/hooks.json.v1-backup +0 -16
- package/plugins/specweave/hooks/v2/hooks.json +0 -16
- /package/dist/src/core/{credentials-manager.d.ts → credentials/credentials-manager.d.ts} +0 -0
- /package/dist/src/core/{credentials-manager.js → credentials/credentials-manager.js} +0 -0
- /package/dist/src/core/{increment-status.d.ts → increment/increment-status.d.ts} +0 -0
- /package/dist/src/core/{increment-utils.d.ts → increment/increment-utils.d.ts} +0 -0
- /package/dist/src/core/{increment-utils.js → increment/increment-utils.js} +0 -0
- /package/dist/src/core/{project-structure-detector.d.ts → project/project-structure-detector.d.ts} +0 -0
- /package/dist/src/core/{project-structure-detector.js → project/project-structure-detector.js} +0 -0
- /package/dist/src/core/{spec-task-mapper.d.ts → specs/spec-task-mapper.d.ts} +0 -0
- /package/dist/src/core/{spec-task-mapper.js → specs/spec-task-mapper.js} +0 -0
|
@@ -13,11 +13,13 @@ import { ItemConverter } from '../../../importers/item-converter.js';
|
|
|
13
13
|
import { loadImportConfig } from '../../../config/import-config.js';
|
|
14
14
|
import { selectRepositories } from '../github-repo-selector.js';
|
|
15
15
|
import { detectAllConfigs } from './config-detection.js';
|
|
16
|
-
import { parseEnvFile } from '../../../utils/env-file.js';
|
|
17
16
|
import { getGitHubAuthFromProject } from '../../../utils/auth-helpers.js';
|
|
18
17
|
import { detectJiraStructure, confirmJiraMapping, detectAdoStructure, confirmAdoMapping, buildJiraCoordinatorConfig, buildAdoCoordinatorConfig, } from './jira-ado-auto-detect.js';
|
|
19
18
|
import { normalizeToProjectId } from '../../../utils/project-id-generator.js';
|
|
20
19
|
import { getJobManager, launchImportJob, detectOrphanedJobs, getActiveImportJob } from '../../../core/background/index.js';
|
|
20
|
+
// Extracted helpers for better maintainability
|
|
21
|
+
import { getExistingSyncProfiles, isUmbrellaModeFromConfig, getSyncProfileProviders, loadAdoConfigFromSyncProfile, getUmbrellaProjects, } from './sync-profile-helpers.js';
|
|
22
|
+
import { groupItemsByExternalContainer, groupAdoItemsByParentHierarchy, groupNonHierarchyItems, } from './external-import-grouping.js';
|
|
21
23
|
/**
|
|
22
24
|
* Get translated strings for external import
|
|
23
25
|
*/
|
|
@@ -580,229 +582,11 @@ export async function promptAndRunExternalImport(targetDir, isCI, language = 'en
|
|
|
580
582
|
estimatedTotal: options.estimatedTotal || 100 // Default estimate for progress tracking
|
|
581
583
|
});
|
|
582
584
|
}
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
* Bug: Parent repo was NOT being imported in umbrella mode - only child repos were processed
|
|
589
|
-
*/
|
|
590
|
-
function getExistingSyncProfiles(targetDir) {
|
|
591
|
-
try {
|
|
592
|
-
const configPath = path.join(targetDir, '.specweave', 'config.json');
|
|
593
|
-
if (!fs.existsSync(configPath)) {
|
|
594
|
-
return null;
|
|
595
|
-
}
|
|
596
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
597
|
-
const repos = [];
|
|
598
|
-
// Check for sync.profiles structure (umbrella repo setup - child repos)
|
|
599
|
-
if (config.sync?.profiles && typeof config.sync.profiles === 'object') {
|
|
600
|
-
const profiles = config.sync.profiles;
|
|
601
|
-
for (const [profileId, profile] of Object.entries(profiles)) {
|
|
602
|
-
const p = profile;
|
|
603
|
-
if (p.config?.owner && p.config?.repo) {
|
|
604
|
-
repos.push(`${p.config.owner}/${p.config.repo}`);
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
// CRITICAL FIX: Also include parent repo from umbrella config
|
|
609
|
-
// Parent repo may have issues/items that need to be imported too!
|
|
610
|
-
if (config.umbrella?.enabled && config.umbrella?.parentRepo) {
|
|
611
|
-
// parentRepo can be "owner/repo" or just "repo" (same owner as git remote)
|
|
612
|
-
let parentRepoFullName = config.umbrella.parentRepo;
|
|
613
|
-
// If parentRepo is just the repo name, try to get owner from git remote or first child repo
|
|
614
|
-
if (!parentRepoFullName.includes('/')) {
|
|
615
|
-
// Try to find owner from sync profiles (same owner as child repos)
|
|
616
|
-
const firstProfile = Object.values(config.sync?.profiles || {})[0];
|
|
617
|
-
const owner = firstProfile?.config?.owner;
|
|
618
|
-
if (owner) {
|
|
619
|
-
parentRepoFullName = `${owner}/${parentRepoFullName}`;
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
// Add parent repo if not already in the list
|
|
623
|
-
if (parentRepoFullName.includes('/') && !repos.includes(parentRepoFullName)) {
|
|
624
|
-
repos.push(parentRepoFullName);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
return repos.length > 0 ? repos : null;
|
|
628
|
-
}
|
|
629
|
-
catch (error) {
|
|
630
|
-
// Log warning for debugging - config parsing errors shouldn't be silent
|
|
631
|
-
console.warn(chalk.yellow(` ⚠️ Failed to read sync profiles: ${error instanceof Error ? error.message : String(error)}`));
|
|
632
|
-
return null;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
/**
|
|
636
|
-
* Check if umbrella mode is enabled from config.json
|
|
637
|
-
* Returns true if sync.profiles exist OR umbrella.enabled is true
|
|
638
|
-
*
|
|
639
|
-
* CRITICAL: Used to force global collision detection even for single-group batches
|
|
640
|
-
*/
|
|
641
|
-
function isUmbrellaModeFromConfig(targetDir) {
|
|
642
|
-
try {
|
|
643
|
-
const configPath = path.join(targetDir, '.specweave', 'config.json');
|
|
644
|
-
if (!fs.existsSync(configPath)) {
|
|
645
|
-
return false;
|
|
646
|
-
}
|
|
647
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
648
|
-
// Check 1: umbrella.enabled is explicitly true
|
|
649
|
-
if (config.umbrella?.enabled === true) {
|
|
650
|
-
return true;
|
|
651
|
-
}
|
|
652
|
-
// Check 2: sync.profiles has multiple entries (umbrella repo setup)
|
|
653
|
-
if (config.sync?.profiles && typeof config.sync.profiles === 'object') {
|
|
654
|
-
const profileCount = Object.keys(config.sync.profiles).length;
|
|
655
|
-
if (profileCount >= 2) {
|
|
656
|
-
return true;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
// Check 3: multiProject.enabled is true
|
|
660
|
-
if (config.multiProject?.enabled === true) {
|
|
661
|
-
return true;
|
|
662
|
-
}
|
|
663
|
-
return false;
|
|
664
|
-
}
|
|
665
|
-
catch {
|
|
666
|
-
return false;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
/**
|
|
670
|
-
* Get sync profile providers from config.json
|
|
671
|
-
* Returns array of provider names ('github', 'jira', 'ado') from sync profiles
|
|
672
|
-
*/
|
|
673
|
-
function getSyncProfileProviders(targetDir) {
|
|
674
|
-
try {
|
|
675
|
-
const configPath = path.join(targetDir, '.specweave', 'config.json');
|
|
676
|
-
if (!fs.existsSync(configPath)) {
|
|
677
|
-
return [];
|
|
678
|
-
}
|
|
679
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
680
|
-
const providers = new Set();
|
|
681
|
-
// Check sync.profiles structure
|
|
682
|
-
if (config.sync?.profiles && typeof config.sync.profiles === 'object') {
|
|
683
|
-
for (const profile of Object.values(config.sync.profiles)) {
|
|
684
|
-
const p = profile;
|
|
685
|
-
if (p.provider) {
|
|
686
|
-
providers.add(p.provider.toLowerCase());
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
// Also check top-level sync.provider
|
|
691
|
-
if (config.sync?.provider) {
|
|
692
|
-
providers.add(config.sync.provider.toLowerCase());
|
|
693
|
-
}
|
|
694
|
-
return Array.from(providers);
|
|
695
|
-
}
|
|
696
|
-
catch {
|
|
697
|
-
return [];
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
/**
|
|
701
|
-
* Load ADO config from sync profile when detectAllConfigs() fails
|
|
702
|
-
* This ensures work items are imported even when the main detection fails
|
|
703
|
-
*
|
|
704
|
-
* CRITICAL FIX (2025-11-29): This fixes the bug where ADO folders were created
|
|
705
|
-
* but no work items were imported because ado was null in the import flow.
|
|
706
|
-
*
|
|
707
|
-
* ENHANCED (2025-11-30): Now supports multi-project ADO setups by collecting
|
|
708
|
-
* ALL ADO profiles and building the projects array for multi-project import.
|
|
709
|
-
*/
|
|
710
|
-
function loadAdoConfigFromSyncProfile(targetDir) {
|
|
711
|
-
try {
|
|
712
|
-
const configPath = path.join(targetDir, '.specweave', 'config.json');
|
|
713
|
-
if (!fs.existsSync(configPath)) {
|
|
714
|
-
return null;
|
|
715
|
-
}
|
|
716
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
717
|
-
// Load PAT from .env file (needed for all profiles)
|
|
718
|
-
let pat;
|
|
719
|
-
const envPath = path.join(targetDir, '.env');
|
|
720
|
-
if (fs.existsSync(envPath)) {
|
|
721
|
-
const envContent = fs.readFileSync(envPath, 'utf-8');
|
|
722
|
-
const envVars = parseEnvFile(envContent);
|
|
723
|
-
pat = envVars.AZURE_DEVOPS_PAT || envVars.ADO_PAT;
|
|
724
|
-
}
|
|
725
|
-
// Also check environment variables
|
|
726
|
-
if (!pat) {
|
|
727
|
-
pat = process.env.AZURE_DEVOPS_PAT || process.env.ADO_PAT;
|
|
728
|
-
}
|
|
729
|
-
if (!pat) {
|
|
730
|
-
return null;
|
|
731
|
-
}
|
|
732
|
-
// Collect ALL ADO profiles for multi-project support
|
|
733
|
-
const adoProjects = [];
|
|
734
|
-
let organization;
|
|
735
|
-
let strategy;
|
|
736
|
-
if (config.sync?.profiles && typeof config.sync.profiles === 'object') {
|
|
737
|
-
const activeProfileId = config.sync.activeProfile;
|
|
738
|
-
for (const [profileId, profile] of Object.entries(config.sync.profiles)) {
|
|
739
|
-
const p = profile;
|
|
740
|
-
if (p.provider?.toLowerCase() === 'ado' && p.config) {
|
|
741
|
-
const profileConfig = p.config;
|
|
742
|
-
if (profileConfig.organization && profileConfig.project) {
|
|
743
|
-
// Use first organization found (they should all be the same)
|
|
744
|
-
if (!organization) {
|
|
745
|
-
organization = profileConfig.organization;
|
|
746
|
-
}
|
|
747
|
-
// Use first strategy found
|
|
748
|
-
if (!strategy && profileConfig.strategy) {
|
|
749
|
-
strategy = profileConfig.strategy;
|
|
750
|
-
}
|
|
751
|
-
adoProjects.push({
|
|
752
|
-
name: profileConfig.project,
|
|
753
|
-
areaPaths: profileConfig.areaPaths,
|
|
754
|
-
isDefault: profileId === activeProfileId,
|
|
755
|
-
isUmbrella: profileConfig.isUmbrella
|
|
756
|
-
});
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
}
|
|
761
|
-
// Return null if no ADO projects found
|
|
762
|
-
if (adoProjects.length === 0 || !organization) {
|
|
763
|
-
return null;
|
|
764
|
-
}
|
|
765
|
-
// Return multi-project config
|
|
766
|
-
const defaultProject = adoProjects.find(p => p.isDefault) || adoProjects[0];
|
|
767
|
-
return {
|
|
768
|
-
orgUrl: `https://dev.azure.com/${organization}`,
|
|
769
|
-
project: defaultProject.name, // Primary project for backwards compatibility
|
|
770
|
-
pat,
|
|
771
|
-
strategy,
|
|
772
|
-
projects: adoProjects // Multi-project support
|
|
773
|
-
};
|
|
774
|
-
}
|
|
775
|
-
catch {
|
|
776
|
-
return null;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
/**
|
|
780
|
-
* Get umbrella project names from config.json
|
|
781
|
-
* Umbrella projects are folder-structure-only (no items imported)
|
|
782
|
-
*/
|
|
783
|
-
function getUmbrellaProjects(targetDir) {
|
|
784
|
-
try {
|
|
785
|
-
const configPath = path.join(targetDir, '.specweave', 'config.json');
|
|
786
|
-
if (!fs.existsSync(configPath)) {
|
|
787
|
-
return [];
|
|
788
|
-
}
|
|
789
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
790
|
-
const umbrellaProjects = [];
|
|
791
|
-
// Check sync.profiles for ADO profiles with isUmbrella flag
|
|
792
|
-
if (config.sync?.profiles && typeof config.sync.profiles === 'object') {
|
|
793
|
-
for (const profile of Object.values(config.sync.profiles)) {
|
|
794
|
-
const p = profile;
|
|
795
|
-
if (p.provider === 'ado' && p.config?.isUmbrella && p.config?.project) {
|
|
796
|
-
umbrellaProjects.push(p.config.project);
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
return umbrellaProjects;
|
|
801
|
-
}
|
|
802
|
-
catch {
|
|
803
|
-
return [];
|
|
804
|
-
}
|
|
805
|
-
}
|
|
585
|
+
// getExistingSyncProfiles moved to ./sync-profile-helpers.ts
|
|
586
|
+
// isUmbrellaModeFromConfig moved to ./sync-profile-helpers.ts
|
|
587
|
+
// getSyncProfileProviders moved to ./sync-profile-helpers.ts
|
|
588
|
+
// loadAdoConfigFromSyncProfile moved to ./sync-profile-helpers.ts
|
|
589
|
+
// getUmbrellaProjects moved to ./sync-profile-helpers.ts
|
|
806
590
|
/**
|
|
807
591
|
* Prompt for multi-repository selection
|
|
808
592
|
*/
|
|
@@ -1206,268 +990,12 @@ async function convertToLivingDocs(targetDir, result, spinner) {
|
|
|
1206
990
|
throw conversionError;
|
|
1207
991
|
}
|
|
1208
992
|
}
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
for (const item of items) {
|
|
1216
|
-
// Extract repo name from sourceRepo (e.g., "owner/repo" -> "repo")
|
|
1217
|
-
let repoKey = '_default';
|
|
1218
|
-
if (item.sourceRepo) {
|
|
1219
|
-
// sourceRepo is "owner/repo", we want just "repo"
|
|
1220
|
-
const parts = item.sourceRepo.split('/');
|
|
1221
|
-
const rawRepoName = parts.length > 1 ? parts[1] : item.sourceRepo;
|
|
1222
|
-
// Sanitize repo name to prevent path injection:
|
|
1223
|
-
// - Allow only alphanumeric, hyphens, underscores
|
|
1224
|
-
// - Trim leading/trailing hyphens
|
|
1225
|
-
// - Limit to 100 chars
|
|
1226
|
-
repoKey = rawRepoName
|
|
1227
|
-
.replace(/[^a-zA-Z0-9-_]/g, '-')
|
|
1228
|
-
.replace(/^-+|-+$/g, '')
|
|
1229
|
-
.slice(0, 100);
|
|
1230
|
-
// Fall back to _default if sanitization results in empty string
|
|
1231
|
-
if (!repoKey) {
|
|
1232
|
-
repoKey = '_default';
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
if (!groups.has(repoKey)) {
|
|
1236
|
-
groups.set(repoKey, []);
|
|
1237
|
-
}
|
|
1238
|
-
groups.get(repoKey).push(item);
|
|
1239
|
-
}
|
|
1240
|
-
return groups;
|
|
1241
|
-
}
|
|
1242
|
-
function groupItemsByExternalContainer(items) {
|
|
1243
|
-
const groups = new Map();
|
|
1244
|
-
// Check if we have ADO items with hierarchy
|
|
1245
|
-
const adoItems = items.filter(item => item.platform === 'ado' && item.adoProjectName);
|
|
1246
|
-
const hasAdoHierarchy = adoItems.some(item => item.parentId || item.type === 'epic');
|
|
1247
|
-
// For ADO with hierarchy, use parent-based grouping
|
|
1248
|
-
if (hasAdoHierarchy && adoItems.length > 0) {
|
|
1249
|
-
const adoGroups = groupAdoItemsByParentHierarchy(adoItems);
|
|
1250
|
-
for (const group of adoGroups) {
|
|
1251
|
-
groups.set(group.projectId, group);
|
|
1252
|
-
}
|
|
1253
|
-
// Also process non-ADO items normally
|
|
1254
|
-
const nonAdoItems = items.filter(item => item.platform !== 'ado' || !item.adoProjectName);
|
|
1255
|
-
if (nonAdoItems.length > 0) {
|
|
1256
|
-
const nonAdoGroups = groupNonHierarchyItems(nonAdoItems);
|
|
1257
|
-
for (const group of nonAdoGroups) {
|
|
1258
|
-
// Avoid key collisions with ADO groups
|
|
1259
|
-
const uniqueKey = `other:${group.projectId}`;
|
|
1260
|
-
groups.set(uniqueKey, group);
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
return Array.from(groups.values());
|
|
1264
|
-
}
|
|
1265
|
-
// No ADO hierarchy - use original grouping logic for all items
|
|
1266
|
-
return groupNonHierarchyItems(items);
|
|
1267
|
-
}
|
|
1268
|
-
/**
|
|
1269
|
-
* Group ADO items by their parent Epic/Capability hierarchy
|
|
1270
|
-
* Each top-level Epic/Capability becomes its own FS-XXX folder
|
|
1271
|
-
*/
|
|
1272
|
-
function groupAdoItemsByParentHierarchy(items) {
|
|
1273
|
-
const groups = new Map();
|
|
1274
|
-
// Build item lookup map
|
|
1275
|
-
const itemById = new Map();
|
|
1276
|
-
for (const item of items) {
|
|
1277
|
-
itemById.set(item.id, item);
|
|
1278
|
-
}
|
|
1279
|
-
// Find feature-level types (these become folder leaders)
|
|
1280
|
-
const featureLevelTypes = new Set(['capability', 'epic', 'feature']);
|
|
1281
|
-
// Find ALL top-level parents (Epics/Capabilities that are NOT children of other items in our dataset)
|
|
1282
|
-
const topLevelParents = new Map();
|
|
1283
|
-
for (const item of items) {
|
|
1284
|
-
const witType = item.adoWorkItemType?.toLowerCase() || item.type;
|
|
1285
|
-
if (featureLevelTypes.has(witType)) {
|
|
1286
|
-
// Check if this item's parent is NOT in our dataset (making it a top-level parent)
|
|
1287
|
-
const hasParentInDataset = item.parentId && itemById.has(item.parentId);
|
|
1288
|
-
if (!hasParentInDataset) {
|
|
1289
|
-
topLevelParents.set(item.id, item);
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
// Function to find the top-level parent for an item
|
|
1294
|
-
function findTopLevelParent(item) {
|
|
1295
|
-
// If this item IS a top-level parent, return it
|
|
1296
|
-
if (topLevelParents.has(item.id)) {
|
|
1297
|
-
return item;
|
|
1298
|
-
}
|
|
1299
|
-
// Walk up the parent chain
|
|
1300
|
-
let current = item;
|
|
1301
|
-
const visited = new Set();
|
|
1302
|
-
while (current && current.parentId && !visited.has(current.id)) {
|
|
1303
|
-
visited.add(current.id);
|
|
1304
|
-
// Check if parent is a top-level parent
|
|
1305
|
-
if (topLevelParents.has(current.parentId)) {
|
|
1306
|
-
return topLevelParents.get(current.parentId);
|
|
1307
|
-
}
|
|
1308
|
-
// Move to parent
|
|
1309
|
-
current = itemById.get(current.parentId);
|
|
1310
|
-
}
|
|
1311
|
-
// No top-level parent found
|
|
1312
|
-
return undefined;
|
|
1313
|
-
}
|
|
1314
|
-
// Create groups for each top-level parent first
|
|
1315
|
-
for (const [parentId, parentItem] of topLevelParents) {
|
|
1316
|
-
const containerId = parentItem.adoProjectName || 'default';
|
|
1317
|
-
const projectId = normalizeToProjectId(parentItem.title) || `ado-${parentId.replace('ADO-', '')}`;
|
|
1318
|
-
const groupKey = `ado:parent:${parentId}`;
|
|
1319
|
-
groups.set(groupKey, {
|
|
1320
|
-
containerId,
|
|
1321
|
-
containerType: 'ado',
|
|
1322
|
-
projectId,
|
|
1323
|
-
items: [parentItem], // Parent item goes first
|
|
1324
|
-
externalContainer: {
|
|
1325
|
-
type: 'ado-project',
|
|
1326
|
-
containerId,
|
|
1327
|
-
containerName: containerId,
|
|
1328
|
-
areaPath: parentItem.adoAreaPath
|
|
1329
|
-
},
|
|
1330
|
-
parentItem
|
|
1331
|
-
});
|
|
1332
|
-
}
|
|
1333
|
-
// Assign child items to their parent groups
|
|
1334
|
-
for (const item of items) {
|
|
1335
|
-
// Skip top-level parents (already added)
|
|
1336
|
-
if (topLevelParents.has(item.id)) {
|
|
1337
|
-
continue;
|
|
1338
|
-
}
|
|
1339
|
-
// Find the top-level parent
|
|
1340
|
-
const topLevelParent = findTopLevelParent(item);
|
|
1341
|
-
if (topLevelParent) {
|
|
1342
|
-
// Add to parent's group
|
|
1343
|
-
const groupKey = `ado:parent:${topLevelParent.id}`;
|
|
1344
|
-
const group = groups.get(groupKey);
|
|
1345
|
-
if (group) {
|
|
1346
|
-
group.items.push(item);
|
|
1347
|
-
}
|
|
1348
|
-
}
|
|
1349
|
-
else {
|
|
1350
|
-
// No parent found - group by area path (2-level structure: project/areaPath)
|
|
1351
|
-
// This handles orphan items (User Stories with parents outside our dataset)
|
|
1352
|
-
// CRITICAL FIX (2025-12-01): Group by area path, NOT by User Story title
|
|
1353
|
-
const containerId = item.adoProjectName || 'default';
|
|
1354
|
-
// Extract area path leaf segment for grouping (e.g., "Project\Platform-Engineering" → "platform-engineering")
|
|
1355
|
-
let areaFolder = '_default';
|
|
1356
|
-
if (item.adoAreaPath) {
|
|
1357
|
-
const segments = item.adoAreaPath.split('\\');
|
|
1358
|
-
// Use leaf segment, or second segment if only project name
|
|
1359
|
-
const leafSegment = segments.length > 1 ? segments[segments.length - 1] : segments[0];
|
|
1360
|
-
areaFolder = normalizeToProjectId(leafSegment) || '_default';
|
|
1361
|
-
}
|
|
1362
|
-
// Group all items without parents by their area path
|
|
1363
|
-
// This ensures siblings with same area path stay together
|
|
1364
|
-
const groupKey = `ado:area:${containerId}:${areaFolder}`;
|
|
1365
|
-
const projectId = areaFolder;
|
|
1366
|
-
if (!groups.has(groupKey)) {
|
|
1367
|
-
groups.set(groupKey, {
|
|
1368
|
-
containerId,
|
|
1369
|
-
containerType: 'ado',
|
|
1370
|
-
projectId,
|
|
1371
|
-
items: [],
|
|
1372
|
-
externalContainer: {
|
|
1373
|
-
type: 'ado-project',
|
|
1374
|
-
containerId,
|
|
1375
|
-
containerName: containerId,
|
|
1376
|
-
areaPath: item.adoAreaPath
|
|
1377
|
-
}
|
|
1378
|
-
});
|
|
1379
|
-
}
|
|
1380
|
-
groups.get(groupKey).items.push(item);
|
|
1381
|
-
}
|
|
1382
|
-
}
|
|
1383
|
-
// Log grouping results for diagnostics
|
|
1384
|
-
console.log(chalk.cyan(` 📊 ADO Hierarchy Grouping:`));
|
|
1385
|
-
console.log(chalk.gray(` → ${topLevelParents.size} top-level Epics/Capabilities found`));
|
|
1386
|
-
for (const [key, group] of groups) {
|
|
1387
|
-
const parentInfo = group.parentItem
|
|
1388
|
-
? ` (parent: ${group.parentItem.adoWorkItemType || 'Epic'} "${group.parentItem.title.slice(0, 30)}...")`
|
|
1389
|
-
: '';
|
|
1390
|
-
console.log(chalk.gray(` → ${group.projectId}: ${group.items.length} items${parentInfo}`));
|
|
1391
|
-
}
|
|
1392
|
-
return Array.from(groups.values());
|
|
1393
|
-
}
|
|
1394
|
-
/**
|
|
1395
|
-
* Group non-hierarchy items (JIRA, GitHub, or ADO without hierarchy)
|
|
1396
|
-
* Original grouping logic by project/board/repo
|
|
1397
|
-
*/
|
|
1398
|
-
function groupNonHierarchyItems(items) {
|
|
1399
|
-
const groups = new Map();
|
|
1400
|
-
for (const item of items) {
|
|
1401
|
-
let groupKey;
|
|
1402
|
-
let containerType = null;
|
|
1403
|
-
let containerId;
|
|
1404
|
-
let projectId;
|
|
1405
|
-
let externalContainer;
|
|
1406
|
-
// Check for JIRA container context
|
|
1407
|
-
if (item.jiraProjectKey) {
|
|
1408
|
-
containerType = 'jira';
|
|
1409
|
-
containerId = item.jiraProjectKey;
|
|
1410
|
-
// Project ID from board name (if available) or default
|
|
1411
|
-
projectId = item.jiraBoardName
|
|
1412
|
-
? normalizeToProjectId(item.jiraBoardName) || 'default'
|
|
1413
|
-
: 'default';
|
|
1414
|
-
groupKey = `jira:${containerId}:${projectId}`;
|
|
1415
|
-
externalContainer = {
|
|
1416
|
-
type: 'jira-project',
|
|
1417
|
-
containerId: containerId,
|
|
1418
|
-
containerName: containerId,
|
|
1419
|
-
boardId: item.jiraBoardId,
|
|
1420
|
-
boardName: item.jiraBoardName
|
|
1421
|
-
};
|
|
1422
|
-
}
|
|
1423
|
-
// Check for ADO container context (without hierarchy)
|
|
1424
|
-
else if (item.adoProjectName) {
|
|
1425
|
-
containerType = 'ado';
|
|
1426
|
-
containerId = item.adoProjectName;
|
|
1427
|
-
// Project ID from area path (extract last segment) or default
|
|
1428
|
-
if (item.adoAreaPath) {
|
|
1429
|
-
const areaSegments = item.adoAreaPath.split('\\');
|
|
1430
|
-
const lastSegment = areaSegments[areaSegments.length - 1];
|
|
1431
|
-
projectId = normalizeToProjectId(lastSegment) || 'default';
|
|
1432
|
-
}
|
|
1433
|
-
else {
|
|
1434
|
-
projectId = 'default';
|
|
1435
|
-
}
|
|
1436
|
-
groupKey = `ado:${containerId}:${projectId}`;
|
|
1437
|
-
externalContainer = {
|
|
1438
|
-
type: 'ado-project',
|
|
1439
|
-
containerId: containerId,
|
|
1440
|
-
containerName: containerId,
|
|
1441
|
-
areaPath: item.adoAreaPath
|
|
1442
|
-
};
|
|
1443
|
-
}
|
|
1444
|
-
// GitHub or default (1-level structure)
|
|
1445
|
-
else {
|
|
1446
|
-
// Use sourceRepo if available, otherwise '_default'
|
|
1447
|
-
if (item.sourceRepo) {
|
|
1448
|
-
const parts = item.sourceRepo.split('/');
|
|
1449
|
-
const rawRepoName = parts.length > 1 ? parts[1] : item.sourceRepo;
|
|
1450
|
-
projectId = normalizeToProjectId(rawRepoName) || '_default';
|
|
1451
|
-
}
|
|
1452
|
-
else {
|
|
1453
|
-
projectId = '_default';
|
|
1454
|
-
}
|
|
1455
|
-
groupKey = `gh:${projectId}`;
|
|
1456
|
-
// No externalContainer for GitHub (1-level structure)
|
|
1457
|
-
}
|
|
1458
|
-
if (!groups.has(groupKey)) {
|
|
1459
|
-
groups.set(groupKey, {
|
|
1460
|
-
containerId: containerId || projectId,
|
|
1461
|
-
containerType,
|
|
1462
|
-
projectId,
|
|
1463
|
-
items: [],
|
|
1464
|
-
externalContainer
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1467
|
-
groups.get(groupKey).items.push(item);
|
|
1468
|
-
}
|
|
1469
|
-
return Array.from(groups.values());
|
|
1470
|
-
}
|
|
993
|
+
// groupItemsBySourceRepo moved to ./external-import-grouping.ts
|
|
994
|
+
// Grouping functions moved to ./external-import-grouping.ts
|
|
995
|
+
// - ContainerGroup interface
|
|
996
|
+
// - groupItemsByExternalContainer()
|
|
997
|
+
// - groupAdoItemsByParentHierarchy()
|
|
998
|
+
// - groupNonHierarchyItems()
|
|
1471
999
|
/**
|
|
1472
1000
|
* Create empty result object
|
|
1473
1001
|
*/
|
|
@@ -1483,6 +1011,7 @@ function emptyResult() {
|
|
|
1483
1011
|
// ============================================================================
|
|
1484
1012
|
// TEST EXPORTS - For unit testing internal functions
|
|
1485
1013
|
// ============================================================================
|
|
1014
|
+
// Re-export from extracted modules for backwards compatibility
|
|
1486
1015
|
export const __test__ = {
|
|
1487
1016
|
groupAdoItemsByParentHierarchy,
|
|
1488
1017
|
groupItemsByExternalContainer,
|