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