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.
Files changed (428) hide show
  1. package/CLAUDE.md +229 -1817
  2. package/README.md +68 -0
  3. package/bin/specweave.js +62 -6
  4. package/dist/locales/de/.gitkeep +0 -0
  5. package/dist/locales/de/cli.json +108 -0
  6. package/dist/locales/en/cli.json +287 -0
  7. package/dist/locales/en/errors.json +7 -0
  8. package/dist/locales/en/templates.json +6 -0
  9. package/dist/locales/es/.gitkeep +0 -0
  10. package/dist/locales/es/cli.json +41 -0
  11. package/dist/locales/fr/.gitkeep +0 -0
  12. package/dist/locales/fr/cli.json +108 -0
  13. package/dist/locales/ja/.gitkeep +0 -0
  14. package/dist/locales/ja/cli.json +108 -0
  15. package/dist/locales/ko/.gitkeep +0 -0
  16. package/dist/locales/ko/cli.json +108 -0
  17. package/dist/locales/pt/.gitkeep +0 -0
  18. package/dist/locales/pt/cli.json +108 -0
  19. package/dist/locales/ru/.gitkeep +0 -0
  20. package/dist/locales/ru/cli.json +269 -0
  21. package/dist/locales/zh/.gitkeep +0 -0
  22. package/dist/locales/zh/cli.json +108 -0
  23. package/dist/plugins/specweave/lib/hooks/sync-living-docs.d.ts.map +1 -1
  24. package/dist/plugins/specweave/lib/hooks/sync-living-docs.js +3 -0
  25. package/dist/plugins/specweave/lib/hooks/sync-living-docs.js.map +1 -1
  26. package/dist/plugins/specweave/lib/hooks/update-ac-status.d.ts +21 -0
  27. package/dist/plugins/specweave/lib/hooks/update-ac-status.d.ts.map +1 -0
  28. package/dist/plugins/specweave/lib/hooks/update-ac-status.js +162 -0
  29. package/dist/plugins/specweave/lib/hooks/update-ac-status.js.map +1 -0
  30. package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.d.ts.map +1 -1
  31. package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js +65 -6
  32. package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js.map +1 -1
  33. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts +25 -0
  34. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts.map +1 -0
  35. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js +191 -0
  36. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js.map +1 -0
  37. package/dist/plugins/specweave-github/lib/completion-calculator.d.ts +112 -0
  38. package/dist/plugins/specweave-github/lib/completion-calculator.d.ts.map +1 -0
  39. package/dist/plugins/specweave-github/lib/completion-calculator.js +301 -0
  40. package/dist/plugins/specweave-github/lib/completion-calculator.js.map +1 -0
  41. package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts +3 -3
  42. package/dist/plugins/specweave-github/lib/duplicate-detector.js +3 -3
  43. package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts +70 -0
  44. package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts.map +1 -0
  45. package/dist/plugins/specweave-github/lib/epic-content-builder.js +258 -0
  46. package/dist/plugins/specweave-github/lib/epic-content-builder.js.map +1 -0
  47. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +14 -0
  48. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
  49. package/dist/plugins/specweave-github/lib/github-client-v2.js +51 -0
  50. package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
  51. package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts +2 -2
  52. package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts.map +1 -1
  53. package/dist/plugins/specweave-github/lib/github-epic-sync.js +20 -5
  54. package/dist/plugins/specweave-github/lib/github-epic-sync.js.map +1 -1
  55. package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts +87 -0
  56. package/dist/plugins/specweave-github/lib/github-feature-sync.d.ts.map +1 -0
  57. package/dist/plugins/specweave-github/lib/github-feature-sync.js +412 -0
  58. package/dist/plugins/specweave-github/lib/github-feature-sync.js.map +1 -0
  59. package/dist/plugins/specweave-github/lib/github-spec-content-sync.d.ts.map +1 -1
  60. package/dist/plugins/specweave-github/lib/github-spec-content-sync.js +64 -13
  61. package/dist/plugins/specweave-github/lib/github-spec-content-sync.js.map +1 -1
  62. package/dist/plugins/specweave-github/lib/progress-comment-builder.d.ts +78 -0
  63. package/dist/plugins/specweave-github/lib/progress-comment-builder.d.ts.map +1 -0
  64. package/dist/plugins/specweave-github/lib/progress-comment-builder.js +237 -0
  65. package/dist/plugins/specweave-github/lib/progress-comment-builder.js.map +1 -0
  66. package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts +97 -0
  67. package/dist/plugins/specweave-github/lib/user-story-content-builder.d.ts.map +1 -0
  68. package/dist/plugins/specweave-github/lib/user-story-content-builder.js +301 -0
  69. package/dist/plugins/specweave-github/lib/user-story-content-builder.js.map +1 -0
  70. package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts +83 -0
  71. package/dist/plugins/specweave-github/lib/user-story-issue-builder.d.ts.map +1 -0
  72. package/dist/plugins/specweave-github/lib/user-story-issue-builder.js +386 -0
  73. package/dist/plugins/specweave-github/lib/user-story-issue-builder.js.map +1 -0
  74. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts +28 -0
  75. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts.map +1 -0
  76. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js +156 -0
  77. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js.map +1 -0
  78. package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.d.ts +57 -0
  79. package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.d.ts.map +1 -0
  80. package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.js +248 -0
  81. package/dist/plugins/specweave-kafka/lib/cli/kcat-wrapper.js.map +1 -0
  82. package/dist/plugins/specweave-kafka/lib/cli/types.d.ts +82 -0
  83. package/dist/plugins/specweave-kafka/lib/cli/types.d.ts.map +1 -0
  84. package/dist/plugins/specweave-kafka/lib/cli/types.js +13 -0
  85. package/dist/plugins/specweave-kafka/lib/cli/types.js.map +1 -0
  86. package/dist/plugins/specweave-kafka/lib/mcp/detector.d.ts +49 -0
  87. package/dist/plugins/specweave-kafka/lib/mcp/detector.d.ts.map +1 -0
  88. package/dist/plugins/specweave-kafka/lib/mcp/detector.js +316 -0
  89. package/dist/plugins/specweave-kafka/lib/mcp/detector.js.map +1 -0
  90. package/dist/plugins/specweave-kafka/lib/mcp/types.d.ts +70 -0
  91. package/dist/plugins/specweave-kafka/lib/mcp/types.d.ts.map +1 -0
  92. package/dist/plugins/specweave-kafka/lib/mcp/types.js +23 -0
  93. package/dist/plugins/specweave-kafka/lib/mcp/types.js.map +1 -0
  94. package/dist/plugins/specweave-kafka/lib/utils/partitioning.d.ts +85 -0
  95. package/dist/plugins/specweave-kafka/lib/utils/partitioning.d.ts.map +1 -0
  96. package/dist/plugins/specweave-kafka/lib/utils/partitioning.js +281 -0
  97. package/dist/plugins/specweave-kafka/lib/utils/partitioning.js.map +1 -0
  98. package/dist/plugins/specweave-kafka/lib/utils/sizing.d.ts +75 -0
  99. package/dist/plugins/specweave-kafka/lib/utils/sizing.d.ts.map +1 -0
  100. package/dist/plugins/specweave-kafka/lib/utils/sizing.js +238 -0
  101. package/dist/plugins/specweave-kafka/lib/utils/sizing.js.map +1 -0
  102. package/dist/spec-parser.js +629 -0
  103. package/dist/src/cli/commands/import-docs.js +4 -4
  104. package/dist/src/cli/commands/import-docs.js.map +1 -1
  105. package/dist/src/cli/commands/init-multiproject.d.ts.map +1 -1
  106. package/dist/src/cli/commands/init-multiproject.js +17 -18
  107. package/dist/src/cli/commands/init-multiproject.js.map +1 -1
  108. package/dist/src/cli/commands/init.d.ts.map +1 -1
  109. package/dist/src/cli/commands/init.js +107 -3
  110. package/dist/src/cli/commands/init.js.map +1 -1
  111. package/dist/src/cli/commands/migrate-to-multiproject.d.ts.map +1 -1
  112. package/dist/src/cli/commands/migrate-to-multiproject.js +8 -4
  113. package/dist/src/cli/commands/migrate-to-multiproject.js.map +1 -1
  114. package/dist/src/cli/commands/switch-project.d.ts.map +1 -1
  115. package/dist/src/cli/commands/switch-project.js +9 -26
  116. package/dist/src/cli/commands/switch-project.js.map +1 -1
  117. package/dist/src/cli/commands/sync-spec-content.js +3 -0
  118. package/dist/src/cli/commands/sync-spec-content.js.map +1 -1
  119. package/dist/src/core/deduplication/command-deduplicator.d.ts +166 -0
  120. package/dist/src/core/deduplication/command-deduplicator.d.ts.map +1 -0
  121. package/dist/src/core/deduplication/command-deduplicator.js +254 -0
  122. package/dist/src/core/deduplication/command-deduplicator.js.map +1 -0
  123. package/dist/src/core/increment/active-increment-manager.d.ts +42 -15
  124. package/dist/src/core/increment/active-increment-manager.d.ts.map +1 -1
  125. package/dist/src/core/increment/active-increment-manager.js +113 -46
  126. package/dist/src/core/increment/active-increment-manager.js.map +1 -1
  127. package/dist/src/core/increment/conflict-resolver.d.ts +40 -0
  128. package/dist/src/core/increment/conflict-resolver.d.ts.map +1 -0
  129. package/dist/src/core/increment/conflict-resolver.js +219 -0
  130. package/dist/src/core/increment/conflict-resolver.js.map +1 -0
  131. package/dist/src/core/increment/discipline-checker.d.ts.map +1 -1
  132. package/dist/src/core/increment/discipline-checker.js +7 -1
  133. package/dist/src/core/increment/discipline-checker.js.map +1 -1
  134. package/dist/src/core/increment/duplicate-detector.d.ts +52 -0
  135. package/dist/src/core/increment/duplicate-detector.d.ts.map +1 -0
  136. package/dist/src/core/increment/duplicate-detector.js +276 -0
  137. package/dist/src/core/increment/duplicate-detector.js.map +1 -0
  138. package/dist/src/core/increment/increment-archiver.d.ts +90 -0
  139. package/dist/src/core/increment/increment-archiver.d.ts.map +1 -0
  140. package/dist/src/core/increment/increment-archiver.js +368 -0
  141. package/dist/src/core/increment/increment-archiver.js.map +1 -0
  142. package/dist/src/core/increment/increment-reopener.d.ts +165 -0
  143. package/dist/src/core/increment/increment-reopener.d.ts.map +1 -0
  144. package/dist/src/core/increment/increment-reopener.js +390 -0
  145. package/dist/src/core/increment/increment-reopener.js.map +1 -0
  146. package/dist/src/core/increment/metadata-manager.d.ts +26 -1
  147. package/dist/src/core/increment/metadata-manager.d.ts.map +1 -1
  148. package/dist/src/core/increment/metadata-manager.js +143 -5
  149. package/dist/src/core/increment/metadata-manager.js.map +1 -1
  150. package/dist/src/core/increment/recent-work-scanner.d.ts +121 -0
  151. package/dist/src/core/increment/recent-work-scanner.d.ts.map +1 -0
  152. package/dist/src/core/increment/recent-work-scanner.js +303 -0
  153. package/dist/src/core/increment/recent-work-scanner.js.map +1 -0
  154. package/dist/src/core/increment/types.d.ts +1 -0
  155. package/dist/src/core/increment/types.d.ts.map +1 -1
  156. package/dist/src/core/increment-utils.d.ts +112 -0
  157. package/dist/src/core/increment-utils.d.ts.map +1 -0
  158. package/dist/src/core/increment-utils.js +210 -0
  159. package/dist/src/core/increment-utils.js.map +1 -0
  160. package/dist/src/core/living-docs/ac-project-specific-generator.d.ts +65 -0
  161. package/dist/src/core/living-docs/ac-project-specific-generator.d.ts.map +1 -0
  162. package/dist/src/core/living-docs/ac-project-specific-generator.js +175 -0
  163. package/dist/src/core/living-docs/ac-project-specific-generator.js.map +1 -0
  164. package/dist/src/core/living-docs/feature-archiver.d.ts +130 -0
  165. package/dist/src/core/living-docs/feature-archiver.d.ts.map +1 -0
  166. package/dist/src/core/living-docs/feature-archiver.js +549 -0
  167. package/dist/src/core/living-docs/feature-archiver.js.map +1 -0
  168. package/dist/src/core/living-docs/feature-id-manager.d.ts +81 -0
  169. package/dist/src/core/living-docs/feature-id-manager.d.ts.map +1 -0
  170. package/dist/src/core/living-docs/feature-id-manager.js +339 -0
  171. package/dist/src/core/living-docs/feature-id-manager.js.map +1 -0
  172. package/dist/src/core/living-docs/hierarchy-mapper.d.ts +144 -83
  173. package/dist/src/core/living-docs/hierarchy-mapper.d.ts.map +1 -1
  174. package/dist/src/core/living-docs/hierarchy-mapper.js +488 -270
  175. package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
  176. package/dist/src/core/living-docs/index.d.ts +6 -0
  177. package/dist/src/core/living-docs/index.d.ts.map +1 -1
  178. package/dist/src/core/living-docs/index.js +6 -0
  179. package/dist/src/core/living-docs/index.js.map +1 -1
  180. package/dist/src/core/living-docs/project-detector.d.ts +6 -0
  181. package/dist/src/core/living-docs/project-detector.d.ts.map +1 -1
  182. package/dist/src/core/living-docs/project-detector.js +35 -1
  183. package/dist/src/core/living-docs/project-detector.js.map +1 -1
  184. package/dist/src/core/living-docs/spec-distributor.d.ts +100 -26
  185. package/dist/src/core/living-docs/spec-distributor.d.ts.map +1 -1
  186. package/dist/src/core/living-docs/spec-distributor.js +1275 -258
  187. package/dist/src/core/living-docs/spec-distributor.js.map +1 -1
  188. package/dist/src/core/living-docs/task-project-specific-generator.d.ts +109 -0
  189. package/dist/src/core/living-docs/task-project-specific-generator.d.ts.map +1 -0
  190. package/dist/src/core/living-docs/task-project-specific-generator.js +221 -0
  191. package/dist/src/core/living-docs/task-project-specific-generator.js.map +1 -0
  192. package/dist/src/core/living-docs/types.d.ts +143 -0
  193. package/dist/src/core/living-docs/types.d.ts.map +1 -1
  194. package/dist/src/core/project-manager.d.ts +2 -17
  195. package/dist/src/core/project-manager.d.ts.map +1 -1
  196. package/dist/src/core/project-manager.js +68 -48
  197. package/dist/src/core/project-manager.js.map +1 -1
  198. package/dist/src/core/spec-content-sync.d.ts +1 -1
  199. package/dist/src/core/spec-content-sync.d.ts.map +1 -1
  200. package/dist/src/core/sync/enhanced-content-builder.d.ts +32 -54
  201. package/dist/src/core/sync/enhanced-content-builder.d.ts.map +1 -1
  202. package/dist/src/core/sync/enhanced-content-builder.js +142 -138
  203. package/dist/src/core/sync/enhanced-content-builder.js.map +1 -1
  204. package/dist/src/core/sync/performance-optimizer.d.ts +153 -0
  205. package/dist/src/core/sync/performance-optimizer.d.ts.map +1 -0
  206. package/dist/src/core/sync/performance-optimizer.js +220 -0
  207. package/dist/src/core/sync/performance-optimizer.js.map +1 -0
  208. package/dist/src/core/sync/retry-handler.d.ts +98 -0
  209. package/dist/src/core/sync/retry-handler.d.ts.map +1 -0
  210. package/dist/src/core/sync/retry-handler.js +196 -0
  211. package/dist/src/core/sync/retry-handler.js.map +1 -0
  212. package/dist/src/core/sync/spec-content-sync.d.ts +88 -0
  213. package/dist/src/core/sync/spec-content-sync.d.ts.map +1 -0
  214. package/dist/src/core/sync/spec-content-sync.js +5 -0
  215. package/dist/src/core/sync/spec-content-sync.js.map +1 -0
  216. package/dist/src/core/sync/types.d.ts +52 -0
  217. package/dist/src/core/sync/types.d.ts.map +1 -0
  218. package/dist/src/core/sync/types.js +5 -0
  219. package/dist/src/core/sync/types.js.map +1 -0
  220. package/dist/src/core/types/config.d.ts +125 -0
  221. package/dist/src/core/types/config.d.ts.map +1 -1
  222. package/dist/src/core/types/config.js +25 -0
  223. package/dist/src/core/types/config.js.map +1 -1
  224. package/dist/src/core/types/increment-metadata.d.ts +10 -0
  225. package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
  226. package/dist/src/core/types/increment-metadata.js +10 -1
  227. package/dist/src/core/types/increment-metadata.js.map +1 -1
  228. package/dist/src/integrations/jira/jira-incremental-mapper.d.ts.map +1 -1
  229. package/dist/src/integrations/jira/jira-incremental-mapper.js +4 -8
  230. package/dist/src/integrations/jira/jira-incremental-mapper.js.map +1 -1
  231. package/dist/src/integrations/jira/jira-mapper.d.ts.map +1 -1
  232. package/dist/src/integrations/jira/jira-mapper.js +4 -8
  233. package/dist/src/integrations/jira/jira-mapper.js.map +1 -1
  234. package/dist/tsconfig.tsbuildinfo +1 -0
  235. package/package.json +1 -1
  236. package/plugins/specweave/COMMANDS.md +13 -4
  237. package/plugins/specweave/agents/pm/AGENT.md +159 -12
  238. package/plugins/specweave/commands/specweave-abandon.md +22 -20
  239. package/plugins/specweave/commands/specweave-archive-features.md +121 -0
  240. package/plugins/specweave/commands/specweave-archive-increments.md +82 -0
  241. package/plugins/specweave/commands/specweave-archive.md +363 -0
  242. package/plugins/specweave/commands/specweave-backlog.md +211 -0
  243. package/plugins/specweave/commands/specweave-fix-duplicates.md +517 -0
  244. package/plugins/specweave/commands/specweave-increment.md +4 -3
  245. package/plugins/specweave/commands/specweave-progress.md +176 -27
  246. package/plugins/specweave/commands/specweave-reopen.md +391 -0
  247. package/plugins/specweave/commands/specweave-restore-feature.md +90 -0
  248. package/plugins/specweave/commands/specweave-restore.md +309 -0
  249. package/plugins/specweave/commands/specweave-resume.md +51 -23
  250. package/plugins/specweave/commands/specweave-status.md +41 -7
  251. package/plugins/specweave/commands/specweave-sync-specs.md +425 -0
  252. package/plugins/specweave/commands/specweave.md +70 -405
  253. package/plugins/specweave/hooks/hooks.json +4 -0
  254. package/plugins/specweave/hooks/lib/sync-spec-content.sh +2 -2
  255. package/plugins/specweave/hooks/post-increment-planning.sh +26 -2
  256. package/plugins/specweave/hooks/post-task-completion.sh +39 -0
  257. package/plugins/specweave/hooks/pre-command-deduplication.sh +83 -0
  258. package/plugins/specweave/hooks/user-prompt-submit.sh +1 -1
  259. package/plugins/specweave/lib/hooks/sync-living-docs.js +2 -0
  260. package/plugins/specweave/lib/hooks/sync-living-docs.ts +4 -0
  261. package/plugins/specweave/lib/hooks/update-ac-status.js +102 -0
  262. package/plugins/specweave/lib/hooks/update-ac-status.ts +192 -0
  263. package/plugins/specweave/skills/archive-increments/SKILL.md +198 -0
  264. package/plugins/specweave/skills/increment-planner/scripts/feature-utils.js +14 -0
  265. package/plugins/specweave/skills/smart-reopen-detector/SKILL.md +244 -0
  266. package/plugins/specweave-ado/lib/ado-spec-content-sync.js +49 -5
  267. package/plugins/specweave-ado/lib/ado-spec-content-sync.ts +72 -6
  268. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  269. package/plugins/specweave-confluent/.claude-plugin/plugin.json +23 -0
  270. package/plugins/specweave-confluent/README.md +375 -0
  271. package/plugins/specweave-confluent/agents/confluent-architect/AGENT.md +306 -0
  272. package/plugins/specweave-confluent/skills/confluent-kafka-connect/SKILL.md +453 -0
  273. package/plugins/specweave-confluent/skills/confluent-ksqldb/SKILL.md +470 -0
  274. package/plugins/specweave-confluent/skills/confluent-schema-registry/SKILL.md +316 -0
  275. package/plugins/specweave-github/agents/github-task-splitter/AGENT.md +2 -2
  276. package/plugins/specweave-github/agents/user-story-updater/AGENT.md +148 -0
  277. package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +1 -1
  278. package/plugins/specweave-github/commands/specweave-github-update-user-story.md +156 -0
  279. package/plugins/specweave-github/hooks/post-task-completion.sh +42 -9
  280. package/plugins/specweave-github/lib/completion-calculator.js +262 -0
  281. package/plugins/specweave-github/lib/completion-calculator.ts +434 -0
  282. package/plugins/specweave-github/lib/duplicate-detector.js +3 -3
  283. package/plugins/specweave-github/lib/duplicate-detector.ts +4 -4
  284. package/plugins/specweave-github/lib/epic-content-builder.js +265 -0
  285. package/plugins/specweave-github/lib/epic-content-builder.ts +376 -0
  286. package/plugins/specweave-github/lib/github-client-v2.js +49 -0
  287. package/plugins/specweave-github/lib/github-client-v2.ts +59 -0
  288. package/plugins/specweave-github/lib/github-epic-sync.js +23 -24
  289. package/plugins/specweave-github/lib/github-epic-sync.ts +30 -5
  290. package/plugins/specweave-github/lib/github-feature-sync.js +381 -0
  291. package/plugins/specweave-github/lib/github-feature-sync.ts +568 -0
  292. package/plugins/specweave-github/lib/github-spec-content-sync.js +40 -10
  293. package/plugins/specweave-github/lib/github-spec-content-sync.ts +82 -14
  294. package/plugins/specweave-github/lib/progress-comment-builder.js +229 -0
  295. package/plugins/specweave-github/lib/progress-comment-builder.ts +324 -0
  296. package/plugins/specweave-github/lib/user-story-content-builder.js +299 -0
  297. package/plugins/specweave-github/lib/user-story-content-builder.ts +413 -0
  298. package/plugins/specweave-github/lib/user-story-issue-builder.js +344 -0
  299. package/plugins/specweave-github/lib/user-story-issue-builder.ts +543 -0
  300. package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +189 -0
  301. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
  302. package/plugins/specweave-jira/lib/{enhanced-jira-sync.ts.disabled → enhanced-jira-sync.ts} +26 -52
  303. package/plugins/specweave-kafka/.claude-plugin/plugin.json +26 -0
  304. package/plugins/specweave-kafka/IMPLEMENTATION-COMPLETE.md +483 -0
  305. package/plugins/specweave-kafka/README.md +242 -0
  306. package/plugins/specweave-kafka/agents/kafka-architect/AGENT.md +235 -0
  307. package/plugins/specweave-kafka/agents/kafka-devops/AGENT.md +209 -0
  308. package/plugins/specweave-kafka/agents/kafka-observability/AGENT.md +266 -0
  309. package/plugins/specweave-kafka/commands/deploy.md +99 -0
  310. package/plugins/specweave-kafka/commands/dev-env.md +176 -0
  311. package/plugins/specweave-kafka/commands/mcp-configure.md +101 -0
  312. package/plugins/specweave-kafka/commands/monitor-setup.md +96 -0
  313. package/plugins/specweave-kafka/docker/kafka-local/docker-compose.yml +187 -0
  314. package/plugins/specweave-kafka/docker/redpanda/docker-compose.yml +199 -0
  315. package/plugins/specweave-kafka/docker/templates/consumer-nodejs.js +225 -0
  316. package/plugins/specweave-kafka/docker/templates/consumer-python.py +220 -0
  317. package/plugins/specweave-kafka/docker/templates/producer-nodejs.js +168 -0
  318. package/plugins/specweave-kafka/docker/templates/producer-python.py +167 -0
  319. package/plugins/specweave-kafka/lib/adapters/apache-kafka-adapter.js +438 -0
  320. package/plugins/specweave-kafka/lib/adapters/apache-kafka-adapter.ts +541 -0
  321. package/plugins/specweave-kafka/lib/adapters/platform-adapter.js +47 -0
  322. package/plugins/specweave-kafka/lib/adapters/platform-adapter.ts +343 -0
  323. package/plugins/specweave-kafka/lib/cli/kcat-wrapper.js +258 -0
  324. package/plugins/specweave-kafka/lib/cli/kcat-wrapper.ts +298 -0
  325. package/plugins/specweave-kafka/lib/cli/types.js +10 -0
  326. package/plugins/specweave-kafka/lib/cli/types.ts +92 -0
  327. package/plugins/specweave-kafka/lib/connectors/connector-catalog.js +305 -0
  328. package/plugins/specweave-kafka/lib/connectors/connector-catalog.ts +528 -0
  329. package/plugins/specweave-kafka/lib/documentation/diagram-generator.js +114 -0
  330. package/plugins/specweave-kafka/lib/documentation/diagram-generator.ts +195 -0
  331. package/plugins/specweave-kafka/lib/documentation/exporter.js +210 -0
  332. package/plugins/specweave-kafka/lib/documentation/exporter.ts +338 -0
  333. package/plugins/specweave-kafka/lib/documentation/schema-catalog-generator.js +60 -0
  334. package/plugins/specweave-kafka/lib/documentation/schema-catalog-generator.ts +130 -0
  335. package/plugins/specweave-kafka/lib/documentation/topology-generator.js +143 -0
  336. package/plugins/specweave-kafka/lib/documentation/topology-generator.ts +290 -0
  337. package/plugins/specweave-kafka/lib/mcp/detector.js +298 -0
  338. package/plugins/specweave-kafka/lib/mcp/detector.ts +352 -0
  339. package/plugins/specweave-kafka/lib/mcp/types.js +21 -0
  340. package/plugins/specweave-kafka/lib/mcp/types.ts +77 -0
  341. package/plugins/specweave-kafka/lib/multi-cluster/cluster-config-manager.js +193 -0
  342. package/plugins/specweave-kafka/lib/multi-cluster/cluster-config-manager.ts +362 -0
  343. package/plugins/specweave-kafka/lib/multi-cluster/cluster-switcher.js +188 -0
  344. package/plugins/specweave-kafka/lib/multi-cluster/cluster-switcher.ts +359 -0
  345. package/plugins/specweave-kafka/lib/multi-cluster/health-aggregator.js +195 -0
  346. package/plugins/specweave-kafka/lib/multi-cluster/health-aggregator.ts +380 -0
  347. package/plugins/specweave-kafka/lib/observability/opentelemetry-kafka.js +209 -0
  348. package/plugins/specweave-kafka/lib/observability/opentelemetry-kafka.ts +358 -0
  349. package/plugins/specweave-kafka/lib/patterns/advanced-ksqldb-patterns.js +354 -0
  350. package/plugins/specweave-kafka/lib/patterns/advanced-ksqldb-patterns.ts +563 -0
  351. package/plugins/specweave-kafka/lib/patterns/circuit-breaker-resilience.js +259 -0
  352. package/plugins/specweave-kafka/lib/patterns/circuit-breaker-resilience.ts +516 -0
  353. package/plugins/specweave-kafka/lib/patterns/dead-letter-queue.js +233 -0
  354. package/plugins/specweave-kafka/lib/patterns/dead-letter-queue.ts +423 -0
  355. package/plugins/specweave-kafka/lib/patterns/exactly-once-semantics.js +266 -0
  356. package/plugins/specweave-kafka/lib/patterns/exactly-once-semantics.ts +445 -0
  357. package/plugins/specweave-kafka/lib/patterns/flink-kafka-integration.js +312 -0
  358. package/plugins/specweave-kafka/lib/patterns/flink-kafka-integration.ts +561 -0
  359. package/plugins/specweave-kafka/lib/patterns/multi-dc-replication.js +289 -0
  360. package/plugins/specweave-kafka/lib/patterns/multi-dc-replication.ts +607 -0
  361. package/plugins/specweave-kafka/lib/patterns/rate-limiting-backpressure.js +264 -0
  362. package/plugins/specweave-kafka/lib/patterns/rate-limiting-backpressure.ts +498 -0
  363. package/plugins/specweave-kafka/lib/patterns/stream-processing-optimization.js +263 -0
  364. package/plugins/specweave-kafka/lib/patterns/stream-processing-optimization.ts +549 -0
  365. package/plugins/specweave-kafka/lib/patterns/tiered-storage-compaction.js +205 -0
  366. package/plugins/specweave-kafka/lib/patterns/tiered-storage-compaction.ts +399 -0
  367. package/plugins/specweave-kafka/lib/performance/performance-optimizer.js +249 -0
  368. package/plugins/specweave-kafka/lib/performance/performance-optimizer.ts +427 -0
  369. package/plugins/specweave-kafka/lib/security/kafka-security.js +252 -0
  370. package/plugins/specweave-kafka/lib/security/kafka-security.ts +494 -0
  371. package/plugins/specweave-kafka/lib/utils/capacity-planner.js +203 -0
  372. package/plugins/specweave-kafka/lib/utils/capacity-planner.ts +469 -0
  373. package/plugins/specweave-kafka/lib/utils/config-validator.js +419 -0
  374. package/plugins/specweave-kafka/lib/utils/config-validator.ts +564 -0
  375. package/plugins/specweave-kafka/lib/utils/partitioning.js +329 -0
  376. package/plugins/specweave-kafka/lib/utils/partitioning.ts +473 -0
  377. package/plugins/specweave-kafka/lib/utils/sizing.js +221 -0
  378. package/plugins/specweave-kafka/lib/utils/sizing.ts +374 -0
  379. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-broker-metrics.json +628 -0
  380. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-cluster-overview.json +564 -0
  381. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-consumer-lag.json +509 -0
  382. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-jvm-metrics.json +674 -0
  383. package/plugins/specweave-kafka/monitoring/grafana/dashboards/kafka-topic-metrics.json +578 -0
  384. package/plugins/specweave-kafka/monitoring/grafana/provisioning/dashboards/kafka.yml +17 -0
  385. package/plugins/specweave-kafka/monitoring/grafana/provisioning/datasources/prometheus.yml +17 -0
  386. package/plugins/specweave-kafka/monitoring/prometheus/kafka-alerts.yml +415 -0
  387. package/plugins/specweave-kafka/monitoring/prometheus/kafka-jmx-exporter.yml +256 -0
  388. package/plugins/specweave-kafka/package.json +41 -0
  389. package/plugins/specweave-kafka/skills/kafka-architecture/SKILL.md +647 -0
  390. package/plugins/specweave-kafka/skills/kafka-cli-tools/SKILL.md +433 -0
  391. package/plugins/specweave-kafka/skills/kafka-iac-deployment/SKILL.md +449 -0
  392. package/plugins/specweave-kafka/skills/kafka-kubernetes/SKILL.md +667 -0
  393. package/plugins/specweave-kafka/skills/kafka-mcp-integration/SKILL.md +273 -0
  394. package/plugins/specweave-kafka/skills/kafka-observability/SKILL.md +576 -0
  395. package/plugins/specweave-kafka/templates/config/broker-production.properties +254 -0
  396. package/plugins/specweave-kafka/templates/config/consumer-low-latency.properties +112 -0
  397. package/plugins/specweave-kafka/templates/config/producer-high-throughput.properties +120 -0
  398. package/plugins/specweave-kafka/templates/migration/mirrormaker2-config.properties +234 -0
  399. package/plugins/specweave-kafka/templates/monitoring/grafana/multi-cluster-dashboard.json +686 -0
  400. package/plugins/specweave-kafka/terraform/apache-kafka/main.tf +347 -0
  401. package/plugins/specweave-kafka/terraform/apache-kafka/outputs.tf +107 -0
  402. package/plugins/specweave-kafka/terraform/apache-kafka/templates/kafka-broker-init.sh.tpl +216 -0
  403. package/plugins/specweave-kafka/terraform/apache-kafka/variables.tf +156 -0
  404. package/plugins/specweave-kafka/terraform/aws-msk/main.tf +362 -0
  405. package/plugins/specweave-kafka/terraform/aws-msk/outputs.tf +93 -0
  406. package/plugins/specweave-kafka/terraform/aws-msk/templates/server.properties.tpl +32 -0
  407. package/plugins/specweave-kafka/terraform/aws-msk/variables.tf +235 -0
  408. package/plugins/specweave-kafka/terraform/azure-event-hubs/main.tf +281 -0
  409. package/plugins/specweave-kafka/terraform/azure-event-hubs/outputs.tf +118 -0
  410. package/plugins/specweave-kafka/terraform/azure-event-hubs/variables.tf +148 -0
  411. package/plugins/specweave-kafka/tsconfig.json +21 -0
  412. package/plugins/specweave-kafka-streams/.claude-plugin/plugin.json +23 -0
  413. package/plugins/specweave-kafka-streams/README.md +310 -0
  414. package/plugins/specweave-kafka-streams/skills/kafka-streams-topology/SKILL.md +539 -0
  415. package/plugins/specweave-n8n/.claude-plugin/plugin.json +22 -0
  416. package/plugins/specweave-n8n/README.md +354 -0
  417. package/plugins/specweave-n8n/skills/n8n-kafka-workflows/SKILL.md +504 -0
  418. package/plugins/specweave-release/commands/specweave-release-platform.md +1 -1
  419. package/plugins/specweave-release/hooks/post-task-completion.sh +2 -2
  420. package/src/templates/AGENTS.md.template +601 -7
  421. package/src/templates/CLAUDE.md.template +188 -88
  422. package/plugins/specweave-ado/commands/specweave-ado-sync-spec.md +0 -255
  423. package/plugins/specweave-github/commands/specweave-github-sync-epic.md +0 -248
  424. package/plugins/specweave-github/commands/specweave-github-sync-from.md +0 -147
  425. package/plugins/specweave-github/commands/specweave-github-sync-spec.md +0 -208
  426. package/plugins/specweave-github/commands/specweave-github-sync-tasks.md +0 -530
  427. package/plugins/specweave-jira/commands/specweave-jira-sync-epic.md +0 -267
  428. package/plugins/specweave-jira/commands/specweave-jira-sync-spec.md +0 -240
@@ -0,0 +1,568 @@
1
+ /**
2
+ * GitHub Feature Sync - Universal Hierarchy Implementation
3
+ *
4
+ * Architecture (CORRECT):
5
+ * - Feature (FS-033) → GitHub Milestone (Container)
6
+ * - User Story (US-001, US-002, etc.) → GitHub Issue (Trackable item)
7
+ * - Tasks (T-001, T-002, etc.) → Checkboxes in User Story issue body
8
+ *
9
+ * This implements the TRUE Universal Hierarchy architecture for GitHub.
10
+ *
11
+ * Key Differences from old github-epic-sync.ts:
12
+ * - ❌ OLD: Feature/Increment → GitHub Issue (WRONG!)
13
+ * - ✅ NEW: User Story → GitHub Issue (CORRECT!)
14
+ * - ✅ Creates ONE issue PER user story file (not one per increment)
15
+ * - ✅ Reads us-*.md files from specs/{project}/FS-XXX/
16
+ */
17
+
18
+ import { readdir, readFile, writeFile } from 'fs/promises';
19
+ import { existsSync } from 'fs';
20
+ import * as path from 'path';
21
+ import * as yaml from 'yaml';
22
+ import { GitHubClientV2 } from './github-client-v2.js';
23
+ import { UserStoryIssueBuilder } from './user-story-issue-builder.js';
24
+ import { CompletionCalculator } from './completion-calculator.js';
25
+ import { execFileNoThrow } from '../../../src/utils/execFileNoThrow.js';
26
+
27
+ interface FeatureFrontmatter {
28
+ id: string;
29
+ title: string;
30
+ type: 'feature' | 'epic';
31
+ status: 'complete' | 'active' | 'planning' | 'archived';
32
+ projects?: string[];
33
+ created: string;
34
+ last_updated: string;
35
+ external_tools?: {
36
+ github?: {
37
+ type: 'milestone';
38
+ id: number | null;
39
+ url: string | null;
40
+ };
41
+ };
42
+ }
43
+
44
+ interface UserStoryInfo {
45
+ id: string; // e.g., "US-001"
46
+ title: string;
47
+ filePath: string;
48
+ project: string;
49
+ status: string;
50
+ existingIssue?: number | null;
51
+ }
52
+
53
+ export class GitHubFeatureSync {
54
+ private client: GitHubClientV2;
55
+ private specsDir: string;
56
+ private projectRoot: string;
57
+ private calculator: CompletionCalculator;
58
+
59
+ constructor(client: GitHubClientV2, specsDir: string, projectRoot: string) {
60
+ this.client = client;
61
+ this.specsDir = specsDir;
62
+ this.projectRoot = projectRoot;
63
+ this.calculator = new CompletionCalculator(projectRoot);
64
+ }
65
+
66
+ /**
67
+ * Sync Feature folder to GitHub (Milestone + User Story Issues)
68
+ *
69
+ * Process:
70
+ * 1. Create/update GitHub Milestone for Feature
71
+ * 2. Find all us-*.md files across all projects
72
+ * 3. Create/update GitHub Issue for EACH user story
73
+ * 4. Update frontmatter with GitHub issue links
74
+ */
75
+ async syncFeatureToGitHub(featureId: string): Promise<{
76
+ milestoneNumber: number;
77
+ milestoneUrl: string;
78
+ issuesCreated: number;
79
+ issuesUpdated: number;
80
+ userStoriesProcessed: number;
81
+ }> {
82
+ console.log(`\n🔄 Syncing Feature ${featureId} to GitHub...`);
83
+
84
+ // 1. Load Feature FEATURE.md
85
+ const featureFolder = await this.findFeatureFolder(featureId);
86
+ if (!featureFolder) {
87
+ throw new Error(`Feature ${featureId} not found in ${this.specsDir}`);
88
+ }
89
+
90
+ const featurePath = path.join(featureFolder, 'FEATURE.md');
91
+ const featureData = await this.parseFeatureMd(featurePath);
92
+
93
+ console.log(` 📦 Feature: ${featureData.title}`);
94
+ console.log(` 📊 Status: ${featureData.status}`);
95
+
96
+ // 2. Create or update GitHub Milestone
97
+ let milestoneNumber = featureData.external_tools?.github?.id;
98
+ let milestoneUrl = featureData.external_tools?.github?.url;
99
+
100
+ if (!milestoneNumber) {
101
+ console.log(` 🚀 Creating GitHub Milestone...`);
102
+ const milestone = await this.createMilestone(featureData);
103
+ milestoneNumber = milestone.number;
104
+ milestoneUrl = milestone.url;
105
+ console.log(` ✅ Created Milestone #${milestoneNumber}`);
106
+
107
+ // Update FEATURE.md with Milestone ID
108
+ await this.updateFeatureMd(featurePath, {
109
+ type: 'milestone',
110
+ id: milestoneNumber,
111
+ url: milestoneUrl,
112
+ });
113
+ } else {
114
+ console.log(` ♻️ Using existing Milestone #${milestoneNumber}`);
115
+ milestoneUrl = featureData.external_tools?.github?.url || milestoneUrl;
116
+ }
117
+
118
+ // 3. Find all User Story files across all projects
119
+ const userStories = await this.findUserStories(featureId);
120
+ console.log(`\n 📝 Found ${userStories.length} User Stories to sync...`);
121
+
122
+ // 4. Sync each User Story as GitHub Issue
123
+ let issuesCreated = 0;
124
+ let issuesUpdated = 0;
125
+
126
+ for (const userStory of userStories) {
127
+ console.log(`\n 🔹 Processing ${userStory.id}: ${userStory.title}`);
128
+
129
+ // Build issue content using UserStoryIssueBuilder
130
+ const repoInfo = {
131
+ owner: this.client.getOwner(),
132
+ repo: this.client.getRepo(),
133
+ branch: 'develop' // TODO: detect from git
134
+ };
135
+
136
+ const builder = new UserStoryIssueBuilder(
137
+ userStory.filePath,
138
+ this.projectRoot,
139
+ featureId,
140
+ repoInfo
141
+ );
142
+
143
+ const issueContent = await builder.buildIssueBody();
144
+
145
+ // ✅ FIX: Add status to issue content for sync
146
+ issueContent.status = userStory.status;
147
+
148
+ // ✅ TRIPLE IDEMPOTENCY CHECK
149
+ // This ensures 100% safety when running sync multiple times
150
+
151
+ // Check 1: User Story frontmatter has issue number
152
+ if (userStory.existingIssue) {
153
+ console.log(` ♻️ Issue #${userStory.existingIssue} exists in frontmatter`);
154
+
155
+ try {
156
+ // Verify issue still exists on GitHub
157
+ await this.client.getIssue(userStory.existingIssue);
158
+
159
+ // Issue exists, update it with verification
160
+ await this.updateUserStoryIssue(userStory.existingIssue, issueContent, userStory.filePath);
161
+ issuesUpdated++;
162
+ console.log(` ✅ Updated Issue #${userStory.existingIssue}`);
163
+ continue;
164
+ } catch (err) {
165
+ // Issue deleted on GitHub, fall through to create new
166
+ console.log(` ⚠️ Issue #${userStory.existingIssue} deleted on GitHub, creating new`);
167
+ }
168
+ }
169
+
170
+ // Check 2: Search GitHub for issue by title
171
+ const existingByTitle = await this.client.searchIssueByTitle(issueContent.title);
172
+ if (existingByTitle) {
173
+ console.log(` ♻️ Found existing issue by title: #${existingByTitle.number}`);
174
+
175
+ // Link it in frontmatter
176
+ await this.updateUserStoryFrontmatter(userStory.filePath, existingByTitle.number);
177
+
178
+ // Update content with verification
179
+ await this.updateUserStoryIssue(existingByTitle.number, issueContent, userStory.filePath);
180
+ issuesUpdated++;
181
+ console.log(` ✅ Linked and updated Issue #${existingByTitle.number}`);
182
+ continue;
183
+ }
184
+
185
+ // Check 3: No existing issue found, create new
186
+ console.log(` 🚀 Creating new issue: ${issueContent.title}`);
187
+ const milestoneTitle = `${featureData.id}: ${featureData.title}`;
188
+ const issueNumber = await this.createUserStoryIssue(
189
+ issueContent,
190
+ milestoneTitle,
191
+ userStory.filePath
192
+ );
193
+ issuesCreated++;
194
+ console.log(` ✅ Created Issue #${issueNumber}`);
195
+
196
+ // Update User Story frontmatter
197
+ await this.updateUserStoryFrontmatter(userStory.filePath, issueNumber);
198
+ }
199
+
200
+ console.log(`\n✅ Feature sync complete!`);
201
+ console.log(` Milestone: ${milestoneUrl}`);
202
+ console.log(` User Stories: ${userStories.length}`);
203
+ console.log(` Issues created: ${issuesCreated}`);
204
+ console.log(` Issues updated: ${issuesUpdated}`);
205
+
206
+ return {
207
+ milestoneNumber: milestoneNumber!,
208
+ milestoneUrl: milestoneUrl!,
209
+ issuesCreated,
210
+ issuesUpdated,
211
+ userStoriesProcessed: userStories.length,
212
+ };
213
+ }
214
+
215
+ /**
216
+ * Find Feature folder in specs directory
217
+ */
218
+ private async findFeatureFolder(featureId: string): Promise<string | null> {
219
+ // Check _features folder first
220
+ const featuresFolder = path.join(this.specsDir, '_features', featureId);
221
+ if (existsSync(featuresFolder)) {
222
+ return featuresFolder;
223
+ }
224
+
225
+ return null;
226
+ }
227
+
228
+ /**
229
+ * Parse FEATURE.md frontmatter
230
+ */
231
+ private async parseFeatureMd(featurePath: string): Promise<FeatureFrontmatter> {
232
+ const content = await readFile(featurePath, 'utf-8');
233
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
234
+
235
+ if (!match) {
236
+ throw new Error(`${featurePath}: Missing YAML frontmatter`);
237
+ }
238
+
239
+ return yaml.parse(match[1]) as FeatureFrontmatter;
240
+ }
241
+
242
+ /**
243
+ * Find all User Story files for this feature across all projects
244
+ */
245
+ private async findUserStories(featureId: string): Promise<UserStoryInfo[]> {
246
+ const userStories: UserStoryInfo[] = [];
247
+
248
+ // Find all project folders
249
+ const projectFolders = await this.findProjectFolders();
250
+
251
+ for (const projectFolder of projectFolders) {
252
+ const featureSpecsFolder = path.join(projectFolder, featureId);
253
+
254
+ if (!existsSync(featureSpecsFolder)) {
255
+ continue; // Feature not present in this project
256
+ }
257
+
258
+ // Read all us-*.md files
259
+ const files = await readdir(featureSpecsFolder);
260
+ const usFiles = files.filter((f) => f.startsWith('us-') && f.endsWith('.md'));
261
+
262
+ for (const file of usFiles.sort()) {
263
+ const filePath = path.join(featureSpecsFolder, file);
264
+ const content = await readFile(filePath, 'utf-8');
265
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
266
+
267
+ if (!match) {
268
+ console.warn(` ⚠️ ${file}: Missing frontmatter, skipping`);
269
+ continue;
270
+ }
271
+
272
+ const frontmatter = yaml.parse(match[1]);
273
+ const projectName = path.basename(projectFolder);
274
+
275
+ userStories.push({
276
+ id: frontmatter.id || file.match(/us-(\d+)/)?.[0]?.toUpperCase() || 'UNKNOWN',
277
+ title: frontmatter.title || 'Untitled User Story',
278
+ filePath,
279
+ project: projectName,
280
+ status: frontmatter.status || 'not-started',
281
+ existingIssue: frontmatter.external?.github?.issue || null,
282
+ });
283
+ }
284
+ }
285
+
286
+ return userStories;
287
+ }
288
+
289
+ /**
290
+ * Find all project folders (default, backend, frontend, etc.)
291
+ */
292
+ private async findProjectFolders(): Promise<string[]> {
293
+ const folders: string[] = [];
294
+ const specsRoot = this.specsDir;
295
+
296
+ // Read all directories in specs root
297
+ const entries = await readdir(specsRoot, { withFileTypes: true });
298
+
299
+ for (const entry of entries) {
300
+ if (entry.isDirectory() && !entry.name.startsWith('_')) {
301
+ folders.push(path.join(specsRoot, entry.name));
302
+ }
303
+ }
304
+
305
+ return folders;
306
+ }
307
+
308
+ /**
309
+ * Create GitHub Milestone for Feature
310
+ */
311
+ private async createMilestone(featureData: FeatureFrontmatter): Promise<{
312
+ number: number;
313
+ url: string;
314
+ }> {
315
+ const title = `${featureData.id}: ${featureData.title}`;
316
+ const description = `Feature ${featureData.id}\n\nStatus: ${featureData.status}\nCreated: ${featureData.created}`;
317
+
318
+ const result = await execFileNoThrow('gh', [
319
+ 'api',
320
+ 'repos/:owner/:repo/milestones',
321
+ '-X',
322
+ 'POST',
323
+ '-f',
324
+ `title=${title}`,
325
+ '-f',
326
+ `description=${description}`,
327
+ '-f',
328
+ 'state=open',
329
+ ]);
330
+
331
+ if (result.exitCode !== 0) {
332
+ throw new Error(`Failed to create Milestone: ${result.stderr || result.stdout}`);
333
+ }
334
+
335
+ const milestone = JSON.parse(result.stdout);
336
+ return {
337
+ number: milestone.number,
338
+ url: milestone.html_url,
339
+ };
340
+ }
341
+
342
+ /**
343
+ * Create GitHub Issue for User Story with AC/Task Verification
344
+ *
345
+ * ✅ VERIFICATION GATE FIX:
346
+ * - Verifies actual completion before closing
347
+ * - Prevents premature closure on creation
348
+ */
349
+ private async createUserStoryIssue(
350
+ issueContent: {
351
+ title: string;
352
+ body: string;
353
+ labels: string[];
354
+ status?: string;
355
+ },
356
+ milestoneTitle: string,
357
+ userStoryPath: string
358
+ ): Promise<number> {
359
+ // Step 1: Create issue (always open initially - gh CLI limitation)
360
+ const result = await execFileNoThrow('gh', [
361
+ 'issue',
362
+ 'create',
363
+ '--title',
364
+ issueContent.title,
365
+ '--body',
366
+ issueContent.body,
367
+ '--milestone',
368
+ milestoneTitle,
369
+ ...issueContent.labels.flatMap((label) => ['--label', label]),
370
+ ]);
371
+
372
+ if (result.exitCode !== 0) {
373
+ throw new Error(`Failed to create GitHub Issue: ${result.stderr || result.stdout}`);
374
+ }
375
+
376
+ // Parse issue number from output
377
+ // Format: "https://github.com/owner/repo/issues/123"
378
+ const match = result.stdout.match(/issues\/(\d+)/);
379
+ if (!match) {
380
+ throw new Error(`Failed to parse issue number from: ${result.stdout}`);
381
+ }
382
+
383
+ const issueNumber = parseInt(match[1], 10);
384
+
385
+ // Step 2: VERIFICATION GATE - Close only if ACs/tasks verified
386
+ const completion = await this.calculator.calculateCompletion(userStoryPath);
387
+
388
+ if (completion.overallComplete) {
389
+ // ✅ SAFE TO CLOSE - All ACs and tasks verified [x]
390
+ await execFileNoThrow('gh', [
391
+ 'issue',
392
+ 'close',
393
+ issueNumber.toString(),
394
+ '--comment',
395
+ this.calculator.buildCompletionComment(completion),
396
+ ]);
397
+ console.log(
398
+ ` ✅ Created and verified complete: ${completion.acsCompleted}/${completion.acsTotal} ACs, ${completion.tasksCompleted}/${completion.tasksTotal} tasks`
399
+ );
400
+ } else {
401
+ // ⚠️ INCOMPLETE - Leave open with progress comment
402
+ await execFileNoThrow('gh', [
403
+ 'issue',
404
+ 'comment',
405
+ issueNumber.toString(),
406
+ '--body',
407
+ this.calculator.buildProgressComment(completion),
408
+ ]);
409
+ console.log(
410
+ ` 📊 Created: ${completion.acsPercentage.toFixed(0)}% ACs, ${completion.tasksPercentage.toFixed(0)}% tasks`
411
+ );
412
+ }
413
+
414
+ return issueNumber;
415
+ }
416
+
417
+ /**
418
+ * Update existing GitHub Issue for User Story with AC/Task Verification
419
+ *
420
+ * ✅ VERIFICATION GATE FIX:
421
+ * - OLD: Closed based on frontmatter `status: complete`
422
+ * - NEW: Closes ONLY if all ACs and tasks are [x]
423
+ *
424
+ * This prevents Issue #574 type bugs (premature closure)
425
+ */
426
+ private async updateUserStoryIssue(
427
+ issueNumber: number,
428
+ issueContent: {
429
+ title: string;
430
+ body: string;
431
+ labels: string[];
432
+ status?: string;
433
+ },
434
+ userStoryPath: string
435
+ ): Promise<void> {
436
+ // Update issue body
437
+ await execFileNoThrow('gh', [
438
+ 'issue',
439
+ 'edit',
440
+ issueNumber.toString(),
441
+ '--title',
442
+ issueContent.title,
443
+ '--body',
444
+ issueContent.body,
445
+ ]);
446
+
447
+ // ✅ VERIFICATION GATE: Calculate ACTUAL completion from checkboxes
448
+ const completion = await this.calculator.calculateCompletion(userStoryPath);
449
+
450
+ // Get current issue state
451
+ const issueData = await this.client.getIssue(issueNumber);
452
+ const currentlyClosed = issueData.state === 'closed';
453
+
454
+ // DECISION LOGIC: Close/Reopen/Update based on VERIFIED completion
455
+ if (completion.overallComplete) {
456
+ // ✅ SAFE TO CLOSE - All ACs and tasks verified [x]
457
+ if (!currentlyClosed) {
458
+ await execFileNoThrow('gh', [
459
+ 'issue',
460
+ 'close',
461
+ issueNumber.toString(),
462
+ '--comment',
463
+ this.calculator.buildCompletionComment(completion),
464
+ ]);
465
+ console.log(
466
+ ` ✅ Verified complete: ${completion.acsCompleted}/${completion.acsTotal} ACs, ${completion.tasksCompleted}/${completion.tasksTotal} tasks`
467
+ );
468
+ }
469
+ } else {
470
+ // ⚠️ INCOMPLETE - Keep open or reopen if needed
471
+ if (currentlyClosed) {
472
+ // Issue was closed prematurely - REOPEN
473
+ await execFileNoThrow('gh', [
474
+ 'issue',
475
+ 'reopen',
476
+ issueNumber.toString(),
477
+ '--comment',
478
+ this.calculator.buildReopenComment(completion, 'Work verification failed'),
479
+ ]);
480
+ console.log(
481
+ ` ⚠️ Reopened: ${completion.blockingAcs.length + completion.blockingTasks.length} items incomplete`
482
+ );
483
+ } else {
484
+ // Update progress comment
485
+ await execFileNoThrow('gh', [
486
+ 'issue',
487
+ 'comment',
488
+ issueNumber.toString(),
489
+ '--body',
490
+ this.calculator.buildProgressComment(completion),
491
+ ]);
492
+ console.log(
493
+ ` 📊 Progress: ${completion.acsPercentage.toFixed(0)}% ACs, ${completion.tasksPercentage.toFixed(0)}% tasks`
494
+ );
495
+ }
496
+ }
497
+
498
+ // Note: Labels are not updated to avoid overwriting manually added labels
499
+ }
500
+
501
+ /**
502
+ * Update FEATURE.md with GitHub Milestone link
503
+ */
504
+ private async updateFeatureMd(
505
+ featurePath: string,
506
+ milestone: {
507
+ type: 'milestone';
508
+ id: number;
509
+ url: string;
510
+ }
511
+ ): Promise<void> {
512
+ const content = await readFile(featurePath, 'utf-8');
513
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
514
+
515
+ if (!match) {
516
+ throw new Error(`${featurePath}: Missing YAML frontmatter`);
517
+ }
518
+
519
+ const frontmatter = yaml.parse(match[1]);
520
+
521
+ // Update external_tools.github
522
+ if (!frontmatter.external_tools) {
523
+ frontmatter.external_tools = {};
524
+ }
525
+ frontmatter.external_tools.github = milestone;
526
+
527
+ // Rebuild content
528
+ const newFrontmatter = yaml.stringify(frontmatter);
529
+ const bodyContent = content.slice(match[0].length);
530
+ const newContent = `---\n${newFrontmatter}---${bodyContent}`;
531
+
532
+ await writeFile(featurePath, newContent, 'utf-8');
533
+ }
534
+
535
+ /**
536
+ * Update User Story frontmatter with GitHub issue link
537
+ */
538
+ private async updateUserStoryFrontmatter(
539
+ userStoryPath: string,
540
+ issueNumber: number
541
+ ): Promise<void> {
542
+ const content = await readFile(userStoryPath, 'utf-8');
543
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
544
+
545
+ if (!match) {
546
+ throw new Error(`${userStoryPath}: Missing YAML frontmatter`);
547
+ }
548
+
549
+ const frontmatter = yaml.parse(match[1]);
550
+
551
+ // Update external.github
552
+ if (!frontmatter.external) {
553
+ frontmatter.external = {};
554
+ }
555
+ if (!frontmatter.external.github) {
556
+ frontmatter.external.github = {};
557
+ }
558
+ frontmatter.external.github.issue = issueNumber;
559
+ frontmatter.external.github.url = `https://github.com/anton-abyzov/specweave/issues/${issueNumber}`;
560
+
561
+ // Rebuild content
562
+ const newFrontmatter = yaml.stringify(frontmatter);
563
+ const bodyContent = content.slice(match[0].length);
564
+ const newContent = `---\n${newFrontmatter}---${bodyContent}`;
565
+
566
+ await writeFile(userStoryPath, newContent, 'utf-8');
567
+ }
568
+ }
@@ -6,6 +6,7 @@ import {
6
6
  hasExternalLink,
7
7
  updateSpecWithExternalLink
8
8
  } from "../../../src/core/spec-content-sync.js";
9
+ import { ProgressCommentBuilder } from "./progress-comment-builder.js";
9
10
  import path from "path";
10
11
  import fs from "fs/promises";
11
12
  async function getGitHubRepoForProject(project, specPath) {
@@ -167,27 +168,35 @@ async function updateGitHubIssue(client, spec, issueNumber, options) {
167
168
  console.log(` - ${change}`);
168
169
  }
169
170
  }
170
- const newTitle = `[${spec.identifier.compact}] ${spec.title}`;
171
- const newBody = buildExternalDescription(spec);
172
171
  if (dryRun) {
173
- console.log("\n\u{1F50D} Dry run - would update issue:");
174
- console.log(` Title: ${newTitle}`);
175
- console.log(` Body:
176
- ${newBody}`);
172
+ console.log("\n\u{1F50D} Dry run - would post progress comment");
177
173
  return {
178
174
  success: true,
179
- action: "updated",
175
+ action: "updated-via-comment",
180
176
  externalId: issueNumber.toString(),
181
177
  externalUrl: issue.html_url
182
178
  };
183
179
  }
184
- await client.updateIssueBody(issueNumber, newBody);
180
+ const labels = [
181
+ "specweave",
182
+ "spec",
183
+ spec.project,
184
+ spec.metadata.priority || "P2"
185
+ ].filter(Boolean);
186
+ await client.addLabels(issueNumber, labels);
187
+ await postProgressComment(
188
+ client,
189
+ specPath,
190
+ issueNumber,
191
+ spec,
192
+ verbose
193
+ );
185
194
  if (verbose) {
186
- console.log(`\u2705 Updated issue #${issueNumber}`);
195
+ console.log(`\u2705 Posted progress comment to issue #${issueNumber}`);
187
196
  }
188
197
  return {
189
198
  success: true,
190
- action: "updated",
199
+ action: "updated-via-comment",
191
200
  externalId: issueNumber.toString(),
192
201
  externalUrl: issue.html_url
193
202
  };
@@ -199,6 +208,27 @@ ${newBody}`);
199
208
  };
200
209
  }
201
210
  }
211
+ async function postProgressComment(client, specPath, issueNumber, spec, verbose = false) {
212
+ try {
213
+ let incrementId = "unknown";
214
+ const incrementMatch = specPath.match(/increments\/([^/]+)/);
215
+ if (incrementMatch) {
216
+ incrementId = incrementMatch[1];
217
+ } else {
218
+ incrementId = spec.identifier.compact;
219
+ }
220
+ const builder = new ProgressCommentBuilder(specPath);
221
+ const comment = await builder.buildProgressComment(incrementId);
222
+ await client.addComment(issueNumber, comment);
223
+ if (verbose) {
224
+ console.log(` \u{1F4CA} Progress comment posted (${comment.length} chars)`);
225
+ }
226
+ } catch (error) {
227
+ if (verbose) {
228
+ console.error(` \u26A0\uFE0F Failed to post progress comment: ${error.message}`);
229
+ }
230
+ }
231
+ }
202
232
  function countUserStoriesInBody(body) {
203
233
  const matches = body.match(/###\s+US-\d+:/g);
204
234
  return matches ? matches.length : 0;