@pennyfarthing/core 10.0.3 → 10.1.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 (282) hide show
  1. package/README.md +9 -7
  2. package/package.json +7 -1
  3. package/packages/core/dist/cli/commands/cyclist.d.ts +5 -1
  4. package/packages/core/dist/cli/commands/cyclist.d.ts.map +1 -1
  5. package/packages/core/dist/cli/commands/cyclist.js +4 -4
  6. package/packages/core/dist/cli/commands/cyclist.js.map +1 -1
  7. package/packages/core/dist/cli/commands/cyclist.test.js +2 -2
  8. package/packages/core/dist/cli/commands/cyclist.test.js.map +1 -1
  9. package/packages/core/dist/cli/commands/doctor-legacy.test.js +17 -16
  10. package/packages/core/dist/cli/commands/doctor-legacy.test.js.map +1 -1
  11. package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
  12. package/packages/core/dist/cli/commands/doctor.js +251 -4
  13. package/packages/core/dist/cli/commands/doctor.js.map +1 -1
  14. package/packages/core/dist/cli/commands/init.d.ts +7 -0
  15. package/packages/core/dist/cli/commands/init.d.ts.map +1 -1
  16. package/packages/core/dist/cli/commands/init.js +43 -7
  17. package/packages/core/dist/cli/commands/init.js.map +1 -1
  18. package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
  19. package/packages/core/dist/cli/commands/update.js +26 -0
  20. package/packages/core/dist/cli/commands/update.js.map +1 -1
  21. package/packages/core/dist/cli/index.js +1 -1
  22. package/packages/core/dist/cli/index.js.map +1 -1
  23. package/packages/core/dist/cli/ocean-profiles.test.js +1 -1
  24. package/packages/core/dist/cli/ocean-profiles.test.js.map +1 -1
  25. package/packages/core/dist/cli/utils/files.d.ts +10 -0
  26. package/packages/core/dist/cli/utils/files.d.ts.map +1 -1
  27. package/packages/core/dist/cli/utils/files.js +35 -0
  28. package/packages/core/dist/cli/utils/files.js.map +1 -1
  29. package/packages/core/dist/cli/utils/python.d.ts +22 -0
  30. package/packages/core/dist/cli/utils/python.d.ts.map +1 -0
  31. package/packages/core/dist/cli/utils/python.js +102 -0
  32. package/packages/core/dist/cli/utils/python.js.map +1 -0
  33. package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
  34. package/packages/core/dist/cli/utils/settings.js +10 -0
  35. package/packages/core/dist/cli/utils/settings.js.map +1 -1
  36. package/packages/core/dist/scripts/generate-report.d.ts.map +1 -1
  37. package/packages/core/dist/scripts/generate-report.js +11 -7
  38. package/packages/core/dist/scripts/generate-report.js.map +1 -1
  39. package/packages/core/dist/scripts/generate-spider-report.d.ts.map +1 -1
  40. package/packages/core/dist/scripts/generate-spider-report.js +12 -8
  41. package/packages/core/dist/scripts/generate-spider-report.js.map +1 -1
  42. package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -1
  43. package/packages/core/dist/scripts/generate-spider.js +6 -4
  44. package/packages/core/dist/scripts/generate-spider.js.map +1 -1
  45. package/packages/core/dist/scripts/generate-spider.test.js +2 -2
  46. package/packages/core/dist/scripts/generate-spider.test.js.map +1 -1
  47. package/pennyfarthing-dist/agents/README.md +1 -3
  48. package/pennyfarthing-dist/agents/architect.md +0 -6
  49. package/pennyfarthing-dist/agents/devops.md +0 -6
  50. package/pennyfarthing-dist/agents/orchestrator.md +0 -6
  51. package/pennyfarthing-dist/agents/pm.md +1 -7
  52. package/pennyfarthing-dist/agents/sm-finish.md +1 -1
  53. package/pennyfarthing-dist/agents/sm-setup.md +2 -2
  54. package/pennyfarthing-dist/agents/sm.md +4 -11
  55. package/pennyfarthing-dist/commands/architect.md +11 -3
  56. package/pennyfarthing-dist/commands/close-epic.md +24 -131
  57. package/pennyfarthing-dist/commands/create-theme.md +14 -24
  58. package/pennyfarthing-dist/commands/dev.md +11 -3
  59. package/pennyfarthing-dist/commands/devops.md +11 -3
  60. package/pennyfarthing-dist/commands/health-check.md +1 -3
  61. package/pennyfarthing-dist/commands/help.md +8 -12
  62. package/pennyfarthing-dist/commands/list-themes.md +14 -16
  63. package/pennyfarthing-dist/commands/orchestrator.md +11 -3
  64. package/pennyfarthing-dist/commands/parallel-work.md +1 -3
  65. package/pennyfarthing-dist/commands/pm.md +11 -3
  66. package/pennyfarthing-dist/commands/prime.md +6 -6
  67. package/pennyfarthing-dist/commands/repo-status.md +2 -2
  68. package/pennyfarthing-dist/commands/reviewer.md +11 -3
  69. package/pennyfarthing-dist/commands/run-ci.md +1 -1
  70. package/pennyfarthing-dist/commands/set-theme.md +14 -51
  71. package/pennyfarthing-dist/commands/setup.md +1 -1
  72. package/pennyfarthing-dist/commands/show-theme.md +14 -16
  73. package/pennyfarthing-dist/commands/sm.md +11 -3
  74. package/pennyfarthing-dist/commands/sprint.md +8 -8
  75. package/pennyfarthing-dist/commands/tea.md +11 -3
  76. package/pennyfarthing-dist/commands/tech-writer.md +11 -3
  77. package/pennyfarthing-dist/commands/theme-maker.md +14 -671
  78. package/pennyfarthing-dist/commands/theme.md +95 -0
  79. package/pennyfarthing-dist/commands/ux-designer.md +11 -3
  80. package/pennyfarthing-dist/commands/work.md +3 -5
  81. package/pennyfarthing-dist/guides/agent-coordination.md +11 -13
  82. package/pennyfarthing-dist/guides/agent-template-tactical.md +2 -3
  83. package/pennyfarthing-dist/guides/command-tag-taxonomy.md +212 -0
  84. package/pennyfarthing-dist/guides/hooks.md +5 -5
  85. package/pennyfarthing-dist/guides/patterns/fan-out-fan-in-pattern.md +3 -3
  86. package/pennyfarthing-dist/guides/patterns/helper-delegation-pattern.md +9 -59
  87. package/pennyfarthing-dist/guides/patterns/tdd-flow-pattern.md +4 -5
  88. package/pennyfarthing-dist/guides/prime.md +2 -2
  89. package/pennyfarthing-dist/guides/skill-schema.md +25 -26
  90. package/pennyfarthing-dist/guides/xml-tags.md +2 -2
  91. package/pennyfarthing-dist/scripts/README.md +2 -2
  92. package/pennyfarthing-dist/scripts/core/agent-session.sh +6 -2
  93. package/pennyfarthing-dist/scripts/core/prime.sh +8 -10
  94. package/pennyfarthing-dist/scripts/git/git-status-all.sh +1 -1
  95. package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +8 -6
  96. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +3 -3
  97. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +14 -12
  98. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +4 -3
  99. package/pennyfarthing-dist/scripts/hooks/pre-push.sh +11 -5
  100. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +1 -1
  101. package/pennyfarthing-dist/scripts/misc/README.md +1 -1
  102. package/pennyfarthing-dist/scripts/misc/repo-utils.sh +3 -3
  103. package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +1 -2
  104. package/pennyfarthing-dist/scripts/sprint/README.md +32 -17
  105. package/pennyfarthing-dist/scripts/story/README.md +1 -1
  106. package/pennyfarthing-dist/scripts/test/test-setup.sh +1 -1
  107. package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +5 -5
  108. package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +3 -79
  109. package/pennyfarthing-dist/scripts/theme/README.md +1 -1
  110. package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +0 -1
  111. package/pennyfarthing-dist/scripts/workflow/finish-story.sh +62 -17
  112. package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +2 -2
  113. package/pennyfarthing-dist/skills/skill-registry.yaml +41 -28
  114. package/pennyfarthing-dist/skills/sprint/skill.md +386 -68
  115. package/pennyfarthing-dist/skills/story/skill.md +14 -206
  116. package/pennyfarthing-dist/skills/theme/skill.md +290 -75
  117. package/pennyfarthing-dist/skills/theme-creation/SKILL.md +23 -166
  118. package/pennyfarthing-dist/skills/workflow/skill.md +4 -4
  119. package/pennyfarthing-dist/templates/agent-scopes.yaml.template +0 -11
  120. package/pennyfarthing-dist/templates/auto-load-sm.sh.template +14 -0
  121. package/pennyfarthing-dist/templates/settings.local.json.template +9 -0
  122. package/pennyfarthing-dist/workflows/2party-tdd.yaml +399 -0
  123. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +42 -25
  124. package/pennyfarthing-dist/workflows/git-cleanup.yaml +1 -1
  125. package/pennyfarthing-dist/workflows/project-setup/steps/step-10-complete.md +1 -1
  126. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  127. package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
  128. package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
  129. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  130. package/pennyfarthing_scripts/cli.py +15 -0
  131. package/pennyfarthing_scripts/codemarkers/__init__.py +19 -0
  132. package/pennyfarthing_scripts/codemarkers/__main__.py +6 -0
  133. package/pennyfarthing_scripts/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
  134. package/pennyfarthing_scripts/codemarkers/__pycache__/__main__.cpython-314.pyc +0 -0
  135. package/pennyfarthing_scripts/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
  136. package/pennyfarthing_scripts/codemarkers/__pycache__/cli.cpython-314.pyc +0 -0
  137. package/pennyfarthing_scripts/codemarkers/__pycache__/formatters.cpython-314.pyc +0 -0
  138. package/pennyfarthing_scripts/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
  139. package/pennyfarthing_scripts/codemarkers/analyze.py +326 -0
  140. package/pennyfarthing_scripts/codemarkers/cli.py +129 -0
  141. package/pennyfarthing_scripts/codemarkers/formatters.py +89 -0
  142. package/pennyfarthing_scripts/codemarkers/models.py +45 -0
  143. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  144. package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
  145. package/pennyfarthing_scripts/common/config.py +2 -1
  146. package/pennyfarthing_scripts/complexity/__init__.py +15 -0
  147. package/pennyfarthing_scripts/complexity/__main__.py +6 -0
  148. package/pennyfarthing_scripts/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
  149. package/pennyfarthing_scripts/complexity/__pycache__/__main__.cpython-314.pyc +0 -0
  150. package/pennyfarthing_scripts/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
  151. package/pennyfarthing_scripts/complexity/__pycache__/cli.cpython-314.pyc +0 -0
  152. package/pennyfarthing_scripts/complexity/__pycache__/formatters.cpython-314.pyc +0 -0
  153. package/pennyfarthing_scripts/complexity/__pycache__/models.cpython-314.pyc +0 -0
  154. package/pennyfarthing_scripts/complexity/analyze.py +207 -0
  155. package/pennyfarthing_scripts/complexity/cli.py +78 -0
  156. package/pennyfarthing_scripts/complexity/formatters.py +64 -0
  157. package/pennyfarthing_scripts/complexity/models.py +32 -0
  158. package/pennyfarthing_scripts/deadcode/__init__.py +6 -0
  159. package/pennyfarthing_scripts/deadcode/__main__.py +6 -0
  160. package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-314.pyc +0 -0
  161. package/pennyfarthing_scripts/deadcode/__pycache__/__main__.cpython-314.pyc +0 -0
  162. package/pennyfarthing_scripts/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
  163. package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
  164. package/pennyfarthing_scripts/deadcode/__pycache__/formatters.cpython-314.pyc +0 -0
  165. package/pennyfarthing_scripts/deadcode/__pycache__/models.cpython-314.pyc +0 -0
  166. package/pennyfarthing_scripts/deadcode/analyze.py +323 -0
  167. package/pennyfarthing_scripts/deadcode/cli.py +163 -0
  168. package/pennyfarthing_scripts/deadcode/formatters.py +106 -0
  169. package/pennyfarthing_scripts/deadcode/models.py +54 -0
  170. package/pennyfarthing_scripts/dependencies/__init__.py +20 -0
  171. package/pennyfarthing_scripts/dependencies/__main__.py +5 -0
  172. package/pennyfarthing_scripts/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/dependencies/__pycache__/__main__.cpython-314.pyc +0 -0
  174. package/pennyfarthing_scripts/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/dependencies/__pycache__/cli.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/dependencies/__pycache__/formatters.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/dependencies/__pycache__/models.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/dependencies/analyze.py +155 -0
  179. package/pennyfarthing_scripts/dependencies/cli.py +72 -0
  180. package/pennyfarthing_scripts/dependencies/formatters.py +63 -0
  181. package/pennyfarthing_scripts/dependencies/models.py +39 -0
  182. package/pennyfarthing_scripts/healthscore/__init__.py +21 -0
  183. package/pennyfarthing_scripts/healthscore/__main__.py +6 -0
  184. package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
  185. package/pennyfarthing_scripts/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
  186. package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
  187. package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
  188. package/pennyfarthing_scripts/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
  189. package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-314.pyc +0 -0
  190. package/pennyfarthing_scripts/healthscore/analyze.py +161 -0
  191. package/pennyfarthing_scripts/healthscore/cli.py +76 -0
  192. package/pennyfarthing_scripts/healthscore/formatters.py +46 -0
  193. package/pennyfarthing_scripts/healthscore/models.py +44 -0
  194. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
  195. package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
  196. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
  197. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
  198. package/pennyfarthing_scripts/hotspots/__pycache__/formatters.cpython-314.pyc +0 -0
  199. package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
  200. package/pennyfarthing_scripts/hotspots/analyze.py +28 -1
  201. package/pennyfarthing_scripts/hotspots/cli.py +11 -9
  202. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  203. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  204. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  205. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  206. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
  207. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
  208. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  209. package/pennyfarthing_scripts/jira/bidirectional.py +42 -15
  210. package/pennyfarthing_scripts/jira/cli.py +78 -1
  211. package/pennyfarthing_scripts/jira/client.py +28 -0
  212. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  213. package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
  214. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  215. package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  216. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  217. package/pennyfarthing_scripts/prime/workflow.py +5 -3
  218. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  219. package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  220. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  221. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  222. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  223. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
  224. package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
  225. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  226. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  227. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  228. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  229. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  230. package/pennyfarthing_scripts/sprint/archive.py +63 -6
  231. package/pennyfarthing_scripts/sprint/archive_epic.py +198 -85
  232. package/pennyfarthing_scripts/sprint/cli.py +1565 -65
  233. package/pennyfarthing_scripts/sprint/epic_add.py +173 -0
  234. package/pennyfarthing_scripts/sprint/loader.py +46 -2
  235. package/pennyfarthing_scripts/sprint/story_add.py +202 -27
  236. package/pennyfarthing_scripts/sprint/story_finish.py +211 -0
  237. package/pennyfarthing_scripts/sprint/validate_cmd.py +44 -5
  238. package/pennyfarthing_scripts/sprint/validator.py +13 -3
  239. package/pennyfarthing_scripts/sprint/work.py +43 -3
  240. package/pennyfarthing_scripts/sprint/yaml_io.py +124 -15
  241. package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
  242. package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
  243. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
  244. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
  245. package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
  246. package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
  247. package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
  248. package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
  249. package/pennyfarthing_scripts/tests/test_codemarkers.py +682 -0
  250. package/pennyfarthing_scripts/tests/test_healthscore.py +524 -0
  251. package/pennyfarthing_scripts/tests/test_sprint_package.py +166 -0
  252. package/pennyfarthing_scripts/tests/test_yaml_io.py +117 -0
  253. package/pennyfarthing_scripts/theme/__init__.py +5 -0
  254. package/pennyfarthing_scripts/theme/__main__.py +6 -0
  255. package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-314.pyc +0 -0
  256. package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
  257. package/pennyfarthing_scripts/theme/cli.py +286 -0
  258. package/scripts/README.md +53 -0
  259. package/scripts/postinstall.cjs +34 -0
  260. package/pennyfarthing-dist/agents/workflow-status-check.md +0 -96
  261. package/pennyfarthing-dist/scripts/sprint/archive-story.sh +0 -133
  262. package/pennyfarthing-dist/scripts/sprint/available-stories.sh +0 -91
  263. package/pennyfarthing-dist/scripts/sprint/check-story.sh +0 -158
  264. package/pennyfarthing-dist/scripts/sprint/get-epic-field.sh +0 -52
  265. package/pennyfarthing-dist/scripts/sprint/get-story-field.sh +0 -63
  266. package/pennyfarthing-dist/scripts/sprint/list-future.sh +0 -145
  267. package/pennyfarthing-dist/scripts/sprint/new-sprint.sh +0 -110
  268. package/pennyfarthing-dist/scripts/sprint/promote-epic.sh +0 -148
  269. package/pennyfarthing-dist/scripts/sprint/sprint-common.sh +0 -415
  270. package/pennyfarthing-dist/scripts/sprint/sprint-info.sh +0 -33
  271. package/pennyfarthing-dist/scripts/sprint/sprint-metrics.sh +0 -230
  272. package/pennyfarthing-dist/scripts/sprint/sprint-status.sh +0 -134
  273. package/pennyfarthing-dist/scripts/sprint/validate-sprint-yaml.sh +0 -139
  274. package/pennyfarthing-dist/skills/sprint/scripts/archive-story.sh +0 -101
  275. package/pennyfarthing-dist/skills/sprint/scripts/available-stories.sh +0 -97
  276. package/pennyfarthing-dist/skills/sprint/scripts/check-story.sh +0 -164
  277. package/pennyfarthing-dist/skills/sprint/scripts/create-jira-epic.sh +0 -23
  278. package/pennyfarthing-dist/skills/sprint/scripts/new-sprint.sh +0 -116
  279. package/pennyfarthing-dist/skills/sprint/scripts/promote-epic.sh +0 -164
  280. package/pennyfarthing-dist/skills/sprint/scripts/sprint-info.sh +0 -39
  281. package/pennyfarthing-dist/skills/sprint/scripts/sprint-status.sh +0 -147
  282. package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +0 -23
@@ -1,97 +0,0 @@
1
- #!/bin/bash
2
- # Display available stories grouped by epic with Jira context
3
- # Usage: .pennyfarthing/scripts/sprint/available-stories.sh
4
- #
5
- # Shows backlog stories with epic context, points, and workflow
6
-
7
- set -euo pipefail
8
-
9
- # PROJECT_ROOT should be set by find-root.sh, but find it if not
10
- if [[ -z "${PROJECT_ROOT:-}" ]]; then
11
- d="$PWD"
12
- while [[ ! -d "$d/.claude" ]] && [[ "$d" != "/" ]]; do
13
- d="$(dirname "$d")"
14
- done
15
- PROJECT_ROOT="$d"
16
- fi
17
-
18
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
19
-
20
- if [[ ! -f "$SPRINT_FILE" ]]; then
21
- echo "Error: Sprint file not found at $SPRINT_FILE"
22
- exit 1
23
- fi
24
-
25
- if ! command -v yq &> /dev/null; then
26
- echo "Error: yq is required but not installed"
27
- echo "Install with: brew install yq"
28
- exit 1
29
- fi
30
-
31
- if ! command -v jira &> /dev/null; then
32
- echo "Error: jira CLI is required but not installed"
33
- echo "Install with: brew install ankitpokhrel/jira/jira"
34
- exit 1
35
- fi
36
-
37
- # Extract sprint info
38
- SPRINT_NAME=$(yq '.sprint.name' "$SPRINT_FILE")
39
- echo "# Available Stories - $SPRINT_NAME"
40
- echo ""
41
-
42
- # Get all epic IDs from the sprint file
43
- EPIC_IDS=$(yq '.epics[].id' "$SPRINT_FILE" | tr '\n' ' ')
44
-
45
- # Batch fetch epic details from Jira
46
- echo "Fetching epic details from Jira..."
47
- echo ""
48
-
49
- # Process each epic
50
- for EPIC_ID in $EPIC_IDS; do
51
- # Get epic title from sprint YAML (faster than Jira for display)
52
- EPIC_TITLE=$(yq ".epics[] | select(.id == \"$EPIC_ID\") | .title" "$SPRINT_FILE")
53
-
54
- # Get stories for this epic that are available (backlog or ready)
55
- STORY_COUNT=$(yq ".epics[] | select(.id == \"$EPIC_ID\") | .stories[] | select(.status == \"backlog\" or .status == \"ready\") | .id" "$SPRINT_FILE" 2>/dev/null | wc -l | tr -d ' ')
56
-
57
- if [[ "$STORY_COUNT" -eq 0 ]]; then
58
- continue
59
- fi
60
-
61
- # Fetch epic description from Jira for context (if it's a valid Jira key)
62
- # Jira uses Atlassian Document Format - extract text content from paragraphs
63
- EPIC_DESCRIPTION=""
64
- if [[ "$EPIC_ID" =~ ^MSSCI-[0-9]+$ ]]; then
65
- EPIC_DESCRIPTION=$(jira issue view "$EPIC_ID" --raw 2>/dev/null | \
66
- jq -r '.fields.description.content[]? | select(.type == "paragraph") | .content[]? | select(.type == "text") | .text' 2>/dev/null | \
67
- head -3 | tr '\n' ' ' | cut -c1-200)
68
- fi
69
-
70
- echo "## $EPIC_TITLE"
71
- if [[ -n "$EPIC_DESCRIPTION" ]]; then
72
- echo "*$EPIC_DESCRIPTION*"
73
- fi
74
- echo ""
75
- echo "| ID | Title | Pts | Pri | Status | Workflow |"
76
- echo "|----|-------|-----|-----|--------|----------|"
77
-
78
- # Get available stories for this epic (backlog or ready)
79
- yq -o=json ".epics[] | select(.id == \"$EPIC_ID\") | .stories[] | select(.status == \"backlog\" or .status == \"ready\")" "$SPRINT_FILE" 2>/dev/null | \
80
- jq -r '[.id, .title, (.points | tostring), (.priority // "P2"), (.status // "backlog"), (.workflow // "tdd")] | @tsv' | \
81
- while IFS=$'\t' read -r story_id story_title story_points story_priority story_status story_workflow; do
82
- # Truncate title if too long
83
- if [[ ${#story_title} -gt 40 ]]; then
84
- story_title="${story_title:0:37}..."
85
- fi
86
- echo "| $story_id | $story_title | $story_points | $story_priority | $story_status | $story_workflow |"
87
- done
88
-
89
- echo ""
90
- done
91
-
92
- # Summary
93
- TOTAL_BACKLOG=$(yq '[.epics[].stories[] | select(.status == "backlog" or .status == "ready")] | length' "$SPRINT_FILE")
94
- TOTAL_POINTS=$(yq '.epics[].stories[] | select(.status == "backlog" or .status == "ready") | .points' "$SPRINT_FILE" | paste -sd+ - | bc 2>/dev/null || echo "0")
95
-
96
- echo "---"
97
- echo "**Total available:** $TOTAL_BACKLOG stories, $TOTAL_POINTS points"
@@ -1,164 +0,0 @@
1
- #!/bin/bash
2
- # Check if a story or epic exists and is available for work
3
- # Usage: .pennyfarthing/scripts/sprint/check-story.sh <id|next>
4
- #
5
- # Arguments:
6
- # <story-id> - Check specific story availability
7
- # <epic-id> - Get first available story in epic
8
- # next - Get highest-priority available story across all epics
9
- #
10
- # Returns JSON with story/epic details and availability
11
-
12
- set -euo pipefail
13
-
14
- ID="${1:-}"
15
-
16
- if [[ -z "$ID" ]]; then
17
- echo '{"type": "error", "message": "No ID provided"}'
18
- exit 1
19
- fi
20
-
21
- # PROJECT_ROOT should be set by find-root.sh
22
- if [[ -z "${PROJECT_ROOT:-}" ]]; then
23
- d="$PWD"
24
- while [[ ! -d "$d/.claude" ]] && [[ "$d" != "/" ]]; do
25
- d="$(dirname "$d")"
26
- done
27
- PROJECT_ROOT="$d"
28
- fi
29
-
30
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
31
-
32
- if [[ ! -f "$SPRINT_FILE" ]]; then
33
- echo '{"type": "error", "message": "Sprint file not found"}'
34
- exit 1
35
- fi
36
-
37
- # Handle "next" argument - find highest priority available story
38
- if [[ "$ID" == "next" ]]; then
39
- # Get all available stories (backlog or ready), sort by priority, take first
40
- NEXT_STORY=$(yq -o json "[.epics[].stories[] | select(.status == \"backlog\" or .status == \"ready\" or .status == null)] | sort_by(.priority) | .[0]" "$SPRINT_FILE" 2>/dev/null || echo "null")
41
-
42
- if [[ "$NEXT_STORY" != "null" && -n "$NEXT_STORY" ]]; then
43
- STORY_ID=$(echo "$NEXT_STORY" | yq -r '.id')
44
- STORY_TITLE=$(echo "$NEXT_STORY" | yq -r '.title')
45
- STORY_POINTS=$(echo "$NEXT_STORY" | yq -r '.points // 0')
46
- STORY_PRIORITY=$(echo "$NEXT_STORY" | yq -r '.priority // "P2"')
47
- STORY_WORKFLOW=$(echo "$NEXT_STORY" | yq -r '.workflow // "tdd"')
48
- STORY_REPOS=$(echo "$NEXT_STORY" | yq -r '.repos // "pennyfarthing"')
49
- STORY_AC=$(echo "$NEXT_STORY" | yq -o json '.acceptance_criteria // []')
50
- EPIC_ID=$(yq -r ".epics[] | select(.stories[].id == \"$STORY_ID\") | .id" "$SPRINT_FILE" 2>/dev/null | head -1)
51
-
52
- cat <<EOF
53
- {
54
- "type": "next",
55
- "story": {
56
- "id": "$STORY_ID",
57
- "title": "$STORY_TITLE",
58
- "points": $STORY_POINTS,
59
- "priority": "$STORY_PRIORITY",
60
- "workflow": "$STORY_WORKFLOW",
61
- "repos": "$STORY_REPOS",
62
- "epic_id": "$EPIC_ID",
63
- "acceptance_criteria": $STORY_AC
64
- }
65
- }
66
- EOF
67
- else
68
- echo '{"type": "next", "story": null, "message": "No available stories in backlog"}'
69
- fi
70
- exit 0
71
- fi
72
-
73
- # Check if it's an epic
74
- EPIC_DATA=$(yq -o json ".epics[] | select(.id == \"$ID\")" "$SPRINT_FILE" 2>/dev/null || echo "")
75
-
76
- if [[ -n "$EPIC_DATA" && "$EPIC_DATA" != "null" ]]; then
77
- # It's an epic - get first available story by priority
78
- FIRST_STORY=$(yq -o json "[.epics[] | select(.id == \"$ID\") | .stories[] | select(.status == \"backlog\" or .status == \"ready\" or .status == null)] | sort_by(.priority) | .[0]" "$SPRINT_FILE" 2>/dev/null || echo "null")
79
-
80
- EPIC_TITLE=$(echo "$EPIC_DATA" | yq -r '.title // "Unknown"')
81
- STORY_COUNT=$(yq "[.epics[] | select(.id == \"$ID\") | .stories[] | select(.status == \"backlog\" or .status == \"ready\" or .status == null)] | length" "$SPRINT_FILE" 2>/dev/null || echo "0")
82
-
83
- if [[ "$FIRST_STORY" != "null" && -n "$FIRST_STORY" ]]; then
84
- STORY_ID=$(echo "$FIRST_STORY" | yq -r '.id')
85
- STORY_TITLE=$(echo "$FIRST_STORY" | yq -r '.title')
86
- STORY_POINTS=$(echo "$FIRST_STORY" | yq -r '.points // 0')
87
- STORY_WORKFLOW=$(echo "$FIRST_STORY" | yq -r '.workflow // "tdd"')
88
- STORY_REPOS=$(echo "$FIRST_STORY" | yq -r '.repos // "pennyfarthing"')
89
- STORY_AC=$(echo "$FIRST_STORY" | yq -o json '.acceptance_criteria // []')
90
-
91
- cat <<EOF
92
- {
93
- "type": "epic",
94
- "id": "$ID",
95
- "title": "$EPIC_TITLE",
96
- "available_stories": $STORY_COUNT,
97
- "first_story": {
98
- "id": "$STORY_ID",
99
- "title": "$STORY_TITLE",
100
- "points": $STORY_POINTS,
101
- "workflow": "$STORY_WORKFLOW",
102
- "repos": "$STORY_REPOS",
103
- "acceptance_criteria": $STORY_AC
104
- }
105
- }
106
- EOF
107
- else
108
- cat <<EOF
109
- {
110
- "type": "epic",
111
- "id": "$ID",
112
- "title": "$EPIC_TITLE",
113
- "available_stories": 0,
114
- "first_story": null,
115
- "message": "No available stories in this epic"
116
- }
117
- EOF
118
- fi
119
- exit 0
120
- fi
121
-
122
- # Check if it's a story
123
- STORY_DATA=$(yq -o json ".epics[].stories[] | select(.id == \"$ID\")" "$SPRINT_FILE" 2>/dev/null || echo "")
124
-
125
- if [[ -n "$STORY_DATA" && "$STORY_DATA" != "null" ]]; then
126
- STATUS=$(echo "$STORY_DATA" | yq -r '.status // "backlog"')
127
- ASSIGNED=$(echo "$STORY_DATA" | yq -r '.assigned_to // ""')
128
- TITLE=$(echo "$STORY_DATA" | yq -r '.title // "Unknown"')
129
- POINTS=$(echo "$STORY_DATA" | yq -r '.points // 0')
130
- WORKFLOW=$(echo "$STORY_DATA" | yq -r '.workflow // "tdd"')
131
- EPIC_ID=$(yq -r ".epics[] | select(.stories[].id == \"$ID\") | .id" "$SPRINT_FILE" 2>/dev/null | head -1)
132
- REPOS=$(echo "$STORY_DATA" | yq -r '.repos // "pennyfarthing"')
133
-
134
- # Story is available if status is backlog/ready and not assigned
135
- if [[ ("$STATUS" == "backlog" || "$STATUS" == "ready") && -z "$ASSIGNED" ]]; then
136
- AVAILABLE="true"
137
- else
138
- AVAILABLE="false"
139
- fi
140
-
141
- # Get acceptance criteria as JSON array
142
- AC=$(echo "$STORY_DATA" | yq -o json '.acceptance_criteria // []')
143
-
144
- cat <<EOF
145
- {
146
- "type": "story",
147
- "id": "$ID",
148
- "title": "$TITLE",
149
- "points": $POINTS,
150
- "workflow": "$WORKFLOW",
151
- "status": "$STATUS",
152
- "assigned_to": "$ASSIGNED",
153
- "epic_id": "$EPIC_ID",
154
- "repos": "$REPOS",
155
- "available": $AVAILABLE,
156
- "acceptance_criteria": $AC
157
- }
158
- EOF
159
- exit 0
160
- fi
161
-
162
- # Not found
163
- echo '{"type": "not_found", "id": "'"$ID"'", "message": "Story or epic not found in current sprint"}'
164
- exit 0
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env zsh
2
- # Create a Jira epic and its child stories from sprint YAML
3
- # Usage: create-jira-epic.sh <epic-id> [--dry-run]
4
- #
5
- # Thin wrapper that delegates to Python CLI:
6
- # python -m pennyfarthing_scripts.jira create epic <epic-id> [--dry-run]
7
-
8
- set -e
9
-
10
- # Source common functions for Python discovery
11
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12
- # Navigate up from skills/sprint/scripts/ to pennyfarthing-dist/scripts/lib/
13
- LIB_DIR="$(cd "$SCRIPT_DIR/../../../scripts/lib" 2>/dev/null && pwd || echo "")"
14
-
15
- if [[ -n "$LIB_DIR" && -f "$LIB_DIR/common.sh" ]]; then
16
- source "$LIB_DIR/common.sh"
17
- run_python_module jira create epic "$@"
18
- else
19
- # Fallback: set PYTHONPATH directly
20
- PACKAGE_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd -P)"
21
- export PYTHONPATH="${PACKAGE_ROOT}:${PYTHONPATH:-}"
22
- exec python3 -m pennyfarthing_scripts.jira create epic "$@"
23
- fi
@@ -1,116 +0,0 @@
1
- #!/bin/bash
2
- # Initialize a new sprint from template
3
- # Usage: .pennyfarthing/scripts/sprint/new-sprint.sh <sprint-yyww> <jira-id> <start-date> <end-date> "<goal>"
4
- #
5
- # Example: .pennyfarthing/scripts/sprint/new-sprint.sh 2605 277 2026-02-03 2026-02-16 "Polish and stabilization"
6
-
7
- set -euo pipefail
8
-
9
- SPRINT_YYWW="${1:-}"
10
- JIRA_ID="${2:-}"
11
- START_DATE="${3:-}"
12
- END_DATE="${4:-}"
13
- GOAL="${5:-}"
14
-
15
- if [[ -z "$SPRINT_YYWW" || -z "$JIRA_ID" || -z "$START_DATE" || -z "$END_DATE" || -z "$GOAL" ]]; then
16
- echo "Usage: new-sprint.sh <sprint-yyww> <jira-id> <start-date> <end-date> \"<goal>\""
17
- echo ""
18
- echo "Arguments:"
19
- echo " sprint-yyww Sprint identifier in YYWW format (e.g., 2605 for 2026 week 5)"
20
- echo " jira-id Jira sprint ID number (e.g., 277)"
21
- echo " start-date Sprint start date YYYY-MM-DD"
22
- echo " end-date Sprint end date YYYY-MM-DD"
23
- echo " goal Sprint goal (quoted string)"
24
- echo ""
25
- echo "Example:"
26
- echo " new-sprint.sh 2605 277 2026-02-03 2026-02-16 \"Polish and stabilization\""
27
- exit 1
28
- fi
29
-
30
- # PROJECT_ROOT should be set by find-root.sh, but find it if not
31
- if [[ -z "${PROJECT_ROOT:-}" ]]; then
32
- d="$PWD"
33
- while [[ ! -d "$d/.claude" ]] && [[ "$d" != "/" ]]; do
34
- d="$(dirname "$d")"
35
- done
36
- PROJECT_ROOT="$d"
37
- fi
38
- TEMPLATE_FILE="$PROJECT_ROOT/sprint/sprint-template.yaml"
39
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
40
- ARCHIVE_FILE="$PROJECT_ROOT/sprint/archive/sprint-${SPRINT_YYWW}-completed.yaml"
41
-
42
- # Check template exists
43
- if [[ ! -f "$TEMPLATE_FILE" ]]; then
44
- echo "Error: Template file not found at $TEMPLATE_FILE"
45
- exit 1
46
- fi
47
-
48
- # Warn if current sprint file exists and is active
49
- if [[ -f "$SPRINT_FILE" ]]; then
50
- if ! command -v yq &> /dev/null; then
51
- echo "Warning: yq not installed, cannot check current sprint status"
52
- else
53
- CURRENT_STATUS=$(yq eval '.sprint.status' "$SPRINT_FILE")
54
- if [[ "$CURRENT_STATUS" == "active" ]]; then
55
- echo "Warning: Current sprint is still active!"
56
- echo "Current sprint file will be overwritten."
57
- echo ""
58
- read -p "Continue? [y/N] " -n 1 -r
59
- echo
60
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
61
- echo "Aborted."
62
- exit 1
63
- fi
64
- fi
65
- fi
66
- fi
67
-
68
- # Create new sprint file
69
- cat > "$SPRINT_FILE" << EOF
70
- sprint:
71
- name: "TO Sprint $SPRINT_YYWW"
72
- jira_sprint_id: $JIRA_ID
73
- jira_sprint_name: "TO Sprint $SPRINT_YYWW"
74
- goal: $GOAL
75
- start_date: $START_DATE
76
- end_date: $END_DATE
77
- status: active
78
-
79
- # Completed stories archived to: sprint/archive/sprint-${SPRINT_YYWW}-completed.yaml
80
-
81
- epics:
82
- # Add epics and stories here
83
- # See sprint/sprint-template.yaml for format reference
84
- EOF
85
-
86
- echo "Created $SPRINT_FILE"
87
-
88
- # Create archive file
89
- cat > "$ARCHIVE_FILE" << EOF
90
- # Sprint TO Sprint $SPRINT_YYWW - Completed Stories
91
- # Jira Sprint ID: $JIRA_ID
92
- # Archived: $(date +%Y-%m-%d)
93
-
94
- sprint:
95
- name: "TO Sprint $SPRINT_YYWW"
96
- jira_sprint_id: $JIRA_ID
97
- jira_sprint_name: "TO Sprint $SPRINT_YYWW"
98
- goal: $GOAL
99
-
100
- completed:
101
- # Completed stories will be appended here by archive-story.sh
102
- EOF
103
-
104
- echo "Created $ARCHIVE_FILE"
105
-
106
- echo ""
107
- echo "New sprint initialized:"
108
- echo " Name: TO Sprint $SPRINT_YYWW"
109
- echo " Jira ID: $JIRA_ID"
110
- echo " Dates: $START_DATE to $END_DATE"
111
- echo " Goal: $GOAL"
112
- echo ""
113
- echo "Next steps:"
114
- echo " 1. Add epics and stories to $SPRINT_FILE"
115
- echo " 2. Use sprint-status.sh to check progress"
116
- echo " 3. Use archive-story.sh to move completed stories"
@@ -1,164 +0,0 @@
1
- #!/bin/bash
2
- # Promote an epic from planning.yaml to current-sprint.yaml
3
- # Usage: .pennyfarthing/scripts/sprint/promote-epic.sh <epic-id>
4
- #
5
- # Example: .pennyfarthing/scripts/sprint/promote-epic.sh epic-41
6
-
7
- set -euo pipefail
8
-
9
- EPIC_ID="${1:-}"
10
-
11
- if [[ -z "$EPIC_ID" ]]; then
12
- echo "Usage: promote-epic.sh <epic-id>"
13
- echo "Example: promote-epic.sh epic-41"
14
- echo ""
15
- echo "Moves an epic and its stories from planning.yaml to current-sprint.yaml"
16
- exit 1
17
- fi
18
-
19
- # PROJECT_ROOT should be set by find-root.sh, but find it if not
20
- if [[ -z "${PROJECT_ROOT:-}" ]]; then
21
- d="$PWD"
22
- while [[ ! -d "$d/.claude" ]] && [[ "$d" != "/" ]]; do
23
- d="$(dirname "$d")"
24
- done
25
- PROJECT_ROOT="$d"
26
- fi
27
-
28
- PLANNING_FILE="$PROJECT_ROOT/sprint/planning.yaml"
29
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
30
-
31
- if [[ ! -f "$PLANNING_FILE" ]]; then
32
- echo "Error: Planning file not found at $PLANNING_FILE"
33
- exit 1
34
- fi
35
-
36
- if [[ ! -f "$SPRINT_FILE" ]]; then
37
- echo "Error: Sprint file not found at $SPRINT_FILE"
38
- exit 1
39
- fi
40
-
41
- if ! command -v yq &> /dev/null; then
42
- echo "Error: yq is required but not installed"
43
- echo "Install with: brew install yq"
44
- exit 1
45
- fi
46
-
47
- # Find the epic in planning.yaml
48
- # Epics are nested under planning.initiatives[].epics[]
49
- EPIC_DATA=$(yq -o json ".planning.initiatives[].epics[] | select(.id == \"$EPIC_ID\")" "$PLANNING_FILE" 2>/dev/null || echo "")
50
-
51
- if [[ -z "$EPIC_DATA" || "$EPIC_DATA" == "null" ]]; then
52
- echo "Error: Epic $EPIC_ID not found in $PLANNING_FILE"
53
- echo ""
54
- echo "Available epics:"
55
- yq '.planning.initiatives[].epics[].id' "$PLANNING_FILE" 2>/dev/null || echo " None found"
56
- exit 1
57
- fi
58
-
59
- # Extract epic fields
60
- EPIC_TITLE=$(echo "$EPIC_DATA" | yq -r '.title // "Unknown"')
61
- EPIC_DESCRIPTION=$(echo "$EPIC_DATA" | yq -r '.description // ""')
62
- EPIC_POINTS=$(echo "$EPIC_DATA" | yq -r '.points // 0')
63
- EPIC_PRIORITY=$(echo "$EPIC_DATA" | yq -r '.priority // "P2"')
64
- EPIC_REPOS=$(echo "$EPIC_DATA" | yq -r '.repos // "pennyfarthing"')
65
- STORY_COUNT=$(echo "$EPIC_DATA" | yq '[.stories[]] | length')
66
-
67
- echo ""
68
- echo "Promoting epic to current sprint:"
69
- echo " ID: $EPIC_ID"
70
- echo " Title: $EPIC_TITLE"
71
- echo " Points: $EPIC_POINTS"
72
- echo " Priority: $EPIC_PRIORITY"
73
- echo " Stories: $STORY_COUNT"
74
- echo ""
75
-
76
- # Generate the epic YAML block for current-sprint.yaml
77
- # The format must match existing epics in current-sprint.yaml
78
- EPIC_YAML=$(cat <<EOF
79
- - id: $EPIC_ID
80
- type: epic
81
- title: "Epic: $EPIC_TITLE"
82
- description: |
83
- $(echo "$EPIC_DESCRIPTION" | sed 's/^/ /')
84
- priority: $EPIC_PRIORITY
85
- status: backlog
86
- repos: $EPIC_REPOS
87
- stories:
88
- EOF
89
- )
90
-
91
- # Get stories and format them using a helper function
92
- format_story() {
93
- local story_json="$1"
94
- local id title desc points priority repos workflow
95
-
96
- id=$(echo "$story_json" | yq -r '.id // ""')
97
- title=$(echo "$story_json" | yq -r '.title // ""')
98
- desc=$(echo "$story_json" | yq -r '.description // ""')
99
- points=$(echo "$story_json" | yq -r '.points // 0')
100
- priority=$(echo "$story_json" | yq -r '.priority // "P2"')
101
- repos=$(echo "$story_json" | yq -r '.repos // "pennyfarthing"')
102
- workflow=$(echo "$story_json" | yq -r '.workflow // "tdd"')
103
-
104
- # Format description with proper indentation
105
- local desc_formatted
106
- desc_formatted=$(echo "$desc" | sed 's/^/ /')
107
-
108
- # Build story YAML
109
- echo " - id: $id"
110
- echo " title: \"$title\""
111
- echo " description: |"
112
- echo "$desc_formatted"
113
- echo " points: $points"
114
- echo " priority: $priority"
115
- echo " status: backlog"
116
- echo " repos: $repos"
117
- echo " workflow: $workflow"
118
-
119
- # Handle acceptance_criteria - check if array exists and has items
120
- local ac_count
121
- ac_count=$(echo "$story_json" | yq -r '(.acceptance_criteria // []) | length')
122
- if [[ "$ac_count" -gt 0 ]]; then
123
- echo " acceptance_criteria:"
124
- echo "$story_json" | yq -r '(.acceptance_criteria // [])[] | " - " + .'
125
- else
126
- echo " acceptance_criteria: []"
127
- fi
128
- }
129
-
130
- # Process each story
131
- STORIES_YAML=""
132
- story_count=$(echo "$EPIC_DATA" | yq -r '.stories | length')
133
- for i in $(seq 0 $((story_count - 1))); do
134
- story_json=$(echo "$EPIC_DATA" | yq -o json ".stories[$i]")
135
- if [[ -n "$STORIES_YAML" ]]; then
136
- STORIES_YAML="$STORIES_YAML
137
- $(format_story "$story_json")"
138
- else
139
- STORIES_YAML=$(format_story "$story_json")
140
- fi
141
- done
142
-
143
- # Combine epic and stories
144
- FULL_EPIC_YAML="$EPIC_YAML
145
- $STORIES_YAML"
146
-
147
- echo "Epic YAML to append:"
148
- echo "---"
149
- echo "$FULL_EPIC_YAML"
150
- echo "---"
151
- echo ""
152
-
153
- # Append to current-sprint.yaml epics section
154
- echo "$FULL_EPIC_YAML" >> "$SPRINT_FILE"
155
-
156
- echo "Appended epic to $SPRINT_FILE"
157
- echo ""
158
- echo "To remove from planning.yaml, manually edit or use:"
159
- echo " yq eval -i 'del(.planning.initiatives[].epics[] | select(.id == \"$EPIC_ID\"))' $PLANNING_FILE"
160
- echo ""
161
- echo "Next steps:"
162
- echo " 1. Review the appended YAML in $SPRINT_FILE"
163
- echo " 2. Optionally create Jira epic: .pennyfarthing/scripts/sprint/create-jira-epic.sh $EPIC_ID"
164
- echo " 3. Remove from planning.yaml if desired"
@@ -1,39 +0,0 @@
1
- #!/bin/bash
2
- # Output sprint info as JSON for Cyclist sidebar
3
- # Usage: .pennyfarthing/scripts/sprint/sprint-info.sh
4
- #
5
- # Returns: {"remaining": N, "inProgress": N, "endDate": "YYYY-MM-DD"}
6
-
7
- set -euo pipefail
8
-
9
- # PROJECT_ROOT should be set by find-root.sh
10
- if [[ -z "${PROJECT_ROOT:-}" ]]; then
11
- d="$PWD"
12
- while [[ ! -d "$d/.claude" ]] && [[ "$d" != "/" ]]; do
13
- d="$(dirname "$d")"
14
- done
15
- PROJECT_ROOT="$d"
16
- fi
17
-
18
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
19
-
20
- if [[ ! -f "$SPRINT_FILE" ]]; then
21
- echo '{"remaining": 0, "inProgress": 0, "endDate": null}'
22
- exit 0
23
- fi
24
-
25
- # Extract end date
26
- END_DATE=$(yq -r '.sprint.end_date // ""' "$SPRINT_FILE")
27
- if [[ -z "$END_DATE" || "$END_DATE" == "null" ]]; then
28
- END_DATE="null"
29
- else
30
- END_DATE="\"$END_DATE\""
31
- fi
32
-
33
- # Calculate remaining points (backlog stories) - use awk for sum since yq add is problematic
34
- REMAINING=$(yq '.epics[].stories[] | select(.status == "backlog" or .status == null) | .points // 0' "$SPRINT_FILE" 2>/dev/null | awk '{sum+=$1} END {print sum+0}')
35
-
36
- # Calculate in-progress points
37
- IN_PROGRESS=$(yq '.epics[].stories[] | select(.status == "in_progress") | .points // 0' "$SPRINT_FILE" 2>/dev/null | awk '{sum+=$1} END {print sum+0}')
38
-
39
- echo "{\"remaining\": $REMAINING, \"inProgress\": $IN_PROGRESS, \"endDate\": $END_DATE}"