@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
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Story 95-2: Backseat Agent Spawn and Lifecycle
|
|
3
|
+
*
|
|
4
|
+
* RED state tests for tandem backseat agent lifecycle in phased workflows.
|
|
5
|
+
* These tests cover all 5 acceptance criteria:
|
|
6
|
+
*
|
|
7
|
+
* AC1: BikeLane spawns backseat agent at tandem phase start
|
|
8
|
+
* AC2: BikeLane terminates backseat agent at phase end
|
|
9
|
+
* AC3: Zero orphan processes (NFR8)
|
|
10
|
+
* AC4: Primary agent continues if backseat crashes (NFR10)
|
|
11
|
+
* AC5: Backward compatible (no tandem = no change)
|
|
12
|
+
*
|
|
13
|
+
* Run with: npm test
|
|
14
|
+
*/
|
|
15
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
16
|
+
import assert from 'node:assert';
|
|
17
|
+
import { mkdirSync, rmSync, existsSync } from 'node:fs';
|
|
18
|
+
import { join, dirname } from 'node:path';
|
|
19
|
+
import { fileURLToPath } from 'node:url';
|
|
20
|
+
// Import tandem lifecycle functions
|
|
21
|
+
import { spawnBackseat, terminateBackseat, getActiveBackseat, registerCleanupHandler, executeCleanupHandlers, _resetForTesting, } from './tandem-lifecycle.js';
|
|
22
|
+
// Get directory for test fixtures
|
|
23
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
24
|
+
const TEST_DIR = join(__dirname, '__test_tandem_lifecycle__');
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// Test Fixtures
|
|
27
|
+
// =============================================================================
|
|
28
|
+
/** Phase with tandem config (file-watch scope) */
|
|
29
|
+
const PHASE_WITH_TANDEM = {
|
|
30
|
+
name: 'implement',
|
|
31
|
+
agent: 'dev',
|
|
32
|
+
tandem: {
|
|
33
|
+
partner: 'architect',
|
|
34
|
+
scope: 'file-watch',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
/** Phase with tandem config (multiple scopes) */
|
|
38
|
+
const PHASE_WITH_MULTI_SCOPE = {
|
|
39
|
+
name: 'implement',
|
|
40
|
+
agent: 'dev',
|
|
41
|
+
tandem: {
|
|
42
|
+
partner: 'tea',
|
|
43
|
+
scope: ['file-watch', 'tool-watch'],
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
/** Phase with tandem config (default scope — no scope specified) */
|
|
47
|
+
const PHASE_WITH_DEFAULT_SCOPE = {
|
|
48
|
+
name: 'implement',
|
|
49
|
+
agent: 'dev',
|
|
50
|
+
tandem: {
|
|
51
|
+
partner: 'architect',
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
/** Phase without tandem config */
|
|
55
|
+
const PHASE_WITHOUT_TANDEM = {
|
|
56
|
+
name: 'review',
|
|
57
|
+
agent: 'reviewer',
|
|
58
|
+
gate: { type: 'approval' },
|
|
59
|
+
};
|
|
60
|
+
// =============================================================================
|
|
61
|
+
// AC1: BikeLane spawns backseat agent at tandem phase start
|
|
62
|
+
// =============================================================================
|
|
63
|
+
describe('95-2: Tandem Lifecycle', () => {
|
|
64
|
+
beforeEach(() => {
|
|
65
|
+
_resetForTesting();
|
|
66
|
+
if (existsSync(TEST_DIR)) {
|
|
67
|
+
rmSync(TEST_DIR, { recursive: true });
|
|
68
|
+
}
|
|
69
|
+
mkdirSync(TEST_DIR, { recursive: true });
|
|
70
|
+
mkdirSync(join(TEST_DIR, '.session'), { recursive: true });
|
|
71
|
+
});
|
|
72
|
+
afterEach(() => {
|
|
73
|
+
if (existsSync(TEST_DIR)) {
|
|
74
|
+
rmSync(TEST_DIR, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
describe('AC1: Spawn backseat agent at tandem phase start', () => {
|
|
78
|
+
it('should detect tandem config on phase and spawn backseat', async () => {
|
|
79
|
+
const params = {
|
|
80
|
+
phase: PHASE_WITH_TANDEM,
|
|
81
|
+
storyId: '95-2',
|
|
82
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
83
|
+
};
|
|
84
|
+
const result = await spawnBackseat(params);
|
|
85
|
+
assert.strictEqual(result.success, true, 'Spawn should succeed');
|
|
86
|
+
assert.ok(result.data, 'Should return backseat handle');
|
|
87
|
+
assert.ok(result.data.taskId, 'Handle should have taskId');
|
|
88
|
+
assert.strictEqual(result.data.partner, 'architect', 'Partner should match tandem config');
|
|
89
|
+
});
|
|
90
|
+
it('should use haiku model for backseat agent', async () => {
|
|
91
|
+
const params = {
|
|
92
|
+
phase: PHASE_WITH_TANDEM,
|
|
93
|
+
storyId: '95-2',
|
|
94
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
95
|
+
};
|
|
96
|
+
const result = await spawnBackseat(params);
|
|
97
|
+
assert.strictEqual(result.success, true);
|
|
98
|
+
assert.strictEqual(result.data?.model, 'haiku', 'Must use haiku model per framework rules');
|
|
99
|
+
});
|
|
100
|
+
it('should run backseat in background', async () => {
|
|
101
|
+
const params = {
|
|
102
|
+
phase: PHASE_WITH_TANDEM,
|
|
103
|
+
storyId: '95-2',
|
|
104
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
105
|
+
};
|
|
106
|
+
const result = await spawnBackseat(params);
|
|
107
|
+
assert.strictEqual(result.success, true);
|
|
108
|
+
assert.strictEqual(result.data?.runInBackground, true, 'Must run in background');
|
|
109
|
+
});
|
|
110
|
+
it('should pass scope config to backseat agent', async () => {
|
|
111
|
+
const params = {
|
|
112
|
+
phase: PHASE_WITH_TANDEM,
|
|
113
|
+
storyId: '95-2',
|
|
114
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
115
|
+
};
|
|
116
|
+
const result = await spawnBackseat(params);
|
|
117
|
+
assert.strictEqual(result.success, true);
|
|
118
|
+
assert.deepStrictEqual(result.data?.scope, ['file-watch'], 'Should normalize scope to array');
|
|
119
|
+
});
|
|
120
|
+
it('should handle multiple scopes', async () => {
|
|
121
|
+
const params = {
|
|
122
|
+
phase: PHASE_WITH_MULTI_SCOPE,
|
|
123
|
+
storyId: '95-2',
|
|
124
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
125
|
+
};
|
|
126
|
+
const result = await spawnBackseat(params);
|
|
127
|
+
assert.strictEqual(result.success, true);
|
|
128
|
+
assert.deepStrictEqual(result.data?.scope, ['file-watch', 'tool-watch']);
|
|
129
|
+
});
|
|
130
|
+
it('should default scope to file-watch when not specified', async () => {
|
|
131
|
+
const params = {
|
|
132
|
+
phase: PHASE_WITH_DEFAULT_SCOPE,
|
|
133
|
+
storyId: '95-2',
|
|
134
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
135
|
+
};
|
|
136
|
+
const result = await spawnBackseat(params);
|
|
137
|
+
assert.strictEqual(result.success, true);
|
|
138
|
+
assert.deepStrictEqual(result.data?.scope, ['file-watch'], 'Should default to file-watch');
|
|
139
|
+
});
|
|
140
|
+
it('should set observation file path on handle', async () => {
|
|
141
|
+
const params = {
|
|
142
|
+
phase: PHASE_WITH_TANDEM,
|
|
143
|
+
storyId: '95-2',
|
|
144
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
145
|
+
};
|
|
146
|
+
const result = await spawnBackseat(params);
|
|
147
|
+
assert.strictEqual(result.success, true);
|
|
148
|
+
const expectedPath = join(TEST_DIR, '.session', '95-2-tandem-architect.md');
|
|
149
|
+
assert.strictEqual(result.data?.observationFilePath, expectedPath, 'Observation file path should follow convention');
|
|
150
|
+
});
|
|
151
|
+
it('should register cleanup handler at spawn time', async () => {
|
|
152
|
+
const params = {
|
|
153
|
+
phase: PHASE_WITH_TANDEM,
|
|
154
|
+
storyId: '95-2',
|
|
155
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
156
|
+
};
|
|
157
|
+
const result = await spawnBackseat(params);
|
|
158
|
+
assert.strictEqual(result.success, true);
|
|
159
|
+
assert.strictEqual(result.data?.cleanupRegistered, true, 'Cleanup handler must be registered at spawn time');
|
|
160
|
+
});
|
|
161
|
+
it('should return no-op result for phase without tandem', async () => {
|
|
162
|
+
const params = {
|
|
163
|
+
phase: PHASE_WITHOUT_TANDEM,
|
|
164
|
+
storyId: '95-2',
|
|
165
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
166
|
+
};
|
|
167
|
+
const result = await spawnBackseat(params);
|
|
168
|
+
assert.strictEqual(result.success, true, 'Should succeed (no-op)');
|
|
169
|
+
assert.strictEqual(result.data, undefined, 'No handle for non-tandem phase');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
// =============================================================================
|
|
173
|
+
// AC2: BikeLane terminates backseat agent at phase end
|
|
174
|
+
// =============================================================================
|
|
175
|
+
describe('AC2: Terminate backseat agent at phase end', () => {
|
|
176
|
+
it('should terminate active backseat by task ID', async () => {
|
|
177
|
+
// First spawn
|
|
178
|
+
const spawnResult = await spawnBackseat({
|
|
179
|
+
phase: PHASE_WITH_TANDEM,
|
|
180
|
+
storyId: '95-2',
|
|
181
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
182
|
+
});
|
|
183
|
+
assert.strictEqual(spawnResult.success, true);
|
|
184
|
+
const handle = spawnResult.data;
|
|
185
|
+
const result = await terminateBackseat(handle);
|
|
186
|
+
assert.strictEqual(result.success, true, 'Termination should succeed');
|
|
187
|
+
});
|
|
188
|
+
it('should update background task status on termination', async () => {
|
|
189
|
+
const spawnResult = await spawnBackseat({
|
|
190
|
+
phase: PHASE_WITH_TANDEM,
|
|
191
|
+
storyId: '95-2',
|
|
192
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
193
|
+
});
|
|
194
|
+
const handle = spawnResult.data;
|
|
195
|
+
const result = await terminateBackseat(handle);
|
|
196
|
+
assert.strictEqual(result.success, true);
|
|
197
|
+
assert.strictEqual(result.data?.status, 'terminated', 'Background task status should be terminated');
|
|
198
|
+
});
|
|
199
|
+
it('should clear active backseat after termination', async () => {
|
|
200
|
+
const spawnResult = await spawnBackseat({
|
|
201
|
+
phase: PHASE_WITH_TANDEM,
|
|
202
|
+
storyId: '95-2',
|
|
203
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
204
|
+
});
|
|
205
|
+
const handle = spawnResult.data;
|
|
206
|
+
await terminateBackseat(handle);
|
|
207
|
+
const active = getActiveBackseat('95-2');
|
|
208
|
+
assert.strictEqual(active, null, 'No active backseat after termination');
|
|
209
|
+
});
|
|
210
|
+
it('should handle termination of already-stopped task gracefully', async () => {
|
|
211
|
+
// Simulate a handle for a task that already stopped
|
|
212
|
+
const staleHandle = {
|
|
213
|
+
taskId: 'stale-task-id',
|
|
214
|
+
partner: 'architect',
|
|
215
|
+
model: 'haiku',
|
|
216
|
+
runInBackground: true,
|
|
217
|
+
scope: ['file-watch'],
|
|
218
|
+
observationFilePath: join(TEST_DIR, '.session', '95-2-tandem-architect.md'),
|
|
219
|
+
cleanupRegistered: true,
|
|
220
|
+
};
|
|
221
|
+
const result = await terminateBackseat(staleHandle);
|
|
222
|
+
// Should succeed gracefully, not throw
|
|
223
|
+
assert.strictEqual(result.success, true, 'Should handle already-stopped gracefully');
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
// =============================================================================
|
|
227
|
+
// AC3: Zero orphan processes (NFR8)
|
|
228
|
+
// =============================================================================
|
|
229
|
+
describe('AC3: Zero orphan processes', () => {
|
|
230
|
+
it('should register cleanup handler that can terminate backseat', async () => {
|
|
231
|
+
let cleanupCalled = false;
|
|
232
|
+
const handler = {
|
|
233
|
+
storyId: '95-2',
|
|
234
|
+
cleanup: async () => { cleanupCalled = true; },
|
|
235
|
+
};
|
|
236
|
+
registerCleanupHandler(handler);
|
|
237
|
+
await executeCleanupHandlers('95-2');
|
|
238
|
+
assert.strictEqual(cleanupCalled, true, 'Cleanup handler should be invoked');
|
|
239
|
+
});
|
|
240
|
+
it('should execute cleanup handlers even on error', async () => {
|
|
241
|
+
let cleanupCalled = false;
|
|
242
|
+
registerCleanupHandler({
|
|
243
|
+
storyId: '95-2',
|
|
244
|
+
cleanup: async () => { cleanupCalled = true; },
|
|
245
|
+
});
|
|
246
|
+
// Simulate crash-like cleanup
|
|
247
|
+
await executeCleanupHandlers('95-2');
|
|
248
|
+
assert.strictEqual(cleanupCalled, true, 'Cleanup must execute even in error scenarios');
|
|
249
|
+
});
|
|
250
|
+
it('should support multiple cleanup handlers per story', async () => {
|
|
251
|
+
let handler1Called = false;
|
|
252
|
+
let handler2Called = false;
|
|
253
|
+
registerCleanupHandler({
|
|
254
|
+
storyId: '95-2',
|
|
255
|
+
cleanup: async () => { handler1Called = true; },
|
|
256
|
+
});
|
|
257
|
+
registerCleanupHandler({
|
|
258
|
+
storyId: '95-2',
|
|
259
|
+
cleanup: async () => { handler2Called = true; },
|
|
260
|
+
});
|
|
261
|
+
await executeCleanupHandlers('95-2');
|
|
262
|
+
assert.strictEqual(handler1Called, true, 'First handler should be called');
|
|
263
|
+
assert.strictEqual(handler2Called, true, 'Second handler should be called');
|
|
264
|
+
});
|
|
265
|
+
it('should not affect handlers for other stories', async () => {
|
|
266
|
+
let otherCalled = false;
|
|
267
|
+
registerCleanupHandler({
|
|
268
|
+
storyId: 'other-story',
|
|
269
|
+
cleanup: async () => { otherCalled = true; },
|
|
270
|
+
});
|
|
271
|
+
registerCleanupHandler({
|
|
272
|
+
storyId: '95-2',
|
|
273
|
+
cleanup: async () => { },
|
|
274
|
+
});
|
|
275
|
+
await executeCleanupHandlers('95-2');
|
|
276
|
+
assert.strictEqual(otherCalled, false, 'Should not invoke handlers for other stories');
|
|
277
|
+
});
|
|
278
|
+
it('should clear handlers after execution', async () => {
|
|
279
|
+
let callCount = 0;
|
|
280
|
+
registerCleanupHandler({
|
|
281
|
+
storyId: '95-2',
|
|
282
|
+
cleanup: async () => { callCount++; },
|
|
283
|
+
});
|
|
284
|
+
await executeCleanupHandlers('95-2');
|
|
285
|
+
await executeCleanupHandlers('95-2'); // Second call
|
|
286
|
+
assert.strictEqual(callCount, 1, 'Handler should only execute once');
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
// =============================================================================
|
|
290
|
+
// AC4: Primary agent continues if backseat crashes (NFR10)
|
|
291
|
+
// =============================================================================
|
|
292
|
+
describe('AC4: Primary continues if backseat crashes', () => {
|
|
293
|
+
it('should return success even when backseat process is unavailable', async () => {
|
|
294
|
+
// Terminating a non-existent task should not throw
|
|
295
|
+
const deadHandle = {
|
|
296
|
+
taskId: 'dead-process-id',
|
|
297
|
+
partner: 'architect',
|
|
298
|
+
model: 'haiku',
|
|
299
|
+
runInBackground: true,
|
|
300
|
+
scope: ['file-watch'],
|
|
301
|
+
observationFilePath: join(TEST_DIR, '.session', '95-2-tandem-architect.md'),
|
|
302
|
+
cleanupRegistered: true,
|
|
303
|
+
};
|
|
304
|
+
const result = await terminateBackseat(deadHandle);
|
|
305
|
+
assert.strictEqual(result.success, true, 'Termination must succeed even for crashed backseat');
|
|
306
|
+
});
|
|
307
|
+
it('should not throw when cleanup handler encounters error', async () => {
|
|
308
|
+
registerCleanupHandler({
|
|
309
|
+
storyId: '95-2',
|
|
310
|
+
cleanup: async () => { throw new Error('Simulated crash'); },
|
|
311
|
+
});
|
|
312
|
+
// executeCleanupHandlers should not throw despite handler error
|
|
313
|
+
await assert.doesNotReject(() => executeCleanupHandlers('95-2'), 'Cleanup should swallow handler errors');
|
|
314
|
+
});
|
|
315
|
+
it('should continue executing remaining handlers after one fails', async () => {
|
|
316
|
+
let secondCalled = false;
|
|
317
|
+
registerCleanupHandler({
|
|
318
|
+
storyId: '95-2',
|
|
319
|
+
cleanup: async () => { throw new Error('First handler crash'); },
|
|
320
|
+
});
|
|
321
|
+
registerCleanupHandler({
|
|
322
|
+
storyId: '95-2',
|
|
323
|
+
cleanup: async () => { secondCalled = true; },
|
|
324
|
+
});
|
|
325
|
+
await executeCleanupHandlers('95-2');
|
|
326
|
+
assert.strictEqual(secondCalled, true, 'Remaining handlers must execute even if earlier ones fail');
|
|
327
|
+
});
|
|
328
|
+
it('should return error info but success=true for crashed backseat spawn', async () => {
|
|
329
|
+
// Spawn with invalid config to simulate crash at spawn
|
|
330
|
+
const params = {
|
|
331
|
+
phase: {
|
|
332
|
+
name: 'test',
|
|
333
|
+
agent: 'dev',
|
|
334
|
+
tandem: {
|
|
335
|
+
partner: '', // Invalid: empty partner
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
storyId: '95-2',
|
|
339
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
340
|
+
};
|
|
341
|
+
const result = await spawnBackseat(params);
|
|
342
|
+
// Should not crash the primary agent
|
|
343
|
+
assert.strictEqual(result.success, false, 'Spawn with invalid config should fail');
|
|
344
|
+
assert.ok(result.error, 'Should include error message');
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
// =============================================================================
|
|
348
|
+
// AC5: Backward compatible
|
|
349
|
+
// =============================================================================
|
|
350
|
+
describe('AC5: Backward compatibility', () => {
|
|
351
|
+
it('should be a no-op for phases without tandem config', async () => {
|
|
352
|
+
const params = {
|
|
353
|
+
phase: PHASE_WITHOUT_TANDEM,
|
|
354
|
+
storyId: '95-2',
|
|
355
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
356
|
+
};
|
|
357
|
+
const result = await spawnBackseat(params);
|
|
358
|
+
assert.strictEqual(result.success, true, 'Should succeed as no-op');
|
|
359
|
+
assert.strictEqual(result.data, undefined, 'No handle for non-tandem');
|
|
360
|
+
});
|
|
361
|
+
it('should not modify WorkflowPhase interface contract', () => {
|
|
362
|
+
// Verify existing phase fields still work without tandem
|
|
363
|
+
const phase = {
|
|
364
|
+
name: 'red',
|
|
365
|
+
agent: 'tea',
|
|
366
|
+
input: ['session_file'],
|
|
367
|
+
output: ['failing_tests'],
|
|
368
|
+
gate: { type: 'tests_fail', condition: 'Coverage check' },
|
|
369
|
+
};
|
|
370
|
+
assert.strictEqual(phase.name, 'red');
|
|
371
|
+
assert.strictEqual(phase.agent, 'tea');
|
|
372
|
+
assert.ok(Array.isArray(phase.input));
|
|
373
|
+
assert.ok(Array.isArray(phase.output));
|
|
374
|
+
assert.strictEqual(phase.gate?.type, 'tests_fail');
|
|
375
|
+
assert.strictEqual(phase.tandem, undefined, 'Tandem should be optional/undefined');
|
|
376
|
+
});
|
|
377
|
+
it('should return null for getActiveBackseat when no tandem running', () => {
|
|
378
|
+
const active = getActiveBackseat('nonexistent-story');
|
|
379
|
+
assert.strictEqual(active, null, 'No active backseat for non-tandem story');
|
|
380
|
+
});
|
|
381
|
+
it('should handle executeCleanupHandlers with no registered handlers', async () => {
|
|
382
|
+
// No handlers registered for this story
|
|
383
|
+
await assert.doesNotReject(() => executeCleanupHandlers('no-handlers-story'), 'Should handle empty cleanup gracefully');
|
|
384
|
+
});
|
|
385
|
+
it('should terminate gracefully when no backseat exists for phase transition', async () => {
|
|
386
|
+
// Simulates completeStep for a non-tandem phase
|
|
387
|
+
const nullHandle = getActiveBackseat('95-2');
|
|
388
|
+
assert.strictEqual(nullHandle, null);
|
|
389
|
+
// No crash, no error — workflow continues
|
|
390
|
+
});
|
|
391
|
+
});
|
|
392
|
+
// =============================================================================
|
|
393
|
+
// ProcessAdapter integration
|
|
394
|
+
// =============================================================================
|
|
395
|
+
describe('ProcessAdapter integration', () => {
|
|
396
|
+
it('should call adapter.spawn when adapter is provided', async () => {
|
|
397
|
+
let spawnCalled = false;
|
|
398
|
+
let spawnParams = {};
|
|
399
|
+
const adapter = {
|
|
400
|
+
spawn: async (params) => {
|
|
401
|
+
spawnCalled = true;
|
|
402
|
+
spawnParams = params;
|
|
403
|
+
return { taskId: 'real-task-123' };
|
|
404
|
+
},
|
|
405
|
+
terminate: async () => { },
|
|
406
|
+
};
|
|
407
|
+
const result = await spawnBackseat({
|
|
408
|
+
phase: PHASE_WITH_TANDEM,
|
|
409
|
+
storyId: '95-2',
|
|
410
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
411
|
+
adapter,
|
|
412
|
+
});
|
|
413
|
+
assert.strictEqual(spawnCalled, true, 'Adapter spawn must be called');
|
|
414
|
+
assert.strictEqual(result.data?.taskId, 'real-task-123', 'Should use adapter taskId');
|
|
415
|
+
assert.strictEqual(spawnParams.partner, 'architect');
|
|
416
|
+
assert.strictEqual(spawnParams.model, 'haiku');
|
|
417
|
+
});
|
|
418
|
+
it('should call adapter.terminate when terminating with adapter', async () => {
|
|
419
|
+
let terminatedId = '';
|
|
420
|
+
const adapter = {
|
|
421
|
+
spawn: async () => ({ taskId: 'real-task-456' }),
|
|
422
|
+
terminate: async (taskId) => { terminatedId = taskId; },
|
|
423
|
+
};
|
|
424
|
+
const spawnResult = await spawnBackseat({
|
|
425
|
+
phase: PHASE_WITH_TANDEM,
|
|
426
|
+
storyId: '95-2',
|
|
427
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
428
|
+
adapter,
|
|
429
|
+
});
|
|
430
|
+
await terminateBackseat(spawnResult.data, adapter);
|
|
431
|
+
assert.strictEqual(terminatedId, 'real-task-456', 'Adapter terminate must be called with correct taskId');
|
|
432
|
+
});
|
|
433
|
+
it('should call adapter.terminate in cleanup handler', async () => {
|
|
434
|
+
let terminatedId = '';
|
|
435
|
+
const adapter = {
|
|
436
|
+
spawn: async () => ({ taskId: 'cleanup-task-789' }),
|
|
437
|
+
terminate: async (taskId) => { terminatedId = taskId; },
|
|
438
|
+
};
|
|
439
|
+
await spawnBackseat({
|
|
440
|
+
phase: PHASE_WITH_TANDEM,
|
|
441
|
+
storyId: '95-2',
|
|
442
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
443
|
+
adapter,
|
|
444
|
+
});
|
|
445
|
+
await executeCleanupHandlers('95-2');
|
|
446
|
+
assert.strictEqual(terminatedId, 'cleanup-task-789', 'Cleanup must call adapter.terminate');
|
|
447
|
+
});
|
|
448
|
+
it('should terminate existing backseat before spawning new one for same story', async () => {
|
|
449
|
+
const terminated = [];
|
|
450
|
+
const adapter = {
|
|
451
|
+
spawn: async () => ({ taskId: `task-${++taskCounter}` }),
|
|
452
|
+
terminate: async (taskId) => { terminated.push(taskId); },
|
|
453
|
+
};
|
|
454
|
+
let taskCounter = 0;
|
|
455
|
+
// First spawn
|
|
456
|
+
await spawnBackseat({
|
|
457
|
+
phase: PHASE_WITH_TANDEM,
|
|
458
|
+
storyId: '95-2',
|
|
459
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
460
|
+
adapter,
|
|
461
|
+
});
|
|
462
|
+
// Second spawn for same story — should terminate first
|
|
463
|
+
await spawnBackseat({
|
|
464
|
+
phase: PHASE_WITH_MULTI_SCOPE,
|
|
465
|
+
storyId: '95-2',
|
|
466
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
467
|
+
adapter,
|
|
468
|
+
});
|
|
469
|
+
assert.strictEqual(terminated.length, 1, 'First backseat should be terminated');
|
|
470
|
+
assert.strictEqual(terminated[0], 'task-1', 'Should terminate the first task');
|
|
471
|
+
});
|
|
472
|
+
it('should return error result when adapter.spawn fails', async () => {
|
|
473
|
+
const adapter = {
|
|
474
|
+
spawn: async () => { throw new Error('Connection refused'); },
|
|
475
|
+
terminate: async () => { },
|
|
476
|
+
};
|
|
477
|
+
const result = await spawnBackseat({
|
|
478
|
+
phase: PHASE_WITH_TANDEM,
|
|
479
|
+
storyId: '95-2',
|
|
480
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
481
|
+
adapter,
|
|
482
|
+
});
|
|
483
|
+
assert.strictEqual(result.success, false);
|
|
484
|
+
assert.ok(result.error?.includes('Connection refused'));
|
|
485
|
+
});
|
|
486
|
+
it('should succeed even when adapter.terminate fails', async () => {
|
|
487
|
+
const adapter = {
|
|
488
|
+
spawn: async () => ({ taskId: 'will-fail-terminate' }),
|
|
489
|
+
terminate: async () => { throw new Error('Process not found'); },
|
|
490
|
+
};
|
|
491
|
+
const spawnResult = await spawnBackseat({
|
|
492
|
+
phase: PHASE_WITH_TANDEM,
|
|
493
|
+
storyId: '95-2',
|
|
494
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
495
|
+
adapter,
|
|
496
|
+
});
|
|
497
|
+
const result = await terminateBackseat(spawnResult.data, adapter);
|
|
498
|
+
assert.strictEqual(result.success, true, 'Should swallow terminate errors');
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
// =============================================================================
|
|
502
|
+
// Result format compliance
|
|
503
|
+
// =============================================================================
|
|
504
|
+
describe('Result format compliance', () => {
|
|
505
|
+
it('should return {success, data?, error?} from spawnBackseat', async () => {
|
|
506
|
+
const result = await spawnBackseat({
|
|
507
|
+
phase: PHASE_WITH_TANDEM,
|
|
508
|
+
storyId: '95-2',
|
|
509
|
+
sessionDir: join(TEST_DIR, '.session'),
|
|
510
|
+
});
|
|
511
|
+
assert.ok('success' in result, 'Must have success field');
|
|
512
|
+
assert.ok(typeof result.success === 'boolean', 'success must be boolean');
|
|
513
|
+
// data and error are optional
|
|
514
|
+
});
|
|
515
|
+
it('should return {success, data?, error?} from terminateBackseat', async () => {
|
|
516
|
+
const handle = {
|
|
517
|
+
taskId: 'test-id',
|
|
518
|
+
partner: 'architect',
|
|
519
|
+
model: 'haiku',
|
|
520
|
+
runInBackground: true,
|
|
521
|
+
scope: ['file-watch'],
|
|
522
|
+
observationFilePath: '/tmp/test.md',
|
|
523
|
+
cleanupRegistered: true,
|
|
524
|
+
};
|
|
525
|
+
const result = await terminateBackseat(handle);
|
|
526
|
+
assert.ok('success' in result, 'Must have success field');
|
|
527
|
+
assert.ok(typeof result.success === 'boolean', 'success must be boolean');
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
//# sourceMappingURL=tandem-lifecycle.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tandem-lifecycle.test.js","sourceRoot":"","sources":["../../src/workflow/tandem-lifecycle.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool-watch Observation Scope for Story 95-5
|
|
3
|
+
*
|
|
4
|
+
* Delivers tool call information (name, params, results) from primary agent
|
|
5
|
+
* to backseat observer within one tool-use cycle. Truncates large results
|
|
6
|
+
* to configurable max size. Non-blocking to primary.
|
|
7
|
+
*
|
|
8
|
+
* Hook side: processToolCall() appends JSONL to transport file (synchronous, fast).
|
|
9
|
+
* Backseat side: startToolWatcher() polls JSONL and writes observations.
|
|
10
|
+
*/
|
|
11
|
+
export interface ToolCallEntry {
|
|
12
|
+
timestamp: string;
|
|
13
|
+
toolName: string;
|
|
14
|
+
params: Record<string, unknown>;
|
|
15
|
+
resultPreview: string;
|
|
16
|
+
resultSize: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ToolWatchConfig {
|
|
19
|
+
sessionDir: string;
|
|
20
|
+
storyId: string;
|
|
21
|
+
agent: string;
|
|
22
|
+
persona: string;
|
|
23
|
+
phase: string;
|
|
24
|
+
pollIntervalMs?: number;
|
|
25
|
+
maxResultSize?: number;
|
|
26
|
+
observationFilePath?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ToolWatchHandle {
|
|
29
|
+
running: boolean;
|
|
30
|
+
pollIntervalMs: number;
|
|
31
|
+
}
|
|
32
|
+
export interface ToolWatchResult<T = unknown> {
|
|
33
|
+
success: boolean;
|
|
34
|
+
data?: T;
|
|
35
|
+
error?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ProcessToolCallParams {
|
|
38
|
+
sessionDir: string;
|
|
39
|
+
storyId: string;
|
|
40
|
+
toolName: string;
|
|
41
|
+
params: Record<string, unknown>;
|
|
42
|
+
toolResult: string;
|
|
43
|
+
maxResultSize?: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Truncate a tool result string to maxSize characters.
|
|
47
|
+
* Appends `[truncated from N chars]` indicator when truncated.
|
|
48
|
+
*/
|
|
49
|
+
export declare function truncateResult(result: string, maxSize: number): string;
|
|
50
|
+
/**
|
|
51
|
+
* Record a tool call to the JSONL transport file.
|
|
52
|
+
* Called from the PostToolUse hook — must be synchronous and fast.
|
|
53
|
+
*/
|
|
54
|
+
export declare function processToolCall(params: ProcessToolCallParams): ToolWatchResult;
|
|
55
|
+
/**
|
|
56
|
+
* Read tool call entries from a JSONL transport file.
|
|
57
|
+
* Skips malformed lines gracefully.
|
|
58
|
+
*/
|
|
59
|
+
export declare function readToolCalls(filePath: string): ToolWatchResult<ToolCallEntry[]>;
|
|
60
|
+
/**
|
|
61
|
+
* Start a polling tool watcher that reads JSONL entries and writes observations.
|
|
62
|
+
*/
|
|
63
|
+
export declare function startToolWatcher(config: ToolWatchConfig): Promise<ToolWatchResult<ToolWatchHandle>>;
|
|
64
|
+
/**
|
|
65
|
+
* Stop a running tool watcher. Idempotent — safe to call multiple times.
|
|
66
|
+
*/
|
|
67
|
+
export declare function stopToolWatcher(handle: ToolWatchHandle): Promise<ToolWatchResult>;
|
|
68
|
+
//# sourceMappingURL=tool-watch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-watch.d.ts","sourceRoot":"","sources":["../../src/workflow/tool-watch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,OAAO;IAC1C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKtE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,CAyB9E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAAC,aAAa,EAAE,CAAC,CAuBhF;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAiE3C;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAYvF"}
|