@pennyfarthing/core 6.6.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 (599) hide show
  1. package/README.md +293 -0
  2. package/package.json +58 -0
  3. package/packages/core/bin/pennyfarthing.js +14 -0
  4. package/packages/core/dist/bmad/context-reader.d.ts +71 -0
  5. package/packages/core/dist/bmad/context-reader.d.ts.map +1 -0
  6. package/packages/core/dist/bmad/context-reader.js +369 -0
  7. package/packages/core/dist/bmad/context-reader.js.map +1 -0
  8. package/packages/core/dist/bmad/context-reader.test.d.ts +71 -0
  9. package/packages/core/dist/bmad/context-reader.test.d.ts.map +1 -0
  10. package/packages/core/dist/bmad/context-reader.test.js +878 -0
  11. package/packages/core/dist/bmad/context-reader.test.js.map +1 -0
  12. package/packages/core/dist/bmad/epics-parser.d.ts +61 -0
  13. package/packages/core/dist/bmad/epics-parser.d.ts.map +1 -0
  14. package/packages/core/dist/bmad/epics-parser.js +331 -0
  15. package/packages/core/dist/bmad/epics-parser.js.map +1 -0
  16. package/packages/core/dist/bmad/epics-parser.test.d.ts +7 -0
  17. package/packages/core/dist/bmad/epics-parser.test.d.ts.map +1 -0
  18. package/packages/core/dist/bmad/epics-parser.test.js +449 -0
  19. package/packages/core/dist/bmad/epics-parser.test.js.map +1 -0
  20. package/packages/core/dist/bmad/index.d.ts +11 -0
  21. package/packages/core/dist/bmad/index.d.ts.map +1 -0
  22. package/packages/core/dist/bmad/index.js +24 -0
  23. package/packages/core/dist/bmad/index.js.map +1 -0
  24. package/packages/core/dist/bmad/status-sync.d.ts +173 -0
  25. package/packages/core/dist/bmad/status-sync.d.ts.map +1 -0
  26. package/packages/core/dist/bmad/status-sync.js +463 -0
  27. package/packages/core/dist/bmad/status-sync.js.map +1 -0
  28. package/packages/core/dist/bmad/status-sync.test.d.ts +7 -0
  29. package/packages/core/dist/bmad/status-sync.test.d.ts.map +1 -0
  30. package/packages/core/dist/bmad/status-sync.test.js +702 -0
  31. package/packages/core/dist/bmad/status-sync.test.js.map +1 -0
  32. package/packages/core/dist/bmad/story-exporter.d.ts +55 -0
  33. package/packages/core/dist/bmad/story-exporter.d.ts.map +1 -0
  34. package/packages/core/dist/bmad/story-exporter.js +170 -0
  35. package/packages/core/dist/bmad/story-exporter.js.map +1 -0
  36. package/packages/core/dist/bmad/story-exporter.test.d.ts +51 -0
  37. package/packages/core/dist/bmad/story-exporter.test.d.ts.map +1 -0
  38. package/packages/core/dist/bmad/story-exporter.test.js +603 -0
  39. package/packages/core/dist/bmad/story-exporter.test.js.map +1 -0
  40. package/packages/core/dist/bmad/story-parser.d.ts +44 -0
  41. package/packages/core/dist/bmad/story-parser.d.ts.map +1 -0
  42. package/packages/core/dist/bmad/story-parser.js +307 -0
  43. package/packages/core/dist/bmad/story-parser.js.map +1 -0
  44. package/packages/core/dist/bmad/story-parser.test.d.ts +44 -0
  45. package/packages/core/dist/bmad/story-parser.test.d.ts.map +1 -0
  46. package/packages/core/dist/bmad/story-parser.test.js +693 -0
  47. package/packages/core/dist/bmad/story-parser.test.js.map +1 -0
  48. package/packages/core/dist/cli/commands/command.d.ts +28 -0
  49. package/packages/core/dist/cli/commands/command.d.ts.map +1 -0
  50. package/packages/core/dist/cli/commands/command.js +399 -0
  51. package/packages/core/dist/cli/commands/command.js.map +1 -0
  52. package/packages/core/dist/cli/commands/cyclist.d.ts +46 -0
  53. package/packages/core/dist/cli/commands/cyclist.d.ts.map +1 -0
  54. package/packages/core/dist/cli/commands/cyclist.js +191 -0
  55. package/packages/core/dist/cli/commands/cyclist.js.map +1 -0
  56. package/packages/core/dist/cli/commands/cyclist.test.d.ts +13 -0
  57. package/packages/core/dist/cli/commands/cyclist.test.d.ts.map +1 -0
  58. package/packages/core/dist/cli/commands/cyclist.test.js +243 -0
  59. package/packages/core/dist/cli/commands/cyclist.test.js.map +1 -0
  60. package/packages/core/dist/cli/commands/doctor.d.ts +9 -0
  61. package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -0
  62. package/packages/core/dist/cli/commands/doctor.js +652 -0
  63. package/packages/core/dist/cli/commands/doctor.js.map +1 -0
  64. package/packages/core/dist/cli/commands/init.d.ts +8 -0
  65. package/packages/core/dist/cli/commands/init.d.ts.map +1 -0
  66. package/packages/core/dist/cli/commands/init.js +524 -0
  67. package/packages/core/dist/cli/commands/init.js.map +1 -0
  68. package/packages/core/dist/cli/commands/skill.d.ts +28 -0
  69. package/packages/core/dist/cli/commands/skill.d.ts.map +1 -0
  70. package/packages/core/dist/cli/commands/skill.js +416 -0
  71. package/packages/core/dist/cli/commands/skill.js.map +1 -0
  72. package/packages/core/dist/cli/commands/theme.d.ts +21 -0
  73. package/packages/core/dist/cli/commands/theme.d.ts.map +1 -0
  74. package/packages/core/dist/cli/commands/theme.js +201 -0
  75. package/packages/core/dist/cli/commands/theme.js.map +1 -0
  76. package/packages/core/dist/cli/commands/uninstall.d.ts +8 -0
  77. package/packages/core/dist/cli/commands/uninstall.d.ts.map +1 -0
  78. package/packages/core/dist/cli/commands/uninstall.js +237 -0
  79. package/packages/core/dist/cli/commands/uninstall.js.map +1 -0
  80. package/packages/core/dist/cli/commands/update.d.ts +9 -0
  81. package/packages/core/dist/cli/commands/update.d.ts.map +1 -0
  82. package/packages/core/dist/cli/commands/update.js +545 -0
  83. package/packages/core/dist/cli/commands/update.js.map +1 -0
  84. package/packages/core/dist/cli/commands/version.d.ts +2 -0
  85. package/packages/core/dist/cli/commands/version.d.ts.map +1 -0
  86. package/packages/core/dist/cli/commands/version.js +28 -0
  87. package/packages/core/dist/cli/commands/version.js.map +1 -0
  88. package/packages/core/dist/cli/customization.test.d.ts +12 -0
  89. package/packages/core/dist/cli/customization.test.d.ts.map +1 -0
  90. package/packages/core/dist/cli/customization.test.js +84 -0
  91. package/packages/core/dist/cli/customization.test.js.map +1 -0
  92. package/packages/core/dist/cli/cyclist-migration.test.d.ts +16 -0
  93. package/packages/core/dist/cli/cyclist-migration.test.d.ts.map +1 -0
  94. package/packages/core/dist/cli/cyclist-migration.test.js +224 -0
  95. package/packages/core/dist/cli/cyclist-migration.test.js.map +1 -0
  96. package/packages/core/dist/cli/index.d.ts +3 -0
  97. package/packages/core/dist/cli/index.d.ts.map +1 -0
  98. package/packages/core/dist/cli/index.js +174 -0
  99. package/packages/core/dist/cli/index.js.map +1 -0
  100. package/packages/core/dist/cli/ocean-profiles.test.d.ts +13 -0
  101. package/packages/core/dist/cli/ocean-profiles.test.d.ts.map +1 -0
  102. package/packages/core/dist/cli/ocean-profiles.test.js +134 -0
  103. package/packages/core/dist/cli/ocean-profiles.test.js.map +1 -0
  104. package/packages/core/dist/cli/theme-maker.test.d.ts +11 -0
  105. package/packages/core/dist/cli/theme-maker.test.d.ts.map +1 -0
  106. package/packages/core/dist/cli/theme-maker.test.js +356 -0
  107. package/packages/core/dist/cli/theme-maker.test.js.map +1 -0
  108. package/packages/core/dist/cli/utils/constants.d.ts +60 -0
  109. package/packages/core/dist/cli/utils/constants.d.ts.map +1 -0
  110. package/packages/core/dist/cli/utils/constants.js +52 -0
  111. package/packages/core/dist/cli/utils/constants.js.map +1 -0
  112. package/packages/core/dist/cli/utils/files.d.ts +71 -0
  113. package/packages/core/dist/cli/utils/files.d.ts.map +1 -0
  114. package/packages/core/dist/cli/utils/files.js +162 -0
  115. package/packages/core/dist/cli/utils/files.js.map +1 -0
  116. package/packages/core/dist/cli/utils/logger.d.ts +26 -0
  117. package/packages/core/dist/cli/utils/logger.d.ts.map +1 -0
  118. package/packages/core/dist/cli/utils/logger.js +88 -0
  119. package/packages/core/dist/cli/utils/logger.js.map +1 -0
  120. package/packages/core/dist/cli/utils/manifest.d.ts +47 -0
  121. package/packages/core/dist/cli/utils/manifest.d.ts.map +1 -0
  122. package/packages/core/dist/cli/utils/manifest.js +90 -0
  123. package/packages/core/dist/cli/utils/manifest.js.map +1 -0
  124. package/packages/core/dist/cli/utils/node-modules.d.ts +6 -0
  125. package/packages/core/dist/cli/utils/node-modules.d.ts.map +1 -0
  126. package/packages/core/dist/cli/utils/node-modules.js +22 -0
  127. package/packages/core/dist/cli/utils/node-modules.js.map +1 -0
  128. package/packages/core/dist/cli/utils/prompts.d.ts +34 -0
  129. package/packages/core/dist/cli/utils/prompts.d.ts.map +1 -0
  130. package/packages/core/dist/cli/utils/prompts.js +93 -0
  131. package/packages/core/dist/cli/utils/prompts.js.map +1 -0
  132. package/packages/core/dist/cli/utils/symlinks.d.ts +29 -0
  133. package/packages/core/dist/cli/utils/symlinks.d.ts.map +1 -0
  134. package/packages/core/dist/cli/utils/symlinks.js +181 -0
  135. package/packages/core/dist/cli/utils/symlinks.js.map +1 -0
  136. package/packages/core/dist/cli/utils/themes.d.ts +104 -0
  137. package/packages/core/dist/cli/utils/themes.d.ts.map +1 -0
  138. package/packages/core/dist/cli/utils/themes.js +393 -0
  139. package/packages/core/dist/cli/utils/themes.js.map +1 -0
  140. package/packages/core/dist/cli/utils/themes.test.d.ts +12 -0
  141. package/packages/core/dist/cli/utils/themes.test.d.ts.map +1 -0
  142. package/packages/core/dist/cli/utils/themes.test.js +144 -0
  143. package/packages/core/dist/cli/utils/themes.test.js.map +1 -0
  144. package/packages/core/dist/cli/utils/version.d.ts +10 -0
  145. package/packages/core/dist/cli/utils/version.d.ts.map +1 -0
  146. package/packages/core/dist/cli/utils/version.js +63 -0
  147. package/packages/core/dist/cli/utils/version.js.map +1 -0
  148. package/packages/core/dist/cli/workspace.test.d.ts +8 -0
  149. package/packages/core/dist/cli/workspace.test.d.ts.map +1 -0
  150. package/packages/core/dist/cli/workspace.test.js +154 -0
  151. package/packages/core/dist/cli/workspace.test.js.map +1 -0
  152. package/packages/core/dist/index.d.ts +6 -0
  153. package/packages/core/dist/index.d.ts.map +1 -0
  154. package/packages/core/dist/index.js +10 -0
  155. package/packages/core/dist/index.js.map +1 -0
  156. package/packages/core/dist/permissions/index.d.ts +9 -0
  157. package/packages/core/dist/permissions/index.d.ts.map +1 -0
  158. package/packages/core/dist/permissions/index.js +13 -0
  159. package/packages/core/dist/permissions/index.js.map +1 -0
  160. package/packages/core/dist/permissions/permission-schema.d.ts +89 -0
  161. package/packages/core/dist/permissions/permission-schema.d.ts.map +1 -0
  162. package/packages/core/dist/permissions/permission-schema.js +120 -0
  163. package/packages/core/dist/permissions/permission-schema.js.map +1 -0
  164. package/packages/core/dist/permissions/permission-schema.test.d.ts +40 -0
  165. package/packages/core/dist/permissions/permission-schema.test.d.ts.map +1 -0
  166. package/packages/core/dist/permissions/permission-schema.test.js +367 -0
  167. package/packages/core/dist/permissions/permission-schema.test.js.map +1 -0
  168. package/packages/core/dist/scripts/add-ocean-profiles.d.ts +9 -0
  169. package/packages/core/dist/scripts/add-ocean-profiles.d.ts.map +1 -0
  170. package/packages/core/dist/scripts/add-ocean-profiles.js +695 -0
  171. package/packages/core/dist/scripts/add-ocean-profiles.js.map +1 -0
  172. package/packages/core/dist/scripts/benchmark-integration.d.ts +182 -0
  173. package/packages/core/dist/scripts/benchmark-integration.d.ts.map +1 -0
  174. package/packages/core/dist/scripts/benchmark-integration.js +691 -0
  175. package/packages/core/dist/scripts/benchmark-integration.js.map +1 -0
  176. package/packages/core/dist/scripts/benchmark-integration.test.d.ts +13 -0
  177. package/packages/core/dist/scripts/benchmark-integration.test.d.ts.map +1 -0
  178. package/packages/core/dist/scripts/benchmark-integration.test.js +680 -0
  179. package/packages/core/dist/scripts/benchmark-integration.test.js.map +1 -0
  180. package/packages/core/dist/scripts/debugging-scenarios.test.d.ts +18 -0
  181. package/packages/core/dist/scripts/debugging-scenarios.test.d.ts.map +1 -0
  182. package/packages/core/dist/scripts/debugging-scenarios.test.js +317 -0
  183. package/packages/core/dist/scripts/debugging-scenarios.test.js.map +1 -0
  184. package/packages/core/dist/scripts/generate-all-faces.d.ts +10 -0
  185. package/packages/core/dist/scripts/generate-all-faces.d.ts.map +1 -0
  186. package/packages/core/dist/scripts/generate-all-faces.js +256 -0
  187. package/packages/core/dist/scripts/generate-all-faces.js.map +1 -0
  188. package/packages/core/dist/scripts/generate-all-faces.test.d.ts +17 -0
  189. package/packages/core/dist/scripts/generate-all-faces.test.d.ts.map +1 -0
  190. package/packages/core/dist/scripts/generate-all-faces.test.js +372 -0
  191. package/packages/core/dist/scripts/generate-all-faces.test.js.map +1 -0
  192. package/packages/core/dist/scripts/generate-all-spiders.d.ts +10 -0
  193. package/packages/core/dist/scripts/generate-all-spiders.d.ts.map +1 -0
  194. package/packages/core/dist/scripts/generate-all-spiders.js +306 -0
  195. package/packages/core/dist/scripts/generate-all-spiders.js.map +1 -0
  196. package/packages/core/dist/scripts/generate-ascii-face.d.ts +52 -0
  197. package/packages/core/dist/scripts/generate-ascii-face.d.ts.map +1 -0
  198. package/packages/core/dist/scripts/generate-ascii-face.js +155 -0
  199. package/packages/core/dist/scripts/generate-ascii-face.js.map +1 -0
  200. package/packages/core/dist/scripts/generate-face.d.ts +52 -0
  201. package/packages/core/dist/scripts/generate-face.d.ts.map +1 -0
  202. package/packages/core/dist/scripts/generate-face.js +199 -0
  203. package/packages/core/dist/scripts/generate-face.js.map +1 -0
  204. package/packages/core/dist/scripts/generate-face.test.d.ts +13 -0
  205. package/packages/core/dist/scripts/generate-face.test.d.ts.map +1 -0
  206. package/packages/core/dist/scripts/generate-face.test.js +301 -0
  207. package/packages/core/dist/scripts/generate-face.test.js.map +1 -0
  208. package/packages/core/dist/scripts/generate-report.d.ts +65 -0
  209. package/packages/core/dist/scripts/generate-report.d.ts.map +1 -0
  210. package/packages/core/dist/scripts/generate-report.js +378 -0
  211. package/packages/core/dist/scripts/generate-report.js.map +1 -0
  212. package/packages/core/dist/scripts/generate-report.test.d.ts +13 -0
  213. package/packages/core/dist/scripts/generate-report.test.d.ts.map +1 -0
  214. package/packages/core/dist/scripts/generate-report.test.js +363 -0
  215. package/packages/core/dist/scripts/generate-report.test.js.map +1 -0
  216. package/packages/core/dist/scripts/generate-spider-report.d.ts +65 -0
  217. package/packages/core/dist/scripts/generate-spider-report.d.ts.map +1 -0
  218. package/packages/core/dist/scripts/generate-spider-report.js +366 -0
  219. package/packages/core/dist/scripts/generate-spider-report.js.map +1 -0
  220. package/packages/core/dist/scripts/generate-spider-report.test.d.ts +13 -0
  221. package/packages/core/dist/scripts/generate-spider-report.test.d.ts.map +1 -0
  222. package/packages/core/dist/scripts/generate-spider-report.test.js +367 -0
  223. package/packages/core/dist/scripts/generate-spider-report.test.js.map +1 -0
  224. package/packages/core/dist/scripts/generate-spider.d.ts +37 -0
  225. package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -0
  226. package/packages/core/dist/scripts/generate-spider.js +315 -0
  227. package/packages/core/dist/scripts/generate-spider.js.map +1 -0
  228. package/packages/core/dist/scripts/generate-spider.test.d.ts +14 -0
  229. package/packages/core/dist/scripts/generate-spider.test.d.ts.map +1 -0
  230. package/packages/core/dist/scripts/generate-spider.test.js +269 -0
  231. package/packages/core/dist/scripts/generate-spider.test.js.map +1 -0
  232. package/packages/core/dist/scripts/job-fair-aggregator.d.ts +150 -0
  233. package/packages/core/dist/scripts/job-fair-aggregator.d.ts.map +1 -0
  234. package/packages/core/dist/scripts/job-fair-aggregator.js +547 -0
  235. package/packages/core/dist/scripts/job-fair-aggregator.js.map +1 -0
  236. package/packages/core/dist/scripts/job-fair-aggregator.test.d.ts +14 -0
  237. package/packages/core/dist/scripts/job-fair-aggregator.test.d.ts.map +1 -0
  238. package/packages/core/dist/scripts/job-fair-aggregator.test.js +616 -0
  239. package/packages/core/dist/scripts/job-fair-aggregator.test.js.map +1 -0
  240. package/packages/core/dist/scripts/run-ci.test.d.ts +20 -0
  241. package/packages/core/dist/scripts/run-ci.test.d.ts.map +1 -0
  242. package/packages/core/dist/scripts/run-ci.test.js +127 -0
  243. package/packages/core/dist/scripts/run-ci.test.js.map +1 -0
  244. package/packages/core/dist/scripts/theme-detail.test.d.ts +10 -0
  245. package/packages/core/dist/scripts/theme-detail.test.d.ts.map +1 -0
  246. package/packages/core/dist/scripts/theme-detail.test.js +199 -0
  247. package/packages/core/dist/scripts/theme-detail.test.js.map +1 -0
  248. package/packages/core/dist/scripts/validate-ocean-profiles.d.ts +9 -0
  249. package/packages/core/dist/scripts/validate-ocean-profiles.d.ts.map +1 -0
  250. package/packages/core/dist/scripts/validate-ocean-profiles.js +130 -0
  251. package/packages/core/dist/scripts/validate-ocean-profiles.js.map +1 -0
  252. package/packages/core/dist/workflow/generic-handoff.d.ts +235 -0
  253. package/packages/core/dist/workflow/generic-handoff.d.ts.map +1 -0
  254. package/packages/core/dist/workflow/generic-handoff.js +358 -0
  255. package/packages/core/dist/workflow/generic-handoff.js.map +1 -0
  256. package/packages/core/dist/workflow/generic-handoff.test.d.ts +21 -0
  257. package/packages/core/dist/workflow/generic-handoff.test.d.ts.map +1 -0
  258. package/packages/core/dist/workflow/generic-handoff.test.js +499 -0
  259. package/packages/core/dist/workflow/generic-handoff.test.js.map +1 -0
  260. package/packages/core/dist/workflow/generic-sm-finish.d.ts +89 -0
  261. package/packages/core/dist/workflow/generic-sm-finish.d.ts.map +1 -0
  262. package/packages/core/dist/workflow/generic-sm-finish.js +157 -0
  263. package/packages/core/dist/workflow/generic-sm-finish.js.map +1 -0
  264. package/packages/core/dist/workflow/generic-sm-setup.d.ts +138 -0
  265. package/packages/core/dist/workflow/generic-sm-setup.d.ts.map +1 -0
  266. package/packages/core/dist/workflow/generic-sm-setup.js +382 -0
  267. package/packages/core/dist/workflow/generic-sm-setup.js.map +1 -0
  268. package/packages/core/dist/workflow/sm-subagents.test.d.ts +23 -0
  269. package/packages/core/dist/workflow/sm-subagents.test.d.ts.map +1 -0
  270. package/packages/core/dist/workflow/sm-subagents.test.js +727 -0
  271. package/packages/core/dist/workflow/sm-subagents.test.js.map +1 -0
  272. package/packages/core/dist/workflow/story-workflow-routing.test.d.ts +17 -0
  273. package/packages/core/dist/workflow/story-workflow-routing.test.d.ts.map +1 -0
  274. package/packages/core/dist/workflow/story-workflow-routing.test.js +559 -0
  275. package/packages/core/dist/workflow/story-workflow-routing.test.js.map +1 -0
  276. package/packages/core/dist/workflow/test-cache.d.ts +131 -0
  277. package/packages/core/dist/workflow/test-cache.d.ts.map +1 -0
  278. package/packages/core/dist/workflow/test-cache.js +226 -0
  279. package/packages/core/dist/workflow/test-cache.js.map +1 -0
  280. package/packages/core/dist/workflow/test-cache.test.d.ts +17 -0
  281. package/packages/core/dist/workflow/test-cache.test.d.ts.map +1 -0
  282. package/packages/core/dist/workflow/test-cache.test.js +438 -0
  283. package/packages/core/dist/workflow/test-cache.test.js.map +1 -0
  284. package/packages/core/dist/workflow/workflow-loader.d.ts +76 -0
  285. package/packages/core/dist/workflow/workflow-loader.d.ts.map +1 -0
  286. package/packages/core/dist/workflow/workflow-loader.js +133 -0
  287. package/packages/core/dist/workflow/workflow-loader.js.map +1 -0
  288. package/packages/core/dist/workflow/workflow-loader.test.d.ts +15 -0
  289. package/packages/core/dist/workflow/workflow-loader.test.d.ts.map +1 -0
  290. package/packages/core/dist/workflow/workflow-loader.test.js +354 -0
  291. package/packages/core/dist/workflow/workflow-loader.test.js.map +1 -0
  292. package/packages/core/dist/workflow/workflow-migration.test.d.ts +17 -0
  293. package/packages/core/dist/workflow/workflow-migration.test.d.ts.map +1 -0
  294. package/packages/core/dist/workflow/workflow-migration.test.js +372 -0
  295. package/packages/core/dist/workflow/workflow-migration.test.js.map +1 -0
  296. package/packages/core/dist/workflow/workflow-router.d.ts +55 -0
  297. package/packages/core/dist/workflow/workflow-router.d.ts.map +1 -0
  298. package/packages/core/dist/workflow/workflow-router.js +245 -0
  299. package/packages/core/dist/workflow/workflow-router.js.map +1 -0
  300. package/packages/core/dist/workflow/workflow-router.test.d.ts +20 -0
  301. package/packages/core/dist/workflow/workflow-router.test.d.ts.map +1 -0
  302. package/packages/core/dist/workflow/workflow-router.test.js +607 -0
  303. package/packages/core/dist/workflow/workflow-router.test.js.map +1 -0
  304. package/packages/core/dist/workflow/workflow-schema.d.ts +98 -0
  305. package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -0
  306. package/packages/core/dist/workflow/workflow-schema.js +230 -0
  307. package/packages/core/dist/workflow/workflow-schema.js.map +1 -0
  308. package/packages/core/dist/workflow/workflow-schema.test.d.ts +45 -0
  309. package/packages/core/dist/workflow/workflow-schema.test.d.ts.map +1 -0
  310. package/packages/core/dist/workflow/workflow-schema.test.js +512 -0
  311. package/packages/core/dist/workflow/workflow-schema.test.js.map +1 -0
  312. package/pennyfarthing-dist/agents/README.md +397 -0
  313. package/pennyfarthing-dist/agents/architect.md +171 -0
  314. package/pennyfarthing-dist/agents/dev.md +225 -0
  315. package/pennyfarthing-dist/agents/devops.md +183 -0
  316. package/pennyfarthing-dist/agents/generic-handoff.md +451 -0
  317. package/pennyfarthing-dist/agents/generic-sm-finish.md +261 -0
  318. package/pennyfarthing-dist/agents/generic-sm-setup.md +214 -0
  319. package/pennyfarthing-dist/agents/orchestrator.md +316 -0
  320. package/pennyfarthing-dist/agents/pm.md +153 -0
  321. package/pennyfarthing-dist/agents/reviewer-preflight.md +224 -0
  322. package/pennyfarthing-dist/agents/reviewer.md +315 -0
  323. package/pennyfarthing-dist/agents/sm-file-summary.md +109 -0
  324. package/pennyfarthing-dist/agents/sm-handoff.md +97 -0
  325. package/pennyfarthing-dist/agents/sm.md +480 -0
  326. package/pennyfarthing-dist/agents/tea.md +191 -0
  327. package/pennyfarthing-dist/agents/tech-writer.md +148 -0
  328. package/pennyfarthing-dist/agents/testing-runner.md +420 -0
  329. package/pennyfarthing-dist/agents/ux-designer.md +158 -0
  330. package/pennyfarthing-dist/agents/workflow-status-check.md +332 -0
  331. package/pennyfarthing-dist/commands/architect.md +62 -0
  332. package/pennyfarthing-dist/commands/benchmark-control.md +69 -0
  333. package/pennyfarthing-dist/commands/benchmark.md +467 -0
  334. package/pennyfarthing-dist/commands/brainstorm.md +91 -0
  335. package/pennyfarthing-dist/commands/check.md +156 -0
  336. package/pennyfarthing-dist/commands/chore.md +178 -0
  337. package/pennyfarthing-dist/commands/close-epic.md +136 -0
  338. package/pennyfarthing-dist/commands/continue-session.md +184 -0
  339. package/pennyfarthing-dist/commands/create-branches-from-story.md +374 -0
  340. package/pennyfarthing-dist/commands/create-theme.md +29 -0
  341. package/pennyfarthing-dist/commands/dev.md +60 -0
  342. package/pennyfarthing-dist/commands/devops.md +59 -0
  343. package/pennyfarthing-dist/commands/git-cleanup.md +340 -0
  344. package/pennyfarthing-dist/commands/health-check.md +108 -0
  345. package/pennyfarthing-dist/commands/help.md +264 -0
  346. package/pennyfarthing-dist/commands/job-fair.md +102 -0
  347. package/pennyfarthing-dist/commands/list-themes.md +17 -0
  348. package/pennyfarthing-dist/commands/new-work.md +127 -0
  349. package/pennyfarthing-dist/commands/orchestrator.md +56 -0
  350. package/pennyfarthing-dist/commands/parallel-work.md +71 -0
  351. package/pennyfarthing-dist/commands/party-mode.md +67 -0
  352. package/pennyfarthing-dist/commands/permissions.md +193 -0
  353. package/pennyfarthing-dist/commands/pm.md +60 -0
  354. package/pennyfarthing-dist/commands/prime.md +140 -0
  355. package/pennyfarthing-dist/commands/release.md +58 -0
  356. package/pennyfarthing-dist/commands/repo-status.md +49 -0
  357. package/pennyfarthing-dist/commands/retro.md +200 -0
  358. package/pennyfarthing-dist/commands/reviewer.md +64 -0
  359. package/pennyfarthing-dist/commands/run-ci.md +116 -0
  360. package/pennyfarthing-dist/commands/set-theme.md +52 -0
  361. package/pennyfarthing-dist/commands/show-theme.md +21 -0
  362. package/pennyfarthing-dist/commands/sm.md +70 -0
  363. package/pennyfarthing-dist/commands/solo.md +411 -0
  364. package/pennyfarthing-dist/commands/sprint-planning.md +109 -0
  365. package/pennyfarthing-dist/commands/start-epic.md +156 -0
  366. package/pennyfarthing-dist/commands/sync-epic-to-jira.md +184 -0
  367. package/pennyfarthing-dist/commands/sync-work-with-sprint.md +376 -0
  368. package/pennyfarthing-dist/commands/tea.md +63 -0
  369. package/pennyfarthing-dist/commands/tech-writer.md +53 -0
  370. package/pennyfarthing-dist/commands/theme-maker.md +671 -0
  371. package/pennyfarthing-dist/commands/update-domain-docs.md +83 -0
  372. package/pennyfarthing-dist/commands/ux-designer.md +62 -0
  373. package/pennyfarthing-dist/commands/work.md +111 -0
  374. package/pennyfarthing-dist/guides/AGENT-COORDINATION.md +480 -0
  375. package/pennyfarthing-dist/guides/AGENT-SCOPES.md +201 -0
  376. package/pennyfarthing-dist/guides/HOOKS.md +230 -0
  377. package/pennyfarthing-dist/guides/PROMPT-PATTERNS.md +338 -0
  378. package/pennyfarthing-dist/guides/SESSION-ARTIFACTS.md +193 -0
  379. package/pennyfarthing-dist/guides/agent-template-strategic.md +148 -0
  380. package/pennyfarthing-dist/guides/agent-template-tactical.md +162 -0
  381. package/pennyfarthing-dist/guides/patterns/approval-gates-pattern.md +746 -0
  382. package/pennyfarthing-dist/guides/patterns/fan-out-fan-in-pattern.md +574 -0
  383. package/pennyfarthing-dist/guides/patterns/helper-delegation-pattern.md +488 -0
  384. package/pennyfarthing-dist/guides/patterns/tdd-flow-pattern.md +402 -0
  385. package/pennyfarthing-dist/guides/permission-protocol.md +188 -0
  386. package/pennyfarthing-dist/guides/persona-loading.md +46 -0
  387. package/pennyfarthing-dist/guides/persona-system.md +294 -0
  388. package/pennyfarthing-dist/guides/shared-agent-behavior.md +388 -0
  389. package/pennyfarthing-dist/guides/shared-context.md +147 -0
  390. package/pennyfarthing-dist/guides/strategic-agent-behavior.md +348 -0
  391. package/pennyfarthing-dist/guides/tactical-agent-behavior.md +1041 -0
  392. package/pennyfarthing-dist/guides/workflow-schema.md +195 -0
  393. package/pennyfarthing-dist/guides/worktree-mode.md +113 -0
  394. package/pennyfarthing-dist/output-styles/teaching.md +33 -0
  395. package/pennyfarthing-dist/output-styles/terse.md +20 -0
  396. package/pennyfarthing-dist/output-styles/verbose.md +28 -0
  397. package/pennyfarthing-dist/personas/themes/1984.yaml +312 -0
  398. package/pennyfarthing-dist/personas/themes/a-team.yaml +207 -0
  399. package/pennyfarthing-dist/personas/themes/agatha-christie.yaml +300 -0
  400. package/pennyfarthing-dist/personas/themes/alice-in-wonderland.yaml +330 -0
  401. package/pennyfarthing-dist/personas/themes/all-stars.yaml +332 -0
  402. package/pennyfarthing-dist/personas/themes/ancient-philosophers.yaml +320 -0
  403. package/pennyfarthing-dist/personas/themes/ancient-strategists.yaml +306 -0
  404. package/pennyfarthing-dist/personas/themes/arcane.yaml +288 -0
  405. package/pennyfarthing-dist/personas/themes/arthurian-mythos.yaml +331 -0
  406. package/pennyfarthing-dist/personas/themes/avatar-the-last-airbender.yaml +288 -0
  407. package/pennyfarthing-dist/personas/themes/babylon-5.yaml +288 -0
  408. package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +288 -0
  409. package/pennyfarthing-dist/personas/themes/better-call-saul.yaml +288 -0
  410. package/pennyfarthing-dist/personas/themes/big-lebowski.yaml +300 -0
  411. package/pennyfarthing-dist/personas/themes/black-sails.yaml +300 -0
  412. package/pennyfarthing-dist/personas/themes/blade-runner.yaml +295 -0
  413. package/pennyfarthing-dist/personas/themes/bobiverse.yaml +288 -0
  414. package/pennyfarthing-dist/personas/themes/breaking-bad.yaml +327 -0
  415. package/pennyfarthing-dist/personas/themes/catch-22.yaml +316 -0
  416. package/pennyfarthing-dist/personas/themes/classical-composers.yaml +310 -0
  417. package/pennyfarthing-dist/personas/themes/control.yaml +197 -0
  418. package/pennyfarthing-dist/personas/themes/count-of-monte-cristo.yaml +320 -0
  419. package/pennyfarthing-dist/personas/themes/cowboy-bebop.yaml +323 -0
  420. package/pennyfarthing-dist/personas/themes/deadwood.yaml +300 -0
  421. package/pennyfarthing-dist/personas/themes/dickens.yaml +320 -0
  422. package/pennyfarthing-dist/personas/themes/discworld.yaml +332 -0
  423. package/pennyfarthing-dist/personas/themes/doctor-who.yaml +290 -0
  424. package/pennyfarthing-dist/personas/themes/don-quixote.yaml +320 -0
  425. package/pennyfarthing-dist/personas/themes/dune.yaml +307 -0
  426. package/pennyfarthing-dist/personas/themes/enlightenment-thinkers.yaml +320 -0
  427. package/pennyfarthing-dist/personas/themes/expeditionary-force.yaml +288 -0
  428. package/pennyfarthing-dist/personas/themes/fargo.yaml +330 -0
  429. package/pennyfarthing-dist/personas/themes/film-auteurs.yaml +312 -0
  430. package/pennyfarthing-dist/personas/themes/firefly.yaml +328 -0
  431. package/pennyfarthing-dist/personas/themes/foundation.yaml +290 -0
  432. package/pennyfarthing-dist/personas/themes/futurama.yaml +321 -0
  433. package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +290 -0
  434. package/pennyfarthing-dist/personas/themes/gilligans-island.yaml +243 -0
  435. package/pennyfarthing-dist/personas/themes/gothic-literature.yaml +308 -0
  436. package/pennyfarthing-dist/personas/themes/great-gatsby.yaml +308 -0
  437. package/pennyfarthing-dist/personas/themes/greek-mythology.yaml +330 -0
  438. package/pennyfarthing-dist/personas/themes/hannibal.yaml +300 -0
  439. package/pennyfarthing-dist/personas/themes/harry-potter.yaml +324 -0
  440. package/pennyfarthing-dist/personas/themes/his-dark-materials.yaml +291 -0
  441. package/pennyfarthing-dist/personas/themes/historical-figures.yaml +288 -0
  442. package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +331 -0
  443. package/pennyfarthing-dist/personas/themes/house-md.yaml +321 -0
  444. package/pennyfarthing-dist/personas/themes/imperial-radch.yaml +289 -0
  445. package/pennyfarthing-dist/personas/themes/inspector-morse.yaml +300 -0
  446. package/pennyfarthing-dist/personas/themes/jane-austen.yaml +287 -0
  447. package/pennyfarthing-dist/personas/themes/jazz-legends.yaml +320 -0
  448. package/pennyfarthing-dist/personas/themes/justified.yaml +300 -0
  449. package/pennyfarthing-dist/personas/themes/legion-of-doom.yaml +219 -0
  450. package/pennyfarthing-dist/personas/themes/les-miserables.yaml +299 -0
  451. package/pennyfarthing-dist/personas/themes/lord-of-the-rings.yaml +334 -0
  452. package/pennyfarthing-dist/personas/themes/lovecraft-mythos.yaml +334 -0
  453. package/pennyfarthing-dist/personas/themes/mad-max.yaml +355 -0
  454. package/pennyfarthing-dist/personas/themes/mad-men.yaml +289 -0
  455. package/pennyfarthing-dist/personas/themes/marvel-mcu.yaml +300 -0
  456. package/pennyfarthing-dist/personas/themes/mash.yaml +334 -0
  457. package/pennyfarthing-dist/personas/themes/mass-effect.yaml +289 -0
  458. package/pennyfarthing-dist/personas/themes/military-commanders.yaml +306 -0
  459. package/pennyfarthing-dist/personas/themes/moby-dick.yaml +320 -0
  460. package/pennyfarthing-dist/personas/themes/monty-python.yaml +303 -0
  461. package/pennyfarthing-dist/personas/themes/neuromancer.yaml +300 -0
  462. package/pennyfarthing-dist/personas/themes/norse-mythology.yaml +329 -0
  463. package/pennyfarthing-dist/personas/themes/parks-and-rec.yaml +242 -0
  464. package/pennyfarthing-dist/personas/themes/peaky-blinders.yaml +298 -0
  465. package/pennyfarthing-dist/personas/themes/princess-bride.yaml +220 -0
  466. package/pennyfarthing-dist/personas/themes/renaissance-masters.yaml +320 -0
  467. package/pennyfarthing-dist/personas/themes/rome.yaml +300 -0
  468. package/pennyfarthing-dist/personas/themes/russian-masters.yaml +318 -0
  469. package/pennyfarthing-dist/personas/themes/sandman.yaml +288 -0
  470. package/pennyfarthing-dist/personas/themes/scientific-revolutionaries.yaml +320 -0
  471. package/pennyfarthing-dist/personas/themes/shakespeare.yaml +301 -0
  472. package/pennyfarthing-dist/personas/themes/sherlock-holmes.yaml +289 -0
  473. package/pennyfarthing-dist/personas/themes/snow-crash.yaml +288 -0
  474. package/pennyfarthing-dist/personas/themes/software-pioneers.yaml +300 -0
  475. package/pennyfarthing-dist/personas/themes/star-trek-tng.yaml +230 -0
  476. package/pennyfarthing-dist/personas/themes/star-trek-tos.yaml +210 -0
  477. package/pennyfarthing-dist/personas/themes/star-wars.yaml +303 -0
  478. package/pennyfarthing-dist/personas/themes/succession.yaml +300 -0
  479. package/pennyfarthing-dist/personas/themes/superfriends.yaml +208 -0
  480. package/pennyfarthing-dist/personas/themes/ted-lasso.yaml +236 -0
  481. package/pennyfarthing-dist/personas/themes/the-americans.yaml +300 -0
  482. package/pennyfarthing-dist/personas/themes/the-crown.yaml +300 -0
  483. package/pennyfarthing-dist/personas/themes/the-expanse.yaml +213 -0
  484. package/pennyfarthing-dist/personas/themes/the-good-place.yaml +322 -0
  485. package/pennyfarthing-dist/personas/themes/the-matrix.yaml +353 -0
  486. package/pennyfarthing-dist/personas/themes/the-odyssey.yaml +300 -0
  487. package/pennyfarthing-dist/personas/themes/the-office.yaml +330 -0
  488. package/pennyfarthing-dist/personas/themes/the-simpsons.yaml +308 -0
  489. package/pennyfarthing-dist/personas/themes/the-sopranos.yaml +300 -0
  490. package/pennyfarthing-dist/personas/themes/the-wire.yaml +311 -0
  491. package/pennyfarthing-dist/personas/themes/the-witcher.yaml +300 -0
  492. package/pennyfarthing-dist/personas/themes/twin-peaks.yaml +302 -0
  493. package/pennyfarthing-dist/personas/themes/vorkosigan-saga.yaml +300 -0
  494. package/pennyfarthing-dist/personas/themes/watchmen.yaml +291 -0
  495. package/pennyfarthing-dist/personas/themes/west-wing.yaml +291 -0
  496. package/pennyfarthing-dist/personas/themes/world-explorers.yaml +320 -0
  497. package/pennyfarthing-dist/personas/themes/wwii-leaders.yaml +307 -0
  498. package/pennyfarthing-dist/personas/themes/x-files.yaml +302 -0
  499. package/pennyfarthing-dist/scripts/add-short-names.mjs +264 -0
  500. package/pennyfarthing-dist/scripts/agent-session.sh +367 -0
  501. package/pennyfarthing-dist/scripts/check-context.sh +187 -0
  502. package/pennyfarthing-dist/scripts/check.sh +497 -0
  503. package/pennyfarthing-dist/scripts/deploy.sh +284 -0
  504. package/pennyfarthing-dist/scripts/doctor-dogfood.sh +360 -0
  505. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +61 -0
  506. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +66 -0
  507. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +35 -0
  508. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +166 -0
  509. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +50 -0
  510. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +71 -0
  511. package/pennyfarthing-dist/scripts/hooks/pre-push.sh +54 -0
  512. package/pennyfarthing-dist/scripts/hooks/session-start.sh +98 -0
  513. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +59 -0
  514. package/pennyfarthing-dist/scripts/install-git-hooks.sh +91 -0
  515. package/pennyfarthing-dist/scripts/prime.sh +161 -0
  516. package/pennyfarthing-dist/scripts/release.sh +198 -0
  517. package/pennyfarthing-dist/scripts/repo-utils.sh +778 -0
  518. package/pennyfarthing-dist/scripts/run-ci.sh +219 -0
  519. package/pennyfarthing-dist/scripts/run.sh +65 -0
  520. package/pennyfarthing-dist/scripts/statusline.sh +264 -0
  521. package/pennyfarthing-dist/scripts/tests/check.test.sh +582 -0
  522. package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +107 -0
  523. package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +597 -0
  524. package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +514 -0
  525. package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +517 -0
  526. package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +331 -0
  527. package/pennyfarthing-dist/scripts/uninstall.sh +271 -0
  528. package/pennyfarthing-dist/scripts/utils/background-tasks.sh +177 -0
  529. package/pennyfarthing-dist/scripts/utils/check-status.sh +251 -0
  530. package/pennyfarthing-dist/scripts/utils/checkpoint.sh +136 -0
  531. package/pennyfarthing-dist/scripts/utils/common.sh +157 -0
  532. package/pennyfarthing-dist/scripts/utils/create-feature-branches.sh +230 -0
  533. package/pennyfarthing-dist/scripts/utils/file-lock.sh +269 -0
  534. package/pennyfarthing-dist/scripts/utils/find-related-work.sh +231 -0
  535. package/pennyfarthing-dist/scripts/utils/find-root.sh +33 -0
  536. package/pennyfarthing-dist/scripts/utils/generate-skill-docs.sh +110 -0
  537. package/pennyfarthing-dist/scripts/utils/git-status-all.sh +127 -0
  538. package/pennyfarthing-dist/scripts/utils/ground-truth-judge.py +289 -0
  539. package/pennyfarthing-dist/scripts/utils/jira/jira-lib.mjs +443 -0
  540. package/pennyfarthing-dist/scripts/utils/jira/jira-sync-story.mjs +208 -0
  541. package/pennyfarthing-dist/scripts/utils/jira/jira-sync.mjs +198 -0
  542. package/pennyfarthing-dist/scripts/utils/jira-claim-story.sh +162 -0
  543. package/pennyfarthing-dist/scripts/utils/jira-lib.sh +463 -0
  544. package/pennyfarthing-dist/scripts/utils/jira-sync-story.sh +8 -0
  545. package/pennyfarthing-dist/scripts/utils/jira-sync.sh +8 -0
  546. package/pennyfarthing-dist/scripts/utils/log-skill-usage.sh +74 -0
  547. package/pennyfarthing-dist/scripts/utils/logging.sh +186 -0
  548. package/pennyfarthing-dist/scripts/utils/repo-scan.sh +141 -0
  549. package/pennyfarthing-dist/scripts/utils/retry.sh +76 -0
  550. package/pennyfarthing-dist/scripts/utils/run-timestamp.sh +7 -0
  551. package/pennyfarthing-dist/scripts/utils/session-cleanup.sh +319 -0
  552. package/pennyfarthing-dist/scripts/utils/skill-usage-report.sh +193 -0
  553. package/pennyfarthing-dist/scripts/utils/sprint-common.sh +286 -0
  554. package/pennyfarthing-dist/scripts/utils/sprint-metrics.sh +241 -0
  555. package/pennyfarthing-dist/scripts/utils/swebench-judge.py +400 -0
  556. package/pennyfarthing-dist/scripts/utils/sync-epic-to-jira.sh +16 -0
  557. package/pennyfarthing-dist/scripts/utils/test-setup.sh +337 -0
  558. package/pennyfarthing-dist/scripts/utils/validate-subagent-frontmatter.sh +160 -0
  559. package/pennyfarthing-dist/scripts/worktree-manager.sh +498 -0
  560. package/pennyfarthing-dist/skills/agentic-patterns/SKILL.md +236 -0
  561. package/pennyfarthing-dist/skills/changelog/SKILL.md +367 -0
  562. package/pennyfarthing-dist/skills/code-review/SKILL.md +168 -0
  563. package/pennyfarthing-dist/skills/context-engineering/SKILL.md +268 -0
  564. package/pennyfarthing-dist/skills/cyclist/SKILL.md +117 -0
  565. package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +421 -0
  566. package/pennyfarthing-dist/skills/finalize-run/SKILL.md +258 -0
  567. package/pennyfarthing-dist/skills/jira/SKILL.md +281 -0
  568. package/pennyfarthing-dist/skills/judge/SKILL.md +524 -0
  569. package/pennyfarthing-dist/skills/just/SKILL.md +160 -0
  570. package/pennyfarthing-dist/skills/mermaid/SKILL.md +240 -0
  571. package/pennyfarthing-dist/skills/otel/skill.md +222 -0
  572. package/pennyfarthing-dist/skills/permissions/skill.md +172 -0
  573. package/pennyfarthing-dist/skills/persona-benchmark/SKILL.md +173 -0
  574. package/pennyfarthing-dist/skills/skill-registry.schema.json +102 -0
  575. package/pennyfarthing-dist/skills/skill-registry.yaml +335 -0
  576. package/pennyfarthing-dist/skills/sprint-context/SKILL.md +120 -0
  577. package/pennyfarthing-dist/skills/story-management/SKILL.md +208 -0
  578. package/pennyfarthing-dist/skills/testing/SKILL.md +99 -0
  579. package/pennyfarthing-dist/skills/testing/references/troubleshooting.md +124 -0
  580. package/pennyfarthing-dist/skills/theme/skill.md +129 -0
  581. package/pennyfarthing-dist/skills/theme-creation/SKILL.md +169 -0
  582. package/pennyfarthing-dist/skills/workflow/SKILL.md +160 -0
  583. package/pennyfarthing-dist/skills/yq/SKILL.md +264 -0
  584. package/pennyfarthing-dist/templates/LEADERBOARD.schema.yaml +187 -0
  585. package/pennyfarthing-dist/templates/LEADERBOARD.template.md +59 -0
  586. package/pennyfarthing-dist/templates/agent-scopes.yaml.template +276 -0
  587. package/pennyfarthing-dist/templates/pennyfarthing-settings.yaml.template +61 -0
  588. package/pennyfarthing-dist/templates/persona-config.yaml.template +22 -0
  589. package/pennyfarthing-dist/templates/preferences.yaml.template +15 -0
  590. package/pennyfarthing-dist/templates/settings.local.json.template +90 -0
  591. package/pennyfarthing-dist/templates/setup-env.sh.template +18 -0
  592. package/pennyfarthing-dist/templates/shared-context.md.template +70 -0
  593. package/pennyfarthing-dist/templates/sidecar/decisions.md.template +40 -0
  594. package/pennyfarthing-dist/templates/sidecar/gotchas.md.template +37 -0
  595. package/pennyfarthing-dist/templates/sidecar/patterns.md.template +34 -0
  596. package/pennyfarthing-dist/workflows/agent-docs.yaml +70 -0
  597. package/pennyfarthing-dist/workflows/bdd.yaml +58 -0
  598. package/pennyfarthing-dist/workflows/tdd.yaml +50 -0
  599. package/pennyfarthing-dist/workflows/trivial.yaml +40 -0
@@ -0,0 +1,693 @@
1
+ /**
2
+ * Tests for Story 32-2: BMAD Story File Parser
3
+ *
4
+ * These tests define the contract for parsing BMAD story markdown files.
5
+ * Dev will implement parseBmadStory() to pass these tests.
6
+ *
7
+ * BMAD story format:
8
+ * - Required: # Story: [title], ## Status, ## Story, ## Acceptance Criteria
9
+ * - Optional: ## Tasks / Subtasks, ## Dev Notes, ## Dev Agent Record, ## File List
10
+ *
11
+ * Run with: npm test
12
+ */
13
+ import { describe, it } from 'node:test';
14
+ import assert from 'node:assert';
15
+ // Import the parser function that Dev will implement
16
+ // This import will fail until the module is implemented
17
+ import { parseBmadStory, } from './story-parser.js';
18
+ // =============================================================================
19
+ // TEST DATA: Valid BMAD story examples
20
+ // =============================================================================
21
+ const MINIMAL_VALID_STORY = `# Story: Minimal Test Story
22
+
23
+ ## Status
24
+ ready-for-dev
25
+
26
+ ## Story
27
+ As a user, I want to test, so that I can verify
28
+
29
+ ## Acceptance Criteria
30
+ - Given a test, When I run it, Then it passes
31
+ `;
32
+ const COMPLETE_STORY = `# Story: User Profile Photo Upload
33
+
34
+ ## Status
35
+ in-progress
36
+
37
+ ## Story
38
+ As a registered user, I want to upload a profile photo, so that other users can identify me visually
39
+
40
+ ## Acceptance Criteria
41
+ - Given I am on my profile page, When I click "Upload Photo", Then I see a file picker dialog
42
+ - Given I select a valid image (JPG/PNG under 5MB), When I confirm upload, Then my photo appears on my profile
43
+ - Given I select an invalid file, When I try to upload, Then I see an appropriate error message
44
+ - Given I have an existing photo, When I upload a new one, Then the old photo is replaced
45
+
46
+ ## Tasks / Subtasks
47
+ - [x] Create photo upload API endpoint
48
+ - [x] Add file validation (type, size)
49
+ - [x] Implement S3 storage integration
50
+ - [x] Generate thumbnail versions
51
+ - [ ] Build frontend upload component
52
+ - [ ] File picker with drag-and-drop
53
+ - [ ] Preview before upload
54
+ - [x] Progress indicator
55
+ - [ ] Write integration tests
56
+
57
+ ## Dev Notes
58
+ 2024-01-15: Started implementation. Using pre-signed S3 URLs for direct upload.
59
+ 2024-01-16: Hit CORS issue with S3, resolved by updating bucket policy.
60
+
61
+ ## Dev Agent Record
62
+ Session: abc123
63
+ Commands:
64
+ - npm run test:upload -- passed
65
+ - aws s3 cp test.jpg s3://bucket/test/ -- verified upload
66
+
67
+ ## File List
68
+ - src/api/upload.ts - Created: Photo upload endpoint with S3 integration
69
+ - src/components/PhotoUpload.tsx - Created: React component for file selection
70
+ - src/utils/imageValidation.ts - Created: File type and size validation
71
+ - tests/upload.test.ts - Created: Integration tests for upload flow
72
+ `;
73
+ const STORY_WITH_NON_BDD_CRITERIA = `# Story: Simple Feature
74
+
75
+ ## Status
76
+ ready-for-dev
77
+
78
+ ## Story
79
+ As a developer, I want a simple feature, so that I can test non-BDD criteria
80
+
81
+ ## Acceptance Criteria
82
+ - Users can log in with email and password
83
+ - Password must be at least 8 characters
84
+ - Failed login attempts are logged
85
+ `;
86
+ const STORY_WITH_MIXED_CRITERIA = `# Story: Mixed Criteria Feature
87
+
88
+ ## Status
89
+ ready-for-dev
90
+
91
+ ## Story
92
+ As a developer, I want mixed criteria, so that I can test both formats
93
+
94
+ ## Acceptance Criteria
95
+ - Given valid credentials, When I login, Then I see the dashboard
96
+ - Users receive email notifications
97
+ - Given invalid password, When I login, Then I see an error
98
+ `;
99
+ // =============================================================================
100
+ // AC1: Parses BMAD story markdown format - extracts all sections
101
+ // =============================================================================
102
+ describe('BMAD Story Parser (32-2)', () => {
103
+ describe('AC1: Valid story parsing', () => {
104
+ it('should parse a minimal valid story', () => {
105
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
106
+ assert.strictEqual(result.success, true, 'Should successfully parse minimal story');
107
+ assert.ok(result.story, 'Should return story object');
108
+ assert.strictEqual(result.story?.title, 'Minimal Test Story');
109
+ assert.strictEqual(result.story?.status, 'ready-for-dev');
110
+ });
111
+ it('should parse a complete story with all sections', () => {
112
+ const result = parseBmadStory(COMPLETE_STORY);
113
+ assert.strictEqual(result.success, true, 'Should successfully parse complete story');
114
+ assert.ok(result.story, 'Should return story object');
115
+ assert.strictEqual(result.story?.title, 'User Profile Photo Upload');
116
+ assert.strictEqual(result.story?.status, 'in-progress');
117
+ });
118
+ it('should extract title from H1 header', () => {
119
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
120
+ assert.strictEqual(result.success, true);
121
+ assert.strictEqual(result.story?.title, 'Minimal Test Story');
122
+ });
123
+ it('should handle title with special characters', () => {
124
+ const story = `# Story: Feature: User Auth (OAuth 2.0)
125
+
126
+ ## Status
127
+ ready-for-dev
128
+
129
+ ## Story
130
+ As a user, I want OAuth, so that I can login
131
+
132
+ ## Acceptance Criteria
133
+ - Given OAuth, When I login, Then I'm authenticated
134
+ `;
135
+ const result = parseBmadStory(story);
136
+ assert.strictEqual(result.success, true);
137
+ assert.strictEqual(result.story?.title, 'Feature: User Auth (OAuth 2.0)');
138
+ });
139
+ it('should preserve whitespace in content sections', () => {
140
+ const result = parseBmadStory(COMPLETE_STORY);
141
+ assert.strictEqual(result.success, true);
142
+ // Dev notes should preserve the timestamps and formatting
143
+ assert.ok(result.story?.devNotes?.includes('2024-01-15:'));
144
+ assert.ok(result.story?.devNotes?.includes('2024-01-16:'));
145
+ });
146
+ });
147
+ // ===========================================================================
148
+ // AC2: Extracts status, ACs, tasks, dev notes - all section content parsed
149
+ // ===========================================================================
150
+ describe('AC2: Section extraction', () => {
151
+ describe('Status section', () => {
152
+ it('should extract ready-for-dev status', () => {
153
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
154
+ assert.strictEqual(result.success, true);
155
+ assert.strictEqual(result.story?.status, 'ready-for-dev');
156
+ });
157
+ it('should extract in-progress status', () => {
158
+ const result = parseBmadStory(COMPLETE_STORY);
159
+ assert.strictEqual(result.success, true);
160
+ assert.strictEqual(result.story?.status, 'in-progress');
161
+ });
162
+ it('should extract review status', () => {
163
+ const story = MINIMAL_VALID_STORY.replace('ready-for-dev', 'review');
164
+ const result = parseBmadStory(story);
165
+ assert.strictEqual(result.success, true);
166
+ assert.strictEqual(result.story?.status, 'review');
167
+ });
168
+ it('should extract done status', () => {
169
+ const story = MINIMAL_VALID_STORY.replace('ready-for-dev', 'done');
170
+ const result = parseBmadStory(story);
171
+ assert.strictEqual(result.success, true);
172
+ assert.strictEqual(result.story?.status, 'done');
173
+ });
174
+ it('should reject invalid status values', () => {
175
+ const story = MINIMAL_VALID_STORY.replace('ready-for-dev', 'invalid-status');
176
+ const result = parseBmadStory(story);
177
+ assert.strictEqual(result.success, false, 'Should reject invalid status');
178
+ assert.ok(result.errors?.some(e => e.section === 'Status'), 'Should report status error');
179
+ });
180
+ it('should trim whitespace from status', () => {
181
+ const story = MINIMAL_VALID_STORY.replace('ready-for-dev', ' in-progress \n');
182
+ const result = parseBmadStory(story);
183
+ assert.strictEqual(result.success, true);
184
+ assert.strictEqual(result.story?.status, 'in-progress');
185
+ });
186
+ });
187
+ describe('Story section (user story)', () => {
188
+ it('should extract user story text', () => {
189
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
190
+ assert.strictEqual(result.success, true);
191
+ assert.strictEqual(result.story?.userStory, 'As a user, I want to test, so that I can verify');
192
+ });
193
+ it('should handle multi-line user stories', () => {
194
+ const story = `# Story: Multi-line Story
195
+
196
+ ## Status
197
+ ready-for-dev
198
+
199
+ ## Story
200
+ As a product manager,
201
+ I want to track feature requests,
202
+ so that I can prioritize development effectively
203
+
204
+ ## Acceptance Criteria
205
+ - Given a feature, When I track it, Then I see progress
206
+ `;
207
+ const result = parseBmadStory(story);
208
+ assert.strictEqual(result.success, true);
209
+ assert.ok(result.story?.userStory.includes('product manager'));
210
+ assert.ok(result.story?.userStory.includes('prioritize development'));
211
+ });
212
+ });
213
+ describe('Acceptance Criteria section', () => {
214
+ it('should parse BDD-style criteria (Given/When/Then)', () => {
215
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
216
+ assert.strictEqual(result.success, true);
217
+ assert.strictEqual(result.story?.acceptanceCriteria.length, 1);
218
+ const ac = result.story?.acceptanceCriteria[0];
219
+ assert.strictEqual(ac?.given, 'a test');
220
+ assert.strictEqual(ac?.when, 'I run it');
221
+ assert.strictEqual(ac?.then, 'it passes');
222
+ });
223
+ it('should parse multiple BDD criteria', () => {
224
+ const result = parseBmadStory(COMPLETE_STORY);
225
+ assert.strictEqual(result.success, true);
226
+ assert.strictEqual(result.story?.acceptanceCriteria.length, 4);
227
+ // First criterion
228
+ const ac1 = result.story?.acceptanceCriteria[0];
229
+ assert.strictEqual(ac1?.given, 'I am on my profile page');
230
+ assert.strictEqual(ac1?.when, 'I click "Upload Photo"');
231
+ assert.strictEqual(ac1?.then, 'I see a file picker dialog');
232
+ });
233
+ it('should handle non-BDD criteria with raw text', () => {
234
+ const result = parseBmadStory(STORY_WITH_NON_BDD_CRITERIA);
235
+ assert.strictEqual(result.success, true);
236
+ assert.strictEqual(result.story?.acceptanceCriteria.length, 3);
237
+ // Non-BDD should have empty given/when/then but populated raw
238
+ const ac1 = result.story?.acceptanceCriteria[0];
239
+ assert.strictEqual(ac1?.raw, 'Users can log in with email and password');
240
+ assert.strictEqual(ac1?.given, '');
241
+ assert.strictEqual(ac1?.when, '');
242
+ assert.strictEqual(ac1?.then, '');
243
+ });
244
+ it('should handle mixed BDD and non-BDD criteria', () => {
245
+ const result = parseBmadStory(STORY_WITH_MIXED_CRITERIA);
246
+ assert.strictEqual(result.success, true);
247
+ assert.strictEqual(result.story?.acceptanceCriteria.length, 3);
248
+ // First is BDD
249
+ assert.strictEqual(result.story?.acceptanceCriteria[0]?.given, 'valid credentials');
250
+ // Second is non-BDD
251
+ assert.strictEqual(result.story?.acceptanceCriteria[1]?.raw, 'Users receive email notifications');
252
+ assert.strictEqual(result.story?.acceptanceCriteria[1]?.given, '');
253
+ // Third is BDD
254
+ assert.strictEqual(result.story?.acceptanceCriteria[2]?.given, 'invalid password');
255
+ });
256
+ it('should preserve raw text for all criteria', () => {
257
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
258
+ assert.strictEqual(result.success, true);
259
+ const ac = result.story?.acceptanceCriteria[0];
260
+ assert.strictEqual(ac?.raw, 'Given a test, When I run it, Then it passes');
261
+ });
262
+ });
263
+ describe('Dev Notes section', () => {
264
+ it('should extract dev notes when present', () => {
265
+ const result = parseBmadStory(COMPLETE_STORY);
266
+ assert.strictEqual(result.success, true);
267
+ assert.ok(result.story?.devNotes);
268
+ assert.ok(result.story?.devNotes?.includes('Started implementation'));
269
+ assert.ok(result.story?.devNotes?.includes('CORS issue'));
270
+ });
271
+ it('should return null when dev notes missing', () => {
272
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
273
+ assert.strictEqual(result.success, true);
274
+ assert.strictEqual(result.story?.devNotes, null);
275
+ });
276
+ });
277
+ describe('Dev Agent Record section', () => {
278
+ it('should extract dev agent record when present', () => {
279
+ const result = parseBmadStory(COMPLETE_STORY);
280
+ assert.strictEqual(result.success, true);
281
+ assert.ok(result.story?.devAgentRecord);
282
+ assert.ok(result.story?.devAgentRecord?.includes('Session: abc123'));
283
+ assert.ok(result.story?.devAgentRecord?.includes('npm run test:upload'));
284
+ });
285
+ it('should return null when dev agent record missing', () => {
286
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
287
+ assert.strictEqual(result.success, true);
288
+ assert.strictEqual(result.story?.devAgentRecord, null);
289
+ });
290
+ });
291
+ describe('File List section', () => {
292
+ it('should extract file list when present', () => {
293
+ const result = parseBmadStory(COMPLETE_STORY);
294
+ assert.strictEqual(result.success, true);
295
+ assert.strictEqual(result.story?.fileList.length, 4);
296
+ assert.ok(result.story?.fileList.includes('src/api/upload.ts - Created: Photo upload endpoint with S3 integration'));
297
+ });
298
+ it('should return empty array when file list missing', () => {
299
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
300
+ assert.strictEqual(result.success, true);
301
+ assert.deepStrictEqual(result.story?.fileList, []);
302
+ });
303
+ it('should handle file list with various formats', () => {
304
+ const story = `# Story: File List Test
305
+
306
+ ## Status
307
+ ready-for-dev
308
+
309
+ ## Story
310
+ As a user, I want files, so that I can track them
311
+
312
+ ## Acceptance Criteria
313
+ - Given files, When I list them, Then I see them
314
+
315
+ ## File List
316
+ - src/simple.ts
317
+ - src/with-description.ts - Modified: Updated logic
318
+ - path/to/nested/file.tsx - Created: New component
319
+ `;
320
+ const result = parseBmadStory(story);
321
+ assert.strictEqual(result.success, true);
322
+ assert.strictEqual(result.story?.fileList.length, 3);
323
+ });
324
+ });
325
+ });
326
+ // ===========================================================================
327
+ // AC3: Converts to Pennyfarthing session structure - BmadStory interface
328
+ // ===========================================================================
329
+ describe('AC3: BmadStory interface population', () => {
330
+ it('should return success: true for valid story', () => {
331
+ const result = parseBmadStory(COMPLETE_STORY);
332
+ assert.strictEqual(result.success, true);
333
+ assert.ok(result.story);
334
+ assert.strictEqual(result.errors, undefined);
335
+ });
336
+ it('should return success: false with errors for invalid story', () => {
337
+ const story = `# Story: Missing Sections
338
+
339
+ ## Status
340
+ invalid-status
341
+ `;
342
+ const result = parseBmadStory(story);
343
+ assert.strictEqual(result.success, false);
344
+ assert.strictEqual(result.story, undefined);
345
+ assert.ok(result.errors && result.errors.length > 0);
346
+ });
347
+ it('should populate all BmadStory fields for complete story', () => {
348
+ const result = parseBmadStory(COMPLETE_STORY);
349
+ assert.strictEqual(result.success, true);
350
+ const story = result.story;
351
+ // All required fields
352
+ assert.strictEqual(typeof story.title, 'string');
353
+ assert.ok(['ready-for-dev', 'in-progress', 'review', 'done'].includes(story.status));
354
+ assert.strictEqual(typeof story.userStory, 'string');
355
+ assert.ok(Array.isArray(story.acceptanceCriteria));
356
+ // All optional fields
357
+ assert.ok(Array.isArray(story.tasks));
358
+ assert.ok(story.devNotes === null || typeof story.devNotes === 'string');
359
+ assert.ok(story.devAgentRecord === null || typeof story.devAgentRecord === 'string');
360
+ assert.ok(Array.isArray(story.fileList));
361
+ });
362
+ it('should have correct types for acceptance criteria', () => {
363
+ const result = parseBmadStory(COMPLETE_STORY);
364
+ assert.strictEqual(result.success, true);
365
+ const ac = result.story?.acceptanceCriteria[0];
366
+ assert.strictEqual(typeof ac.given, 'string');
367
+ assert.strictEqual(typeof ac.when, 'string');
368
+ assert.strictEqual(typeof ac.then, 'string');
369
+ assert.strictEqual(typeof ac.raw, 'string');
370
+ });
371
+ it('should have correct types for tasks', () => {
372
+ const result = parseBmadStory(COMPLETE_STORY);
373
+ assert.strictEqual(result.success, true);
374
+ const task = result.story?.tasks[0];
375
+ assert.strictEqual(typeof task.text, 'string');
376
+ assert.strictEqual(typeof task.completed, 'boolean');
377
+ // subtasks is optional
378
+ assert.ok(task.subtasks === undefined || Array.isArray(task.subtasks));
379
+ });
380
+ });
381
+ // ===========================================================================
382
+ // AC4: Preserves task checkbox state - [ ] incomplete, [x] complete
383
+ // ===========================================================================
384
+ describe('AC4: Task checkbox parsing', () => {
385
+ it('should parse completed tasks ([x])', () => {
386
+ const result = parseBmadStory(COMPLETE_STORY);
387
+ assert.strictEqual(result.success, true);
388
+ const firstTask = result.story?.tasks[0];
389
+ assert.strictEqual(firstTask?.text, 'Create photo upload API endpoint');
390
+ assert.strictEqual(firstTask?.completed, true);
391
+ });
392
+ it('should parse incomplete tasks ([ ])', () => {
393
+ const result = parseBmadStory(COMPLETE_STORY);
394
+ assert.strictEqual(result.success, true);
395
+ const secondTask = result.story?.tasks[1];
396
+ assert.strictEqual(secondTask?.text, 'Build frontend upload component');
397
+ assert.strictEqual(secondTask?.completed, false);
398
+ });
399
+ it('should parse nested subtasks', () => {
400
+ const result = parseBmadStory(COMPLETE_STORY);
401
+ assert.strictEqual(result.success, true);
402
+ const firstTask = result.story?.tasks[0];
403
+ assert.ok(firstTask?.subtasks);
404
+ assert.strictEqual(firstTask?.subtasks?.length, 3);
405
+ assert.strictEqual(firstTask?.subtasks?.[0].text, 'Add file validation (type, size)');
406
+ assert.strictEqual(firstTask?.subtasks?.[0].completed, true);
407
+ });
408
+ it('should handle mixed completed/incomplete subtasks', () => {
409
+ const result = parseBmadStory(COMPLETE_STORY);
410
+ assert.strictEqual(result.success, true);
411
+ const secondTask = result.story?.tasks[1];
412
+ assert.ok(secondTask?.subtasks);
413
+ // "File picker with drag-and-drop" - incomplete
414
+ assert.strictEqual(secondTask?.subtasks?.[0].completed, false);
415
+ // "Preview before upload" - incomplete
416
+ assert.strictEqual(secondTask?.subtasks?.[1].completed, false);
417
+ // "Progress indicator" - complete
418
+ assert.strictEqual(secondTask?.subtasks?.[2].completed, true);
419
+ });
420
+ it('should return empty tasks array when no tasks section', () => {
421
+ const result = parseBmadStory(MINIMAL_VALID_STORY);
422
+ assert.strictEqual(result.success, true);
423
+ assert.deepStrictEqual(result.story?.tasks, []);
424
+ });
425
+ it('should handle tasks without subtasks', () => {
426
+ const story = `# Story: Simple Tasks
427
+
428
+ ## Status
429
+ ready-for-dev
430
+
431
+ ## Story
432
+ As a user, I want tasks, so that I can track work
433
+
434
+ ## Acceptance Criteria
435
+ - Given tasks, When I check them, Then I see status
436
+
437
+ ## Tasks / Subtasks
438
+ - [x] First task done
439
+ - [ ] Second task pending
440
+ - [x] Third task done
441
+ `;
442
+ const result = parseBmadStory(story);
443
+ assert.strictEqual(result.success, true);
444
+ assert.strictEqual(result.story?.tasks.length, 3);
445
+ assert.strictEqual(result.story?.tasks[0].completed, true);
446
+ assert.strictEqual(result.story?.tasks[1].completed, false);
447
+ assert.strictEqual(result.story?.tasks[2].completed, true);
448
+ // No subtasks
449
+ assert.strictEqual(result.story?.tasks[0].subtasks, undefined);
450
+ });
451
+ it('should handle deeply nested subtasks (2-space indent)', () => {
452
+ const story = `# Story: Deep Nesting
453
+
454
+ ## Status
455
+ ready-for-dev
456
+
457
+ ## Story
458
+ As a user, I want nested tasks, so that I can organize work
459
+
460
+ ## Acceptance Criteria
461
+ - Given nesting, When I parse it, Then hierarchy preserved
462
+
463
+ ## Tasks / Subtasks
464
+ - [ ] Top level task
465
+ - [ ] First level subtask
466
+ - [x] Another first level
467
+ `;
468
+ const result = parseBmadStory(story);
469
+ assert.strictEqual(result.success, true);
470
+ assert.strictEqual(result.story?.tasks.length, 1);
471
+ assert.strictEqual(result.story?.tasks[0].subtasks?.length, 2);
472
+ assert.strictEqual(result.story?.tasks[0].subtasks?.[0].text, 'First level subtask');
473
+ assert.strictEqual(result.story?.tasks[0].subtasks?.[1].completed, true);
474
+ });
475
+ });
476
+ // ===========================================================================
477
+ // AC5: Unit tests - error accumulation and edge cases
478
+ // ===========================================================================
479
+ describe('AC5: Error handling and edge cases', () => {
480
+ describe('Required section validation', () => {
481
+ it('should reject story missing title', () => {
482
+ const story = `## Status
483
+ ready-for-dev
484
+
485
+ ## Story
486
+ As a user, I want something
487
+
488
+ ## Acceptance Criteria
489
+ - Given test, When I run, Then pass
490
+ `;
491
+ const result = parseBmadStory(story);
492
+ assert.strictEqual(result.success, false);
493
+ assert.ok(result.errors?.some(e => e.section === 'Title'));
494
+ });
495
+ it('should reject story missing status section', () => {
496
+ const story = `# Story: No Status
497
+
498
+ ## Story
499
+ As a user, I want something
500
+
501
+ ## Acceptance Criteria
502
+ - Given test, When I run, Then pass
503
+ `;
504
+ const result = parseBmadStory(story);
505
+ assert.strictEqual(result.success, false);
506
+ assert.ok(result.errors?.some(e => e.section === 'Status'));
507
+ });
508
+ it('should reject story missing story section', () => {
509
+ const story = `# Story: No User Story
510
+
511
+ ## Status
512
+ ready-for-dev
513
+
514
+ ## Acceptance Criteria
515
+ - Given test, When I run, Then pass
516
+ `;
517
+ const result = parseBmadStory(story);
518
+ assert.strictEqual(result.success, false);
519
+ assert.ok(result.errors?.some(e => e.section === 'Story'));
520
+ });
521
+ it('should reject story missing acceptance criteria', () => {
522
+ const story = `# Story: No ACs
523
+
524
+ ## Status
525
+ ready-for-dev
526
+
527
+ ## Story
528
+ As a user, I want something
529
+ `;
530
+ const result = parseBmadStory(story);
531
+ assert.strictEqual(result.success, false);
532
+ assert.ok(result.errors?.some(e => e.section === 'Acceptance Criteria'));
533
+ });
534
+ });
535
+ describe('Error accumulation', () => {
536
+ it('should report multiple errors at once', () => {
537
+ const story = `# Story: Multiple Errors
538
+
539
+ ## Status
540
+ invalid-status
541
+ `;
542
+ // Missing: valid status, Story section, Acceptance Criteria
543
+ const result = parseBmadStory(story);
544
+ assert.strictEqual(result.success, false);
545
+ assert.ok(result.errors && result.errors.length >= 2, 'Should report multiple errors');
546
+ });
547
+ it('should include section name in error', () => {
548
+ const story = `# Story: Bad Status
549
+
550
+ ## Status
551
+ not-a-valid-status
552
+
553
+ ## Story
554
+ As a user, I want something
555
+
556
+ ## Acceptance Criteria
557
+ - Given test, When I run, Then pass
558
+ `;
559
+ const result = parseBmadStory(story);
560
+ assert.strictEqual(result.success, false);
561
+ const statusError = result.errors?.find(e => e.section === 'Status');
562
+ assert.ok(statusError, 'Should have error for Status section');
563
+ });
564
+ it('should include human-readable error message', () => {
565
+ const story = `# Story: Bad Story
566
+
567
+ ## Status
568
+ invalid
569
+ `;
570
+ const result = parseBmadStory(story);
571
+ assert.strictEqual(result.success, false);
572
+ const error = result.errors?.[0];
573
+ assert.ok(error?.message, 'Error should have message');
574
+ assert.ok(error?.message.length > 0, 'Message should not be empty');
575
+ });
576
+ });
577
+ describe('Edge cases', () => {
578
+ it('should handle empty content', () => {
579
+ const result = parseBmadStory('');
580
+ assert.strictEqual(result.success, false);
581
+ assert.ok(result.errors && result.errors.length > 0);
582
+ });
583
+ it('should handle content with only whitespace', () => {
584
+ const result = parseBmadStory(' \n\n \t ');
585
+ assert.strictEqual(result.success, false);
586
+ });
587
+ it('should handle extra blank lines between sections', () => {
588
+ const story = `# Story: Extra Whitespace
589
+
590
+
591
+ ## Status
592
+
593
+ ready-for-dev
594
+
595
+
596
+ ## Story
597
+
598
+ As a user, I want to test
599
+
600
+
601
+ ## Acceptance Criteria
602
+
603
+ - Given test, When I run, Then pass
604
+
605
+ `;
606
+ const result = parseBmadStory(story);
607
+ assert.strictEqual(result.success, true);
608
+ assert.strictEqual(result.story?.status, 'ready-for-dev');
609
+ });
610
+ it('should handle section headers with extra spaces', () => {
611
+ const story = `# Story: Spaced Title
612
+
613
+ ## Status
614
+ ready-for-dev
615
+
616
+ ## Story
617
+ As a user, I want to test
618
+
619
+ ## Acceptance Criteria
620
+ - Given test, When I run, Then pass
621
+ `;
622
+ const result = parseBmadStory(story);
623
+ assert.strictEqual(result.success, true);
624
+ assert.strictEqual(result.story?.title, 'Spaced Title');
625
+ });
626
+ it('should handle acceptance criteria with inline code', () => {
627
+ const story = `# Story: Code in ACs
628
+
629
+ ## Status
630
+ ready-for-dev
631
+
632
+ ## Story
633
+ As a developer, I want to test code references
634
+
635
+ ## Acceptance Criteria
636
+ - Given a \`user_id\` parameter, When I call \`getUser()\`, Then I get the user object
637
+ `;
638
+ const result = parseBmadStory(story);
639
+ assert.strictEqual(result.success, true);
640
+ assert.ok(result.story?.acceptanceCriteria[0].raw.includes('`user_id`'));
641
+ });
642
+ it('should handle Windows line endings (CRLF)', () => {
643
+ const story = '# Story: Windows\r\n\r\n## Status\r\nready-for-dev\r\n\r\n## Story\r\nAs a user, I want Windows support\r\n\r\n## Acceptance Criteria\r\n- Given CRLF, When I parse, Then it works\r\n';
644
+ const result = parseBmadStory(story);
645
+ assert.strictEqual(result.success, true);
646
+ assert.strictEqual(result.story?.title, 'Windows');
647
+ });
648
+ it('should handle Tasks section with alternative header name', () => {
649
+ const story = `# Story: Alt Tasks Header
650
+
651
+ ## Status
652
+ ready-for-dev
653
+
654
+ ## Story
655
+ As a user, I want flexibility
656
+
657
+ ## Acceptance Criteria
658
+ - Given alt header, When I parse, Then tasks found
659
+
660
+ ## Tasks
661
+ - [ ] Simple task without "/ Subtasks" suffix
662
+ `;
663
+ const result = parseBmadStory(story);
664
+ assert.strictEqual(result.success, true);
665
+ assert.strictEqual(result.story?.tasks.length, 1);
666
+ });
667
+ it('should handle empty acceptance criteria section', () => {
668
+ const story = `# Story: Empty ACs
669
+
670
+ ## Status
671
+ ready-for-dev
672
+
673
+ ## Story
674
+ As a user, I want to test
675
+
676
+ ## Acceptance Criteria
677
+ `;
678
+ const result = parseBmadStory(story);
679
+ assert.strictEqual(result.success, false);
680
+ assert.ok(result.errors?.some(e => e.section === 'Acceptance Criteria' &&
681
+ e.message.toLowerCase().includes('empty')));
682
+ });
683
+ it('should handle uppercase status values', () => {
684
+ const story = MINIMAL_VALID_STORY.replace('ready-for-dev', 'READY-FOR-DEV');
685
+ const result = parseBmadStory(story);
686
+ // Should normalize to lowercase
687
+ assert.strictEqual(result.success, true);
688
+ assert.strictEqual(result.story?.status, 'ready-for-dev');
689
+ });
690
+ });
691
+ });
692
+ });
693
+ //# sourceMappingURL=story-parser.test.js.map