@pennyfarthing/core 10.0.2 → 10.0.5

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 (722) hide show
  1. package/README.md +287 -0
  2. package/package.json +29 -41
  3. package/{dist → packages/core/dist}/cli/commands/cyclist.d.ts +5 -1
  4. package/packages/core/dist/cli/commands/cyclist.d.ts.map +1 -0
  5. package/{dist → packages/core/dist}/cli/commands/cyclist.js +4 -4
  6. package/packages/core/dist/cli/commands/cyclist.js.map +1 -0
  7. package/{dist → packages/core/dist}/cli/commands/cyclist.test.js +2 -2
  8. package/packages/core/dist/cli/commands/cyclist.test.js.map +1 -0
  9. package/packages/core/dist/cli/commands/doctor-file-layout.test.d.ts +13 -0
  10. package/packages/core/dist/cli/commands/doctor-file-layout.test.d.ts.map +1 -0
  11. package/packages/core/dist/cli/commands/doctor-file-layout.test.js +234 -0
  12. package/packages/core/dist/cli/commands/doctor-file-layout.test.js.map +1 -0
  13. package/{dist → packages/core/dist}/cli/commands/doctor-legacy.test.js +17 -16
  14. package/{dist → packages/core/dist}/cli/commands/doctor-legacy.test.js.map +1 -1
  15. package/{dist → packages/core/dist}/cli/commands/doctor.d.ts +8 -0
  16. package/{dist → packages/core/dist}/cli/commands/doctor.d.ts.map +1 -1
  17. package/{dist → packages/core/dist}/cli/commands/doctor.js +224 -3
  18. package/packages/core/dist/cli/commands/doctor.js.map +1 -0
  19. package/{dist → packages/core/dist}/cli/commands/e2e-fresh-install.test.js +1 -1
  20. package/{dist → packages/core/dist}/cli/commands/e2e-fresh-install.test.js.map +1 -1
  21. package/{dist → packages/core/dist}/cli/commands/e2e-upgrade.test.js +1 -1
  22. package/{dist → packages/core/dist}/cli/commands/e2e-upgrade.test.js.map +1 -1
  23. package/packages/core/dist/cli/commands/hooks-consolidation.test.d.ts +19 -0
  24. package/packages/core/dist/cli/commands/hooks-consolidation.test.d.ts.map +1 -0
  25. package/packages/core/dist/cli/commands/hooks-consolidation.test.js +358 -0
  26. package/packages/core/dist/cli/commands/hooks-consolidation.test.js.map +1 -0
  27. package/{dist → packages/core/dist}/cli/commands/init.d.ts.map +1 -1
  28. package/{dist → packages/core/dist}/cli/commands/init.js +3 -0
  29. package/packages/core/dist/cli/commands/init.js.map +1 -0
  30. package/{dist → packages/core/dist}/cli/commands/update.d.ts.map +1 -1
  31. package/{dist → packages/core/dist}/cli/commands/update.js +53 -1
  32. package/{dist → packages/core/dist}/cli/commands/update.js.map +1 -1
  33. package/{dist → packages/core/dist}/cli/ocean-profiles.test.js +1 -1
  34. package/{dist → packages/core/dist}/cli/ocean-profiles.test.js.map +1 -1
  35. package/{dist → packages/core/dist}/cli/utils/files.d.ts +10 -0
  36. package/{dist → packages/core/dist}/cli/utils/files.d.ts.map +1 -1
  37. package/{dist → packages/core/dist}/cli/utils/files.js +35 -0
  38. package/{dist → packages/core/dist}/cli/utils/files.js.map +1 -1
  39. package/{dist → packages/core/dist}/cli/utils/settings.d.ts.map +1 -1
  40. package/{dist → packages/core/dist}/cli/utils/settings.js +24 -0
  41. package/packages/core/dist/cli/utils/settings.js.map +1 -0
  42. package/{dist → packages/core/dist}/cli/utils/themes.d.ts +1 -0
  43. package/packages/core/dist/cli/utils/themes.d.ts.map +1 -0
  44. package/{dist → packages/core/dist}/cli/utils/themes.js.map +1 -1
  45. package/{dist → packages/core/dist}/scripts/generate-report.d.ts.map +1 -1
  46. package/{dist → packages/core/dist}/scripts/generate-report.js +11 -7
  47. package/packages/core/dist/scripts/generate-report.js.map +1 -0
  48. package/{dist → packages/core/dist}/scripts/generate-spider-report.d.ts.map +1 -1
  49. package/{dist → packages/core/dist}/scripts/generate-spider-report.js +12 -8
  50. package/packages/core/dist/scripts/generate-spider-report.js.map +1 -0
  51. package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -0
  52. package/{dist → packages/core/dist}/scripts/generate-spider.js +6 -4
  53. package/packages/core/dist/scripts/generate-spider.js.map +1 -0
  54. package/{dist → packages/core/dist}/scripts/generate-spider.test.js +2 -2
  55. package/packages/core/dist/scripts/generate-spider.test.js.map +1 -0
  56. package/pennyfarthing-dist/agents/pm.md +1 -1
  57. package/pennyfarthing-dist/agents/sm-finish.md +1 -1
  58. package/pennyfarthing-dist/agents/sm-setup.md +6 -6
  59. package/pennyfarthing-dist/agents/sm.md +12 -6
  60. package/pennyfarthing-dist/agents/workflow-status-check.md +1 -1
  61. package/pennyfarthing-dist/commands/repo-status.md +2 -2
  62. package/pennyfarthing-dist/commands/sprint.md +8 -8
  63. package/pennyfarthing-dist/guides/bell-mode.md +65 -0
  64. package/pennyfarthing-dist/guides/benchmarks.md +62 -0
  65. package/pennyfarthing-dist/guides/bikelane.md +86 -0
  66. package/pennyfarthing-dist/guides/prime.md +72 -0
  67. package/pennyfarthing-dist/guides/reflector.md +59 -0
  68. package/pennyfarthing-dist/guides/relay-mode.md +53 -0
  69. package/pennyfarthing-dist/guides/skill-schema.md +25 -26
  70. package/pennyfarthing-dist/guides/tirepump.md +54 -0
  71. package/pennyfarthing-dist/guides/xml-tags.md +2 -2
  72. package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +59 -58
  73. package/pennyfarthing-dist/personas/themes/blade-runner.yaml +10 -10
  74. package/pennyfarthing-dist/personas/themes/doctor-who.yaml +10 -10
  75. package/pennyfarthing-dist/personas/themes/dune.yaml +64 -69
  76. package/pennyfarthing-dist/personas/themes/firefly.yaml +60 -73
  77. package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +60 -69
  78. package/pennyfarthing-dist/personas/themes/harry-potter.yaml +59 -73
  79. package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +45 -57
  80. package/pennyfarthing-dist/personas/themes/mad-max.yaml +5 -11
  81. package/pennyfarthing-dist/personas/themes/princess-bride.yaml +53 -63
  82. package/pennyfarthing-dist/personas/themes/sandman.yaml +59 -59
  83. package/pennyfarthing-dist/personas/themes/the-matrix.yaml +61 -62
  84. package/pennyfarthing-dist/personas/themes/west-wing.yaml +8 -9
  85. package/pennyfarthing-dist/scripts/README.md +2 -2
  86. package/pennyfarthing-dist/scripts/git/git-status-all.sh +1 -1
  87. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +3 -3
  88. package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +32 -0
  89. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +2 -7
  90. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +1 -1
  91. package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +12 -91
  92. package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +11 -86
  93. package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +11 -255
  94. package/pennyfarthing-dist/scripts/misc/repo-utils.sh +3 -3
  95. package/pennyfarthing-dist/scripts/sprint/README.md +32 -17
  96. package/pennyfarthing-dist/scripts/story/README.md +1 -1
  97. package/pennyfarthing-dist/scripts/test/test-setup.sh +1 -1
  98. package/pennyfarthing-dist/skills/jira/SKILL.md +107 -408
  99. package/pennyfarthing-dist/skills/skill-registry.yaml +21 -12
  100. package/pennyfarthing-dist/skills/sprint/skill.md +386 -68
  101. package/pennyfarthing-dist/skills/story/skill.md +14 -206
  102. package/pennyfarthing-dist/templates/settings.local.json.template +9 -1
  103. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +1 -1
  104. package/pennyfarthing-dist/workflows/git-cleanup.yaml +1 -1
  105. package/pennyfarthing-dist/workflows/project-setup/steps/step-10-complete.md +1 -1
  106. package/pennyfarthing_scripts/README.md +66 -0
  107. package/pennyfarthing_scripts/__init__.py +17 -0
  108. package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  109. package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  110. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  111. package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
  112. package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
  113. package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
  114. package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
  115. package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
  116. package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
  117. package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
  118. package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
  119. package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
  120. package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
  121. package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
  122. package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
  123. package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
  124. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  125. package/pennyfarthing_scripts/bellmode_hook.py +154 -0
  126. package/pennyfarthing_scripts/brownfield/__init__.py +35 -0
  127. package/pennyfarthing_scripts/brownfield/__main__.py +7 -0
  128. package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
  129. package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
  130. package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
  131. package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
  132. package/pennyfarthing_scripts/brownfield/cli.py +131 -0
  133. package/pennyfarthing_scripts/brownfield/discover.py +753 -0
  134. package/pennyfarthing_scripts/cli.py +184 -0
  135. package/pennyfarthing_scripts/common/__init__.py +49 -0
  136. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
  137. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  138. package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
  139. package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
  140. package/pennyfarthing_scripts/common/config.py +92 -0
  141. package/pennyfarthing_scripts/common/output.py +180 -0
  142. package/pennyfarthing_scripts/common/themes.py +253 -0
  143. package/pennyfarthing_scripts/config.py +21 -0
  144. package/pennyfarthing_scripts/context.py +414 -0
  145. package/pennyfarthing_scripts/git/__init__.py +29 -0
  146. package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
  147. package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
  148. package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
  149. package/pennyfarthing_scripts/git/create_branches.py +439 -0
  150. package/pennyfarthing_scripts/git/status_all.py +310 -0
  151. package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +7 -0
  152. package/pennyfarthing_scripts/hooks.py +454 -0
  153. package/pennyfarthing_scripts/hotspots/__init__.py +31 -0
  154. package/pennyfarthing_scripts/hotspots/__main__.py +6 -0
  155. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
  156. package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
  157. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
  158. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
  159. package/pennyfarthing_scripts/hotspots/__pycache__/formatters.cpython-314.pyc +0 -0
  160. package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
  161. package/pennyfarthing_scripts/hotspots/analyze.py +472 -0
  162. package/pennyfarthing_scripts/hotspots/cli.py +152 -0
  163. package/pennyfarthing_scripts/hotspots/formatters.py +109 -0
  164. package/pennyfarthing_scripts/hotspots/models.py +60 -0
  165. package/pennyfarthing_scripts/jira/__init__.py +99 -0
  166. package/pennyfarthing_scripts/jira/__main__.py +10 -0
  167. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  168. package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
  169. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  170. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
  171. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  172. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
  174. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
  179. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  180. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
  181. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
  182. package/pennyfarthing_scripts/jira/bidirectional.py +561 -0
  183. package/pennyfarthing_scripts/jira/claim.py +211 -0
  184. package/pennyfarthing_scripts/jira/cli.py +351 -0
  185. package/pennyfarthing_scripts/jira/client.py +762 -0
  186. package/pennyfarthing_scripts/jira/create.py +267 -0
  187. package/pennyfarthing_scripts/jira/epic.py +176 -0
  188. package/pennyfarthing_scripts/jira/operations.py +124 -0
  189. package/pennyfarthing_scripts/jira/reconcile.py +277 -0
  190. package/pennyfarthing_scripts/jira/story.py +219 -0
  191. package/pennyfarthing_scripts/jira/sync.py +350 -0
  192. package/pennyfarthing_scripts/jira_bidirectional_sync.py +37 -0
  193. package/pennyfarthing_scripts/jira_epic_creation.py +30 -0
  194. package/pennyfarthing_scripts/jira_sync.py +36 -0
  195. package/pennyfarthing_scripts/jira_sync_story.py +30 -0
  196. package/pennyfarthing_scripts/migration/__init__.py +39 -0
  197. package/pennyfarthing_scripts/migration/__main__.py +10 -0
  198. package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
  199. package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
  200. package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
  201. package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
  202. package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
  203. package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
  204. package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
  205. package/pennyfarthing_scripts/migration/cli.py +304 -0
  206. package/pennyfarthing_scripts/migration/session.py +384 -0
  207. package/pennyfarthing_scripts/migration/skill.py +188 -0
  208. package/pennyfarthing_scripts/migration/step.py +229 -0
  209. package/pennyfarthing_scripts/migration/validate.py +282 -0
  210. package/pennyfarthing_scripts/output.py +37 -0
  211. package/pennyfarthing_scripts/patch_mode.py +449 -0
  212. package/pennyfarthing_scripts/preflight/__init__.py +17 -0
  213. package/pennyfarthing_scripts/preflight/__main__.py +10 -0
  214. package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
  215. package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
  216. package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
  217. package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
  218. package/pennyfarthing_scripts/preflight/cli.py +141 -0
  219. package/pennyfarthing_scripts/preflight/finish.py +382 -0
  220. package/pennyfarthing_scripts/pretooluse_hook.py +193 -0
  221. package/pennyfarthing_scripts/prime/__init__.py +125 -0
  222. package/pennyfarthing_scripts/prime/__main__.py +8 -0
  223. package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  224. package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
  225. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  226. package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
  227. package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
  228. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  229. package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
  230. package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  231. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  232. package/pennyfarthing_scripts/prime/cli.py +645 -0
  233. package/pennyfarthing_scripts/prime/loader.py +239 -0
  234. package/pennyfarthing_scripts/prime/models.py +206 -0
  235. package/pennyfarthing_scripts/prime/persona.py +309 -0
  236. package/pennyfarthing_scripts/prime/session.py +183 -0
  237. package/pennyfarthing_scripts/prime/tiers.py +201 -0
  238. package/pennyfarthing_scripts/prime/workflow.py +277 -0
  239. package/pennyfarthing_scripts/schema_validation_hook.py +306 -0
  240. package/pennyfarthing_scripts/sprint/__init__.py +66 -0
  241. package/pennyfarthing_scripts/sprint/__main__.py +10 -0
  242. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  243. package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
  244. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  245. package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  246. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  247. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  248. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  249. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
  250. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
  251. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  252. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  253. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  254. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  255. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  256. package/pennyfarthing_scripts/sprint/archive.py +165 -0
  257. package/pennyfarthing_scripts/sprint/archive_epic.py +408 -0
  258. package/pennyfarthing_scripts/sprint/cli.py +1863 -0
  259. package/pennyfarthing_scripts/sprint/epic_add.py +173 -0
  260. package/pennyfarthing_scripts/sprint/import_epic.py +431 -0
  261. package/pennyfarthing_scripts/sprint/loader.py +237 -0
  262. package/pennyfarthing_scripts/sprint/status.py +122 -0
  263. package/pennyfarthing_scripts/sprint/story_add.py +187 -0
  264. package/pennyfarthing_scripts/sprint/story_update.py +181 -0
  265. package/pennyfarthing_scripts/sprint/validate_cmd.py +307 -0
  266. package/pennyfarthing_scripts/sprint/validator.py +580 -0
  267. package/pennyfarthing_scripts/sprint/work.py +208 -0
  268. package/pennyfarthing_scripts/sprint/yaml_io.py +367 -0
  269. package/pennyfarthing_scripts/story/__init__.py +67 -0
  270. package/pennyfarthing_scripts/story/__main__.py +10 -0
  271. package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
  272. package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
  273. package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
  274. package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
  275. package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
  276. package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
  277. package/pennyfarthing_scripts/story/cli.py +105 -0
  278. package/pennyfarthing_scripts/story/create.py +167 -0
  279. package/pennyfarthing_scripts/story/size.py +113 -0
  280. package/pennyfarthing_scripts/story/template.py +151 -0
  281. package/pennyfarthing_scripts/swebench.py +216 -0
  282. package/pennyfarthing_scripts/tests/__init__.py +1 -0
  283. package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
  284. package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  285. package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
  286. package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
  287. package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
  288. package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
  289. package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
  290. package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
  291. package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
  292. package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
  293. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
  294. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
  295. package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
  296. package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
  297. package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
  298. package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
  299. package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
  300. package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
  301. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
  302. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  303. package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
  304. package/pennyfarthing_scripts/tests/conftest.py +106 -0
  305. package/pennyfarthing_scripts/tests/test_brownfield.py +842 -0
  306. package/pennyfarthing_scripts/tests/test_cli_modules.py +245 -0
  307. package/pennyfarthing_scripts/tests/test_common.py +180 -0
  308. package/pennyfarthing_scripts/tests/test_git_utils.py +866 -0
  309. package/pennyfarthing_scripts/tests/test_jira_package.py +334 -0
  310. package/pennyfarthing_scripts/tests/test_package_structure.py +372 -0
  311. package/pennyfarthing_scripts/tests/test_patch_mode.py +830 -0
  312. package/pennyfarthing_scripts/tests/test_prime.py +1050 -0
  313. package/pennyfarthing_scripts/tests/test_sprint_package.py +402 -0
  314. package/pennyfarthing_scripts/tests/test_sprint_validator.py +731 -0
  315. package/pennyfarthing_scripts/tests/test_story_add.py +921 -0
  316. package/pennyfarthing_scripts/tests/test_story_package.py +156 -0
  317. package/pennyfarthing_scripts/tests/test_story_update.py +769 -0
  318. package/pennyfarthing_scripts/tests/test_tiers.py +1090 -0
  319. package/pennyfarthing_scripts/tests/test_token_counting.py +559 -0
  320. package/pennyfarthing_scripts/tests/test_validate_cmd.py +500 -0
  321. package/pennyfarthing_scripts/tests/test_workflow_check.py +341 -0
  322. package/pennyfarthing_scripts/tests/test_yaml_io.py +815 -0
  323. package/pennyfarthing_scripts/welcome_hook.py +157 -0
  324. package/pennyfarthing_scripts/workflow.py +287 -0
  325. package/scripts/postinstall.cjs +34 -0
  326. package/dist/cli/commands/cyclist.d.ts.map +0 -1
  327. package/dist/cli/commands/cyclist.js.map +0 -1
  328. package/dist/cli/commands/cyclist.test.js.map +0 -1
  329. package/dist/cli/commands/doctor.js.map +0 -1
  330. package/dist/cli/commands/init.js.map +0 -1
  331. package/dist/cli/utils/settings.js.map +0 -1
  332. package/dist/cli/utils/themes.d.ts.map +0 -1
  333. package/dist/scripts/generate-report.js.map +0 -1
  334. package/dist/scripts/generate-spider-report.js.map +0 -1
  335. package/dist/scripts/generate-spider.d.ts.map +0 -1
  336. package/dist/scripts/generate-spider.js.map +0 -1
  337. package/dist/scripts/generate-spider.test.js.map +0 -1
  338. package/pennyfarthing-dist/scripts/jira/jira-lib.sh +0 -464
  339. package/pennyfarthing-dist/scripts/jira/jira-sync.sh +0 -16
  340. package/pennyfarthing-dist/scripts/jira/sync-epic-to-jira.sh +0 -16
  341. package/pennyfarthing-dist/scripts/sprint/archive-story.sh +0 -133
  342. package/pennyfarthing-dist/scripts/sprint/available-stories.sh +0 -91
  343. package/pennyfarthing-dist/scripts/sprint/check-story.sh +0 -158
  344. package/pennyfarthing-dist/scripts/sprint/get-epic-field.sh +0 -52
  345. package/pennyfarthing-dist/scripts/sprint/get-story-field.sh +0 -63
  346. package/pennyfarthing-dist/scripts/sprint/list-future.sh +0 -145
  347. package/pennyfarthing-dist/scripts/sprint/new-sprint.sh +0 -110
  348. package/pennyfarthing-dist/scripts/sprint/promote-epic.sh +0 -148
  349. package/pennyfarthing-dist/scripts/sprint/sprint-common.sh +0 -415
  350. package/pennyfarthing-dist/scripts/sprint/sprint-info.sh +0 -33
  351. package/pennyfarthing-dist/scripts/sprint/sprint-metrics.sh +0 -230
  352. package/pennyfarthing-dist/scripts/sprint/sprint-status.sh +0 -134
  353. package/pennyfarthing-dist/scripts/sprint/validate-sprint-yaml.sh +0 -139
  354. package/pennyfarthing-dist/skills/sprint/scripts/archive-story.sh +0 -101
  355. package/pennyfarthing-dist/skills/sprint/scripts/available-stories.sh +0 -97
  356. package/pennyfarthing-dist/skills/sprint/scripts/check-story.sh +0 -164
  357. package/pennyfarthing-dist/skills/sprint/scripts/create-jira-epic.sh +0 -101
  358. package/pennyfarthing-dist/skills/sprint/scripts/new-sprint.sh +0 -116
  359. package/pennyfarthing-dist/skills/sprint/scripts/promote-epic.sh +0 -164
  360. package/pennyfarthing-dist/skills/sprint/scripts/sprint-info.sh +0 -39
  361. package/pennyfarthing-dist/skills/sprint/scripts/sprint-status.sh +0 -147
  362. package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +0 -93
  363. /package/{bin → packages/core/bin}/pennyfarthing.js +0 -0
  364. /package/{dist → packages/core/dist}/bmad/context-reader.d.ts +0 -0
  365. /package/{dist → packages/core/dist}/bmad/context-reader.d.ts.map +0 -0
  366. /package/{dist → packages/core/dist}/bmad/context-reader.js +0 -0
  367. /package/{dist → packages/core/dist}/bmad/context-reader.js.map +0 -0
  368. /package/{dist → packages/core/dist}/bmad/context-reader.test.d.ts +0 -0
  369. /package/{dist → packages/core/dist}/bmad/context-reader.test.d.ts.map +0 -0
  370. /package/{dist → packages/core/dist}/bmad/context-reader.test.js +0 -0
  371. /package/{dist → packages/core/dist}/bmad/context-reader.test.js.map +0 -0
  372. /package/{dist → packages/core/dist}/bmad/epics-parser.d.ts +0 -0
  373. /package/{dist → packages/core/dist}/bmad/epics-parser.d.ts.map +0 -0
  374. /package/{dist → packages/core/dist}/bmad/epics-parser.js +0 -0
  375. /package/{dist → packages/core/dist}/bmad/epics-parser.js.map +0 -0
  376. /package/{dist → packages/core/dist}/bmad/epics-parser.test.d.ts +0 -0
  377. /package/{dist → packages/core/dist}/bmad/epics-parser.test.d.ts.map +0 -0
  378. /package/{dist → packages/core/dist}/bmad/epics-parser.test.js +0 -0
  379. /package/{dist → packages/core/dist}/bmad/epics-parser.test.js.map +0 -0
  380. /package/{dist → packages/core/dist}/bmad/index.d.ts +0 -0
  381. /package/{dist → packages/core/dist}/bmad/index.d.ts.map +0 -0
  382. /package/{dist → packages/core/dist}/bmad/index.js +0 -0
  383. /package/{dist → packages/core/dist}/bmad/index.js.map +0 -0
  384. /package/{dist → packages/core/dist}/bmad/status-sync.d.ts +0 -0
  385. /package/{dist → packages/core/dist}/bmad/status-sync.d.ts.map +0 -0
  386. /package/{dist → packages/core/dist}/bmad/status-sync.js +0 -0
  387. /package/{dist → packages/core/dist}/bmad/status-sync.js.map +0 -0
  388. /package/{dist → packages/core/dist}/bmad/status-sync.test.d.ts +0 -0
  389. /package/{dist → packages/core/dist}/bmad/status-sync.test.d.ts.map +0 -0
  390. /package/{dist → packages/core/dist}/bmad/status-sync.test.js +0 -0
  391. /package/{dist → packages/core/dist}/bmad/status-sync.test.js.map +0 -0
  392. /package/{dist → packages/core/dist}/bmad/story-exporter.d.ts +0 -0
  393. /package/{dist → packages/core/dist}/bmad/story-exporter.d.ts.map +0 -0
  394. /package/{dist → packages/core/dist}/bmad/story-exporter.js +0 -0
  395. /package/{dist → packages/core/dist}/bmad/story-exporter.js.map +0 -0
  396. /package/{dist → packages/core/dist}/bmad/story-exporter.test.d.ts +0 -0
  397. /package/{dist → packages/core/dist}/bmad/story-exporter.test.d.ts.map +0 -0
  398. /package/{dist → packages/core/dist}/bmad/story-exporter.test.js +0 -0
  399. /package/{dist → packages/core/dist}/bmad/story-exporter.test.js.map +0 -0
  400. /package/{dist → packages/core/dist}/bmad/story-parser.d.ts +0 -0
  401. /package/{dist → packages/core/dist}/bmad/story-parser.d.ts.map +0 -0
  402. /package/{dist → packages/core/dist}/bmad/story-parser.js +0 -0
  403. /package/{dist → packages/core/dist}/bmad/story-parser.js.map +0 -0
  404. /package/{dist → packages/core/dist}/bmad/story-parser.test.d.ts +0 -0
  405. /package/{dist → packages/core/dist}/bmad/story-parser.test.d.ts.map +0 -0
  406. /package/{dist → packages/core/dist}/bmad/story-parser.test.js +0 -0
  407. /package/{dist → packages/core/dist}/bmad/story-parser.test.js.map +0 -0
  408. /package/{dist → packages/core/dist}/cli/commands/command.d.ts +0 -0
  409. /package/{dist → packages/core/dist}/cli/commands/command.d.ts.map +0 -0
  410. /package/{dist → packages/core/dist}/cli/commands/command.js +0 -0
  411. /package/{dist → packages/core/dist}/cli/commands/command.js.map +0 -0
  412. /package/{dist → packages/core/dist}/cli/commands/cyclist.test.d.ts +0 -0
  413. /package/{dist → packages/core/dist}/cli/commands/cyclist.test.d.ts.map +0 -0
  414. /package/{dist → packages/core/dist}/cli/commands/doctor-legacy.test.d.ts +0 -0
  415. /package/{dist → packages/core/dist}/cli/commands/doctor-legacy.test.d.ts.map +0 -0
  416. /package/{dist → packages/core/dist}/cli/commands/e2e-fresh-install.test.d.ts +0 -0
  417. /package/{dist → packages/core/dist}/cli/commands/e2e-fresh-install.test.d.ts.map +0 -0
  418. /package/{dist → packages/core/dist}/cli/commands/e2e-upgrade.test.d.ts +0 -0
  419. /package/{dist → packages/core/dist}/cli/commands/e2e-upgrade.test.d.ts.map +0 -0
  420. /package/{dist → packages/core/dist}/cli/commands/init-consolidation.test.d.ts +0 -0
  421. /package/{dist → packages/core/dist}/cli/commands/init-consolidation.test.d.ts.map +0 -0
  422. /package/{dist → packages/core/dist}/cli/commands/init-consolidation.test.js +0 -0
  423. /package/{dist → packages/core/dist}/cli/commands/init-consolidation.test.js.map +0 -0
  424. /package/{dist → packages/core/dist}/cli/commands/init.d.ts +0 -0
  425. /package/{dist → packages/core/dist}/cli/commands/persona-config-consolidation.test.d.ts +0 -0
  426. /package/{dist → packages/core/dist}/cli/commands/persona-config-consolidation.test.d.ts.map +0 -0
  427. /package/{dist → packages/core/dist}/cli/commands/persona-config-consolidation.test.js +0 -0
  428. /package/{dist → packages/core/dist}/cli/commands/persona-config-consolidation.test.js.map +0 -0
  429. /package/{dist → packages/core/dist}/cli/commands/skill.d.ts +0 -0
  430. /package/{dist → packages/core/dist}/cli/commands/skill.d.ts.map +0 -0
  431. /package/{dist → packages/core/dist}/cli/commands/skill.js +0 -0
  432. /package/{dist → packages/core/dist}/cli/commands/skill.js.map +0 -0
  433. /package/{dist → packages/core/dist}/cli/commands/theme.d.ts +0 -0
  434. /package/{dist → packages/core/dist}/cli/commands/theme.d.ts.map +0 -0
  435. /package/{dist → packages/core/dist}/cli/commands/theme.js +0 -0
  436. /package/{dist → packages/core/dist}/cli/commands/theme.js.map +0 -0
  437. /package/{dist → packages/core/dist}/cli/commands/uninstall.d.ts +0 -0
  438. /package/{dist → packages/core/dist}/cli/commands/uninstall.d.ts.map +0 -0
  439. /package/{dist → packages/core/dist}/cli/commands/uninstall.js +0 -0
  440. /package/{dist → packages/core/dist}/cli/commands/uninstall.js.map +0 -0
  441. /package/{dist → packages/core/dist}/cli/commands/update-consolidation.test.d.ts +0 -0
  442. /package/{dist → packages/core/dist}/cli/commands/update-consolidation.test.d.ts.map +0 -0
  443. /package/{dist → packages/core/dist}/cli/commands/update-consolidation.test.js +0 -0
  444. /package/{dist → packages/core/dist}/cli/commands/update-consolidation.test.js.map +0 -0
  445. /package/{dist → packages/core/dist}/cli/commands/update.d.ts +0 -0
  446. /package/{dist → packages/core/dist}/cli/commands/version.d.ts +0 -0
  447. /package/{dist → packages/core/dist}/cli/commands/version.d.ts.map +0 -0
  448. /package/{dist → packages/core/dist}/cli/commands/version.js +0 -0
  449. /package/{dist → packages/core/dist}/cli/commands/version.js.map +0 -0
  450. /package/{dist → packages/core/dist}/cli/customization.test.d.ts +0 -0
  451. /package/{dist → packages/core/dist}/cli/customization.test.d.ts.map +0 -0
  452. /package/{dist → packages/core/dist}/cli/customization.test.js +0 -0
  453. /package/{dist → packages/core/dist}/cli/customization.test.js.map +0 -0
  454. /package/{dist → packages/core/dist}/cli/cyclist-migration.test.d.ts +0 -0
  455. /package/{dist → packages/core/dist}/cli/cyclist-migration.test.d.ts.map +0 -0
  456. /package/{dist → packages/core/dist}/cli/cyclist-migration.test.js +0 -0
  457. /package/{dist → packages/core/dist}/cli/cyclist-migration.test.js.map +0 -0
  458. /package/{dist → packages/core/dist}/cli/index.d.ts +0 -0
  459. /package/{dist → packages/core/dist}/cli/index.d.ts.map +0 -0
  460. /package/{dist → packages/core/dist}/cli/index.js +0 -0
  461. /package/{dist → packages/core/dist}/cli/index.js.map +0 -0
  462. /package/{dist → packages/core/dist}/cli/ocean-profiles.test.d.ts +0 -0
  463. /package/{dist → packages/core/dist}/cli/ocean-profiles.test.d.ts.map +0 -0
  464. /package/{dist → packages/core/dist}/cli/theme-maker.test.d.ts +0 -0
  465. /package/{dist → packages/core/dist}/cli/theme-maker.test.d.ts.map +0 -0
  466. /package/{dist → packages/core/dist}/cli/theme-maker.test.js +0 -0
  467. /package/{dist → packages/core/dist}/cli/theme-maker.test.js.map +0 -0
  468. /package/{dist → packages/core/dist}/cli/utils/constants.d.ts +0 -0
  469. /package/{dist → packages/core/dist}/cli/utils/constants.d.ts.map +0 -0
  470. /package/{dist → packages/core/dist}/cli/utils/constants.js +0 -0
  471. /package/{dist → packages/core/dist}/cli/utils/constants.js.map +0 -0
  472. /package/{dist → packages/core/dist}/cli/utils/logger.d.ts +0 -0
  473. /package/{dist → packages/core/dist}/cli/utils/logger.d.ts.map +0 -0
  474. /package/{dist → packages/core/dist}/cli/utils/logger.js +0 -0
  475. /package/{dist → packages/core/dist}/cli/utils/logger.js.map +0 -0
  476. /package/{dist → packages/core/dist}/cli/utils/manifest.d.ts +0 -0
  477. /package/{dist → packages/core/dist}/cli/utils/manifest.d.ts.map +0 -0
  478. /package/{dist → packages/core/dist}/cli/utils/manifest.js +0 -0
  479. /package/{dist → packages/core/dist}/cli/utils/manifest.js.map +0 -0
  480. /package/{dist → packages/core/dist}/cli/utils/node-modules.d.ts +0 -0
  481. /package/{dist → packages/core/dist}/cli/utils/node-modules.d.ts.map +0 -0
  482. /package/{dist → packages/core/dist}/cli/utils/node-modules.js +0 -0
  483. /package/{dist → packages/core/dist}/cli/utils/node-modules.js.map +0 -0
  484. /package/{dist → packages/core/dist}/cli/utils/prompts.d.ts +0 -0
  485. /package/{dist → packages/core/dist}/cli/utils/prompts.d.ts.map +0 -0
  486. /package/{dist → packages/core/dist}/cli/utils/prompts.js +0 -0
  487. /package/{dist → packages/core/dist}/cli/utils/prompts.js.map +0 -0
  488. /package/{dist → packages/core/dist}/cli/utils/settings-consolidation.test.d.ts +0 -0
  489. /package/{dist → packages/core/dist}/cli/utils/settings-consolidation.test.d.ts.map +0 -0
  490. /package/{dist → packages/core/dist}/cli/utils/settings-consolidation.test.js +0 -0
  491. /package/{dist → packages/core/dist}/cli/utils/settings-consolidation.test.js.map +0 -0
  492. /package/{dist → packages/core/dist}/cli/utils/settings.d.ts +0 -0
  493. /package/{dist → packages/core/dist}/cli/utils/symlinks.d.ts +0 -0
  494. /package/{dist → packages/core/dist}/cli/utils/symlinks.d.ts.map +0 -0
  495. /package/{dist → packages/core/dist}/cli/utils/symlinks.js +0 -0
  496. /package/{dist → packages/core/dist}/cli/utils/symlinks.js.map +0 -0
  497. /package/{dist → packages/core/dist}/cli/utils/themes.js +0 -0
  498. /package/{dist → packages/core/dist}/cli/utils/themes.test.d.ts +0 -0
  499. /package/{dist → packages/core/dist}/cli/utils/themes.test.d.ts.map +0 -0
  500. /package/{dist → packages/core/dist}/cli/utils/themes.test.js +0 -0
  501. /package/{dist → packages/core/dist}/cli/utils/themes.test.js.map +0 -0
  502. /package/{dist → packages/core/dist}/cli/utils/version.d.ts +0 -0
  503. /package/{dist → packages/core/dist}/cli/utils/version.d.ts.map +0 -0
  504. /package/{dist → packages/core/dist}/cli/utils/version.js +0 -0
  505. /package/{dist → packages/core/dist}/cli/utils/version.js.map +0 -0
  506. /package/{dist → packages/core/dist}/cli/workspace.test.d.ts +0 -0
  507. /package/{dist → packages/core/dist}/cli/workspace.test.d.ts.map +0 -0
  508. /package/{dist → packages/core/dist}/cli/workspace.test.js +0 -0
  509. /package/{dist → packages/core/dist}/cli/workspace.test.js.map +0 -0
  510. /package/{dist → packages/core/dist}/index.d.ts +0 -0
  511. /package/{dist → packages/core/dist}/index.d.ts.map +0 -0
  512. /package/{dist → packages/core/dist}/index.js +0 -0
  513. /package/{dist → packages/core/dist}/index.js.map +0 -0
  514. /package/{dist → packages/core/dist}/jira/jira-epic-creation.d.ts +0 -0
  515. /package/{dist → packages/core/dist}/jira/jira-epic-creation.d.ts.map +0 -0
  516. /package/{dist → packages/core/dist}/jira/jira-epic-creation.js +0 -0
  517. /package/{dist → packages/core/dist}/jira/jira-epic-creation.js.map +0 -0
  518. /package/{dist → packages/core/dist}/jira/jira-epic-creation.test.d.ts +0 -0
  519. /package/{dist → packages/core/dist}/jira/jira-epic-creation.test.d.ts.map +0 -0
  520. /package/{dist → packages/core/dist}/jira/jira-epic-creation.test.js +0 -0
  521. /package/{dist → packages/core/dist}/jira/jira-epic-creation.test.js.map +0 -0
  522. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.d.ts +0 -0
  523. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.d.ts.map +0 -0
  524. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.js +0 -0
  525. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.js.map +0 -0
  526. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.test.d.ts +0 -0
  527. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.test.d.ts.map +0 -0
  528. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.test.js +0 -0
  529. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.test.js.map +0 -0
  530. /package/{dist → packages/core/dist}/permissions/index.d.ts +0 -0
  531. /package/{dist → packages/core/dist}/permissions/index.d.ts.map +0 -0
  532. /package/{dist → packages/core/dist}/permissions/index.js +0 -0
  533. /package/{dist → packages/core/dist}/permissions/index.js.map +0 -0
  534. /package/{dist → packages/core/dist}/permissions/permission-schema.d.ts +0 -0
  535. /package/{dist → packages/core/dist}/permissions/permission-schema.d.ts.map +0 -0
  536. /package/{dist → packages/core/dist}/permissions/permission-schema.js +0 -0
  537. /package/{dist → packages/core/dist}/permissions/permission-schema.js.map +0 -0
  538. /package/{dist → packages/core/dist}/permissions/permission-schema.test.d.ts +0 -0
  539. /package/{dist → packages/core/dist}/permissions/permission-schema.test.d.ts.map +0 -0
  540. /package/{dist → packages/core/dist}/permissions/permission-schema.test.js +0 -0
  541. /package/{dist → packages/core/dist}/permissions/permission-schema.test.js.map +0 -0
  542. /package/{dist → packages/core/dist}/scripts/add-ocean-profiles.d.ts +0 -0
  543. /package/{dist → packages/core/dist}/scripts/add-ocean-profiles.d.ts.map +0 -0
  544. /package/{dist → packages/core/dist}/scripts/add-ocean-profiles.js +0 -0
  545. /package/{dist → packages/core/dist}/scripts/add-ocean-profiles.js.map +0 -0
  546. /package/{dist → packages/core/dist}/scripts/benchmark-integration.d.ts +0 -0
  547. /package/{dist → packages/core/dist}/scripts/benchmark-integration.d.ts.map +0 -0
  548. /package/{dist → packages/core/dist}/scripts/benchmark-integration.js +0 -0
  549. /package/{dist → packages/core/dist}/scripts/benchmark-integration.js.map +0 -0
  550. /package/{dist → packages/core/dist}/scripts/benchmark-integration.test.d.ts +0 -0
  551. /package/{dist → packages/core/dist}/scripts/benchmark-integration.test.d.ts.map +0 -0
  552. /package/{dist → packages/core/dist}/scripts/benchmark-integration.test.js +0 -0
  553. /package/{dist → packages/core/dist}/scripts/benchmark-integration.test.js.map +0 -0
  554. /package/{dist → packages/core/dist}/scripts/debugging-scenarios.test.d.ts +0 -0
  555. /package/{dist → packages/core/dist}/scripts/debugging-scenarios.test.d.ts.map +0 -0
  556. /package/{dist → packages/core/dist}/scripts/debugging-scenarios.test.js +0 -0
  557. /package/{dist → packages/core/dist}/scripts/debugging-scenarios.test.js.map +0 -0
  558. /package/{dist → packages/core/dist}/scripts/generate-all-spiders.d.ts +0 -0
  559. /package/{dist → packages/core/dist}/scripts/generate-all-spiders.d.ts.map +0 -0
  560. /package/{dist → packages/core/dist}/scripts/generate-all-spiders.js +0 -0
  561. /package/{dist → packages/core/dist}/scripts/generate-all-spiders.js.map +0 -0
  562. /package/{dist → packages/core/dist}/scripts/generate-report.d.ts +0 -0
  563. /package/{dist → packages/core/dist}/scripts/generate-report.test.d.ts +0 -0
  564. /package/{dist → packages/core/dist}/scripts/generate-report.test.d.ts.map +0 -0
  565. /package/{dist → packages/core/dist}/scripts/generate-report.test.js +0 -0
  566. /package/{dist → packages/core/dist}/scripts/generate-report.test.js.map +0 -0
  567. /package/{dist → packages/core/dist}/scripts/generate-spider-report.d.ts +0 -0
  568. /package/{dist → packages/core/dist}/scripts/generate-spider-report.test.d.ts +0 -0
  569. /package/{dist → packages/core/dist}/scripts/generate-spider-report.test.d.ts.map +0 -0
  570. /package/{dist → packages/core/dist}/scripts/generate-spider-report.test.js +0 -0
  571. /package/{dist → packages/core/dist}/scripts/generate-spider-report.test.js.map +0 -0
  572. /package/{dist → packages/core/dist}/scripts/generate-spider.d.ts +0 -0
  573. /package/{dist → packages/core/dist}/scripts/generate-spider.test.d.ts +0 -0
  574. /package/{dist → packages/core/dist}/scripts/generate-spider.test.d.ts.map +0 -0
  575. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.d.ts +0 -0
  576. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.d.ts.map +0 -0
  577. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.js +0 -0
  578. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.js.map +0 -0
  579. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.test.d.ts +0 -0
  580. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.test.d.ts.map +0 -0
  581. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.test.js +0 -0
  582. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.test.js.map +0 -0
  583. /package/{dist → packages/core/dist}/scripts/run-ci.test.d.ts +0 -0
  584. /package/{dist → packages/core/dist}/scripts/run-ci.test.d.ts.map +0 -0
  585. /package/{dist → packages/core/dist}/scripts/run-ci.test.js +0 -0
  586. /package/{dist → packages/core/dist}/scripts/run-ci.test.js.map +0 -0
  587. /package/{dist → packages/core/dist}/scripts/theme-detail.test.d.ts +0 -0
  588. /package/{dist → packages/core/dist}/scripts/theme-detail.test.d.ts.map +0 -0
  589. /package/{dist → packages/core/dist}/scripts/theme-detail.test.js +0 -0
  590. /package/{dist → packages/core/dist}/scripts/theme-detail.test.js.map +0 -0
  591. /package/{dist → packages/core/dist}/scripts/validate-ocean-profiles.d.ts +0 -0
  592. /package/{dist → packages/core/dist}/scripts/validate-ocean-profiles.d.ts.map +0 -0
  593. /package/{dist → packages/core/dist}/scripts/validate-ocean-profiles.js +0 -0
  594. /package/{dist → packages/core/dist}/scripts/validate-ocean-profiles.js.map +0 -0
  595. /package/{dist → packages/core/dist}/workflow/complete-step-integration.test.d.ts +0 -0
  596. /package/{dist → packages/core/dist}/workflow/complete-step-integration.test.d.ts.map +0 -0
  597. /package/{dist → packages/core/dist}/workflow/complete-step-integration.test.js +0 -0
  598. /package/{dist → packages/core/dist}/workflow/complete-step-integration.test.js.map +0 -0
  599. /package/{dist → packages/core/dist}/workflow/gate-handler.d.ts +0 -0
  600. /package/{dist → packages/core/dist}/workflow/gate-handler.d.ts.map +0 -0
  601. /package/{dist → packages/core/dist}/workflow/gate-handler.js +0 -0
  602. /package/{dist → packages/core/dist}/workflow/gate-handler.js.map +0 -0
  603. /package/{dist → packages/core/dist}/workflow/gate-handler.test.d.ts +0 -0
  604. /package/{dist → packages/core/dist}/workflow/gate-handler.test.d.ts.map +0 -0
  605. /package/{dist → packages/core/dist}/workflow/gate-handler.test.js +0 -0
  606. /package/{dist → packages/core/dist}/workflow/gate-handler.test.js.map +0 -0
  607. /package/{dist → packages/core/dist}/workflow/generic-sm-finish.d.ts +0 -0
  608. /package/{dist → packages/core/dist}/workflow/generic-sm-finish.d.ts.map +0 -0
  609. /package/{dist → packages/core/dist}/workflow/generic-sm-finish.js +0 -0
  610. /package/{dist → packages/core/dist}/workflow/generic-sm-finish.js.map +0 -0
  611. /package/{dist → packages/core/dist}/workflow/generic-sm-setup.d.ts +0 -0
  612. /package/{dist → packages/core/dist}/workflow/generic-sm-setup.d.ts.map +0 -0
  613. /package/{dist → packages/core/dist}/workflow/generic-sm-setup.js +0 -0
  614. /package/{dist → packages/core/dist}/workflow/generic-sm-setup.js.map +0 -0
  615. /package/{dist → packages/core/dist}/workflow/handoff.d.ts +0 -0
  616. /package/{dist → packages/core/dist}/workflow/handoff.d.ts.map +0 -0
  617. /package/{dist → packages/core/dist}/workflow/handoff.js +0 -0
  618. /package/{dist → packages/core/dist}/workflow/handoff.js.map +0 -0
  619. /package/{dist → packages/core/dist}/workflow/handoff.test.d.ts +0 -0
  620. /package/{dist → packages/core/dist}/workflow/handoff.test.d.ts.map +0 -0
  621. /package/{dist → packages/core/dist}/workflow/handoff.test.js +0 -0
  622. /package/{dist → packages/core/dist}/workflow/handoff.test.js.map +0 -0
  623. /package/{dist → packages/core/dist}/workflow/index.d.ts +0 -0
  624. /package/{dist → packages/core/dist}/workflow/index.d.ts.map +0 -0
  625. /package/{dist → packages/core/dist}/workflow/index.js +0 -0
  626. /package/{dist → packages/core/dist}/workflow/index.js.map +0 -0
  627. /package/{dist → packages/core/dist}/workflow/session-state.d.ts +0 -0
  628. /package/{dist → packages/core/dist}/workflow/session-state.d.ts.map +0 -0
  629. /package/{dist → packages/core/dist}/workflow/session-state.js +0 -0
  630. /package/{dist → packages/core/dist}/workflow/session-state.js.map +0 -0
  631. /package/{dist → packages/core/dist}/workflow/session-state.test.d.ts +0 -0
  632. /package/{dist → packages/core/dist}/workflow/session-state.test.d.ts.map +0 -0
  633. /package/{dist → packages/core/dist}/workflow/session-state.test.js +0 -0
  634. /package/{dist → packages/core/dist}/workflow/session-state.test.js.map +0 -0
  635. /package/{dist → packages/core/dist}/workflow/sm-subagents.test.d.ts +0 -0
  636. /package/{dist → packages/core/dist}/workflow/sm-subagents.test.d.ts.map +0 -0
  637. /package/{dist → packages/core/dist}/workflow/sm-subagents.test.js +0 -0
  638. /package/{dist → packages/core/dist}/workflow/sm-subagents.test.js.map +0 -0
  639. /package/{dist → packages/core/dist}/workflow/step-parser.d.ts +0 -0
  640. /package/{dist → packages/core/dist}/workflow/step-parser.d.ts.map +0 -0
  641. /package/{dist → packages/core/dist}/workflow/step-parser.js +0 -0
  642. /package/{dist → packages/core/dist}/workflow/step-parser.js.map +0 -0
  643. /package/{dist → packages/core/dist}/workflow/step-parser.test.d.ts +0 -0
  644. /package/{dist → packages/core/dist}/workflow/step-parser.test.d.ts.map +0 -0
  645. /package/{dist → packages/core/dist}/workflow/step-parser.test.js +0 -0
  646. /package/{dist → packages/core/dist}/workflow/step-parser.test.js.map +0 -0
  647. /package/{dist → packages/core/dist}/workflow/story-workflow-routing.test.d.ts +0 -0
  648. /package/{dist → packages/core/dist}/workflow/story-workflow-routing.test.d.ts.map +0 -0
  649. /package/{dist → packages/core/dist}/workflow/story-workflow-routing.test.js +0 -0
  650. /package/{dist → packages/core/dist}/workflow/story-workflow-routing.test.js.map +0 -0
  651. /package/{dist → packages/core/dist}/workflow/test-cache.d.ts +0 -0
  652. /package/{dist → packages/core/dist}/workflow/test-cache.d.ts.map +0 -0
  653. /package/{dist → packages/core/dist}/workflow/test-cache.js +0 -0
  654. /package/{dist → packages/core/dist}/workflow/test-cache.js.map +0 -0
  655. /package/{dist → packages/core/dist}/workflow/test-cache.test.d.ts +0 -0
  656. /package/{dist → packages/core/dist}/workflow/test-cache.test.d.ts.map +0 -0
  657. /package/{dist → packages/core/dist}/workflow/test-cache.test.js +0 -0
  658. /package/{dist → packages/core/dist}/workflow/test-cache.test.js.map +0 -0
  659. /package/{dist → packages/core/dist}/workflow/trimodal.d.ts +0 -0
  660. /package/{dist → packages/core/dist}/workflow/trimodal.d.ts.map +0 -0
  661. /package/{dist → packages/core/dist}/workflow/trimodal.js +0 -0
  662. /package/{dist → packages/core/dist}/workflow/trimodal.js.map +0 -0
  663. /package/{dist → packages/core/dist}/workflow/trimodal.test.d.ts +0 -0
  664. /package/{dist → packages/core/dist}/workflow/trimodal.test.d.ts.map +0 -0
  665. /package/{dist → packages/core/dist}/workflow/trimodal.test.js +0 -0
  666. /package/{dist → packages/core/dist}/workflow/trimodal.test.js.map +0 -0
  667. /package/{dist → packages/core/dist}/workflow/variable-resolver.d.ts +0 -0
  668. /package/{dist → packages/core/dist}/workflow/variable-resolver.d.ts.map +0 -0
  669. /package/{dist → packages/core/dist}/workflow/variable-resolver.js +0 -0
  670. /package/{dist → packages/core/dist}/workflow/variable-resolver.js.map +0 -0
  671. /package/{dist → packages/core/dist}/workflow/variable-resolver.test.d.ts +0 -0
  672. /package/{dist → packages/core/dist}/workflow/variable-resolver.test.d.ts.map +0 -0
  673. /package/{dist → packages/core/dist}/workflow/variable-resolver.test.js +0 -0
  674. /package/{dist → packages/core/dist}/workflow/variable-resolver.test.js.map +0 -0
  675. /package/{dist → packages/core/dist}/workflow/workflow-executor.d.ts +0 -0
  676. /package/{dist → packages/core/dist}/workflow/workflow-executor.d.ts.map +0 -0
  677. /package/{dist → packages/core/dist}/workflow/workflow-executor.js +0 -0
  678. /package/{dist → packages/core/dist}/workflow/workflow-executor.js.map +0 -0
  679. /package/{dist → packages/core/dist}/workflow/workflow-executor.test.d.ts +0 -0
  680. /package/{dist → packages/core/dist}/workflow/workflow-executor.test.d.ts.map +0 -0
  681. /package/{dist → packages/core/dist}/workflow/workflow-executor.test.js +0 -0
  682. /package/{dist → packages/core/dist}/workflow/workflow-executor.test.js.map +0 -0
  683. /package/{dist → packages/core/dist}/workflow/workflow-loader.d.ts +0 -0
  684. /package/{dist → packages/core/dist}/workflow/workflow-loader.d.ts.map +0 -0
  685. /package/{dist → packages/core/dist}/workflow/workflow-loader.js +0 -0
  686. /package/{dist → packages/core/dist}/workflow/workflow-loader.js.map +0 -0
  687. /package/{dist → packages/core/dist}/workflow/workflow-loader.test.d.ts +0 -0
  688. /package/{dist → packages/core/dist}/workflow/workflow-loader.test.d.ts.map +0 -0
  689. /package/{dist → packages/core/dist}/workflow/workflow-loader.test.js +0 -0
  690. /package/{dist → packages/core/dist}/workflow/workflow-loader.test.js.map +0 -0
  691. /package/{dist → packages/core/dist}/workflow/workflow-migration.test.d.ts +0 -0
  692. /package/{dist → packages/core/dist}/workflow/workflow-migration.test.d.ts.map +0 -0
  693. /package/{dist → packages/core/dist}/workflow/workflow-migration.test.js +0 -0
  694. /package/{dist → packages/core/dist}/workflow/workflow-migration.test.js.map +0 -0
  695. /package/{dist → packages/core/dist}/workflow/workflow-permissions.d.ts +0 -0
  696. /package/{dist → packages/core/dist}/workflow/workflow-permissions.d.ts.map +0 -0
  697. /package/{dist → packages/core/dist}/workflow/workflow-permissions.js +0 -0
  698. /package/{dist → packages/core/dist}/workflow/workflow-permissions.js.map +0 -0
  699. /package/{dist → packages/core/dist}/workflow/workflow-permissions.test.d.ts +0 -0
  700. /package/{dist → packages/core/dist}/workflow/workflow-permissions.test.d.ts.map +0 -0
  701. /package/{dist → packages/core/dist}/workflow/workflow-permissions.test.js +0 -0
  702. /package/{dist → packages/core/dist}/workflow/workflow-permissions.test.js.map +0 -0
  703. /package/{dist → packages/core/dist}/workflow/workflow-router.d.ts +0 -0
  704. /package/{dist → packages/core/dist}/workflow/workflow-router.d.ts.map +0 -0
  705. /package/{dist → packages/core/dist}/workflow/workflow-router.js +0 -0
  706. /package/{dist → packages/core/dist}/workflow/workflow-router.js.map +0 -0
  707. /package/{dist → packages/core/dist}/workflow/workflow-router.test.d.ts +0 -0
  708. /package/{dist → packages/core/dist}/workflow/workflow-router.test.d.ts.map +0 -0
  709. /package/{dist → packages/core/dist}/workflow/workflow-router.test.js +0 -0
  710. /package/{dist → packages/core/dist}/workflow/workflow-router.test.js.map +0 -0
  711. /package/{dist → packages/core/dist}/workflow/workflow-schema.d.ts +0 -0
  712. /package/{dist → packages/core/dist}/workflow/workflow-schema.d.ts.map +0 -0
  713. /package/{dist → packages/core/dist}/workflow/workflow-schema.js +0 -0
  714. /package/{dist → packages/core/dist}/workflow/workflow-schema.js.map +0 -0
  715. /package/{dist → packages/core/dist}/workflow/workflow-schema.test.d.ts +0 -0
  716. /package/{dist → packages/core/dist}/workflow/workflow-schema.test.d.ts.map +0 -0
  717. /package/{dist → packages/core/dist}/workflow/workflow-schema.test.js +0 -0
  718. /package/{dist → packages/core/dist}/workflow/workflow-schema.test.js.map +0 -0
  719. /package/{dist → packages/core/dist}/workflow/workflow-stepped-schema.test.d.ts +0 -0
  720. /package/{dist → packages/core/dist}/workflow/workflow-stepped-schema.test.d.ts.map +0 -0
  721. /package/{dist → packages/core/dist}/workflow/workflow-stepped-schema.test.js +0 -0
  722. /package/{dist → packages/core/dist}/workflow/workflow-stepped-schema.test.js.map +0 -0
@@ -0,0 +1,173 @@
1
+ """Sprint epic add command.
2
+
3
+ Adds a new epic to the current sprint, creating a shard file
4
+ and updating the index.
5
+
6
+ Provides:
7
+ - add_epic(sprint_path, epic_id, title, ...) -> dict
8
+ - epic_add_command (Click command for CLI registration)
9
+ """
10
+
11
+ from pathlib import Path
12
+ from typing import Any
13
+
14
+ import click
15
+ from ruamel.yaml.comments import CommentedMap, CommentedSeq
16
+
17
+ from pennyfarthing_scripts.sprint.yaml_io import (
18
+ EPIC_KEY_ORDER,
19
+ _read_yaml_file,
20
+ _write_yaml_file,
21
+ _get_epic_ref,
22
+ )
23
+
24
+
25
+ def add_epic(
26
+ sprint_path: Path,
27
+ epic_id: str,
28
+ title: str,
29
+ *,
30
+ priority: str = "P1",
31
+ status: str = "backlog",
32
+ repos: str = "pennyfarthing",
33
+ jira: str | None = None,
34
+ description: str | None = None,
35
+ ) -> dict[str, Any]:
36
+ """Add a new epic to the current sprint.
37
+
38
+ Creates a shard file for the epic and adds its reference to the index.
39
+
40
+ Args:
41
+ sprint_path: Path to sprint index YAML file
42
+ epic_id: Epic ID (e.g., "epic-85" or "MSSCI-14400")
43
+ title: Epic title
44
+ priority: Priority (default: P1)
45
+ status: Initial status (default: backlog)
46
+ repos: Repository scope (default: pennyfarthing)
47
+ jira: Optional Jira epic key
48
+ description: Optional epic description
49
+
50
+ Returns:
51
+ Dict with success status and epic_id or error
52
+ """
53
+ sprint_dir = sprint_path.parent
54
+
55
+ # Build epic as CommentedMap with canonical key ordering
56
+ epic = CommentedMap()
57
+ fields: dict[str, Any] = {
58
+ "id": epic_id,
59
+ "type": "epic",
60
+ "title": title,
61
+ "priority": priority,
62
+ "status": status,
63
+ "repos": repos,
64
+ "stories": CommentedSeq(),
65
+ }
66
+ if description is not None:
67
+ fields["description"] = description
68
+ if jira is not None:
69
+ fields["jira"] = jira
70
+
71
+ # Insert keys in EPIC_KEY_ORDER, then any extras
72
+ for key in EPIC_KEY_ORDER:
73
+ if key in fields:
74
+ epic[key] = fields[key]
75
+ for key in fields:
76
+ if key not in EPIC_KEY_ORDER:
77
+ epic[key] = fields[key]
78
+
79
+ # Determine the shard reference
80
+ ref = _get_epic_ref(epic)
81
+ shard_file = sprint_dir / f"epic-{ref}.yaml"
82
+
83
+ if shard_file.exists():
84
+ return {
85
+ "success": False,
86
+ "error": f"Epic shard file already exists: {shard_file.name}",
87
+ }
88
+
89
+ # Read current index
90
+ data = _read_yaml_file(sprint_path)
91
+ epics = data.get("epics", [])
92
+
93
+ # Check for duplicate refs
94
+ for existing in epics:
95
+ existing_str = str(existing) if isinstance(existing, str) else str(existing.get("id", ""))
96
+ if existing_str == ref or existing_str == epic_id:
97
+ return {
98
+ "success": False,
99
+ "error": f"Epic '{epic_id}' already exists in the sprint",
100
+ }
101
+
102
+ # Detect format: sharded (string refs) or monolithic (full dicts)
103
+ is_sharded = bool(epics) and isinstance(epics[0], str)
104
+
105
+ if is_sharded or not epics:
106
+ # Sharded format: write shard file and add string ref to index
107
+ _write_yaml_file(shard_file, epic)
108
+
109
+ if not isinstance(epics, CommentedSeq):
110
+ epics = CommentedSeq(epics)
111
+ epics.append(ref)
112
+ data["epics"] = epics
113
+ _write_yaml_file(sprint_path, data)
114
+ else:
115
+ # Monolithic format: add full epic dict to index
116
+ if not isinstance(epics, CommentedSeq):
117
+ epics = CommentedSeq(epics)
118
+ epics.append(epic)
119
+ data["epics"] = epics
120
+ _write_yaml_file(sprint_path, data)
121
+
122
+ return {
123
+ "success": True,
124
+ "epic_id": epic_id,
125
+ "ref": ref,
126
+ "shard_file": shard_file.name if is_sharded or not epics else None,
127
+ }
128
+
129
+
130
+ @click.command("epic-add")
131
+ @click.argument("epic_id", type=str)
132
+ @click.argument("title", type=str)
133
+ @click.option("--priority", type=click.Choice(["P0", "P1", "P2", "P3"]), default="P1")
134
+ @click.option("--status", type=click.Choice(["backlog", "ready", "in_progress"]), default="backlog")
135
+ @click.option("--repos", default="pennyfarthing")
136
+ @click.option("--jira", "jira_id", type=str, default=None, help="Jira epic key (MSSCI-NNNNN)")
137
+ @click.option("--description", "-d", type=str, default=None, help="Epic description")
138
+ @click.option("--sprint-file", type=click.Path(), default=None, help="Path to sprint YAML file")
139
+ def epic_add_command(
140
+ epic_id: str,
141
+ title: str,
142
+ priority: str,
143
+ status: str,
144
+ repos: str,
145
+ jira_id: str | None,
146
+ description: str | None,
147
+ sprint_file: str | None,
148
+ ) -> None:
149
+ """Add a new epic to the current sprint."""
150
+ if sprint_file is None:
151
+ from pennyfarthing_scripts.common.config import get_project_root
152
+ path = get_project_root() / "sprint" / "current-sprint.yaml"
153
+ else:
154
+ path = Path(sprint_file)
155
+
156
+ result = add_epic(
157
+ sprint_path=path,
158
+ epic_id=epic_id,
159
+ title=title,
160
+ priority=priority,
161
+ status=status,
162
+ repos=repos,
163
+ jira=jira_id,
164
+ description=description,
165
+ )
166
+
167
+ if result["success"]:
168
+ msg = f"Added epic {result['epic_id']}: {title}"
169
+ if result.get("shard_file"):
170
+ msg += f" ({result['shard_file']})"
171
+ click.echo(msg)
172
+ else:
173
+ raise click.ClickException(result["error"])
@@ -0,0 +1,431 @@
1
+ """
2
+ Import BMAD epics-and-stories output to future.yaml.
3
+
4
+ Transforms the markdown output from the epics-and-stories workflow into
5
+ the YAML format used by sprint/future.yaml.
6
+ """
7
+
8
+ import re
9
+ from datetime import date
10
+ from pathlib import Path
11
+ from typing import Any
12
+
13
+ import yaml
14
+
15
+ from pennyfarthing_scripts.common.config import get_project_root, load_yaml_config
16
+
17
+
18
+ def parse_epics_markdown(content: str) -> dict[str, Any]:
19
+ """Parse epics markdown file from BMAD epics-and-stories workflow.
20
+
21
+ Args:
22
+ content: Markdown content to parse
23
+
24
+ Returns:
25
+ Dict with parsed initiative data
26
+ """
27
+ result: dict[str, Any] = {
28
+ "title": "",
29
+ "description": "",
30
+ "total_points": 0,
31
+ "epics": [],
32
+ }
33
+
34
+ # Extract title from first # heading
35
+ title_match = re.search(r"^# (.+?)( - Epic Breakdown)?$", content, re.MULTILINE)
36
+ if title_match:
37
+ result["title"] = title_match.group(1).replace(" - Epics and Stories", "")
38
+
39
+ # Extract description from Overview section
40
+ overview_match = re.search(
41
+ r"## Overview\s*\n\s*\n(.+?)(?=\n\n##|\n##)", content, re.DOTALL
42
+ )
43
+ if overview_match:
44
+ result["description"] = overview_match.group(1).strip()
45
+
46
+ # Extract total points
47
+ points_match = re.search(r"\*\*Points:\*\*\s*(\d+)", content)
48
+ if points_match:
49
+ result["total_points"] = int(points_match.group(1))
50
+ else:
51
+ effort_match = re.search(
52
+ r"Total Effort.*?(\d+)\s*story points", content, re.IGNORECASE
53
+ )
54
+ if effort_match:
55
+ result["total_points"] = int(effort_match.group(1))
56
+
57
+ # Parse all epics
58
+ epic_pattern = re.compile(r"^## Epic (\d+):\s*(.+)$", re.MULTILINE)
59
+ epic_positions = []
60
+ for match in epic_pattern.finditer(content):
61
+ epic_positions.append(
62
+ {
63
+ "num": int(match.group(1)),
64
+ "title": match.group(2),
65
+ "index": match.start(),
66
+ }
67
+ )
68
+
69
+ # Process each epic
70
+ for i, epic_pos in enumerate(epic_positions):
71
+ start_index = epic_pos["index"]
72
+ end_index = (
73
+ epic_positions[i + 1]["index"] if i < len(epic_positions) - 1 else len(content)
74
+ )
75
+ epic_content = content[start_index:end_index]
76
+
77
+ epic: dict[str, Any] = {
78
+ "num": epic_pos["num"],
79
+ "title": epic_pos["title"],
80
+ "description": "",
81
+ "points": 0,
82
+ "stories": [],
83
+ }
84
+
85
+ # Extract epic description (User Outcome)
86
+ user_outcome_match = re.search(r"\*\*User Outcome:\*\*\s*(.+)", epic_content)
87
+ if user_outcome_match:
88
+ epic["description"] = user_outcome_match.group(1)
89
+
90
+ # Extract epic points
91
+ epic_points_match = re.search(r"\*\*Points:\*\*\s*(\d+)", epic_content)
92
+ if epic_points_match:
93
+ epic["points"] = int(epic_points_match.group(1))
94
+
95
+ # Parse stories within this epic
96
+ story_pattern = re.compile(
97
+ rf"^### Story {epic_pos['num']}\.(\d+):\s*(.+)$", re.MULTILINE
98
+ )
99
+ story_positions = []
100
+ for match in story_pattern.finditer(epic_content):
101
+ story_positions.append(
102
+ {
103
+ "num": int(match.group(1)),
104
+ "title": match.group(2),
105
+ "index": match.start(),
106
+ }
107
+ )
108
+
109
+ for j, story_pos in enumerate(story_positions):
110
+ story_start = story_pos["index"]
111
+ story_end = (
112
+ story_positions[j + 1]["index"]
113
+ if j < len(story_positions) - 1
114
+ else len(epic_content)
115
+ )
116
+ story_content = epic_content[story_start:story_end]
117
+
118
+ # Extract story description
119
+ i_want_match = re.search(r"^I want \*\*(.+?)\*\*,", story_content, re.MULTILINE)
120
+ description = i_want_match.group(1) if i_want_match else ""
121
+
122
+ # Extract story points
123
+ story_points_match = re.search(r"\*\*Points:\*\*\s*(\d+)", story_content)
124
+ points = int(story_points_match.group(1)) if story_points_match else 1
125
+
126
+ epic["stories"].append(
127
+ {
128
+ "num": story_pos["num"],
129
+ "title": story_pos["title"],
130
+ "description": description,
131
+ "points": points,
132
+ }
133
+ )
134
+
135
+ result["epics"].append(epic)
136
+
137
+ # Calculate total if not found
138
+ if result["total_points"] == 0:
139
+ result["total_points"] = sum(e.get("points", 0) for e in result["epics"])
140
+
141
+ return result
142
+
143
+
144
+ def get_next_epic_number(project_root: Path | None = None) -> int:
145
+ """Get next available epic number from future.yaml.
146
+
147
+ Args:
148
+ project_root: Project root path (defaults to auto-detect)
149
+
150
+ Returns:
151
+ Next available epic number
152
+ """
153
+ root = project_root or get_project_root()
154
+ future_path = root / "sprint" / "future.yaml"
155
+
156
+ if not future_path.exists():
157
+ return 74 # Default starting point
158
+
159
+ content = future_path.read_text()
160
+
161
+ # Look for "Next Available Epic Number: XX"
162
+ next_match = re.search(r"Next Available Epic Number:\s*(\d+)", content, re.IGNORECASE)
163
+ if next_match:
164
+ return int(next_match.group(1))
165
+
166
+ # Fallback: find highest epic-XX number
167
+ max_num = 73
168
+ for match in re.finditer(r"epic-(\d+)", content):
169
+ num = int(match.group(1))
170
+ if num > max_num:
171
+ max_num = num
172
+
173
+ return max_num + 1
174
+
175
+
176
+ def generate_initiative_yaml(
177
+ parsed: dict[str, Any],
178
+ start_epic_num: int,
179
+ initiative_name: str,
180
+ source_file: str,
181
+ marker: str = "imported",
182
+ ) -> tuple[str, int]:
183
+ """Generate YAML for an initiative.
184
+
185
+ Args:
186
+ parsed: Parsed markdown data
187
+ start_epic_num: Starting epic number
188
+ initiative_name: Name for the initiative
189
+ source_file: Path to source markdown file
190
+ marker: Marker tag for stories
191
+
192
+ Returns:
193
+ Tuple of (YAML string, next epic number)
194
+ """
195
+ today = date.today().isoformat()
196
+
197
+ lines = [
198
+ f" # ==========================================================================",
199
+ f" # {initiative_name.upper()}",
200
+ f" # Imported from: {source_file}",
201
+ f" # Date: {today}",
202
+ f" # ==========================================================================",
203
+ f' - name: "{initiative_name}"',
204
+ f" description: |",
205
+ ]
206
+
207
+ # Add description lines with proper indentation
208
+ for line in parsed.get("description", initiative_name).split("\n"):
209
+ lines.append(f" {line}")
210
+
211
+ lines.extend(
212
+ [
213
+ f" status: ready",
214
+ f" blocked_by: null",
215
+ f" total_points: {parsed['total_points']}",
216
+ f" epics:",
217
+ ]
218
+ )
219
+
220
+ current_epic_num = start_epic_num
221
+
222
+ for epic in parsed.get("epics", []):
223
+ epic_points = epic.get("points", 0)
224
+ if epic_points == 0:
225
+ epic_points = sum(s.get("points", 1) for s in epic.get("stories", []))
226
+
227
+ lines.extend(
228
+ [
229
+ f" - id: epic-{current_epic_num}",
230
+ f' title: "{epic["title"]}"',
231
+ f" description: |",
232
+ f" {epic.get('description', epic['title'])}",
233
+ f" points: {epic_points}",
234
+ f" priority: P1",
235
+ f' marker: "{marker}"',
236
+ f" repos: pennyfarthing",
237
+ f" status: planning",
238
+ f" stories:",
239
+ ]
240
+ )
241
+
242
+ for story in epic.get("stories", []):
243
+ story_id = f"{current_epic_num}-{story['num']}"
244
+ # Escape quotes in title
245
+ title = story["title"].replace('"', '\\"')
246
+ lines.extend(
247
+ [
248
+ f' - id: "{story_id}"',
249
+ f' title: "{title}"',
250
+ f" description: |",
251
+ f" {story.get('description', title)}",
252
+ f" points: {story.get('points', 1)}",
253
+ f" priority: P0",
254
+ f" status: planning",
255
+ f" repos: pennyfarthing",
256
+ ]
257
+ )
258
+
259
+ current_epic_num += 1
260
+
261
+ return "\n".join(lines), current_epic_num
262
+
263
+
264
+ def import_epic(
265
+ epics_file: str | Path,
266
+ initiative_name: str | None = None,
267
+ marker: str = "imported",
268
+ *,
269
+ project_root: Path | None = None,
270
+ dry_run: bool = False,
271
+ ) -> dict[str, Any]:
272
+ """Import BMAD epics-and-stories markdown to future.yaml.
273
+
274
+ Args:
275
+ epics_file: Path to the markdown file from epics-and-stories workflow
276
+ initiative_name: Name for the initiative (extracted from file if not provided)
277
+ marker: Marker tag for stories
278
+ project_root: Project root path (defaults to auto-detect)
279
+ dry_run: If True, show what would be done without making changes
280
+
281
+ Returns:
282
+ Dict with success status and details
283
+ """
284
+ root = project_root or get_project_root()
285
+
286
+ # Resolve epics file path
287
+ epics_path = Path(epics_file)
288
+ if not epics_path.is_absolute():
289
+ epics_path = root / epics_path
290
+
291
+ if not epics_path.exists():
292
+ return {"success": False, "error": f"File not found: {epics_path}"}
293
+
294
+ # Read and parse
295
+ content = epics_path.read_text()
296
+ parsed = parse_epics_markdown(content)
297
+
298
+ if not parsed.get("epics"):
299
+ return {"success": False, "error": "No epics found in markdown file"}
300
+
301
+ # Use provided name or extract from file
302
+ name = initiative_name or parsed.get("title") or "Imported Initiative"
303
+
304
+ # Get next epic number
305
+ start_epic_num = get_next_epic_number(root)
306
+
307
+ # Generate YAML
308
+ relative_path = str(epics_path.relative_to(root)) if epics_path.is_relative_to(root) else str(epics_path)
309
+ new_yaml, next_epic_num = generate_initiative_yaml(
310
+ parsed, start_epic_num, name, relative_path, marker
311
+ )
312
+
313
+ if dry_run:
314
+ return {
315
+ "success": True,
316
+ "dry_run": True,
317
+ "initiative_name": name,
318
+ "epics_count": len(parsed["epics"]),
319
+ "stories_count": sum(len(e.get("stories", [])) for e in parsed["epics"]),
320
+ "total_points": parsed["total_points"],
321
+ "start_epic_num": start_epic_num,
322
+ "next_epic_num": next_epic_num,
323
+ "yaml_preview": new_yaml,
324
+ "message": f"Would import '{name}' with {len(parsed['epics'])} epics",
325
+ }
326
+
327
+ # Update future.yaml
328
+ future_path = root / "sprint" / "future.yaml"
329
+ future_content = future_path.read_text()
330
+
331
+ # Update next epic number comment
332
+ future_content = re.sub(
333
+ r"Next Available Epic Number:\s*\d+",
334
+ f"Next Available Epic Number: {next_epic_num}",
335
+ future_content,
336
+ flags=re.IGNORECASE,
337
+ )
338
+
339
+ # Find insertion point (before SUMMARY section)
340
+ summary_marker = "# =============================================================================\n# SUMMARY"
341
+ summary_index = future_content.find(summary_marker)
342
+
343
+ if summary_index == -1:
344
+ future_content += "\n" + new_yaml
345
+ else:
346
+ future_content = (
347
+ future_content[:summary_index] + new_yaml + "\n" + future_content[summary_index:]
348
+ )
349
+
350
+ future_path.write_text(future_content)
351
+
352
+ return {
353
+ "success": True,
354
+ "initiative_name": name,
355
+ "epics_count": len(parsed["epics"]),
356
+ "stories_count": sum(len(e.get("stories", [])) for e in parsed["epics"]),
357
+ "total_points": parsed["total_points"],
358
+ "start_epic_num": start_epic_num,
359
+ "next_epic_num": next_epic_num,
360
+ "message": f"Imported '{name}' with {len(parsed['epics'])} epics (epic-{start_epic_num} to epic-{next_epic_num - 1})",
361
+ }
362
+
363
+
364
+ def main(args: list[str] | None = None) -> int:
365
+ """CLI entry point for epic import.
366
+
367
+ Args:
368
+ args: Command line arguments
369
+
370
+ Returns:
371
+ Exit code
372
+ """
373
+ import argparse
374
+ import sys
375
+
376
+ parser = argparse.ArgumentParser(
377
+ description="Import BMAD epics-and-stories workflow output to future.yaml"
378
+ )
379
+ parser.add_argument(
380
+ "epics_file",
381
+ help="Path to the markdown file from epics-and-stories workflow",
382
+ )
383
+ parser.add_argument(
384
+ "initiative_name",
385
+ nargs="?",
386
+ help="Name for the initiative (optional, extracted from file if not provided)",
387
+ )
388
+ parser.add_argument(
389
+ "--marker",
390
+ default="imported",
391
+ help="Marker tag for stories (default: imported)",
392
+ )
393
+ parser.add_argument(
394
+ "--dry-run",
395
+ action="store_true",
396
+ help="Show what would be done without making changes",
397
+ )
398
+
399
+ parsed = parser.parse_args(args)
400
+
401
+ result = import_epic(
402
+ parsed.epics_file,
403
+ initiative_name=parsed.initiative_name,
404
+ marker=parsed.marker,
405
+ dry_run=parsed.dry_run,
406
+ )
407
+
408
+ if result.get("success"):
409
+ if result.get("dry_run"):
410
+ print(f"[DRY-RUN] {result.get('message')}")
411
+ print(f" Epics: {result.get('epics_count')}")
412
+ print(f" Stories: {result.get('stories_count')}")
413
+ print(f" Points: {result.get('total_points')}")
414
+ print(f" Epic numbers: epic-{result.get('start_epic_num')} to epic-{result.get('next_epic_num') - 1}")
415
+ print("\nYAML Preview:")
416
+ print("-" * 60)
417
+ print(result.get("yaml_preview"))
418
+ print("-" * 60)
419
+ else:
420
+ print(f"✓ {result.get('message')}")
421
+ print(f" Next available epic number: {result.get('next_epic_num')}")
422
+ return 0
423
+ else:
424
+ print(f"Failed: {result.get('error')}", file=sys.stderr)
425
+ return 1
426
+
427
+
428
+ if __name__ == "__main__":
429
+ import sys
430
+
431
+ sys.exit(main())