@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.
- package/README.md +1 -1
- package/package.json +13 -11
- package/packages/core/dist/cli/commands/cyclist.d.ts +5 -1
- package/packages/core/dist/cli/commands/cyclist.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/cyclist.js +4 -4
- package/packages/core/dist/cli/commands/cyclist.js.map +1 -1
- package/packages/core/dist/cli/commands/cyclist.test.js +2 -2
- package/packages/core/dist/cli/commands/cyclist.test.js.map +1 -1
- package/packages/core/dist/cli/commands/doctor-legacy.test.js +17 -16
- package/packages/core/dist/cli/commands/doctor-legacy.test.js.map +1 -1
- package/packages/core/dist/cli/commands/init.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/init.js +3 -0
- package/packages/core/dist/cli/commands/init.js.map +1 -1
- package/packages/core/dist/cli/ocean-profiles.test.js +1 -1
- package/packages/core/dist/cli/ocean-profiles.test.js.map +1 -1
- package/packages/core/dist/cli/utils/files.d.ts +10 -0
- package/packages/core/dist/cli/utils/files.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/files.js +35 -0
- package/packages/core/dist/cli/utils/files.js.map +1 -1
- package/packages/core/dist/scripts/generate-report.d.ts.map +1 -1
- package/packages/core/dist/scripts/generate-report.js +11 -7
- package/packages/core/dist/scripts/generate-report.js.map +1 -1
- package/packages/core/dist/scripts/generate-spider-report.d.ts.map +1 -1
- package/packages/core/dist/scripts/generate-spider-report.js +12 -8
- package/packages/core/dist/scripts/generate-spider-report.js.map +1 -1
- package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -1
- package/packages/core/dist/scripts/generate-spider.js +6 -4
- package/packages/core/dist/scripts/generate-spider.js.map +1 -1
- package/packages/core/dist/scripts/generate-spider.test.js +2 -2
- package/packages/core/dist/scripts/generate-spider.test.js.map +1 -1
- package/pennyfarthing-dist/agents/pm.md +1 -1
- package/pennyfarthing-dist/agents/sm-finish.md +1 -1
- package/pennyfarthing-dist/agents/sm-setup.md +2 -2
- package/pennyfarthing-dist/agents/sm.md +4 -5
- package/pennyfarthing-dist/agents/workflow-status-check.md +1 -1
- package/pennyfarthing-dist/commands/repo-status.md +2 -2
- package/pennyfarthing-dist/commands/sprint.md +8 -8
- package/pennyfarthing-dist/guides/skill-schema.md +25 -26
- package/pennyfarthing-dist/guides/xml-tags.md +2 -2
- package/pennyfarthing-dist/scripts/README.md +2 -2
- package/pennyfarthing-dist/scripts/core/agent-session.sh +0 -0
- package/pennyfarthing-dist/scripts/core/check-context.sh +0 -0
- package/pennyfarthing-dist/scripts/core/handoff-marker.sh +0 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +0 -0
- package/pennyfarthing-dist/scripts/core/prime.sh +0 -0
- package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +0 -0
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +0 -0
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +1 -1
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +0 -0
- package/pennyfarthing-dist/scripts/git/release.sh +0 -0
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +3 -3
- package/pennyfarthing-dist/scripts/health/drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/post-merge.sh +2 -7
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +0 -0
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +1 -1
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/background-tasks.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/common.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/file-lock.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/logging.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/retry.sh +0 -0
- package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +0 -0
- package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add-short-names.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add_short_names.py +0 -0
- package/pennyfarthing-dist/scripts/misc/backlog.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/check-status.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/find-related-work.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-scan.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-utils.sh +3 -3
- package/pennyfarthing-dist/scripts/misc/run-ci.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/statusline.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/uninstall.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +0 -0
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +0 -0
- package/pennyfarthing-dist/scripts/sprint/README.md +32 -17
- package/pennyfarthing-dist/scripts/story/README.md +1 -1
- package/pennyfarthing-dist/scripts/story/create-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/size-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/story-template.sh +0 -0
- package/pennyfarthing-dist/scripts/test/ensure-swebench-data.sh +0 -0
- package/pennyfarthing-dist/scripts/test/swebench-judge.py +0 -0
- package/pennyfarthing-dist/scripts/test/test-cache.sh +0 -0
- package/pennyfarthing-dist/scripts/test/test-setup.sh +1 -1
- package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/compute_theme_tiers.py +0 -0
- package/pennyfarthing-dist/scripts/theme/list-themes.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/update-theme-tiers.sh +0 -0
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/check.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/check.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/complete-step.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +0 -0
- package/pennyfarthing-dist/skills/skill-registry.yaml +21 -12
- package/pennyfarthing-dist/skills/sprint/skill.md +386 -68
- package/pennyfarthing-dist/skills/story/scripts/create-story.sh +0 -0
- package/pennyfarthing-dist/skills/story/scripts/size-story.sh +0 -0
- package/pennyfarthing-dist/skills/story/scripts/story-template.sh +0 -0
- package/pennyfarthing-dist/skills/story/skill.md +14 -206
- package/pennyfarthing-dist/skills/workflow/scripts/list-workflows.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/resume-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/show-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/start-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/workflow-status.sh +0 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +1 -1
- package/pennyfarthing-dist/workflows/git-cleanup.yaml +1 -1
- package/pennyfarthing-dist/workflows/project-setup/steps/step-10-complete.md +1 -1
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/config.py +2 -1
- package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/analyze.py +1 -1
- package/pennyfarthing_scripts/hotspots/cli.py +1 -1
- package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/cli.py +74 -0
- package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/workflow.py +5 -3
- package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/archive.py +63 -6
- package/pennyfarthing_scripts/sprint/archive_epic.py +14 -5
- package/pennyfarthing_scripts/sprint/cli.py +1555 -65
- package/pennyfarthing_scripts/sprint/epic_add.py +173 -0
- package/pennyfarthing_scripts/sprint/loader.py +46 -2
- package/pennyfarthing_scripts/sprint/validate_cmd.py +44 -5
- package/pennyfarthing_scripts/sprint/validator.py +13 -3
- package/pennyfarthing_scripts/sprint/work.py +17 -1
- package/pennyfarthing_scripts/sprint/yaml_io.py +124 -15
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/test_sprint_package.py +166 -0
- package/pennyfarthing_scripts/tests/test_yaml_io.py +117 -0
- package/scripts/postinstall.cjs +34 -0
- package/pennyfarthing-dist/scripts/sprint/archive-story.sh +0 -133
- package/pennyfarthing-dist/scripts/sprint/available-stories.sh +0 -91
- package/pennyfarthing-dist/scripts/sprint/check-story.sh +0 -158
- package/pennyfarthing-dist/scripts/sprint/get-epic-field.sh +0 -52
- package/pennyfarthing-dist/scripts/sprint/get-story-field.sh +0 -63
- package/pennyfarthing-dist/scripts/sprint/list-future.sh +0 -145
- package/pennyfarthing-dist/scripts/sprint/new-sprint.sh +0 -110
- package/pennyfarthing-dist/scripts/sprint/promote-epic.sh +0 -148
- package/pennyfarthing-dist/scripts/sprint/sprint-common.sh +0 -415
- package/pennyfarthing-dist/scripts/sprint/sprint-info.sh +0 -33
- package/pennyfarthing-dist/scripts/sprint/sprint-metrics.sh +0 -230
- package/pennyfarthing-dist/scripts/sprint/sprint-status.sh +0 -134
- package/pennyfarthing-dist/scripts/sprint/validate-sprint-yaml.sh +0 -139
- package/pennyfarthing-dist/skills/sprint/scripts/archive-story.sh +0 -101
- package/pennyfarthing-dist/skills/sprint/scripts/available-stories.sh +0 -97
- package/pennyfarthing-dist/skills/sprint/scripts/check-story.sh +0 -164
- package/pennyfarthing-dist/skills/sprint/scripts/create-jira-epic.sh +0 -23
- package/pennyfarthing-dist/skills/sprint/scripts/new-sprint.sh +0 -116
- package/pennyfarthing-dist/skills/sprint/scripts/promote-epic.sh +0 -164
- package/pennyfarthing-dist/skills/sprint/scripts/sprint-info.sh +0 -39
- package/pennyfarthing-dist/skills/sprint/scripts/sprint-status.sh +0 -147
- 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"
|