@pennyfarthing/core 10.1.0 → 10.2.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 +13 -18
- package/package.json +3 -1
- package/packages/core/dist/cli/commands/doctor-file-layout.test.js.map +1 -1
- package/packages/core/dist/cli/commands/doctor-legacy.test.js +24 -0
- 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 +101 -15
- package/packages/core/dist/cli/commands/doctor.js.map +1 -1
- package/packages/core/dist/cli/commands/e2e-fresh-install.test.js +1 -1
- package/packages/core/dist/cli/commands/e2e-fresh-install.test.js.map +1 -1
- package/packages/core/dist/cli/commands/e2e-upgrade.test.js +1 -1
- package/packages/core/dist/cli/commands/e2e-upgrade.test.js.map +1 -1
- package/packages/core/dist/cli/commands/hooks-consolidation.test.js +2 -2
- package/packages/core/dist/cli/commands/hooks-consolidation.test.js.map +1 -1
- package/packages/core/dist/cli/commands/init-consolidation.test.js.map +1 -1
- package/packages/core/dist/cli/commands/uninstall.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/uninstall.js +24 -13
- package/packages/core/dist/cli/commands/uninstall.js.map +1 -1
- package/packages/core/dist/cli/commands/update-consolidation.test.js +0 -10
- package/packages/core/dist/cli/commands/update-consolidation.test.js.map +1 -1
- package/packages/core/dist/cli/commands/update.js.map +1 -1
- package/packages/core/dist/cli/ocean-profiles.test.js.map +1 -1
- package/packages/core/dist/cli/theme-maker.test.js +64 -115
- package/packages/core/dist/cli/theme-maker.test.js.map +1 -1
- package/packages/core/dist/index.d.ts +1 -1
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +2 -2
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/plugins/plugin-discovery.d.ts +116 -0
- package/packages/core/dist/plugins/plugin-discovery.d.ts.map +1 -0
- package/packages/core/dist/plugins/plugin-discovery.js +165 -0
- package/packages/core/dist/plugins/plugin-discovery.js.map +1 -0
- package/packages/core/dist/plugins/plugin-discovery.test.d.ts +22 -0
- package/packages/core/dist/plugins/plugin-discovery.test.d.ts.map +1 -0
- package/packages/core/dist/plugins/plugin-discovery.test.js +498 -0
- package/packages/core/dist/plugins/plugin-discovery.test.js.map +1 -0
- package/packages/core/dist/scripts/generate-spider-report.js.map +1 -1
- package/packages/core/dist/workflow/context-watch.d.ts +80 -0
- package/packages/core/dist/workflow/context-watch.d.ts.map +1 -0
- package/packages/core/dist/workflow/context-watch.js +235 -0
- package/packages/core/dist/workflow/context-watch.js.map +1 -0
- package/packages/core/dist/workflow/context-watch.test.d.ts +1 -0
- package/packages/core/dist/workflow/context-watch.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/context-watch.test.js +746 -0
- package/packages/core/dist/workflow/context-watch.test.js.map +1 -0
- package/packages/core/dist/workflow/file-watch.d.ts +82 -0
- package/packages/core/dist/workflow/file-watch.d.ts.map +1 -0
- package/packages/core/dist/workflow/file-watch.js +198 -0
- package/packages/core/dist/workflow/file-watch.js.map +1 -0
- package/packages/core/dist/workflow/file-watch.test.d.ts +21 -0
- package/packages/core/dist/workflow/file-watch.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/file-watch.test.js +469 -0
- package/packages/core/dist/workflow/file-watch.test.js.map +1 -0
- package/packages/core/dist/workflow/observation-writer.d.ts +79 -0
- package/packages/core/dist/workflow/observation-writer.d.ts.map +1 -0
- package/packages/core/dist/workflow/observation-writer.js +97 -0
- package/packages/core/dist/workflow/observation-writer.js.map +1 -0
- package/packages/core/dist/workflow/observation-writer.test.d.ts +18 -0
- package/packages/core/dist/workflow/observation-writer.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/observation-writer.test.js +424 -0
- package/packages/core/dist/workflow/observation-writer.test.js.map +1 -0
- package/packages/core/dist/workflow/story-workflow-routing.test.js +4 -2
- package/packages/core/dist/workflow/story-workflow-routing.test.js.map +1 -1
- package/packages/core/dist/workflow/tandem-lifecycle.d.ts +117 -0
- package/packages/core/dist/workflow/tandem-lifecycle.d.ts.map +1 -0
- package/packages/core/dist/workflow/tandem-lifecycle.js +186 -0
- package/packages/core/dist/workflow/tandem-lifecycle.js.map +1 -0
- package/packages/core/dist/workflow/tandem-lifecycle.test.d.ts +16 -0
- package/packages/core/dist/workflow/tandem-lifecycle.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/tandem-lifecycle.test.js +531 -0
- package/packages/core/dist/workflow/tandem-lifecycle.test.js.map +1 -0
- package/packages/core/dist/workflow/tool-watch.d.ts +68 -0
- package/packages/core/dist/workflow/tool-watch.d.ts.map +1 -0
- package/packages/core/dist/workflow/tool-watch.js +166 -0
- package/packages/core/dist/workflow/tool-watch.js.map +1 -0
- package/packages/core/dist/workflow/tool-watch.test.d.ts +18 -0
- package/packages/core/dist/workflow/tool-watch.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/tool-watch.test.js +718 -0
- package/packages/core/dist/workflow/tool-watch.test.js.map +1 -0
- package/packages/core/dist/workflow/workflow-migration.test.js +8 -4
- package/packages/core/dist/workflow/workflow-migration.test.js.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.d.ts +7 -0
- package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.js +44 -0
- package/packages/core/dist/workflow/workflow-schema.js.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.test.d.ts.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.test.js +192 -0
- package/packages/core/dist/workflow/workflow-schema.test.js.map +1 -1
- package/pennyfarthing-dist/agents/handoff.md +18 -3
- package/pennyfarthing-dist/agents/sm-finish.md +1 -1
- package/pennyfarthing-dist/agents/sm-handoff.md +27 -4
- package/pennyfarthing-dist/agents/sm.md +11 -5
- package/pennyfarthing-dist/agents/tandem-backseat.md +119 -0
- package/pennyfarthing-dist/commands/setup.md +4 -0
- package/pennyfarthing-dist/guides/agent-behavior.md +62 -6
- package/pennyfarthing-dist/guides/bikelane.md +3 -2
- package/pennyfarthing-dist/guides/scale-levels.md +4 -6
- package/pennyfarthing-dist/guides/tandem-protocol.md +158 -0
- package/pennyfarthing-dist/personas/themes/discworld.yaml +1 -1
- package/pennyfarthing-dist/personas/themes/fifth-element.yaml +295 -0
- package/pennyfarthing-dist/scripts/README.md +1 -1
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +131 -54
- package/pennyfarthing-dist/scripts/hooks/post-merge.sh +20 -10
- package/pennyfarthing-dist/scripts/misc/statusline.sh +50 -8
- package/pennyfarthing-dist/scripts/workflow/README.md +2 -2
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +10 -189
- package/pennyfarthing-dist/skills/skill-registry.schema.json +8 -0
- package/pennyfarthing-dist/skills/skill-registry.yaml +1 -1
- package/pennyfarthing-dist/skills/sprint/skill.md +25 -2
- package/pennyfarthing-dist/skills/workflow/skill.md +24 -1
- package/pennyfarthing-dist/workflows/architecture/workflow.yaml +65 -0
- package/pennyfarthing-dist/workflows/bdd-tandem.yaml +70 -0
- package/pennyfarthing-dist/workflows/tdd-tandem.yaml +61 -0
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/bellmode_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/patch_mode.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/bellmode_hook.py +202 -47
- package/pennyfarthing_scripts/brownfield/__init__.py +6 -6
- package/pennyfarthing_scripts/brownfield/__main__.py +1 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/cli.py +0 -1
- package/pennyfarthing_scripts/brownfield/discover.py +1 -2
- package/pennyfarthing_scripts/cli.py +11 -6
- package/pennyfarthing_scripts/codemarkers/__init__.py +5 -1
- 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 +177 -2
- package/pennyfarthing_scripts/codemarkers/cli.py +50 -0
- package/pennyfarthing_scripts/codemarkers/formatters.py +0 -1
- package/pennyfarthing_scripts/codemarkers/models.py +15 -0
- package/pennyfarthing_scripts/common/__init__.py +8 -9
- package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/config.py +1 -1
- package/pennyfarthing_scripts/complexity/__init__.py +1 -1
- 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 +1 -1
- package/pennyfarthing_scripts/complexity/cli.py +5 -1
- package/pennyfarthing_scripts/complexity/formatters.py +1 -1
- package/pennyfarthing_scripts/context.py +14 -15
- 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 +3 -4
- package/pennyfarthing_scripts/deadcode/cli.py +2 -2
- package/pennyfarthing_scripts/dependencies/__init__.py +2 -2
- 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 +1 -1
- package/pennyfarthing_scripts/dependencies/cli.py +8 -4
- package/pennyfarthing_scripts/dependencies/formatters.py +1 -1
- package/pennyfarthing_scripts/git/__init__.py +5 -5
- package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/create_branches.py +3 -2
- package/pennyfarthing_scripts/git/status_all.py +1 -1
- package/pennyfarthing_scripts/healthscore/__init__.py +2 -2
- package/pennyfarthing_scripts/healthscore/__main__.py +8 -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 +451 -21
- package/pennyfarthing_scripts/healthscore/cli.py +5 -1
- package/pennyfarthing_scripts/healthscore/models.py +0 -1
- package/pennyfarthing_scripts/hooks.py +8 -11
- package/pennyfarthing_scripts/hotspots/__init__.py +6 -6
- 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 +128 -14
- package/pennyfarthing_scripts/hotspots/cli.py +2 -2
- package/pennyfarthing_scripts/hotspots/models.py +0 -1
- package/pennyfarthing_scripts/jira/__init__.py +15 -17
- package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/claim.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__/epic.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/__pycache__/story.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/bidirectional.py +2 -3
- package/pennyfarthing_scripts/jira/claim.py +21 -0
- package/pennyfarthing_scripts/jira/cli.py +2 -2
- package/pennyfarthing_scripts/jira/client.py +4 -4
- package/pennyfarthing_scripts/jira/create.py +45 -1
- package/pennyfarthing_scripts/jira/epic.py +3 -2
- package/pennyfarthing_scripts/jira/reconcile.py +0 -1
- package/pennyfarthing_scripts/jira/story.py +2 -0
- package/pennyfarthing_scripts/jira/sync.py +1 -1
- package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/skill.py +0 -1
- package/pennyfarthing_scripts/migration/step.py +0 -1
- package/pennyfarthing_scripts/migration/validate.py +8 -5
- package/pennyfarthing_scripts/patch_mode.py +2 -2
- package/pennyfarthing_scripts/preflight/__init__.py +1 -1
- package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/finish.py +0 -1
- package/pennyfarthing_scripts/pretooluse_hook.py +6 -7
- package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/loader.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__/session.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/cli.py +5 -1
- package/pennyfarthing_scripts/prime/loader.py +2 -3
- package/pennyfarthing_scripts/prime/persona.py +2 -1
- package/pennyfarthing_scripts/prime/tiers.py +4 -4
- package/pennyfarthing_scripts/schema_validation_hook.py +2 -3
- package/pennyfarthing_scripts/sprint/__init__.py +10 -12
- package/pennyfarthing_scripts/sprint/__main__.py +2 -2
- package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
- 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__/import_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/status.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 +0 -1
- package/pennyfarthing_scripts/sprint/archive_epic.py +1 -4
- package/pennyfarthing_scripts/sprint/cli.py +34 -28
- package/pennyfarthing_scripts/sprint/epic_add.py +8 -1
- package/pennyfarthing_scripts/sprint/import_epic.py +42 -18
- package/pennyfarthing_scripts/sprint/loader.py +6 -0
- package/pennyfarthing_scripts/sprint/status.py +1 -2
- package/pennyfarthing_scripts/sprint/story_add.py +2 -2
- package/pennyfarthing_scripts/sprint/story_finish.py +3 -5
- package/pennyfarthing_scripts/sprint/story_update.py +11 -3
- package/pennyfarthing_scripts/sprint/validate_cmd.py +0 -1
- package/pennyfarthing_scripts/sprint/validator.py +120 -6
- package/pennyfarthing_scripts/sprint/work.py +1 -4
- package/pennyfarthing_scripts/sprint/yaml_io.py +10 -2
- package/pennyfarthing_scripts/story/__init__.py +14 -16
- package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/size.py +0 -1
- package/pennyfarthing_scripts/story/template.py +0 -1
- package/pennyfarthing_scripts/swebench.py +1 -2
- package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.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_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_prime.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_package.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_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.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_workflow_check.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/conftest.py +1 -2
- package/pennyfarthing_scripts/tests/test_brownfield.py +10 -13
- package/pennyfarthing_scripts/tests/test_cli_modules.py +0 -4
- package/pennyfarthing_scripts/tests/test_codemarkers.py +13 -8
- package/pennyfarthing_scripts/tests/test_common.py +9 -4
- package/pennyfarthing_scripts/tests/test_epic_shard_validation.py +699 -0
- package/pennyfarthing_scripts/tests/test_git_utils.py +10 -13
- package/pennyfarthing_scripts/tests/test_healthscore.py +17 -25
- package/pennyfarthing_scripts/tests/test_jira_package.py +0 -3
- package/pennyfarthing_scripts/tests/test_package_structure.py +3 -16
- package/pennyfarthing_scripts/tests/test_patch_mode.py +7 -11
- package/pennyfarthing_scripts/tests/test_prime.py +39 -21
- package/pennyfarthing_scripts/tests/test_sprint_package.py +3 -8
- package/pennyfarthing_scripts/tests/test_sprint_validator.py +53 -5
- package/pennyfarthing_scripts/tests/test_story_add.py +3 -7
- package/pennyfarthing_scripts/tests/test_story_package.py +0 -3
- package/pennyfarthing_scripts/tests/test_story_update.py +5 -10
- package/pennyfarthing_scripts/tests/test_tiers.py +18 -17
- package/pennyfarthing_scripts/tests/test_token_counting.py +19 -13
- package/pennyfarthing_scripts/tests/test_validate_cmd.py +2 -7
- package/pennyfarthing_scripts/tests/test_workflow_check.py +0 -2
- package/pennyfarthing_scripts/tests/test_yaml_io.py +0 -3
- 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 +3 -2
- package/pennyfarthing_scripts/validate/__init__.py +21 -0
- package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__init__.py +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/agent.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/schema.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/skill_command.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/sprint.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/agent.py +239 -0
- package/pennyfarthing_scripts/validate/adapters/schema.py +30 -0
- package/pennyfarthing_scripts/validate/adapters/skill_command.py +292 -0
- package/pennyfarthing_scripts/validate/adapters/sprint.py +69 -0
- package/pennyfarthing_scripts/validate/adapters/workflow.py +320 -0
- package/pennyfarthing_scripts/validate/cli.py +141 -0
- package/pennyfarthing_scripts/welcome_hook.py +2 -3
- package/pennyfarthing_scripts/workflow.py +3 -3
- package/scripts/README.md +3 -15
- package/pennyfarthing-dist/commands/benchmark-control.md +0 -69
- package/pennyfarthing-dist/commands/benchmark.md +0 -485
- package/pennyfarthing-dist/commands/job-fair.md +0 -102
- package/pennyfarthing-dist/commands/solo.md +0 -447
- package/pennyfarthing-dist/guides/benchmarks.md +0 -62
- package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/scripts/test/ensure-swebench-data.sh +0 -59
- package/pennyfarthing-dist/scripts/test/ground-truth-judge.py +0 -220
- package/pennyfarthing-dist/scripts/test/swebench-judge.py +0 -374
- package/pennyfarthing-dist/scripts/test/test-cache.sh +0 -165
- package/pennyfarthing-dist/scripts/test/test-setup.sh +0 -337
- package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.sh +0 -13
- package/pennyfarthing-dist/scripts/theme/compute_theme_tiers.py +0 -402
- package/pennyfarthing-dist/scripts/theme/update-theme-tiers.sh +0 -97
- package/pennyfarthing-dist/skills/finalize-run/SKILL.md +0 -261
- package/pennyfarthing-dist/skills/judge/SKILL.md +0 -644
- package/pennyfarthing-dist/skills/persona-benchmark/SKILL.md +0 -187
- package/pennyfarthing-dist/workflows/dev-story/checklist.md +0 -80
- package/pennyfarthing-dist/workflows/dev-story/instructions.xml +0 -410
- package/pennyfarthing-dist/workflows/dev-story/workflow.yaml +0 -50
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-01-understand.md +0 -201
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-02-investigate.md +0 -156
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-03-generate.md +0 -140
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-04-review.md +0 -203
- package/pennyfarthing-dist/workflows/quick-spec/tech-spec-template.md +0 -74
- package/pennyfarthing-dist/workflows/quick-spec/workflow.yaml +0 -27
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -40,15 +40,14 @@ from pathlib import Path
|
|
|
40
40
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
41
41
|
|
|
42
42
|
from hooks import (
|
|
43
|
-
find_project_root,
|
|
44
|
-
get_cyclist_port,
|
|
45
|
-
send_to_cyclist,
|
|
46
|
-
read_stdin_json,
|
|
47
|
-
output_hook_response,
|
|
48
43
|
HookResponse,
|
|
49
|
-
|
|
50
|
-
is_cyclist_running,
|
|
44
|
+
find_project_root,
|
|
51
45
|
get_context_state,
|
|
46
|
+
is_cyclist_running,
|
|
47
|
+
load_settings,
|
|
48
|
+
output_hook_response,
|
|
49
|
+
read_stdin_json,
|
|
50
|
+
send_to_cyclist,
|
|
52
51
|
)
|
|
53
52
|
|
|
54
53
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -22,6 +22,10 @@ import argparse
|
|
|
22
22
|
import json
|
|
23
23
|
import sys
|
|
24
24
|
from pathlib import Path
|
|
25
|
+
from typing import TYPE_CHECKING
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from typing import Any
|
|
25
29
|
|
|
26
30
|
from pennyfarthing_scripts.common.config import get_project_root
|
|
27
31
|
from pennyfarthing_scripts.prime.loader import (
|
|
@@ -42,7 +46,7 @@ from pennyfarthing_scripts.prime.persona import (
|
|
|
42
46
|
load_persona,
|
|
43
47
|
)
|
|
44
48
|
from pennyfarthing_scripts.prime.session import cleanup_old_sessions, register_session
|
|
45
|
-
from pennyfarthing_scripts.prime.tiers import ContextTier,
|
|
49
|
+
from pennyfarthing_scripts.prime.tiers import ContextTier, load_tier_components, tier_from_string
|
|
46
50
|
from pennyfarthing_scripts.prime.workflow import check_redirect, detect_workflow_state
|
|
47
51
|
|
|
48
52
|
|
|
@@ -14,7 +14,6 @@ from __future__ import annotations
|
|
|
14
14
|
|
|
15
15
|
import re
|
|
16
16
|
from pathlib import Path
|
|
17
|
-
from typing import Any
|
|
18
17
|
|
|
19
18
|
from pennyfarthing_scripts.common.config import get_project_root
|
|
20
19
|
|
|
@@ -68,7 +67,7 @@ def load_sprint_context(project_root: Path | None = None) -> str | None:
|
|
|
68
67
|
Formatted sprint summary, or None if no sprint data
|
|
69
68
|
"""
|
|
70
69
|
# Import here to avoid circular imports
|
|
71
|
-
from pennyfarthing_scripts.sprint.loader import load_sprint
|
|
70
|
+
from pennyfarthing_scripts.sprint.loader import load_sprint
|
|
72
71
|
from pennyfarthing_scripts.sprint.status import get_sprint_status
|
|
73
72
|
|
|
74
73
|
root = project_root or get_project_root()
|
|
@@ -136,7 +135,7 @@ def _extract_session_parts(content: str) -> tuple[str, str]:
|
|
|
136
135
|
|
|
137
136
|
# Header: everything before first ## heading
|
|
138
137
|
header_lines = []
|
|
139
|
-
for
|
|
138
|
+
for line in lines:
|
|
140
139
|
if line.startswith("## "):
|
|
141
140
|
break
|
|
142
141
|
header_lines.append(line)
|
|
@@ -14,11 +14,12 @@ import yaml
|
|
|
14
14
|
from pennyfarthing_scripts.common.config import get_project_root, load_yaml_config
|
|
15
15
|
from pennyfarthing_scripts.common.themes import (
|
|
16
16
|
get_current_theme as _get_current_theme,
|
|
17
|
+
)
|
|
18
|
+
from pennyfarthing_scripts.common.themes import (
|
|
17
19
|
resolve_theme_path,
|
|
18
20
|
)
|
|
19
21
|
from pennyfarthing_scripts.prime.models import CrewMember, Persona
|
|
20
22
|
|
|
21
|
-
|
|
22
23
|
# Standard agent roles for crew manifest
|
|
23
24
|
AGENT_ROLES = [
|
|
24
25
|
"sm", "tea", "dev", "reviewer", "architect",
|
|
@@ -35,21 +35,21 @@ def estimate_tokens(text: str) -> int:
|
|
|
35
35
|
return max(1, len(text) // 4)
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
from pennyfarthing_scripts.prime.loader import (
|
|
38
|
+
from pennyfarthing_scripts.prime.loader import ( # noqa: E402
|
|
39
39
|
load_agent_definition,
|
|
40
40
|
load_behavior_guide,
|
|
41
41
|
load_session_context,
|
|
42
42
|
load_sidecars,
|
|
43
43
|
load_sprint_context,
|
|
44
44
|
)
|
|
45
|
-
from pennyfarthing_scripts.prime.persona import (
|
|
45
|
+
from pennyfarthing_scripts.prime.persona import ( # noqa: E402
|
|
46
46
|
format_persona_compressed,
|
|
47
47
|
get_crew_manifest,
|
|
48
48
|
get_user_title,
|
|
49
49
|
is_character_voice_enabled,
|
|
50
50
|
load_persona,
|
|
51
51
|
)
|
|
52
|
-
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
52
|
+
from pennyfarthing_scripts.prime.workflow import detect_workflow_state # noqa: E402
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
class ContextTier(Enum):
|
|
@@ -78,7 +78,7 @@ def tier_from_string(value: str) -> ContextTier:
|
|
|
78
78
|
return ContextTier(normalized)
|
|
79
79
|
except ValueError:
|
|
80
80
|
valid = ", ".join(t.value for t in ContextTier)
|
|
81
|
-
raise ValueError(f"Invalid tier '{value}'. Must be one of: {valid}")
|
|
81
|
+
raise ValueError(f"Invalid tier '{value}'. Must be one of: {valid}") from None
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
def load_tier_components(
|
|
@@ -29,12 +29,11 @@ from pathlib import Path
|
|
|
29
29
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
30
30
|
|
|
31
31
|
from hooks import (
|
|
32
|
-
read_stdin_json,
|
|
33
|
-
output_hook_response,
|
|
34
32
|
HookResponse,
|
|
33
|
+
output_hook_response,
|
|
34
|
+
read_stdin_json,
|
|
35
35
|
)
|
|
36
36
|
|
|
37
|
-
|
|
38
37
|
# =============================================================================
|
|
39
38
|
# File Type Detection
|
|
40
39
|
# =============================================================================
|
|
@@ -18,6 +18,16 @@ Usage:
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
# Re-export from loader for backwards compatibility
|
|
21
|
+
# Import submodules to make them accessible
|
|
22
|
+
# CLI entry point - import module, not function, so "from sprint import cli" gets the module
|
|
23
|
+
from pennyfarthing_scripts.sprint import (
|
|
24
|
+
archive,
|
|
25
|
+
cli,
|
|
26
|
+
loader,
|
|
27
|
+
status,
|
|
28
|
+
work,
|
|
29
|
+
)
|
|
30
|
+
from pennyfarthing_scripts.sprint.cli import main
|
|
21
31
|
from pennyfarthing_scripts.sprint.loader import (
|
|
22
32
|
find_epic,
|
|
23
33
|
find_story,
|
|
@@ -31,18 +41,6 @@ from pennyfarthing_scripts.sprint.loader import (
|
|
|
31
41
|
load_sprint,
|
|
32
42
|
)
|
|
33
43
|
|
|
34
|
-
# Import submodules to make them accessible
|
|
35
|
-
from pennyfarthing_scripts.sprint import (
|
|
36
|
-
archive,
|
|
37
|
-
loader,
|
|
38
|
-
status,
|
|
39
|
-
work,
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
# CLI entry point - import module, not function, so "from sprint import cli" gets the module
|
|
43
|
-
from pennyfarthing_scripts.sprint import cli
|
|
44
|
-
from pennyfarthing_scripts.sprint.cli import main
|
|
45
|
-
|
|
46
44
|
__all__ = [
|
|
47
45
|
# Loader functions
|
|
48
46
|
"find_epic",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -18,7 +18,6 @@ from pennyfarthing_scripts.sprint.yaml_io import (
|
|
|
18
18
|
_read_yaml_file,
|
|
19
19
|
_write_yaml_file,
|
|
20
20
|
read_sprint,
|
|
21
|
-
write_sprint,
|
|
22
21
|
)
|
|
23
22
|
|
|
24
23
|
|
|
@@ -252,13 +251,11 @@ def archive_epic(
|
|
|
252
251
|
|
|
253
252
|
# Find the epic in merged data
|
|
254
253
|
epic = None
|
|
255
|
-
|
|
256
|
-
for i, e in enumerate(sprint_data["epics"]):
|
|
254
|
+
for e in sprint_data["epics"]:
|
|
257
255
|
eid = str(e.get("id", ""))
|
|
258
256
|
ejira = str(e.get("jira", ""))
|
|
259
257
|
if eid == epic_id or ejira == epic_id:
|
|
260
258
|
epic = e
|
|
261
|
-
epic_index = i
|
|
262
259
|
break
|
|
263
260
|
|
|
264
261
|
if not epic:
|
|
@@ -150,7 +150,7 @@ def work(story_id: str | None, dry_run: bool):
|
|
|
150
150
|
click.echo(f"Story: {story.get('id')}")
|
|
151
151
|
click.echo(f"Title: {story.get('title')}")
|
|
152
152
|
click.echo(f"Points: {story.get('points')}")
|
|
153
|
-
click.echo(
|
|
153
|
+
click.echo("Status: Available")
|
|
154
154
|
else:
|
|
155
155
|
error_msg = result.get("error") or result.get("reason")
|
|
156
156
|
raise click.ClickException(f"Not available: {error_msg}")
|
|
@@ -334,12 +334,12 @@ def story_claim(story_id: str, claim: bool):
|
|
|
334
334
|
|
|
335
335
|
|
|
336
336
|
# Register story-add as story.add
|
|
337
|
-
from pennyfarthing_scripts.sprint.story_add import story_add_command
|
|
337
|
+
from pennyfarthing_scripts.sprint.story_add import story_add_command # noqa: E402
|
|
338
338
|
|
|
339
339
|
story.add_command(story_add_command, "add")
|
|
340
340
|
|
|
341
341
|
# Register story-update as story.update
|
|
342
|
-
from pennyfarthing_scripts.sprint.story_update import story_update_command
|
|
342
|
+
from pennyfarthing_scripts.sprint.story_update import story_update_command # noqa: E402
|
|
343
343
|
|
|
344
344
|
story.add_command(story_update_command, "update")
|
|
345
345
|
|
|
@@ -501,7 +501,6 @@ def epic_cancel(epic_id: str, jira: bool, dry_run: bool):
|
|
|
501
501
|
pf sprint epic cancel epic-42 --jira
|
|
502
502
|
"""
|
|
503
503
|
from pennyfarthing_scripts.common.config import get_project_root
|
|
504
|
-
from pennyfarthing_scripts.sprint.loader import load_sprint
|
|
505
504
|
from pennyfarthing_scripts.sprint.yaml_io import read_sprint, write_sprint
|
|
506
505
|
|
|
507
506
|
root = get_project_root()
|
|
@@ -583,7 +582,7 @@ def _cancel_epic_in_initiatives(epic_id: str, root, *, jira: bool, dry_run: bool
|
|
|
583
582
|
init_name = init_data.get("name", init_file.stem)
|
|
584
583
|
epics = init_data.get("epics", [])
|
|
585
584
|
|
|
586
|
-
for
|
|
585
|
+
for _i, e in enumerate(epics):
|
|
587
586
|
matched = False
|
|
588
587
|
epic_dict = None
|
|
589
588
|
|
|
@@ -663,6 +662,8 @@ def epic_archive(epic_id: str | None, dry_run: bool, jira: bool):
|
|
|
663
662
|
# Lazy import
|
|
664
663
|
from pennyfarthing_scripts.sprint.archive_epic import (
|
|
665
664
|
archive_all_completed,
|
|
665
|
+
)
|
|
666
|
+
from pennyfarthing_scripts.sprint.archive_epic import (
|
|
666
667
|
archive_epic as do_archive_epic,
|
|
667
668
|
)
|
|
668
669
|
|
|
@@ -757,7 +758,6 @@ def epic_remove(epic_id: str, dry_run: bool):
|
|
|
757
758
|
pf sprint epic remove epic-41
|
|
758
759
|
pf sprint epic remove epic-41 --dry-run
|
|
759
760
|
"""
|
|
760
|
-
from pathlib import Path
|
|
761
761
|
|
|
762
762
|
import yaml
|
|
763
763
|
|
|
@@ -886,20 +886,23 @@ def epic_promote(epic_id: str):
|
|
|
886
886
|
new_epic_id = original_id
|
|
887
887
|
existing_ids = {str(e.get("id", "")) for e in sprint_data["epics"] if isinstance(e, dict)}
|
|
888
888
|
|
|
889
|
+
# Normalize to numeric ID (ADR-0022: strip epic- prefix from values)
|
|
890
|
+
new_epic_id = new_epic_id.replace("epic-", "") if new_epic_id.startswith("epic-") else new_epic_id
|
|
891
|
+
|
|
889
892
|
if new_epic_id in existing_ids:
|
|
890
893
|
max_num = 0
|
|
891
894
|
for eid in existing_ids:
|
|
892
|
-
if eid.startswith("epic-")
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
new_epic_id =
|
|
895
|
+
clean_eid = eid.replace("epic-", "") if eid.startswith("epic-") else eid
|
|
896
|
+
try:
|
|
897
|
+
max_num = max(max_num, int(clean_eid))
|
|
898
|
+
except ValueError:
|
|
899
|
+
pass
|
|
900
|
+
new_epic_id = str(max_num + 1)
|
|
898
901
|
click.echo(f"Warning: Epic ID {original_id} already exists. Assigning new ID: {new_epic_id}")
|
|
899
902
|
|
|
900
903
|
# Transform epic for current sprint
|
|
901
904
|
old_id_num = original_id.replace("epic-", "")
|
|
902
|
-
new_id_num = new_epic_id.replace("epic-", "")
|
|
905
|
+
new_id_num = new_epic_id.replace("epic-", "") if new_epic_id.startswith("epic-") else new_epic_id
|
|
903
906
|
|
|
904
907
|
epic_data["id"] = new_epic_id
|
|
905
908
|
epic_data["status"] = "backlog"
|
|
@@ -928,6 +931,13 @@ def epic_promote(epic_id: str):
|
|
|
928
931
|
click.echo(f" Stories: {story_count}")
|
|
929
932
|
click.echo("")
|
|
930
933
|
|
|
934
|
+
# Validate epic shard before writing (ADR-0022)
|
|
935
|
+
from pennyfarthing_scripts.sprint.validator import validate_epic_shard
|
|
936
|
+
validation = validate_epic_shard(dict(epic_data))
|
|
937
|
+
if not validation.valid:
|
|
938
|
+
error_msgs = "; ".join(e.message for e in validation.errors)
|
|
939
|
+
raise click.ClickException(f"Epic validation failed: {error_msgs}")
|
|
940
|
+
|
|
931
941
|
# Append to sprint
|
|
932
942
|
sprint_data["epics"].append(epic_data)
|
|
933
943
|
|
|
@@ -960,7 +970,6 @@ def epic_promote(epic_id: str):
|
|
|
960
970
|
click.echo(f"Removed {original_id} from {source_init_file.name}")
|
|
961
971
|
else:
|
|
962
972
|
# Initiative is empty — remove shard and future.yaml reference
|
|
963
|
-
init_name = init_data.get("name", "")
|
|
964
973
|
init_slug = source_init_file.stem.replace("initiative-", "")
|
|
965
974
|
source_init_file.unlink()
|
|
966
975
|
click.echo(f"Removed empty initiative shard: {source_init_file.name}")
|
|
@@ -987,7 +996,7 @@ def epic_promote(epic_id: str):
|
|
|
987
996
|
|
|
988
997
|
|
|
989
998
|
# Register epic-add as epic.add
|
|
990
|
-
from pennyfarthing_scripts.sprint.epic_add import epic_add_command
|
|
999
|
+
from pennyfarthing_scripts.sprint.epic_add import epic_add_command # noqa: E402
|
|
991
1000
|
|
|
992
1001
|
epic.add_command(epic_add_command, "add")
|
|
993
1002
|
|
|
@@ -1161,7 +1170,7 @@ def initiative_cancel(name: str, jira: bool, dry_run: bool):
|
|
|
1161
1170
|
return
|
|
1162
1171
|
|
|
1163
1172
|
# Cancel all epics
|
|
1164
|
-
for
|
|
1173
|
+
for _i, e in enumerate(epics):
|
|
1165
1174
|
if isinstance(e, str):
|
|
1166
1175
|
shard = _epic_shard_path(sprint_dir, e)
|
|
1167
1176
|
if shard.exists():
|
|
@@ -1216,7 +1225,6 @@ def check(id: str):
|
|
|
1216
1225
|
|
|
1217
1226
|
from pennyfarthing_scripts.sprint.loader import (
|
|
1218
1227
|
find_epic,
|
|
1219
|
-
get_all_stories,
|
|
1220
1228
|
load_sprint,
|
|
1221
1229
|
)
|
|
1222
1230
|
from pennyfarthing_scripts.sprint.work import check_story, get_next_story
|
|
@@ -1328,10 +1336,10 @@ def _find_epic_for_story(data: dict | None, story_id: str) -> str:
|
|
|
1328
1336
|
|
|
1329
1337
|
@sprint.command()
|
|
1330
1338
|
def info():
|
|
1331
|
-
"""Output sprint info as JSON
|
|
1339
|
+
"""Output sprint info as JSON.
|
|
1332
1340
|
|
|
1333
1341
|
\b
|
|
1334
|
-
Returns
|
|
1342
|
+
Returns sprint header fields plus computed story point totals.
|
|
1335
1343
|
"""
|
|
1336
1344
|
import json
|
|
1337
1345
|
|
|
@@ -1340,8 +1348,6 @@ def info():
|
|
|
1340
1348
|
sprint_data = get_sprint_info()
|
|
1341
1349
|
stories = get_all_stories()
|
|
1342
1350
|
|
|
1343
|
-
end_date = sprint_data.get("end_date")
|
|
1344
|
-
|
|
1345
1351
|
remaining = sum(
|
|
1346
1352
|
s.get("points", 0) or 0
|
|
1347
1353
|
for s in stories
|
|
@@ -1353,11 +1359,11 @@ def info():
|
|
|
1353
1359
|
if s.get("status") == "in_progress"
|
|
1354
1360
|
)
|
|
1355
1361
|
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1362
|
+
result = {str(k): str(v) if hasattr(v, 'isoformat') else v for k, v in sprint_data.items()}
|
|
1363
|
+
result["remaining"] = remaining
|
|
1364
|
+
result["inProgress"] = in_progress
|
|
1365
|
+
|
|
1366
|
+
click.echo(json.dumps(result))
|
|
1361
1367
|
|
|
1362
1368
|
|
|
1363
1369
|
# --- Metrics command (replaces sprint-metrics.sh) ---
|
|
@@ -1783,7 +1789,7 @@ completed:
|
|
|
1783
1789
|
click.echo(f"Created {archive_file}")
|
|
1784
1790
|
|
|
1785
1791
|
click.echo("")
|
|
1786
|
-
click.echo(
|
|
1792
|
+
click.echo("New sprint initialized:")
|
|
1787
1793
|
click.echo(f" Name: TO Sprint {sprint_yyww}")
|
|
1788
1794
|
click.echo(f" Jira ID: {jira_id}")
|
|
1789
1795
|
click.echo(f" Dates: {start_date} to {end_date}")
|
|
@@ -1854,7 +1860,7 @@ sprint.commands["epic-add"].hidden = True
|
|
|
1854
1860
|
|
|
1855
1861
|
|
|
1856
1862
|
# Register validate command from validate_cmd module
|
|
1857
|
-
from pennyfarthing_scripts.sprint.validate_cmd import validate_command
|
|
1863
|
+
from pennyfarthing_scripts.sprint.validate_cmd import validate_command # noqa: E402
|
|
1858
1864
|
|
|
1859
1865
|
sprint.add_command(validate_command)
|
|
1860
1866
|
|
|
@@ -14,11 +14,12 @@ from typing import Any
|
|
|
14
14
|
import click
|
|
15
15
|
from ruamel.yaml.comments import CommentedMap, CommentedSeq
|
|
16
16
|
|
|
17
|
+
from pennyfarthing_scripts.sprint import validator as _shard_validator
|
|
17
18
|
from pennyfarthing_scripts.sprint.yaml_io import (
|
|
18
19
|
EPIC_KEY_ORDER,
|
|
20
|
+
_get_epic_ref,
|
|
19
21
|
_read_yaml_file,
|
|
20
22
|
_write_yaml_file,
|
|
21
|
-
_get_epic_ref,
|
|
22
23
|
)
|
|
23
24
|
|
|
24
25
|
|
|
@@ -76,6 +77,12 @@ def add_epic(
|
|
|
76
77
|
if key not in EPIC_KEY_ORDER:
|
|
77
78
|
epic[key] = fields[key]
|
|
78
79
|
|
|
80
|
+
# Validate epic shard before writing
|
|
81
|
+
validation = _shard_validator.validate_epic_shard(dict(epic))
|
|
82
|
+
if not validation.valid:
|
|
83
|
+
error_msgs = "; ".join(e.message for e in validation.errors)
|
|
84
|
+
return {"success": False, "error": f"Epic validation failed: {error_msgs}"}
|
|
85
|
+
|
|
79
86
|
# Determine the shard reference
|
|
80
87
|
ref = _get_epic_ref(epic)
|
|
81
88
|
shard_file = sprint_dir / f"epic-{ref}.yaml"
|
|
@@ -10,9 +10,7 @@ from datetime import date
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Any
|
|
12
12
|
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
from pennyfarthing_scripts.common.config import get_project_root, load_yaml_config
|
|
13
|
+
from pennyfarthing_scripts.common.config import get_project_root
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
def parse_epics_markdown(content: str) -> dict[str, Any]:
|
|
@@ -195,13 +193,13 @@ def generate_initiative_yaml(
|
|
|
195
193
|
today = date.today().isoformat()
|
|
196
194
|
|
|
197
195
|
lines = [
|
|
198
|
-
|
|
196
|
+
" # ==========================================================================",
|
|
199
197
|
f" # {initiative_name.upper()}",
|
|
200
198
|
f" # Imported from: {source_file}",
|
|
201
199
|
f" # Date: {today}",
|
|
202
|
-
|
|
200
|
+
" # ==========================================================================",
|
|
203
201
|
f' - name: "{initiative_name}"',
|
|
204
|
-
|
|
202
|
+
" description: |",
|
|
205
203
|
]
|
|
206
204
|
|
|
207
205
|
# Add description lines with proper indentation
|
|
@@ -210,10 +208,10 @@ def generate_initiative_yaml(
|
|
|
210
208
|
|
|
211
209
|
lines.extend(
|
|
212
210
|
[
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
" status: ready",
|
|
212
|
+
" blocked_by: null",
|
|
215
213
|
f" total_points: {parsed['total_points']}",
|
|
216
|
-
|
|
214
|
+
" epics:",
|
|
217
215
|
]
|
|
218
216
|
)
|
|
219
217
|
|
|
@@ -228,14 +226,14 @@ def generate_initiative_yaml(
|
|
|
228
226
|
[
|
|
229
227
|
f" - id: epic-{current_epic_num}",
|
|
230
228
|
f' title: "{epic["title"]}"',
|
|
231
|
-
|
|
229
|
+
" description: |",
|
|
232
230
|
f" {epic.get('description', epic['title'])}",
|
|
233
231
|
f" points: {epic_points}",
|
|
234
|
-
|
|
232
|
+
" priority: P1",
|
|
235
233
|
f' marker: "{marker}"',
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
234
|
+
" repos: pennyfarthing",
|
|
235
|
+
" status: planning",
|
|
236
|
+
" stories:",
|
|
239
237
|
]
|
|
240
238
|
)
|
|
241
239
|
|
|
@@ -247,12 +245,12 @@ def generate_initiative_yaml(
|
|
|
247
245
|
[
|
|
248
246
|
f' - id: "{story_id}"',
|
|
249
247
|
f' title: "{title}"',
|
|
250
|
-
|
|
248
|
+
" description: |",
|
|
251
249
|
f" {story.get('description', title)}",
|
|
252
250
|
f" points: {story.get('points', 1)}",
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
251
|
+
" priority: P0",
|
|
252
|
+
" status: planning",
|
|
253
|
+
" repos: pennyfarthing",
|
|
256
254
|
]
|
|
257
255
|
)
|
|
258
256
|
|
|
@@ -304,6 +302,32 @@ def import_epic(
|
|
|
304
302
|
# Get next epic number
|
|
305
303
|
start_epic_num = get_next_epic_number(root)
|
|
306
304
|
|
|
305
|
+
# Validate each parsed epic before writing (ADR-0022)
|
|
306
|
+
from pennyfarthing_scripts.sprint.validator import validate_epic_shard
|
|
307
|
+
|
|
308
|
+
epic_num = start_epic_num
|
|
309
|
+
for epic in parsed["epics"]:
|
|
310
|
+
# Build a shard-like dict for validation
|
|
311
|
+
shard_dict = {
|
|
312
|
+
"id": str(epic_num),
|
|
313
|
+
"title": epic.get("title", ""),
|
|
314
|
+
"status": "planning",
|
|
315
|
+
"stories": [
|
|
316
|
+
{
|
|
317
|
+
"id": f"{epic_num}-{s['num']}",
|
|
318
|
+
"title": s.get("title", ""),
|
|
319
|
+
"points": s.get("points", 1),
|
|
320
|
+
"status": "planning",
|
|
321
|
+
}
|
|
322
|
+
for s in epic.get("stories", [])
|
|
323
|
+
],
|
|
324
|
+
}
|
|
325
|
+
validation = validate_epic_shard(shard_dict)
|
|
326
|
+
if not validation.valid:
|
|
327
|
+
error_msgs = "; ".join(e.message for e in validation.errors)
|
|
328
|
+
return {"success": False, "error": f"Epic {epic_num} validation failed: {error_msgs}"}
|
|
329
|
+
epic_num += 1
|
|
330
|
+
|
|
307
331
|
# Generate YAML
|
|
308
332
|
relative_path = str(epics_path.relative_to(root)) if epics_path.is_relative_to(root) else str(epics_path)
|
|
309
333
|
new_yaml, next_epic_num = generate_initiative_yaml(
|
|
@@ -5,6 +5,7 @@ Provides access to sprint/current-sprint.yaml data.
|
|
|
5
5
|
Supports sharded per-epic format (epic-{ref}.yaml shard files).
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
import warnings
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from typing import Any
|
|
10
11
|
|
|
@@ -40,6 +41,11 @@ def _merge_epic_shards(data: dict[str, Any], sprint_dir: Path) -> dict[str, Any]
|
|
|
40
41
|
epic_data = load_yaml_config(epic_file)
|
|
41
42
|
if epic_data is not None:
|
|
42
43
|
merged_epics.append(epic_data)
|
|
44
|
+
else:
|
|
45
|
+
warnings.warn(
|
|
46
|
+
f"Sprint epic ref '{ref}' not found: {epic_file}",
|
|
47
|
+
stacklevel=2,
|
|
48
|
+
)
|
|
43
49
|
|
|
44
50
|
data["epics"] = merged_epics
|
|
45
51
|
return data
|
|
@@ -6,7 +6,7 @@ Provides functions for getting and displaying sprint status.
|
|
|
6
6
|
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
from pennyfarthing_scripts.sprint.loader import get_all_stories, get_sprint_info
|
|
9
|
+
from pennyfarthing_scripts.sprint.loader import get_all_stories, get_sprint_info
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def get_sprint_status(filter_status: str | None = None) -> dict[str, Any]:
|
|
@@ -99,7 +99,6 @@ def main(args: list[str] | None = None) -> int:
|
|
|
99
99
|
Exit code
|
|
100
100
|
"""
|
|
101
101
|
import argparse
|
|
102
|
-
import sys
|
|
103
102
|
|
|
104
103
|
parser = argparse.ArgumentParser(description="Show sprint status")
|
|
105
104
|
parser.add_argument(
|