@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
|
@@ -16,21 +16,11 @@ Acceptance Criteria:
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
import asyncio
|
|
19
|
-
import tempfile
|
|
20
19
|
from pathlib import Path
|
|
21
|
-
from
|
|
22
|
-
from unittest.mock import AsyncMock, MagicMock, patch
|
|
20
|
+
from unittest.mock import AsyncMock, patch
|
|
23
21
|
|
|
24
22
|
import pytest
|
|
25
23
|
|
|
26
|
-
from pennyfarthing_scripts.git.status_all import (
|
|
27
|
-
RepoStatus,
|
|
28
|
-
format_status_brief,
|
|
29
|
-
format_status_full,
|
|
30
|
-
format_summary,
|
|
31
|
-
get_all_repo_status,
|
|
32
|
-
get_repo_status,
|
|
33
|
-
)
|
|
34
24
|
from pennyfarthing_scripts.git.create_branches import (
|
|
35
25
|
BranchAction,
|
|
36
26
|
BranchResult,
|
|
@@ -40,7 +30,14 @@ from pennyfarthing_scripts.git.create_branches import (
|
|
|
40
30
|
filter_repos,
|
|
41
31
|
format_results,
|
|
42
32
|
)
|
|
43
|
-
|
|
33
|
+
from pennyfarthing_scripts.git.status_all import (
|
|
34
|
+
RepoStatus,
|
|
35
|
+
format_status_brief,
|
|
36
|
+
format_status_full,
|
|
37
|
+
format_summary,
|
|
38
|
+
get_all_repo_status,
|
|
39
|
+
get_repo_status,
|
|
40
|
+
)
|
|
44
41
|
|
|
45
42
|
# =============================================================================
|
|
46
43
|
# Test Fixtures
|
|
@@ -793,8 +790,8 @@ class TestCrossPlatformCompatibility:
|
|
|
793
790
|
def test_no_shell_specific_commands(self) -> None:
|
|
794
791
|
"""Implementation should not use shell-specific commands."""
|
|
795
792
|
# This is more of a code review check, but we can verify the modules exist
|
|
796
|
-
import pennyfarthing_scripts.git.status_all as status_mod
|
|
797
793
|
import pennyfarthing_scripts.git.create_branches as branch_mod
|
|
794
|
+
import pennyfarthing_scripts.git.status_all as status_mod
|
|
798
795
|
|
|
799
796
|
# Modules should exist and be importable
|
|
800
797
|
assert status_mod is not None
|
|
@@ -17,19 +17,12 @@ from __future__ import annotations
|
|
|
17
17
|
|
|
18
18
|
import asyncio
|
|
19
19
|
import json
|
|
20
|
-
import time
|
|
21
20
|
from dataclasses import asdict
|
|
22
21
|
from pathlib import Path
|
|
23
|
-
from unittest.mock import patch
|
|
22
|
+
from unittest.mock import patch
|
|
24
23
|
|
|
25
|
-
import pytest
|
|
26
24
|
from click.testing import CliRunner
|
|
27
25
|
|
|
28
|
-
from pennyfarthing_scripts.healthscore.models import (
|
|
29
|
-
DimensionScore,
|
|
30
|
-
HealthscoreResult,
|
|
31
|
-
DEFAULT_WEIGHTS,
|
|
32
|
-
)
|
|
33
26
|
from pennyfarthing_scripts.healthscore.analyze import (
|
|
34
27
|
analyze_healthscore,
|
|
35
28
|
compute_composite_score,
|
|
@@ -37,13 +30,12 @@ from pennyfarthing_scripts.healthscore.analyze import (
|
|
|
37
30
|
read_cached_score,
|
|
38
31
|
write_cached_score,
|
|
39
32
|
)
|
|
40
|
-
from pennyfarthing_scripts.healthscore.formatters import (
|
|
41
|
-
format_table,
|
|
42
|
-
export_json,
|
|
43
|
-
export_csv,
|
|
44
|
-
)
|
|
45
33
|
from pennyfarthing_scripts.healthscore.cli import healthscore
|
|
46
|
-
|
|
34
|
+
from pennyfarthing_scripts.healthscore.models import (
|
|
35
|
+
DEFAULT_WEIGHTS,
|
|
36
|
+
DimensionScore,
|
|
37
|
+
HealthscoreResult,
|
|
38
|
+
)
|
|
47
39
|
|
|
48
40
|
# ---------------------------------------------------------------------------
|
|
49
41
|
# AC1: Module structure
|
|
@@ -122,17 +114,17 @@ class TestWeightedScoring:
|
|
|
122
114
|
|
|
123
115
|
def test_custom_weights_override_defaults(self):
|
|
124
116
|
"""compute_composite_score must accept custom weights."""
|
|
125
|
-
custom =
|
|
126
|
-
scores =
|
|
117
|
+
custom = dict.fromkeys(DEFAULT_WEIGHTS, 1.0 / 8)
|
|
118
|
+
scores = dict.fromkeys(DEFAULT_WEIGHTS, 80.0)
|
|
127
119
|
result = compute_composite_score(scores, custom)
|
|
128
120
|
assert abs(result - 80.0) < 1e-9
|
|
129
121
|
|
|
130
122
|
def test_unequal_custom_weights(self):
|
|
131
123
|
"""Asymmetric weights should shift composite score."""
|
|
132
|
-
weights =
|
|
124
|
+
weights = dict.fromkeys(DEFAULT_WEIGHTS, 0.0)
|
|
133
125
|
weights["churn"] = 1.0 # All weight on churn
|
|
134
126
|
|
|
135
|
-
scores =
|
|
127
|
+
scores = dict.fromkeys(DEFAULT_WEIGHTS, 50.0)
|
|
136
128
|
scores["churn"] = 100.0
|
|
137
129
|
|
|
138
130
|
result = compute_composite_score(scores, weights)
|
|
@@ -148,13 +140,13 @@ class TestScoreRanges:
|
|
|
148
140
|
|
|
149
141
|
def test_all_zeros_yields_zero(self):
|
|
150
142
|
"""All dimensions at 0 → composite 0."""
|
|
151
|
-
scores =
|
|
143
|
+
scores = dict.fromkeys(DEFAULT_WEIGHTS, 0.0)
|
|
152
144
|
result = compute_composite_score(scores, DEFAULT_WEIGHTS)
|
|
153
145
|
assert result == 0.0
|
|
154
146
|
|
|
155
147
|
def test_all_hundreds_yields_hundred(self):
|
|
156
148
|
"""All dimensions at 100 → composite 100."""
|
|
157
|
-
scores =
|
|
149
|
+
scores = dict.fromkeys(DEFAULT_WEIGHTS, 100.0)
|
|
158
150
|
result = compute_composite_score(scores, DEFAULT_WEIGHTS)
|
|
159
151
|
assert abs(result - 100.0) < 1e-9
|
|
160
152
|
|
|
@@ -176,7 +168,7 @@ class TestScoreRanges:
|
|
|
176
168
|
|
|
177
169
|
def test_none_dimensions_excluded_and_renormalized(self):
|
|
178
170
|
"""Unavailable dimensions (None) are excluded; remaining weights renormalize."""
|
|
179
|
-
scores =
|
|
171
|
+
scores = dict.fromkeys(DEFAULT_WEIGHTS)
|
|
180
172
|
scores["churn"] = 80.0
|
|
181
173
|
scores["complexity"] = 60.0
|
|
182
174
|
# Only churn (0.15) and complexity (0.15) available → renorm to 0.5 each
|
|
@@ -186,7 +178,7 @@ class TestScoreRanges:
|
|
|
186
178
|
|
|
187
179
|
def test_all_none_dimensions_returns_zero(self):
|
|
188
180
|
"""All dimensions unavailable → composite 0."""
|
|
189
|
-
scores =
|
|
181
|
+
scores = dict.fromkeys(DEFAULT_WEIGHTS)
|
|
190
182
|
result = compute_composite_score(scores, DEFAULT_WEIGHTS)
|
|
191
183
|
assert result == 0.0
|
|
192
184
|
|
|
@@ -374,7 +366,7 @@ class TestCaching:
|
|
|
374
366
|
"pennyfarthing_scripts.healthscore.analyze.read_cached_score",
|
|
375
367
|
return_value=99.0,
|
|
376
368
|
) as mock_read:
|
|
377
|
-
|
|
369
|
+
asyncio.run(
|
|
378
370
|
analyze_healthscore(Path("/tmp/project"), cache_ttl=0)
|
|
379
371
|
)
|
|
380
372
|
# With ttl=0, cached values should not be used
|
|
@@ -484,7 +476,7 @@ class TestMainCLIRegistration:
|
|
|
484
476
|
def test_healthscore_registered_in_main_cli(self):
|
|
485
477
|
"""Main CLI must have a 'healthscore' command group."""
|
|
486
478
|
from pennyfarthing_scripts.cli import cli
|
|
487
|
-
command_names =
|
|
479
|
+
command_names = list(cli.commands)
|
|
488
480
|
assert "healthscore" in command_names
|
|
489
481
|
|
|
490
482
|
|
|
@@ -507,7 +499,7 @@ class TestAnalyzeIntegration:
|
|
|
507
499
|
|
|
508
500
|
def test_analyze_with_custom_weights(self):
|
|
509
501
|
"""Custom weights must be accepted and applied."""
|
|
510
|
-
custom =
|
|
502
|
+
custom = dict.fromkeys(DEFAULT_WEIGHTS, 1.0 / 8)
|
|
511
503
|
result = asyncio.run(analyze_healthscore(Path("/tmp/nonexistent"), weights=custom))
|
|
512
504
|
assert isinstance(result, HealthscoreResult)
|
|
513
505
|
|
|
@@ -10,12 +10,7 @@ These tests verify:
|
|
|
10
10
|
5. Backwards compatibility for existing imports
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
-
import importlib
|
|
14
13
|
import sys
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
from typing import Any
|
|
17
|
-
|
|
18
|
-
import pytest
|
|
19
14
|
|
|
20
15
|
|
|
21
16
|
class TestCommonPackage:
|
|
@@ -126,8 +121,6 @@ class TestJiraPackage:
|
|
|
126
121
|
from pennyfarthing_scripts.jira import (
|
|
127
122
|
JiraClient,
|
|
128
123
|
extract_jira_key,
|
|
129
|
-
map_status_to_jira,
|
|
130
|
-
map_jira_to_status,
|
|
131
124
|
)
|
|
132
125
|
|
|
133
126
|
assert JiraClient is not None
|
|
@@ -136,9 +129,7 @@ class TestJiraPackage:
|
|
|
136
129
|
def test_jira_backwards_compatibility(self) -> None:
|
|
137
130
|
"""Old-style imports should still work."""
|
|
138
131
|
# These imports should work for backwards compatibility
|
|
139
|
-
from pennyfarthing_scripts.jira import JiraClient
|
|
140
|
-
from pennyfarthing_scripts.jira import get_issue
|
|
141
|
-
from pennyfarthing_scripts.jira import STATUS_TO_JIRA
|
|
132
|
+
from pennyfarthing_scripts.jira import STATUS_TO_JIRA, JiraClient, get_issue
|
|
142
133
|
|
|
143
134
|
assert JiraClient is not None
|
|
144
135
|
assert callable(get_issue)
|
|
@@ -188,10 +179,8 @@ class TestSprintPackage:
|
|
|
188
179
|
def test_sprint_package_reexports(self) -> None:
|
|
189
180
|
"""sprint/__init__.py should re-export commonly used items."""
|
|
190
181
|
from pennyfarthing_scripts.sprint import (
|
|
191
|
-
load_sprint,
|
|
192
182
|
find_epic,
|
|
193
|
-
|
|
194
|
-
get_all_stories,
|
|
183
|
+
load_sprint,
|
|
195
184
|
)
|
|
196
185
|
|
|
197
186
|
assert callable(load_sprint)
|
|
@@ -199,9 +188,7 @@ class TestSprintPackage:
|
|
|
199
188
|
|
|
200
189
|
def test_sprint_backwards_compatibility(self) -> None:
|
|
201
190
|
"""Old-style imports should still work."""
|
|
202
|
-
from pennyfarthing_scripts.sprint import load_sprint
|
|
203
|
-
from pennyfarthing_scripts.sprint import find_epic
|
|
204
|
-
from pennyfarthing_scripts.sprint import load_current_sprint
|
|
191
|
+
from pennyfarthing_scripts.sprint import find_epic, load_current_sprint, load_sprint
|
|
205
192
|
|
|
206
193
|
assert callable(load_sprint)
|
|
207
194
|
assert callable(find_epic)
|
|
@@ -18,13 +18,9 @@ Acceptance Criteria:
|
|
|
18
18
|
These tests should FAIL until patch_mode.py is implemented.
|
|
19
19
|
"""
|
|
20
20
|
|
|
21
|
-
import json
|
|
22
|
-
import os
|
|
23
|
-
import subprocess
|
|
24
|
-
import sys
|
|
25
21
|
from pathlib import Path
|
|
26
|
-
from typing import Any
|
|
27
|
-
from unittest.mock import MagicMock, patch
|
|
22
|
+
from typing import Any
|
|
23
|
+
from unittest.mock import MagicMock, patch
|
|
28
24
|
|
|
29
25
|
import pytest
|
|
30
26
|
import yaml
|
|
@@ -32,17 +28,17 @@ import yaml
|
|
|
32
28
|
# Import will fail until module exists - this is intentional for RED state
|
|
33
29
|
try:
|
|
34
30
|
from pennyfarthing_scripts.patch_mode import (
|
|
35
|
-
PatchState,
|
|
36
31
|
PatchStack,
|
|
32
|
+
PatchState,
|
|
33
|
+
create_patch_branch,
|
|
37
34
|
enter_patch_mode,
|
|
38
35
|
exit_patch_mode,
|
|
36
|
+
generate_patch_commit_message,
|
|
39
37
|
get_patch_stack,
|
|
40
|
-
|
|
38
|
+
is_in_patch_mode,
|
|
39
|
+
log_patch_to_session,
|
|
41
40
|
merge_patch_branch,
|
|
42
41
|
restore_workflow_state,
|
|
43
|
-
log_patch_to_session,
|
|
44
|
-
generate_patch_commit_message,
|
|
45
|
-
is_in_patch_mode,
|
|
46
42
|
)
|
|
47
43
|
IMPORT_SUCCESS = True
|
|
48
44
|
except ImportError:
|
|
@@ -3,21 +3,22 @@
|
|
|
3
3
|
Tests context loading for prime command.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
-
import pytest
|
|
7
6
|
from pathlib import Path
|
|
8
|
-
from unittest.mock import patch
|
|
7
|
+
from unittest.mock import patch
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
9
10
|
|
|
11
|
+
from pennyfarthing_scripts.prime.cli import main, prime
|
|
10
12
|
from pennyfarthing_scripts.prime.loader import (
|
|
13
|
+
_extract_session_parts,
|
|
14
|
+
_find_session_file,
|
|
11
15
|
load_agent_definition,
|
|
12
16
|
load_behavior_guide,
|
|
13
|
-
|
|
17
|
+
load_domain_docs,
|
|
14
18
|
load_session_context,
|
|
15
19
|
load_sidecars,
|
|
16
|
-
|
|
17
|
-
_extract_session_parts,
|
|
18
|
-
_find_session_file,
|
|
20
|
+
load_sprint_context,
|
|
19
21
|
)
|
|
20
|
-
from pennyfarthing_scripts.prime.cli import prime, main
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class TestLoadAgentDefinition:
|
|
@@ -407,8 +408,8 @@ class TestWorkflowStateDetection:
|
|
|
407
408
|
|
|
408
409
|
def test_detect_finish_state(self, tmp_path: Path) -> None:
|
|
409
410
|
"""Test detecting FINISH_STATE when phase is approved."""
|
|
410
|
-
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
411
411
|
from pennyfarthing_scripts.prime.models import WorkflowState
|
|
412
|
+
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
412
413
|
|
|
413
414
|
# Setup
|
|
414
415
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
@@ -436,10 +437,11 @@ class TestWorkflowStateDetection:
|
|
|
436
437
|
|
|
437
438
|
def test_detect_in_progress_state(self, tmp_path: Path) -> None:
|
|
438
439
|
"""Test detecting IN_PROGRESS_STATE with active phase."""
|
|
439
|
-
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
440
|
-
from pennyfarthing_scripts.prime.models import WorkflowState
|
|
441
440
|
import yaml
|
|
442
441
|
|
|
442
|
+
from pennyfarthing_scripts.prime.models import WorkflowState
|
|
443
|
+
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
444
|
+
|
|
443
445
|
# Setup
|
|
444
446
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
445
447
|
pf_dir.mkdir()
|
|
@@ -483,10 +485,11 @@ class TestWorkflowStateDetection:
|
|
|
483
485
|
|
|
484
486
|
def test_detect_new_work_state(self, tmp_path: Path) -> None:
|
|
485
487
|
"""Test detecting NEW_WORK_STATE with backlog stories."""
|
|
486
|
-
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
487
|
-
from pennyfarthing_scripts.prime.models import WorkflowState
|
|
488
488
|
import yaml
|
|
489
489
|
|
|
490
|
+
from pennyfarthing_scripts.prime.models import WorkflowState
|
|
491
|
+
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
492
|
+
|
|
490
493
|
# Setup
|
|
491
494
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
492
495
|
pf_dir.mkdir()
|
|
@@ -514,10 +517,11 @@ class TestWorkflowStateDetection:
|
|
|
514
517
|
|
|
515
518
|
def test_detect_empty_backlog_state(self, tmp_path: Path) -> None:
|
|
516
519
|
"""Test detecting EMPTY_BACKLOG_STATE with no backlog."""
|
|
517
|
-
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
518
|
-
from pennyfarthing_scripts.prime.models import WorkflowState
|
|
519
520
|
import yaml
|
|
520
521
|
|
|
522
|
+
from pennyfarthing_scripts.prime.models import WorkflowState
|
|
523
|
+
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
524
|
+
|
|
521
525
|
# Setup
|
|
522
526
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
523
527
|
pf_dir.mkdir()
|
|
@@ -587,8 +591,8 @@ class TestCheckRedirect:
|
|
|
587
591
|
|
|
588
592
|
def test_redirect_when_wrong_agent(self) -> None:
|
|
589
593
|
"""Test redirect is detected when wrong agent is activated."""
|
|
590
|
-
from pennyfarthing_scripts.prime.workflow import check_redirect
|
|
591
594
|
from pennyfarthing_scripts.prime.models import WorkflowState, WorkflowStatus
|
|
595
|
+
from pennyfarthing_scripts.prime.workflow import check_redirect
|
|
592
596
|
|
|
593
597
|
status = WorkflowStatus(
|
|
594
598
|
state=WorkflowState.IN_PROGRESS_STATE,
|
|
@@ -606,8 +610,8 @@ class TestCheckRedirect:
|
|
|
606
610
|
|
|
607
611
|
def test_no_redirect_when_correct_agent(self) -> None:
|
|
608
612
|
"""Test no redirect when correct agent is activated."""
|
|
609
|
-
from pennyfarthing_scripts.prime.workflow import check_redirect
|
|
610
613
|
from pennyfarthing_scripts.prime.models import WorkflowState, WorkflowStatus
|
|
614
|
+
from pennyfarthing_scripts.prime.workflow import check_redirect
|
|
611
615
|
|
|
612
616
|
status = WorkflowStatus(
|
|
613
617
|
state=WorkflowState.IN_PROGRESS_STATE,
|
|
@@ -621,8 +625,8 @@ class TestCheckRedirect:
|
|
|
621
625
|
|
|
622
626
|
def test_no_redirect_for_new_work(self) -> None:
|
|
623
627
|
"""Test no redirect for NEW_WORK_STATE."""
|
|
624
|
-
from pennyfarthing_scripts.prime.workflow import check_redirect
|
|
625
628
|
from pennyfarthing_scripts.prime.models import WorkflowState, WorkflowStatus
|
|
629
|
+
from pennyfarthing_scripts.prime.workflow import check_redirect
|
|
626
630
|
|
|
627
631
|
status = WorkflowStatus(
|
|
628
632
|
state=WorkflowState.NEW_WORK_STATE,
|
|
@@ -644,9 +648,10 @@ class TestPersonaLoading:
|
|
|
644
648
|
|
|
645
649
|
def test_load_persona_from_theme(self, tmp_path: Path) -> None:
|
|
646
650
|
"""Test loading persona from theme YAML."""
|
|
647
|
-
from pennyfarthing_scripts.prime.persona import load_persona
|
|
648
651
|
import yaml
|
|
649
652
|
|
|
653
|
+
from pennyfarthing_scripts.prime.persona import load_persona
|
|
654
|
+
|
|
650
655
|
# Setup
|
|
651
656
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
652
657
|
pf_dir.mkdir()
|
|
@@ -697,9 +702,10 @@ class TestPersonaLoading:
|
|
|
697
702
|
|
|
698
703
|
def test_get_crew_manifest(self, tmp_path: Path) -> None:
|
|
699
704
|
"""Test getting crew manifest for handoff reference."""
|
|
700
|
-
from pennyfarthing_scripts.prime.persona import get_crew_manifest
|
|
701
705
|
import yaml
|
|
702
706
|
|
|
707
|
+
from pennyfarthing_scripts.prime.persona import get_crew_manifest
|
|
708
|
+
|
|
703
709
|
# Setup
|
|
704
710
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
705
711
|
pf_dir.mkdir()
|
|
@@ -730,8 +736,8 @@ class TestPersonaLoading:
|
|
|
730
736
|
|
|
731
737
|
def test_format_persona_output(self) -> None:
|
|
732
738
|
"""Test formatting persona as XML."""
|
|
739
|
+
from pennyfarthing_scripts.prime.models import CrewMember, Persona
|
|
733
740
|
from pennyfarthing_scripts.prime.persona import format_persona_output
|
|
734
|
-
from pennyfarthing_scripts.prime.models import Persona, CrewMember
|
|
735
741
|
|
|
736
742
|
persona = Persona(
|
|
737
743
|
character="Naomi Nagata",
|
|
@@ -798,9 +804,10 @@ class TestSessionRegistration:
|
|
|
798
804
|
|
|
799
805
|
def test_cleanup_old_sessions(self, tmp_path: Path) -> None:
|
|
800
806
|
"""Test cleanup of old session files."""
|
|
801
|
-
from pennyfarthing_scripts.prime.session import cleanup_old_sessions
|
|
802
807
|
import time
|
|
803
808
|
|
|
809
|
+
from pennyfarthing_scripts.prime.session import cleanup_old_sessions
|
|
810
|
+
|
|
804
811
|
# Setup
|
|
805
812
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
806
813
|
pf_dir.mkdir()
|
|
@@ -886,11 +893,15 @@ class TestJSONOutput:
|
|
|
886
893
|
def test_json_output_with_workflow(self, tmp_path: Path, capsys) -> None:
|
|
887
894
|
"""Test JSON output includes workflow status."""
|
|
888
895
|
import json
|
|
896
|
+
|
|
889
897
|
import yaml
|
|
890
898
|
|
|
891
899
|
# Setup
|
|
892
900
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
893
901
|
pf_dir.mkdir()
|
|
902
|
+
agents_dir = pf_dir / "agents"
|
|
903
|
+
agents_dir.mkdir()
|
|
904
|
+
(agents_dir / "sm.md").write_text("# SM Agent\nScrum Master")
|
|
894
905
|
sprint_dir = tmp_path / "sprint"
|
|
895
906
|
sprint_dir.mkdir()
|
|
896
907
|
(sprint_dir / "current-sprint.yaml").write_text(yaml.dump({
|
|
@@ -925,11 +936,15 @@ class TestJSONOutput:
|
|
|
925
936
|
def test_json_output_with_redirect(self, tmp_path: Path, capsys) -> None:
|
|
926
937
|
"""Test JSON output includes redirect info."""
|
|
927
938
|
import json
|
|
939
|
+
|
|
928
940
|
import yaml
|
|
929
941
|
|
|
930
942
|
# Setup
|
|
931
943
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
932
944
|
pf_dir.mkdir()
|
|
945
|
+
agents_dir = pf_dir / "agents"
|
|
946
|
+
agents_dir.mkdir()
|
|
947
|
+
(agents_dir / "tea.md").write_text("# TEA Agent\nTest Engineer")
|
|
933
948
|
|
|
934
949
|
# Create workflow YAML
|
|
935
950
|
workflows_dir = tmp_path / "pennyfarthing-dist" / "workflows"
|
|
@@ -1039,6 +1054,9 @@ class TestCLIFlagsV2:
|
|
|
1039
1054
|
|
|
1040
1055
|
pf_dir = tmp_path / ".pennyfarthing"
|
|
1041
1056
|
pf_dir.mkdir()
|
|
1057
|
+
agents_dir = pf_dir / "agents"
|
|
1058
|
+
agents_dir.mkdir()
|
|
1059
|
+
(agents_dir / "sm.md").write_text("# SM Agent\nScrum Master")
|
|
1042
1060
|
|
|
1043
1061
|
with patch("pennyfarthing_scripts.prime.cli.get_project_root", return_value=tmp_path):
|
|
1044
1062
|
result = main(["--agent", "sm", "--session-id", "explicit-123", "--no-workflow"])
|
|
@@ -7,10 +7,7 @@ after reorganization from flat modules.
|
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from
|
|
11
|
-
from unittest.mock import MagicMock, patch
|
|
12
|
-
|
|
13
|
-
import pytest
|
|
10
|
+
from unittest.mock import patch
|
|
14
11
|
|
|
15
12
|
|
|
16
13
|
class TestSprintLoader:
|
|
@@ -28,8 +25,8 @@ class TestSprintLoader:
|
|
|
28
25
|
|
|
29
26
|
def test_load_sprint_with_custom_root(self) -> None:
|
|
30
27
|
"""load_sprint should accept custom project root."""
|
|
31
|
-
from pennyfarthing_scripts.sprint.loader import load_sprint
|
|
32
28
|
from pennyfarthing_scripts.common.config import get_project_root
|
|
29
|
+
from pennyfarthing_scripts.sprint.loader import load_sprint
|
|
33
30
|
|
|
34
31
|
root = get_project_root()
|
|
35
32
|
result = load_sprint(project_root=root)
|
|
@@ -341,8 +338,7 @@ epics:
|
|
|
341
338
|
|
|
342
339
|
def test_get_all_stories_with_shards(self, tmp_path: Path) -> None:
|
|
343
340
|
"""get_all_stories should return stories from merged shards."""
|
|
344
|
-
from pennyfarthing_scripts.sprint.loader import get_all_stories
|
|
345
|
-
from unittest.mock import patch
|
|
341
|
+
from pennyfarthing_scripts.sprint.loader import get_all_stories
|
|
346
342
|
|
|
347
343
|
root = self._create_sharded_sprint(tmp_path)
|
|
348
344
|
|
|
@@ -379,7 +375,6 @@ epics:
|
|
|
379
375
|
def test_backlog_count_defensive_on_strings(self) -> None:
|
|
380
376
|
"""get_backlog_count should not crash on string epics."""
|
|
381
377
|
from pennyfarthing_scripts.prime.workflow import get_backlog_count
|
|
382
|
-
from unittest.mock import patch
|
|
383
378
|
|
|
384
379
|
fake_data = {"epics": ["MSSCI-14298", "MSSCI-14317"]}
|
|
385
380
|
with patch("pennyfarthing_scripts.sprint.loader.load_sprint", return_value=fake_data):
|
|
@@ -19,19 +19,18 @@ from typing import Any
|
|
|
19
19
|
import pytest
|
|
20
20
|
|
|
21
21
|
from pennyfarthing_scripts.sprint.validator import (
|
|
22
|
-
ValidationError,
|
|
23
22
|
ValidationResult,
|
|
24
23
|
ValidationSeverity,
|
|
25
24
|
format_validation_errors,
|
|
26
25
|
validate_archived_sprint,
|
|
27
26
|
validate_epic,
|
|
27
|
+
validate_epic_shard,
|
|
28
28
|
validate_full_sprint,
|
|
29
29
|
validate_sprint,
|
|
30
30
|
validate_sprint_file,
|
|
31
31
|
validate_story,
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
-
|
|
35
34
|
# =============================================================================
|
|
36
35
|
# Test Fixtures - Valid Data
|
|
37
36
|
# =============================================================================
|
|
@@ -239,7 +238,7 @@ class TestStoryValidation:
|
|
|
239
238
|
|
|
240
239
|
def test_all_valid_story_statuses_pass(self) -> None:
|
|
241
240
|
"""All valid status values should pass."""
|
|
242
|
-
valid_statuses = ["backlog", "in_progress", "done", "
|
|
241
|
+
valid_statuses = ["backlog", "ready", "in_progress", "done", "canceled", "planning"]
|
|
243
242
|
|
|
244
243
|
for status in valid_statuses:
|
|
245
244
|
story = {"id": "63-1", "title": "Test", "status": status, "points": 3}
|
|
@@ -364,6 +363,55 @@ class TestEpicValidation:
|
|
|
364
363
|
assert result.valid is False
|
|
365
364
|
assert any("duplicate" in e.message.lower() for e in result.errors)
|
|
366
365
|
|
|
366
|
+
def test_integer_epic_id_fails(self) -> None:
|
|
367
|
+
"""Epic with integer id (YAML bare number) should fail.
|
|
368
|
+
|
|
369
|
+
YAML parses `id: 87` as int. Cyclist's sprint-data.ts calls
|
|
370
|
+
epicId.match() which crashes on non-strings, blanking the panel.
|
|
371
|
+
"""
|
|
372
|
+
epic = {
|
|
373
|
+
"id": 87, # Bare integer — not quoted in YAML
|
|
374
|
+
"title": "Test Epic",
|
|
375
|
+
"stories": [
|
|
376
|
+
{"id": "87-1", "title": "Story 1", "status": "backlog", "points": 2},
|
|
377
|
+
],
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
result = validate_epic(epic, set())
|
|
381
|
+
|
|
382
|
+
assert result.valid is False
|
|
383
|
+
assert any("must be a string" in e.message.lower() for e in result.errors)
|
|
384
|
+
|
|
385
|
+
def test_integer_epic_id_fails_in_shard(self) -> None:
|
|
386
|
+
"""Epic shard with integer id should fail validation."""
|
|
387
|
+
epic = {
|
|
388
|
+
"id": 87,
|
|
389
|
+
"title": "Test Epic",
|
|
390
|
+
"status": "planning",
|
|
391
|
+
"stories": [
|
|
392
|
+
{"id": "87-1", "title": "Story 1", "status": "backlog", "points": 2},
|
|
393
|
+
],
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
result = validate_epic_shard(epic)
|
|
397
|
+
|
|
398
|
+
assert result.valid is False
|
|
399
|
+
assert any("must be a string" in e.message.lower() for e in result.errors)
|
|
400
|
+
|
|
401
|
+
def test_string_epic_id_passes(self) -> None:
|
|
402
|
+
"""Epic with properly quoted string id should pass."""
|
|
403
|
+
epic = {
|
|
404
|
+
"id": "87", # Quoted in YAML — parsed as string
|
|
405
|
+
"title": "Test Epic",
|
|
406
|
+
"stories": [
|
|
407
|
+
{"id": "87-1", "title": "Story 1", "status": "backlog", "points": 2},
|
|
408
|
+
],
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
result = validate_epic(epic, set())
|
|
412
|
+
|
|
413
|
+
assert result.valid is True
|
|
414
|
+
|
|
367
415
|
|
|
368
416
|
# =============================================================================
|
|
369
417
|
# AC4: Clear error messages for validation failures
|
|
@@ -470,7 +518,7 @@ class TestArchivedSprintValidation:
|
|
|
470
518
|
assert result.valid is True
|
|
471
519
|
|
|
472
520
|
def test_archived_sprint_allows_all_done_stories(self) -> None:
|
|
473
|
-
"""Archived sprints should allow all stories to be done/
|
|
521
|
+
"""Archived sprints should allow all stories to be done/canceled."""
|
|
474
522
|
data = {
|
|
475
523
|
"sprint": {
|
|
476
524
|
"number": 11,
|
|
@@ -486,7 +534,7 @@ class TestArchivedSprintValidation:
|
|
|
486
534
|
"title": "Old Epic",
|
|
487
535
|
"stories": [
|
|
488
536
|
{"id": "50-1", "title": "Done Story", "status": "done", "points": 3},
|
|
489
|
-
{"id": "50-2", "title": "
|
|
537
|
+
{"id": "50-2", "title": "Canceled Story", "status": "canceled", "points": 2},
|
|
490
538
|
],
|
|
491
539
|
}
|
|
492
540
|
],
|
|
@@ -15,11 +15,10 @@ Acceptance Criteria:
|
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
17
|
from pathlib import Path
|
|
18
|
-
from typing import Any
|
|
19
18
|
|
|
20
19
|
import pytest
|
|
21
20
|
from click.testing import CliRunner
|
|
22
|
-
from ruamel.yaml.comments import CommentedMap
|
|
21
|
+
from ruamel.yaml.comments import CommentedMap
|
|
23
22
|
|
|
24
23
|
from pennyfarthing_scripts.sprint.story_add import (
|
|
25
24
|
add_story,
|
|
@@ -28,10 +27,8 @@ from pennyfarthing_scripts.sprint.story_add import (
|
|
|
28
27
|
from pennyfarthing_scripts.sprint.yaml_io import (
|
|
29
28
|
STORY_KEY_ORDER,
|
|
30
29
|
read_sprint,
|
|
31
|
-
write_sprint,
|
|
32
30
|
)
|
|
33
31
|
|
|
34
|
-
|
|
35
32
|
# =============================================================================
|
|
36
33
|
# Test Fixtures
|
|
37
34
|
# =============================================================================
|
|
@@ -676,7 +673,6 @@ epics:
|
|
|
676
673
|
"""
|
|
677
674
|
p = tmp_path / "current-sprint.yaml"
|
|
678
675
|
p.write_text(yaml_content)
|
|
679
|
-
original_content = p.read_text()
|
|
680
676
|
|
|
681
677
|
# Normal add should work fine
|
|
682
678
|
result = add_story(
|
|
@@ -699,10 +695,10 @@ class TestCLIIntegration:
|
|
|
699
695
|
|
|
700
696
|
def test_story_add_command_exists(self) -> None:
|
|
701
697
|
"""story_add_command should be importable and be a Click command."""
|
|
702
|
-
from pennyfarthing_scripts.sprint.story_add import story_add_command
|
|
703
|
-
|
|
704
698
|
import click
|
|
705
699
|
|
|
700
|
+
from pennyfarthing_scripts.sprint.story_add import story_add_command
|
|
701
|
+
|
|
706
702
|
assert isinstance(story_add_command, click.BaseCommand)
|
|
707
703
|
|
|
708
704
|
def test_basic_add_via_cli(self, runner: CliRunner, sprint_file: Path) -> None:
|