@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
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Story 95-4: File-watch Observation Scope
|
|
3
|
+
*
|
|
4
|
+
* RED state tests for file change detection in the backseat agent.
|
|
5
|
+
* These tests cover all acceptance criteria:
|
|
6
|
+
*
|
|
7
|
+
* AC1: Detect file create events in working tree
|
|
8
|
+
* AC2: Detect file modify events in working tree
|
|
9
|
+
* AC3: Detect file delete events in working tree
|
|
10
|
+
* AC4: Detection within 5 seconds (poll interval ≤ 2s)
|
|
11
|
+
* AC5: Non-blocking — functions return promptly, polling is async
|
|
12
|
+
* AC6: Writes observations with file-watch trigger type via ObservationWriter
|
|
13
|
+
* AC7: Context accumulation — tracks seen files, avoids redundant observations
|
|
14
|
+
* AC8: Ignores non-source directories (.pennyfarthing/, .session/, node_modules/)
|
|
15
|
+
* AC9: Error resilience — continues observing if a single write fails
|
|
16
|
+
* AC10: Returns result objects ({success, error?}) per framework pattern
|
|
17
|
+
*
|
|
18
|
+
* Run with: npm test
|
|
19
|
+
*/
|
|
20
|
+
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
21
|
+
import assert from 'node:assert';
|
|
22
|
+
import { mkdirSync, rmSync, existsSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
23
|
+
import { join, dirname } from 'node:path';
|
|
24
|
+
import { fileURLToPath } from 'node:url';
|
|
25
|
+
// Import the module under test (does not exist yet — will cause import failure)
|
|
26
|
+
import { detectFileChanges, startFileWatcher, stopFileWatcher, createFileWatchScope, } from './file-watch.js';
|
|
27
|
+
// Import observation writer for integration tests
|
|
28
|
+
import { initObservationFile, parseObservationFile, } from './observation-writer.js';
|
|
29
|
+
// Get directory for test fixtures
|
|
30
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
const TEST_DIR = join(__dirname, '__test_file_watch__');
|
|
32
|
+
const SESSION_DIR = join(TEST_DIR, '.session');
|
|
33
|
+
const WORK_DIR = join(TEST_DIR, 'workdir');
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// Test Fixtures
|
|
36
|
+
// =============================================================================
|
|
37
|
+
const DEFAULT_POLL_MS = 100; // Fast for testing
|
|
38
|
+
const DEFAULT_CONFIG = {
|
|
39
|
+
workDir: WORK_DIR,
|
|
40
|
+
sessionDir: SESSION_DIR,
|
|
41
|
+
storyId: '95-4',
|
|
42
|
+
agent: 'architect',
|
|
43
|
+
persona: 'Will Bailey',
|
|
44
|
+
phase: 'implement',
|
|
45
|
+
pollIntervalMs: DEFAULT_POLL_MS,
|
|
46
|
+
ignorePaths: ['.pennyfarthing/', '.session/', 'node_modules/'],
|
|
47
|
+
};
|
|
48
|
+
const OBS_CONFIG = {
|
|
49
|
+
storyId: '95-4',
|
|
50
|
+
agent: 'architect',
|
|
51
|
+
persona: 'Will Bailey',
|
|
52
|
+
phase: 'implement',
|
|
53
|
+
sessionDir: SESSION_DIR,
|
|
54
|
+
};
|
|
55
|
+
// =============================================================================
|
|
56
|
+
// Setup / Teardown
|
|
57
|
+
// =============================================================================
|
|
58
|
+
describe('95-4: File-watch Observation Scope', () => {
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
if (existsSync(TEST_DIR)) {
|
|
61
|
+
rmSync(TEST_DIR, { recursive: true });
|
|
62
|
+
}
|
|
63
|
+
mkdirSync(SESSION_DIR, { recursive: true });
|
|
64
|
+
mkdirSync(WORK_DIR, { recursive: true });
|
|
65
|
+
});
|
|
66
|
+
afterEach(() => {
|
|
67
|
+
if (existsSync(TEST_DIR)) {
|
|
68
|
+
rmSync(TEST_DIR, { recursive: true });
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
// ===========================================================================
|
|
72
|
+
// AC1: Detect file create events
|
|
73
|
+
// ===========================================================================
|
|
74
|
+
describe('AC1: Detect file create events', () => {
|
|
75
|
+
it('should detect a newly created file', async () => {
|
|
76
|
+
// Baseline — no files yet
|
|
77
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
78
|
+
assert.ok(baseline.success);
|
|
79
|
+
// Create a file
|
|
80
|
+
writeFileSync(join(WORK_DIR, 'new-file.ts'), 'export const x = 1;');
|
|
81
|
+
// Detect changes
|
|
82
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
83
|
+
assert.ok(result.success);
|
|
84
|
+
assert.ok(result.data);
|
|
85
|
+
assert.ok(result.data.length > 0, 'Should detect at least one change');
|
|
86
|
+
const created = result.data.find((c) => c.path.includes('new-file.ts'));
|
|
87
|
+
assert.ok(created, 'Should find the created file');
|
|
88
|
+
assert.strictEqual(created.event, 'create');
|
|
89
|
+
});
|
|
90
|
+
it('should detect multiple created files in a single poll', async () => {
|
|
91
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
92
|
+
assert.ok(baseline.success);
|
|
93
|
+
writeFileSync(join(WORK_DIR, 'a.ts'), 'a');
|
|
94
|
+
writeFileSync(join(WORK_DIR, 'b.ts'), 'b');
|
|
95
|
+
writeFileSync(join(WORK_DIR, 'c.ts'), 'c');
|
|
96
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
97
|
+
assert.ok(result.success);
|
|
98
|
+
assert.ok(result.data);
|
|
99
|
+
assert.ok(result.data.length >= 3, `Expected ≥3 changes, got ${result.data.length}`);
|
|
100
|
+
});
|
|
101
|
+
it('should detect files created in subdirectories', async () => {
|
|
102
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
103
|
+
assert.ok(baseline.success);
|
|
104
|
+
const subDir = join(WORK_DIR, 'src', 'components');
|
|
105
|
+
mkdirSync(subDir, { recursive: true });
|
|
106
|
+
writeFileSync(join(subDir, 'Widget.tsx'), 'export function Widget() {}');
|
|
107
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
108
|
+
assert.ok(result.success);
|
|
109
|
+
assert.ok(result.data);
|
|
110
|
+
const created = result.data.find((c) => c.path.includes('Widget.tsx'));
|
|
111
|
+
assert.ok(created, 'Should find file in subdirectory');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
// ===========================================================================
|
|
115
|
+
// AC2: Detect file modify events
|
|
116
|
+
// ===========================================================================
|
|
117
|
+
describe('AC2: Detect file modify events', () => {
|
|
118
|
+
it('should detect a modified file', async () => {
|
|
119
|
+
// Create file first
|
|
120
|
+
const filePath = join(WORK_DIR, 'existing.ts');
|
|
121
|
+
writeFileSync(filePath, 'export const x = 1;');
|
|
122
|
+
// Baseline with existing file
|
|
123
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
124
|
+
assert.ok(baseline.success);
|
|
125
|
+
// Modify the file
|
|
126
|
+
writeFileSync(filePath, 'export const x = 2;');
|
|
127
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
128
|
+
assert.ok(result.success);
|
|
129
|
+
assert.ok(result.data);
|
|
130
|
+
const modified = result.data.find((c) => c.path.includes('existing.ts'));
|
|
131
|
+
assert.ok(modified, 'Should find the modified file');
|
|
132
|
+
assert.strictEqual(modified.event, 'modify');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
// ===========================================================================
|
|
136
|
+
// AC3: Detect file delete events
|
|
137
|
+
// ===========================================================================
|
|
138
|
+
describe('AC3: Detect file delete events', () => {
|
|
139
|
+
it('should detect a deleted file', async () => {
|
|
140
|
+
// Create file first
|
|
141
|
+
const filePath = join(WORK_DIR, 'to-delete.ts');
|
|
142
|
+
writeFileSync(filePath, 'export const temp = true;');
|
|
143
|
+
// Baseline
|
|
144
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
145
|
+
assert.ok(baseline.success);
|
|
146
|
+
// Delete the file
|
|
147
|
+
unlinkSync(filePath);
|
|
148
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
149
|
+
assert.ok(result.success);
|
|
150
|
+
assert.ok(result.data);
|
|
151
|
+
const deleted = result.data.find((c) => c.path.includes('to-delete.ts'));
|
|
152
|
+
assert.ok(deleted, 'Should find the deleted file');
|
|
153
|
+
assert.strictEqual(deleted.event, 'delete');
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
// ===========================================================================
|
|
157
|
+
// AC4: Detection within 5 seconds (poll interval)
|
|
158
|
+
// ===========================================================================
|
|
159
|
+
describe('AC4: Detection within 5 seconds', () => {
|
|
160
|
+
it('should accept poll interval ≤ 2000ms', () => {
|
|
161
|
+
// Verify the config accepts a valid poll interval
|
|
162
|
+
const config = {
|
|
163
|
+
...DEFAULT_CONFIG,
|
|
164
|
+
pollIntervalMs: 2000,
|
|
165
|
+
};
|
|
166
|
+
assert.strictEqual(config.pollIntervalMs, 2000);
|
|
167
|
+
});
|
|
168
|
+
it('should default poll interval to ≤ 2000ms when not specified', async () => {
|
|
169
|
+
const configNoInterval = {
|
|
170
|
+
workDir: WORK_DIR,
|
|
171
|
+
sessionDir: SESSION_DIR,
|
|
172
|
+
storyId: '95-4',
|
|
173
|
+
agent: 'architect',
|
|
174
|
+
persona: 'Will Bailey',
|
|
175
|
+
phase: 'implement',
|
|
176
|
+
ignorePaths: [],
|
|
177
|
+
};
|
|
178
|
+
// createFileWatchScope should use a default interval ≤ 2000ms
|
|
179
|
+
const scope = createFileWatchScope(configNoInterval);
|
|
180
|
+
assert.ok(scope, 'Should create scope');
|
|
181
|
+
assert.ok(scope.pollIntervalMs <= 2000, `Default poll interval should be ≤ 2000ms, got ${scope.pollIntervalMs}`);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
// ===========================================================================
|
|
185
|
+
// AC5: Non-blocking — functions return promptly
|
|
186
|
+
// ===========================================================================
|
|
187
|
+
describe('AC5: Non-blocking', () => {
|
|
188
|
+
it('detectFileChanges should resolve without long blocking', async () => {
|
|
189
|
+
const start = Date.now();
|
|
190
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
191
|
+
const elapsed = Date.now() - start;
|
|
192
|
+
assert.ok(result.success);
|
|
193
|
+
// Single detection cycle should complete in < 5000ms
|
|
194
|
+
assert.ok(elapsed < 5000, `detectFileChanges took ${elapsed}ms, expected < 5000ms`);
|
|
195
|
+
});
|
|
196
|
+
it('startFileWatcher should return handle immediately', async () => {
|
|
197
|
+
const start = Date.now();
|
|
198
|
+
const result = await startFileWatcher(DEFAULT_CONFIG);
|
|
199
|
+
const elapsed = Date.now() - start;
|
|
200
|
+
assert.ok(result.success);
|
|
201
|
+
assert.ok(result.data, 'Should return a handle');
|
|
202
|
+
// Start should be fast — sets up watcher, doesn't block
|
|
203
|
+
assert.ok(elapsed < 1000, `startFileWatcher took ${elapsed}ms, expected < 1000ms`);
|
|
204
|
+
// Cleanup
|
|
205
|
+
if (result.data) {
|
|
206
|
+
await stopFileWatcher(result.data);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
// ===========================================================================
|
|
211
|
+
// AC6: Writes observations with file-watch trigger type
|
|
212
|
+
// ===========================================================================
|
|
213
|
+
describe('AC6: Writes file-watch observations', () => {
|
|
214
|
+
it('should write observation with file-watch trigger type on file create', async () => {
|
|
215
|
+
// Init observation file
|
|
216
|
+
const initResult = initObservationFile(OBS_CONFIG);
|
|
217
|
+
assert.ok(initResult.success);
|
|
218
|
+
assert.ok(initResult.data);
|
|
219
|
+
// Start watcher
|
|
220
|
+
const watchResult = await startFileWatcher({
|
|
221
|
+
...DEFAULT_CONFIG,
|
|
222
|
+
observationFilePath: initResult.data.path,
|
|
223
|
+
});
|
|
224
|
+
assert.ok(watchResult.success);
|
|
225
|
+
assert.ok(watchResult.data);
|
|
226
|
+
// Create a file to trigger observation
|
|
227
|
+
writeFileSync(join(WORK_DIR, 'trigger.ts'), 'export const trigger = true;');
|
|
228
|
+
// Wait for at least one poll cycle
|
|
229
|
+
await new Promise(resolve => setTimeout(resolve, DEFAULT_POLL_MS * 3));
|
|
230
|
+
// Stop watcher
|
|
231
|
+
await stopFileWatcher(watchResult.data);
|
|
232
|
+
// Parse the observation file
|
|
233
|
+
const parsed = parseObservationFile(initResult.data.path);
|
|
234
|
+
assert.ok(parsed.success);
|
|
235
|
+
assert.ok(parsed.data);
|
|
236
|
+
assert.ok(parsed.data.entries.length > 0, 'Should have at least one observation entry');
|
|
237
|
+
const entry = parsed.data.entries[0];
|
|
238
|
+
assert.strictEqual(entry.triggerType, 'file-watch', 'Trigger type should be file-watch');
|
|
239
|
+
assert.ok(entry.triggerDetail.includes('trigger.ts'), 'Trigger detail should mention the file');
|
|
240
|
+
});
|
|
241
|
+
it('should include event type (create/modify/delete) in trigger detail', async () => {
|
|
242
|
+
const initResult = initObservationFile(OBS_CONFIG);
|
|
243
|
+
assert.ok(initResult.success);
|
|
244
|
+
assert.ok(initResult.data);
|
|
245
|
+
const watchResult = await startFileWatcher({
|
|
246
|
+
...DEFAULT_CONFIG,
|
|
247
|
+
observationFilePath: initResult.data.path,
|
|
248
|
+
});
|
|
249
|
+
assert.ok(watchResult.success);
|
|
250
|
+
assert.ok(watchResult.data);
|
|
251
|
+
// Create a file
|
|
252
|
+
writeFileSync(join(WORK_DIR, 'event-type.ts'), 'content');
|
|
253
|
+
await new Promise(resolve => setTimeout(resolve, DEFAULT_POLL_MS * 3));
|
|
254
|
+
await stopFileWatcher(watchResult.data);
|
|
255
|
+
const parsed = parseObservationFile(initResult.data.path);
|
|
256
|
+
assert.ok(parsed.success);
|
|
257
|
+
assert.ok(parsed.data);
|
|
258
|
+
assert.ok(parsed.data.entries.length > 0);
|
|
259
|
+
// Trigger detail should contain the event type
|
|
260
|
+
const entry = parsed.data.entries[0];
|
|
261
|
+
assert.ok(entry.triggerDetail.includes('create') ||
|
|
262
|
+
entry.triggerDetail.includes('modify') ||
|
|
263
|
+
entry.triggerDetail.includes('delete'), `Trigger detail should include event type, got: "${entry.triggerDetail}"`);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
// ===========================================================================
|
|
267
|
+
// AC7: Context accumulation — no redundant observations
|
|
268
|
+
// ===========================================================================
|
|
269
|
+
describe('AC7: Context accumulation', () => {
|
|
270
|
+
it('should not write duplicate observations for the same unchanged file', async () => {
|
|
271
|
+
const initResult = initObservationFile(OBS_CONFIG);
|
|
272
|
+
assert.ok(initResult.success);
|
|
273
|
+
assert.ok(initResult.data);
|
|
274
|
+
const watchResult = await startFileWatcher({
|
|
275
|
+
...DEFAULT_CONFIG,
|
|
276
|
+
observationFilePath: initResult.data.path,
|
|
277
|
+
});
|
|
278
|
+
assert.ok(watchResult.success);
|
|
279
|
+
assert.ok(watchResult.data);
|
|
280
|
+
// Create a file
|
|
281
|
+
writeFileSync(join(WORK_DIR, 'once.ts'), 'content');
|
|
282
|
+
// Wait for multiple poll cycles
|
|
283
|
+
await new Promise(resolve => setTimeout(resolve, DEFAULT_POLL_MS * 6));
|
|
284
|
+
await stopFileWatcher(watchResult.data);
|
|
285
|
+
const parsed = parseObservationFile(initResult.data.path);
|
|
286
|
+
assert.ok(parsed.success);
|
|
287
|
+
assert.ok(parsed.data);
|
|
288
|
+
// File was created once and not modified again — should appear at most once
|
|
289
|
+
const onceEntries = parsed.data.entries.filter((e) => e.triggerDetail.includes('once.ts'));
|
|
290
|
+
assert.strictEqual(onceEntries.length, 1, `File should appear exactly once, got ${onceEntries.length}`);
|
|
291
|
+
});
|
|
292
|
+
it('should write a new observation when a previously seen file changes again', async () => {
|
|
293
|
+
const initResult = initObservationFile(OBS_CONFIG);
|
|
294
|
+
assert.ok(initResult.success);
|
|
295
|
+
assert.ok(initResult.data);
|
|
296
|
+
const watchResult = await startFileWatcher({
|
|
297
|
+
...DEFAULT_CONFIG,
|
|
298
|
+
observationFilePath: initResult.data.path,
|
|
299
|
+
});
|
|
300
|
+
assert.ok(watchResult.success);
|
|
301
|
+
assert.ok(watchResult.data);
|
|
302
|
+
const filePath = join(WORK_DIR, 'changing.ts');
|
|
303
|
+
// Create file
|
|
304
|
+
writeFileSync(filePath, 'version 1');
|
|
305
|
+
await new Promise(resolve => setTimeout(resolve, DEFAULT_POLL_MS * 3));
|
|
306
|
+
// Modify the same file
|
|
307
|
+
writeFileSync(filePath, 'version 2');
|
|
308
|
+
await new Promise(resolve => setTimeout(resolve, DEFAULT_POLL_MS * 3));
|
|
309
|
+
await stopFileWatcher(watchResult.data);
|
|
310
|
+
const parsed = parseObservationFile(initResult.data.path);
|
|
311
|
+
assert.ok(parsed.success);
|
|
312
|
+
assert.ok(parsed.data);
|
|
313
|
+
const changingEntries = parsed.data.entries.filter((e) => e.triggerDetail.includes('changing.ts'));
|
|
314
|
+
// Should have at least 2 entries: create + modify
|
|
315
|
+
assert.ok(changingEntries.length >= 2, `Expected ≥2 entries for file, got ${changingEntries.length}`);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
// ===========================================================================
|
|
319
|
+
// AC8: Ignores non-source directories
|
|
320
|
+
// ===========================================================================
|
|
321
|
+
describe('AC8: Ignores non-source paths', () => {
|
|
322
|
+
it('should ignore files in .pennyfarthing/ directory', async () => {
|
|
323
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
324
|
+
assert.ok(baseline.success);
|
|
325
|
+
const ignoredDir = join(WORK_DIR, '.pennyfarthing');
|
|
326
|
+
mkdirSync(ignoredDir, { recursive: true });
|
|
327
|
+
writeFileSync(join(ignoredDir, 'config.yaml'), 'ignored: true');
|
|
328
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
329
|
+
assert.ok(result.success);
|
|
330
|
+
const changes = result.data ?? [];
|
|
331
|
+
const pfChanges = changes.filter((c) => c.path.includes('.pennyfarthing'));
|
|
332
|
+
assert.strictEqual(pfChanges.length, 0, 'Should not detect changes in .pennyfarthing/');
|
|
333
|
+
});
|
|
334
|
+
it('should ignore files in node_modules/ directory', async () => {
|
|
335
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
336
|
+
assert.ok(baseline.success);
|
|
337
|
+
const ignoredDir = join(WORK_DIR, 'node_modules', 'some-pkg');
|
|
338
|
+
mkdirSync(ignoredDir, { recursive: true });
|
|
339
|
+
writeFileSync(join(ignoredDir, 'index.js'), 'module.exports = {}');
|
|
340
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
341
|
+
assert.ok(result.success);
|
|
342
|
+
const changes = result.data ?? [];
|
|
343
|
+
const nmChanges = changes.filter((c) => c.path.includes('node_modules'));
|
|
344
|
+
assert.strictEqual(nmChanges.length, 0, 'Should not detect changes in node_modules/');
|
|
345
|
+
});
|
|
346
|
+
it('should ignore files in .session/ directory', async () => {
|
|
347
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
348
|
+
assert.ok(baseline.success);
|
|
349
|
+
mkdirSync(join(WORK_DIR, '.session'), { recursive: true });
|
|
350
|
+
writeFileSync(join(WORK_DIR, '.session', 'state.md'), '# state');
|
|
351
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
352
|
+
assert.ok(result.success);
|
|
353
|
+
const changes = result.data ?? [];
|
|
354
|
+
// Note: .session within WORK_DIR, not SESSION_DIR
|
|
355
|
+
const sessionChanges = changes.filter((c) => c.path.includes('.session'));
|
|
356
|
+
assert.strictEqual(sessionChanges.length, 0, 'Should not detect changes in .session/');
|
|
357
|
+
});
|
|
358
|
+
it('should detect files in non-ignored directories', async () => {
|
|
359
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
360
|
+
assert.ok(baseline.success);
|
|
361
|
+
const srcDir = join(WORK_DIR, 'src');
|
|
362
|
+
mkdirSync(srcDir, { recursive: true });
|
|
363
|
+
writeFileSync(join(srcDir, 'app.ts'), 'export const app = true;');
|
|
364
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
365
|
+
assert.ok(result.success);
|
|
366
|
+
assert.ok(result.data);
|
|
367
|
+
assert.ok(result.data.length > 0, 'Should detect changes in src/');
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
// ===========================================================================
|
|
371
|
+
// AC9: Error resilience — continue if write fails
|
|
372
|
+
// ===========================================================================
|
|
373
|
+
describe('AC9: Error resilience', () => {
|
|
374
|
+
it('should return error result for invalid work directory', async () => {
|
|
375
|
+
const badConfig = {
|
|
376
|
+
...DEFAULT_CONFIG,
|
|
377
|
+
workDir: '/nonexistent/path/that/does/not/exist',
|
|
378
|
+
};
|
|
379
|
+
const result = await detectFileChanges(badConfig);
|
|
380
|
+
// Should return error result, not throw
|
|
381
|
+
assert.strictEqual(result.success, false);
|
|
382
|
+
assert.ok(result.error, 'Should have error message');
|
|
383
|
+
});
|
|
384
|
+
it('startFileWatcher should continue polling after observation write error', async () => {
|
|
385
|
+
// Use a non-existent observation file path to trigger write errors
|
|
386
|
+
const watchResult = await startFileWatcher({
|
|
387
|
+
...DEFAULT_CONFIG,
|
|
388
|
+
observationFilePath: '/nonexistent/obs.md',
|
|
389
|
+
});
|
|
390
|
+
assert.ok(watchResult.success, 'Watcher should start even with bad observation path');
|
|
391
|
+
assert.ok(watchResult.data);
|
|
392
|
+
// Create a file — should trigger detection but write will fail
|
|
393
|
+
writeFileSync(join(WORK_DIR, 'resilient.ts'), 'content');
|
|
394
|
+
// Wait for a few poll cycles — watcher should NOT crash
|
|
395
|
+
await new Promise(resolve => setTimeout(resolve, DEFAULT_POLL_MS * 5));
|
|
396
|
+
// Watcher should still be alive (stopFileWatcher should succeed)
|
|
397
|
+
const stopResult = await stopFileWatcher(watchResult.data);
|
|
398
|
+
assert.ok(stopResult.success, 'Should stop cleanly even after write errors');
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
// ===========================================================================
|
|
402
|
+
// AC10: Returns result objects per framework pattern
|
|
403
|
+
// ===========================================================================
|
|
404
|
+
describe('AC10: Result objects', () => {
|
|
405
|
+
it('detectFileChanges should return {success, data?, error?}', async () => {
|
|
406
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
407
|
+
assert.ok(typeof result === 'object');
|
|
408
|
+
assert.ok('success' in result, 'Result must have success field');
|
|
409
|
+
if (result.success) {
|
|
410
|
+
assert.ok('data' in result || result.data === undefined, 'Successful result may have data');
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
assert.ok('error' in result, 'Failed result must have error');
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
it('startFileWatcher should return {success, data?: FileWatchHandle, error?}', async () => {
|
|
417
|
+
const result = await startFileWatcher(DEFAULT_CONFIG);
|
|
418
|
+
assert.ok(typeof result === 'object');
|
|
419
|
+
assert.ok('success' in result);
|
|
420
|
+
if (result.success && result.data) {
|
|
421
|
+
assert.ok('handle' in result.data || 'stop' in result.data || typeof result.data === 'object', 'Handle should be an object');
|
|
422
|
+
await stopFileWatcher(result.data);
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
it('stopFileWatcher should return {success, error?}', async () => {
|
|
426
|
+
const watchResult = await startFileWatcher(DEFAULT_CONFIG);
|
|
427
|
+
assert.ok(watchResult.success);
|
|
428
|
+
assert.ok(watchResult.data);
|
|
429
|
+
const stopResult = await stopFileWatcher(watchResult.data);
|
|
430
|
+
assert.ok(typeof stopResult === 'object');
|
|
431
|
+
assert.ok('success' in stopResult);
|
|
432
|
+
assert.ok(stopResult.success);
|
|
433
|
+
});
|
|
434
|
+
});
|
|
435
|
+
// ===========================================================================
|
|
436
|
+
// Edge cases
|
|
437
|
+
// ===========================================================================
|
|
438
|
+
describe('Edge cases', () => {
|
|
439
|
+
it('should handle empty working directory gracefully', async () => {
|
|
440
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
441
|
+
assert.ok(result.success);
|
|
442
|
+
assert.ok(Array.isArray(result.data));
|
|
443
|
+
assert.strictEqual(result.data.length, 0, 'No changes in empty directory');
|
|
444
|
+
});
|
|
445
|
+
it('should handle rapid successive file changes', async () => {
|
|
446
|
+
const baseline = await detectFileChanges(DEFAULT_CONFIG);
|
|
447
|
+
assert.ok(baseline.success);
|
|
448
|
+
// Create many files rapidly
|
|
449
|
+
for (let i = 0; i < 10; i++) {
|
|
450
|
+
writeFileSync(join(WORK_DIR, `rapid-${i}.ts`), `content ${i}`);
|
|
451
|
+
}
|
|
452
|
+
const result = await detectFileChanges(DEFAULT_CONFIG);
|
|
453
|
+
assert.ok(result.success);
|
|
454
|
+
assert.ok(result.data);
|
|
455
|
+
assert.strictEqual(result.data.length, 10, `Expected 10 changes, got ${result.data.length}`);
|
|
456
|
+
});
|
|
457
|
+
it('stopFileWatcher should be idempotent', async () => {
|
|
458
|
+
const watchResult = await startFileWatcher(DEFAULT_CONFIG);
|
|
459
|
+
assert.ok(watchResult.success);
|
|
460
|
+
assert.ok(watchResult.data);
|
|
461
|
+
// Stop twice — second should not throw
|
|
462
|
+
const stop1 = await stopFileWatcher(watchResult.data);
|
|
463
|
+
assert.ok(stop1.success);
|
|
464
|
+
const stop2 = await stopFileWatcher(watchResult.data);
|
|
465
|
+
assert.ok(stop2.success, 'Second stop should also succeed (idempotent)');
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
//# sourceMappingURL=file-watch.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-watch.test.js","sourceRoot":"","sources":["../../src/workflow/file-watch.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observation File Writer for Story 95-3
|
|
3
|
+
*
|
|
4
|
+
* Creates and appends to observation files used by tandem backseat agents.
|
|
5
|
+
* Files are append-only markdown at `.session/{storyId}-tandem-{agent}.md`.
|
|
6
|
+
* Each write is entry-atomic — the file remains valid markdown on crash.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Configuration for initializing an observation file
|
|
10
|
+
*/
|
|
11
|
+
export interface ObservationWriterConfig {
|
|
12
|
+
/** Current story ID */
|
|
13
|
+
storyId: string;
|
|
14
|
+
/** Observer agent name */
|
|
15
|
+
agent: string;
|
|
16
|
+
/** Observer persona name */
|
|
17
|
+
persona: string;
|
|
18
|
+
/** Current workflow phase */
|
|
19
|
+
phase: string;
|
|
20
|
+
/** Path to .session/ directory */
|
|
21
|
+
sessionDir: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* A single observation entry to append
|
|
25
|
+
*/
|
|
26
|
+
export interface ObservationEntry {
|
|
27
|
+
/** Trigger type: file-watch, tool-watch, context-watch */
|
|
28
|
+
triggerType: string;
|
|
29
|
+
/** Trigger detail, e.g. "src/foo.ts modified" */
|
|
30
|
+
triggerDetail: string;
|
|
31
|
+
/** The observation text */
|
|
32
|
+
observation: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Standard result object per framework pattern
|
|
36
|
+
*/
|
|
37
|
+
export interface ObservationResult<T = unknown> {
|
|
38
|
+
success: boolean;
|
|
39
|
+
data?: T;
|
|
40
|
+
error?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ObservationFileHeader {
|
|
43
|
+
storyId: string;
|
|
44
|
+
observer: string;
|
|
45
|
+
phase: string;
|
|
46
|
+
started: string;
|
|
47
|
+
}
|
|
48
|
+
export interface ParsedObservationEntry {
|
|
49
|
+
timestamp: string;
|
|
50
|
+
triggerType: string;
|
|
51
|
+
triggerDetail: string;
|
|
52
|
+
observation: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Initialize an observation file with header metadata.
|
|
56
|
+
*
|
|
57
|
+
* Creates the file at `.session/{storyId}-tandem-{agent}.md` with
|
|
58
|
+
* a header containing observer agent, persona, phase, and start timestamp.
|
|
59
|
+
*/
|
|
60
|
+
export declare function initObservationFile(config: ObservationWriterConfig): ObservationResult<{
|
|
61
|
+
path: string;
|
|
62
|
+
}>;
|
|
63
|
+
/**
|
|
64
|
+
* Append an observation entry to an existing observation file.
|
|
65
|
+
*
|
|
66
|
+
* Each append is entry-atomic: the complete entry (separator, timestamp,
|
|
67
|
+
* trigger, observation text) is written in a single operation.
|
|
68
|
+
*/
|
|
69
|
+
export declare function appendObservation(filePath: string, entry: ObservationEntry): ObservationResult;
|
|
70
|
+
/**
|
|
71
|
+
* Parse an observation file and return its entries.
|
|
72
|
+
*
|
|
73
|
+
* Used by bell mode to read recent observations for injection.
|
|
74
|
+
*/
|
|
75
|
+
export declare function parseObservationFile(filePath: string): ObservationResult<{
|
|
76
|
+
header: ObservationFileHeader;
|
|
77
|
+
entries: ParsedObservationEntry[];
|
|
78
|
+
}>;
|
|
79
|
+
//# sourceMappingURL=observation-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observation-writer.d.ts","sourceRoot":"","sources":["../../src/workflow/observation-writer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,aAAa,EAAE,MAAM,CAAC;IACtB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,OAAO;IAC5C,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAMD,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAMD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,uBAAuB,GAC9B,iBAAiB,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBrC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,gBAAgB,GACtB,iBAAiB,CAkBnB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,GACf,iBAAiB,CAAC;IAAE,MAAM,EAAE,qBAAqB,CAAC;IAAC,OAAO,EAAE,sBAAsB,EAAE,CAAA;CAAE,CAAC,CAsCzF"}
|