specweave 0.18.1 → 0.20.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.
Files changed (389) hide show
  1. package/CLAUDE.md +229 -1817
  2. package/README.md +68 -0
  3. package/bin/specweave.js +62 -6
  4. package/dist/plugins/specweave/lib/hooks/sync-living-docs.d.ts.map +1 -1
  5. package/dist/plugins/specweave/lib/hooks/sync-living-docs.js +3 -0
  6. package/dist/plugins/specweave/lib/hooks/sync-living-docs.js.map +1 -1
  7. package/dist/plugins/specweave/lib/hooks/update-ac-status.d.ts +21 -0
  8. package/dist/plugins/specweave/lib/hooks/update-ac-status.d.ts.map +1 -0
  9. package/dist/plugins/specweave/lib/hooks/update-ac-status.js +162 -0
  10. package/dist/plugins/specweave/lib/hooks/update-ac-status.js.map +1 -0
  11. package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.d.ts.map +1 -1
  12. package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js +65 -6
  13. package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js.map +1 -1
  14. package/dist/plugins/specweave-github/lib/completion-calculator.d.ts +112 -0
  15. package/dist/plugins/specweave-github/lib/completion-calculator.d.ts.map +1 -0
  16. package/dist/plugins/specweave-github/lib/completion-calculator.js +301 -0
  17. package/dist/plugins/specweave-github/lib/completion-calculator.js.map +1 -0
  18. package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts +3 -3
  19. package/dist/plugins/specweave-github/lib/duplicate-detector.js +3 -3
  20. package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts +7 -0
  21. package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts.map +1 -1
  22. package/dist/plugins/specweave-github/lib/epic-content-builder.js +42 -0
  23. package/dist/plugins/specweave-github/lib/epic-content-builder.js.map +1 -1
  24. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +14 -0
  25. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
  26. package/dist/plugins/specweave-github/lib/github-client-v2.js +51 -0
  27. package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
  28. package/dist/plugins/specweave-github/lib/github-epic-sync.js +1 -1
  29. package/dist/plugins/specweave-github/lib/github-epic-sync.js.map +1 -1
  30. package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts +87 -0
  31. package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -0
  32. package/dist/plugins/specweave-github/lib/github-feature-sync.js +412 -0
  33. package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -0
  34. package/dist/plugins/specweave-github/lib/github-spec-content-sync.d.ts.map +1 -1
  35. package/dist/plugins/specweave-github/lib/github-spec-content-sync.js +64 -13
  36. package/dist/plugins/specweave-github/lib/github-spec-content-sync.js.map +1 -1
  37. package/dist/plugins/specweave-github/lib/progress-comment-builder.d.ts +78 -0
  38. package/dist/plugins/specweave-github/lib/progress-comment-builder.d.ts.map +1 -0
  39. package/dist/plugins/specweave-github/lib/progress-comment-builder.js +237 -0
  40. package/dist/plugins/specweave-github/lib/progress-comment-builder.js.map +1 -0
  41. package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts +97 -0
  42. package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts.map +1 -0
  43. package/dist/plugins/specweave-github/lib/user-story-content-builder.js +301 -0
  44. package/dist/plugins/specweave-github/lib/user-story-content-builder.js.map +1 -0
  45. package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts +83 -0
  46. package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts.map +1 -0
  47. package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +386 -0
  48. package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -0
  49. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts +8 -6
  50. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts.map +1 -1
  51. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js +78 -117
  52. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js.map +1 -1
  53. package/dist/src/cli/commands/import-docs.js +4 -4
  54. package/dist/src/cli/commands/import-docs.js.map +1 -1
  55. package/dist/src/cli/commands/init-multiproject.d.ts.map +1 -1
  56. package/dist/src/cli/commands/init-multiproject.js +17 -18
  57. package/dist/src/cli/commands/init-multiproject.js.map +1 -1
  58. package/dist/src/cli/commands/migrate-to-multiproject.d.ts.map +1 -1
  59. package/dist/src/cli/commands/migrate-to-multiproject.js +8 -4
  60. package/dist/src/cli/commands/migrate-to-multiproject.js.map +1 -1
  61. package/dist/src/cli/commands/switch-project.d.ts.map +1 -1
  62. package/dist/src/cli/commands/switch-project.js +9 -26
  63. package/dist/src/cli/commands/switch-project.js.map +1 -1
  64. package/dist/src/cli/commands/sync-spec-content.js +3 -0
  65. package/dist/src/cli/commands/sync-spec-content.js.map +1 -1
  66. package/dist/src/core/deduplication/command-deduplicator.d.ts +166 -0
  67. package/dist/src/core/deduplication/command-deduplicator.d.ts.map +1 -0
  68. package/dist/src/core/deduplication/command-deduplicator.js +254 -0
  69. package/dist/src/core/deduplication/command-deduplicator.js.map +1 -0
  70. package/dist/src/core/increment/active-increment-manager.d.ts +42 -15
  71. package/dist/src/core/increment/active-increment-manager.d.ts.map +1 -1
  72. package/dist/src/core/increment/active-increment-manager.js +113 -46
  73. package/dist/src/core/increment/active-increment-manager.js.map +1 -1
  74. package/dist/src/core/increment/conflict-resolver.d.ts +40 -0
  75. package/dist/src/core/increment/conflict-resolver.d.ts.map +1 -0
  76. package/dist/src/core/increment/conflict-resolver.js +219 -0
  77. package/dist/src/core/increment/conflict-resolver.js.map +1 -0
  78. package/dist/src/core/increment/discipline-checker.d.ts.map +1 -1
  79. package/dist/src/core/increment/discipline-checker.js +7 -1
  80. package/dist/src/core/increment/discipline-checker.js.map +1 -1
  81. package/dist/src/core/increment/duplicate-detector.d.ts +52 -0
  82. package/dist/src/core/increment/duplicate-detector.d.ts.map +1 -0
  83. package/dist/src/core/increment/duplicate-detector.js +276 -0
  84. package/dist/src/core/increment/duplicate-detector.js.map +1 -0
  85. package/dist/src/core/increment/increment-archiver.d.ts +90 -0
  86. package/dist/src/core/increment/increment-archiver.d.ts.map +1 -0
  87. package/dist/src/core/increment/increment-archiver.js +368 -0
  88. package/dist/src/core/increment/increment-archiver.js.map +1 -0
  89. package/dist/src/core/increment/increment-reopener.d.ts +165 -0
  90. package/dist/src/core/increment/increment-reopener.d.ts.map +1 -0
  91. package/dist/src/core/increment/increment-reopener.js +390 -0
  92. package/dist/src/core/increment/increment-reopener.js.map +1 -0
  93. package/dist/src/core/increment/metadata-manager.d.ts +26 -1
  94. package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
  95. package/dist/src/core/increment/metadata-manager.js +143 -5
  96. package/dist/src/core/increment/metadata-manager.js.map +1 -1
  97. package/dist/src/core/increment/recent-work-scanner.d.ts +121 -0
  98. package/dist/src/core/increment/recent-work-scanner.d.ts.map +1 -0
  99. package/dist/src/core/increment/recent-work-scanner.js +303 -0
  100. package/dist/src/core/increment/recent-work-scanner.js.map +1 -0
  101. package/dist/src/core/increment/types.d.ts +1 -0
  102. package/dist/src/core/increment/types.d.ts.map +1 -1
  103. package/dist/src/core/increment-utils.d.ts +112 -0
  104. package/dist/src/core/increment-utils.d.ts.map +1 -0
  105. package/dist/src/core/increment-utils.js +210 -0
  106. package/dist/src/core/increment-utils.js.map +1 -0
  107. package/dist/src/core/living-docs/ac-project-specific-generator.d.ts +65 -0
  108. package/dist/src/core/living-docs/ac-project-specific-generator.d.ts.map +1 -0
  109. package/dist/src/core/living-docs/ac-project-specific-generator.js +175 -0
  110. package/dist/src/core/living-docs/ac-project-specific-generator.js.map +1 -0
  111. package/dist/src/core/living-docs/feature-archiver.d.ts +130 -0
  112. package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -0
  113. package/dist/src/core/living-docs/feature-archiver.js +549 -0
  114. package/dist/src/core/living-docs/feature-archiver.js.map +1 -0
  115. package/dist/src/core/living-docs/feature-id-manager.d.ts +81 -0
  116. package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -0
  117. package/dist/src/core/living-docs/feature-id-manager.js +339 -0
  118. package/dist/src/core/living-docs/feature-id-manager.js.map +1 -0
  119. package/dist/src/core/living-docs/hierarchy-mapper.d.ts +144 -83
  120. package/dist/src/core/living-docs/hierarchy-mapper.d.ts.map +1 -1
  121. package/dist/src/core/living-docs/hierarchy-mapper.js +488 -270
  122. package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
  123. package/dist/src/core/living-docs/index.d.ts +6 -0
  124. package/dist/src/core/living-docs/index.d.ts.map +1 -1
  125. package/dist/src/core/living-docs/index.js +6 -0
  126. package/dist/src/core/living-docs/index.js.map +1 -1
  127. package/dist/src/core/living-docs/project-detector.d.ts +6 -0
  128. package/dist/src/core/living-docs/project-detector.d.ts.map +1 -1
  129. package/dist/src/core/living-docs/project-detector.js +35 -1
  130. package/dist/src/core/living-docs/project-detector.js.map +1 -1
  131. package/dist/src/core/living-docs/spec-distributor.d.ts +100 -26
  132. package/dist/src/core/living-docs/spec-distributor.d.ts.map +1 -1
  133. package/dist/src/core/living-docs/spec-distributor.js +1275 -258
  134. package/dist/src/core/living-docs/spec-distributor.js.map +1 -1
  135. package/dist/src/core/living-docs/task-project-specific-generator.d.ts +109 -0
  136. package/dist/src/core/living-docs/task-project-specific-generator.d.ts.map +1 -0
  137. package/dist/src/core/living-docs/task-project-specific-generator.js +221 -0
  138. package/dist/src/core/living-docs/task-project-specific-generator.js.map +1 -0
  139. package/dist/src/core/living-docs/types.d.ts +143 -0
  140. package/dist/src/core/living-docs/types.d.ts.map +1 -1
  141. package/dist/src/core/project-manager.d.ts +2 -17
  142. package/dist/src/core/project-manager.d.ts.map +1 -1
  143. package/dist/src/core/project-manager.js +68 -48
  144. package/dist/src/core/project-manager.js.map +1 -1
  145. package/dist/src/core/spec-content-sync.d.ts +1 -1
  146. package/dist/src/core/spec-content-sync.d.ts.map +1 -1
  147. package/dist/src/core/sync/enhanced-content-builder.d.ts.map +1 -1
  148. package/dist/src/core/sync/enhanced-content-builder.js +2 -1
  149. package/dist/src/core/sync/enhanced-content-builder.js.map +1 -1
  150. package/dist/src/core/sync/performance-optimizer.d.ts +153 -0
  151. package/dist/src/core/sync/performance-optimizer.d.ts.map +1 -0
  152. package/dist/src/core/sync/performance-optimizer.js +220 -0
  153. package/dist/src/core/sync/performance-optimizer.js.map +1 -0
  154. package/dist/src/core/sync/retry-handler.d.ts +98 -0
  155. package/dist/src/core/sync/retry-handler.d.ts.map +1 -0
  156. package/dist/src/core/sync/retry-handler.js +196 -0
  157. package/dist/src/core/sync/retry-handler.js.map +1 -0
  158. package/dist/src/core/types/config.d.ts +94 -0
  159. package/dist/src/core/types/config.d.ts.map +1 -1
  160. package/dist/src/core/types/config.js +16 -0
  161. package/dist/src/core/types/config.js.map +1 -1
  162. package/dist/src/core/types/increment-metadata.d.ts +6 -0
  163. package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
  164. package/dist/src/core/types/increment-metadata.js +10 -1
  165. package/dist/src/core/types/increment-metadata.js.map +1 -1
  166. package/dist/src/integrations/jira/jira-incremental-mapper.d.ts.map +1 -1
  167. package/dist/src/integrations/jira/jira-incremental-mapper.js +4 -8
  168. package/dist/src/integrations/jira/jira-incremental-mapper.js.map +1 -1
  169. package/dist/src/integrations/jira/jira-mapper.d.ts.map +1 -1
  170. package/dist/src/integrations/jira/jira-mapper.js +4 -8
  171. package/dist/src/integrations/jira/jira-mapper.js.map +1 -1
  172. package/package.json +1 -1
  173. package/plugins/specweave/COMMANDS.md +13 -4
  174. package/plugins/specweave/commands/specweave-abandon.md +22 -20
  175. package/plugins/specweave/commands/specweave-archive-features.md +121 -0
  176. package/plugins/specweave/commands/specweave-archive-increments.md +82 -0
  177. package/plugins/specweave/commands/specweave-archive.md +363 -0
  178. package/plugins/specweave/commands/specweave-backlog.md +211 -0
  179. package/plugins/specweave/commands/specweave-fix-duplicates.md +517 -0
  180. package/plugins/specweave/commands/specweave-increment.md +4 -3
  181. package/plugins/specweave/commands/specweave-progress.md +176 -27
  182. package/plugins/specweave/commands/specweave-reopen.md +391 -0
  183. package/plugins/specweave/commands/specweave-restore-feature.md +90 -0
  184. package/plugins/specweave/commands/specweave-restore.md +309 -0
  185. package/plugins/specweave/commands/specweave-resume.md +51 -23
  186. package/plugins/specweave/commands/specweave-status.md +41 -7
  187. package/plugins/specweave/commands/specweave-sync-specs.md +425 -0
  188. package/plugins/specweave/hooks/hooks.json +4 -0
  189. package/plugins/specweave/hooks/lib/sync-spec-content.sh +2 -2
  190. package/plugins/specweave/hooks/post-task-completion.sh +39 -0
  191. package/plugins/specweave/hooks/pre-command-deduplication.sh +83 -0
  192. package/plugins/specweave/hooks/user-prompt-submit.sh +1 -1
  193. package/plugins/specweave/lib/hooks/sync-living-docs.js +2 -0
  194. package/plugins/specweave/lib/hooks/sync-living-docs.ts +4 -0
  195. package/plugins/specweave/lib/hooks/update-ac-status.js +102 -0
  196. package/plugins/specweave/lib/hooks/update-ac-status.ts +192 -0
  197. package/plugins/specweave/skills/archive-increments/SKILL.md +198 -0
  198. package/plugins/specweave/skills/increment-planner/scripts/feature-utils.js +14 -0
  199. package/plugins/specweave/skills/smart-reopen-detector/SKILL.md +244 -0
  200. package/plugins/specweave-ado/lib/ado-spec-content-sync.js +49 -5
  201. package/plugins/specweave-ado/lib/ado-spec-content-sync.ts +72 -6
  202. package/plugins/specweave-confluent/.claude-plugin/plugin.json +23 -0
  203. package/plugins/specweave-confluent/README.md +375 -0
  204. package/plugins/specweave-confluent/agents/confluent-architect/AGENT.md +306 -0
  205. package/plugins/specweave-confluent/skills/confluent-kafka-connect/SKILL.md +453 -0
  206. package/plugins/specweave-confluent/skills/confluent-ksqldb/SKILL.md +470 -0
  207. package/plugins/specweave-confluent/skills/confluent-schema-registry/SKILL.md +316 -0
  208. package/plugins/specweave-github/agents/github-task-splitter/AGENT.md +2 -2
  209. package/plugins/specweave-github/agents/user-story-updater/AGENT.md +148 -0
  210. package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +1 -1
  211. package/plugins/specweave-github/commands/specweave-github-update-user-story.md +156 -0
  212. package/plugins/specweave-github/hooks/post-task-completion.sh +10 -9
  213. package/plugins/specweave-github/lib/completion-calculator.js +262 -0
  214. package/plugins/specweave-github/lib/completion-calculator.ts +434 -0
  215. package/plugins/specweave-github/lib/duplicate-detector.js +3 -3
  216. package/plugins/specweave-github/lib/duplicate-detector.ts +4 -4
  217. package/plugins/specweave-github/lib/epic-content-builder.js +38 -0
  218. package/plugins/specweave-github/lib/epic-content-builder.ts +59 -0
  219. package/plugins/specweave-github/lib/github-client-v2.js +49 -0
  220. package/plugins/specweave-github/lib/github-client-v2.ts +59 -0
  221. package/plugins/specweave-github/lib/github-epic-sync.ts +1 -1
  222. package/plugins/specweave-github/lib/github-feature-sync.js +381 -0
  223. package/plugins/specweave-github/lib/github-feature-sync.ts +568 -0
  224. package/plugins/specweave-github/lib/github-spec-content-sync.js +40 -10
  225. package/plugins/specweave-github/lib/github-spec-content-sync.ts +82 -14
  226. package/plugins/specweave-github/lib/progress-comment-builder.js +229 -0
  227. package/plugins/specweave-github/lib/progress-comment-builder.ts +324 -0
  228. package/plugins/specweave-github/lib/user-story-content-builder.js +299 -0
  229. package/plugins/specweave-github/lib/user-story-content-builder.ts +413 -0
  230. package/plugins/specweave-github/lib/user-story-issue-builder.js +344 -0
  231. package/plugins/specweave-github/lib/user-story-issue-builder.ts +543 -0
  232. package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +189 -0
  233. package/plugins/{specweave-ado/lib/enhanced-ado-sync.js → specweave-jira/lib/enhanced-jira-sync.js} +25 -61
  234. package/plugins/specweave-jira/lib/{enhanced-jira-sync.ts.disabled → enhanced-jira-sync.ts} +26 -52
  235. package/plugins/specweave-kafka/.claude-plugin/plugin.json +26 -0
  236. package/plugins/specweave-kafka/IMPLEMENTATION-COMPLETE.md +483 -0
  237. package/plugins/specweave-kafka/README.md +242 -0
  238. package/plugins/specweave-kafka/agents/kafka-architect/AGENT.md +235 -0
  239. package/plugins/specweave-kafka/agents/kafka-devops/AGENT.md +209 -0
  240. package/plugins/specweave-kafka/agents/kafka-observability/AGENT.md +266 -0
  241. package/plugins/specweave-kafka/commands/deploy.md +99 -0
  242. package/plugins/specweave-kafka/commands/dev-env.md +176 -0
  243. package/plugins/specweave-kafka/commands/mcp-configure.md +101 -0
  244. package/plugins/specweave-kafka/commands/monitor-setup.md +96 -0
  245. package/plugins/specweave-kafka/docker/kafka-local/docker-compose.yml +187 -0
  246. package/plugins/specweave-kafka/docker/redpanda/docker-compose.yml +199 -0
  247. package/plugins/specweave-kafka/docker/templates/consumer-nodejs.js +225 -0
  248. package/plugins/specweave-kafka/docker/templates/consumer-python.py +220 -0
  249. package/plugins/specweave-kafka/docker/templates/producer-nodejs.js +168 -0
  250. package/plugins/specweave-kafka/docker/templates/producer-python.py +167 -0
  251. package/plugins/specweave-kafka/lib/adapters/apache-kafka-adapter.js +438 -0
  252. package/plugins/specweave-kafka/lib/adapters/apache-kafka-adapter.ts +541 -0
  253. package/plugins/specweave-kafka/lib/adapters/platform-adapter.js +47 -0
  254. package/plugins/specweave-kafka/lib/adapters/platform-adapter.ts +343 -0
  255. package/plugins/specweave-kafka/lib/cli/kcat-wrapper.js +258 -0
  256. package/plugins/specweave-kafka/lib/cli/kcat-wrapper.ts +298 -0
  257. package/plugins/specweave-kafka/lib/cli/types.js +10 -0
  258. package/plugins/specweave-kafka/lib/cli/types.ts +92 -0
  259. package/plugins/specweave-kafka/lib/connectors/connector-catalog.js +305 -0
  260. package/plugins/specweave-kafka/lib/connectors/connector-catalog.ts +528 -0
  261. package/plugins/specweave-kafka/lib/documentation/diagram-generator.js +114 -0
  262. package/plugins/specweave-kafka/lib/documentation/diagram-generator.ts +195 -0
  263. package/plugins/specweave-kafka/lib/documentation/exporter.js +210 -0
  264. package/plugins/specweave-kafka/lib/documentation/exporter.ts +338 -0
  265. package/plugins/specweave-kafka/lib/documentation/schema-catalog-generator.js +60 -0
  266. package/plugins/specweave-kafka/lib/documentation/schema-catalog-generator.ts +130 -0
  267. package/plugins/specweave-kafka/lib/documentation/topology-generator.js +143 -0
  268. package/plugins/specweave-kafka/lib/documentation/topology-generator.ts +290 -0
  269. package/plugins/specweave-kafka/lib/mcp/detector.js +298 -0
  270. package/plugins/specweave-kafka/lib/mcp/detector.ts +352 -0
  271. package/plugins/specweave-kafka/lib/mcp/types.js +21 -0
  272. package/plugins/specweave-kafka/lib/mcp/types.ts +77 -0
  273. package/plugins/specweave-kafka/lib/multi-cluster/cluster-config-manager.js +193 -0
  274. package/plugins/specweave-kafka/lib/multi-cluster/cluster-config-manager.ts +362 -0
  275. package/plugins/specweave-kafka/lib/multi-cluster/cluster-switcher.js +188 -0
  276. package/plugins/specweave-kafka/lib/multi-cluster/cluster-switcher.ts +359 -0
  277. package/plugins/specweave-kafka/lib/multi-cluster/health-aggregator.js +195 -0
  278. package/plugins/specweave-kafka/lib/multi-cluster/health-aggregator.ts +380 -0
  279. package/plugins/specweave-kafka/lib/observability/opentelemetry-kafka.js +209 -0
  280. package/plugins/specweave-kafka/lib/observability/opentelemetry-kafka.ts +358 -0
  281. package/plugins/specweave-kafka/lib/patterns/advanced-ksqldb-patterns.js +354 -0
  282. package/plugins/specweave-kafka/lib/patterns/advanced-ksqldb-patterns.ts +563 -0
  283. package/plugins/specweave-kafka/lib/patterns/circuit-breaker-resilience.js +259 -0
  284. package/plugins/specweave-kafka/lib/patterns/circuit-breaker-resilience.ts +516 -0
  285. package/plugins/specweave-kafka/lib/patterns/dead-letter-queue.js +233 -0
  286. package/plugins/specweave-kafka/lib/patterns/dead-letter-queue.ts +423 -0
  287. package/plugins/specweave-kafka/lib/patterns/exactly-once-semantics.js +266 -0
  288. package/plugins/specweave-kafka/lib/patterns/exactly-once-semantics.ts +445 -0
  289. package/plugins/specweave-kafka/lib/patterns/flink-kafka-integration.js +312 -0
  290. package/plugins/specweave-kafka/lib/patterns/flink-kafka-integration.ts +561 -0
  291. package/plugins/specweave-kafka/lib/patterns/multi-dc-replication.js +289 -0
  292. package/plugins/specweave-kafka/lib/patterns/multi-dc-replication.ts +607 -0
  293. package/plugins/specweave-kafka/lib/patterns/rate-limiting-backpressure.js +264 -0
  294. package/plugins/specweave-kafka/lib/patterns/rate-limiting-backpressure.ts +498 -0
  295. package/plugins/specweave-kafka/lib/patterns/stream-processing-optimization.js +263 -0
  296. package/plugins/specweave-kafka/lib/patterns/stream-processing-optimization.ts +549 -0
  297. package/plugins/specweave-kafka/lib/patterns/tiered-storage-compaction.js +205 -0
  298. package/plugins/specweave-kafka/lib/patterns/tiered-storage-compaction.ts +399 -0
  299. package/plugins/specweave-kafka/lib/performance/performance-optimizer.js +249 -0
  300. package/plugins/specweave-kafka/lib/performance/performance-optimizer.ts +427 -0
  301. package/plugins/specweave-kafka/lib/security/kafka-security.js +252 -0
  302. package/plugins/specweave-kafka/lib/security/kafka-security.ts +494 -0
  303. package/plugins/specweave-kafka/lib/utils/capacity-planner.js +203 -0
  304. package/plugins/specweave-kafka/lib/utils/capacity-planner.ts +469 -0
  305. package/plugins/specweave-kafka/lib/utils/config-validator.js +419 -0
  306. package/plugins/specweave-kafka/lib/utils/config-validator.ts +564 -0
  307. package/plugins/specweave-kafka/lib/utils/partitioning.js +329 -0
  308. package/plugins/specweave-kafka/lib/utils/partitioning.ts +473 -0
  309. package/plugins/specweave-kafka/lib/utils/sizing.js +221 -0
  310. package/plugins/specweave-kafka/lib/utils/sizing.ts +374 -0
  311. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-broker-metrics.json +628 -0
  312. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-cluster-overview.json +564 -0
  313. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-consumer-lag.json +509 -0
  314. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-jvm-metrics.json +674 -0
  315. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-topic-metrics.json +578 -0
  316. package/plugins/specweave-kafka/monitoring/grafana/provisioning/dashboards/kafka.yml +17 -0
  317. package/plugins/specweave-kafka/monitoring/grafana/provisioning/datasources/prometheus.yml +17 -0
  318. package/plugins/specweave-kafka/monitoring/prometheus/kafka-alerts.yml +415 -0
  319. package/plugins/specweave-kafka/monitoring/prometheus/kafka-jmx-exporter.yml +256 -0
  320. package/plugins/specweave-kafka/package.json +41 -0
  321. package/plugins/specweave-kafka/skills/kafka-architecture/SKILL.md +647 -0
  322. package/plugins/specweave-kafka/skills/kafka-cli-tools/SKILL.md +433 -0
  323. package/plugins/specweave-kafka/skills/kafka-iac-deployment/SKILL.md +449 -0
  324. package/plugins/specweave-kafka/skills/kafka-kubernetes/SKILL.md +667 -0
  325. package/plugins/specweave-kafka/skills/kafka-mcp-integration/SKILL.md +273 -0
  326. package/plugins/specweave-kafka/skills/kafka-observability/SKILL.md +576 -0
  327. package/plugins/specweave-kafka/templates/config/broker-production.properties +254 -0
  328. package/plugins/specweave-kafka/templates/config/consumer-low-latency.properties +112 -0
  329. package/plugins/specweave-kafka/templates/config/producer-high-throughput.properties +120 -0
  330. package/plugins/specweave-kafka/templates/migration/mirrormaker2-config.properties +234 -0
  331. package/plugins/specweave-kafka/templates/monitoring/grafana/multi-cluster-dashboard.json +686 -0
  332. package/plugins/specweave-kafka/terraform/apache-kafka/main.tf +347 -0
  333. package/plugins/specweave-kafka/terraform/apache-kafka/outputs.tf +107 -0
  334. package/plugins/specweave-kafka/terraform/apache-kafka/templates/kafka-broker-init.sh.tpl +216 -0
  335. package/plugins/specweave-kafka/terraform/apache-kafka/variables.tf +156 -0
  336. package/plugins/specweave-kafka/terraform/aws-msk/main.tf +362 -0
  337. package/plugins/specweave-kafka/terraform/aws-msk/outputs.tf +93 -0
  338. package/plugins/specweave-kafka/terraform/aws-msk/templates/server.properties.tpl +32 -0
  339. package/plugins/specweave-kafka/terraform/aws-msk/variables.tf +235 -0
  340. package/plugins/specweave-kafka/terraform/azure-event-hubs/main.tf +281 -0
  341. package/plugins/specweave-kafka/terraform/azure-event-hubs/outputs.tf +118 -0
  342. package/plugins/specweave-kafka/terraform/azure-event-hubs/variables.tf +148 -0
  343. package/plugins/specweave-kafka/tsconfig.json +21 -0
  344. package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +23 -0
  345. package/plugins/specweave-kafka-streams/README.md +310 -0
  346. package/plugins/specweave-kafka-streams/skills/kafka-streams-topology/SKILL.md +539 -0
  347. package/plugins/specweave-n8n/.claude-plugin/plugin.json +22 -0
  348. package/plugins/specweave-n8n/README.md +354 -0
  349. package/plugins/specweave-n8n/skills/n8n-kafka-workflows/SKILL.md +504 -0
  350. package/plugins/specweave-release/commands/specweave-release-platform.md +1 -1
  351. package/plugins/specweave-release/hooks/post-task-completion.sh +2 -2
  352. package/src/templates/AGENTS.md.template +601 -7
  353. package/src/templates/CLAUDE.md.template +188 -88
  354. package/dist/locales/de/.gitkeep +0 -0
  355. package/dist/locales/de/cli.json +0 -108
  356. package/dist/locales/en/cli.json +0 -287
  357. package/dist/locales/en/errors.json +0 -7
  358. package/dist/locales/en/templates.json +0 -6
  359. package/dist/locales/es/.gitkeep +0 -0
  360. package/dist/locales/es/cli.json +0 -41
  361. package/dist/locales/fr/.gitkeep +0 -0
  362. package/dist/locales/fr/cli.json +0 -108
  363. package/dist/locales/ja/.gitkeep +0 -0
  364. package/dist/locales/ja/cli.json +0 -108
  365. package/dist/locales/ko/.gitkeep +0 -0
  366. package/dist/locales/ko/cli.json +0 -108
  367. package/dist/locales/pt/.gitkeep +0 -0
  368. package/dist/locales/pt/cli.json +0 -108
  369. package/dist/locales/ru/.gitkeep +0 -0
  370. package/dist/locales/ru/cli.json +0 -269
  371. package/dist/locales/zh/.gitkeep +0 -0
  372. package/dist/locales/zh/cli.json +0 -108
  373. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts +0 -25
  374. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts.map +0 -1
  375. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -191
  376. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js.map +0 -1
  377. package/dist/spec-parser.js +0 -629
  378. package/dist/src/core/sync/spec-content-sync.d.ts +0 -88
  379. package/dist/src/core/sync/spec-content-sync.d.ts.map +0 -1
  380. package/dist/src/core/sync/spec-content-sync.js +0 -5
  381. package/dist/src/core/sync/spec-content-sync.js.map +0 -1
  382. package/dist/tsconfig.tsbuildinfo +0 -1
  383. package/plugins/specweave-ado/commands/specweave-ado-sync-spec.md +0 -255
  384. package/plugins/specweave-github/commands/specweave-github-sync-epic.md +0 -248
  385. package/plugins/specweave-github/commands/specweave-github-sync-from.md +0 -147
  386. package/plugins/specweave-github/commands/specweave-github-sync-spec.md +0 -208
  387. package/plugins/specweave-github/commands/specweave-github-sync-tasks.md +0 -530
  388. package/plugins/specweave-jira/commands/specweave-jira-sync-epic.md +0 -267
  389. package/plugins/specweave-jira/commands/specweave-jira-sync-spec.md +0 -240
@@ -0,0 +1,299 @@
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 UserStoryContentBuilder {
6
+ constructor(userStoryPath, projectRoot) {
7
+ this.userStoryPath = userStoryPath;
8
+ this.projectRoot = projectRoot;
9
+ }
10
+ /**
11
+ * Parse user story file and extract all content
12
+ */
13
+ async parse() {
14
+ const content = await readFile(this.userStoryPath, "utf-8");
15
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
16
+ if (!match) {
17
+ throw new Error("User story file missing YAML frontmatter");
18
+ }
19
+ const frontmatter = yaml.parse(match[1]);
20
+ const bodyContent = content.slice(match[0].length).trim();
21
+ const featureId = this.extractFeatureId(frontmatter.epic, this.userStoryPath);
22
+ const userStoryDescription = this.extractUserStoryDescription(bodyContent);
23
+ const acceptanceCriteria = this.extractAcceptanceCriteria(bodyContent);
24
+ const incrementId = this.extractIncrementId(bodyContent);
25
+ const tasks = incrementId ? await this.extractTasks(bodyContent, incrementId, frontmatter.id) : [];
26
+ return {
27
+ frontmatter,
28
+ userStoryDescription,
29
+ acceptanceCriteria,
30
+ tasks,
31
+ incrementId,
32
+ featureId
33
+ };
34
+ }
35
+ /**
36
+ * Build GitHub issue body from user story content
37
+ *
38
+ * @param githubRepo Optional GitHub repo in format "owner/repo" for generating URLs
39
+ */
40
+ async buildIssueBody(githubRepo) {
41
+ const content = await this.parse();
42
+ let body = "";
43
+ const priority = this.extractPriorityFromACs(content.acceptanceCriteria);
44
+ const repo = githubRepo || await this.detectGitHubRepo();
45
+ if (repo) {
46
+ body += `**Feature**: [${content.featureId}](https://github.com/${repo}/tree/develop/.specweave/docs/internal/specs/_features/${content.featureId})
47
+ `;
48
+ } else {
49
+ body += `**Feature**: ${content.featureId}
50
+ `;
51
+ }
52
+ body += `**Status**: ${content.frontmatter.status}
53
+ `;
54
+ if (priority) {
55
+ body += `**Priority**: ${priority}
56
+ `;
57
+ }
58
+ body += `
59
+ ---
60
+
61
+ `;
62
+ body += `## User Story
63
+
64
+ `;
65
+ if (content.userStoryDescription) {
66
+ body += `**As a** ${content.userStoryDescription.asA}
67
+ `;
68
+ body += `**I want** ${content.userStoryDescription.iWant}
69
+ `;
70
+ body += `**So that** ${content.userStoryDescription.soThat}
71
+
72
+ `;
73
+ } else {
74
+ body += `*User story description not found*
75
+
76
+ `;
77
+ }
78
+ const usFilename = path.basename(this.userStoryPath);
79
+ if (repo) {
80
+ const relativePath = this.userStoryPath.replace(this.projectRoot, "").replace(/^\//, "");
81
+ body += `\u{1F4C4} View full story: [\`${usFilename}\`](https://github.com/${repo}/tree/develop/${relativePath})
82
+
83
+ `;
84
+ }
85
+ body += `---
86
+
87
+ `;
88
+ body += `## Acceptance Criteria
89
+
90
+ `;
91
+ if (content.acceptanceCriteria.length > 0) {
92
+ const completed = content.acceptanceCriteria.filter((ac) => ac.completed).length;
93
+ const total = content.acceptanceCriteria.length;
94
+ const percentage = total > 0 ? Math.round(completed / total * 100) : 0;
95
+ body += `Progress: ${completed}/${total} criteria met (${percentage}%)
96
+
97
+ `;
98
+ for (const ac of content.acceptanceCriteria) {
99
+ const checkbox = ac.completed ? "[x]" : "[ ]";
100
+ const priority2 = ac.priority ? ` (${ac.priority})` : "";
101
+ const testable = ac.testable ? " [testable]" : "";
102
+ body += `- ${checkbox} **${ac.id}**: ${ac.description}${priority2}${testable}
103
+ `;
104
+ }
105
+ body += "\n";
106
+ } else {
107
+ body += `*No acceptance criteria defined*
108
+
109
+ `;
110
+ }
111
+ body += `---
112
+
113
+ `;
114
+ body += `## Implementation Tasks
115
+
116
+ `;
117
+ if (content.tasks.length > 0) {
118
+ const completed = content.tasks.filter((t) => t.status).length;
119
+ const total = content.tasks.length;
120
+ const percentage = total > 0 ? Math.round(completed / total * 100) : 0;
121
+ body += `Progress: ${completed}/${total} tasks complete (${percentage}%)
122
+
123
+ `;
124
+ if (content.incrementId) {
125
+ if (repo) {
126
+ body += `**Increment**: [${content.incrementId}](https://github.com/${repo}/tree/develop/.specweave/increments/${content.incrementId})
127
+
128
+ `;
129
+ } else {
130
+ body += `**Increment**: ${content.incrementId}
131
+
132
+ `;
133
+ }
134
+ }
135
+ for (const task of content.tasks) {
136
+ const checkbox = task.status ? "[x]" : "[ ]";
137
+ let taskLink = task.link;
138
+ if (repo && taskLink.startsWith("../../")) {
139
+ const relativePath = taskLink.replace(/^\.\.\/\.\.\//, ".specweave/");
140
+ taskLink = `https://github.com/${repo}/tree/develop/${relativePath}`;
141
+ }
142
+ body += `- ${checkbox} [${task.id}: ${task.title}](${taskLink})
143
+ `;
144
+ }
145
+ body += "\n";
146
+ } else {
147
+ body += `*No tasks defined yet*
148
+
149
+ `;
150
+ }
151
+ body += `---
152
+
153
+ `;
154
+ body += `\u{1F916} Auto-synced by SpecWeave User Story Sync`;
155
+ return body;
156
+ }
157
+ /**
158
+ * Extract feature ID from epic or path
159
+ */
160
+ extractFeatureId(epic, filePath) {
161
+ if (epic && epic.startsWith("FS-")) {
162
+ return epic;
163
+ }
164
+ const match = filePath.match(/FS-\d+/);
165
+ return match ? match[0] : "FS-UNKNOWN";
166
+ }
167
+ /**
168
+ * Extract user story description (As a... I want... So that...)
169
+ */
170
+ extractUserStoryDescription(content) {
171
+ const asAMatch = content.match(/\*\*As a\*\*\s+([^\n]+)/);
172
+ const iWantMatch = content.match(/\*\*I want\*\*\s+([^\n]+)/);
173
+ const soThatMatch = content.match(/\*\*So that\*\*\s+([^\n]+)/);
174
+ if (asAMatch && iWantMatch && soThatMatch) {
175
+ return {
176
+ asA: asAMatch[1].trim(),
177
+ iWant: iWantMatch[1].trim(),
178
+ soThat: soThatMatch[1].trim()
179
+ };
180
+ }
181
+ return null;
182
+ }
183
+ /**
184
+ * Extract acceptance criteria from content
185
+ */
186
+ extractAcceptanceCriteria(content) {
187
+ const criteria = [];
188
+ const acPattern = /- \[([ x])\] \*\*AC-US(\d+)-(\d+)\*\*:\s*([^(]+)(?:\(([^)]+)\))?/g;
189
+ let match;
190
+ while ((match = acPattern.exec(content)) !== null) {
191
+ const completed = match[1] === "x";
192
+ const usNumber = match[2];
193
+ const acNumber = match[3];
194
+ const description = match[4].trim();
195
+ const metadata = match[5] || "";
196
+ criteria.push({
197
+ id: `AC-US${usNumber}-${acNumber}`,
198
+ description,
199
+ completed,
200
+ priority: metadata.includes("P1") ? "P1" : metadata.includes("P2") ? "P2" : "",
201
+ testable: metadata.includes("testable")
202
+ });
203
+ }
204
+ return criteria;
205
+ }
206
+ /**
207
+ * Extract increment ID from Implementation section
208
+ */
209
+ extractIncrementId(content) {
210
+ const match = content.match(/\*\*Increment\*\*:\s*\[([^\]]+)\]/);
211
+ return match ? match[1] : null;
212
+ }
213
+ /**
214
+ * Extract tasks for this user story from increment tasks.md
215
+ */
216
+ async extractTasks(content, incrementId, userStoryId) {
217
+ const tasks = [];
218
+ const incrementFolder = path.join(
219
+ this.projectRoot,
220
+ ".specweave",
221
+ "increments",
222
+ incrementId
223
+ );
224
+ if (!existsSync(incrementFolder)) {
225
+ console.warn(` \u26A0\uFE0F Increment folder not found: ${incrementId}`);
226
+ return [];
227
+ }
228
+ const tasksPath = path.join(incrementFolder, "tasks.md");
229
+ if (!existsSync(tasksPath)) {
230
+ console.warn(` \u26A0\uFE0F tasks.md not found in ${incrementId}`);
231
+ return [];
232
+ }
233
+ const tasksContent = await readFile(tasksPath, "utf-8");
234
+ const taskLinkPattern = /- \[([T-\d]+):\s*([^\]]+)\]/g;
235
+ let match;
236
+ while ((match = taskLinkPattern.exec(content)) !== null) {
237
+ const taskId = match[1];
238
+ const taskTitle = match[2].trim();
239
+ const taskPattern = new RegExp(
240
+ `###\\s+${taskId}:\\s*([^\\n]+)[\\s\\S]*?\\*\\*Status\\*\\*:\\s*\\[([x\\s])\\]`,
241
+ "i"
242
+ );
243
+ const taskMatch = tasksContent.match(taskPattern);
244
+ const isCompleted = taskMatch ? taskMatch[2] === "x" : false;
245
+ const taskAnchor = taskId.toLowerCase() + "-" + taskTitle.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-");
246
+ const link = `../../increments/${incrementId}/tasks.md#${taskAnchor}`;
247
+ tasks.push({
248
+ id: taskId,
249
+ title: taskTitle,
250
+ status: isCompleted,
251
+ link
252
+ });
253
+ }
254
+ return tasks;
255
+ }
256
+ /**
257
+ * Extract highest priority from acceptance criteria
258
+ * Priority order: P1 > P2 > P3
259
+ */
260
+ extractPriorityFromACs(acceptanceCriteria) {
261
+ if (acceptanceCriteria.length === 0) {
262
+ return null;
263
+ }
264
+ if (acceptanceCriteria.some((ac) => ac.priority === "P1")) {
265
+ return "P1";
266
+ }
267
+ if (acceptanceCriteria.some((ac) => ac.priority === "P2")) {
268
+ return "P2";
269
+ }
270
+ if (acceptanceCriteria.some((ac) => ac.priority === "P3")) {
271
+ return "P3";
272
+ }
273
+ return null;
274
+ }
275
+ /**
276
+ * Detect GitHub repository from git remote
277
+ * Returns "owner/repo" format
278
+ */
279
+ async detectGitHubRepo() {
280
+ try {
281
+ const { execFileNoThrow } = await import("../../../src/utils/execFileNoThrow.js");
282
+ const result = await execFileNoThrow("git", ["remote", "get-url", "origin"]);
283
+ if (result.exitCode !== 0 || !result.stdout) {
284
+ return null;
285
+ }
286
+ const remoteUrl = result.stdout.trim();
287
+ const githubMatch = remoteUrl.match(/github\.com[:/](.+\/.+?)(?:\.git)?$/);
288
+ if (githubMatch) {
289
+ return githubMatch[1];
290
+ }
291
+ return null;
292
+ } catch {
293
+ return null;
294
+ }
295
+ }
296
+ }
297
+ export {
298
+ UserStoryContentBuilder
299
+ };
@@ -0,0 +1,413 @@
1
+ /**
2
+ * User Story Content Builder - GitHub issue content for individual user stories
3
+ *
4
+ * Architecture:
5
+ * - Reads individual us-*.md files from living docs
6
+ * - Extracts ACs and converts to GitHub task checkboxes
7
+ * - Finds and links related tasks from increment tasks.md
8
+ * - Generates rich GitHub issue body with proper formatting
9
+ *
10
+ * Key Features:
11
+ * - Checkable ACs (GitHub task checkboxes)
12
+ * - Task connections (links to increment tasks)
13
+ * - User story description (As a... I want... So that...)
14
+ * - Implementation details
15
+ */
16
+
17
+ import { readFile } from 'fs/promises';
18
+ import { existsSync } from 'fs';
19
+ import * as path from 'path';
20
+ import * as yaml from 'yaml';
21
+
22
+ interface UserStoryFrontmatter {
23
+ id: string;
24
+ epic: string;
25
+ title: string;
26
+ status: 'complete' | 'active' | 'planning' | 'not-started';
27
+ project: string;
28
+ priority: string;
29
+ created: string;
30
+ completed?: string;
31
+ }
32
+
33
+ interface AcceptanceCriterion {
34
+ id: string; // AC-US4-01
35
+ description: string;
36
+ completed: boolean;
37
+ priority: string;
38
+ testable: boolean;
39
+ }
40
+
41
+ interface Task {
42
+ id: string; // T-008
43
+ title: string;
44
+ status: boolean; // true = completed
45
+ link: string; // Link to tasks.md
46
+ }
47
+
48
+ export interface UserStoryContent {
49
+ frontmatter: UserStoryFrontmatter;
50
+ userStoryDescription: {
51
+ asA: string;
52
+ iWant: string;
53
+ soThat: string;
54
+ } | null;
55
+ acceptanceCriteria: AcceptanceCriterion[];
56
+ tasks: Task[];
57
+ incrementId: string | null;
58
+ featureId: string; // FS-031
59
+ }
60
+
61
+ export class UserStoryContentBuilder {
62
+ private userStoryPath: string;
63
+ private projectRoot: string;
64
+
65
+ constructor(userStoryPath: string, projectRoot: string) {
66
+ this.userStoryPath = userStoryPath;
67
+ this.projectRoot = projectRoot;
68
+ }
69
+
70
+ /**
71
+ * Parse user story file and extract all content
72
+ */
73
+ async parse(): Promise<UserStoryContent> {
74
+ const content = await readFile(this.userStoryPath, 'utf-8');
75
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
76
+
77
+ if (!match) {
78
+ throw new Error('User story file missing YAML frontmatter');
79
+ }
80
+
81
+ const frontmatter = yaml.parse(match[1]) as UserStoryFrontmatter;
82
+ const bodyContent = content.slice(match[0].length).trim();
83
+
84
+ // Extract feature ID from epic or path
85
+ const featureId = this.extractFeatureId(frontmatter.epic, this.userStoryPath);
86
+
87
+ // Extract user story description
88
+ const userStoryDescription = this.extractUserStoryDescription(bodyContent);
89
+
90
+ // Extract acceptance criteria
91
+ const acceptanceCriteria = this.extractAcceptanceCriteria(bodyContent);
92
+
93
+ // Extract increment ID and tasks
94
+ const incrementId = this.extractIncrementId(bodyContent);
95
+ const tasks = incrementId
96
+ ? await this.extractTasks(bodyContent, incrementId, frontmatter.id)
97
+ : [];
98
+
99
+ return {
100
+ frontmatter,
101
+ userStoryDescription,
102
+ acceptanceCriteria,
103
+ tasks,
104
+ incrementId,
105
+ featureId,
106
+ };
107
+ }
108
+
109
+ /**
110
+ * Build GitHub issue body from user story content
111
+ *
112
+ * @param githubRepo Optional GitHub repo in format "owner/repo" for generating URLs
113
+ */
114
+ async buildIssueBody(githubRepo?: string): Promise<string> {
115
+ const content = await this.parse();
116
+
117
+ let body = '';
118
+
119
+ // Extract priority from ACs (highest priority wins)
120
+ const priority = this.extractPriorityFromACs(content.acceptanceCriteria);
121
+
122
+ // Detect GitHub repo from git remote if not provided
123
+ const repo = githubRepo || await this.detectGitHubRepo();
124
+
125
+ // Header with metadata
126
+ if (repo) {
127
+ body += `**Feature**: [${content.featureId}](https://github.com/${repo}/tree/develop/.specweave/docs/internal/specs/_features/${content.featureId})\n`;
128
+ } else {
129
+ body += `**Feature**: ${content.featureId}\n`;
130
+ }
131
+ body += `**Status**: ${content.frontmatter.status}\n`;
132
+ if (priority) {
133
+ body += `**Priority**: ${priority}\n`;
134
+ }
135
+
136
+ body += `\n---\n\n`;
137
+
138
+ // User Story description
139
+ body += `## User Story\n\n`;
140
+ if (content.userStoryDescription) {
141
+ body += `**As a** ${content.userStoryDescription.asA}\n`;
142
+ body += `**I want** ${content.userStoryDescription.iWant}\n`;
143
+ body += `**So that** ${content.userStoryDescription.soThat}\n\n`;
144
+ } else {
145
+ body += `*User story description not found*\n\n`;
146
+ }
147
+
148
+ // Link to full user story file (GitHub URL)
149
+ const usFilename = path.basename(this.userStoryPath);
150
+ if (repo) {
151
+ const relativePath = this.userStoryPath
152
+ .replace(this.projectRoot, '')
153
+ .replace(/^\//, '');
154
+ body += `📄 View full story: [\`${usFilename}\`](https://github.com/${repo}/tree/develop/${relativePath})\n\n`;
155
+ }
156
+
157
+ body += `---\n\n`;
158
+
159
+ // Acceptance Criteria (checkable!)
160
+ body += `## Acceptance Criteria\n\n`;
161
+ if (content.acceptanceCriteria.length > 0) {
162
+ const completed = content.acceptanceCriteria.filter((ac) => ac.completed).length;
163
+ const total = content.acceptanceCriteria.length;
164
+ const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;
165
+ body += `Progress: ${completed}/${total} criteria met (${percentage}%)\n\n`;
166
+
167
+ for (const ac of content.acceptanceCriteria) {
168
+ const checkbox = ac.completed ? '[x]' : '[ ]';
169
+ const priority = ac.priority ? ` (${ac.priority})` : '';
170
+ const testable = ac.testable ? ' [testable]' : '';
171
+ body += `- ${checkbox} **${ac.id}**: ${ac.description}${priority}${testable}\n`;
172
+ }
173
+ body += '\n';
174
+ } else {
175
+ body += `*No acceptance criteria defined*\n\n`;
176
+ }
177
+
178
+ body += `---\n\n`;
179
+
180
+ // Tasks (linked to increment!)
181
+ body += `## Implementation Tasks\n\n`;
182
+ if (content.tasks.length > 0) {
183
+ const completed = content.tasks.filter((t) => t.status).length;
184
+ const total = content.tasks.length;
185
+ const percentage = total > 0 ? Math.round((completed / total) * 100) : 0;
186
+ body += `Progress: ${completed}/${total} tasks complete (${percentage}%)\n\n`;
187
+
188
+ if (content.incrementId) {
189
+ if (repo) {
190
+ body += `**Increment**: [${content.incrementId}](https://github.com/${repo}/tree/develop/.specweave/increments/${content.incrementId})\n\n`;
191
+ } else {
192
+ body += `**Increment**: ${content.incrementId}\n\n`;
193
+ }
194
+ }
195
+
196
+ for (const task of content.tasks) {
197
+ const checkbox = task.status ? '[x]' : '[ ]';
198
+ // Convert relative link to GitHub URL if repo is known
199
+ let taskLink = task.link;
200
+ if (repo && taskLink.startsWith('../../')) {
201
+ const relativePath = taskLink.replace(/^\.\.\/\.\.\//, '.specweave/');
202
+ taskLink = `https://github.com/${repo}/tree/develop/${relativePath}`;
203
+ }
204
+ body += `- ${checkbox} [${task.id}: ${task.title}](${taskLink})\n`;
205
+ }
206
+ body += '\n';
207
+ } else {
208
+ body += `*No tasks defined yet*\n\n`;
209
+ }
210
+
211
+ body += `---\n\n`;
212
+ body += `🤖 Auto-synced by SpecWeave User Story Sync`;
213
+
214
+ return body;
215
+ }
216
+
217
+ /**
218
+ * Extract feature ID from epic or path
219
+ */
220
+ private extractFeatureId(epic: string, filePath: string): string {
221
+ // Try epic first (e.g., "FS-031")
222
+ if (epic && epic.startsWith('FS-')) {
223
+ return epic;
224
+ }
225
+
226
+ // Extract from path: .../specs/default/FS-031/us-001-...md
227
+ const match = filePath.match(/FS-\d+/);
228
+ return match ? match[0] : 'FS-UNKNOWN';
229
+ }
230
+
231
+ /**
232
+ * Extract user story description (As a... I want... So that...)
233
+ */
234
+ private extractUserStoryDescription(content: string): {
235
+ asA: string;
236
+ iWant: string;
237
+ soThat: string;
238
+ } | null {
239
+ const asAMatch = content.match(/\*\*As a\*\*\s+([^\n]+)/);
240
+ const iWantMatch = content.match(/\*\*I want\*\*\s+([^\n]+)/);
241
+ const soThatMatch = content.match(/\*\*So that\*\*\s+([^\n]+)/);
242
+
243
+ if (asAMatch && iWantMatch && soThatMatch) {
244
+ return {
245
+ asA: asAMatch[1].trim(),
246
+ iWant: iWantMatch[1].trim(),
247
+ soThat: soThatMatch[1].trim(),
248
+ };
249
+ }
250
+
251
+ return null;
252
+ }
253
+
254
+ /**
255
+ * Extract acceptance criteria from content
256
+ */
257
+ private extractAcceptanceCriteria(content: string): AcceptanceCriterion[] {
258
+ const criteria: AcceptanceCriterion[] = [];
259
+
260
+ // Pattern: - [x] **AC-US4-01**: Description (P1, testable)
261
+ const acPattern =
262
+ /- \[([ x])\] \*\*AC-US(\d+)-(\d+)\*\*:\s*([^(]+)(?:\(([^)]+)\))?/g;
263
+
264
+ let match;
265
+ while ((match = acPattern.exec(content)) !== null) {
266
+ const completed = match[1] === 'x';
267
+ const usNumber = match[2];
268
+ const acNumber = match[3];
269
+ const description = match[4].trim();
270
+ const metadata = match[5] || '';
271
+
272
+ criteria.push({
273
+ id: `AC-US${usNumber}-${acNumber}`,
274
+ description,
275
+ completed,
276
+ priority: metadata.includes('P1') ? 'P1' : metadata.includes('P2') ? 'P2' : '',
277
+ testable: metadata.includes('testable'),
278
+ });
279
+ }
280
+
281
+ return criteria;
282
+ }
283
+
284
+ /**
285
+ * Extract increment ID from Implementation section
286
+ */
287
+ private extractIncrementId(content: string): string | null {
288
+ // Pattern: **Increment**: [0031-external-tool-status-sync](...)
289
+ const match = content.match(/\*\*Increment\*\*:\s*\[([^\]]+)\]/);
290
+ return match ? match[1] : null;
291
+ }
292
+
293
+ /**
294
+ * Extract tasks for this user story from increment tasks.md
295
+ */
296
+ private async extractTasks(
297
+ content: string,
298
+ incrementId: string,
299
+ userStoryId: string
300
+ ): Promise<Task[]> {
301
+ const tasks: Task[] = [];
302
+
303
+ // Find increment folder
304
+ const incrementFolder = path.join(
305
+ this.projectRoot,
306
+ '.specweave',
307
+ 'increments',
308
+ incrementId
309
+ );
310
+
311
+ if (!existsSync(incrementFolder)) {
312
+ console.warn(` ⚠️ Increment folder not found: ${incrementId}`);
313
+ return [];
314
+ }
315
+
316
+ const tasksPath = path.join(incrementFolder, 'tasks.md');
317
+ if (!existsSync(tasksPath)) {
318
+ console.warn(` ⚠️ tasks.md not found in ${incrementId}`);
319
+ return [];
320
+ }
321
+
322
+ // Read tasks.md
323
+ const tasksContent = await readFile(tasksPath, 'utf-8');
324
+
325
+ // Extract task links from user story's Implementation section
326
+ // Format: - [T-008: Create Status Sync Engine](link#t-008-create-status-sync-engine)
327
+ const taskLinkPattern = /- \[([T-\d]+):\s*([^\]]+)\]/g;
328
+
329
+ let match;
330
+ while ((match = taskLinkPattern.exec(content)) !== null) {
331
+ const taskId = match[1]; // e.g., "T-008"
332
+ const taskTitle = match[2].trim();
333
+
334
+ // Find task in tasks.md to get completion status
335
+ // Pattern: ### T-008: Create Status Sync Engine ... **Status**: [x]
336
+ const taskPattern = new RegExp(
337
+ `###\\s+${taskId}:\\s*([^\\n]+)[\\s\\S]*?\\*\\*Status\\*\\*:\\s*\\[([x\\s])\\]`,
338
+ 'i'
339
+ );
340
+ const taskMatch = tasksContent.match(taskPattern);
341
+
342
+ const isCompleted = taskMatch ? taskMatch[2] === 'x' : false;
343
+
344
+ // Build link to task in tasks.md
345
+ const taskAnchor = taskId.toLowerCase() + '-' + taskTitle.toLowerCase().replace(/[^\w\s-]/g, '').replace(/\s+/g, '-');
346
+ const link = `../../increments/${incrementId}/tasks.md#${taskAnchor}`;
347
+
348
+ tasks.push({
349
+ id: taskId,
350
+ title: taskTitle,
351
+ status: isCompleted,
352
+ link,
353
+ });
354
+ }
355
+
356
+ return tasks;
357
+ }
358
+
359
+ /**
360
+ * Extract highest priority from acceptance criteria
361
+ * Priority order: P1 > P2 > P3
362
+ */
363
+ private extractPriorityFromACs(acceptanceCriteria: AcceptanceCriterion[]): string | null {
364
+ if (acceptanceCriteria.length === 0) {
365
+ return null;
366
+ }
367
+
368
+ // Check for P1 first (highest priority)
369
+ if (acceptanceCriteria.some(ac => ac.priority === 'P1')) {
370
+ return 'P1';
371
+ }
372
+
373
+ // Then P2
374
+ if (acceptanceCriteria.some(ac => ac.priority === 'P2')) {
375
+ return 'P2';
376
+ }
377
+
378
+ // Then P3
379
+ if (acceptanceCriteria.some(ac => ac.priority === 'P3')) {
380
+ return 'P3';
381
+ }
382
+
383
+ return null; // No priority found
384
+ }
385
+
386
+ /**
387
+ * Detect GitHub repository from git remote
388
+ * Returns "owner/repo" format
389
+ */
390
+ private async detectGitHubRepo(): Promise<string | null> {
391
+ try {
392
+ const { execFileNoThrow } = await import('../../../src/utils/execFileNoThrow.js');
393
+ const result = await execFileNoThrow('git', ['remote', 'get-url', 'origin']);
394
+
395
+ if (result.exitCode !== 0 || !result.stdout) {
396
+ return null;
397
+ }
398
+
399
+ const remoteUrl = result.stdout.trim();
400
+
401
+ // Parse GitHub URL
402
+ // Formats: git@github.com:owner/repo.git or https://github.com/owner/repo.git
403
+ const githubMatch = remoteUrl.match(/github\.com[:/](.+\/.+?)(?:\.git)?$/);
404
+ if (githubMatch) {
405
+ return githubMatch[1]; // "owner/repo"
406
+ }
407
+
408
+ return null;
409
+ } catch {
410
+ return null;
411
+ }
412
+ }
413
+ }