specweave 0.18.0 → 0.20.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.md +229 -1817
- package/README.md +68 -0
- package/bin/specweave.js +62 -6
- package/dist/locales/de/.gitkeep +0 -0
- package/dist/locales/de/cli.json +108 -0
- package/dist/locales/en/cli.json +287 -0
- package/dist/locales/en/errors.json +7 -0
- package/dist/locales/en/templates.json +6 -0
- package/dist/locales/es/.gitkeep +0 -0
- package/dist/locales/es/cli.json +41 -0
- package/dist/locales/fr/.gitkeep +0 -0
- package/dist/locales/fr/cli.json +108 -0
- package/dist/locales/ja/.gitkeep +0 -0
- package/dist/locales/ja/cli.json +108 -0
- package/dist/locales/ko/.gitkeep +0 -0
- package/dist/locales/ko/cli.json +108 -0
- package/dist/locales/pt/.gitkeep +0 -0
- package/dist/locales/pt/cli.json +108 -0
- package/dist/locales/ru/.gitkeep +0 -0
- package/dist/locales/ru/cli.json +269 -0
- package/dist/locales/zh/.gitkeep +0 -0
- package/dist/locales/zh/cli.json +108 -0
- package/dist/plugins/specweave/lib/hooks/sync-living-docs.d.ts.map +1 -1
- package/dist/plugins/specweave/lib/hooks/sync-living-docs.js +3 -0
- package/dist/plugins/specweave/lib/hooks/sync-living-docs.js.map +1 -1
- package/dist/plugins/specweave/lib/hooks/update-ac-status.d.ts +21 -0
- package/dist/plugins/specweave/lib/hooks/update-ac-status.d.ts.map +1 -0
- package/dist/plugins/specweave/lib/hooks/update-ac-status.js +162 -0
- package/dist/plugins/specweave/lib/hooks/update-ac-status.js.map +1 -0
- 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 +65 -6
- package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts +25 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js +191 -0
- package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js.map +1 -0
- package/dist/plugins/specweave-github/lib/completion-calculator.d.ts +112 -0
- package/dist/plugins/specweave-github/lib/completion-calculator.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/completion-calculator.js +301 -0
- package/dist/plugins/specweave-github/lib/completion-calculator.js.map +1 -0
- package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts +3 -3
- package/dist/plugins/specweave-github/lib/duplicate-detector.js +3 -3
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts +70 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.js +258 -0
- package/dist/plugins/specweave-github/lib/epic-content-builder.js.map +1 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +14 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-client-v2.js +51 -0
- package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts +2 -2
- package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts.map +1 -1
- package/dist/plugins/specweave-github/lib/github-epic-sync.js +20 -5
- package/dist/plugins/specweave-github/lib/github-epic-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts +87 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync.js +412 -0
- package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -0
- 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 +64 -13
- package/dist/plugins/specweave-github/lib/github-spec-content-sync.js.map +1 -1
- package/dist/plugins/specweave-github/lib/progress-comment-builder.d.ts +78 -0
- package/dist/plugins/specweave-github/lib/progress-comment-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/progress-comment-builder.js +237 -0
- package/dist/plugins/specweave-github/lib/progress-comment-builder.js.map +1 -0
- package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts +97 -0
- package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/user-story-content-builder.js +301 -0
- package/dist/plugins/specweave-github/lib/user-story-content-builder.js.map +1 -0
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts +83 -0
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts.map +1 -0
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +386 -0
- package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts +28 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts.map +1 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js +156 -0
- package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.d.ts +57 -0
- package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.js +248 -0
- package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/cli/types.d.ts +82 -0
- package/dist/plugins/specweave-kafka/lib/cli/types.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/cli/types.js +13 -0
- package/dist/plugins/specweave-kafka/lib/cli/types.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/mcp/detector.d.ts +49 -0
- package/dist/plugins/specweave-kafka/lib/mcp/detector.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/mcp/detector.js +316 -0
- package/dist/plugins/specweave-kafka/lib/mcp/detector.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/mcp/types.d.ts +70 -0
- package/dist/plugins/specweave-kafka/lib/mcp/types.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/mcp/types.js +23 -0
- package/dist/plugins/specweave-kafka/lib/mcp/types.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/utils/partitioning.d.ts +85 -0
- package/dist/plugins/specweave-kafka/lib/utils/partitioning.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/utils/partitioning.js +281 -0
- package/dist/plugins/specweave-kafka/lib/utils/partitioning.js.map +1 -0
- package/dist/plugins/specweave-kafka/lib/utils/sizing.d.ts +75 -0
- package/dist/plugins/specweave-kafka/lib/utils/sizing.d.ts.map +1 -0
- package/dist/plugins/specweave-kafka/lib/utils/sizing.js +238 -0
- package/dist/plugins/specweave-kafka/lib/utils/sizing.js.map +1 -0
- package/dist/spec-parser.js +629 -0
- package/dist/src/cli/commands/import-docs.js +4 -4
- package/dist/src/cli/commands/import-docs.js.map +1 -1
- package/dist/src/cli/commands/init-multiproject.d.ts.map +1 -1
- package/dist/src/cli/commands/init-multiproject.js +17 -18
- 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 +107 -3
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/migrate-to-multiproject.d.ts.map +1 -1
- package/dist/src/cli/commands/migrate-to-multiproject.js +8 -4
- package/dist/src/cli/commands/migrate-to-multiproject.js.map +1 -1
- package/dist/src/cli/commands/switch-project.d.ts.map +1 -1
- package/dist/src/cli/commands/switch-project.js +9 -26
- package/dist/src/cli/commands/switch-project.js.map +1 -1
- package/dist/src/cli/commands/sync-spec-content.js +3 -0
- package/dist/src/cli/commands/sync-spec-content.js.map +1 -1
- package/dist/src/core/deduplication/command-deduplicator.d.ts +166 -0
- package/dist/src/core/deduplication/command-deduplicator.d.ts.map +1 -0
- package/dist/src/core/deduplication/command-deduplicator.js +254 -0
- package/dist/src/core/deduplication/command-deduplicator.js.map +1 -0
- package/dist/src/core/increment/active-increment-manager.d.ts +42 -15
- package/dist/src/core/increment/active-increment-manager.d.ts.map +1 -1
- package/dist/src/core/increment/active-increment-manager.js +113 -46
- package/dist/src/core/increment/active-increment-manager.js.map +1 -1
- package/dist/src/core/increment/conflict-resolver.d.ts +40 -0
- package/dist/src/core/increment/conflict-resolver.d.ts.map +1 -0
- package/dist/src/core/increment/conflict-resolver.js +219 -0
- package/dist/src/core/increment/conflict-resolver.js.map +1 -0
- package/dist/src/core/increment/discipline-checker.d.ts.map +1 -1
- package/dist/src/core/increment/discipline-checker.js +7 -1
- package/dist/src/core/increment/discipline-checker.js.map +1 -1
- package/dist/src/core/increment/duplicate-detector.d.ts +52 -0
- package/dist/src/core/increment/duplicate-detector.d.ts.map +1 -0
- package/dist/src/core/increment/duplicate-detector.js +276 -0
- package/dist/src/core/increment/duplicate-detector.js.map +1 -0
- package/dist/src/core/increment/increment-archiver.d.ts +90 -0
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -0
- package/dist/src/core/increment/increment-archiver.js +368 -0
- package/dist/src/core/increment/increment-archiver.js.map +1 -0
- package/dist/src/core/increment/increment-reopener.d.ts +165 -0
- package/dist/src/core/increment/increment-reopener.d.ts.map +1 -0
- package/dist/src/core/increment/increment-reopener.js +390 -0
- package/dist/src/core/increment/increment-reopener.js.map +1 -0
- package/dist/src/core/increment/metadata-manager.d.ts +26 -1
- package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
- package/dist/src/core/increment/metadata-manager.js +143 -5
- package/dist/src/core/increment/metadata-manager.js.map +1 -1
- package/dist/src/core/increment/recent-work-scanner.d.ts +121 -0
- package/dist/src/core/increment/recent-work-scanner.d.ts.map +1 -0
- package/dist/src/core/increment/recent-work-scanner.js +303 -0
- package/dist/src/core/increment/recent-work-scanner.js.map +1 -0
- package/dist/src/core/increment/types.d.ts +1 -0
- package/dist/src/core/increment/types.d.ts.map +1 -1
- package/dist/src/core/increment-utils.d.ts +112 -0
- package/dist/src/core/increment-utils.d.ts.map +1 -0
- package/dist/src/core/increment-utils.js +210 -0
- package/dist/src/core/increment-utils.js.map +1 -0
- package/dist/src/core/living-docs/ac-project-specific-generator.d.ts +65 -0
- package/dist/src/core/living-docs/ac-project-specific-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/ac-project-specific-generator.js +175 -0
- package/dist/src/core/living-docs/ac-project-specific-generator.js.map +1 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts +130 -0
- package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -0
- package/dist/src/core/living-docs/feature-archiver.js +549 -0
- package/dist/src/core/living-docs/feature-archiver.js.map +1 -0
- package/dist/src/core/living-docs/feature-id-manager.d.ts +81 -0
- package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -0
- package/dist/src/core/living-docs/feature-id-manager.js +339 -0
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -0
- package/dist/src/core/living-docs/hierarchy-mapper.d.ts +144 -83
- package/dist/src/core/living-docs/hierarchy-mapper.d.ts.map +1 -1
- package/dist/src/core/living-docs/hierarchy-mapper.js +488 -270
- package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
- package/dist/src/core/living-docs/index.d.ts +6 -0
- package/dist/src/core/living-docs/index.d.ts.map +1 -1
- package/dist/src/core/living-docs/index.js +6 -0
- package/dist/src/core/living-docs/index.js.map +1 -1
- package/dist/src/core/living-docs/project-detector.d.ts +6 -0
- package/dist/src/core/living-docs/project-detector.d.ts.map +1 -1
- package/dist/src/core/living-docs/project-detector.js +35 -1
- package/dist/src/core/living-docs/project-detector.js.map +1 -1
- package/dist/src/core/living-docs/spec-distributor.d.ts +100 -26
- package/dist/src/core/living-docs/spec-distributor.d.ts.map +1 -1
- package/dist/src/core/living-docs/spec-distributor.js +1275 -258
- package/dist/src/core/living-docs/spec-distributor.js.map +1 -1
- package/dist/src/core/living-docs/task-project-specific-generator.d.ts +109 -0
- package/dist/src/core/living-docs/task-project-specific-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/task-project-specific-generator.js +221 -0
- package/dist/src/core/living-docs/task-project-specific-generator.js.map +1 -0
- package/dist/src/core/living-docs/types.d.ts +143 -0
- package/dist/src/core/living-docs/types.d.ts.map +1 -1
- package/dist/src/core/project-manager.d.ts +2 -17
- package/dist/src/core/project-manager.d.ts.map +1 -1
- package/dist/src/core/project-manager.js +68 -48
- package/dist/src/core/project-manager.js.map +1 -1
- package/dist/src/core/spec-content-sync.d.ts +1 -1
- package/dist/src/core/spec-content-sync.d.ts.map +1 -1
- package/dist/src/core/sync/enhanced-content-builder.d.ts +32 -54
- package/dist/src/core/sync/enhanced-content-builder.d.ts.map +1 -1
- package/dist/src/core/sync/enhanced-content-builder.js +142 -138
- package/dist/src/core/sync/enhanced-content-builder.js.map +1 -1
- package/dist/src/core/sync/performance-optimizer.d.ts +153 -0
- package/dist/src/core/sync/performance-optimizer.d.ts.map +1 -0
- package/dist/src/core/sync/performance-optimizer.js +220 -0
- package/dist/src/core/sync/performance-optimizer.js.map +1 -0
- package/dist/src/core/sync/retry-handler.d.ts +98 -0
- package/dist/src/core/sync/retry-handler.d.ts.map +1 -0
- package/dist/src/core/sync/retry-handler.js +196 -0
- package/dist/src/core/sync/retry-handler.js.map +1 -0
- package/dist/src/core/sync/spec-content-sync.d.ts +88 -0
- package/dist/src/core/sync/spec-content-sync.d.ts.map +1 -0
- package/dist/src/core/sync/spec-content-sync.js +5 -0
- package/dist/src/core/sync/spec-content-sync.js.map +1 -0
- package/dist/src/core/sync/types.d.ts +52 -0
- package/dist/src/core/sync/types.d.ts.map +1 -0
- package/dist/src/core/sync/types.js +5 -0
- package/dist/src/core/sync/types.js.map +1 -0
- package/dist/src/core/types/config.d.ts +125 -0
- package/dist/src/core/types/config.d.ts.map +1 -1
- package/dist/src/core/types/config.js +25 -0
- package/dist/src/core/types/config.js.map +1 -1
- package/dist/src/core/types/increment-metadata.d.ts +10 -0
- package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
- package/dist/src/core/types/increment-metadata.js +10 -1
- package/dist/src/core/types/increment-metadata.js.map +1 -1
- package/dist/src/integrations/jira/jira-incremental-mapper.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-incremental-mapper.js +4 -8
- package/dist/src/integrations/jira/jira-incremental-mapper.js.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.d.ts.map +1 -1
- package/dist/src/integrations/jira/jira-mapper.js +4 -8
- package/dist/src/integrations/jira/jira-mapper.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
- package/plugins/specweave/COMMANDS.md +13 -4
- package/plugins/specweave/agents/pm/AGENT.md +159 -12
- package/plugins/specweave/commands/specweave-abandon.md +22 -20
- package/plugins/specweave/commands/specweave-archive-features.md +121 -0
- package/plugins/specweave/commands/specweave-archive-increments.md +82 -0
- package/plugins/specweave/commands/specweave-archive.md +363 -0
- package/plugins/specweave/commands/specweave-backlog.md +211 -0
- package/plugins/specweave/commands/specweave-fix-duplicates.md +517 -0
- package/plugins/specweave/commands/specweave-increment.md +4 -3
- package/plugins/specweave/commands/specweave-progress.md +176 -27
- package/plugins/specweave/commands/specweave-reopen.md +391 -0
- package/plugins/specweave/commands/specweave-restore-feature.md +90 -0
- package/plugins/specweave/commands/specweave-restore.md +309 -0
- package/plugins/specweave/commands/specweave-resume.md +51 -23
- package/plugins/specweave/commands/specweave-status.md +41 -7
- package/plugins/specweave/commands/specweave-sync-specs.md +425 -0
- package/plugins/specweave/commands/specweave.md +70 -405
- package/plugins/specweave/hooks/hooks.json +4 -0
- package/plugins/specweave/hooks/lib/sync-spec-content.sh +2 -2
- package/plugins/specweave/hooks/post-increment-planning.sh +26 -2
- package/plugins/specweave/hooks/post-task-completion.sh +39 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh +83 -0
- package/plugins/specweave/hooks/user-prompt-submit.sh +1 -1
- package/plugins/specweave/lib/hooks/sync-living-docs.js +2 -0
- package/plugins/specweave/lib/hooks/sync-living-docs.ts +4 -0
- package/plugins/specweave/lib/hooks/update-ac-status.js +102 -0
- package/plugins/specweave/lib/hooks/update-ac-status.ts +192 -0
- package/plugins/specweave/skills/archive-increments/SKILL.md +198 -0
- package/plugins/specweave/skills/increment-planner/scripts/feature-utils.js +14 -0
- package/plugins/specweave/skills/smart-reopen-detector/SKILL.md +244 -0
- package/plugins/specweave-ado/lib/ado-spec-content-sync.js +49 -5
- package/plugins/specweave-ado/lib/ado-spec-content-sync.ts +72 -6
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-confluent/.claude-plugin/plugin.json +23 -0
- package/plugins/specweave-confluent/README.md +375 -0
- package/plugins/specweave-confluent/agents/confluent-architect/AGENT.md +306 -0
- package/plugins/specweave-confluent/skills/confluent-kafka-connect/SKILL.md +453 -0
- package/plugins/specweave-confluent/skills/confluent-ksqldb/SKILL.md +470 -0
- package/plugins/specweave-confluent/skills/confluent-schema-registry/SKILL.md +316 -0
- package/plugins/specweave-github/agents/github-task-splitter/AGENT.md +2 -2
- package/plugins/specweave-github/agents/user-story-updater/AGENT.md +148 -0
- package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +1 -1
- package/plugins/specweave-github/commands/specweave-github-update-user-story.md +156 -0
- package/plugins/specweave-github/hooks/post-task-completion.sh +42 -9
- package/plugins/specweave-github/lib/completion-calculator.js +262 -0
- package/plugins/specweave-github/lib/completion-calculator.ts +434 -0
- package/plugins/specweave-github/lib/duplicate-detector.js +3 -3
- package/plugins/specweave-github/lib/duplicate-detector.ts +4 -4
- package/plugins/specweave-github/lib/epic-content-builder.js +265 -0
- package/plugins/specweave-github/lib/epic-content-builder.ts +376 -0
- package/plugins/specweave-github/lib/github-client-v2.js +49 -0
- package/plugins/specweave-github/lib/github-client-v2.ts +59 -0
- package/plugins/specweave-github/lib/github-epic-sync.js +23 -24
- package/plugins/specweave-github/lib/github-epic-sync.ts +30 -5
- package/plugins/specweave-github/lib/github-feature-sync.js +381 -0
- package/plugins/specweave-github/lib/github-feature-sync.ts +568 -0
- package/plugins/specweave-github/lib/github-spec-content-sync.js +40 -10
- package/plugins/specweave-github/lib/github-spec-content-sync.ts +82 -14
- package/plugins/specweave-github/lib/progress-comment-builder.js +229 -0
- package/plugins/specweave-github/lib/progress-comment-builder.ts +324 -0
- package/plugins/specweave-github/lib/user-story-content-builder.js +299 -0
- package/plugins/specweave-github/lib/user-story-content-builder.ts +413 -0
- package/plugins/specweave-github/lib/user-story-issue-builder.js +344 -0
- package/plugins/specweave-github/lib/user-story-issue-builder.ts +543 -0
- package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +189 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
- package/plugins/specweave-jira/lib/{enhanced-jira-sync.ts.disabled → enhanced-jira-sync.ts} +26 -52
- package/plugins/specweave-kafka/.claude-plugin/plugin.json +26 -0
- package/plugins/specweave-kafka/IMPLEMENTATION-COMPLETE.md +483 -0
- package/plugins/specweave-kafka/README.md +242 -0
- package/plugins/specweave-kafka/agents/kafka-architect/AGENT.md +235 -0
- package/plugins/specweave-kafka/agents/kafka-devops/AGENT.md +209 -0
- package/plugins/specweave-kafka/agents/kafka-observability/AGENT.md +266 -0
- package/plugins/specweave-kafka/commands/deploy.md +99 -0
- package/plugins/specweave-kafka/commands/dev-env.md +176 -0
- package/plugins/specweave-kafka/commands/mcp-configure.md +101 -0
- package/plugins/specweave-kafka/commands/monitor-setup.md +96 -0
- package/plugins/specweave-kafka/docker/kafka-local/docker-compose.yml +187 -0
- package/plugins/specweave-kafka/docker/redpanda/docker-compose.yml +199 -0
- package/plugins/specweave-kafka/docker/templates/consumer-nodejs.js +225 -0
- package/plugins/specweave-kafka/docker/templates/consumer-python.py +220 -0
- package/plugins/specweave-kafka/docker/templates/producer-nodejs.js +168 -0
- package/plugins/specweave-kafka/docker/templates/producer-python.py +167 -0
- package/plugins/specweave-kafka/lib/adapters/apache-kafka-adapter.js +438 -0
- package/plugins/specweave-kafka/lib/adapters/apache-kafka-adapter.ts +541 -0
- package/plugins/specweave-kafka/lib/adapters/platform-adapter.js +47 -0
- package/plugins/specweave-kafka/lib/adapters/platform-adapter.ts +343 -0
- package/plugins/specweave-kafka/lib/cli/kcat-wrapper.js +258 -0
- package/plugins/specweave-kafka/lib/cli/kcat-wrapper.ts +298 -0
- package/plugins/specweave-kafka/lib/cli/types.js +10 -0
- package/plugins/specweave-kafka/lib/cli/types.ts +92 -0
- package/plugins/specweave-kafka/lib/connectors/connector-catalog.js +305 -0
- package/plugins/specweave-kafka/lib/connectors/connector-catalog.ts +528 -0
- package/plugins/specweave-kafka/lib/documentation/diagram-generator.js +114 -0
- package/plugins/specweave-kafka/lib/documentation/diagram-generator.ts +195 -0
- package/plugins/specweave-kafka/lib/documentation/exporter.js +210 -0
- package/plugins/specweave-kafka/lib/documentation/exporter.ts +338 -0
- package/plugins/specweave-kafka/lib/documentation/schema-catalog-generator.js +60 -0
- package/plugins/specweave-kafka/lib/documentation/schema-catalog-generator.ts +130 -0
- package/plugins/specweave-kafka/lib/documentation/topology-generator.js +143 -0
- package/plugins/specweave-kafka/lib/documentation/topology-generator.ts +290 -0
- package/plugins/specweave-kafka/lib/mcp/detector.js +298 -0
- package/plugins/specweave-kafka/lib/mcp/detector.ts +352 -0
- package/plugins/specweave-kafka/lib/mcp/types.js +21 -0
- package/plugins/specweave-kafka/lib/mcp/types.ts +77 -0
- package/plugins/specweave-kafka/lib/multi-cluster/cluster-config-manager.js +193 -0
- package/plugins/specweave-kafka/lib/multi-cluster/cluster-config-manager.ts +362 -0
- package/plugins/specweave-kafka/lib/multi-cluster/cluster-switcher.js +188 -0
- package/plugins/specweave-kafka/lib/multi-cluster/cluster-switcher.ts +359 -0
- package/plugins/specweave-kafka/lib/multi-cluster/health-aggregator.js +195 -0
- package/plugins/specweave-kafka/lib/multi-cluster/health-aggregator.ts +380 -0
- package/plugins/specweave-kafka/lib/observability/opentelemetry-kafka.js +209 -0
- package/plugins/specweave-kafka/lib/observability/opentelemetry-kafka.ts +358 -0
- package/plugins/specweave-kafka/lib/patterns/advanced-ksqldb-patterns.js +354 -0
- package/plugins/specweave-kafka/lib/patterns/advanced-ksqldb-patterns.ts +563 -0
- package/plugins/specweave-kafka/lib/patterns/circuit-breaker-resilience.js +259 -0
- package/plugins/specweave-kafka/lib/patterns/circuit-breaker-resilience.ts +516 -0
- package/plugins/specweave-kafka/lib/patterns/dead-letter-queue.js +233 -0
- package/plugins/specweave-kafka/lib/patterns/dead-letter-queue.ts +423 -0
- package/plugins/specweave-kafka/lib/patterns/exactly-once-semantics.js +266 -0
- package/plugins/specweave-kafka/lib/patterns/exactly-once-semantics.ts +445 -0
- package/plugins/specweave-kafka/lib/patterns/flink-kafka-integration.js +312 -0
- package/plugins/specweave-kafka/lib/patterns/flink-kafka-integration.ts +561 -0
- package/plugins/specweave-kafka/lib/patterns/multi-dc-replication.js +289 -0
- package/plugins/specweave-kafka/lib/patterns/multi-dc-replication.ts +607 -0
- package/plugins/specweave-kafka/lib/patterns/rate-limiting-backpressure.js +264 -0
- package/plugins/specweave-kafka/lib/patterns/rate-limiting-backpressure.ts +498 -0
- package/plugins/specweave-kafka/lib/patterns/stream-processing-optimization.js +263 -0
- package/plugins/specweave-kafka/lib/patterns/stream-processing-optimization.ts +549 -0
- package/plugins/specweave-kafka/lib/patterns/tiered-storage-compaction.js +205 -0
- package/plugins/specweave-kafka/lib/patterns/tiered-storage-compaction.ts +399 -0
- package/plugins/specweave-kafka/lib/performance/performance-optimizer.js +249 -0
- package/plugins/specweave-kafka/lib/performance/performance-optimizer.ts +427 -0
- package/plugins/specweave-kafka/lib/security/kafka-security.js +252 -0
- package/plugins/specweave-kafka/lib/security/kafka-security.ts +494 -0
- package/plugins/specweave-kafka/lib/utils/capacity-planner.js +203 -0
- package/plugins/specweave-kafka/lib/utils/capacity-planner.ts +469 -0
- package/plugins/specweave-kafka/lib/utils/config-validator.js +419 -0
- package/plugins/specweave-kafka/lib/utils/config-validator.ts +564 -0
- package/plugins/specweave-kafka/lib/utils/partitioning.js +329 -0
- package/plugins/specweave-kafka/lib/utils/partitioning.ts +473 -0
- package/plugins/specweave-kafka/lib/utils/sizing.js +221 -0
- package/plugins/specweave-kafka/lib/utils/sizing.ts +374 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-broker-metrics.json +628 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-cluster-overview.json +564 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-consumer-lag.json +509 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-jvm-metrics.json +674 -0
- package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-topic-metrics.json +578 -0
- package/plugins/specweave-kafka/monitoring/grafana/provisioning/dashboards/kafka.yml +17 -0
- package/plugins/specweave-kafka/monitoring/grafana/provisioning/datasources/prometheus.yml +17 -0
- package/plugins/specweave-kafka/monitoring/prometheus/kafka-alerts.yml +415 -0
- package/plugins/specweave-kafka/monitoring/prometheus/kafka-jmx-exporter.yml +256 -0
- package/plugins/specweave-kafka/package.json +41 -0
- package/plugins/specweave-kafka/skills/kafka-architecture/SKILL.md +647 -0
- package/plugins/specweave-kafka/skills/kafka-cli-tools/SKILL.md +433 -0
- package/plugins/specweave-kafka/skills/kafka-iac-deployment/SKILL.md +449 -0
- package/plugins/specweave-kafka/skills/kafka-kubernetes/SKILL.md +667 -0
- package/plugins/specweave-kafka/skills/kafka-mcp-integration/SKILL.md +273 -0
- package/plugins/specweave-kafka/skills/kafka-observability/SKILL.md +576 -0
- package/plugins/specweave-kafka/templates/config/broker-production.properties +254 -0
- package/plugins/specweave-kafka/templates/config/consumer-low-latency.properties +112 -0
- package/plugins/specweave-kafka/templates/config/producer-high-throughput.properties +120 -0
- package/plugins/specweave-kafka/templates/migration/mirrormaker2-config.properties +234 -0
- package/plugins/specweave-kafka/templates/monitoring/grafana/multi-cluster-dashboard.json +686 -0
- package/plugins/specweave-kafka/terraform/apache-kafka/main.tf +347 -0
- package/plugins/specweave-kafka/terraform/apache-kafka/outputs.tf +107 -0
- package/plugins/specweave-kafka/terraform/apache-kafka/templates/kafka-broker-init.sh.tpl +216 -0
- package/plugins/specweave-kafka/terraform/apache-kafka/variables.tf +156 -0
- package/plugins/specweave-kafka/terraform/aws-msk/main.tf +362 -0
- package/plugins/specweave-kafka/terraform/aws-msk/outputs.tf +93 -0
- package/plugins/specweave-kafka/terraform/aws-msk/templates/server.properties.tpl +32 -0
- package/plugins/specweave-kafka/terraform/aws-msk/variables.tf +235 -0
- package/plugins/specweave-kafka/terraform/azure-event-hubs/main.tf +281 -0
- package/plugins/specweave-kafka/terraform/azure-event-hubs/outputs.tf +118 -0
- package/plugins/specweave-kafka/terraform/azure-event-hubs/variables.tf +148 -0
- package/plugins/specweave-kafka/tsconfig.json +21 -0
- package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +23 -0
- package/plugins/specweave-kafka-streams/README.md +310 -0
- package/plugins/specweave-kafka-streams/skills/kafka-streams-topology/SKILL.md +539 -0
- package/plugins/specweave-n8n/.claude-plugin/plugin.json +22 -0
- package/plugins/specweave-n8n/README.md +354 -0
- package/plugins/specweave-n8n/skills/n8n-kafka-workflows/SKILL.md +504 -0
- package/plugins/specweave-release/commands/specweave-release-platform.md +1 -1
- package/plugins/specweave-release/hooks/post-task-completion.sh +2 -2
- package/src/templates/AGENTS.md.template +601 -7
- package/src/templates/CLAUDE.md.template +188 -88
- package/plugins/specweave-ado/commands/specweave-ado-sync-spec.md +0 -255
- package/plugins/specweave-github/commands/specweave-github-sync-epic.md +0 -248
- package/plugins/specweave-github/commands/specweave-github-sync-from.md +0 -147
- package/plugins/specweave-github/commands/specweave-github-sync-spec.md +0 -208
- package/plugins/specweave-github/commands/specweave-github-sync-tasks.md +0 -530
- package/plugins/specweave-jira/commands/specweave-jira-sync-epic.md +0 -267
- package/plugins/specweave-jira/commands/specweave-jira-sync-spec.md +0 -240
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
SpecContent,
|
|
21
21
|
ContentSyncResult,
|
|
22
22
|
} from '../../../src/core/spec-content-sync.js';
|
|
23
|
+
import { ProgressCommentBuilder } from './progress-comment-builder.js';
|
|
23
24
|
import path from 'path';
|
|
24
25
|
import fs from 'fs/promises';
|
|
25
26
|
|
|
@@ -215,6 +216,11 @@ async function createGitHubIssue(
|
|
|
215
216
|
|
|
216
217
|
/**
|
|
217
218
|
* Update existing GitHub issue with spec content
|
|
219
|
+
*
|
|
220
|
+
* ARCHITECTURE: IMMUTABLE DESCRIPTIONS (Phase 4)
|
|
221
|
+
* - Issue description is NEVER edited after creation
|
|
222
|
+
* - All content updates communicated via progress comments
|
|
223
|
+
* - Metadata updates only (labels, milestone, assignees)
|
|
218
224
|
*/
|
|
219
225
|
async function updateGitHubIssue(
|
|
220
226
|
client: GitHubClientV2,
|
|
@@ -262,36 +268,47 @@ async function updateGitHubIssue(
|
|
|
262
268
|
}
|
|
263
269
|
}
|
|
264
270
|
|
|
265
|
-
// Build updated content using compact format
|
|
266
|
-
const newTitle = `[${spec.identifier.compact}] ${spec.title}`;
|
|
267
|
-
const newBody = buildExternalDescription(spec);
|
|
268
|
-
|
|
269
271
|
if (dryRun) {
|
|
270
|
-
console.log('\n🔍 Dry run - would
|
|
271
|
-
console.log(` Title: ${newTitle}`);
|
|
272
|
-
console.log(` Body:\n${newBody}`);
|
|
272
|
+
console.log('\n🔍 Dry run - would post progress comment');
|
|
273
273
|
|
|
274
274
|
return {
|
|
275
275
|
success: true,
|
|
276
|
-
action: 'updated',
|
|
276
|
+
action: 'updated-via-comment',
|
|
277
277
|
externalId: issueNumber.toString(),
|
|
278
278
|
externalUrl: issue.html_url,
|
|
279
279
|
};
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
//
|
|
283
|
-
|
|
282
|
+
// IMMUTABLE DESCRIPTION PATTERN:
|
|
283
|
+
// ❌ OLD: Update issue body (overwrites description)
|
|
284
|
+
// ✅ NEW: Post progress comment (preserves description)
|
|
284
285
|
|
|
285
|
-
//
|
|
286
|
-
|
|
286
|
+
// Update metadata only (labels via GitHub CLI - no direct API method)
|
|
287
|
+
const labels = [
|
|
288
|
+
'specweave',
|
|
289
|
+
'spec',
|
|
290
|
+
spec.project,
|
|
291
|
+
spec.metadata.priority || 'P2'
|
|
292
|
+
].filter(Boolean);
|
|
293
|
+
|
|
294
|
+
await client.addLabels(issueNumber, labels);
|
|
295
|
+
|
|
296
|
+
// Post progress comment (NOT edit body)
|
|
297
|
+
await postProgressComment(
|
|
298
|
+
client,
|
|
299
|
+
specPath,
|
|
300
|
+
issueNumber,
|
|
301
|
+
spec,
|
|
302
|
+
verbose
|
|
303
|
+
);
|
|
287
304
|
|
|
288
305
|
if (verbose) {
|
|
289
|
-
console.log(`✅
|
|
306
|
+
console.log(`✅ Posted progress comment to issue #${issueNumber}`);
|
|
290
307
|
}
|
|
291
308
|
|
|
292
309
|
return {
|
|
293
310
|
success: true,
|
|
294
|
-
action: 'updated',
|
|
311
|
+
action: 'updated-via-comment',
|
|
295
312
|
externalId: issueNumber.toString(),
|
|
296
313
|
externalUrl: issue.html_url,
|
|
297
314
|
};
|
|
@@ -304,6 +321,57 @@ async function updateGitHubIssue(
|
|
|
304
321
|
}
|
|
305
322
|
}
|
|
306
323
|
|
|
324
|
+
/**
|
|
325
|
+
* Post progress comment to GitHub issue (IMMUTABLE DESCRIPTION PATTERN)
|
|
326
|
+
*
|
|
327
|
+
* This replaces the old pattern of editing issue body.
|
|
328
|
+
* Benefits:
|
|
329
|
+
* - Preserves original issue description
|
|
330
|
+
* - Creates audit trail of changes
|
|
331
|
+
* - Stakeholders get notifications on updates
|
|
332
|
+
*/
|
|
333
|
+
async function postProgressComment(
|
|
334
|
+
client: GitHubClientV2,
|
|
335
|
+
specPath: string,
|
|
336
|
+
issueNumber: number,
|
|
337
|
+
spec: SpecContent,
|
|
338
|
+
verbose: boolean = false
|
|
339
|
+
): Promise<void> {
|
|
340
|
+
try {
|
|
341
|
+
// Extract increment ID from spec path or identifier
|
|
342
|
+
// Examples:
|
|
343
|
+
// - .specweave/increments/0031-external-tool-sync/spec.md → 0031
|
|
344
|
+
// - .specweave/docs/internal/specs/default/FS-031/us-001-*.md → FS-031
|
|
345
|
+
|
|
346
|
+
let incrementId = 'unknown';
|
|
347
|
+
|
|
348
|
+
// Try to extract from spec path
|
|
349
|
+
const incrementMatch = specPath.match(/increments\/([^/]+)/);
|
|
350
|
+
if (incrementMatch) {
|
|
351
|
+
incrementId = incrementMatch[1];
|
|
352
|
+
} else {
|
|
353
|
+
// Fallback: use spec identifier
|
|
354
|
+
incrementId = spec.identifier.compact;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// Build progress comment using ProgressCommentBuilder
|
|
358
|
+
const builder = new ProgressCommentBuilder(specPath);
|
|
359
|
+
const comment = await builder.buildProgressComment(incrementId);
|
|
360
|
+
|
|
361
|
+
// Post comment (using addComment method)
|
|
362
|
+
await client.addComment(issueNumber, comment);
|
|
363
|
+
|
|
364
|
+
if (verbose) {
|
|
365
|
+
console.log(` 📊 Progress comment posted (${comment.length} chars)`);
|
|
366
|
+
}
|
|
367
|
+
} catch (error: any) {
|
|
368
|
+
// Non-blocking: Log error but don't fail the sync
|
|
369
|
+
if (verbose) {
|
|
370
|
+
console.error(` ⚠️ Failed to post progress comment: ${error.message}`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
307
375
|
/**
|
|
308
376
|
* Count user stories in issue body
|
|
309
377
|
*/
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as yaml from "yaml";
|
|
5
|
+
class ProgressCommentBuilder {
|
|
6
|
+
constructor(userStoryPath, projectRoot = process.cwd()) {
|
|
7
|
+
this.userStoryPath = userStoryPath;
|
|
8
|
+
this.projectRoot = projectRoot;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Build complete progress comment
|
|
12
|
+
*/
|
|
13
|
+
async buildProgressComment(incrementId) {
|
|
14
|
+
const summary = await this.calculateProgressSummary();
|
|
15
|
+
const frontmatter = await this.extractFrontmatter();
|
|
16
|
+
let comment = "";
|
|
17
|
+
comment += `\u{1F4CA} **Progress Update from Increment ${incrementId}**
|
|
18
|
+
|
|
19
|
+
`;
|
|
20
|
+
comment += `**Status**: ${summary.statusSummary} (${summary.completedACs}/${summary.totalACs} AC implemented - ${summary.percentage}%)
|
|
21
|
+
|
|
22
|
+
`;
|
|
23
|
+
if (summary.completedCriteria.length > 0) {
|
|
24
|
+
comment += `## \u2705 Completed Acceptance Criteria
|
|
25
|
+
|
|
26
|
+
`;
|
|
27
|
+
for (const ac of summary.completedCriteria) {
|
|
28
|
+
const priority = ac.priority ? ` (${ac.priority})` : "";
|
|
29
|
+
const testable = ac.testable ? " [testable]" : "";
|
|
30
|
+
comment += `- [x] **${ac.id}**: ${ac.description}${priority}${testable}
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
comment += "\n";
|
|
34
|
+
}
|
|
35
|
+
if (summary.remainingCriteria.length > 0) {
|
|
36
|
+
const p1 = summary.remainingCriteria.filter((ac) => ac.priority === "P1");
|
|
37
|
+
const p2 = summary.remainingCriteria.filter((ac) => ac.priority === "P2");
|
|
38
|
+
const p3 = summary.remainingCriteria.filter((ac) => ac.priority === "P3");
|
|
39
|
+
if (p1.length > 0) {
|
|
40
|
+
comment += `## \u{1F534} Remaining Work (P1 - Critical)
|
|
41
|
+
|
|
42
|
+
`;
|
|
43
|
+
for (const ac of p1) {
|
|
44
|
+
const testable = ac.testable ? " [testable]" : "";
|
|
45
|
+
comment += `- [ ] **${ac.id}**: ${ac.description} (P1)${testable}
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
comment += "\n";
|
|
49
|
+
}
|
|
50
|
+
if (p2.length > 0 || p3.length > 0) {
|
|
51
|
+
comment += `## \u23F3 Remaining Work (P2-P3)
|
|
52
|
+
|
|
53
|
+
`;
|
|
54
|
+
for (const ac of [...p2, ...p3]) {
|
|
55
|
+
const priority = ac.priority ? ` (${ac.priority})` : "";
|
|
56
|
+
const testable = ac.testable ? " [testable]" : "";
|
|
57
|
+
comment += `- [ ] **${ac.id}**: ${ac.description}${priority}${testable}
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
comment += "\n";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (summary.tasks.length > 0) {
|
|
64
|
+
const completedTasks = summary.tasks.filter((t) => t.status).length;
|
|
65
|
+
const totalTasks = summary.tasks.length;
|
|
66
|
+
comment += `## \u{1F4CB} Implementation Tasks (${completedTasks}/${totalTasks})
|
|
67
|
+
|
|
68
|
+
`;
|
|
69
|
+
for (const task of summary.tasks) {
|
|
70
|
+
const checkbox = task.status ? "[x]" : "[ ]";
|
|
71
|
+
comment += `- ${checkbox} ${task.id}: ${task.title}
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
comment += "\n";
|
|
75
|
+
}
|
|
76
|
+
comment += `---
|
|
77
|
+
|
|
78
|
+
`;
|
|
79
|
+
comment += `\u{1F916} Auto-synced by SpecWeave | `;
|
|
80
|
+
comment += `[View increment](../../increments/${incrementId}) | `;
|
|
81
|
+
comment += `${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}
|
|
82
|
+
`;
|
|
83
|
+
return comment;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Calculate progress summary
|
|
87
|
+
*/
|
|
88
|
+
async calculateProgressSummary() {
|
|
89
|
+
const content = await readFile(this.userStoryPath, "utf-8");
|
|
90
|
+
const acceptanceCriteria = this.extractAcceptanceCriteria(content);
|
|
91
|
+
const tasks = await this.extractTasks(content);
|
|
92
|
+
const completedCriteria = acceptanceCriteria.filter((ac) => ac.completed);
|
|
93
|
+
const remainingCriteria = acceptanceCriteria.filter((ac) => !ac.completed);
|
|
94
|
+
const totalACs = acceptanceCriteria.length;
|
|
95
|
+
const completedACs = completedCriteria.length;
|
|
96
|
+
const percentage = totalACs > 0 ? Math.round(completedACs / totalACs * 100) : 0;
|
|
97
|
+
let statusSummary = "In Progress";
|
|
98
|
+
if (completedACs === totalACs && totalACs > 0) {
|
|
99
|
+
statusSummary = "Complete";
|
|
100
|
+
} else if (completedACs > 0) {
|
|
101
|
+
const p1Criteria = acceptanceCriteria.filter((ac) => ac.priority === "P1");
|
|
102
|
+
const p1Completed = p1Criteria.filter((ac) => ac.completed).length;
|
|
103
|
+
if (p1Completed === p1Criteria.length && p1Criteria.length > 0) {
|
|
104
|
+
statusSummary = "Core Complete";
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
totalACs,
|
|
109
|
+
completedACs,
|
|
110
|
+
percentage,
|
|
111
|
+
statusSummary,
|
|
112
|
+
completedCriteria,
|
|
113
|
+
remainingCriteria,
|
|
114
|
+
tasks
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Format AC checkboxes (for inline display)
|
|
119
|
+
*/
|
|
120
|
+
formatACCheckboxes() {
|
|
121
|
+
return "";
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Format task checkboxes (for inline display)
|
|
125
|
+
*/
|
|
126
|
+
formatTaskCheckboxes() {
|
|
127
|
+
return "";
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Calculate progress percentage
|
|
131
|
+
*/
|
|
132
|
+
async calculateProgressPercentage() {
|
|
133
|
+
const summary = await this.calculateProgressSummary();
|
|
134
|
+
return summary.percentage;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Extract frontmatter from user story file
|
|
138
|
+
*/
|
|
139
|
+
async extractFrontmatter() {
|
|
140
|
+
const content = await readFile(this.userStoryPath, "utf-8");
|
|
141
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
142
|
+
if (!match) {
|
|
143
|
+
throw new Error(`User story file missing YAML frontmatter: ${this.userStoryPath}`);
|
|
144
|
+
}
|
|
145
|
+
return yaml.parse(match[1]);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Extract acceptance criteria from content
|
|
149
|
+
*/
|
|
150
|
+
extractAcceptanceCriteria(content) {
|
|
151
|
+
const criteria = [];
|
|
152
|
+
const acPattern = /- \[([ x])\] \*\*AC-US(\d+)-(\d+)\*\*:\s*([^(]+)(?:\(([^)]+)\))?/g;
|
|
153
|
+
let match;
|
|
154
|
+
while ((match = acPattern.exec(content)) !== null) {
|
|
155
|
+
const completed = match[1] === "x";
|
|
156
|
+
const usNumber = match[2];
|
|
157
|
+
const acNumber = match[3];
|
|
158
|
+
const description = match[4].trim();
|
|
159
|
+
const metadata = match[5] || "";
|
|
160
|
+
criteria.push({
|
|
161
|
+
id: `AC-US${usNumber}-${acNumber}`,
|
|
162
|
+
description,
|
|
163
|
+
completed,
|
|
164
|
+
priority: metadata.includes("P1") ? "P1" : metadata.includes("P2") ? "P2" : metadata.includes("P3") ? "P3" : "",
|
|
165
|
+
testable: metadata.includes("testable")
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
return criteria;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Extract tasks from Implementation section
|
|
172
|
+
*/
|
|
173
|
+
async extractTasks(content) {
|
|
174
|
+
const tasks = [];
|
|
175
|
+
const incrementMatch = content.match(/\*\*Increment\*\*:\s*\[([^\]]+)\]/);
|
|
176
|
+
if (!incrementMatch) {
|
|
177
|
+
return tasks;
|
|
178
|
+
}
|
|
179
|
+
const incrementId = incrementMatch[1];
|
|
180
|
+
const tasksPath = path.join(
|
|
181
|
+
this.projectRoot,
|
|
182
|
+
".specweave",
|
|
183
|
+
"increments",
|
|
184
|
+
incrementId,
|
|
185
|
+
"tasks.md"
|
|
186
|
+
);
|
|
187
|
+
if (!existsSync(tasksPath)) {
|
|
188
|
+
return tasks;
|
|
189
|
+
}
|
|
190
|
+
const tasksContent = await readFile(tasksPath, "utf-8");
|
|
191
|
+
const taskLinkPattern = /- \[([T-\d]+):\s*([^\]]+)\]/g;
|
|
192
|
+
let match;
|
|
193
|
+
while ((match = taskLinkPattern.exec(content)) !== null) {
|
|
194
|
+
const taskId = match[1];
|
|
195
|
+
const taskTitle = match[2].trim();
|
|
196
|
+
const taskPattern = new RegExp(`### ${taskId}[:\\s].*?\\n\\*\\*Status\\*\\*:\\s*\\[([x ]?)\\]`, "s");
|
|
197
|
+
const taskMatch = tasksContent.match(taskPattern);
|
|
198
|
+
const completed = taskMatch ? taskMatch[1] === "x" : false;
|
|
199
|
+
tasks.push({
|
|
200
|
+
id: taskId,
|
|
201
|
+
title: taskTitle,
|
|
202
|
+
status: completed
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return tasks;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async function main() {
|
|
209
|
+
const args = process.argv.slice(2);
|
|
210
|
+
if (args.length < 4) {
|
|
211
|
+
console.error("Usage: node progress-comment-builder.js --user-story <path> --increment <id>");
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
const userStoryPath = args[args.indexOf("--user-story") + 1];
|
|
215
|
+
const incrementId = args[args.indexOf("--increment") + 1];
|
|
216
|
+
const builder = new ProgressCommentBuilder(userStoryPath);
|
|
217
|
+
const comment = await builder.buildProgressComment(incrementId);
|
|
218
|
+
console.log(comment);
|
|
219
|
+
}
|
|
220
|
+
if (require.main === module) {
|
|
221
|
+
main().catch((error) => {
|
|
222
|
+
console.error("Error generating progress comment:", error.message);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
export {
|
|
227
|
+
ProgressCommentBuilder,
|
|
228
|
+
main
|
|
229
|
+
};
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress Comment Builder - Generate progress update comments for GitHub issues
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* - Reads user story files from living docs
|
|
6
|
+
* - Extracts current AC completion status
|
|
7
|
+
* - Formats progress comment with checkboxes
|
|
8
|
+
* - Creates audit trail of changes over time
|
|
9
|
+
*
|
|
10
|
+
* Key Principle: IMMUTABLE DESCRIPTIONS
|
|
11
|
+
* - Issue description created once (snapshot)
|
|
12
|
+
* - All updates via progress comments (current state)
|
|
13
|
+
* - Complete audit trail preserved
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { readFile } from 'fs/promises';
|
|
17
|
+
import { existsSync } from 'fs';
|
|
18
|
+
import * as path from 'path';
|
|
19
|
+
import * as yaml from 'yaml';
|
|
20
|
+
|
|
21
|
+
interface UserStoryFrontmatter {
|
|
22
|
+
id: string;
|
|
23
|
+
epic: string;
|
|
24
|
+
title: string;
|
|
25
|
+
status: 'complete' | 'active' | 'planning' | 'not-started';
|
|
26
|
+
created: string;
|
|
27
|
+
completed?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface AcceptanceCriterion {
|
|
31
|
+
id: string; // AC-US4-01
|
|
32
|
+
description: string;
|
|
33
|
+
completed: boolean;
|
|
34
|
+
priority: string; // P1, P2, P3
|
|
35
|
+
testable: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface Task {
|
|
39
|
+
id: string; // T-008
|
|
40
|
+
title: string;
|
|
41
|
+
status: boolean; // true = completed
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ProgressSummary {
|
|
45
|
+
totalACs: number;
|
|
46
|
+
completedACs: number;
|
|
47
|
+
percentage: number;
|
|
48
|
+
statusSummary: string; // "Core Complete", "Complete", "In Progress"
|
|
49
|
+
completedCriteria: AcceptanceCriterion[];
|
|
50
|
+
remainingCriteria: AcceptanceCriterion[];
|
|
51
|
+
tasks: Task[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export class ProgressCommentBuilder {
|
|
55
|
+
private userStoryPath: string;
|
|
56
|
+
private projectRoot: string;
|
|
57
|
+
|
|
58
|
+
constructor(userStoryPath: string, projectRoot: string = process.cwd()) {
|
|
59
|
+
this.userStoryPath = userStoryPath;
|
|
60
|
+
this.projectRoot = projectRoot;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Build complete progress comment
|
|
65
|
+
*/
|
|
66
|
+
async buildProgressComment(incrementId: string): Promise<string> {
|
|
67
|
+
const summary = await this.calculateProgressSummary();
|
|
68
|
+
const frontmatter = await this.extractFrontmatter();
|
|
69
|
+
|
|
70
|
+
let comment = '';
|
|
71
|
+
|
|
72
|
+
// Header
|
|
73
|
+
comment += `📊 **Progress Update from Increment ${incrementId}**\n\n`;
|
|
74
|
+
comment += `**Status**: ${summary.statusSummary} (${summary.completedACs}/${summary.totalACs} AC implemented - ${summary.percentage}%)\n\n`;
|
|
75
|
+
|
|
76
|
+
// Completed Acceptance Criteria
|
|
77
|
+
if (summary.completedCriteria.length > 0) {
|
|
78
|
+
comment += `## ✅ Completed Acceptance Criteria\n\n`;
|
|
79
|
+
for (const ac of summary.completedCriteria) {
|
|
80
|
+
const priority = ac.priority ? ` (${ac.priority})` : '';
|
|
81
|
+
const testable = ac.testable ? ' [testable]' : '';
|
|
82
|
+
comment += `- [x] **${ac.id}**: ${ac.description}${priority}${testable}\n`;
|
|
83
|
+
}
|
|
84
|
+
comment += '\n';
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Remaining Work
|
|
88
|
+
if (summary.remainingCriteria.length > 0) {
|
|
89
|
+
// Group by priority
|
|
90
|
+
const p1 = summary.remainingCriteria.filter(ac => ac.priority === 'P1');
|
|
91
|
+
const p2 = summary.remainingCriteria.filter(ac => ac.priority === 'P2');
|
|
92
|
+
const p3 = summary.remainingCriteria.filter(ac => ac.priority === 'P3');
|
|
93
|
+
|
|
94
|
+
if (p1.length > 0) {
|
|
95
|
+
comment += `## 🔴 Remaining Work (P1 - Critical)\n\n`;
|
|
96
|
+
for (const ac of p1) {
|
|
97
|
+
const testable = ac.testable ? ' [testable]' : '';
|
|
98
|
+
comment += `- [ ] **${ac.id}**: ${ac.description} (P1)${testable}\n`;
|
|
99
|
+
}
|
|
100
|
+
comment += '\n';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (p2.length > 0 || p3.length > 0) {
|
|
104
|
+
comment += `## ⏳ Remaining Work (P2-P3)\n\n`;
|
|
105
|
+
for (const ac of [...p2, ...p3]) {
|
|
106
|
+
const priority = ac.priority ? ` (${ac.priority})` : '';
|
|
107
|
+
const testable = ac.testable ? ' [testable]' : '';
|
|
108
|
+
comment += `- [ ] **${ac.id}**: ${ac.description}${priority}${testable}\n`;
|
|
109
|
+
}
|
|
110
|
+
comment += '\n';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Tasks (if any)
|
|
115
|
+
if (summary.tasks.length > 0) {
|
|
116
|
+
const completedTasks = summary.tasks.filter(t => t.status).length;
|
|
117
|
+
const totalTasks = summary.tasks.length;
|
|
118
|
+
comment += `## 📋 Implementation Tasks (${completedTasks}/${totalTasks})\n\n`;
|
|
119
|
+
|
|
120
|
+
for (const task of summary.tasks) {
|
|
121
|
+
const checkbox = task.status ? '[x]' : '[ ]';
|
|
122
|
+
comment += `- ${checkbox} ${task.id}: ${task.title}\n`;
|
|
123
|
+
}
|
|
124
|
+
comment += '\n';
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Footer
|
|
128
|
+
comment += `---\n\n`;
|
|
129
|
+
comment += `🤖 Auto-synced by SpecWeave | `;
|
|
130
|
+
comment += `[View increment](../../increments/${incrementId}) | `;
|
|
131
|
+
comment += `${new Date().toISOString().split('T')[0]}\n`;
|
|
132
|
+
|
|
133
|
+
return comment;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Calculate progress summary
|
|
138
|
+
*/
|
|
139
|
+
async calculateProgressSummary(): Promise<ProgressSummary> {
|
|
140
|
+
const content = await readFile(this.userStoryPath, 'utf-8');
|
|
141
|
+
const acceptanceCriteria = this.extractAcceptanceCriteria(content);
|
|
142
|
+
const tasks = await this.extractTasks(content);
|
|
143
|
+
|
|
144
|
+
const completedCriteria = acceptanceCriteria.filter(ac => ac.completed);
|
|
145
|
+
const remainingCriteria = acceptanceCriteria.filter(ac => !ac.completed);
|
|
146
|
+
|
|
147
|
+
const totalACs = acceptanceCriteria.length;
|
|
148
|
+
const completedACs = completedCriteria.length;
|
|
149
|
+
const percentage = totalACs > 0 ? Math.round((completedACs / totalACs) * 100) : 0;
|
|
150
|
+
|
|
151
|
+
// Determine status summary
|
|
152
|
+
let statusSummary = 'In Progress';
|
|
153
|
+
if (completedACs === totalACs && totalACs > 0) {
|
|
154
|
+
statusSummary = 'Complete';
|
|
155
|
+
} else if (completedACs > 0) {
|
|
156
|
+
// Check if all P1 are done
|
|
157
|
+
const p1Criteria = acceptanceCriteria.filter(ac => ac.priority === 'P1');
|
|
158
|
+
const p1Completed = p1Criteria.filter(ac => ac.completed).length;
|
|
159
|
+
if (p1Completed === p1Criteria.length && p1Criteria.length > 0) {
|
|
160
|
+
statusSummary = 'Core Complete';
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
totalACs,
|
|
166
|
+
completedACs,
|
|
167
|
+
percentage,
|
|
168
|
+
statusSummary,
|
|
169
|
+
completedCriteria,
|
|
170
|
+
remainingCriteria,
|
|
171
|
+
tasks,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Format AC checkboxes (for inline display)
|
|
177
|
+
*/
|
|
178
|
+
formatACCheckboxes(): string {
|
|
179
|
+
// This method is for simple inline formatting
|
|
180
|
+
// The full buildProgressComment does structured formatting
|
|
181
|
+
return ''; // Placeholder for CLI usage if needed
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Format task checkboxes (for inline display)
|
|
186
|
+
*/
|
|
187
|
+
formatTaskCheckboxes(): string {
|
|
188
|
+
// This method is for simple inline formatting
|
|
189
|
+
// The full buildProgressComment does structured formatting
|
|
190
|
+
return ''; // Placeholder for CLI usage if needed
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Calculate progress percentage
|
|
195
|
+
*/
|
|
196
|
+
async calculateProgressPercentage(): Promise<number> {
|
|
197
|
+
const summary = await this.calculateProgressSummary();
|
|
198
|
+
return summary.percentage;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Extract frontmatter from user story file
|
|
203
|
+
*/
|
|
204
|
+
private async extractFrontmatter(): Promise<UserStoryFrontmatter> {
|
|
205
|
+
const content = await readFile(this.userStoryPath, 'utf-8');
|
|
206
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
207
|
+
|
|
208
|
+
if (!match) {
|
|
209
|
+
throw new Error(`User story file missing YAML frontmatter: ${this.userStoryPath}`);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return yaml.parse(match[1]) as UserStoryFrontmatter;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Extract acceptance criteria from content
|
|
217
|
+
*/
|
|
218
|
+
private extractAcceptanceCriteria(content: string): AcceptanceCriterion[] {
|
|
219
|
+
const criteria: AcceptanceCriterion[] = [];
|
|
220
|
+
|
|
221
|
+
// Pattern: - [x] **AC-US4-01**: Description (P1, testable)
|
|
222
|
+
const acPattern =
|
|
223
|
+
/- \[([ x])\] \*\*AC-US(\d+)-(\d+)\*\*:\s*([^(]+)(?:\(([^)]+)\))?/g;
|
|
224
|
+
|
|
225
|
+
let match;
|
|
226
|
+
while ((match = acPattern.exec(content)) !== null) {
|
|
227
|
+
const completed = match[1] === 'x';
|
|
228
|
+
const usNumber = match[2];
|
|
229
|
+
const acNumber = match[3];
|
|
230
|
+
const description = match[4].trim();
|
|
231
|
+
const metadata = match[5] || '';
|
|
232
|
+
|
|
233
|
+
criteria.push({
|
|
234
|
+
id: `AC-US${usNumber}-${acNumber}`,
|
|
235
|
+
description,
|
|
236
|
+
completed,
|
|
237
|
+
priority: metadata.includes('P1') ? 'P1' : metadata.includes('P2') ? 'P2' : metadata.includes('P3') ? 'P3' : '',
|
|
238
|
+
testable: metadata.includes('testable'),
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return criteria;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Extract tasks from Implementation section
|
|
247
|
+
*/
|
|
248
|
+
private async extractTasks(content: string): Promise<Task[]> {
|
|
249
|
+
const tasks: Task[] = [];
|
|
250
|
+
|
|
251
|
+
// Extract increment ID from Implementation section
|
|
252
|
+
const incrementMatch = content.match(/\*\*Increment\*\*:\s*\[([^\]]+)\]/);
|
|
253
|
+
if (!incrementMatch) {
|
|
254
|
+
return tasks; // No increment linked
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const incrementId = incrementMatch[1];
|
|
258
|
+
|
|
259
|
+
// Find tasks.md file
|
|
260
|
+
const tasksPath = path.join(
|
|
261
|
+
this.projectRoot,
|
|
262
|
+
'.specweave',
|
|
263
|
+
'increments',
|
|
264
|
+
incrementId,
|
|
265
|
+
'tasks.md'
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
if (!existsSync(tasksPath)) {
|
|
269
|
+
return tasks; // Tasks file not found
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const tasksContent = await readFile(tasksPath, 'utf-8');
|
|
273
|
+
|
|
274
|
+
// Extract task links from user story (e.g., - [T-001: Title](link))
|
|
275
|
+
const taskLinkPattern = /- \[([T-\d]+):\s*([^\]]+)\]/g;
|
|
276
|
+
let match;
|
|
277
|
+
|
|
278
|
+
while ((match = taskLinkPattern.exec(content)) !== null) {
|
|
279
|
+
const taskId = match[1];
|
|
280
|
+
const taskTitle = match[2].trim();
|
|
281
|
+
|
|
282
|
+
// Check if task is completed in tasks.md
|
|
283
|
+
const taskPattern = new RegExp(`### ${taskId}[:\\s].*?\\n\\*\\*Status\\*\\*:\\s*\\[([x ]?)\\]`, 's');
|
|
284
|
+
const taskMatch = tasksContent.match(taskPattern);
|
|
285
|
+
const completed = taskMatch ? taskMatch[1] === 'x' : false;
|
|
286
|
+
|
|
287
|
+
tasks.push({
|
|
288
|
+
id: taskId,
|
|
289
|
+
title: taskTitle,
|
|
290
|
+
status: completed,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return tasks;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* CLI entry point for generating progress comments
|
|
300
|
+
*/
|
|
301
|
+
export async function main() {
|
|
302
|
+
const args = process.argv.slice(2);
|
|
303
|
+
|
|
304
|
+
if (args.length < 4) {
|
|
305
|
+
console.error('Usage: node progress-comment-builder.js --user-story <path> --increment <id>');
|
|
306
|
+
process.exit(1);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const userStoryPath = args[args.indexOf('--user-story') + 1];
|
|
310
|
+
const incrementId = args[args.indexOf('--increment') + 1];
|
|
311
|
+
|
|
312
|
+
const builder = new ProgressCommentBuilder(userStoryPath);
|
|
313
|
+
const comment = await builder.buildProgressComment(incrementId);
|
|
314
|
+
|
|
315
|
+
console.log(comment);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Run if called directly
|
|
319
|
+
if (require.main === module) {
|
|
320
|
+
main().catch((error) => {
|
|
321
|
+
console.error('Error generating progress comment:', error.message);
|
|
322
|
+
process.exit(1);
|
|
323
|
+
});
|
|
324
|
+
}
|