@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
|
@@ -293,7 +293,7 @@ pf sprint story add <epic-id> "<title>" <points> [options]
|
|
|
293
293
|
| `points` | Yes | Story points (1, 2, 3, 5, 8) |
|
|
294
294
|
| `--type` | No | Story type: feature, bug, chore, refactor (default: feature) |
|
|
295
295
|
| `--priority` | No | Priority: P0, P1, P2, P3 (default: P1) |
|
|
296
|
-
| `--workflow` | No | Workflow: tdd, trivial, bdd (default: tdd) |
|
|
296
|
+
| `--workflow` | No | Workflow: tdd, tdd-tandem, trivial, bdd, bdd-tandem (default: tdd) |
|
|
297
297
|
| `--jira` | No | Jira issue key |
|
|
298
298
|
</args>
|
|
299
299
|
|
|
@@ -399,6 +399,28 @@ pf sprint story claim <story-id>
|
|
|
399
399
|
|
|
400
400
|
---
|
|
401
401
|
|
|
402
|
+
### `/sprint story assign <story-id> <assignee>`
|
|
403
|
+
|
|
404
|
+
Assign a Jira story to a user. Shortcut for `/jira assign`.
|
|
405
|
+
|
|
406
|
+
<run>
|
|
407
|
+
pf jira assign <story-id> <assignee>
|
|
408
|
+
</run>
|
|
409
|
+
|
|
410
|
+
<args>
|
|
411
|
+
| Arg | Required | Description |
|
|
412
|
+
|-----|----------|-------------|
|
|
413
|
+
| `story-id` | Yes | Jira key (e.g., `MSSCI-14552`) |
|
|
414
|
+
| `assignee` | Yes | Email or GitHub username (e.g., `keith.avery@1898andco.io`, `slabgorb`) |
|
|
415
|
+
</args>
|
|
416
|
+
|
|
417
|
+
<example>
|
|
418
|
+
pf jira assign MSSCI-14552 keith.avery@1898andco.io
|
|
419
|
+
pf jira assign MSSCI-14552 slabgorb
|
|
420
|
+
</example>
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
402
424
|
### `/sprint epic add <epic-id> <title> [options]`
|
|
403
425
|
|
|
404
426
|
Add a new epic to the current sprint.
|
|
@@ -696,7 +718,7 @@ All gates must pass before handoff:
|
|
|
696
718
|
| Sprint name | `"TO Sprint YYWW"` (e.g., "TO Sprint 2604") |
|
|
697
719
|
| Story IDs | Jira keys `MSSCI-XXXXX` |
|
|
698
720
|
| Status | `backlog`, `ready`, `in_progress`, `done` |
|
|
699
|
-
| Workflow | `tdd`, `trivial`, `agent-docs`, `bdd` |
|
|
721
|
+
| Workflow | `tdd`, `tdd-tandem`, `trivial`, `agent-docs`, `bdd`, `bdd-tandem` |
|
|
700
722
|
| Priority | `P0`, `P1`, `P2`, `P3` |
|
|
701
723
|
| in_sprint | `true`, `false` - Jira sprint membership |
|
|
702
724
|
|
|
@@ -761,6 +783,7 @@ For Jira integration, see `/jira` skill prerequisites.
|
|
|
761
783
|
| `/sprint story template` | `pf sprint story template` |
|
|
762
784
|
| `/sprint story finish ID` | `pf sprint story finish ID` |
|
|
763
785
|
| `/sprint story claim ID` | `pf sprint story claim ID` |
|
|
786
|
+
| `/sprint story assign ID USER` | `pf jira assign ID USER` |
|
|
764
787
|
| `/sprint epic show ID` | `pf sprint epic show ID` |
|
|
765
788
|
| `/sprint epic field ID FIELD` | `pf sprint epic field ID FIELD` |
|
|
766
789
|
| `/sprint epic add ...` | `pf sprint epic add ...` |
|
|
@@ -163,6 +163,18 @@ SM → TEA → Dev → Reviewer → SM
|
|
|
163
163
|
- Dev implements to make tests pass
|
|
164
164
|
- **Triggers:** `types: [feature, enhancement]`, `points.min: 3`
|
|
165
165
|
|
|
166
|
+
### TDD-Tandem (TDD with full tandem chain)
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
setup → red (+Architect) → green (+TEA) → review (+PM) → finish
|
|
170
|
+
SM → TEA (+Architect) → Dev (+TEA) → Reviewer (+PM) → SM
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
- Full tandem chain: every phase has a backseat observer
|
|
174
|
+
- Architect watches test design, TEA watches implementation, PM watches review
|
|
175
|
+
- For high-stakes features needing cross-role visibility
|
|
176
|
+
- **Triggers:** `tags: [tandem]`, `points.min: 3`
|
|
177
|
+
|
|
166
178
|
### Trivial (for 1-2 point fixes)
|
|
167
179
|
|
|
168
180
|
```
|
|
@@ -196,6 +208,17 @@ SM → UX-Designer → TEA → Dev → Reviewer → SM
|
|
|
196
208
|
- For UI components and user-facing features
|
|
197
209
|
- **Triggers:** `types: [ui, ux, behavior]`, `tags: [bdd, ux-first]`
|
|
198
210
|
|
|
211
|
+
### BDD-Tandem (BDD with full tandem chain)
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
setup → design (+Architect) → red → green (+UX-Designer) → review (+PM) → finish
|
|
215
|
+
SM → UX-Designer (+Architect) → TEA → Dev (+UX-Designer) → Reviewer (+PM) → SM
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
- Full tandem chain: Architect watches design, UX-Designer watches implementation, PM watches review
|
|
219
|
+
- Everyone shares their cake — cross-role visibility at every phase
|
|
220
|
+
- **Triggers:** `tags: [bdd-tandem, tandem, ux-first]`, `points.min: 3`
|
|
221
|
+
|
|
199
222
|
### Architecture (stepped workflow)
|
|
200
223
|
|
|
201
224
|
```
|
|
@@ -341,5 +364,5 @@ workflow:
|
|
|
341
364
|
For comprehensive documentation on creating stepped workflows, see:
|
|
342
365
|
|
|
343
366
|
- **[guides/bikelane.md](../../guides/bikelane.md)** - Full BikeLane user guide
|
|
344
|
-
- **
|
|
367
|
+
- **ADR-0013: Stepped Workflow Support** - Technical ADR (see `docs/adr/0013-bmad-workflow-import.md` in framework repo)
|
|
345
368
|
- **[pennyfarthing-dist/workflows/architecture.yaml](../../workflows/architecture.yaml)** - Example implementation
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Architecture Workflow - Migrated from BMAD format
|
|
2
|
+
# Collaborative architectural decision-making with progressive disclosure
|
|
3
|
+
#
|
|
4
|
+
# Flow: Initialize → [Continue?] → Context → Patterns → Components → Interfaces → Risks → Document
|
|
5
|
+
# Use for architectural decisions, system design, and technical planning
|
|
6
|
+
#
|
|
7
|
+
# BMAD Enhancements:
|
|
8
|
+
# - Continuation handler (step-01b) for resuming workflows
|
|
9
|
+
# - A/P/C menus: Advanced Elicitation, Party Mode, Continue
|
|
10
|
+
# - Web search integration for current technology versions
|
|
11
|
+
# - AI agent consistency focus in component and risk steps
|
|
12
|
+
# - Pre-documentation validation checks
|
|
13
|
+
|
|
14
|
+
workflow:
|
|
15
|
+
name: architecture
|
|
16
|
+
description: Collaborative architectural decision facilitation for AI-agent consistency. Produces a decision-focused architecture document optimized for preventing agent conflicts through step-by-step discovery with A/P/C collaboration menus.
|
|
17
|
+
version: "2.0.0"
|
|
18
|
+
type: stepped
|
|
19
|
+
|
|
20
|
+
# Step configuration
|
|
21
|
+
steps:
|
|
22
|
+
path: ./steps/
|
|
23
|
+
pattern: step-{nn}-*.md
|
|
24
|
+
# Note: step-01b-continue.md is loaded conditionally by step-01 when existing workflow detected
|
|
25
|
+
|
|
26
|
+
# Variables available in step files
|
|
27
|
+
variables:
|
|
28
|
+
project_root: .
|
|
29
|
+
planning_artifacts: ./artifacts
|
|
30
|
+
output_file: artifacts/architecture.md
|
|
31
|
+
input_required:
|
|
32
|
+
- prd
|
|
33
|
+
|
|
34
|
+
# User approval gates - pause for confirmation at key decision points
|
|
35
|
+
# Steps with A/P/C menus naturally pause; these are the formal gates
|
|
36
|
+
gates:
|
|
37
|
+
after_steps: [2, 4, 6]
|
|
38
|
+
gate_marker: "<!-- GATE -->"
|
|
39
|
+
|
|
40
|
+
# Collaboration menus available in steps
|
|
41
|
+
collaboration:
|
|
42
|
+
menus:
|
|
43
|
+
- key: A
|
|
44
|
+
name: Advanced Elicitation
|
|
45
|
+
description: Use discovery protocols to develop deeper insights
|
|
46
|
+
- key: P
|
|
47
|
+
name: Party Mode
|
|
48
|
+
description: Bring multiple perspectives to analyze from different angles
|
|
49
|
+
- key: C
|
|
50
|
+
name: Continue
|
|
51
|
+
description: Save content and proceed to next step
|
|
52
|
+
- key: R
|
|
53
|
+
name: Revise
|
|
54
|
+
description: Need to gather more information or make changes
|
|
55
|
+
|
|
56
|
+
# Output template
|
|
57
|
+
template: ./templates/architecture-decision.md
|
|
58
|
+
|
|
59
|
+
# Agent assignment
|
|
60
|
+
agent: architect
|
|
61
|
+
|
|
62
|
+
# Triggers - when to suggest this workflow
|
|
63
|
+
triggers:
|
|
64
|
+
types: [architecture, design, adr, system-design]
|
|
65
|
+
tags: [architecture, stepped]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# BDD Tandem Workflow - BDD with Full Tandem Chain
|
|
2
|
+
# Extends standard BDD with tandem observers:
|
|
3
|
+
# - Architect backseats UX-Designer during design
|
|
4
|
+
# - UX-Designer backseats Dev during implementation
|
|
5
|
+
# - PM backseats Reviewer during review
|
|
6
|
+
#
|
|
7
|
+
# Flow: SM → UX-Designer (+Architect) → TEA → Dev (+UX-Designer) → Reviewer (+PM) → SM
|
|
8
|
+
|
|
9
|
+
workflow:
|
|
10
|
+
name: bdd-tandem
|
|
11
|
+
description: BDD with full tandem chain across design, implementation, and review
|
|
12
|
+
version: "1.0.0"
|
|
13
|
+
|
|
14
|
+
phases:
|
|
15
|
+
- name: setup
|
|
16
|
+
agent: sm
|
|
17
|
+
output: [session_file, branches, story_context]
|
|
18
|
+
|
|
19
|
+
- name: design
|
|
20
|
+
agent: ux-designer
|
|
21
|
+
input: [session_file, story_context]
|
|
22
|
+
output: [design_spec, user_flows, wireframes, behavior_scenarios]
|
|
23
|
+
gate:
|
|
24
|
+
type: design_review
|
|
25
|
+
condition: UX spec defines user flows and acceptance behaviors
|
|
26
|
+
tandem:
|
|
27
|
+
partner: architect
|
|
28
|
+
scope: file-watch
|
|
29
|
+
|
|
30
|
+
- name: red
|
|
31
|
+
agent: tea
|
|
32
|
+
input: [design_spec, behavior_scenarios, story_context]
|
|
33
|
+
output: [failing_tests]
|
|
34
|
+
gate:
|
|
35
|
+
type: tests_fail
|
|
36
|
+
condition: Behavior scenarios have test coverage
|
|
37
|
+
|
|
38
|
+
- name: green
|
|
39
|
+
agent: dev
|
|
40
|
+
input: [failing_tests, design_spec, story_context]
|
|
41
|
+
output: [implementation, passing_tests]
|
|
42
|
+
gate:
|
|
43
|
+
type: tests_pass
|
|
44
|
+
condition: All tests passing, UX spec implemented
|
|
45
|
+
tandem:
|
|
46
|
+
partner: ux-designer
|
|
47
|
+
scope: file-watch
|
|
48
|
+
|
|
49
|
+
- name: review
|
|
50
|
+
agent: reviewer
|
|
51
|
+
input: [implementation, passing_tests, design_spec]
|
|
52
|
+
output: [approval]
|
|
53
|
+
gate:
|
|
54
|
+
type: approval
|
|
55
|
+
condition: Code review approved, UX requirements met
|
|
56
|
+
tandem:
|
|
57
|
+
partner: pm
|
|
58
|
+
scope: file-watch
|
|
59
|
+
|
|
60
|
+
- name: finish
|
|
61
|
+
agent: sm
|
|
62
|
+
input: [approval]
|
|
63
|
+
output: [archived_session, story_summary]
|
|
64
|
+
|
|
65
|
+
triggers:
|
|
66
|
+
types: [ui, ux, behavior, component, settings]
|
|
67
|
+
tags: [bdd-tandem, tandem, ux-first]
|
|
68
|
+
points:
|
|
69
|
+
min: 3
|
|
70
|
+
default: false
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# TDD Tandem Workflow - TDD with Full Tandem Chain
|
|
2
|
+
# Extends standard TDD with tandem observers on every phase:
|
|
3
|
+
# - Architect backseats TEA during red phase
|
|
4
|
+
# - TEA backseats Dev during green phase
|
|
5
|
+
# - PM backseats Reviewer during review phase
|
|
6
|
+
#
|
|
7
|
+
# Flow: SM → TEA (+Architect) → Dev (+TEA) → Reviewer (+PM) → SM
|
|
8
|
+
|
|
9
|
+
workflow:
|
|
10
|
+
name: tdd-tandem
|
|
11
|
+
description: TDD with full tandem chain across all phases
|
|
12
|
+
version: "2.0.0"
|
|
13
|
+
|
|
14
|
+
phases:
|
|
15
|
+
- name: setup
|
|
16
|
+
agent: sm
|
|
17
|
+
output: [session_file, branches, story_context]
|
|
18
|
+
|
|
19
|
+
- name: red
|
|
20
|
+
agent: tea
|
|
21
|
+
input: [session_file, story_context]
|
|
22
|
+
output: [failing_tests]
|
|
23
|
+
gate:
|
|
24
|
+
type: tests_fail
|
|
25
|
+
condition: All acceptance criteria have test coverage
|
|
26
|
+
tandem:
|
|
27
|
+
partner: architect
|
|
28
|
+
scope: file-watch
|
|
29
|
+
|
|
30
|
+
- name: green
|
|
31
|
+
agent: dev
|
|
32
|
+
input: [failing_tests, story_context]
|
|
33
|
+
output: [implementation, passing_tests]
|
|
34
|
+
gate:
|
|
35
|
+
type: tests_pass
|
|
36
|
+
condition: All tests passing, no skipped tests
|
|
37
|
+
tandem:
|
|
38
|
+
partner: tea
|
|
39
|
+
scope: file-watch
|
|
40
|
+
|
|
41
|
+
- name: review
|
|
42
|
+
agent: reviewer
|
|
43
|
+
input: [implementation, passing_tests]
|
|
44
|
+
output: [approval]
|
|
45
|
+
gate:
|
|
46
|
+
type: approval
|
|
47
|
+
condition: Code review approved, no blocking issues
|
|
48
|
+
tandem:
|
|
49
|
+
partner: pm
|
|
50
|
+
scope: file-watch
|
|
51
|
+
|
|
52
|
+
- name: finish
|
|
53
|
+
agent: sm
|
|
54
|
+
input: [approval]
|
|
55
|
+
output: [archived_session, story_summary]
|
|
56
|
+
|
|
57
|
+
triggers:
|
|
58
|
+
tags: [tandem]
|
|
59
|
+
points:
|
|
60
|
+
min: 3
|
|
61
|
+
default: false
|
|
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
|
|
@@ -1,30 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""
|
|
3
|
-
Bell Mode
|
|
3
|
+
PostToolUse Hook — Bell Mode + Tandem Injection (Python)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
the first queued message as additionalContext to be injected into
|
|
8
|
-
Claude's next API call.
|
|
5
|
+
Called by Claude Code after each tool execution. Handles two independent
|
|
6
|
+
injection systems:
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
1. Bell queue (Cyclist only) — injects queued user messages when Cyclist
|
|
9
|
+
is running and bell_mode is enabled. In CLI sessions this is a no-op.
|
|
10
|
+
2. Tandem observations (always active) — injects backseat agent observations
|
|
11
|
+
when tandem observation files exist. No configuration required.
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"hookSpecificOutput": {
|
|
17
|
-
"hookEventName": "PostToolUse",
|
|
18
|
-
"additionalContext": "User feedback: <message>"
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
Output when disabled or queue empty: (nothing - exit 0)
|
|
13
|
+
Bell queue takes precedence: if a queued message exists, tandem is
|
|
14
|
+
deferred to the next hook invocation.
|
|
23
15
|
|
|
24
16
|
Story: MSSCI-12409 - Hook consistency and WheelHub consolidation
|
|
25
17
|
"""
|
|
26
18
|
|
|
27
19
|
import json
|
|
20
|
+
import re
|
|
28
21
|
import sys
|
|
29
22
|
from pathlib import Path
|
|
30
23
|
|
|
@@ -32,12 +25,13 @@ from pathlib import Path
|
|
|
32
25
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
33
26
|
|
|
34
27
|
from hooks import (
|
|
35
|
-
|
|
36
|
-
get_cyclist_port,
|
|
37
|
-
send_to_cyclist,
|
|
38
|
-
output_hook_response,
|
|
28
|
+
CYCLIST_PORT_FILE,
|
|
39
29
|
HookResponse,
|
|
30
|
+
find_project_root,
|
|
40
31
|
is_bell_mode_enabled,
|
|
32
|
+
output_hook_response,
|
|
33
|
+
read_port_file,
|
|
34
|
+
send_to_cyclist,
|
|
41
35
|
)
|
|
42
36
|
|
|
43
37
|
|
|
@@ -106,8 +100,170 @@ def notify_cyclist(project_root: Path, message_text: str) -> None:
|
|
|
106
100
|
pass
|
|
107
101
|
|
|
108
102
|
|
|
103
|
+
# =============================================================================
|
|
104
|
+
# Tandem Observation Injection (Story 95-7 / MSSCI-14672)
|
|
105
|
+
# =============================================================================
|
|
106
|
+
# Stubs for tandem observation injection. Dev will implement.
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def read_tandem_observations(project_root: Path) -> list[Path]:
|
|
110
|
+
"""Find tandem observation files in .session/ directory.
|
|
111
|
+
|
|
112
|
+
Looks for files matching .session/*-tandem-*.md pattern.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
project_root: Project root directory
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
List of Path objects for tandem observation files
|
|
119
|
+
"""
|
|
120
|
+
session_dir = project_root / ".session"
|
|
121
|
+
if not session_dir.is_dir():
|
|
122
|
+
return []
|
|
123
|
+
return sorted(session_dir.glob("*-tandem-*.md"))
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def get_latest_observation(file_content: str) -> dict | None:
|
|
127
|
+
"""Extract the latest observation entry from a tandem observation file.
|
|
128
|
+
|
|
129
|
+
Parses the markdown format to extract the most recent ## [HH:MM] Observation
|
|
130
|
+
block, including the observer persona name from the file header.
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
file_content: Full text content of the tandem observation file
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Dict with 'persona' and 'text' keys, or None if no observations found
|
|
137
|
+
"""
|
|
138
|
+
# Extract persona from header: **Observer:** agent (Persona Name)
|
|
139
|
+
persona_match = re.search(r"\*\*Observer:\*\*\s*\w+\s*\(([^)]+)\)", file_content)
|
|
140
|
+
persona = persona_match.group(1) if persona_match else "Unknown"
|
|
141
|
+
|
|
142
|
+
# Split on observation headers: ## [HH:MM] Observation
|
|
143
|
+
entries = re.split(r"## \[\d{1,2}:\d{2}\] Observation\n", file_content)
|
|
144
|
+
if len(entries) < 2:
|
|
145
|
+
return None
|
|
146
|
+
|
|
147
|
+
# Last entry is the most recent observation
|
|
148
|
+
last_entry = entries[-1].strip()
|
|
149
|
+
# Remove trailing --- separator
|
|
150
|
+
last_entry = re.sub(r"\n---\s*$", "", last_entry).strip()
|
|
151
|
+
# Remove the **Trigger:** line
|
|
152
|
+
lines = last_entry.split("\n")
|
|
153
|
+
text_lines = [l for l in lines if not l.startswith("**Trigger:**")]
|
|
154
|
+
text = "\n".join(text_lines).strip()
|
|
155
|
+
|
|
156
|
+
if not text:
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
return {"persona": persona, "text": text}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def format_tandem_message(persona_name: str, observation_text: str) -> str:
|
|
163
|
+
"""Format a tandem observation as a bell mode injection message.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
persona_name: The backseat agent's persona name
|
|
167
|
+
observation_text: The observation summary text
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Formatted string: [Tandem] {persona_name}: {observation_text}
|
|
171
|
+
"""
|
|
172
|
+
return f"[Tandem] {persona_name}: {observation_text}"
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def get_tandem_mtime(project_root: Path, agent: str) -> float:
|
|
176
|
+
"""Read the last-checked mtime for a tandem agent's observation file.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
project_root: Project root directory
|
|
180
|
+
agent: Agent name (e.g. 'reviewer', 'tea')
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
Last-checked mtime as float, or 0.0 if no sidecar exists
|
|
184
|
+
"""
|
|
185
|
+
sidecar = project_root / ".session" / f".tandem-mtime-{agent}"
|
|
186
|
+
if not sidecar.exists():
|
|
187
|
+
return 0.0
|
|
188
|
+
try:
|
|
189
|
+
return float(sidecar.read_text().strip())
|
|
190
|
+
except (ValueError, OSError):
|
|
191
|
+
return 0.0
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def save_tandem_mtime(project_root: Path, agent: str, mtime: float) -> None:
|
|
195
|
+
"""Save the mtime for a tandem agent's observation file.
|
|
196
|
+
|
|
197
|
+
Writes to .session/.tandem-mtime-{agent} sidecar file.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
project_root: Project root directory
|
|
201
|
+
agent: Agent name (e.g. 'reviewer', 'tea')
|
|
202
|
+
mtime: The mtime value to save
|
|
203
|
+
"""
|
|
204
|
+
sidecar = project_root / ".session" / f".tandem-mtime-{agent}"
|
|
205
|
+
try:
|
|
206
|
+
sidecar.write_text(str(mtime))
|
|
207
|
+
except OSError:
|
|
208
|
+
pass
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def check_tandem_files(project_root: Path) -> list[dict]:
|
|
212
|
+
"""Check for new tandem observations and return injection messages.
|
|
213
|
+
|
|
214
|
+
Main entry point for tandem injection in the PostToolUse hook.
|
|
215
|
+
Always active — no configuration required. The presence of tandem
|
|
216
|
+
observation files in .session/ is the only signal needed.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
project_root: Project root directory
|
|
220
|
+
|
|
221
|
+
Returns:
|
|
222
|
+
List of dicts with 'agent', 'message' keys for each new observation
|
|
223
|
+
"""
|
|
224
|
+
tandem_files = read_tandem_observations(project_root)
|
|
225
|
+
if not tandem_files:
|
|
226
|
+
return []
|
|
227
|
+
|
|
228
|
+
results = []
|
|
229
|
+
for obs_file in tandem_files:
|
|
230
|
+
# Extract agent name from filename: *-tandem-{agent}.md
|
|
231
|
+
agent_match = re.search(r"-tandem-(\w+)\.md$", obs_file.name)
|
|
232
|
+
if not agent_match:
|
|
233
|
+
continue
|
|
234
|
+
agent = agent_match.group(1)
|
|
235
|
+
|
|
236
|
+
# Compare mtime
|
|
237
|
+
try:
|
|
238
|
+
file_mtime = obs_file.stat().st_mtime
|
|
239
|
+
except OSError:
|
|
240
|
+
continue
|
|
241
|
+
saved_mtime = get_tandem_mtime(project_root, agent)
|
|
242
|
+
if file_mtime == saved_mtime:
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
# Read and parse
|
|
246
|
+
try:
|
|
247
|
+
content = obs_file.read_text()
|
|
248
|
+
except OSError:
|
|
249
|
+
continue
|
|
250
|
+
obs = get_latest_observation(content)
|
|
251
|
+
if not obs:
|
|
252
|
+
# Update mtime even for unparseable files to avoid re-checking
|
|
253
|
+
save_tandem_mtime(project_root, agent, file_mtime)
|
|
254
|
+
continue
|
|
255
|
+
|
|
256
|
+
message = format_tandem_message(obs["persona"], obs["text"])
|
|
257
|
+
results.append({"agent": agent, "message": message})
|
|
258
|
+
|
|
259
|
+
# Update mtime sidecar
|
|
260
|
+
save_tandem_mtime(project_root, agent, file_mtime)
|
|
261
|
+
|
|
262
|
+
return results
|
|
263
|
+
|
|
264
|
+
|
|
109
265
|
def main() -> None:
|
|
110
|
-
"""Main entry point for PostToolUse
|
|
266
|
+
"""Main entry point for PostToolUse hook."""
|
|
111
267
|
try:
|
|
112
268
|
# Read and discard stdin (required by hook protocol)
|
|
113
269
|
sys.stdin.read()
|
|
@@ -117,35 +273,34 @@ def main() -> None:
|
|
|
117
273
|
if not project_root:
|
|
118
274
|
sys.exit(0)
|
|
119
275
|
|
|
120
|
-
#
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
276
|
+
# --- Bell queue (Cyclist only, requires bell_mode: true) ---
|
|
277
|
+
# Takes precedence over tandem when active.
|
|
278
|
+
is_cyclist = read_port_file(CYCLIST_PORT_FILE, project_root) is not None
|
|
279
|
+
if is_cyclist and is_bell_mode_enabled(project_root):
|
|
280
|
+
queue = read_bell_queue(project_root)
|
|
281
|
+
if queue:
|
|
282
|
+
first_message = queue[0]
|
|
283
|
+
message_text = first_message.get("text", "")
|
|
284
|
+
if message_text:
|
|
285
|
+
output_hook_response(HookResponse(
|
|
286
|
+
event_name="PostToolUse",
|
|
287
|
+
additional_context=f"User feedback: {message_text}",
|
|
288
|
+
))
|
|
289
|
+
dequeue_message(project_root)
|
|
290
|
+
notify_cyclist(project_root, message_text)
|
|
291
|
+
sys.exit(0)
|
|
292
|
+
|
|
293
|
+
# --- Tandem observations (always active, no config required) ---
|
|
294
|
+
tandem_results = check_tandem_files(project_root)
|
|
295
|
+
if tandem_results:
|
|
296
|
+
output_hook_response(HookResponse(
|
|
297
|
+
event_name="PostToolUse",
|
|
298
|
+
additional_context=tandem_results[0]["message"],
|
|
299
|
+
))
|
|
144
300
|
|
|
145
301
|
sys.exit(0)
|
|
146
302
|
|
|
147
303
|
except Exception as e:
|
|
148
|
-
# On error, exit silently
|
|
149
304
|
print(f"[bellmode-hook] Error: {e}", file=sys.stderr)
|
|
150
305
|
sys.exit(0)
|
|
151
306
|
|
|
@@ -6,17 +6,17 @@ Analyzes existing codebases and generates AI-ready documentation.
|
|
|
6
6
|
|
|
7
7
|
from pennyfarthing_scripts.brownfield.discover import (
|
|
8
8
|
DepthLevel,
|
|
9
|
-
ProjectType,
|
|
10
9
|
DiscoveryResult,
|
|
10
|
+
ProjectType,
|
|
11
|
+
detect_architecture_patterns,
|
|
11
12
|
detect_project_type,
|
|
12
13
|
detect_tech_stack,
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
discover,
|
|
15
|
+
generate_ai_guidance_doc,
|
|
15
16
|
generate_project_overview,
|
|
16
|
-
generate_tech_stack_doc,
|
|
17
17
|
generate_source_tree_doc,
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
generate_tech_stack_doc,
|
|
19
|
+
scan_directory_structure,
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
__all__ = [
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|