@pennyfarthing/core 10.1.0 → 10.3.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 +22 -24
- 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 +2 -2
- package/packages/core/dist/cli/commands/e2e-fresh-install.test.js.map +1 -1
- package/packages/core/dist/cli/commands/e2e-upgrade.test.js +2 -2
- 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/theme.js +1 -1
- package/packages/core/dist/cli/commands/theme.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/cli/utils/themes.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/themes.js +3 -2
- package/packages/core/dist/cli/utils/themes.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/add-ocean-profiles.js +1 -1
- package/packages/core/dist/scripts/add-ocean-profiles.js.map +1 -1
- package/packages/core/dist/scripts/generate-all-spiders.js +2 -0
- package/packages/core/dist/scripts/generate-all-spiders.js.map +1 -1
- package/packages/core/dist/scripts/generate-report.d.ts.map +1 -1
- package/packages/core/dist/scripts/generate-report.js +2 -0
- package/packages/core/dist/scripts/generate-report.js.map +1 -1
- package/packages/core/dist/scripts/generate-spider-report.js.map +1 -1
- package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -1
- package/packages/core/dist/scripts/generate-spider.js +2 -0
- package/packages/core/dist/scripts/generate-spider.js.map +1 -1
- package/packages/core/dist/scripts/validate-ocean-profiles.js +1 -1
- package/packages/core/dist/scripts/validate-ocean-profiles.js.map +1 -1
- 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/output-path-normalizer.d.ts +47 -0
- package/packages/core/dist/workflow/output-path-normalizer.d.ts.map +1 -0
- package/packages/core/dist/workflow/output-path-normalizer.js +79 -0
- package/packages/core/dist/workflow/output-path-normalizer.js.map +1 -0
- package/packages/core/dist/workflow/output-path-normalizer.test.d.ts +16 -0
- package/packages/core/dist/workflow/output-path-normalizer.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/output-path-normalizer.test.js +157 -0
- package/packages/core/dist/workflow/output-path-normalizer.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 +717 -0
- package/packages/core/dist/workflow/tool-watch.test.js.map +1 -0
- package/packages/core/dist/workflow/variable-resolver.js +1 -1
- package/packages/core/dist/workflow/variable-resolver.js.map +1 -1
- 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/README.md +3 -1
- package/pennyfarthing-dist/agents/ba.md +165 -0
- 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/ba.md +17 -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/guides/workflow-schema.md +1 -1
- package/pennyfarthing-dist/personas/themes/a-team.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/alice-in-wonderland.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/blade-runner.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/catch-22.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/control.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/cowboy-bebop.yaml +31 -0
- package/pennyfarthing-dist/personas/themes/discworld.yaml +32 -1
- package/pennyfarthing-dist/personas/themes/doctor-who.yaml +31 -0
- package/pennyfarthing-dist/personas/themes/dune.yaml +32 -0
- package/pennyfarthing-dist/personas/themes/fifth-element.yaml +327 -0
- package/pennyfarthing-dist/personas/themes/firefly.yaml +31 -0
- package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/harry-potter.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/lord-of-the-rings.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/mad-max.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/mash.yaml +33 -0
- package/pennyfarthing-dist/personas/themes/princess-bride.yaml +34 -0
- package/pennyfarthing-dist/personas/themes/sandman.yaml +33 -0
- package/pennyfarthing-dist/personas/themes/star-trek-tng.yaml +34 -0
- package/pennyfarthing-dist/personas/themes/star-wars.yaml +33 -0
- package/pennyfarthing-dist/personas/themes/the-expanse.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/the-matrix.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/watchmen.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/west-wing.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/x-files.yaml +30 -0
- package/pennyfarthing-dist/scripts/README.md +1 -1
- package/pennyfarthing-dist/scripts/core/agent-session.sh +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/portraits/generate-portraits.py +2 -2
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +1 -0
- 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/theme/skill.md +1 -1
- package/pennyfarthing-dist/skills/workflow/skill.md +24 -1
- package/pennyfarthing-dist/workflows/architecture/workflow.yaml +65 -0
- package/pennyfarthing-dist/workflows/architecture.yaml +2 -2
- package/pennyfarthing-dist/workflows/bdd-tandem.yaml +70 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/implementation-readiness/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/prd/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/product-brief/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/project-context/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/quick-dev/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/research/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/retrospective/workflow.yaml +1 -1
- package/pennyfarthing-dist/workflows/sprint-planning/workflow.yaml +3 -3
- package/pennyfarthing-dist/workflows/tdd-tandem.yaml +61 -0
- package/pennyfarthing-dist/workflows/ux-design/workflow.yaml +2 -2
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/pretooluse_hook.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/bikerack/__init__.py +36 -0
- package/pennyfarthing_scripts/bikerack/__main__.py +5 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/cli.py +148 -0
- package/pennyfarthing_scripts/bikerack/launcher.py +181 -0
- package/pennyfarthing_scripts/brownfield/__init__.py +6 -6
- package/pennyfarthing_scripts/brownfield/__main__.py +1 -0
- package/pennyfarthing_scripts/brownfield/cli.py +0 -1
- package/pennyfarthing_scripts/brownfield/discover.py +1 -2
- package/pennyfarthing_scripts/cli.py +16 -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/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/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 +452 -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__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/cli.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__/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__/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__/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/__init__.py +2 -0
- 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__/persona.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/cli.py +18 -1
- package/pennyfarthing_scripts/prime/loader.py +72 -3
- package/pennyfarthing_scripts/prime/persona.py +4 -2
- package/pennyfarthing_scripts/prime/tiers.py +17 -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__/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__/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__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_epic_shard_validation.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.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_bikerack.py +785 -0
- 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_topology_loader.py +620 -0
- 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 +291 -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/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
|
@@ -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
|
|
|
@@ -47,6 +47,7 @@ from pennyfarthing_scripts.prime.loader import (
|
|
|
47
47
|
load_agent_definition,
|
|
48
48
|
load_behavior_guide,
|
|
49
49
|
load_domain_docs,
|
|
50
|
+
load_repos_topology,
|
|
50
51
|
load_session_context,
|
|
51
52
|
load_sidecars,
|
|
52
53
|
load_sprint_context,
|
|
@@ -94,6 +95,7 @@ __all__ = [
|
|
|
94
95
|
"load_session_context",
|
|
95
96
|
"load_sidecars",
|
|
96
97
|
"load_domain_docs",
|
|
98
|
+
"load_repos_topology",
|
|
97
99
|
# Workflow detection
|
|
98
100
|
"detect_workflow_state",
|
|
99
101
|
"check_redirect",
|
|
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
|
|
|
@@ -98,6 +102,7 @@ def _component_header(name: str, agent_name: str | None) -> str:
|
|
|
98
102
|
"persona_compressed": f"Persona: {agent_name} (compressed)",
|
|
99
103
|
"behavior_guide": "Agent Behavior Guide",
|
|
100
104
|
"sprint_context": "Sprint Context",
|
|
105
|
+
"repos_topology": "Repos Topology",
|
|
101
106
|
"session_header": "Active Session",
|
|
102
107
|
"session_assessment": "Session Assessment",
|
|
103
108
|
"sidecars": f"Agent Sidecar: {agent_name}",
|
|
@@ -114,6 +119,7 @@ def _component_source(name: str, agent_name: str | None, root: Path) -> str | No
|
|
|
114
119
|
"persona_compressed": None,
|
|
115
120
|
"behavior_guide": ".pennyfarthing/guides/agent-behavior.md",
|
|
116
121
|
"sprint_context": "sprint/current-sprint.yaml",
|
|
122
|
+
"repos_topology": ".pennyfarthing/repos.yaml",
|
|
117
123
|
"session_header": None,
|
|
118
124
|
"session_assessment": None,
|
|
119
125
|
"sidecars": f".pennyfarthing/sidecars/{agent_name}/",
|
|
@@ -470,6 +476,17 @@ def prime(
|
|
|
470
476
|
_print_header("Sprint Context", quiet)
|
|
471
477
|
print(sprint_content)
|
|
472
478
|
|
|
479
|
+
# ==========================================================================
|
|
480
|
+
# PRIORITY 5.5: Repos Topology
|
|
481
|
+
# ==========================================================================
|
|
482
|
+
if not json_output:
|
|
483
|
+
from pennyfarthing_scripts.prime.loader import load_repos_topology
|
|
484
|
+
|
|
485
|
+
topology_content = load_repos_topology(root)
|
|
486
|
+
if topology_content:
|
|
487
|
+
_print_header("Repos Topology", quiet)
|
|
488
|
+
print(topology_content)
|
|
489
|
+
|
|
473
490
|
# ==========================================================================
|
|
474
491
|
# PRIORITY 6: Session context
|
|
475
492
|
# ==========================================================================
|
|
@@ -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)
|
|
@@ -237,3 +236,73 @@ def load_domain_docs(project_root: Path | None = None) -> list[tuple[str, str]]:
|
|
|
237
236
|
docs.append((doc_file.name, doc_file.read_text()))
|
|
238
237
|
|
|
239
238
|
return docs
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def load_repos_topology(project_root: Path | None = None) -> str | None:
|
|
242
|
+
"""Load repos.yaml topology as formatted context for agents.
|
|
243
|
+
|
|
244
|
+
Reads .pennyfarthing/repos.yaml and formats the topology fields
|
|
245
|
+
(owns, never_edit, symlinks, ui_layer, components_path) as a
|
|
246
|
+
readable manifest for agent spatial awareness.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
project_root: Project root path (auto-detected if not provided)
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
Formatted topology context string, or None if unavailable
|
|
253
|
+
"""
|
|
254
|
+
import yaml
|
|
255
|
+
|
|
256
|
+
root = project_root or get_project_root()
|
|
257
|
+
repos_file = root / ".pennyfarthing" / "repos.yaml"
|
|
258
|
+
|
|
259
|
+
if not repos_file.exists():
|
|
260
|
+
return None
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
data = yaml.safe_load(repos_file.read_text())
|
|
264
|
+
except Exception:
|
|
265
|
+
return None
|
|
266
|
+
|
|
267
|
+
if not isinstance(data, dict) or "repos" not in data:
|
|
268
|
+
return None
|
|
269
|
+
|
|
270
|
+
repos = data["repos"]
|
|
271
|
+
if not repos:
|
|
272
|
+
return None
|
|
273
|
+
|
|
274
|
+
lines: list[str] = []
|
|
275
|
+
for name, config in repos.items():
|
|
276
|
+
lines.append(f"## {name}")
|
|
277
|
+
if config.get("path"):
|
|
278
|
+
lines.append(f"Path: {config['path']}")
|
|
279
|
+
if config.get("type"):
|
|
280
|
+
lines.append(f"Type: {config['type']}")
|
|
281
|
+
if config.get("description"):
|
|
282
|
+
lines.append(f"Description: {config['description']}")
|
|
283
|
+
|
|
284
|
+
owns = config.get("owns", [])
|
|
285
|
+
if owns:
|
|
286
|
+
lines.append(f"Owns: {', '.join(owns)}")
|
|
287
|
+
|
|
288
|
+
never_edit = config.get("never_edit", [])
|
|
289
|
+
if never_edit:
|
|
290
|
+
lines.append(f"Never Edit: {', '.join(never_edit)}")
|
|
291
|
+
|
|
292
|
+
symlinks = config.get("symlinks", {})
|
|
293
|
+
if symlinks:
|
|
294
|
+
lines.append("Symlinks:")
|
|
295
|
+
for src, dest in symlinks.items():
|
|
296
|
+
lines.append(f" {src} → {dest}")
|
|
297
|
+
|
|
298
|
+
ui_layer = config.get("ui_layer")
|
|
299
|
+
if ui_layer:
|
|
300
|
+
lines.append(f"UI Layer: {ui_layer}")
|
|
301
|
+
|
|
302
|
+
components_path = config.get("components_path")
|
|
303
|
+
if components_path:
|
|
304
|
+
lines.append(f"Components: {components_path}")
|
|
305
|
+
|
|
306
|
+
lines.append("")
|
|
307
|
+
|
|
308
|
+
return "\n".join(lines).strip() if lines else None
|
|
@@ -14,15 +14,17 @@ 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",
|
|
25
26
|
"pm", "tech-writer", "ux-designer", "devops", "orchestrator",
|
|
27
|
+
"ba",
|
|
26
28
|
]
|
|
27
29
|
|
|
28
30
|
|
|
@@ -128,7 +130,7 @@ def get_crew_manifest(project_root: Path | None = None) -> list[CrewMember]:
|
|
|
128
130
|
project_root: Project root path (auto-detected if not provided)
|
|
129
131
|
|
|
130
132
|
Returns:
|
|
131
|
-
List of CrewMember objects for all
|
|
133
|
+
List of CrewMember objects for all 11 standard roles
|
|
132
134
|
"""
|
|
133
135
|
root = project_root or get_project_root()
|
|
134
136
|
theme = get_current_theme(root)
|
|
@@ -35,21 +35,22 @@ 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
|
+
load_repos_topology,
|
|
41
42
|
load_session_context,
|
|
42
43
|
load_sidecars,
|
|
43
44
|
load_sprint_context,
|
|
44
45
|
)
|
|
45
|
-
from pennyfarthing_scripts.prime.persona import (
|
|
46
|
+
from pennyfarthing_scripts.prime.persona import ( # noqa: E402
|
|
46
47
|
format_persona_compressed,
|
|
47
48
|
get_crew_manifest,
|
|
48
49
|
get_user_title,
|
|
49
50
|
is_character_voice_enabled,
|
|
50
51
|
load_persona,
|
|
51
52
|
)
|
|
52
|
-
from pennyfarthing_scripts.prime.workflow import detect_workflow_state
|
|
53
|
+
from pennyfarthing_scripts.prime.workflow import detect_workflow_state # noqa: E402
|
|
53
54
|
|
|
54
55
|
|
|
55
56
|
class ContextTier(Enum):
|
|
@@ -78,7 +79,7 @@ def tier_from_string(value: str) -> ContextTier:
|
|
|
78
79
|
return ContextTier(normalized)
|
|
79
80
|
except ValueError:
|
|
80
81
|
valid = ", ".join(t.value for t in ContextTier)
|
|
81
|
-
raise ValueError(f"Invalid tier '{value}'. Must be one of: {valid}")
|
|
82
|
+
raise ValueError(f"Invalid tier '{value}'. Must be one of: {valid}") from None
|
|
82
83
|
|
|
83
84
|
|
|
84
85
|
def load_tier_components(
|
|
@@ -134,6 +135,10 @@ def load_tier_components(
|
|
|
134
135
|
if sprint_content:
|
|
135
136
|
add_component("sprint_context", sprint_content)
|
|
136
137
|
|
|
138
|
+
topology_content = load_repos_topology(project_root)
|
|
139
|
+
if topology_content:
|
|
140
|
+
add_component("repos_topology", topology_content)
|
|
141
|
+
|
|
137
142
|
session_result = load_session_context(project_root)
|
|
138
143
|
if session_result:
|
|
139
144
|
filename, header, _ = session_result
|
|
@@ -156,6 +161,10 @@ def load_tier_components(
|
|
|
156
161
|
compressed = format_persona_compressed(persona, theme, agent_name)
|
|
157
162
|
add_component("persona_compressed", compressed)
|
|
158
163
|
|
|
164
|
+
topology_content = load_repos_topology(project_root)
|
|
165
|
+
if topology_content:
|
|
166
|
+
add_component("repos_topology", topology_content)
|
|
167
|
+
|
|
159
168
|
components["token_counts"] = token_counts
|
|
160
169
|
components["total_tokens"] = sum(token_counts.values())
|
|
161
170
|
return components
|
|
@@ -185,6 +194,10 @@ def load_tier_components(
|
|
|
185
194
|
if sprint_content:
|
|
186
195
|
add_component("sprint_context", sprint_content)
|
|
187
196
|
|
|
197
|
+
topology_content = load_repos_topology(project_root)
|
|
198
|
+
if topology_content:
|
|
199
|
+
add_component("repos_topology", topology_content)
|
|
200
|
+
|
|
188
201
|
session_result = load_session_context(project_root)
|
|
189
202
|
if session_result:
|
|
190
203
|
filename, header, assessment = session_result
|
|
@@ -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
|
|
@@ -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"
|