@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,133 +0,0 @@
1
- #!/bin/bash
2
- # Archive a completed story from current-sprint.yaml to the sprint archive
3
- # Usage: .pennyfarthing/scripts/sprint/archive-story.sh <story-id> [pr-number] [--apply]
4
- #
5
- # Example: .pennyfarthing/scripts/sprint/archive-story.sh MSSCI-11945 368
6
- # .pennyfarthing/scripts/sprint/archive-story.sh MSSCI-11945 368 --apply
7
- #
8
- # Options:
9
- # --apply Also remove story from current-sprint.yaml (atomic operation)
10
-
11
- set -euo pipefail
12
-
13
- STORY_ID="${1:-}"
14
- PR_NUMBER=""
15
- APPLY_FLAG=false
16
-
17
- # Parse positional and flag arguments
18
- shift || true
19
- for arg in "$@"; do
20
- case $arg in
21
- --apply)
22
- APPLY_FLAG=true
23
- ;;
24
- *)
25
- # If not a flag, it's the PR number
26
- if [[ -z "$PR_NUMBER" ]]; then
27
- PR_NUMBER="$arg"
28
- fi
29
- ;;
30
- esac
31
- done
32
-
33
- if [[ -z "$STORY_ID" ]]; then
34
- echo "Usage: archive-story.sh <story-id> [pr-number] [--apply]"
35
- echo "Example: archive-story.sh MSSCI-11945 368"
36
- echo " archive-story.sh MSSCI-11945 368 --apply"
37
- echo ""
38
- echo "Options:"
39
- echo " --apply Also remove story from current-sprint.yaml"
40
- exit 1
41
- fi
42
-
43
- # Find project root
44
- source "$(dirname "${BASH_SOURCE[0]}")/../lib/find-root.sh"
45
-
46
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
47
-
48
- if [[ ! -f "$SPRINT_FILE" ]]; then
49
- echo "Error: Sprint file not found at $SPRINT_FILE"
50
- exit 1
51
- fi
52
-
53
- # Extract sprint name to determine archive file
54
- # Try jira_sprint_name first (newer format), then fall back to name (older format)
55
- SPRINT_NAME=$(grep -E "^\s+jira_sprint_name:" "$SPRINT_FILE" | head -1 | sed 's/.*TO Sprint \([0-9]*\).*/\1/')
56
- if [[ -z "$SPRINT_NAME" ]]; then
57
- SPRINT_NAME=$(grep -E "^\s+name:" "$SPRINT_FILE" | head -1 | sed 's/.*"TO Sprint \([0-9]*\)".*/\1/')
58
- fi
59
- if [[ -z "$SPRINT_NAME" ]]; then
60
- echo "Error: Could not extract sprint name from $SPRINT_FILE"
61
- exit 1
62
- fi
63
-
64
- ARCHIVE_FILE="$PROJECT_ROOT/sprint/archive/sprint-${SPRINT_NAME}-completed.yaml"
65
-
66
- # Check if archive file exists
67
- if [[ ! -f "$ARCHIVE_FILE" ]]; then
68
- echo "Error: Archive file not found at $ARCHIVE_FILE"
69
- echo "Create it first with new-sprint.sh or manually"
70
- exit 1
71
- fi
72
-
73
- # Use yq to extract story data
74
- if ! command -v yq &> /dev/null; then
75
- echo "Error: yq is required but not installed"
76
- echo "Install with: brew install yq"
77
- exit 1
78
- fi
79
-
80
- # Find the story in current sprint
81
- STORY_DATA=$(yq eval ".epics[].stories[] | select(.id == \"$STORY_ID\")" "$SPRINT_FILE")
82
-
83
- if [[ -z "$STORY_DATA" ]]; then
84
- echo "Error: Story $STORY_ID not found in $SPRINT_FILE"
85
- exit 1
86
- fi
87
-
88
- # Extract story fields
89
- TITLE=$(echo "$STORY_DATA" | yq eval '.title' -)
90
- POINTS=$(echo "$STORY_DATA" | yq eval '.points' -)
91
- EPIC_ID=$(yq eval ".epics[] | select(.stories[].id == \"$STORY_ID\") | .id" "$SPRINT_FILE" | head -1)
92
-
93
- # Get today's date
94
- COMPLETED_DATE=$(date +%Y-%m-%d)
95
-
96
- # Build the archive entry
97
- echo ""
98
- echo "Archiving story:"
99
- echo " ID: $STORY_ID"
100
- echo " Title: $TITLE"
101
- echo " Points: $POINTS"
102
- echo " Epic: $EPIC_ID"
103
- echo " Completed: $COMPLETED_DATE"
104
- [[ -n "$PR_NUMBER" ]] && echo " PR: $PR_NUMBER"
105
- echo ""
106
-
107
- # Append to archive file
108
- {
109
- echo " - id: $STORY_ID"
110
- echo " epic: $EPIC_ID"
111
- echo " title: \"$TITLE\""
112
- echo " points: $POINTS"
113
- echo " completed: $COMPLETED_DATE"
114
- [[ -n "$PR_NUMBER" ]] && echo " pr: $PR_NUMBER"
115
- } >> "$ARCHIVE_FILE"
116
-
117
- echo "Added to $ARCHIVE_FILE"
118
-
119
- # Remove from current sprint (if --apply)
120
- if $APPLY_FLAG; then
121
- echo ""
122
- echo "Removing story from current sprint..."
123
- yq eval -i "del(.epics[].stories[] | select(.id == \"$STORY_ID\"))" "$SPRINT_FILE"
124
- echo "✓ Story removed from $SPRINT_FILE"
125
- echo ""
126
- echo "If the epic has no more stories, you may want to remove the empty epic section."
127
- else
128
- echo ""
129
- echo "To also remove from $SPRINT_FILE, re-run with --apply:"
130
- echo " .pennyfarthing/scripts/sprint/archive-story.sh $STORY_ID ${PR_NUMBER:-<pr>} --apply"
131
- echo ""
132
- echo "Or manually: yq eval -i 'del(.epics[].stories[] | select(.id == \"$STORY_ID\"))' $SPRINT_FILE"
133
- fi
@@ -1,91 +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
- # Find project root
10
- source "$(dirname "${BASH_SOURCE[0]}")/../lib/find-root.sh"
11
-
12
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
13
-
14
- if [[ ! -f "$SPRINT_FILE" ]]; then
15
- echo "Error: Sprint file not found at $SPRINT_FILE"
16
- exit 1
17
- fi
18
-
19
- if ! command -v yq &> /dev/null; then
20
- echo "Error: yq is required but not installed"
21
- echo "Install with: brew install yq"
22
- exit 1
23
- fi
24
-
25
- if ! command -v jira &> /dev/null; then
26
- echo "Error: jira CLI is required but not installed"
27
- echo "Install with: brew install ankitpokhrel/jira/jira"
28
- exit 1
29
- fi
30
-
31
- # Extract sprint info
32
- SPRINT_NAME=$(yq '.sprint.name' "$SPRINT_FILE")
33
- echo "# Available Stories - $SPRINT_NAME"
34
- echo ""
35
-
36
- # Get all epic IDs from the sprint file
37
- EPIC_IDS=$(yq '.epics[].id' "$SPRINT_FILE" | tr '\n' ' ')
38
-
39
- # Batch fetch epic details from Jira
40
- echo "Fetching epic details from Jira..."
41
- echo ""
42
-
43
- # Process each epic
44
- for EPIC_ID in $EPIC_IDS; do
45
- # Get epic title from sprint YAML (faster than Jira for display)
46
- EPIC_TITLE=$(yq ".epics[] | select(.id == \"$EPIC_ID\") | .title" "$SPRINT_FILE")
47
-
48
- # Get stories for this epic that are available (backlog or ready)
49
- 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 ' ')
50
-
51
- if [[ "$STORY_COUNT" -eq 0 ]]; then
52
- continue
53
- fi
54
-
55
- # Fetch epic description from Jira for context (if it's a valid Jira key)
56
- # Jira uses Atlassian Document Format - extract text content from paragraphs
57
- EPIC_DESCRIPTION=""
58
- if [[ "$EPIC_ID" =~ ^MSSCI-[0-9]+$ ]]; then
59
- EPIC_DESCRIPTION=$(jira issue view "$EPIC_ID" --raw 2>/dev/null | \
60
- jq -r '.fields.description.content[]? | select(.type == "paragraph") | .content[]? | select(.type == "text") | .text' 2>/dev/null | \
61
- head -3 | tr '\n' ' ' | cut -c1-200)
62
- fi
63
-
64
- echo "## $EPIC_TITLE"
65
- if [[ -n "$EPIC_DESCRIPTION" ]]; then
66
- echo "*$EPIC_DESCRIPTION*"
67
- fi
68
- echo ""
69
- echo "| ID | Title | Pts | Pri | Status | Workflow |"
70
- echo "|----|-------|-----|-----|--------|----------|"
71
-
72
- # Get available stories for this epic (backlog or ready)
73
- yq -o=json ".epics[] | select(.id == \"$EPIC_ID\") | .stories[] | select(.status == \"backlog\" or .status == \"ready\")" "$SPRINT_FILE" 2>/dev/null | \
74
- jq -r '[.id, .title, (.points | tostring), (.priority // "P2"), (.status // "backlog"), (.workflow // "tdd")] | @tsv' | \
75
- while IFS=$'\t' read -r story_id story_title story_points story_priority story_status story_workflow; do
76
- # Truncate title if too long
77
- if [[ ${#story_title} -gt 40 ]]; then
78
- story_title="${story_title:0:37}..."
79
- fi
80
- echo "| $story_id | $story_title | $story_points | $story_priority | $story_status | $story_workflow |"
81
- done
82
-
83
- echo ""
84
- done
85
-
86
- # Summary
87
- TOTAL_BACKLOG=$(yq '[.epics[].stories[] | select(.status == "backlog" or .status == "ready")] | length' "$SPRINT_FILE")
88
- TOTAL_POINTS=$(yq '.epics[].stories[] | select(.status == "backlog" or .status == "ready") | .points' "$SPRINT_FILE" | paste -sd+ - | bc 2>/dev/null || echo "0")
89
-
90
- echo "---"
91
- echo "**Total available:** $TOTAL_BACKLOG stories, $TOTAL_POINTS points"
@@ -1,158 +0,0 @@
1
- #!/bin/bash
2
- # Check if a story or epic exists and is available for work
3
- # Usage: 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
- # Find project root
22
- source "$(dirname "${BASH_SOURCE[0]}")/../lib/find-root.sh"
23
-
24
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
25
-
26
- if [[ ! -f "$SPRINT_FILE" ]]; then
27
- echo '{"type": "error", "message": "Sprint file not found"}'
28
- exit 1
29
- fi
30
-
31
- # Handle "next" argument - find highest priority available story
32
- if [[ "$ID" == "next" ]]; then
33
- # Get all available stories (backlog or ready), sort by priority, take first
34
- 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")
35
-
36
- if [[ "$NEXT_STORY" != "null" && -n "$NEXT_STORY" ]]; then
37
- STORY_ID=$(echo "$NEXT_STORY" | yq -r '.id')
38
- STORY_TITLE=$(echo "$NEXT_STORY" | yq -r '.title')
39
- STORY_POINTS=$(echo "$NEXT_STORY" | yq -r '.points // 0')
40
- STORY_PRIORITY=$(echo "$NEXT_STORY" | yq -r '.priority // "P2"')
41
- STORY_WORKFLOW=$(echo "$NEXT_STORY" | yq -r '.workflow // "tdd"')
42
- STORY_REPOS=$(echo "$NEXT_STORY" | yq -r '.repos // "pennyfarthing"')
43
- STORY_AC=$(echo "$NEXT_STORY" | yq -o json '.acceptance_criteria // []')
44
- EPIC_ID=$(yq -r ".epics[] | select(.stories[].id == \"$STORY_ID\") | .id" "$SPRINT_FILE" 2>/dev/null | head -1)
45
-
46
- cat <<EOF
47
- {
48
- "type": "next",
49
- "story": {
50
- "id": "$STORY_ID",
51
- "title": "$STORY_TITLE",
52
- "points": $STORY_POINTS,
53
- "priority": "$STORY_PRIORITY",
54
- "workflow": "$STORY_WORKFLOW",
55
- "repos": "$STORY_REPOS",
56
- "epic_id": "$EPIC_ID",
57
- "acceptance_criteria": $STORY_AC
58
- }
59
- }
60
- EOF
61
- else
62
- echo '{"type": "next", "story": null, "message": "No available stories in backlog"}'
63
- fi
64
- exit 0
65
- fi
66
-
67
- # Check if it's an epic
68
- EPIC_DATA=$(yq -o json ".epics[] | select(.id == \"$ID\")" "$SPRINT_FILE" 2>/dev/null || echo "")
69
-
70
- if [[ -n "$EPIC_DATA" && "$EPIC_DATA" != "null" ]]; then
71
- # It's an epic - get first available story by priority
72
- 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")
73
-
74
- EPIC_TITLE=$(echo "$EPIC_DATA" | yq -r '.title // "Unknown"')
75
- 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")
76
-
77
- if [[ "$FIRST_STORY" != "null" && -n "$FIRST_STORY" ]]; then
78
- STORY_ID=$(echo "$FIRST_STORY" | yq -r '.id')
79
- STORY_TITLE=$(echo "$FIRST_STORY" | yq -r '.title')
80
- STORY_POINTS=$(echo "$FIRST_STORY" | yq -r '.points // 0')
81
- STORY_WORKFLOW=$(echo "$FIRST_STORY" | yq -r '.workflow // "tdd"')
82
- STORY_REPOS=$(echo "$FIRST_STORY" | yq -r '.repos // "pennyfarthing"')
83
- STORY_AC=$(echo "$FIRST_STORY" | yq -o json '.acceptance_criteria // []')
84
-
85
- cat <<EOF
86
- {
87
- "type": "epic",
88
- "id": "$ID",
89
- "title": "$EPIC_TITLE",
90
- "available_stories": $STORY_COUNT,
91
- "first_story": {
92
- "id": "$STORY_ID",
93
- "title": "$STORY_TITLE",
94
- "points": $STORY_POINTS,
95
- "workflow": "$STORY_WORKFLOW",
96
- "repos": "$STORY_REPOS",
97
- "acceptance_criteria": $STORY_AC
98
- }
99
- }
100
- EOF
101
- else
102
- cat <<EOF
103
- {
104
- "type": "epic",
105
- "id": "$ID",
106
- "title": "$EPIC_TITLE",
107
- "available_stories": 0,
108
- "first_story": null,
109
- "message": "No available stories in this epic"
110
- }
111
- EOF
112
- fi
113
- exit 0
114
- fi
115
-
116
- # Check if it's a story
117
- STORY_DATA=$(yq -o json ".epics[].stories[] | select(.id == \"$ID\")" "$SPRINT_FILE" 2>/dev/null || echo "")
118
-
119
- if [[ -n "$STORY_DATA" && "$STORY_DATA" != "null" ]]; then
120
- STATUS=$(echo "$STORY_DATA" | yq -r '.status // "backlog"')
121
- ASSIGNED=$(echo "$STORY_DATA" | yq -r '.assigned_to // ""')
122
- TITLE=$(echo "$STORY_DATA" | yq -r '.title // "Unknown"')
123
- POINTS=$(echo "$STORY_DATA" | yq -r '.points // 0')
124
- WORKFLOW=$(echo "$STORY_DATA" | yq -r '.workflow // "tdd"')
125
- EPIC_ID=$(yq -r ".epics[] | select(.stories[].id == \"$ID\") | .id" "$SPRINT_FILE" 2>/dev/null | head -1)
126
- REPOS=$(echo "$STORY_DATA" | yq -r '.repos // "pennyfarthing"')
127
-
128
- # Story is available if status is backlog/ready and not assigned
129
- if [[ ("$STATUS" == "backlog" || "$STATUS" == "ready") && -z "$ASSIGNED" ]]; then
130
- AVAILABLE="true"
131
- else
132
- AVAILABLE="false"
133
- fi
134
-
135
- # Get acceptance criteria as JSON array
136
- AC=$(echo "$STORY_DATA" | yq -o json '.acceptance_criteria // []')
137
-
138
- cat <<EOF
139
- {
140
- "type": "story",
141
- "id": "$ID",
142
- "title": "$TITLE",
143
- "points": $POINTS,
144
- "workflow": "$WORKFLOW",
145
- "status": "$STATUS",
146
- "assigned_to": "$ASSIGNED",
147
- "epic_id": "$EPIC_ID",
148
- "repos": "$REPOS",
149
- "available": $AVAILABLE,
150
- "acceptance_criteria": $AC
151
- }
152
- EOF
153
- exit 0
154
- fi
155
-
156
- # Not found
157
- echo '{"type": "not_found", "id": "'"$ID"'", "message": "Story or epic not found in current sprint"}'
158
- exit 0
@@ -1,52 +0,0 @@
1
- #!/bin/bash
2
- # Get a field value from an epic in sprint YAML
3
- # Usage: .pennyfarthing/scripts/sprint/get-epic-field.sh <epic-id> <field>
4
- #
5
- # Examples:
6
- # .pennyfarthing/scripts/sprint/get-epic-field.sh epic-35 jira
7
- # .pennyfarthing/scripts/sprint/get-epic-field.sh epic-35 title
8
- # .pennyfarthing/scripts/sprint/get-epic-field.sh 35 jira # Also works without 'epic-' prefix
9
- #
10
- # Common fields: jira, title, description, status
11
- # Returns the field value or "null" if not found
12
-
13
- set -euo pipefail
14
-
15
- EPIC_ID="${1:-}"
16
- FIELD="${2:-}"
17
-
18
- if [[ -z "$EPIC_ID" || -z "$FIELD" ]]; then
19
- echo "Usage: get-epic-field.sh <epic-id> <field>"
20
- echo ""
21
- echo "Examples:"
22
- echo " get-epic-field.sh epic-35 jira # Returns: MSSCI-11234"
23
- echo " get-epic-field.sh epic-35 title # Returns: Epic title"
24
- echo " get-epic-field.sh 35 jira # Also works without 'epic-' prefix"
25
- echo ""
26
- echo "Common fields: jira, title, description, status"
27
- exit 1
28
- fi
29
-
30
- # Normalize epic ID - add 'epic-' prefix if not present
31
- if [[ ! "$EPIC_ID" =~ ^epic- ]]; then
32
- EPIC_ID="epic-$EPIC_ID"
33
- fi
34
-
35
- # Find project root
36
- source "$(dirname "${BASH_SOURCE[0]}")/../lib/find-root.sh"
37
-
38
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
39
-
40
- if [[ ! -f "$SPRINT_FILE" ]]; then
41
- echo "null"
42
- exit 1
43
- fi
44
-
45
- # Extract field value using yq
46
- VALUE=$(yq eval ".epics[] | select(.id == \"$EPIC_ID\") | .$FIELD // \"null\"" "$SPRINT_FILE" 2>/dev/null | head -1)
47
-
48
- if [[ -z "$VALUE" ]]; then
49
- echo "null"
50
- else
51
- echo "$VALUE"
52
- fi
@@ -1,63 +0,0 @@
1
- #!/bin/bash
2
- # Get a field value from a story in sprint YAML
3
- # Usage: .pennyfarthing/scripts/sprint/get-story-field.sh <story-id> <field>
4
- #
5
- # Examples:
6
- # .pennyfarthing/scripts/sprint/get-story-field.sh 35-2 workflow
7
- # .pennyfarthing/scripts/sprint/get-story-field.sh 35-2 jira
8
- # .pennyfarthing/scripts/sprint/get-story-field.sh 35-2 status
9
- #
10
- # Common fields: workflow, status, jira, points, title, repos, priority
11
- # Returns the field value or "null" if not found
12
-
13
- set -euo pipefail
14
-
15
- STORY_ID="${1:-}"
16
- FIELD="${2:-}"
17
-
18
- if [[ -z "$STORY_ID" || -z "$FIELD" ]]; then
19
- echo "Usage: get-story-field.sh <story-id> <field>"
20
- echo ""
21
- echo "Examples:"
22
- echo " get-story-field.sh 35-2 workflow # Returns: tdd"
23
- echo " get-story-field.sh 35-2 jira # Returns: MSSCI-12345"
24
- echo " get-story-field.sh 35-2 status # Returns: in_progress"
25
- echo ""
26
- echo "Common fields: workflow, status, jira, points, title, repos, priority"
27
- exit 1
28
- fi
29
-
30
- # Find project root
31
- source "$(dirname "${BASH_SOURCE[0]}")/../lib/find-root.sh"
32
-
33
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
34
-
35
- if [[ ! -f "$SPRINT_FILE" ]]; then
36
- echo "null"
37
- exit 1
38
- fi
39
-
40
- # Extract field value using yq
41
- # Handle default values for common fields
42
- case "$FIELD" in
43
- workflow)
44
- DEFAULT="tdd"
45
- ;;
46
- status)
47
- DEFAULT="backlog"
48
- ;;
49
- repos)
50
- DEFAULT="pennyfarthing"
51
- ;;
52
- *)
53
- DEFAULT="null"
54
- ;;
55
- esac
56
-
57
- VALUE=$(yq eval ".epics[].stories[] | select(.id == \"$STORY_ID\") | .$FIELD // \"$DEFAULT\"" "$SPRINT_FILE" 2>/dev/null | head -1)
58
-
59
- if [[ -z "$VALUE" ]]; then
60
- echo "null"
61
- else
62
- echo "$VALUE"
63
- fi
@@ -1,145 +0,0 @@
1
- #!/bin/bash
2
- # Display future work initiatives and epics from future.yaml
3
- # Usage: .pennyfarthing/scripts/sprint/list-future.sh [--epic EPIC_ID]
4
- #
5
- # Shows initiatives with their epics, points, status, and blockers
6
- # Use --epic to show detailed stories for a specific epic
7
-
8
- set -euo pipefail
9
-
10
- # Find project root
11
- source "$(dirname "${BASH_SOURCE[0]}")/../lib/find-root.sh"
12
-
13
- FUTURE_FILE="$PROJECT_ROOT/sprint/future.yaml"
14
-
15
- if [[ ! -f "$FUTURE_FILE" ]]; then
16
- echo "Error: Future file not found at $FUTURE_FILE"
17
- exit 1
18
- fi
19
-
20
- if ! command -v yq &> /dev/null; then
21
- echo "Error: yq is required but not installed"
22
- echo "Install with: brew install yq"
23
- exit 1
24
- fi
25
-
26
- # Parse arguments
27
- EPIC_DETAIL=""
28
- while [[ $# -gt 0 ]]; do
29
- case $1 in
30
- --epic)
31
- EPIC_DETAIL="$2"
32
- shift 2
33
- ;;
34
- *)
35
- echo "Unknown argument: $1"
36
- exit 1
37
- ;;
38
- esac
39
- done
40
-
41
- # If specific epic requested, show detailed view
42
- if [[ -n "$EPIC_DETAIL" ]]; then
43
- echo "# Epic Details: $EPIC_DETAIL"
44
- echo ""
45
-
46
- # Find the epic
47
- EPIC_DATA=$(yq -o=json ".future.initiatives[].epics[] | select(.id == \"$EPIC_DETAIL\")" "$FUTURE_FILE" 2>/dev/null)
48
-
49
- if [[ -z "$EPIC_DATA" ]]; then
50
- echo "Error: Epic $EPIC_DETAIL not found in future.yaml"
51
- exit 1
52
- fi
53
-
54
- EPIC_TITLE=$(echo "$EPIC_DATA" | jq -r '.title')
55
- EPIC_DESC=$(echo "$EPIC_DATA" | jq -r '.description // "No description"' | head -5)
56
- EPIC_POINTS=$(echo "$EPIC_DATA" | jq -r '.points')
57
- EPIC_PRIORITY=$(echo "$EPIC_DATA" | jq -r '.priority // "P2"')
58
- EPIC_STATUS=$(echo "$EPIC_DATA" | jq -r '.status // "planning"')
59
-
60
- echo "**Title:** $EPIC_TITLE"
61
- echo "**Points:** $EPIC_POINTS | **Priority:** $EPIC_PRIORITY | **Status:** $EPIC_STATUS"
62
- echo ""
63
- echo "**Description:**"
64
- echo "$EPIC_DESC"
65
- echo ""
66
- echo "## Stories"
67
- echo ""
68
- echo "| ID | Title | Pts | Pri | Status |"
69
- echo "|----|-------|-----|-----|--------|"
70
-
71
- echo "$EPIC_DATA" | jq -r '.stories[]? | [.id, .title, (.points | tostring), (.priority // "P1"), (.status // "planning")] | @tsv' | \
72
- while IFS=$'\t' read -r story_id story_title story_points story_priority story_status; do
73
- # Truncate title if too long
74
- if [[ ${#story_title} -gt 45 ]]; then
75
- story_title="${story_title:0:42}..."
76
- fi
77
- echo "| $story_id | $story_title | $story_points | $story_priority | $story_status |"
78
- done
79
-
80
- echo ""
81
- echo "---"
82
- echo "To promote this epic: \`/sprint promote $EPIC_DETAIL\`"
83
- exit 0
84
- fi
85
-
86
- # Default: show initiative summary
87
- echo "# Future Work - Available for Promotion"
88
- echo ""
89
-
90
- # Get initiatives
91
- INITIATIVE_COUNT=$(yq '.future.initiatives | length' "$FUTURE_FILE")
92
-
93
- for ((i=0; i<INITIATIVE_COUNT; i++)); do
94
- INIT_NAME=$(yq ".future.initiatives[$i].name" "$FUTURE_FILE")
95
- INIT_STATUS=$(yq ".future.initiatives[$i].status // \"planning\"" "$FUTURE_FILE")
96
- INIT_BLOCKED=$(yq ".future.initiatives[$i].blocked_by // \"\"" "$FUTURE_FILE")
97
- INIT_POINTS=$(yq ".future.initiatives[$i].total_points // 0" "$FUTURE_FILE")
98
-
99
- # Status indicator
100
- if [[ "$INIT_STATUS" == "ready" ]]; then
101
- STATUS_ICON="[READY]"
102
- elif [[ -n "$INIT_BLOCKED" && "$INIT_BLOCKED" != "null" ]]; then
103
- STATUS_ICON="[BLOCKED]"
104
- else
105
- STATUS_ICON="[$INIT_STATUS]"
106
- fi
107
-
108
- echo "## $INIT_NAME $STATUS_ICON"
109
- echo "**Total:** $INIT_POINTS points"
110
-
111
- if [[ -n "$INIT_BLOCKED" && "$INIT_BLOCKED" != "null" ]]; then
112
- echo "**Blocked:** $INIT_BLOCKED"
113
- fi
114
- echo ""
115
-
116
- echo "| Epic | Title | Pts | Pri | Status |"
117
- echo "|------|-------|-----|-----|--------|"
118
-
119
- # Get epics for this initiative
120
- yq -o=json ".future.initiatives[$i].epics[]" "$FUTURE_FILE" 2>/dev/null | \
121
- jq -r '[.id, .title, (.points | tostring), (.priority // "P2"), (.status // "planning")] | @tsv' | \
122
- while IFS=$'\t' read -r epic_id epic_title epic_points epic_priority epic_status; do
123
- # Truncate title if too long
124
- if [[ ${#epic_title} -gt 40 ]]; then
125
- epic_title="${epic_title:0:37}..."
126
- fi
127
- echo "| $epic_id | $epic_title | $epic_points | $epic_priority | $epic_status |"
128
- done
129
-
130
- echo ""
131
- done
132
-
133
- # Summary
134
- TOTAL_EPICS=$(yq '[.future.initiatives[].epics[]] | length' "$FUTURE_FILE")
135
- TOTAL_POINTS=$(yq '.future.initiatives[].epics[].points' "$FUTURE_FILE" | paste -sd+ - | bc 2>/dev/null || echo "0")
136
- READY_COUNT=$(yq '[.future.initiatives[] | select(.status == "ready") | .epics[]] | length' "$FUTURE_FILE")
137
-
138
- echo "---"
139
- echo "**Summary:** $TOTAL_EPICS epics, $TOTAL_POINTS points total"
140
- if [[ "$READY_COUNT" -gt 0 ]]; then
141
- echo "**Ready to promote:** $READY_COUNT epics"
142
- fi
143
- echo ""
144
- echo "To see epic details: \`/sprint future --epic epic-55\`"
145
- echo "To promote an epic: \`/sprint promote epic-55\`"