@pennyfarthing/core 10.0.3 → 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 (220) hide show
  1. package/README.md +1 -1
  2. package/package.json +13 -11
  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/init.d.ts.map +1 -1
  12. package/packages/core/dist/cli/commands/init.js +3 -0
  13. package/packages/core/dist/cli/commands/init.js.map +1 -1
  14. package/packages/core/dist/cli/ocean-profiles.test.js +1 -1
  15. package/packages/core/dist/cli/ocean-profiles.test.js.map +1 -1
  16. package/packages/core/dist/cli/utils/files.d.ts +10 -0
  17. package/packages/core/dist/cli/utils/files.d.ts.map +1 -1
  18. package/packages/core/dist/cli/utils/files.js +35 -0
  19. package/packages/core/dist/cli/utils/files.js.map +1 -1
  20. package/packages/core/dist/scripts/generate-report.d.ts.map +1 -1
  21. package/packages/core/dist/scripts/generate-report.js +11 -7
  22. package/packages/core/dist/scripts/generate-report.js.map +1 -1
  23. package/packages/core/dist/scripts/generate-spider-report.d.ts.map +1 -1
  24. package/packages/core/dist/scripts/generate-spider-report.js +12 -8
  25. package/packages/core/dist/scripts/generate-spider-report.js.map +1 -1
  26. package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -1
  27. package/packages/core/dist/scripts/generate-spider.js +6 -4
  28. package/packages/core/dist/scripts/generate-spider.js.map +1 -1
  29. package/packages/core/dist/scripts/generate-spider.test.js +2 -2
  30. package/packages/core/dist/scripts/generate-spider.test.js.map +1 -1
  31. package/pennyfarthing-dist/agents/pm.md +1 -1
  32. package/pennyfarthing-dist/agents/sm-finish.md +1 -1
  33. package/pennyfarthing-dist/agents/sm-setup.md +2 -2
  34. package/pennyfarthing-dist/agents/sm.md +4 -5
  35. package/pennyfarthing-dist/agents/workflow-status-check.md +1 -1
  36. package/pennyfarthing-dist/commands/repo-status.md +2 -2
  37. package/pennyfarthing-dist/commands/sprint.md +8 -8
  38. package/pennyfarthing-dist/guides/skill-schema.md +25 -26
  39. package/pennyfarthing-dist/guides/xml-tags.md +2 -2
  40. package/pennyfarthing-dist/scripts/README.md +2 -2
  41. package/pennyfarthing-dist/scripts/core/agent-session.sh +0 -0
  42. package/pennyfarthing-dist/scripts/core/check-context.sh +0 -0
  43. package/pennyfarthing-dist/scripts/core/handoff-marker.sh +0 -0
  44. package/pennyfarthing-dist/scripts/core/phase-check-start.sh +0 -0
  45. package/pennyfarthing-dist/scripts/core/prime.sh +0 -0
  46. package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +0 -0
  47. package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +0 -0
  48. package/pennyfarthing-dist/scripts/git/git-status-all.sh +1 -1
  49. package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +0 -0
  50. package/pennyfarthing-dist/scripts/git/release.sh +0 -0
  51. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +3 -3
  52. package/pennyfarthing-dist/scripts/health/drift-detection.sh +0 -0
  53. package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +0 -0
  54. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -0
  55. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -0
  56. package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
  57. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +0 -0
  58. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +2 -7
  59. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +0 -0
  60. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
  61. package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -0
  62. package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +0 -0
  63. package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +0 -0
  64. package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +0 -0
  65. package/pennyfarthing-dist/scripts/hooks/session-start.sh +0 -0
  66. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -0
  67. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +1 -1
  68. package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +0 -0
  69. package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +0 -0
  70. package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +0 -0
  71. package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +0 -0
  72. package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +0 -0
  73. package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +0 -0
  74. package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +0 -0
  75. package/pennyfarthing-dist/scripts/lib/background-tasks.sh +0 -0
  76. package/pennyfarthing-dist/scripts/lib/checkpoint.sh +0 -0
  77. package/pennyfarthing-dist/scripts/lib/common.sh +0 -0
  78. package/pennyfarthing-dist/scripts/lib/file-lock.sh +0 -0
  79. package/pennyfarthing-dist/scripts/lib/logging.sh +0 -0
  80. package/pennyfarthing-dist/scripts/lib/retry.sh +0 -0
  81. package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +0 -0
  82. package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +0 -0
  83. package/pennyfarthing-dist/scripts/misc/add-short-names.sh +0 -0
  84. package/pennyfarthing-dist/scripts/misc/add_short_names.py +0 -0
  85. package/pennyfarthing-dist/scripts/misc/backlog.sh +0 -0
  86. package/pennyfarthing-dist/scripts/misc/check-status.sh +0 -0
  87. package/pennyfarthing-dist/scripts/misc/find-related-work.sh +0 -0
  88. package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +0 -0
  89. package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +0 -0
  90. package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +0 -0
  91. package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -0
  92. package/pennyfarthing-dist/scripts/misc/repo-scan.sh +0 -0
  93. package/pennyfarthing-dist/scripts/misc/repo-utils.sh +3 -3
  94. package/pennyfarthing-dist/scripts/misc/run-ci.sh +0 -0
  95. package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +0 -0
  96. package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +0 -0
  97. package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +0 -0
  98. package/pennyfarthing-dist/scripts/misc/statusline.sh +0 -0
  99. package/pennyfarthing-dist/scripts/misc/uninstall.sh +0 -0
  100. package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +0 -0
  101. package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +0 -0
  102. package/pennyfarthing-dist/scripts/sprint/README.md +32 -17
  103. package/pennyfarthing-dist/scripts/story/README.md +1 -1
  104. package/pennyfarthing-dist/scripts/story/create-story.sh +0 -0
  105. package/pennyfarthing-dist/scripts/story/size-story.sh +0 -0
  106. package/pennyfarthing-dist/scripts/story/story-template.sh +0 -0
  107. package/pennyfarthing-dist/scripts/test/ensure-swebench-data.sh +0 -0
  108. package/pennyfarthing-dist/scripts/test/swebench-judge.py +0 -0
  109. package/pennyfarthing-dist/scripts/test/test-cache.sh +0 -0
  110. package/pennyfarthing-dist/scripts/test/test-setup.sh +1 -1
  111. package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
  112. package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +0 -0
  113. package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +0 -0
  114. package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +0 -0
  115. package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +0 -0
  116. package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +0 -0
  117. package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +0 -0
  118. package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +0 -0
  119. package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -0
  120. package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +0 -0
  121. package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -0
  122. package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -0
  123. package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
  124. package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +0 -0
  125. package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.sh +0 -0
  126. package/pennyfarthing-dist/scripts/theme/compute_theme_tiers.py +0 -0
  127. package/pennyfarthing-dist/scripts/theme/list-themes.sh +0 -0
  128. package/pennyfarthing-dist/scripts/theme/update-theme-tiers.sh +0 -0
  129. package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +0 -0
  130. package/pennyfarthing-dist/scripts/workflow/check.py +0 -0
  131. package/pennyfarthing-dist/scripts/workflow/check.sh +0 -0
  132. package/pennyfarthing-dist/scripts/workflow/complete-step.py +0 -0
  133. package/pennyfarthing-dist/scripts/workflow/finish-story.sh +0 -0
  134. package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +0 -0
  135. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +0 -0
  136. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +0 -0
  137. package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +0 -0
  138. package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +0 -0
  139. package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +0 -0
  140. package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +0 -0
  141. package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +0 -0
  142. package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +0 -0
  143. package/pennyfarthing-dist/skills/skill-registry.yaml +21 -12
  144. package/pennyfarthing-dist/skills/sprint/skill.md +386 -68
  145. package/pennyfarthing-dist/skills/story/scripts/create-story.sh +0 -0
  146. package/pennyfarthing-dist/skills/story/scripts/size-story.sh +0 -0
  147. package/pennyfarthing-dist/skills/story/scripts/story-template.sh +0 -0
  148. package/pennyfarthing-dist/skills/story/skill.md +14 -206
  149. package/pennyfarthing-dist/skills/workflow/scripts/list-workflows.sh +0 -0
  150. package/pennyfarthing-dist/skills/workflow/scripts/resume-workflow.sh +0 -0
  151. package/pennyfarthing-dist/skills/workflow/scripts/show-workflow.sh +0 -0
  152. package/pennyfarthing-dist/skills/workflow/scripts/start-workflow.sh +0 -0
  153. package/pennyfarthing-dist/skills/workflow/scripts/workflow-status.sh +0 -0
  154. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +1 -1
  155. package/pennyfarthing-dist/workflows/git-cleanup.yaml +1 -1
  156. package/pennyfarthing-dist/workflows/project-setup/steps/step-10-complete.md +1 -1
  157. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  158. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  159. package/pennyfarthing_scripts/common/config.py +2 -1
  160. package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
  161. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
  162. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
  163. package/pennyfarthing_scripts/hotspots/analyze.py +1 -1
  164. package/pennyfarthing_scripts/hotspots/cli.py +1 -1
  165. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  166. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  167. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  168. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
  169. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
  170. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  171. package/pennyfarthing_scripts/jira/cli.py +74 -0
  172. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/prime/workflow.py +5 -3
  174. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  179. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  180. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  181. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  182. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  183. package/pennyfarthing_scripts/sprint/archive.py +63 -6
  184. package/pennyfarthing_scripts/sprint/archive_epic.py +14 -5
  185. package/pennyfarthing_scripts/sprint/cli.py +1555 -65
  186. package/pennyfarthing_scripts/sprint/epic_add.py +173 -0
  187. package/pennyfarthing_scripts/sprint/loader.py +46 -2
  188. package/pennyfarthing_scripts/sprint/validate_cmd.py +44 -5
  189. package/pennyfarthing_scripts/sprint/validator.py +13 -3
  190. package/pennyfarthing_scripts/sprint/work.py +17 -1
  191. package/pennyfarthing_scripts/sprint/yaml_io.py +124 -15
  192. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
  193. package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
  194. package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
  195. package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
  196. package/pennyfarthing_scripts/tests/test_sprint_package.py +166 -0
  197. package/pennyfarthing_scripts/tests/test_yaml_io.py +117 -0
  198. package/scripts/postinstall.cjs +34 -0
  199. package/pennyfarthing-dist/scripts/sprint/archive-story.sh +0 -133
  200. package/pennyfarthing-dist/scripts/sprint/available-stories.sh +0 -91
  201. package/pennyfarthing-dist/scripts/sprint/check-story.sh +0 -158
  202. package/pennyfarthing-dist/scripts/sprint/get-epic-field.sh +0 -52
  203. package/pennyfarthing-dist/scripts/sprint/get-story-field.sh +0 -63
  204. package/pennyfarthing-dist/scripts/sprint/list-future.sh +0 -145
  205. package/pennyfarthing-dist/scripts/sprint/new-sprint.sh +0 -110
  206. package/pennyfarthing-dist/scripts/sprint/promote-epic.sh +0 -148
  207. package/pennyfarthing-dist/scripts/sprint/sprint-common.sh +0 -415
  208. package/pennyfarthing-dist/scripts/sprint/sprint-info.sh +0 -33
  209. package/pennyfarthing-dist/scripts/sprint/sprint-metrics.sh +0 -230
  210. package/pennyfarthing-dist/scripts/sprint/sprint-status.sh +0 -134
  211. package/pennyfarthing-dist/scripts/sprint/validate-sprint-yaml.sh +0 -139
  212. package/pennyfarthing-dist/skills/sprint/scripts/archive-story.sh +0 -101
  213. package/pennyfarthing-dist/skills/sprint/scripts/available-stories.sh +0 -97
  214. package/pennyfarthing-dist/skills/sprint/scripts/check-story.sh +0 -164
  215. package/pennyfarthing-dist/skills/sprint/scripts/create-jira-epic.sh +0 -23
  216. package/pennyfarthing-dist/skills/sprint/scripts/new-sprint.sh +0 -116
  217. package/pennyfarthing-dist/skills/sprint/scripts/promote-epic.sh +0 -164
  218. package/pennyfarthing-dist/skills/sprint/scripts/sprint-info.sh +0 -39
  219. package/pennyfarthing-dist/skills/sprint/scripts/sprint-status.sh +0 -147
  220. package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +0 -23
@@ -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\`"
@@ -1,110 +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
- # Find project root
31
- source "$(dirname "${BASH_SOURCE[0]}")/../lib/find-root.sh"
32
- TEMPLATE_FILE="$PROJECT_ROOT/sprint/sprint-template.yaml"
33
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
34
- ARCHIVE_FILE="$PROJECT_ROOT/sprint/archive/sprint-${SPRINT_YYWW}-completed.yaml"
35
-
36
- # Check template exists
37
- if [[ ! -f "$TEMPLATE_FILE" ]]; then
38
- echo "Error: Template file not found at $TEMPLATE_FILE"
39
- exit 1
40
- fi
41
-
42
- # Warn if current sprint file exists and is active
43
- if [[ -f "$SPRINT_FILE" ]]; then
44
- if ! command -v yq &> /dev/null; then
45
- echo "Warning: yq not installed, cannot check current sprint status"
46
- else
47
- CURRENT_STATUS=$(yq eval '.sprint.status' "$SPRINT_FILE")
48
- if [[ "$CURRENT_STATUS" == "active" ]]; then
49
- echo "Warning: Current sprint is still active!"
50
- echo "Current sprint file will be overwritten."
51
- echo ""
52
- read -p "Continue? [y/N] " -n 1 -r
53
- echo
54
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
55
- echo "Aborted."
56
- exit 1
57
- fi
58
- fi
59
- fi
60
- fi
61
-
62
- # Create new sprint file
63
- cat > "$SPRINT_FILE" << EOF
64
- sprint:
65
- name: "TO Sprint $SPRINT_YYWW"
66
- jira_sprint_id: $JIRA_ID
67
- jira_sprint_name: "TO Sprint $SPRINT_YYWW"
68
- goal: $GOAL
69
- start_date: $START_DATE
70
- end_date: $END_DATE
71
- status: active
72
-
73
- # Completed stories archived to: sprint/archive/sprint-${SPRINT_YYWW}-completed.yaml
74
-
75
- epics:
76
- # Add epics and stories here
77
- # See sprint/sprint-template.yaml for format reference
78
- EOF
79
-
80
- echo "Created $SPRINT_FILE"
81
-
82
- # Create archive file
83
- cat > "$ARCHIVE_FILE" << EOF
84
- # Sprint TO Sprint $SPRINT_YYWW - Completed Stories
85
- # Jira Sprint ID: $JIRA_ID
86
- # Archived: $(date +%Y-%m-%d)
87
-
88
- sprint:
89
- name: "TO Sprint $SPRINT_YYWW"
90
- jira_sprint_id: $JIRA_ID
91
- jira_sprint_name: "TO Sprint $SPRINT_YYWW"
92
- goal: $GOAL
93
-
94
- completed:
95
- # Completed stories will be appended here by archive-story.sh
96
- EOF
97
-
98
- echo "Created $ARCHIVE_FILE"
99
-
100
- echo ""
101
- echo "New sprint initialized:"
102
- echo " Name: TO Sprint $SPRINT_YYWW"
103
- echo " Jira ID: $JIRA_ID"
104
- echo " Dates: $START_DATE to $END_DATE"
105
- echo " Goal: $GOAL"
106
- echo ""
107
- echo "Next steps:"
108
- echo " 1. Add epics and stories to $SPRINT_FILE"
109
- echo " 2. Use sprint-status.sh to check progress"
110
- echo " 3. Use archive-story.sh to move completed stories"
@@ -1,148 +0,0 @@
1
- #!/bin/bash
2
- # Promote an epic from future.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
- # Features:
8
- # - Detects ID collisions and assigns new ID if needed
9
- # - Uses yq for proper YAML array insertion
10
- # - Automatically removes from future.yaml after successful promotion
11
-
12
- set -euo pipefail
13
-
14
- EPIC_ID="${1:-}"
15
-
16
- if [[ -z "$EPIC_ID" ]]; then
17
- echo "Usage: promote-epic.sh <epic-id>"
18
- echo "Example: promote-epic.sh epic-41"
19
- echo ""
20
- echo "Moves an epic and its stories from future.yaml to current-sprint.yaml"
21
- exit 1
22
- fi
23
-
24
- # Find project root
25
- source "$(dirname "${BASH_SOURCE[0]}")/../lib/find-root.sh"
26
-
27
- FUTURE_FILE="$PROJECT_ROOT/sprint/future.yaml"
28
- SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
29
-
30
- if [[ ! -f "$FUTURE_FILE" ]]; then
31
- echo "Error: Future file not found at $FUTURE_FILE"
32
- exit 1
33
- fi
34
-
35
- if [[ ! -f "$SPRINT_FILE" ]]; then
36
- echo "Error: Sprint file not found at $SPRINT_FILE"
37
- exit 1
38
- fi
39
-
40
- if ! command -v yq &> /dev/null; then
41
- echo "Error: yq is required but not installed"
42
- echo "Install with: brew install yq"
43
- exit 1
44
- fi
45
-
46
- # Find the epic in future.yaml
47
- # Epics are nested under future.initiatives[].epics[]
48
- EPIC_DATA=$(yq -o json ".future.initiatives[].epics[] | select(.id == \"$EPIC_ID\")" "$FUTURE_FILE" 2>/dev/null || echo "")
49
-
50
- if [[ -z "$EPIC_DATA" || "$EPIC_DATA" == "null" ]]; then
51
- echo "Error: Epic $EPIC_ID not found in $FUTURE_FILE"
52
- echo ""
53
- echo "Available epics:"
54
- yq '.future.initiatives[].epics[].id' "$FUTURE_FILE" 2>/dev/null || echo " None found"
55
- exit 1
56
- fi
57
-
58
- # Check for ID collision in current-sprint.yaml
59
- EXISTING_ID=$(yq ".epics[] | select(.id == \"$EPIC_ID\") | .id" "$SPRINT_FILE" 2>/dev/null || echo "")
60
-
61
- NEW_EPIC_ID="$EPIC_ID"
62
- if [[ -n "$EXISTING_ID" && "$EXISTING_ID" != "null" ]]; then
63
- echo "Warning: Epic ID $EPIC_ID already exists in current sprint."
64
-
65
- # Find the highest epic-N ID and increment
66
- MAX_EPIC_NUM=$(yq '.epics[].id' "$SPRINT_FILE" 2>/dev/null | grep -oE 'epic-[0-9]+' | sed 's/epic-//' | sort -n | tail -1 || echo "0")
67
- if [[ -z "$MAX_EPIC_NUM" ]]; then
68
- MAX_EPIC_NUM=0
69
- fi
70
- NEW_EPIC_NUM=$((MAX_EPIC_NUM + 1))
71
- NEW_EPIC_ID="epic-$NEW_EPIC_NUM"
72
-
73
- echo "Assigning new ID: $NEW_EPIC_ID"
74
- echo ""
75
- fi
76
-
77
- # Extract epic fields
78
- EPIC_TITLE=$(echo "$EPIC_DATA" | yq -r '.title // "Unknown"')
79
- EPIC_DESCRIPTION=$(echo "$EPIC_DATA" | yq -r '.description // ""')
80
- EPIC_POINTS=$(echo "$EPIC_DATA" | yq -r '.points // 0')
81
- EPIC_PRIORITY=$(echo "$EPIC_DATA" | yq -r '.priority // "P2"')
82
- EPIC_REPOS=$(echo "$EPIC_DATA" | yq -r '.repos // "pennyfarthing"')
83
- STORY_COUNT=$(echo "$EPIC_DATA" | yq '[.stories[]] | length')
84
-
85
- echo ""
86
- echo "Promoting epic to current sprint:"
87
- echo " Original ID: $EPIC_ID"
88
- if [[ "$NEW_EPIC_ID" != "$EPIC_ID" ]]; then
89
- echo " New ID: $NEW_EPIC_ID"
90
- fi
91
- echo " Title: $EPIC_TITLE"
92
- echo " Points: $EPIC_POINTS"
93
- echo " Priority: $EPIC_PRIORITY"
94
- echo " Stories: $STORY_COUNT"
95
- echo ""
96
-
97
- # Build the new epic object as JSON, then use yq to append it properly
98
- # This ensures valid YAML structure
99
-
100
- # Extract old epic ID prefix for updating story IDs (e.g., "64" from "epic-64")
101
- OLD_ID_NUM=$(echo "$EPIC_ID" | sed 's/epic-//')
102
- NEW_ID_NUM=$(echo "$NEW_EPIC_ID" | sed 's/epic-//')
103
-
104
- # Create a temp file for the new epic
105
- TEMP_EPIC=$(mktemp)
106
- trap "rm -f $TEMP_EPIC" EXIT
107
-
108
- # Transform the epic data: update IDs, add required fields, format for current-sprint.yaml
109
- # Note: Using -o yaml for Go yq (not -y which is Python yq)
110
- echo "$EPIC_DATA" | yq -o yaml "
111
- .id = \"$NEW_EPIC_ID\" |
112
- .type = \"epic\" |
113
- .title = \"Epic: \" + .title |
114
- .status = \"backlog\" |
115
- .stories = [.stories[] |
116
- .id = ((.id | tostring) | sub(\"^${OLD_ID_NUM}-\"; \"${NEW_ID_NUM}-\")) |
117
- .status = \"backlog\" |
118
- .repos = (.repos // \"pennyfarthing\") |
119
- .workflow = (.workflow // \"tdd\") |
120
- .priority = (.priority // \"P2\") |
121
- .acceptance_criteria = (.acceptance_criteria // [])
122
- ]
123
- " > "$TEMP_EPIC"
124
-
125
- echo "Epic to add:"
126
- echo "---"
127
- cat "$TEMP_EPIC"
128
- echo "---"
129
- echo ""
130
-
131
- # Use yq to properly append the epic to the epics array
132
- yq eval -i ".epics += [$(cat "$TEMP_EPIC" | yq -o json)]" "$SPRINT_FILE"
133
-
134
- echo "Successfully added epic to $SPRINT_FILE"
135
-
136
- # Remove from future.yaml
137
- echo ""
138
- echo "Removing from future.yaml..."
139
- yq eval -i "del(.future.initiatives[].epics[] | select(.id == \"$EPIC_ID\"))" "$FUTURE_FILE"
140
- echo "Removed $EPIC_ID from future.yaml"
141
-
142
- echo ""
143
- echo "Promotion complete!"
144
- echo ""
145
- echo "Next steps:"
146
- echo " 1. Review the epic in $SPRINT_FILE"
147
- echo " 2. Create Jira epic: .pennyfarthing/scripts/jira/create-jira-epic.sh $NEW_EPIC_ID"
148
- echo " 3. Start work: /sprint work ${NEW_ID_NUM}-1"