@pennyfarthing/core 10.0.5 → 10.1.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 +9 -7
- package/package.json +15 -11
- package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/doctor.js +251 -4
- package/packages/core/dist/cli/commands/doctor.js.map +1 -1
- package/packages/core/dist/cli/commands/init.d.ts +7 -0
- package/packages/core/dist/cli/commands/init.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/init.js +41 -8
- 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 +26 -0
- package/packages/core/dist/cli/commands/update.js.map +1 -1
- package/packages/core/dist/cli/index.js +1 -1
- package/packages/core/dist/cli/index.js.map +1 -1
- package/packages/core/dist/cli/utils/python.d.ts +22 -0
- package/packages/core/dist/cli/utils/python.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/python.js +102 -0
- package/packages/core/dist/cli/utils/python.js.map +1 -0
- package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/settings.js +10 -0
- package/packages/core/dist/cli/utils/settings.js.map +1 -1
- package/pennyfarthing-dist/agents/README.md +1 -3
- package/pennyfarthing-dist/agents/architect.md +0 -6
- package/pennyfarthing-dist/agents/devops.md +0 -6
- package/pennyfarthing-dist/agents/orchestrator.md +0 -6
- package/pennyfarthing-dist/agents/pm.md +0 -6
- package/pennyfarthing-dist/agents/sm.md +0 -6
- package/pennyfarthing-dist/commands/architect.md +11 -3
- package/pennyfarthing-dist/commands/close-epic.md +24 -131
- package/pennyfarthing-dist/commands/create-theme.md +14 -24
- package/pennyfarthing-dist/commands/dev.md +11 -3
- package/pennyfarthing-dist/commands/devops.md +11 -3
- package/pennyfarthing-dist/commands/health-check.md +1 -3
- package/pennyfarthing-dist/commands/help.md +8 -12
- package/pennyfarthing-dist/commands/list-themes.md +14 -16
- package/pennyfarthing-dist/commands/orchestrator.md +11 -3
- package/pennyfarthing-dist/commands/parallel-work.md +1 -3
- package/pennyfarthing-dist/commands/pm.md +11 -3
- package/pennyfarthing-dist/commands/prime.md +6 -6
- package/pennyfarthing-dist/commands/reviewer.md +11 -3
- package/pennyfarthing-dist/commands/run-ci.md +1 -1
- package/pennyfarthing-dist/commands/set-theme.md +14 -51
- package/pennyfarthing-dist/commands/setup.md +1 -1
- package/pennyfarthing-dist/commands/show-theme.md +14 -16
- package/pennyfarthing-dist/commands/sm.md +11 -3
- package/pennyfarthing-dist/commands/tea.md +11 -3
- package/pennyfarthing-dist/commands/tech-writer.md +11 -3
- package/pennyfarthing-dist/commands/theme-maker.md +14 -671
- package/pennyfarthing-dist/commands/theme.md +95 -0
- package/pennyfarthing-dist/commands/ux-designer.md +11 -3
- package/pennyfarthing-dist/commands/work.md +3 -5
- package/pennyfarthing-dist/guides/agent-coordination.md +11 -13
- package/pennyfarthing-dist/guides/agent-template-tactical.md +2 -3
- package/pennyfarthing-dist/guides/command-tag-taxonomy.md +212 -0
- package/pennyfarthing-dist/guides/hooks.md +5 -5
- package/pennyfarthing-dist/guides/patterns/fan-out-fan-in-pattern.md +3 -3
- package/pennyfarthing-dist/guides/patterns/helper-delegation-pattern.md +9 -59
- package/pennyfarthing-dist/guides/patterns/tdd-flow-pattern.md +4 -5
- package/pennyfarthing-dist/guides/prime.md +2 -2
- package/pennyfarthing-dist/guides/skill-schema.md +4 -4
- package/pennyfarthing-dist/scripts/core/agent-session.sh +6 -2
- package/pennyfarthing-dist/scripts/core/check-context.sh +0 -0
- package/pennyfarthing-dist/scripts/core/handoff-marker.sh +0 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +0 -0
- package/pennyfarthing-dist/scripts/core/prime.sh +8 -10
- package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +0 -0
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +0 -0
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +0 -0
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +8 -6
- package/pennyfarthing-dist/scripts/git/release.sh +0 -0
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +0 -0
- package/pennyfarthing-dist/scripts/health/drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/post-merge.sh +12 -5
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +4 -3
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-push.sh +11 -5
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +0 -0
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/background-tasks.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/common.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/file-lock.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/logging.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/retry.sh +0 -0
- package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +0 -0
- package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/README.md +1 -1
- package/pennyfarthing-dist/scripts/misc/add-short-names.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add_short_names.py +0 -0
- package/pennyfarthing-dist/scripts/misc/backlog.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/check-status.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/find-related-work.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-scan.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-utils.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-ci.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/statusline.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/uninstall.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +1 -2
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +0 -0
- package/pennyfarthing-dist/scripts/story/create-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/size-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/story-template.sh +0 -0
- package/pennyfarthing-dist/scripts/test/ensure-swebench-data.sh +0 -0
- package/pennyfarthing-dist/scripts/test/swebench-judge.py +0 -0
- package/pennyfarthing-dist/scripts/test/test-cache.sh +0 -0
- package/pennyfarthing-dist/scripts/test/test-setup.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +5 -5
- package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +3 -79
- package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/README.md +1 -1
- package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/compute_theme_tiers.py +0 -0
- package/pennyfarthing-dist/scripts/theme/list-themes.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/update-theme-tiers.sh +0 -0
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +0 -1
- package/pennyfarthing-dist/scripts/workflow/check.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/check.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/complete-step.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +62 -17
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +0 -0
- package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +2 -2
- package/pennyfarthing-dist/skills/skill-registry.yaml +20 -16
- package/pennyfarthing-dist/skills/story/scripts/create-story.sh +0 -0
- package/pennyfarthing-dist/skills/story/scripts/size-story.sh +0 -0
- package/pennyfarthing-dist/skills/story/scripts/story-template.sh +0 -0
- package/pennyfarthing-dist/skills/theme/skill.md +290 -75
- package/pennyfarthing-dist/skills/theme-creation/SKILL.md +23 -166
- package/pennyfarthing-dist/skills/workflow/scripts/list-workflows.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/resume-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/show-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/start-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/workflow-status.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/skill.md +4 -4
- package/pennyfarthing-dist/templates/agent-scopes.yaml.template +0 -11
- package/pennyfarthing-dist/templates/auto-load-sm.sh.template +14 -0
- package/pennyfarthing-dist/templates/settings.local.json.template +9 -0
- package/pennyfarthing-dist/workflows/2party-tdd.yaml +399 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +41 -24
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.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/cli.py +15 -0
- package/pennyfarthing_scripts/codemarkers/__init__.py +19 -0
- package/pennyfarthing_scripts/codemarkers/__main__.py +6 -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/codemarkers/analyze.py +326 -0
- package/pennyfarthing_scripts/codemarkers/cli.py +129 -0
- package/pennyfarthing_scripts/codemarkers/formatters.py +89 -0
- package/pennyfarthing_scripts/codemarkers/models.py +45 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__init__.py +15 -0
- package/pennyfarthing_scripts/complexity/__main__.py +6 -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/complexity/analyze.py +207 -0
- package/pennyfarthing_scripts/complexity/cli.py +78 -0
- package/pennyfarthing_scripts/complexity/formatters.py +64 -0
- package/pennyfarthing_scripts/complexity/models.py +32 -0
- package/pennyfarthing_scripts/deadcode/__init__.py +6 -0
- package/pennyfarthing_scripts/deadcode/__main__.py +6 -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/deadcode/analyze.py +323 -0
- package/pennyfarthing_scripts/deadcode/cli.py +163 -0
- package/pennyfarthing_scripts/deadcode/formatters.py +106 -0
- package/pennyfarthing_scripts/deadcode/models.py +54 -0
- package/pennyfarthing_scripts/dependencies/__init__.py +20 -0
- package/pennyfarthing_scripts/dependencies/__main__.py +5 -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/dependencies/analyze.py +155 -0
- package/pennyfarthing_scripts/dependencies/cli.py +72 -0
- package/pennyfarthing_scripts/dependencies/formatters.py +63 -0
- package/pennyfarthing_scripts/dependencies/models.py +39 -0
- package/pennyfarthing_scripts/healthscore/__init__.py +21 -0
- package/pennyfarthing_scripts/healthscore/__main__.py +6 -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 +161 -0
- package/pennyfarthing_scripts/healthscore/cli.py +76 -0
- package/pennyfarthing_scripts/healthscore/formatters.py +46 -0
- package/pennyfarthing_scripts/healthscore/models.py +44 -0
- package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- 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 +27 -0
- package/pennyfarthing_scripts/hotspots/cli.py +10 -8
- package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/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__/operations.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/bidirectional.py +42 -15
- package/pennyfarthing_scripts/jira/cli.py +4 -1
- package/pennyfarthing_scripts/jira/client.py +28 -0
- package/pennyfarthing_scripts/prime/__pycache__/cli.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__/tiers.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/workflow.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__/loader.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_epic.py +198 -94
- package/pennyfarthing_scripts/sprint/cli.py +29 -19
- package/pennyfarthing_scripts/sprint/story_add.py +202 -27
- package/pennyfarthing_scripts/sprint/story_finish.py +211 -0
- package/pennyfarthing_scripts/sprint/work.py +27 -3
- package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_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_validate_cmd.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_codemarkers.py +682 -0
- package/pennyfarthing_scripts/tests/test_healthscore.py +524 -0
- package/pennyfarthing_scripts/theme/__init__.py +5 -0
- package/pennyfarthing_scripts/theme/__main__.py +6 -0
- 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 +286 -0
- package/scripts/README.md +53 -0
- package/pennyfarthing-dist/agents/workflow-status-check.md +0 -96
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pennyfarthing
|
|
2
2
|
|
|
3
|
-
**v10.0
|
|
3
|
+
**v10.1.0** | *The outer loop goes once, the inner loop goes many times.*
|
|
4
4
|
|
|
5
5
|
<img src="pennyfarthing.png" alt="Pennyfarthing Logo" width="75" style="float:left; margin:10px">
|
|
6
6
|
|
|
@@ -15,8 +15,8 @@ A Claude Code agent orchestration framework built around three pillars: a flexib
|
|
|
15
15
|
A multi-agent system with customizable BikeLane workflows for structured software development:
|
|
16
16
|
|
|
17
17
|
- **10 Coordinated Agents** - SM, TEA, Dev, Reviewer, Architect, PM, Tech Writer, UX Designer, DevOps, Orchestrator
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
18
|
+
- **9 BikeLane Workflows** - Phased (TDD, BDD, Trivial, 2pTDD), Stepped (Architecture, Release, Git Cleanup)
|
|
19
|
+
- **50 Slash Commands** - Entry points for agent activation and workflows
|
|
20
20
|
- **22 Skills** - Reusable knowledge domains (testing, code-review, jira, mermaid, etc.)
|
|
21
21
|
- **Prime Context System** - Tiered context injection assembles agent definition, persona, session state, and sidecar memory
|
|
22
22
|
- **Automatic Handoffs** - Context-aware agent transitions via subagent delegation
|
|
@@ -266,14 +266,16 @@ your-project/
|
|
|
266
266
|
└── {story-id}-session.md # Active work session
|
|
267
267
|
```
|
|
268
268
|
|
|
269
|
-
## What's New in v10.
|
|
269
|
+
## What's New in v10.1.0
|
|
270
270
|
|
|
271
|
-
- **
|
|
272
|
-
- **Tool
|
|
273
|
-
- **
|
|
271
|
+
- **Codebase Health Dashboard** — Health score gauge, dead code analysis, code markers, complexity metrics, and dependency tracking — all with Cyclist dialogs
|
|
272
|
+
- **Tool Dialog System** — Shared ToolDialog component with standardized dialogs across all diagnostic tools
|
|
273
|
+
- **2party-TDD Workflow** — New workflow for pair-programming TDD with review rejection loops
|
|
274
|
+
- **Cross-File Reference Validator** — Detects broken references across agent definitions, workflows, skills, and guides
|
|
274
275
|
|
|
275
276
|
### Previous Highlights
|
|
276
277
|
|
|
278
|
+
- **v10.0** - Clean install consolidation, tool use approval system, plan mode exit UI
|
|
277
279
|
- **v9.3** - Theme packages (97 themes across 7 packs), release workflow, shadcn/ui migration
|
|
278
280
|
- **v9.0** - Dockview panel system, React 19 rewrite, tool visualization, prime context, bell/relay modes
|
|
279
281
|
- **v8.x** - BikeLane workflows, scientific benchmarking, JobFair, agent sidecars
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pennyfarthing/core",
|
|
3
|
-
"version": "10.0
|
|
3
|
+
"version": "10.1.0",
|
|
4
4
|
"description": "Claude Code agent framework with TDD workflow and persona system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -30,6 +30,18 @@
|
|
|
30
30
|
"bugs": {
|
|
31
31
|
"url": "https://github.com/1898andCo/pennyfarthing/issues"
|
|
32
32
|
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"prepublishOnly": "find pennyfarthing-dist/scripts -name '*.sh' ! -name 'find-root.sh' -exec chmod +x {} +",
|
|
35
|
+
"postinstall": "node scripts/postinstall.cjs",
|
|
36
|
+
"build": "pnpm --filter @pennyfarthing/shared build && pnpm --filter @pennyfarthing/core build && pnpm --filter @pennyfarthing/cyclist build && ./scripts/generate-skill-docs.sh",
|
|
37
|
+
"docs": "./scripts/generate-skill-docs.sh",
|
|
38
|
+
"dev": "pnpm -r --parallel dev",
|
|
39
|
+
"test": "pnpm -r test",
|
|
40
|
+
"lint": "eslint 'packages/*/src/**/*.ts' --max-warnings 0",
|
|
41
|
+
"validate:refs": "node scripts/validate-refs.js",
|
|
42
|
+
"test:validate-refs": "node --test scripts/validate-refs.test.js",
|
|
43
|
+
"clean": "pnpm -r clean"
|
|
44
|
+
},
|
|
33
45
|
"dependencies": {
|
|
34
46
|
"@pennyfarthing/shared": "^10.0.3",
|
|
35
47
|
"chalk": "^5.3.0",
|
|
@@ -49,13 +61,5 @@
|
|
|
49
61
|
"engines": {
|
|
50
62
|
"node": ">=18.0.0"
|
|
51
63
|
},
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
"build": "pnpm --filter @pennyfarthing/shared build && pnpm --filter @pennyfarthing/core build && pnpm --filter @pennyfarthing/cyclist build && ./scripts/generate-skill-docs.sh",
|
|
55
|
-
"docs": "./scripts/generate-skill-docs.sh",
|
|
56
|
-
"dev": "pnpm -r --parallel dev",
|
|
57
|
-
"test": "pnpm -r test",
|
|
58
|
-
"lint": "eslint 'packages/*/src/**/*.ts' --max-warnings 0",
|
|
59
|
-
"clean": "pnpm -r clean"
|
|
60
|
-
}
|
|
61
|
-
}
|
|
64
|
+
"packageManager": "pnpm@9.0.0"
|
|
65
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"AAsBA,UAAU,aAAa;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA2HzE;AA+iDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,EAAE,CAgKnE;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,CAkF1E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,WAAW,EAAE,CAsIlE"}
|
|
@@ -10,14 +10,15 @@ import { pathExists, isDirectory, isSymlink, fileMatchesHash } from '../utils/fi
|
|
|
10
10
|
import { getPackageVersion } from '../utils/version.js';
|
|
11
11
|
import { findNodeModulesPath } from '../utils/node-modules.js';
|
|
12
12
|
import { ALL_SYMLINKS, CORE_AGENTS } from '../utils/constants.js';
|
|
13
|
+
import { getPfVersion, installPfCli } from '../utils/python.js';
|
|
13
14
|
export async function doctorCommand(options) {
|
|
14
15
|
const projectRoot = process.cwd();
|
|
15
|
-
// Handle
|
|
16
|
+
// Handle dogfood mode - run checks for framework/orchestrator development
|
|
16
17
|
if (options.dogfood) {
|
|
17
18
|
const dogfoodScript = join(projectRoot, 'pennyfarthing-dist/scripts/misc/doctor-dogfood.sh');
|
|
18
19
|
if (!existsSync(dogfoodScript)) {
|
|
19
|
-
logger.error('Dogfood mode requires
|
|
20
|
-
logger.info('This flag is for
|
|
20
|
+
logger.error('Dogfood mode requires pennyfarthing-dist/ (framework repo or orchestrator with inlined pennyfarthing/)');
|
|
21
|
+
logger.info('This flag is for framework development and orchestrator repos.');
|
|
21
22
|
process.exit(1);
|
|
22
23
|
}
|
|
23
24
|
const args = options.fix ? ['--fix'] : [];
|
|
@@ -41,16 +42,20 @@ export async function doctorCommand(options) {
|
|
|
41
42
|
logger.info(`Version: ${installedVersion} (installed) / ${packageVersion} (package)`);
|
|
42
43
|
logger.info(`Mode: ${installationType}${installationType === 'symlink' ? ' (node_modules)' : ' (file copies)'}`);
|
|
43
44
|
logger.newline();
|
|
45
|
+
// Resolve node_modules path for checks that need it
|
|
46
|
+
const nodeModulesPath = findNodeModulesPath(projectRoot);
|
|
44
47
|
// Run checks
|
|
45
48
|
results.push(...checkInstallation(projectRoot, manifest));
|
|
46
49
|
results.push(...checkCoreFiles(projectRoot, manifest));
|
|
47
50
|
results.push(...checkUserFiles(projectRoot));
|
|
48
51
|
results.push(...checkDirectories(projectRoot));
|
|
49
52
|
results.push(...checkHooks(projectRoot));
|
|
53
|
+
results.push(...checkGitHooks(projectRoot, nodeModulesPath));
|
|
50
54
|
results.push(...checkFileLayout(projectRoot));
|
|
51
55
|
results.push(...checkLegacyFiles(projectRoot));
|
|
52
56
|
results.push(checkLegacyStatuslinePath(projectRoot));
|
|
53
57
|
results.push(...checkCyclist(projectRoot));
|
|
58
|
+
results.push(checkPfCli(nodeModulesPath));
|
|
54
59
|
// Output results
|
|
55
60
|
if (options.json) {
|
|
56
61
|
console.log(JSON.stringify(results, null, 2));
|
|
@@ -63,9 +68,11 @@ export async function doctorCommand(options) {
|
|
|
63
68
|
{ name: 'User Files', filter: (r) => r.name.startsWith('project/') || r.name.startsWith('persona') || r.name.startsWith('settings') },
|
|
64
69
|
{ name: 'Directories', filter: (r) => r.name.startsWith('dir/') },
|
|
65
70
|
{ name: 'Hooks', filter: (r) => r.name.startsWith('hook/') },
|
|
71
|
+
{ name: 'Git Hooks', filter: (r) => r.name.startsWith('git-hook/') },
|
|
66
72
|
{ name: 'File Layout', filter: (r) => r.name.startsWith('layout/') },
|
|
67
73
|
{ name: 'Legacy Files', filter: (r) => r.name.startsWith('legacy/') },
|
|
68
|
-
{ name: 'Cyclist', filter: (r) => r.name.startsWith('cyclist/') }
|
|
74
|
+
{ name: 'Cyclist', filter: (r) => r.name.startsWith('cyclist/') },
|
|
75
|
+
{ name: 'Tools', filter: (r) => r.name.startsWith('tools/') }
|
|
69
76
|
];
|
|
70
77
|
for (const category of categories) {
|
|
71
78
|
const categoryResults = results.filter(category.filter);
|
|
@@ -314,6 +321,9 @@ function checkUserFiles(projectRoot) {
|
|
|
314
321
|
// Check SessionStart hooks are configured (critical for PROJECT_ROOT)
|
|
315
322
|
const hookCheck = checkSessionStartHooks(projectRoot, installationType);
|
|
316
323
|
results.push(hookCheck);
|
|
324
|
+
// Check auto-load-sm hook is configured (auto-invokes /sm on new sessions)
|
|
325
|
+
const autoLoadSmCheck = checkAutoLoadSmHook(projectRoot);
|
|
326
|
+
results.push(autoLoadSmCheck);
|
|
317
327
|
// Check Stop hook is configured (question reflector enforcement)
|
|
318
328
|
const stopHookCheck = checkStopHook(projectRoot, installationType);
|
|
319
329
|
results.push(stopHookCheck);
|
|
@@ -462,6 +472,133 @@ function checkSessionStartHooks(projectRoot, installationType) {
|
|
|
462
472
|
};
|
|
463
473
|
}
|
|
464
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* Check that auto-load-sm hook is configured in SessionStart
|
|
477
|
+
* This auto-invokes /sm agent on new session start
|
|
478
|
+
*/
|
|
479
|
+
function checkAutoLoadSmHook(projectRoot) {
|
|
480
|
+
const settingsPath = join(projectRoot, '.claude/settings.local.json');
|
|
481
|
+
try {
|
|
482
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
483
|
+
if (!settings.hooks?.SessionStart) {
|
|
484
|
+
return {
|
|
485
|
+
name: 'settings/auto-load-sm',
|
|
486
|
+
status: 'warn',
|
|
487
|
+
detail: 'Missing SessionStart hooks - auto-load-sm not configured',
|
|
488
|
+
fix: () => {
|
|
489
|
+
addAutoLoadSmHook(projectRoot);
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
const hasAutoLoadSm = settings.hooks.SessionStart.some((entry) => {
|
|
494
|
+
if (typeof entry === 'object' && entry !== null) {
|
|
495
|
+
const hookEntry = entry;
|
|
496
|
+
return hookEntry.hooks?.some(h => h.command?.includes('auto-load-sm'));
|
|
497
|
+
}
|
|
498
|
+
return false;
|
|
499
|
+
});
|
|
500
|
+
if (!hasAutoLoadSm) {
|
|
501
|
+
return {
|
|
502
|
+
name: 'settings/auto-load-sm',
|
|
503
|
+
status: 'warn',
|
|
504
|
+
detail: 'auto-load-sm not configured - /sm will not auto-invoke on startup',
|
|
505
|
+
fix: () => {
|
|
506
|
+
addAutoLoadSmHook(projectRoot);
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
// Also check that the hook script file exists
|
|
511
|
+
const hookScript = join(projectRoot, '.pennyfarthing/project/hooks/auto-load-sm.sh');
|
|
512
|
+
if (!pathExists(hookScript)) {
|
|
513
|
+
return {
|
|
514
|
+
name: 'settings/auto-load-sm',
|
|
515
|
+
status: 'warn',
|
|
516
|
+
detail: 'Hook registered but script missing at .pennyfarthing/project/hooks/auto-load-sm.sh',
|
|
517
|
+
fix: () => {
|
|
518
|
+
ensureDirSync(dirname(hookScript));
|
|
519
|
+
writeFileSync(hookScript, `#!/usr/bin/env bash
|
|
520
|
+
# Auto-load /sm agent on new session start
|
|
521
|
+
set -euo pipefail
|
|
522
|
+
|
|
523
|
+
cat <<'HOOKEOF'
|
|
524
|
+
{
|
|
525
|
+
"hookSpecificOutput": {
|
|
526
|
+
"hookEventName": "SessionStart",
|
|
527
|
+
"additionalContext": "IMPORTANT: Auto-invoke the /sm agent immediately. Run the Skill tool with skill: \\"sm\\" as your first action. Do not greet the user or do anything else first."
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
HOOKEOF
|
|
531
|
+
`, { mode: 0o755 });
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
return {
|
|
536
|
+
name: 'settings/auto-load-sm',
|
|
537
|
+
status: 'pass',
|
|
538
|
+
detail: undefined
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
catch {
|
|
542
|
+
return {
|
|
543
|
+
name: 'settings/auto-load-sm',
|
|
544
|
+
status: 'warn',
|
|
545
|
+
detail: 'Could not parse settings.local.json'
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Fix function: Add auto-load-sm hook to SessionStart in settings.local.json
|
|
551
|
+
*/
|
|
552
|
+
function addAutoLoadSmHook(projectRoot) {
|
|
553
|
+
const settingsPath = join(projectRoot, '.claude/settings.local.json');
|
|
554
|
+
const requiredHook = {
|
|
555
|
+
matcher: 'startup',
|
|
556
|
+
hooks: [
|
|
557
|
+
{
|
|
558
|
+
type: 'command',
|
|
559
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/project/hooks/auto-load-sm.sh'
|
|
560
|
+
}
|
|
561
|
+
]
|
|
562
|
+
};
|
|
563
|
+
let settings = {};
|
|
564
|
+
if (pathExists(settingsPath)) {
|
|
565
|
+
try {
|
|
566
|
+
settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
567
|
+
}
|
|
568
|
+
catch {
|
|
569
|
+
// Start fresh if parse fails
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (!settings.hooks) {
|
|
573
|
+
settings.hooks = {};
|
|
574
|
+
}
|
|
575
|
+
const hooks = settings.hooks;
|
|
576
|
+
if (!hooks.SessionStart) {
|
|
577
|
+
hooks.SessionStart = [requiredHook];
|
|
578
|
+
}
|
|
579
|
+
else if (Array.isArray(hooks.SessionStart)) {
|
|
580
|
+
hooks.SessionStart = [...hooks.SessionStart, requiredHook];
|
|
581
|
+
}
|
|
582
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
583
|
+
// Also ensure the hook script exists
|
|
584
|
+
const hookScript = join(projectRoot, '.pennyfarthing/project/hooks/auto-load-sm.sh');
|
|
585
|
+
if (!pathExists(hookScript)) {
|
|
586
|
+
ensureDirSync(dirname(hookScript));
|
|
587
|
+
writeFileSync(hookScript, `#!/usr/bin/env bash
|
|
588
|
+
# Auto-load /sm agent on new session start
|
|
589
|
+
set -euo pipefail
|
|
590
|
+
|
|
591
|
+
cat <<'HOOKEOF'
|
|
592
|
+
{
|
|
593
|
+
"hookSpecificOutput": {
|
|
594
|
+
"hookEventName": "SessionStart",
|
|
595
|
+
"additionalContext": "IMPORTANT: Auto-invoke the /sm agent immediately. Run the Skill tool with skill: \\"sm\\" as your first action. Do not greet the user or do anything else first."
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
HOOKEOF
|
|
599
|
+
`, { mode: 0o755 });
|
|
600
|
+
}
|
|
601
|
+
}
|
|
465
602
|
/**
|
|
466
603
|
* Check that Stop hook is properly configured in settings.local.json
|
|
467
604
|
* This is needed for question reflector enforcement in Cyclist
|
|
@@ -936,6 +1073,15 @@ function addSessionStartHooks(projectRoot, installationType) {
|
|
|
936
1073
|
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/project/hooks/setup-env.sh'
|
|
937
1074
|
}
|
|
938
1075
|
]
|
|
1076
|
+
},
|
|
1077
|
+
{
|
|
1078
|
+
matcher: 'startup',
|
|
1079
|
+
hooks: [
|
|
1080
|
+
{
|
|
1081
|
+
type: 'command',
|
|
1082
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/project/hooks/auto-load-sm.sh'
|
|
1083
|
+
}
|
|
1084
|
+
]
|
|
939
1085
|
}
|
|
940
1086
|
];
|
|
941
1087
|
let settings = {};
|
|
@@ -1021,6 +1167,15 @@ function createSettingsLocalJson(projectRoot, installationType) {
|
|
|
1021
1167
|
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/project/hooks/setup-env.sh'
|
|
1022
1168
|
}
|
|
1023
1169
|
]
|
|
1170
|
+
},
|
|
1171
|
+
{
|
|
1172
|
+
matcher: 'startup',
|
|
1173
|
+
hooks: [
|
|
1174
|
+
{
|
|
1175
|
+
type: 'command',
|
|
1176
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/project/hooks/auto-load-sm.sh'
|
|
1177
|
+
}
|
|
1178
|
+
]
|
|
1024
1179
|
}
|
|
1025
1180
|
],
|
|
1026
1181
|
PostToolUse: [
|
|
@@ -1158,6 +1313,74 @@ function checkHooks(projectRoot) {
|
|
|
1158
1313
|
}
|
|
1159
1314
|
return results;
|
|
1160
1315
|
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Check git hooks in .git/hooks/ are up-to-date with package source.
|
|
1318
|
+
* Detects stale copies that were installed by `pennyfarthing init` but never refreshed.
|
|
1319
|
+
* Provides --fix to overwrite stale hooks with current package content.
|
|
1320
|
+
*/
|
|
1321
|
+
function checkGitHooks(projectRoot, nodeModulesPath) {
|
|
1322
|
+
const results = [];
|
|
1323
|
+
const gitHooksDir = join(projectRoot, '.git/hooks');
|
|
1324
|
+
if (!pathExists(gitHooksDir)) {
|
|
1325
|
+
return results;
|
|
1326
|
+
}
|
|
1327
|
+
if (!nodeModulesPath) {
|
|
1328
|
+
return results;
|
|
1329
|
+
}
|
|
1330
|
+
const hooks = [
|
|
1331
|
+
{ source: 'pre-commit.sh', dest: 'pre-commit', marker: 'pennyfarthing' },
|
|
1332
|
+
{ source: 'pre-push.sh', dest: 'pre-push', marker: 'pennyfarthing' },
|
|
1333
|
+
{ source: 'post-merge.sh', dest: 'post-merge', marker: 'pennyfarthing' },
|
|
1334
|
+
];
|
|
1335
|
+
for (const hook of hooks) {
|
|
1336
|
+
const sourcePath = join(nodeModulesPath, 'scripts/hooks', hook.source);
|
|
1337
|
+
const destPath = join(gitHooksDir, hook.dest);
|
|
1338
|
+
if (!pathExists(sourcePath)) {
|
|
1339
|
+
continue;
|
|
1340
|
+
}
|
|
1341
|
+
if (!pathExists(destPath)) {
|
|
1342
|
+
results.push({
|
|
1343
|
+
name: `git-hook/${hook.dest}`,
|
|
1344
|
+
status: 'warn',
|
|
1345
|
+
detail: 'Not installed',
|
|
1346
|
+
fix: () => {
|
|
1347
|
+
const content = readFileSync(sourcePath, 'utf8');
|
|
1348
|
+
writeFileSync(destPath, content, { mode: 0o755 });
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
continue;
|
|
1352
|
+
}
|
|
1353
|
+
const existingContent = readFileSync(destPath, 'utf8');
|
|
1354
|
+
// Only check hooks that are ours (contain the marker)
|
|
1355
|
+
if (!existingContent.includes(hook.marker)) {
|
|
1356
|
+
results.push({
|
|
1357
|
+
name: `git-hook/${hook.dest}`,
|
|
1358
|
+
status: 'pass',
|
|
1359
|
+
detail: 'Custom (non-pennyfarthing)'
|
|
1360
|
+
});
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
const sourceContent = readFileSync(sourcePath, 'utf8');
|
|
1364
|
+
if (existingContent === sourceContent) {
|
|
1365
|
+
results.push({
|
|
1366
|
+
name: `git-hook/${hook.dest}`,
|
|
1367
|
+
status: 'pass',
|
|
1368
|
+
detail: undefined
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
else {
|
|
1372
|
+
results.push({
|
|
1373
|
+
name: `git-hook/${hook.dest}`,
|
|
1374
|
+
status: 'warn',
|
|
1375
|
+
detail: 'Stale — content differs from package',
|
|
1376
|
+
fix: () => {
|
|
1377
|
+
writeFileSync(destPath, sourceContent, { mode: 0o755 });
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
return results;
|
|
1383
|
+
}
|
|
1161
1384
|
/**
|
|
1162
1385
|
* Check Cyclist installation health (if installed as a workspace package)
|
|
1163
1386
|
* Detects node-pty spawn-helper permission issues that cause posix_spawnp failures
|
|
@@ -1260,6 +1483,30 @@ function checkCyclist(projectRoot) {
|
|
|
1260
1483
|
}
|
|
1261
1484
|
return results;
|
|
1262
1485
|
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Check if the pf CLI is installed and working.
|
|
1488
|
+
* The pf CLI is required for agent commands (e.g., `pf agent start "dev"`).
|
|
1489
|
+
*/
|
|
1490
|
+
function checkPfCli(nodeModulesPath) {
|
|
1491
|
+
const version = getPfVersion();
|
|
1492
|
+
if (version) {
|
|
1493
|
+
return {
|
|
1494
|
+
name: 'tools/pf-cli',
|
|
1495
|
+
status: 'pass',
|
|
1496
|
+
detail: version
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
return {
|
|
1500
|
+
name: 'tools/pf-cli',
|
|
1501
|
+
status: 'warn',
|
|
1502
|
+
detail: 'pf CLI not found — agent commands will not work',
|
|
1503
|
+
fix: () => {
|
|
1504
|
+
if (!installPfCli(nodeModulesPath)) {
|
|
1505
|
+
throw new Error('Neither uv nor pipx available. Install manually: uv tool install pennyfarthing-scripts');
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1263
1510
|
/**
|
|
1264
1511
|
* Known legacy statusline paths from various Pennyfarthing versions.
|
|
1265
1512
|
* These should be detected and cleaned up when proper statusline exists.
|