@pennyfarthing/core 11.2.0 → 11.2.1
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 +1 -1
- package/package.json +2 -1
- package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/doctor.js +381 -66
- package/packages/core/dist/cli/commands/doctor.js.map +1 -1
- package/packages/core/dist/cli/commands/init.js +4 -4
- package/packages/core/dist/cli/commands/init.js.map +1 -1
- package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/update.js +4 -5
- package/packages/core/dist/cli/commands/update.js.map +1 -1
- package/packages/core/dist/cli/utils/constants.d.ts +3 -8
- package/packages/core/dist/cli/utils/constants.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/constants.js +3 -4
- package/packages/core/dist/cli/utils/constants.js.map +1 -1
- package/packages/core/dist/cli/utils/settings.d.ts +11 -0
- package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/settings.js +65 -29
- package/packages/core/dist/cli/utils/settings.js.map +1 -1
- package/packages/core/dist/cli/utils/symlinks.js +16 -16
- package/packages/core/dist/cli/utils/symlinks.js.map +1 -1
- package/packages/core/dist/consultation/tandem-metrics.d.ts +91 -0
- package/packages/core/dist/consultation/tandem-metrics.d.ts.map +1 -0
- package/packages/core/dist/consultation/tandem-metrics.js +131 -0
- package/packages/core/dist/consultation/tandem-metrics.js.map +1 -0
- package/packages/core/dist/consultation/tandem-metrics.test.d.ts +18 -0
- package/packages/core/dist/consultation/tandem-metrics.test.d.ts.map +1 -0
- package/packages/core/dist/consultation/tandem-metrics.test.js +457 -0
- package/packages/core/dist/consultation/tandem-metrics.test.js.map +1 -0
- package/packages/core/dist/public/js/react/react.js +14 -14
- package/packages/core/dist/scripts/benchmark-integration.d.ts +182 -0
- package/packages/core/dist/scripts/benchmark-integration.d.ts.map +1 -0
- package/packages/core/dist/scripts/benchmark-integration.js +691 -0
- package/packages/core/dist/scripts/benchmark-integration.js.map +1 -0
- package/packages/core/dist/scripts/job-fair-aggregator.d.ts +150 -0
- package/packages/core/dist/scripts/job-fair-aggregator.d.ts.map +1 -0
- package/packages/core/dist/scripts/job-fair-aggregator.js +547 -0
- package/packages/core/dist/scripts/job-fair-aggregator.js.map +1 -0
- package/packages/core/dist/server/api/agent-load.js +1 -1
- package/packages/core/dist/server/api/agent-load.js.map +1 -1
- package/packages/core/dist/server/server.d.ts +0 -3
- package/packages/core/dist/server/server.d.ts.map +1 -1
- package/packages/core/dist/server/server.js +3 -37
- package/packages/core/dist/server/server.js.map +1 -1
- package/packages/core/dist/server/server.test.d.ts +1 -1
- package/packages/core/dist/server/server.test.js +12 -23
- package/packages/core/dist/server/server.test.js.map +1 -1
- package/packages/core/dist/shared/capabilities.d.ts +88 -0
- package/packages/core/dist/shared/capabilities.d.ts.map +1 -0
- package/packages/core/dist/shared/capabilities.js +133 -0
- package/packages/core/dist/shared/capabilities.js.map +1 -0
- package/packages/core/dist/shared/capabilities.test.d.ts +2 -0
- package/packages/core/dist/shared/capabilities.test.d.ts.map +1 -0
- package/packages/core/dist/shared/capabilities.test.js +217 -0
- package/packages/core/dist/shared/capabilities.test.js.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.d.ts +47 -0
- package/packages/core/dist/shared/spawn-prompt.d.ts.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.js +82 -0
- package/packages/core/dist/shared/spawn-prompt.js.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.test.d.ts +2 -0
- package/packages/core/dist/shared/spawn-prompt.test.d.ts.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.test.js +251 -0
- package/packages/core/dist/shared/spawn-prompt.test.js.map +1 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts +18 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.js +434 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.js.map +1 -0
- package/packages/core/dist/workflow/workflow-schema.d.ts +32 -0
- package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.js +120 -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 +570 -1
- package/packages/core/dist/workflow/workflow-schema.test.js.map +1 -1
- package/pennyfarthing-dist/agents/dev.md +6 -10
- package/pennyfarthing-dist/agents/reviewer.md +8 -2
- package/pennyfarthing-dist/agents/sm-finish.md +18 -1
- package/pennyfarthing-dist/commands/pf-git.md +4 -2
- package/pennyfarthing-dist/gates/approval.md +63 -0
- package/pennyfarthing-dist/gates/confidence-sm.md +71 -0
- package/pennyfarthing-dist/gates/context-ok.md +56 -0
- package/pennyfarthing-dist/gates/evaluations/confidence-sm.md +54 -0
- package/pennyfarthing-dist/gates/quality-pass.md +67 -0
- package/pennyfarthing-dist/gates/tests-fail.md +84 -0
- package/pennyfarthing-dist/gates/tests-pass.md +79 -0
- package/pennyfarthing-dist/guides/agent-behavior.md +23 -19
- package/pennyfarthing-dist/guides/bell-mode.md +1 -1
- package/pennyfarthing-dist/guides/hooks.md +28 -28
- package/pennyfarthing-dist/guides/reflector.md +1 -1
- package/pennyfarthing-dist/guides/tandem-protocol.md +3 -3
- package/pennyfarthing-dist/scripts/core/check-context.sh +2 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +5 -87
- package/pennyfarthing-dist/scripts/hooks/README.md +5 -5
- package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +4 -183
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +4 -95
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +4 -65
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +3 -31
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +27 -33
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +4 -71
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +3 -19
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +4 -30
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +3 -32
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +4 -65
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +4 -78
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +4 -93
- package/pennyfarthing-dist/scripts/misc/README.md +1 -1
- package/pennyfarthing-dist/scripts/misc/statusline.sh +4 -301
- package/pennyfarthing-dist/templates/settings.local.json.template +19 -10
- package/pennyfarthing-dist/workflows/tdd.yaml +11 -2
- package/pennyfarthing_scripts/CLAUDE.md +19 -10
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -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__/context.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira.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__/pretooluse_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/session_start_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/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bellmode_hook.py +12 -296
- 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__/audit_log_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/context_meter_footer.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/events.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/audit_log_panel.py +119 -0
- package/pennyfarthing_scripts/bikerack/base_panel.py +27 -4
- package/pennyfarthing_scripts/bikerack/changed_panel.py +96 -4
- package/pennyfarthing_scripts/bikerack/context_meter_footer.py +88 -0
- package/pennyfarthing_scripts/bikerack/debug_panel.py +1 -1
- package/pennyfarthing_scripts/bikerack/diffs_panel.py +30 -0
- package/pennyfarthing_scripts/bikerack/events.py +28 -0
- package/pennyfarthing_scripts/bikerack/portrait_resolver.py +139 -0
- package/pennyfarthing_scripts/bikerack/sprint_panel.py +373 -142
- package/pennyfarthing_scripts/bikerack/story_detail_data.py +244 -0
- package/pennyfarthing_scripts/bikerack/story_detail_screen.py +176 -0
- package/pennyfarthing_scripts/bikerack/tui.py +293 -61
- 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/cli.py +5 -0
- 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/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/pr_config.py +38 -0
- 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/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__pycache__/dialogue_manager.cpython-314.pyc +0 -0
- 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/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/epic/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-314.pyc +0 -0
- 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_group/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/gate_file.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/gate_runner.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/marker.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/cli.py +33 -1
- package/pennyfarthing_scripts/handoff/complete_phase.py +28 -0
- package/pennyfarthing_scripts/handoff/marker.py +15 -15
- package/pennyfarthing_scripts/handoff/phase_check.py +96 -0
- package/pennyfarthing_scripts/handoff/resolve_gate.py +13 -1
- 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/hooks/__init__.py +437 -0
- package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/bell_mode.py +215 -0
- package/pennyfarthing_scripts/hooks/cli.py +96 -0
- package/pennyfarthing_scripts/hooks/context_breaker.py +104 -0
- package/pennyfarthing_scripts/hooks/context_warning.py +66 -0
- package/pennyfarthing_scripts/hooks/cyclist_pretooluse.py +129 -0
- package/pennyfarthing_scripts/hooks/pre_edit_check.py +78 -0
- package/pennyfarthing_scripts/hooks/reflector_check.py +271 -0
- package/pennyfarthing_scripts/hooks/schema_validation.py +203 -0
- package/pennyfarthing_scripts/hooks/session_start.py +296 -0
- package/pennyfarthing_scripts/hooks/session_stop.py +111 -0
- package/pennyfarthing_scripts/hooks/sprint_yaml_validation.py +97 -0
- package/pennyfarthing_scripts/hooks/statusline.py +420 -0
- package/pennyfarthing_scripts/hooks.py +27 -432
- 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/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__/compat.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__/mappings.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/models.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/launch/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/__init__.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/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/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/pretooluse_hook.py +3 -185
- package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/__main__.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__/version_sentinel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/workflow.py +2 -1
- package/pennyfarthing_scripts/schema_validation_hook.py +3 -298
- package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/session/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/session_start_hook.py +4 -186
- 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__/epic_update.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/story_update.py +19 -0
- 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/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_108_1_gate_migration.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_archive_epic.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bc.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_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_cli_normalization.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_confidence_sm_evaluation.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_gate.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_dialogue_manager.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_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_handoff_e2e.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_panel.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_topology_loader.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tui_focus.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tui_panel_persistence.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_version_sentinel.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_workflow_cli.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/test_sprint_panel.py +344 -265
- 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/validate/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +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__/tandem_awareness.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/workflow.py +19 -0
- package/pennyfarthing_scripts/welcome_hook.py +3 -149
- package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/cli.py +7 -6
- package/pennyfarthing_scripts/workflow/team_lifecycle.py +257 -0
- package/packages/core/dist/scripts/theme-detail.test.d.ts +0 -10
- package/packages/core/dist/scripts/theme-detail.test.js +0 -199
- package/pennyfarthing_scripts/bikerack/__pycache__/portrait.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/gate/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/gate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/gate/__pycache__/validate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/hooks_installer.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/repos.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/worktree.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/heatmap.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_108_2_remove_handoff_fallback.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_gate_file_resolution.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_gate_runner.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_resolve_gate_file_field.cpython-314-pytest-9.0.2.pyc +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<gate name="tests-pass" model="haiku">
|
|
2
|
+
|
|
3
|
+
<purpose>
|
|
4
|
+
Verify that all tests pass and the working tree is clean before handing off
|
|
5
|
+
to the reviewer. This gate runs after the Dev agent's implementation phase
|
|
6
|
+
to confirm the codebase is in a GREEN state.
|
|
7
|
+
</purpose>
|
|
8
|
+
|
|
9
|
+
<pass>
|
|
10
|
+
Run these checks and report results:
|
|
11
|
+
|
|
12
|
+
1. **Test suite:** Run the project test suite for the repos listed in the session file.
|
|
13
|
+
- For `pennyfarthing` repo: `cd pennyfarthing && pnpm test`
|
|
14
|
+
- For `orchestrator` repo: tests in the orchestrator root if applicable
|
|
15
|
+
- Record: total tests, passed, failed, skipped
|
|
16
|
+
|
|
17
|
+
2. **Working tree:** Run `git status --porcelain` in each repo listed in session `**Repos:**`.
|
|
18
|
+
- Verify no uncommitted or untracked files (empty output = clean)
|
|
19
|
+
|
|
20
|
+
3. **Branch status:** Run `git branch --show-current` and `git log --oneline -1`.
|
|
21
|
+
- Confirm on the expected feature branch from session `**Branch:**`
|
|
22
|
+
|
|
23
|
+
If ALL checks pass, return:
|
|
24
|
+
|
|
25
|
+
```yaml
|
|
26
|
+
GATE_RESULT:
|
|
27
|
+
status: pass
|
|
28
|
+
gate: tests-pass
|
|
29
|
+
message: "All {N} tests passing. Working tree clean. Branch: {branch}"
|
|
30
|
+
checks:
|
|
31
|
+
- name: test-suite
|
|
32
|
+
status: pass
|
|
33
|
+
detail: "{passed}/{total} tests passing ({skipped} skipped)"
|
|
34
|
+
- name: working-tree
|
|
35
|
+
status: pass
|
|
36
|
+
detail: "No uncommitted changes"
|
|
37
|
+
- name: branch-status
|
|
38
|
+
status: pass
|
|
39
|
+
detail: "On branch {branch}, HEAD at {short-sha}"
|
|
40
|
+
```
|
|
41
|
+
</pass>
|
|
42
|
+
|
|
43
|
+
<fail>
|
|
44
|
+
If ANY check fails, diagnose and report:
|
|
45
|
+
|
|
46
|
+
1. **Failing tests:** List each failing test file and line number.
|
|
47
|
+
- Run tests with verbose output to capture failure details.
|
|
48
|
+
- Group failures by file.
|
|
49
|
+
|
|
50
|
+
2. **Dirty working tree:** List uncommitted and untracked files.
|
|
51
|
+
- Run `git status --porcelain` and report each file with its status code.
|
|
52
|
+
|
|
53
|
+
3. **Wrong branch:** Report actual vs expected branch name.
|
|
54
|
+
|
|
55
|
+
Return with actionable recovery guidance:
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
GATE_RESULT:
|
|
59
|
+
status: fail
|
|
60
|
+
gate: tests-pass
|
|
61
|
+
message: "Gate failed: {summary of failures}"
|
|
62
|
+
checks:
|
|
63
|
+
- name: test-suite
|
|
64
|
+
status: pass | fail
|
|
65
|
+
detail: "{description of test results or failures}"
|
|
66
|
+
- name: working-tree
|
|
67
|
+
status: pass | fail
|
|
68
|
+
detail: "{list of uncommitted files, or 'clean'}"
|
|
69
|
+
- name: branch-status
|
|
70
|
+
status: pass | fail
|
|
71
|
+
detail: "{branch info or mismatch details}"
|
|
72
|
+
recovery:
|
|
73
|
+
- "Fix failing tests in: {file1}, {file2}"
|
|
74
|
+
- "Commit or stash uncommitted changes before handoff"
|
|
75
|
+
- "Switch to correct branch: git checkout {expected-branch}"
|
|
76
|
+
```
|
|
77
|
+
</fail>
|
|
78
|
+
|
|
79
|
+
</gate>
|
|
@@ -49,7 +49,7 @@ On activation, check session file for a `**Tandem:**` line (e.g., `**Tandem:** a
|
|
|
49
49
|
|
|
50
50
|
**If tandem is configured:**
|
|
51
51
|
|
|
52
|
-
1. **Resolve backseat persona** from theme
|
|
52
|
+
1. **Resolve backseat persona** from theme using the `pf theme`
|
|
53
53
|
```bash
|
|
54
54
|
THEME=$(yq '.theme' .pennyfarthing/config.local.yaml)
|
|
55
55
|
PARTNER_CHARACTER=$(yq ".agents.{PARTNER}.character" .pennyfarthing/personas/themes/${THEME}.yaml)
|
|
@@ -98,16 +98,17 @@ See `.pennyfarthing/guides/tandem-protocol.md` for full protocol details.
|
|
|
98
98
|
## Reflector
|
|
99
99
|
|
|
100
100
|
<critical>
|
|
101
|
-
**EVERY TURN MUST END WITH A CYCLIST MARKER
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
101
|
+
**Cyclist only:** EVERY TURN MUST END WITH A CYCLIST MARKER. Stop hook enforces this.
|
|
102
|
+
**CLI mode:** Do NOT emit CYCLIST markers — they are inert outside Cyclist.
|
|
103
|
+
|
|
104
|
+
| Situation | Cyclist Marker | CLI Behavior |
|
|
105
|
+
|-----------|---------------|--------------|
|
|
106
|
+
| Workflow handoff | `<!-- CYCLIST:HANDOFF:/agent -->` | Use AGENT_COMMAND `action` field |
|
|
107
|
+
| Handoff + context >80% | `<!-- CYCLIST:CONTEXT_CLEAR:/agent -->` | Tell user to `/clear` then run agent |
|
|
108
|
+
| Yes/no question | `<!-- CYCLIST:QUESTION:yesno -->` | Ask user directly |
|
|
109
|
+
| Open-ended question | `<!-- CYCLIST:QUESTION:open -->` | Ask user directly |
|
|
110
|
+
| Multiple choice | `<!-- CYCLIST:CHOICES:a,b,c -->` | Ask user directly |
|
|
111
|
+
| Everything else | `<!-- CYCLIST:CONTINUE -->` | (no marker needed) |
|
|
111
112
|
</critical>
|
|
112
113
|
|
|
113
114
|
---
|
|
@@ -124,7 +125,12 @@ See `.pennyfarthing/guides/tandem-protocol.md` for full protocol details.
|
|
|
124
125
|
- If fail → fix issues, retry from step 3 (max 3 retries)
|
|
125
126
|
- If pass → continue
|
|
126
127
|
7. `pf handoff complete-phase {story-id} {workflow} {from} {to} {gate-type}`
|
|
127
|
-
8. `pf handoff marker {next_agent}` →
|
|
128
|
+
8. `pf handoff marker {next_agent}` → AGENT_COMMAND block
|
|
129
|
+
9. **Act on AGENT_COMMAND:**
|
|
130
|
+
- Has `marker:` field → emit the CYCLIST marker (Cyclist path)
|
|
131
|
+
- `action: "inline_handoff"` → run `activation_command` via Bash, output result, adopt new agent identity
|
|
132
|
+
- `action: "tirepump_handoff"` → tell user: "Context is high. Run `/clear` then `{fallback}`"
|
|
133
|
+
- No action, no marker → output `fallback` text and EXIT
|
|
128
134
|
|
|
129
135
|
**Agents drive exit directly — no handoff subagent.** Scripts handle routing and session updates atomically.
|
|
130
136
|
</agent-exit-protocol>
|
|
@@ -135,14 +141,12 @@ See `.pennyfarthing/guides/tandem-protocol.md` for full protocol details.
|
|
|
135
141
|
On activation, check if story phase belongs to you:
|
|
136
142
|
|
|
137
143
|
```bash
|
|
138
|
-
|
|
139
|
-
# If OWNER != your agent → emit handoff marker and EXIT
|
|
144
|
+
pf handoff phase-check {your_agent_name}
|
|
140
145
|
```
|
|
141
146
|
|
|
142
|
-
|
|
143
|
-
```
|
|
144
|
-
<!-- CYCLIST:HANDOFF:/{OWNER} -->
|
|
147
|
+
If result has `action: "redirect"`:
|
|
145
148
|
|
|
146
|
-
|
|
147
|
-
|
|
149
|
+
- **Cyclist:** Emit `<!-- CYCLIST:HANDOFF:/{phase_owner} -->` and EXIT
|
|
150
|
+
- **CLI + relay ON:** Run `pf agent start {phase_owner} --tier handoff --quiet` via Bash, adopt new identity
|
|
151
|
+
- **CLI + relay OFF:** Output `Run /pf-{phase_owner} to continue` and EXIT
|
|
148
152
|
</wrong-phase-detection>
|
|
@@ -26,7 +26,7 @@ User queues message in Editor
|
|
|
26
26
|
|------|---------|
|
|
27
27
|
| `packages/cyclist/src/bell-mode.ts` | State management: `isBellModeEnabled()`, `setBellMode()`, `toggleBellMode()` |
|
|
28
28
|
| `packages/cyclist/src/api/bell.ts` | WebSocket broadcast of bell-consumed events |
|
|
29
|
-
| `
|
|
29
|
+
| `pf hooks bell-mode` | PostToolUse hook — reads queue, returns `additionalContext` |
|
|
30
30
|
| `packages/cyclist/src/public/hooks/useMessageQueue.ts` | React hook: `queueMessage()`, `dequeueMessage()`, `injectMessage()`, `handleTurnComplete()` |
|
|
31
31
|
| `packages/cyclist/src/public/contexts/MessageQueueContext.tsx` | Shared React context (single queue instance across components) |
|
|
32
32
|
| `packages/cyclist/src/public/components/ControlBar.tsx` | Bell mode toggle button |
|
|
@@ -4,7 +4,7 @@ Pennyfarthing uses Claude Code hooks to integrate with session lifecycle events
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
Hooks are
|
|
7
|
+
Hooks are commands that Claude Code runs at specific events:
|
|
8
8
|
|
|
9
9
|
| Hook Type | When It Runs | Purpose |
|
|
10
10
|
|-----------|--------------|---------|
|
|
@@ -16,18 +16,18 @@ Hooks are shell scripts that Claude Code runs at specific events:
|
|
|
16
16
|
|
|
17
17
|
### SessionStart Hooks
|
|
18
18
|
|
|
19
|
-
#### session-start
|
|
19
|
+
#### pf hooks session-start
|
|
20
20
|
|
|
21
|
-
**Location:**
|
|
21
|
+
**Location:** `pf hooks session-start`
|
|
22
22
|
|
|
23
23
|
Initializes the Pennyfarthing environment:
|
|
24
24
|
- Creates `.session/` directory structure
|
|
25
25
|
- Clears stale agent state from previous sessions
|
|
26
26
|
- Sets `PROJECT_ROOT` and `SESSION_ID` environment variables
|
|
27
27
|
|
|
28
|
-
#### session-stop
|
|
28
|
+
#### pf hooks session-stop
|
|
29
29
|
|
|
30
|
-
**Location:**
|
|
30
|
+
**Location:** `pf hooks session-stop`
|
|
31
31
|
|
|
32
32
|
Cleans up session state when Claude Code exits.
|
|
33
33
|
|
|
@@ -46,66 +46,66 @@ Project-specific environment setup. Edit this file to:
|
|
|
46
46
|
|
|
47
47
|
Auto-configures OTEL telemetry for Cyclist web mode. Checks for a `.wheelhub-port` file and sets `OTEL_EXPORTER_OTLP_PROTOCOL` and `OTEL_EXPORTER_OTLP_ENDPOINT` to route Claude Code telemetry to the running Cyclist/BikeRack server.
|
|
48
48
|
|
|
49
|
-
#### welcome
|
|
49
|
+
#### pf hooks session-start (welcome)
|
|
50
50
|
|
|
51
|
-
**Location:**
|
|
51
|
+
**Location:** `pf hooks session-start`
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Welcome display is now folded into `pf hooks session-start`. In CLI mode, shows ASCII art. In Cyclist mode, sends a WebSocket message to display the logo. Runs once per session (lock file guard).
|
|
54
54
|
|
|
55
55
|
### PreToolUse Hooks
|
|
56
56
|
|
|
57
|
-
#### pre-edit-check
|
|
57
|
+
#### pf hooks pre-edit-check
|
|
58
58
|
|
|
59
|
-
**Location:**
|
|
59
|
+
**Location:** `pf hooks pre-edit-check`
|
|
60
60
|
|
|
61
61
|
Protects sensitive files from accidental edits:
|
|
62
62
|
- Blocks: `.env`, `.pem`, `.key`, credentials, secrets
|
|
63
63
|
- Blocks: `.git/`, `node_modules/`, `vendor/`
|
|
64
64
|
- Blocks: `.pennyfarthing/*` (managed files)
|
|
65
65
|
|
|
66
|
-
#### cyclist-pretooluse
|
|
66
|
+
#### pf hooks cyclist-pretooluse
|
|
67
67
|
|
|
68
|
-
**Location:**
|
|
68
|
+
**Location:** `pf hooks cyclist-pretooluse`
|
|
69
69
|
|
|
70
70
|
Cyclist-specific pre-tool validation. Runs additional safety checks when operating inside Cyclist.
|
|
71
71
|
|
|
72
|
-
#### context-warning
|
|
72
|
+
#### pf hooks context-warning
|
|
73
73
|
|
|
74
|
-
**Location:**
|
|
74
|
+
**Location:** `pf hooks context-warning`
|
|
75
75
|
|
|
76
76
|
Warns agents when context usage is high. Outputs a warning at 60% usage and a critical warning at 85%. Never blocks — warning only (always exits 0).
|
|
77
77
|
|
|
78
|
-
#### context-
|
|
78
|
+
#### pf hooks context-breaker
|
|
79
79
|
|
|
80
|
-
**Location:**
|
|
80
|
+
**Location:** `pf hooks context-breaker`
|
|
81
81
|
|
|
82
|
-
Hard stop when context reaches 80% (configurable via `CRITICAL_THRESHOLD`). Unlike `context-warning
|
|
82
|
+
Hard stop when context reaches 80% (configurable via `CRITICAL_THRESHOLD`). Unlike `pf hooks context-warning`, this **blocks tool execution** (exit 2). Auto-saves the active agent to a checkpoint so `/pf-session continue` can restore it with FULL tier context.
|
|
83
83
|
|
|
84
|
-
#### schema-validation
|
|
84
|
+
#### pf hooks schema-validation
|
|
85
85
|
|
|
86
|
-
**Location:**
|
|
86
|
+
**Location:** `pf hooks schema-validation`
|
|
87
87
|
|
|
88
88
|
Validates file writes against XML schema rules for agent definitions, workflow files, and other structured content.
|
|
89
89
|
|
|
90
|
-
#### sprint-yaml
|
|
90
|
+
#### pf hooks sprint-yaml
|
|
91
91
|
|
|
92
|
-
**Location:**
|
|
92
|
+
**Location:** `pf hooks sprint-yaml`
|
|
93
93
|
|
|
94
94
|
Validates sprint YAML files on write to prevent structural corruption.
|
|
95
95
|
|
|
96
96
|
### PostToolUse Hooks
|
|
97
97
|
|
|
98
|
-
#### bell-mode
|
|
98
|
+
#### pf hooks bell-mode
|
|
99
99
|
|
|
100
|
-
**Location:**
|
|
100
|
+
**Location:** `pf hooks bell-mode`
|
|
101
101
|
|
|
102
102
|
Bell mode message injection. Checks the bell mode queue and injects queued messages into the agent's context at the next tool execution. Also handles tandem observation injection.
|
|
103
103
|
|
|
104
|
-
####
|
|
104
|
+
#### pf hooks reflector-check
|
|
105
105
|
|
|
106
|
-
**Location:**
|
|
106
|
+
**Location:** `pf hooks reflector-check`
|
|
107
107
|
|
|
108
|
-
Stop hook enforcing that every agent turn ends with a CYCLIST marker. Detects questions, handoff phrases, and validates marker presence. Blocks turns without valid markers in Cyclist mode.
|
|
108
|
+
Stop hook enforcing that every agent turn ends with a CYCLIST marker. Detects questions, handoff phrases, and validates marker presence. Blocks turns without valid markers in Cyclist mode.
|
|
109
109
|
|
|
110
110
|
### Git Hooks
|
|
111
111
|
|
|
@@ -133,7 +133,7 @@ Hooks are configured in `.claude/settings.local.json`:
|
|
|
133
133
|
"hooks": [
|
|
134
134
|
{
|
|
135
135
|
"type": "command",
|
|
136
|
-
"command": "
|
|
136
|
+
"command": "pf hooks session-start"
|
|
137
137
|
}
|
|
138
138
|
]
|
|
139
139
|
}
|
|
@@ -144,7 +144,7 @@ Hooks are configured in `.claude/settings.local.json`:
|
|
|
144
144
|
"hooks": [
|
|
145
145
|
{
|
|
146
146
|
"type": "command",
|
|
147
|
-
"command": "
|
|
147
|
+
"command": "pf hooks pre-edit-check"
|
|
148
148
|
}
|
|
149
149
|
]
|
|
150
150
|
}
|
|
@@ -41,7 +41,7 @@ Marker pattern: /<!--\s*CYCLIST:(\w+)(?::([^>]+?))?\s*-->/gi
|
|
|
41
41
|
| `packages/cyclist/src/public/components/QuickActions.tsx` | Renders action buttons from detected markers |
|
|
42
42
|
| `packages/cyclist/src/public/hooks/useMarkerActions.ts` | Detects markers, builds action metadata |
|
|
43
43
|
| `pennyfarthing-dist/scripts/hooks/question_reflector_check.py` | Stop hook — enforces marker presence |
|
|
44
|
-
| `
|
|
44
|
+
| `pf hooks reflector-check` | CLI entry point for stop hook |
|
|
45
45
|
|
|
46
46
|
## Enforcement Hook
|
|
47
47
|
|
|
@@ -13,7 +13,7 @@ Primary Agent (Opus) Backseat Agent (Haiku, background)
|
|
|
13
13
|
│ │ .session/{story}-tandem-{partner}.md
|
|
14
14
|
│ │
|
|
15
15
|
├── PostToolUse hook fires ────┤
|
|
16
|
-
│ bell-mode
|
|
16
|
+
│ pf hooks bell-mode detects │
|
|
17
17
|
│ new observation, injects │
|
|
18
18
|
│ "[Tandem] Character: ..." │
|
|
19
19
|
│ │
|
|
@@ -163,8 +163,8 @@ For active, synchronous agent-to-agent questions (as opposed to passive observat
|
|
|
163
163
|
| `observation-writer.ts` | Built | TypeScript API for observation file I/O |
|
|
164
164
|
| `file-watch.ts` | Built | File system change detection |
|
|
165
165
|
| `tool-watch.ts` | Built | Tool call log monitoring |
|
|
166
|
-
| `bell-mode
|
|
166
|
+
| `pf hooks bell-mode` | Built | PostToolUse hook with tandem injection |
|
|
167
167
|
| `bellmode_hook.py` | Built | Python implementation of bell mode hook |
|
|
168
|
-
| `statusline
|
|
168
|
+
| `pf hooks statusline` | Built | CLI statusline with tandem indicator |
|
|
169
169
|
| `tandem-backseat.md` | Built | Backseat agent prompt template |
|
|
170
170
|
| `agent-behavior.md` | Built | Shared agent behavior with tandem protocol |
|
|
@@ -1,90 +1,8 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
#
|
|
3
|
-
#
|
|
2
|
+
# DEPRECATED: Use `pf handoff phase-check <agent>` instead.
|
|
3
|
+
# This shim delegates to the Python implementation.
|
|
4
4
|
#
|
|
5
|
-
# Usage:
|
|
6
|
-
# Example: phase-check-start.sh dev
|
|
5
|
+
# Usage: phase-check-start.sh <agent>
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
AGENT="${1:-}"
|
|
11
|
-
|
|
12
|
-
if [[ -z "$AGENT" ]]; then
|
|
13
|
-
echo "Usage: phase-check-start.sh <agent>" >&2
|
|
14
|
-
exit 1
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
# Self-locate and set up PROJECT_ROOT
|
|
18
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
19
|
-
source "$SCRIPT_DIR/../lib/find-root.sh"
|
|
20
|
-
|
|
21
|
-
SCRIPTS_DIR="$SCRIPT_DIR/.."
|
|
22
|
-
SESSION_DIR="$PROJECT_ROOT/.session"
|
|
23
|
-
|
|
24
|
-
# Find active session file
|
|
25
|
-
SESSION_FILE=$(find "$SESSION_DIR" -maxdepth 1 -name "*-session.md" 2>/dev/null | head -1)
|
|
26
|
-
|
|
27
|
-
if [[ -z "$SESSION_FILE" || ! -f "$SESSION_FILE" ]]; then
|
|
28
|
-
# No session - just start the agent normally
|
|
29
|
-
exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
|
|
30
|
-
fi
|
|
31
|
-
|
|
32
|
-
# Extract workflow and phase from session (handles multiple formats)
|
|
33
|
-
# Format 1: **Workflow:** value
|
|
34
|
-
# Format 2: - **Workflow**: value
|
|
35
|
-
WORKFLOW=$(grep -E "\*\*Workflow\*?\*?:" "$SESSION_FILE" 2>/dev/null | head -1 | sed 's/.*\*\*Workflow\*\*[:\*]* *//' | tr -d ' ' || echo "")
|
|
36
|
-
PHASE=$(grep -E "\*\*Phase\*?\*?:" "$SESSION_FILE" 2>/dev/null | head -1 | sed 's/.*\*\*Phase\*\*[:\*]* *//' | tr -d ' ' || echo "")
|
|
37
|
-
|
|
38
|
-
if [[ -z "$WORKFLOW" ]]; then
|
|
39
|
-
# Can't determine workflow - start normally
|
|
40
|
-
exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
|
|
41
|
-
fi
|
|
42
|
-
|
|
43
|
-
# If no Phase field, try to infer from status patterns
|
|
44
|
-
if [[ -z "$PHASE" ]]; then
|
|
45
|
-
# Check for approval status (story is done, needs SM to close)
|
|
46
|
-
if grep -qE "\*\*Status\*\*:.*APPROVED" "$SESSION_FILE" 2>/dev/null; then
|
|
47
|
-
PHASE="approved"
|
|
48
|
-
# Check for review status
|
|
49
|
-
elif grep -qE "Reviewer Assessment|Review.*REJECTED\|Review.*APPROVED" "$SESSION_FILE" 2>/dev/null; then
|
|
50
|
-
PHASE="review"
|
|
51
|
-
# Check for green/implementation complete
|
|
52
|
-
elif grep -qE "Dev Assessment|\*\*Status\*\*:.*GREEN" "$SESSION_FILE" 2>/dev/null; then
|
|
53
|
-
# Has dev assessment - could be in review or approved
|
|
54
|
-
if grep -qE "Reviewer Assessment" "$SESSION_FILE" 2>/dev/null; then
|
|
55
|
-
PHASE="approved" # Reviewer already assessed
|
|
56
|
-
else
|
|
57
|
-
PHASE="review" # Needs reviewer
|
|
58
|
-
fi
|
|
59
|
-
# Check for red/test phase
|
|
60
|
-
elif grep -qE "TEA Assessment|\*\*Status\*\*:.*RED" "$SESSION_FILE" 2>/dev/null; then
|
|
61
|
-
PHASE="green" # TEA done, Dev's turn
|
|
62
|
-
else
|
|
63
|
-
# Can't determine phase - start normally
|
|
64
|
-
exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
|
|
65
|
-
fi
|
|
66
|
-
fi
|
|
67
|
-
|
|
68
|
-
# Get the owner of this phase
|
|
69
|
-
OWNER=$("$SCRIPTS_DIR/workflow/phase-owner.sh" "$WORKFLOW" "$PHASE" 2>/dev/null || echo "")
|
|
70
|
-
|
|
71
|
-
if [[ -z "$OWNER" ]]; then
|
|
72
|
-
# Phase owner lookup failed - start normally
|
|
73
|
-
exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
|
|
74
|
-
fi
|
|
75
|
-
|
|
76
|
-
# Check if this agent owns the phase
|
|
77
|
-
if [[ "$OWNER" == "$AGENT" ]]; then
|
|
78
|
-
# Correct agent - start normally
|
|
79
|
-
exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
|
|
80
|
-
fi
|
|
81
|
-
|
|
82
|
-
# Wrong agent! Output the handoff marker and info
|
|
83
|
-
STORY_ID=$(basename "$SESSION_FILE" -session.md)
|
|
84
|
-
|
|
85
|
-
echo "Phase check: Story $STORY_ID is in '$PHASE' phase (workflow: $WORKFLOW)"
|
|
86
|
-
echo "Phase owner: $OWNER (you requested: $AGENT)"
|
|
87
|
-
echo ""
|
|
88
|
-
|
|
89
|
-
# Generate and output the handoff marker
|
|
90
|
-
pf handoff marker "$OWNER"
|
|
7
|
+
echo "DEPRECATED: phase-check-start.sh — use 'pf handoff phase-check $1' instead" >&2
|
|
8
|
+
exec pf handoff phase-check "$@"
|
|
@@ -6,15 +6,15 @@ Git hooks and Claude Code hooks.
|
|
|
6
6
|
|
|
7
7
|
| Script | Purpose |
|
|
8
8
|
|--------|---------|
|
|
9
|
-
| `context-
|
|
10
|
-
| `context-warning
|
|
9
|
+
| `pf hooks context-breaker` | Claude hook: halt at context limit |
|
|
10
|
+
| `pf hooks context-warning` | Claude hook: warn on high context |
|
|
11
11
|
| `otel-auto-config.sh` | Claude hook: configure OTEL |
|
|
12
12
|
| `post-merge.sh` | Git hook: post-merge actions |
|
|
13
13
|
| `pre-commit.sh` | Git hook: branch protection, agent validation, sprint YAML validation |
|
|
14
|
-
| `pre-edit-check
|
|
14
|
+
| `pf hooks pre-edit-check` | Claude hook: validate before edit |
|
|
15
15
|
| `pre-push.sh` | Git hook: pre-push validation |
|
|
16
|
-
| `session-start
|
|
17
|
-
| `session-stop
|
|
16
|
+
| `pf hooks session-start` | Claude hook: session start |
|
|
17
|
+
| `pf hooks session-stop` | Claude hook: session stop |
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
Binary file
|
|
@@ -1,183 +1,4 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
# Called by Claude Code after each tool execution. Handles two independent
|
|
6
|
-
# injection systems:
|
|
7
|
-
#
|
|
8
|
-
# 1. Bell queue (Cyclist only) — injects queued user messages when Cyclist
|
|
9
|
-
# is running and bell_mode is enabled. In CLI sessions this is a no-op.
|
|
10
|
-
# 2. Tandem observations (always active) — injects backseat agent observations
|
|
11
|
-
# when tandem observation files exist. No configuration required.
|
|
12
|
-
#
|
|
13
|
-
# Bell queue takes precedence: if a queued message exists, tandem is
|
|
14
|
-
# deferred to the next hook invocation.
|
|
15
|
-
#
|
|
16
|
-
# Output format (when injecting):
|
|
17
|
-
# {
|
|
18
|
-
# "hookSpecificOutput": {
|
|
19
|
-
# "hookEventName": "PostToolUse",
|
|
20
|
-
# "additionalContext": "<message>"
|
|
21
|
-
# }
|
|
22
|
-
# }
|
|
23
|
-
#
|
|
24
|
-
# Output when nothing to inject: (nothing - exit 0)
|
|
25
|
-
|
|
26
|
-
# Find project root (walk up to find .pennyfarthing)
|
|
27
|
-
PROJECT_ROOT="$PWD"
|
|
28
|
-
while [[ "$PROJECT_ROOT" != "/" ]]; do
|
|
29
|
-
if [[ -d "$PROJECT_ROOT/.pennyfarthing" ]]; then
|
|
30
|
-
break
|
|
31
|
-
fi
|
|
32
|
-
PROJECT_ROOT="$(dirname "$PROJECT_ROOT")"
|
|
33
|
-
done
|
|
34
|
-
|
|
35
|
-
if [[ ! -d "$PROJECT_ROOT/.pennyfarthing" ]]; then
|
|
36
|
-
exit 0
|
|
37
|
-
fi
|
|
38
|
-
|
|
39
|
-
CONFIG_LOCAL_YAML="$PROJECT_ROOT/.pennyfarthing/config.local.yaml"
|
|
40
|
-
BELL_QUEUE_FILE="$PROJECT_ROOT/.pennyfarthing/bell-queue.json"
|
|
41
|
-
|
|
42
|
-
# Detect Cyclist — bell queue is a Cyclist-only feature
|
|
43
|
-
IS_CYCLIST=false
|
|
44
|
-
CYCLIST_PORT=""
|
|
45
|
-
PORT_FILE="$PROJECT_ROOT/.wheelhub-port"
|
|
46
|
-
if [[ -f "$PORT_FILE" ]]; then
|
|
47
|
-
CYCLIST_PORT=$(cat "$PORT_FILE" 2>/dev/null)
|
|
48
|
-
if [[ -n "$CYCLIST_PORT" ]] && [[ "$CYCLIST_PORT" =~ ^[0-9]+$ ]]; then
|
|
49
|
-
IS_CYCLIST=true
|
|
50
|
-
fi
|
|
51
|
-
fi
|
|
52
|
-
|
|
53
|
-
# --- Bell queue check (Cyclist only, requires bell_mode: true) ---
|
|
54
|
-
# Takes precedence over tandem injection when active.
|
|
55
|
-
|
|
56
|
-
if [[ "$IS_CYCLIST" == "true" ]] && [[ -f "$CONFIG_LOCAL_YAML" ]]; then
|
|
57
|
-
BELL_ENABLED=$(grep -E '^\s*bell_mode:\s*true' "$CONFIG_LOCAL_YAML" 2>/dev/null || true)
|
|
58
|
-
|
|
59
|
-
if [[ -n "$BELL_ENABLED" ]] && [[ -f "$BELL_QUEUE_FILE" ]]; then
|
|
60
|
-
QUEUE_CONTENT=$(cat "$BELL_QUEUE_FILE" 2>/dev/null)
|
|
61
|
-
if [[ -n "$QUEUE_CONTENT" ]] && [[ "$QUEUE_CONTENT" != "[]" ]]; then
|
|
62
|
-
FIRST_MESSAGE_TEXT=$(echo "$QUEUE_CONTENT" | sed -n 's/.*"text"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
|
|
63
|
-
|
|
64
|
-
if [[ -n "$FIRST_MESSAGE_TEXT" ]]; then
|
|
65
|
-
cat << EOF
|
|
66
|
-
{
|
|
67
|
-
"hookSpecificOutput": {
|
|
68
|
-
"hookEventName": "PostToolUse",
|
|
69
|
-
"additionalContext": "User feedback: $FIRST_MESSAGE_TEXT"
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
EOF
|
|
73
|
-
|
|
74
|
-
# Dequeue and notify Cyclist in background
|
|
75
|
-
(
|
|
76
|
-
if command -v jq &> /dev/null; then
|
|
77
|
-
jq 'if length > 0 then .[1:] else [] end' "$BELL_QUEUE_FILE" > "$BELL_QUEUE_FILE.tmp" 2>/dev/null && mv "$BELL_QUEUE_FILE.tmp" "$BELL_QUEUE_FILE"
|
|
78
|
-
fi
|
|
79
|
-
|
|
80
|
-
curl -s -X POST "http://localhost:$CYCLIST_PORT/api/bell-consumed" \
|
|
81
|
-
-H "Content-Type: application/json" \
|
|
82
|
-
-d "{\"text\": \"$FIRST_MESSAGE_TEXT\"}" \
|
|
83
|
-
>/dev/null 2>&1 || true
|
|
84
|
-
) &
|
|
85
|
-
|
|
86
|
-
exit 0
|
|
87
|
-
fi
|
|
88
|
-
fi
|
|
89
|
-
fi
|
|
90
|
-
fi
|
|
91
|
-
|
|
92
|
-
# --- Tandem observation injection ---
|
|
93
|
-
# Always active. No configuration required.
|
|
94
|
-
# Checks .session/*-tandem-*.md files for new observations via mtime comparison.
|
|
95
|
-
|
|
96
|
-
SESSION_DIR="$PROJECT_ROOT/.session"
|
|
97
|
-
if [[ ! -d "$SESSION_DIR" ]]; then
|
|
98
|
-
exit 0
|
|
99
|
-
fi
|
|
100
|
-
|
|
101
|
-
# Find tandem observation files
|
|
102
|
-
TANDEM_FILES=$(find "$SESSION_DIR" -maxdepth 1 -name "*-tandem-*.md" 2>/dev/null)
|
|
103
|
-
if [[ -z "$TANDEM_FILES" ]]; then
|
|
104
|
-
exit 0
|
|
105
|
-
fi
|
|
106
|
-
|
|
107
|
-
# Check each tandem file for new content
|
|
108
|
-
for TANDEM_FILE in $TANDEM_FILES; do
|
|
109
|
-
# Extract agent name from filename: *-tandem-{agent}.md
|
|
110
|
-
AGENT=$(echo "$TANDEM_FILE" | sed -n 's/.*-tandem-\([a-zA-Z_]*\)\.md$/\1/p')
|
|
111
|
-
if [[ -z "$AGENT" ]]; then
|
|
112
|
-
continue
|
|
113
|
-
fi
|
|
114
|
-
|
|
115
|
-
# Get file mtime (portable: stat -f %m on macOS, stat -c %Y on Linux)
|
|
116
|
-
if [[ "$(uname)" == "Darwin" ]]; then
|
|
117
|
-
FILE_MTIME=$(stat -f %m "$TANDEM_FILE" 2>/dev/null)
|
|
118
|
-
else
|
|
119
|
-
FILE_MTIME=$(stat -c %Y "$TANDEM_FILE" 2>/dev/null)
|
|
120
|
-
fi
|
|
121
|
-
if [[ -z "$FILE_MTIME" ]]; then
|
|
122
|
-
continue
|
|
123
|
-
fi
|
|
124
|
-
|
|
125
|
-
# Compare with saved mtime sidecar
|
|
126
|
-
MTIME_SIDECAR="$SESSION_DIR/.tandem-mtime-$AGENT"
|
|
127
|
-
SAVED_MTIME="0"
|
|
128
|
-
if [[ -f "$MTIME_SIDECAR" ]]; then
|
|
129
|
-
SAVED_MTIME=$(cat "$MTIME_SIDECAR" 2>/dev/null)
|
|
130
|
-
fi
|
|
131
|
-
|
|
132
|
-
if [[ "$FILE_MTIME" == "$SAVED_MTIME" ]]; then
|
|
133
|
-
continue
|
|
134
|
-
fi
|
|
135
|
-
|
|
136
|
-
# Read tandem file and extract latest observation
|
|
137
|
-
CONTENT=$(cat "$TANDEM_FILE" 2>/dev/null)
|
|
138
|
-
if [[ -z "$CONTENT" ]]; then
|
|
139
|
-
continue
|
|
140
|
-
fi
|
|
141
|
-
|
|
142
|
-
# Extract persona from header: **Observer:** agent (Persona Name)
|
|
143
|
-
PERSONA=$(echo "$CONTENT" | sed -n 's/.*\*\*Observer:\*\*[[:space:]]*[a-zA-Z_]*[[:space:]]*(\([^)]*\)).*/\1/p' | head -1)
|
|
144
|
-
if [[ -z "$PERSONA" ]]; then
|
|
145
|
-
PERSONA="Unknown"
|
|
146
|
-
fi
|
|
147
|
-
|
|
148
|
-
# Extract latest observation text (last ## [HH:MM] Observation block)
|
|
149
|
-
# Get text between last observation header and trailing ---
|
|
150
|
-
OBS_TEXT=$(echo "$CONTENT" | awk '
|
|
151
|
-
/^## \[[0-9]+:[0-9]+\] Observation/ { found=1; text=""; next }
|
|
152
|
-
found && /^---/ { next }
|
|
153
|
-
found && /^\*\*Trigger:\*\*/ { next }
|
|
154
|
-
found { text = text (text ? "\n" : "") $0 }
|
|
155
|
-
END { if (text) print text }
|
|
156
|
-
' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
157
|
-
|
|
158
|
-
if [[ -z "$OBS_TEXT" ]]; then
|
|
159
|
-
# Update mtime even if no parseable observation
|
|
160
|
-
echo "$FILE_MTIME" > "$MTIME_SIDECAR"
|
|
161
|
-
continue
|
|
162
|
-
fi
|
|
163
|
-
|
|
164
|
-
# Format as [Tandem] prefix and output
|
|
165
|
-
TANDEM_MSG="[Tandem] $PERSONA: $OBS_TEXT"
|
|
166
|
-
|
|
167
|
-
cat << EOF
|
|
168
|
-
{
|
|
169
|
-
"hookSpecificOutput": {
|
|
170
|
-
"hookEventName": "PostToolUse",
|
|
171
|
-
"additionalContext": "$TANDEM_MSG"
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
EOF
|
|
175
|
-
|
|
176
|
-
# Save mtime sidecar
|
|
177
|
-
echo "$FILE_MTIME" > "$MTIME_SIDECAR"
|
|
178
|
-
|
|
179
|
-
# Only inject one tandem observation per hook invocation
|
|
180
|
-
exit 0
|
|
181
|
-
done
|
|
182
|
-
|
|
183
|
-
exit 0
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# DEPRECATED: This script is a shim. Logic has moved to Python.
|
|
3
|
+
# Use: pf hooks bell-mode
|
|
4
|
+
exec pf hooks bell-mode
|