@pennyfarthing/core 11.2.1 → 11.3.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 +102 -42
- package/package.json +1 -1
- package/packages/core/dist/cli/commands/doctor-legacy.test.js +2 -2
- package/packages/core/dist/cli/commands/doctor-legacy.test.js.map +1 -1
- package/packages/core/dist/cli/commands/doctor.d.ts +55 -0
- package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/doctor.js +324 -50
- package/packages/core/dist/cli/commands/doctor.js.map +1 -1
- package/packages/core/dist/cli/commands/init.d.ts +12 -0
- package/packages/core/dist/cli/commands/init.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/init.js +45 -0
- package/packages/core/dist/cli/commands/init.js.map +1 -1
- package/packages/core/dist/cli/commands/pyproject-install.test.d.ts +19 -0
- package/packages/core/dist/cli/commands/pyproject-install.test.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/pyproject-install.test.js +261 -0
- package/packages/core/dist/cli/commands/pyproject-install.test.js.map +1 -0
- package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.d.ts +17 -0
- package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.js +470 -0
- package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.js.map +1 -0
- package/packages/core/dist/cli/commands/update-consolidation.test.js +14 -6
- package/packages/core/dist/cli/commands/update-consolidation.test.js.map +1 -1
- package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/update.js +31 -2
- package/packages/core/dist/cli/commands/update.js.map +1 -1
- package/packages/core/dist/cli/index.js +2 -0
- package/packages/core/dist/cli/index.js.map +1 -1
- package/packages/core/dist/cli/utils/python.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/python.js +11 -0
- package/packages/core/dist/cli/utils/python.js.map +1 -1
- package/packages/core/dist/cli/utils/settings-hook-migration.test.d.ts +17 -0
- package/packages/core/dist/cli/utils/settings-hook-migration.test.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/settings-hook-migration.test.js +382 -0
- package/packages/core/dist/cli/utils/settings-hook-migration.test.js.map +1 -0
- package/packages/core/dist/cli/utils/settings.d.ts +0 -4
- package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/settings.js +45 -27
- package/packages/core/dist/cli/utils/settings.js.map +1 -1
- package/packages/core/dist/cli/utils/stale-artifacts.d.ts +59 -0
- package/packages/core/dist/cli/utils/stale-artifacts.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/stale-artifacts.js +163 -0
- package/packages/core/dist/cli/utils/stale-artifacts.js.map +1 -0
- package/packages/core/dist/consultation/dialogue-manager.d.ts +1 -1
- package/packages/core/dist/consultation/dialogue-manager.d.ts.map +1 -1
- package/packages/core/dist/consultation/dialogue-manager.js +1 -1
- package/packages/core/dist/consultation/dialogue-manager.js.map +1 -1
- package/packages/core/dist/consultation/dialogue-manager.test.js.map +1 -1
- package/packages/core/dist/consultation/tandem-metrics.test.js.map +1 -1
- package/packages/core/dist/public/css/react.css +1 -1
- package/packages/core/dist/public/js/react/react.js +9 -9
- package/packages/core/dist/server/api/git.d.ts.map +1 -1
- package/packages/core/dist/server/api/git.js +0 -1
- package/packages/core/dist/server/api/git.js.map +1 -1
- package/packages/core/dist/server/api/index.d.ts +2 -0
- package/packages/core/dist/server/api/index.d.ts.map +1 -1
- package/packages/core/dist/server/api/index.js +2 -0
- package/packages/core/dist/server/api/index.js.map +1 -1
- package/packages/core/dist/server/api/project-info.d.ts +11 -0
- package/packages/core/dist/server/api/project-info.d.ts.map +1 -0
- package/packages/core/dist/server/api/project-info.js +18 -0
- package/packages/core/dist/server/api/project-info.js.map +1 -0
- package/packages/core/dist/server/otlp-receiver.d.ts.map +1 -1
- package/packages/core/dist/server/otlp-receiver.js +18 -1
- package/packages/core/dist/server/otlp-receiver.js.map +1 -1
- package/packages/core/dist/server/otlp-receiver.test.js +1 -1
- package/packages/core/dist/server/otlp-receiver.test.js.map +1 -1
- package/packages/core/dist/server/server.d.ts.map +1 -1
- package/packages/core/dist/server/server.js +3 -2
- 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 +8 -8
- package/packages/core/dist/server/settings.d.ts +1 -0
- package/packages/core/dist/server/settings.d.ts.map +1 -1
- package/packages/core/dist/server/settings.js +18 -0
- package/packages/core/dist/server/settings.js.map +1 -1
- package/packages/core/dist/workflow/tandem-workflow-templates.test.js +7 -5
- package/packages/core/dist/workflow/tandem-workflow-templates.test.js.map +1 -1
- package/packages/core/dist/workflow/workflow-migration.test.js +6 -5
- package/packages/core/dist/workflow/workflow-migration.test.js.map +1 -1
- package/packages/core/dist/workflow/workflow-team-templates.test.d.ts +17 -0
- package/packages/core/dist/workflow/workflow-team-templates.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/workflow-team-templates.test.js +275 -0
- package/packages/core/dist/workflow/workflow-team-templates.test.js.map +1 -0
- package/pennyfarthing-dist/agents/dev.md +19 -4
- package/pennyfarthing-dist/agents/devops.md +2 -10
- package/pennyfarthing-dist/agents/reviewer-preflight.md +4 -5
- package/pennyfarthing-dist/agents/reviewer.md +17 -4
- package/pennyfarthing-dist/agents/sm-finish.md +1 -1
- package/pennyfarthing-dist/agents/sm-setup.md +7 -7
- package/pennyfarthing-dist/agents/sm.md +16 -29
- package/pennyfarthing-dist/agents/tea.md +2 -2
- package/pennyfarthing-dist/agents/testing-runner.md +1 -1
- package/pennyfarthing-dist/commands/pf-architect.md +1 -1
- package/pennyfarthing-dist/commands/pf-ba.md +1 -1
- package/pennyfarthing-dist/commands/pf-chore.md +2 -2
- package/pennyfarthing-dist/commands/pf-dev.md +1 -1
- package/pennyfarthing-dist/commands/pf-devops.md +1 -1
- package/pennyfarthing-dist/commands/pf-epic.md +6 -6
- package/pennyfarthing-dist/commands/pf-git.md +10 -10
- package/pennyfarthing-dist/commands/pf-health-check.md +31 -12
- package/pennyfarthing-dist/commands/pf-help.md +12 -12
- package/pennyfarthing-dist/commands/pf-orchestrator.md +1 -1
- package/pennyfarthing-dist/commands/pf-pm.md +1 -1
- package/pennyfarthing-dist/commands/pf-prime.md +8 -8
- package/pennyfarthing-dist/commands/pf-reviewer.md +1 -1
- package/pennyfarthing-dist/commands/pf-session.md +7 -7
- package/pennyfarthing-dist/commands/pf-sm.md +1 -1
- package/pennyfarthing-dist/commands/pf-sprint.md +7 -7
- package/pennyfarthing-dist/commands/pf-tea.md +1 -1
- package/pennyfarthing-dist/commands/pf-tech-writer.md +1 -1
- package/pennyfarthing-dist/commands/pf-theme.md +9 -9
- package/pennyfarthing-dist/commands/pf-ux-designer.md +1 -1
- package/pennyfarthing-dist/commands/pf-work.md +1 -1
- package/pennyfarthing-dist/gates/{confidence-sm.md → confidence.md} +16 -17
- package/pennyfarthing-dist/gates/dev-exit.md +75 -0
- package/pennyfarthing-dist/gates/merge-ready.md +49 -0
- package/pennyfarthing-dist/gates/release-ready.md +95 -0
- package/pennyfarthing-dist/gates/reviewer-preflight-check.md +90 -0
- package/pennyfarthing-dist/gates/sm-setup-exit.md +82 -0
- package/pennyfarthing-dist/guides/agent-behavior.md +129 -20
- package/pennyfarthing-dist/guides/agent-coordination.md +10 -10
- package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +6 -6
- package/pennyfarthing-dist/guides/agent-template-tactical.md +1 -1
- package/pennyfarthing-dist/guides/bell-mode.md +1 -1
- package/pennyfarthing-dist/guides/bikerack.md +10 -10
- package/pennyfarthing-dist/guides/brownfield-tools.md +24 -24
- package/pennyfarthing-dist/guides/command-tag-taxonomy.md +1 -1
- package/pennyfarthing-dist/guides/gate-schema.md +2 -2
- package/pennyfarthing-dist/guides/gates.md +10 -5
- package/pennyfarthing-dist/guides/handoff-cli.md +8 -8
- package/pennyfarthing-dist/guides/hooks.md +27 -27
- package/pennyfarthing-dist/guides/prime.md +2 -2
- package/pennyfarthing-dist/guides/reflector.md +1 -1
- package/pennyfarthing-dist/guides/skill-schema.md +6 -6
- package/pennyfarthing-dist/guides/tandem-protocol.md +3 -3
- package/pennyfarthing-dist/guides/workflow-schema.md +1 -1
- package/pennyfarthing-dist/guides/worktree-mode.md +3 -3
- package/pennyfarthing-dist/guides/xml-tags.md +8 -8
- package/pennyfarthing-dist/scripts/README.md +4 -4
- package/pennyfarthing-dist/scripts/core/agent-session.sh +2 -5
- package/pennyfarthing-dist/scripts/core/check-context.sh +1 -1
- package/pennyfarthing-dist/scripts/core/pf.sh +5 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +2 -5
- package/pennyfarthing-dist/scripts/core/prime.sh +2 -25
- package/pennyfarthing-dist/scripts/git/README.md +14 -14
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +2 -3
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +2 -3
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +2 -3
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +2 -4
- package/pennyfarthing-dist/scripts/hooks/README.md +6 -6
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +5 -4
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +2 -1
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +3 -3
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +3 -4
- package/pennyfarthing-dist/scripts/lib/env.sh +34 -0
- package/pennyfarthing-dist/scripts/lib/find-root.sh +5 -0
- package/pennyfarthing-dist/scripts/lib/run-pf.sh +43 -0
- package/pennyfarthing-dist/scripts/misc/README.md +1 -1
- package/pennyfarthing-dist/scripts/misc/statusline.sh +3 -3
- package/pennyfarthing-dist/scripts/sprint/README.md +21 -21
- package/pennyfarthing-dist/scripts/workflow/README.md +2 -2
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +2 -16
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +3 -3
- package/pennyfarthing-dist/skills/pf-bc/examples.md +23 -23
- package/pennyfarthing-dist/skills/pf-bc/skill.md +17 -17
- package/pennyfarthing-dist/skills/pf-bc/usage.md +8 -8
- package/pennyfarthing-dist/skills/pf-jira/SKILL.md +15 -15
- package/pennyfarthing-dist/skills/pf-jira/examples.md +48 -48
- package/pennyfarthing-dist/skills/pf-jira/usage.md +15 -15
- package/pennyfarthing-dist/skills/pf-settings/skill.md +42 -0
- package/pennyfarthing-dist/skills/pf-sprint/examples.md +80 -80
- package/pennyfarthing-dist/skills/pf-sprint/skill.md +35 -35
- package/pennyfarthing-dist/skills/pf-sprint/usage.md +30 -30
- package/pennyfarthing-dist/skills/pf-theme/examples.md +15 -15
- package/pennyfarthing-dist/skills/pf-theme/skill.md +6 -6
- package/pennyfarthing-dist/skills/pf-theme/usage.md +5 -5
- package/pennyfarthing-dist/skills/pf-workflow/examples.md +27 -27
- package/pennyfarthing-dist/skills/pf-workflow/skill.md +11 -11
- package/pennyfarthing-dist/skills/pf-workflow/usage.md +11 -11
- package/pennyfarthing-dist/skills/skill-registry.yaml +34 -19
- package/pennyfarthing-dist/templates/pyproject.toml +27 -0
- package/pennyfarthing-dist/templates/settings.local.json.template +11 -11
- package/pennyfarthing-dist/workflows/bdd-tandem.yaml +7 -3
- package/pennyfarthing-dist/workflows/bdd-team.yaml +89 -0
- package/pennyfarthing-dist/workflows/bdd.yaml +7 -3
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +1 -1
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +1 -1
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +1 -1
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +1 -1
- package/pennyfarthing-dist/workflows/installation-check/steps/step-01-foundation.md +77 -0
- package/pennyfarthing-dist/workflows/installation-check/steps/step-02-commands.md +82 -0
- package/pennyfarthing-dist/workflows/installation-check/steps/step-03-hooks.md +121 -0
- package/pennyfarthing-dist/workflows/installation-check/steps/step-04-scripts.md +83 -0
- package/pennyfarthing-dist/workflows/installation-check/steps/step-05-layout.md +81 -0
- package/pennyfarthing-dist/workflows/installation-check/steps/step-06-legacy.md +94 -0
- package/pennyfarthing-dist/workflows/installation-check/steps/step-07-tools.md +80 -0
- package/pennyfarthing-dist/workflows/installation-check/steps/step-08-summary.md +99 -0
- package/pennyfarthing-dist/workflows/installation-check/workflow.yaml +47 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-01-discover.md +47 -0
- package/pennyfarthing-dist/workflows/tdd-tandem.yaml +7 -3
- package/pennyfarthing-dist/workflows/tdd-team.yaml +80 -0
- package/pennyfarthing-dist/workflows/tdd.yaml +7 -3
- package/pennyfarthing-dist/workflows/trivial.yaml +7 -3
- package/pennyfarthing_scripts/__init__.py +1 -1
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/context.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/context.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/split.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/cli.py +23 -2
- package/pennyfarthing_scripts/bc/focus.py +1 -0
- package/pennyfarthing_scripts/bc/split.py +52 -0
- package/pennyfarthing_scripts/bellmode_hook.py +2 -5
- package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-311.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-311.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-311.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 +48 -6
- package/pennyfarthing_scripts/bikerack/context_meter_footer.py +53 -3
- package/pennyfarthing_scripts/bikerack/launcher.py +6 -6
- package/pennyfarthing_scripts/bikerack/progress_panel.py +0 -1
- package/pennyfarthing_scripts/bikerack/sprint_panel.py +1 -1
- package/pennyfarthing_scripts/bikerack/story_detail_data.py +4 -1
- package/pennyfarthing_scripts/bikerack/story_detail_screen.py +2 -1
- package/pennyfarthing_scripts/bikerack/tui.py +214 -10
- package/pennyfarthing_scripts/bikerack/ws_client.py +2 -2
- package/pennyfarthing_scripts/cli.py +5 -0
- package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/output.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/pr_config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/config.py +29 -2
- package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/cli.py +3 -3
- package/pennyfarthing_scripts/context.py +3 -3
- package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/git/hooks_installer.py +2 -3
- package/pennyfarthing_scripts/git/status_all.py +1 -1
- package/pennyfarthing_scripts/git/worktree.py +2 -2
- package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-311.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__/marker.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/phase_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__init__.py +8 -3
- package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-311.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-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/bell_mode.py +0 -1
- package/pennyfarthing_scripts/hooks/pre_edit_check.py +0 -1
- package/pennyfarthing_scripts/hooks/reflector_check.py +1 -2
- package/pennyfarthing_scripts/hooks/schema_validation.py +0 -1
- package/pennyfarthing_scripts/hooks/session_start.py +6 -8
- package/pennyfarthing_scripts/hooks/statusline.py +10 -1
- package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/client.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/create.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/story.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/heatmap.py +3 -15
- package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/session/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/settings/__init__.py +0 -0
- package/pennyfarthing_scripts/settings/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/settings/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/settings/__pycache__/settings.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/settings/cli.py +55 -0
- package/pennyfarthing_scripts/settings/settings.py +98 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/sprint/cli.py +121 -0
- package/pennyfarthing_scripts/sprint/loader.py +154 -3
- package/pennyfarthing_scripts/sprint/story_update.py +7 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.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/test_bikerack.py +26 -26
- package/pennyfarthing_scripts/tests/test_confidence_sm_gate.py +17 -16
- package/pennyfarthing_scripts/tests/test_dialogue_manager.py +0 -1
- package/pennyfarthing_scripts/tests/test_resolve_gate_file_field.py +45 -47
- package/pennyfarthing_scripts/tests/test_workflow_list_team.py +143 -0
- package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/team_mode.py +323 -0
- package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-311.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-311.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/cli.py +15 -14
- package/pennyfarthing_scripts/workflow/state.py +0 -1
- package/pennyfarthing_scripts/workflow/team_lifecycle.py +3 -4
|
@@ -12,8 +12,35 @@ import { findNodeModulesPath } from '../utils/node-modules.js';
|
|
|
12
12
|
import { ALL_SYMLINKS, CORE_AGENTS } from '../utils/constants.js';
|
|
13
13
|
import { getPfVersion, installPfCli } from '../utils/python.js';
|
|
14
14
|
import { LEGACY_HOOK_MIGRATIONS, migrateHookPaths } from '../utils/settings.js';
|
|
15
|
+
/**
|
|
16
|
+
* Category-to-check-function mapping for --category filtering.
|
|
17
|
+
* Each category maps to the check functions that produce results in that group.
|
|
18
|
+
*/
|
|
19
|
+
export const CATEGORY_CHECKS = {
|
|
20
|
+
'installation': ['checkInstallation', 'checkCoreFiles'],
|
|
21
|
+
'commands': ['checkCommandsAndSkills', 'checkUserFilesBasic'],
|
|
22
|
+
'hooks': ['checkSettingsHooks'],
|
|
23
|
+
'scripts': ['checkHooks', 'checkGitHooks'],
|
|
24
|
+
'layout': ['checkDirectories', 'checkFileLayout'],
|
|
25
|
+
'legacy': ['checkLegacyFiles', 'checkLegacyStatuslinePath', 'checkLegacyHookCommands'],
|
|
26
|
+
'tools': ['checkCyclist', 'checkPfCli'],
|
|
27
|
+
};
|
|
15
28
|
export async function doctorCommand(options) {
|
|
16
29
|
const projectRoot = process.cwd();
|
|
30
|
+
// Handle --list-categories
|
|
31
|
+
if (options.listCategories) {
|
|
32
|
+
console.log('Available check categories:');
|
|
33
|
+
for (const [name, checks] of Object.entries(CATEGORY_CHECKS)) {
|
|
34
|
+
console.log(` ${name.padEnd(14)} ${checks.join(', ')}`);
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Validate --category if provided
|
|
39
|
+
if (options.category && !CATEGORY_CHECKS[options.category]) {
|
|
40
|
+
logger.error(`Unknown category: ${options.category}`);
|
|
41
|
+
logger.info(`Available categories: ${Object.keys(CATEGORY_CHECKS).join(', ')}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
17
44
|
// Handle dogfood mode - run checks for framework/orchestrator development
|
|
18
45
|
if (options.dogfood) {
|
|
19
46
|
const dogfoodScript = join(projectRoot, 'pennyfarthing-dist/scripts/misc/doctor-dogfood.sh');
|
|
@@ -45,20 +72,58 @@ export async function doctorCommand(options) {
|
|
|
45
72
|
logger.newline();
|
|
46
73
|
// Resolve node_modules path for checks that need it
|
|
47
74
|
const nodeModulesPath = findNodeModulesPath(projectRoot);
|
|
48
|
-
//
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
75
|
+
// Determine which checks to run
|
|
76
|
+
const activeChecks = options.category
|
|
77
|
+
? new Set(CATEGORY_CHECKS[options.category])
|
|
78
|
+
: null; // null = run all
|
|
79
|
+
// Run checks — when category is specified, only run matching subset
|
|
80
|
+
if (activeChecks) {
|
|
81
|
+
// Category-filtered run
|
|
82
|
+
if (activeChecks.has('checkInstallation'))
|
|
83
|
+
results.push(...checkInstallation(projectRoot, manifest));
|
|
84
|
+
if (activeChecks.has('checkCoreFiles'))
|
|
85
|
+
results.push(...checkCoreFiles(projectRoot, manifest));
|
|
86
|
+
if (activeChecks.has('checkCommandsAndSkills'))
|
|
87
|
+
results.push(...checkCommandsAndSkills(projectRoot, nodeModulesPath));
|
|
88
|
+
if (activeChecks.has('checkUserFilesBasic'))
|
|
89
|
+
results.push(...checkUserFilesBasic(projectRoot));
|
|
90
|
+
if (activeChecks.has('checkSettingsHooks'))
|
|
91
|
+
results.push(...checkSettingsHooks(projectRoot));
|
|
92
|
+
if (activeChecks.has('checkDirectories'))
|
|
93
|
+
results.push(...checkDirectories(projectRoot));
|
|
94
|
+
if (activeChecks.has('checkHooks'))
|
|
95
|
+
results.push(...checkHooks(projectRoot));
|
|
96
|
+
if (activeChecks.has('checkGitHooks'))
|
|
97
|
+
results.push(...checkGitHooks(projectRoot, nodeModulesPath));
|
|
98
|
+
if (activeChecks.has('checkFileLayout'))
|
|
99
|
+
results.push(...checkFileLayout(projectRoot));
|
|
100
|
+
if (activeChecks.has('checkLegacyFiles'))
|
|
101
|
+
results.push(...checkLegacyFiles(projectRoot));
|
|
102
|
+
if (activeChecks.has('checkLegacyStatuslinePath'))
|
|
103
|
+
results.push(checkLegacyStatuslinePath(projectRoot));
|
|
104
|
+
if (activeChecks.has('checkLegacyHookCommands'))
|
|
105
|
+
results.push(checkLegacyHookCommands(projectRoot));
|
|
106
|
+
if (activeChecks.has('checkCyclist'))
|
|
107
|
+
results.push(...checkCyclist(projectRoot));
|
|
108
|
+
if (activeChecks.has('checkPfCli'))
|
|
109
|
+
results.push(checkPfCli(nodeModulesPath));
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Full run — original behavior
|
|
113
|
+
results.push(...checkInstallation(projectRoot, manifest));
|
|
114
|
+
results.push(...checkCoreFiles(projectRoot, manifest));
|
|
115
|
+
results.push(...checkCommandsAndSkills(projectRoot, nodeModulesPath));
|
|
116
|
+
results.push(...checkUserFiles(projectRoot));
|
|
117
|
+
results.push(...checkDirectories(projectRoot));
|
|
118
|
+
results.push(...checkHooks(projectRoot));
|
|
119
|
+
results.push(...checkGitHooks(projectRoot, nodeModulesPath));
|
|
120
|
+
results.push(...checkFileLayout(projectRoot));
|
|
121
|
+
results.push(...checkLegacyFiles(projectRoot));
|
|
122
|
+
results.push(checkLegacyStatuslinePath(projectRoot));
|
|
123
|
+
results.push(checkLegacyHookCommands(projectRoot));
|
|
124
|
+
results.push(...checkCyclist(projectRoot));
|
|
125
|
+
results.push(checkPfCli(nodeModulesPath));
|
|
126
|
+
}
|
|
62
127
|
// Output results
|
|
63
128
|
if (options.json) {
|
|
64
129
|
console.log(JSON.stringify(results, null, 2));
|
|
@@ -124,7 +189,7 @@ export async function doctorCommand(options) {
|
|
|
124
189
|
process.exit(1);
|
|
125
190
|
}
|
|
126
191
|
}
|
|
127
|
-
function checkInstallation(projectRoot, manifest) {
|
|
192
|
+
export function checkInstallation(projectRoot, manifest) {
|
|
128
193
|
const results = [];
|
|
129
194
|
// Check manifest exists
|
|
130
195
|
results.push({
|
|
@@ -134,7 +199,7 @@ function checkInstallation(projectRoot, manifest) {
|
|
|
134
199
|
});
|
|
135
200
|
return results;
|
|
136
201
|
}
|
|
137
|
-
function checkCoreFiles(projectRoot, manifest) {
|
|
202
|
+
export function checkCoreFiles(projectRoot, manifest) {
|
|
138
203
|
const results = [];
|
|
139
204
|
const installationType = manifest?.installationType || 'copy';
|
|
140
205
|
const nodeModulesPath = findNodeModulesPath(projectRoot);
|
|
@@ -196,7 +261,7 @@ function checkCoreFiles(projectRoot, manifest) {
|
|
|
196
261
|
* Check commands and skills are properly copied (not symlinked) and up to date.
|
|
197
262
|
* Commands and skills are file copies since v11.3.0 to avoid node_modules drift.
|
|
198
263
|
*/
|
|
199
|
-
function checkCommandsAndSkills(projectRoot,
|
|
264
|
+
export function checkCommandsAndSkills(projectRoot, _nodeModulesPath) {
|
|
200
265
|
const results = [];
|
|
201
266
|
// Use assetsPath for source resolution (correct pf-* prefix in dogfood)
|
|
202
267
|
let assetsPath = null;
|
|
@@ -480,6 +545,91 @@ function checkSymlinks(projectRoot, nodeModulesPath) {
|
|
|
480
545
|
}
|
|
481
546
|
return results;
|
|
482
547
|
}
|
|
548
|
+
/**
|
|
549
|
+
* Check basic user files only (project dir, sidecars, persona config, settings.local.json existence).
|
|
550
|
+
* Does NOT include the settings hook checks — use checkSettingsHooks() for those.
|
|
551
|
+
* Used by --category commands to separate user file checks from hook configuration checks.
|
|
552
|
+
*/
|
|
553
|
+
export function checkUserFilesBasic(projectRoot) {
|
|
554
|
+
const results = [];
|
|
555
|
+
const manifest = readManifest(projectRoot);
|
|
556
|
+
const installationType = manifest?.installationType || 'copy';
|
|
557
|
+
// Check project directory
|
|
558
|
+
const projectDir = join(projectRoot, '.claude/project');
|
|
559
|
+
results.push({
|
|
560
|
+
name: 'project/directory',
|
|
561
|
+
status: pathExists(projectDir) ? 'pass' : 'warn',
|
|
562
|
+
detail: pathExists(projectDir) ? undefined : 'Run init to create'
|
|
563
|
+
});
|
|
564
|
+
// Check agent sidecars (now in .pennyfarthing/sidecars/)
|
|
565
|
+
const sidecarsDir = join(projectRoot, '.pennyfarthing/sidecars');
|
|
566
|
+
if (pathExists(sidecarsDir)) {
|
|
567
|
+
const existingSidecars = CORE_AGENTS.filter(a => pathExists(join(sidecarsDir, a)));
|
|
568
|
+
results.push({
|
|
569
|
+
name: 'project/sidecars',
|
|
570
|
+
status: existingSidecars.length > 0 ? 'pass' : 'warn',
|
|
571
|
+
detail: `${existingSidecars.length} agent sidecars configured`
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
// Check persona config at canonical location
|
|
575
|
+
const personaConfig = join(projectRoot, '.pennyfarthing/config.local.yaml');
|
|
576
|
+
results.push({
|
|
577
|
+
name: 'persona-config',
|
|
578
|
+
status: pathExists(personaConfig) ? 'pass' : 'warn',
|
|
579
|
+
detail: pathExists(personaConfig) ? undefined : 'No theme configured'
|
|
580
|
+
});
|
|
581
|
+
// Check settings.local.json exists (CRITICAL - registers hooks with Claude Code)
|
|
582
|
+
const settingsLocal = join(projectRoot, '.claude/settings.local.json');
|
|
583
|
+
if (!pathExists(settingsLocal)) {
|
|
584
|
+
results.push({
|
|
585
|
+
name: 'settings.local.json',
|
|
586
|
+
status: 'fail',
|
|
587
|
+
detail: 'Missing - hooks not registered with Claude Code!',
|
|
588
|
+
fix: () => {
|
|
589
|
+
createSettingsLocalJson(projectRoot, installationType);
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
else {
|
|
594
|
+
results.push({
|
|
595
|
+
name: 'settings.local.json',
|
|
596
|
+
status: 'pass',
|
|
597
|
+
detail: undefined
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
return results;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Check all settings hook configurations in settings.local.json.
|
|
604
|
+
* Returns results for all 9 hook checks (session-start, otel, auto-load-sm,
|
|
605
|
+
* stop, post-tool-use, benchmark-permissions, context-circuit-breaker,
|
|
606
|
+
* schema-validation, sprint-yaml-validation).
|
|
607
|
+
* Used by --category hooks for targeted hook configuration checking.
|
|
608
|
+
*/
|
|
609
|
+
export function checkSettingsHooks(projectRoot) {
|
|
610
|
+
const results = [];
|
|
611
|
+
const manifest = readManifest(projectRoot);
|
|
612
|
+
const installationType = manifest?.installationType || 'copy';
|
|
613
|
+
const settingsLocal = join(projectRoot, '.claude/settings.local.json');
|
|
614
|
+
if (!pathExists(settingsLocal)) {
|
|
615
|
+
results.push({
|
|
616
|
+
name: 'settings.local.json',
|
|
617
|
+
status: 'fail',
|
|
618
|
+
detail: 'Missing - cannot check hook configuration'
|
|
619
|
+
});
|
|
620
|
+
return results;
|
|
621
|
+
}
|
|
622
|
+
results.push(checkSessionStartHooks(projectRoot, installationType));
|
|
623
|
+
results.push(checkOtelAutoStart(projectRoot, installationType));
|
|
624
|
+
results.push(checkAutoLoadSmHook(projectRoot));
|
|
625
|
+
results.push(checkStopHook(projectRoot, installationType));
|
|
626
|
+
results.push(checkPostToolUseHook(projectRoot, installationType));
|
|
627
|
+
results.push(checkBenchmarkPermissions(projectRoot));
|
|
628
|
+
results.push(checkContextCircuitBreaker(projectRoot, installationType));
|
|
629
|
+
results.push(checkSchemaValidationHook(projectRoot, installationType));
|
|
630
|
+
results.push(checkSprintYamlValidationHook(projectRoot, installationType));
|
|
631
|
+
return results;
|
|
632
|
+
}
|
|
483
633
|
function checkUserFiles(projectRoot) {
|
|
484
634
|
const results = [];
|
|
485
635
|
// Detect installation type from manifest
|
|
@@ -530,6 +680,9 @@ function checkUserFiles(projectRoot) {
|
|
|
530
680
|
// Check SessionStart hooks are configured (critical for PROJECT_ROOT)
|
|
531
681
|
const hookCheck = checkSessionStartHooks(projectRoot, installationType);
|
|
532
682
|
results.push(hookCheck);
|
|
683
|
+
// Check OTEL auto-configuration (WheelHub auto-start + telemetry env vars)
|
|
684
|
+
const otelCheck = checkOtelAutoStart(projectRoot, installationType);
|
|
685
|
+
results.push(otelCheck);
|
|
533
686
|
// Check auto-load-sm hook is configured (auto-invokes /sm on new sessions)
|
|
534
687
|
const autoLoadSmCheck = checkAutoLoadSmHook(projectRoot);
|
|
535
688
|
results.push(autoLoadSmCheck);
|
|
@@ -654,7 +807,7 @@ function checkSessionStartHooks(projectRoot, installationType) {
|
|
|
654
807
|
const hasSessionStartHook = settings.hooks.SessionStart.some((entry) => {
|
|
655
808
|
if (typeof entry === 'object' && entry !== null) {
|
|
656
809
|
const hookEntry = entry;
|
|
657
|
-
return hookEntry.hooks?.some(h => h.command?.includes('pf hooks session-start') || h.command?.includes('session-start.sh'));
|
|
810
|
+
return hookEntry.hooks?.some(h => h.command?.includes('pf.sh hooks session-start') || h.command?.includes('pf hooks session-start') || h.command?.includes('session-start.sh'));
|
|
658
811
|
}
|
|
659
812
|
return false;
|
|
660
813
|
});
|
|
@@ -682,6 +835,96 @@ function checkSessionStartHooks(projectRoot, installationType) {
|
|
|
682
835
|
};
|
|
683
836
|
}
|
|
684
837
|
}
|
|
838
|
+
/**
|
|
839
|
+
* Check that session-start hook uses `pf hooks session-start` (Python version)
|
|
840
|
+
* which handles WheelHub auto-start + OTEL env var configuration.
|
|
841
|
+
* Legacy .sh hooks only set 2 of 5 required OTEL vars, breaking telemetry.
|
|
842
|
+
*/
|
|
843
|
+
function checkOtelAutoStart(projectRoot, installationType) {
|
|
844
|
+
const settingsPath = join(projectRoot, '.claude/settings.local.json');
|
|
845
|
+
try {
|
|
846
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
847
|
+
if (!settings.hooks?.SessionStart) {
|
|
848
|
+
return {
|
|
849
|
+
name: 'settings/otel-auto-start',
|
|
850
|
+
status: 'warn',
|
|
851
|
+
detail: 'No SessionStart hooks — WheelHub auto-start and OTEL not configured',
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
// Check if `pf hooks session-start` is used (Python version with full OTEL support)
|
|
855
|
+
const hasPfHooksSessionStart = settings.hooks.SessionStart.some((entry) => {
|
|
856
|
+
if (typeof entry === 'object' && entry !== null) {
|
|
857
|
+
const hookEntry = entry;
|
|
858
|
+
return hookEntry.hooks?.some(h => h.command?.includes('pf.sh hooks session-start') || h.command?.includes('pf hooks session-start'));
|
|
859
|
+
}
|
|
860
|
+
return false;
|
|
861
|
+
});
|
|
862
|
+
if (hasPfHooksSessionStart) {
|
|
863
|
+
return {
|
|
864
|
+
name: 'settings/otel-auto-start',
|
|
865
|
+
status: 'pass',
|
|
866
|
+
detail: undefined,
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
// Check if using legacy .sh (only sets 2 of 5 OTEL vars)
|
|
870
|
+
const hasLegacySh = settings.hooks.SessionStart.some((entry) => {
|
|
871
|
+
if (typeof entry === 'object' && entry !== null) {
|
|
872
|
+
const hookEntry = entry;
|
|
873
|
+
return hookEntry.hooks?.some(h => h.command?.includes('session-start.sh'));
|
|
874
|
+
}
|
|
875
|
+
return false;
|
|
876
|
+
});
|
|
877
|
+
if (hasLegacySh) {
|
|
878
|
+
return {
|
|
879
|
+
name: 'settings/otel-auto-start',
|
|
880
|
+
status: 'warn',
|
|
881
|
+
detail: 'Using legacy session-start.sh — missing WheelHub auto-start and 3 OTEL env vars. Migrate to `pf hooks session-start`',
|
|
882
|
+
fix: () => {
|
|
883
|
+
migrateSessionStartToPfHooks(projectRoot);
|
|
884
|
+
},
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
return {
|
|
888
|
+
name: 'settings/otel-auto-start',
|
|
889
|
+
status: 'warn',
|
|
890
|
+
detail: 'session-start hook not found — WheelHub auto-start and OTEL not configured',
|
|
891
|
+
fix: () => {
|
|
892
|
+
addSessionStartHooks(projectRoot, installationType);
|
|
893
|
+
},
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
catch {
|
|
897
|
+
return {
|
|
898
|
+
name: 'settings/otel-auto-start',
|
|
899
|
+
status: 'warn',
|
|
900
|
+
detail: 'Could not parse settings.local.json',
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Migrate legacy session-start.sh hooks to `pf hooks session-start`
|
|
906
|
+
*/
|
|
907
|
+
function migrateSessionStartToPfHooks(projectRoot) {
|
|
908
|
+
const settingsPath = join(projectRoot, '.claude/settings.local.json');
|
|
909
|
+
try {
|
|
910
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
911
|
+
if (Array.isArray(settings.hooks?.SessionStart)) {
|
|
912
|
+
for (const entry of settings.hooks.SessionStart) {
|
|
913
|
+
if (typeof entry === 'object' && entry !== null && Array.isArray(entry.hooks)) {
|
|
914
|
+
for (const h of entry.hooks) {
|
|
915
|
+
if (h.command?.includes('session-start.sh')) {
|
|
916
|
+
h.command = '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks session-start';
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
923
|
+
}
|
|
924
|
+
catch {
|
|
925
|
+
// Silent fail — doctor will re-report on next run
|
|
926
|
+
}
|
|
927
|
+
}
|
|
685
928
|
/**
|
|
686
929
|
* Check that auto-load-sm hook is configured in SessionStart
|
|
687
930
|
* This auto-invokes /sm agent on new session start
|
|
@@ -832,7 +1075,7 @@ function checkStopHook(projectRoot, installationType) {
|
|
|
832
1075
|
const hasReflectorHook = settings.hooks.Stop.some((entry) => {
|
|
833
1076
|
if (typeof entry === 'object' && entry !== null) {
|
|
834
1077
|
const hookEntry = entry;
|
|
835
|
-
return hookEntry.hooks?.some(h => h.command?.includes('pf hooks reflector-check') || h.command?.includes('question-reflector-check'));
|
|
1078
|
+
return hookEntry.hooks?.some(h => h.command?.includes('pf.sh hooks reflector-check') || h.command?.includes('pf hooks reflector-check') || h.command?.includes('question-reflector-check'));
|
|
836
1079
|
}
|
|
837
1080
|
return false;
|
|
838
1081
|
});
|
|
@@ -883,7 +1126,7 @@ function checkContextCircuitBreaker(projectRoot, installationType) {
|
|
|
883
1126
|
const hasCircuitBreaker = settings.hooks.PreToolUse.some((entry) => {
|
|
884
1127
|
if (typeof entry === 'object' && entry !== null) {
|
|
885
1128
|
const hookEntry = entry;
|
|
886
|
-
return hookEntry.hooks?.some(h => h.command?.includes('pf hooks context-breaker') || h.command?.includes('context-circuit-breaker'));
|
|
1129
|
+
return hookEntry.hooks?.some(h => h.command?.includes('pf.sh hooks context-breaker') || h.command?.includes('pf hooks context-breaker') || h.command?.includes('context-circuit-breaker'));
|
|
887
1130
|
}
|
|
888
1131
|
return false;
|
|
889
1132
|
});
|
|
@@ -921,7 +1164,7 @@ function addContextCircuitBreaker(projectRoot, _installationType) {
|
|
|
921
1164
|
hooks: [
|
|
922
1165
|
{
|
|
923
1166
|
type: 'command',
|
|
924
|
-
command: 'pf hooks context-breaker'
|
|
1167
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks context-breaker'
|
|
925
1168
|
}
|
|
926
1169
|
]
|
|
927
1170
|
};
|
|
@@ -1009,7 +1252,7 @@ function addSchemaValidationHook(projectRoot, _installationType) {
|
|
|
1009
1252
|
hooks: [
|
|
1010
1253
|
{
|
|
1011
1254
|
type: 'command',
|
|
1012
|
-
command: 'pf hooks schema-validation'
|
|
1255
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks schema-validation'
|
|
1013
1256
|
}
|
|
1014
1257
|
]
|
|
1015
1258
|
};
|
|
@@ -1059,7 +1302,7 @@ function checkPostToolUseHook(projectRoot, installationType) {
|
|
|
1059
1302
|
const hasBellModeHook = settings.hooks.PostToolUse.some((entry) => {
|
|
1060
1303
|
if (typeof entry === 'object' && entry !== null) {
|
|
1061
1304
|
const hookEntry = entry;
|
|
1062
|
-
return hookEntry.hooks?.some(h => h.command?.includes('pf hooks bell-mode') || h.command?.includes('bell-mode-hook'));
|
|
1305
|
+
return hookEntry.hooks?.some(h => h.command?.includes('pf.sh hooks bell-mode') || h.command?.includes('pf hooks bell-mode') || h.command?.includes('bell-mode-hook'));
|
|
1063
1306
|
}
|
|
1064
1307
|
return false;
|
|
1065
1308
|
});
|
|
@@ -1098,7 +1341,7 @@ function addPostToolUseHook(projectRoot, _installationType) {
|
|
|
1098
1341
|
hooks: [
|
|
1099
1342
|
{
|
|
1100
1343
|
type: 'command',
|
|
1101
|
-
command: 'pf hooks bell-mode'
|
|
1344
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks bell-mode'
|
|
1102
1345
|
}
|
|
1103
1346
|
]
|
|
1104
1347
|
};
|
|
@@ -1148,7 +1391,7 @@ function checkSprintYamlValidationHook(projectRoot, installationType) {
|
|
|
1148
1391
|
const hasSprintYamlValidation = settings.hooks.PostToolUse.some((entry) => {
|
|
1149
1392
|
if (typeof entry === 'object' && entry !== null) {
|
|
1150
1393
|
const hookEntry = entry;
|
|
1151
|
-
return hookEntry.hooks?.some(h => h.command?.includes('pf hooks sprint-yaml') || h.command?.includes('sprint-yaml-validation'));
|
|
1394
|
+
return hookEntry.hooks?.some(h => h.command?.includes('pf.sh hooks sprint-yaml') || h.command?.includes('pf hooks sprint-yaml') || h.command?.includes('sprint-yaml-validation'));
|
|
1152
1395
|
}
|
|
1153
1396
|
return false;
|
|
1154
1397
|
});
|
|
@@ -1187,7 +1430,7 @@ function addSprintYamlValidationHook(projectRoot, _installationType) {
|
|
|
1187
1430
|
hooks: [
|
|
1188
1431
|
{
|
|
1189
1432
|
type: 'command',
|
|
1190
|
-
command: 'pf hooks sprint-yaml'
|
|
1433
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks sprint-yaml'
|
|
1191
1434
|
}
|
|
1192
1435
|
]
|
|
1193
1436
|
};
|
|
@@ -1225,7 +1468,7 @@ function addStopHook(projectRoot, _installationType) {
|
|
|
1225
1468
|
hooks: [
|
|
1226
1469
|
{
|
|
1227
1470
|
type: 'command',
|
|
1228
|
-
command: 'pf hooks reflector-check'
|
|
1471
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks reflector-check'
|
|
1229
1472
|
}
|
|
1230
1473
|
]
|
|
1231
1474
|
},
|
|
@@ -1234,7 +1477,7 @@ function addStopHook(projectRoot, _installationType) {
|
|
|
1234
1477
|
hooks: [
|
|
1235
1478
|
{
|
|
1236
1479
|
type: 'command',
|
|
1237
|
-
command: 'pf hooks session-stop'
|
|
1480
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks session-stop'
|
|
1238
1481
|
}
|
|
1239
1482
|
]
|
|
1240
1483
|
}
|
|
@@ -1282,7 +1525,7 @@ function addSessionStartHooks(projectRoot, _installationType) {
|
|
|
1282
1525
|
hooks: [
|
|
1283
1526
|
{
|
|
1284
1527
|
type: 'command',
|
|
1285
|
-
command: 'pf hooks session-start'
|
|
1528
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks session-start'
|
|
1286
1529
|
}
|
|
1287
1530
|
]
|
|
1288
1531
|
},
|
|
@@ -1376,7 +1619,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1376
1619
|
hooks: [
|
|
1377
1620
|
{
|
|
1378
1621
|
type: 'command',
|
|
1379
|
-
command: 'pf hooks session-start'
|
|
1622
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks session-start'
|
|
1380
1623
|
}
|
|
1381
1624
|
]
|
|
1382
1625
|
},
|
|
@@ -1404,7 +1647,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1404
1647
|
hooks: [
|
|
1405
1648
|
{
|
|
1406
1649
|
type: 'command',
|
|
1407
|
-
command: 'pf hooks reflector-check'
|
|
1650
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks reflector-check'
|
|
1408
1651
|
}
|
|
1409
1652
|
]
|
|
1410
1653
|
},
|
|
@@ -1413,7 +1656,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1413
1656
|
hooks: [
|
|
1414
1657
|
{
|
|
1415
1658
|
type: 'command',
|
|
1416
|
-
command: 'pf hooks session-stop'
|
|
1659
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks session-stop'
|
|
1417
1660
|
}
|
|
1418
1661
|
]
|
|
1419
1662
|
}
|
|
@@ -1424,7 +1667,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1424
1667
|
hooks: [
|
|
1425
1668
|
{
|
|
1426
1669
|
type: 'command',
|
|
1427
|
-
command: 'pf hooks bell-mode'
|
|
1670
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks bell-mode'
|
|
1428
1671
|
}
|
|
1429
1672
|
]
|
|
1430
1673
|
},
|
|
@@ -1433,7 +1676,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1433
1676
|
hooks: [
|
|
1434
1677
|
{
|
|
1435
1678
|
type: 'command',
|
|
1436
|
-
command: 'pf hooks sprint-yaml'
|
|
1679
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks sprint-yaml'
|
|
1437
1680
|
}
|
|
1438
1681
|
]
|
|
1439
1682
|
}
|
|
@@ -1444,7 +1687,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1444
1687
|
hooks: [
|
|
1445
1688
|
{
|
|
1446
1689
|
type: 'command',
|
|
1447
|
-
command: 'pf hooks pre-edit-check'
|
|
1690
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks pre-edit-check'
|
|
1448
1691
|
}
|
|
1449
1692
|
]
|
|
1450
1693
|
},
|
|
@@ -1453,7 +1696,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1453
1696
|
hooks: [
|
|
1454
1697
|
{
|
|
1455
1698
|
type: 'command',
|
|
1456
|
-
command: 'pf hooks schema-validation'
|
|
1699
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks schema-validation'
|
|
1457
1700
|
}
|
|
1458
1701
|
]
|
|
1459
1702
|
},
|
|
@@ -1462,7 +1705,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1462
1705
|
hooks: [
|
|
1463
1706
|
{
|
|
1464
1707
|
type: 'command',
|
|
1465
|
-
command: 'pf hooks context-warning'
|
|
1708
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks context-warning'
|
|
1466
1709
|
}
|
|
1467
1710
|
]
|
|
1468
1711
|
},
|
|
@@ -1471,7 +1714,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1471
1714
|
hooks: [
|
|
1472
1715
|
{
|
|
1473
1716
|
type: 'command',
|
|
1474
|
-
command: 'pf hooks context-breaker'
|
|
1717
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks context-breaker'
|
|
1475
1718
|
}
|
|
1476
1719
|
]
|
|
1477
1720
|
},
|
|
@@ -1479,7 +1722,7 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1479
1722
|
hooks: [
|
|
1480
1723
|
{
|
|
1481
1724
|
type: 'command',
|
|
1482
|
-
command: 'pf hooks cyclist-pretooluse'
|
|
1725
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks cyclist-pretooluse'
|
|
1483
1726
|
}
|
|
1484
1727
|
]
|
|
1485
1728
|
}
|
|
@@ -1487,13 +1730,13 @@ function createSettingsLocalJson(projectRoot, _installationType) {
|
|
|
1487
1730
|
},
|
|
1488
1731
|
statusLine: {
|
|
1489
1732
|
type: 'command',
|
|
1490
|
-
command: 'pf hooks statusline'
|
|
1733
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks statusline'
|
|
1491
1734
|
}
|
|
1492
1735
|
};
|
|
1493
1736
|
ensureDirSync(join(projectRoot, '.claude'));
|
|
1494
1737
|
writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
1495
1738
|
}
|
|
1496
|
-
function checkDirectories(projectRoot) {
|
|
1739
|
+
export function checkDirectories(projectRoot) {
|
|
1497
1740
|
const results = [];
|
|
1498
1741
|
const dirs = [
|
|
1499
1742
|
{ path: 'sprint', name: 'dir/sprint' },
|
|
@@ -1509,7 +1752,7 @@ function checkDirectories(projectRoot) {
|
|
|
1509
1752
|
}
|
|
1510
1753
|
return results;
|
|
1511
1754
|
}
|
|
1512
|
-
function checkHooks(projectRoot) {
|
|
1755
|
+
export function checkHooks(projectRoot) {
|
|
1513
1756
|
const results = [];
|
|
1514
1757
|
// Detect installation type from manifest
|
|
1515
1758
|
const manifest = readManifest(projectRoot);
|
|
@@ -1566,7 +1809,7 @@ function checkHooks(projectRoot) {
|
|
|
1566
1809
|
* symlinked rather than copied, since symlinks stay current automatically.
|
|
1567
1810
|
* Provides --fix to refresh stale hooks or replace copies with symlinks.
|
|
1568
1811
|
*/
|
|
1569
|
-
function checkGitHooks(projectRoot, nodeModulesPath) {
|
|
1812
|
+
export function checkGitHooks(projectRoot, nodeModulesPath) {
|
|
1570
1813
|
const results = [];
|
|
1571
1814
|
// Use git rev-parse to find the actual git dir (handles worktrees where .git is a file)
|
|
1572
1815
|
const gitDirResult = spawnSync('git', ['rev-parse', '--git-dir'], { cwd: projectRoot, encoding: 'utf8' });
|
|
@@ -1710,7 +1953,7 @@ function checkGitHooks(projectRoot, nodeModulesPath) {
|
|
|
1710
1953
|
* Check Cyclist installation health (if installed as a workspace package)
|
|
1711
1954
|
* Detects node-pty spawn-helper permission issues that cause posix_spawnp failures
|
|
1712
1955
|
*/
|
|
1713
|
-
function checkCyclist(projectRoot) {
|
|
1956
|
+
export function checkCyclist(projectRoot) {
|
|
1714
1957
|
const results = [];
|
|
1715
1958
|
// Detect Cyclist package — check common locations
|
|
1716
1959
|
const cyclistLocations = [
|
|
@@ -1812,7 +2055,7 @@ function checkCyclist(projectRoot) {
|
|
|
1812
2055
|
* Check if the pf CLI is installed and working.
|
|
1813
2056
|
* The pf CLI is required for agent commands (e.g., `pf agent start "dev"`).
|
|
1814
2057
|
*/
|
|
1815
|
-
function checkPfCli(nodeModulesPath) {
|
|
2058
|
+
export function checkPfCli(nodeModulesPath) {
|
|
1816
2059
|
const version = getPfVersion();
|
|
1817
2060
|
if (version) {
|
|
1818
2061
|
return {
|
|
@@ -2049,7 +2292,7 @@ export function checkLegacyStatuslinePath(projectRoot) {
|
|
|
2049
2292
|
const pathMatch = command.match(/(?:\"\$CLAUDE_PROJECT_DIR\"\/)?([^\s"]+)/);
|
|
2050
2293
|
const currentPath = pathMatch ? pathMatch[1] : command;
|
|
2051
2294
|
// Check if it's the canonical pf hooks command or the legacy .sh path
|
|
2052
|
-
if (command === 'pf hooks statusline' || currentPath.includes('misc/statusline.sh') || command.includes('misc/statusline.sh')) {
|
|
2295
|
+
if (command.includes('pf.sh hooks statusline') || command === 'pf hooks statusline' || currentPath.includes('misc/statusline.sh') || command.includes('misc/statusline.sh')) {
|
|
2053
2296
|
return {
|
|
2054
2297
|
name: 'settings/statusline-path',
|
|
2055
2298
|
status: 'pass',
|
|
@@ -2070,7 +2313,7 @@ export function checkLegacyStatuslinePath(projectRoot) {
|
|
|
2070
2313
|
const updatedSettings = { ...settings };
|
|
2071
2314
|
updatedSettings.statusLine = {
|
|
2072
2315
|
type: 'command',
|
|
2073
|
-
command: 'pf hooks statusline'
|
|
2316
|
+
command: '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh hooks statusline'
|
|
2074
2317
|
};
|
|
2075
2318
|
writeFileSync(settingsPath, JSON.stringify(updatedSettings, null, 2));
|
|
2076
2319
|
}
|
|
@@ -2089,7 +2332,7 @@ export function checkLegacyStatuslinePath(projectRoot) {
|
|
|
2089
2332
|
* be migrated to `pf hooks` commands. The .sh scripts still work (they're shims)
|
|
2090
2333
|
* but `pf hooks` is the canonical path — faster, no shell indirection.
|
|
2091
2334
|
*/
|
|
2092
|
-
function checkLegacyHookCommands(projectRoot) {
|
|
2335
|
+
export function checkLegacyHookCommands(projectRoot) {
|
|
2093
2336
|
const settingsPath = join(projectRoot, '.claude/settings.local.json');
|
|
2094
2337
|
if (!pathExists(settingsPath)) {
|
|
2095
2338
|
return { name: 'legacy/hook-commands', status: 'pass', detail: 'No settings file' };
|
|
@@ -2126,7 +2369,7 @@ function checkLegacyHookCommands(projectRoot) {
|
|
|
2126
2369
|
}
|
|
2127
2370
|
// Also check statusLine
|
|
2128
2371
|
const statusLine = settings.statusLine;
|
|
2129
|
-
if (statusLine?.command && statusLine.command !== 'pf hooks statusline') {
|
|
2372
|
+
if (statusLine?.command && !statusLine.command.includes('pf.sh hooks statusline') && statusLine.command !== 'pf hooks statusline') {
|
|
2130
2373
|
for (const shName of Object.keys(LEGACY_HOOK_MIGRATIONS)) {
|
|
2131
2374
|
if (statusLine.command.includes(shName)) {
|
|
2132
2375
|
legacyCount++;
|
|
@@ -2148,7 +2391,7 @@ function checkLegacyHookCommands(projectRoot) {
|
|
|
2148
2391
|
}
|
|
2149
2392
|
}
|
|
2150
2393
|
// Migrate statusLine
|
|
2151
|
-
if (statusLine?.command && statusLine.command !== 'pf hooks statusline') {
|
|
2394
|
+
if (statusLine?.command && !statusLine.command.includes('pf.sh hooks statusline') && statusLine.command !== 'pf hooks statusline') {
|
|
2152
2395
|
for (const [shName, pfCommand] of Object.entries(LEGACY_HOOK_MIGRATIONS)) {
|
|
2153
2396
|
if (statusLine.command.includes(shName)) {
|
|
2154
2397
|
statusLine.command = pfCommand;
|
|
@@ -2261,6 +2504,26 @@ export function checkFileLayout(projectRoot) {
|
|
|
2261
2504
|
status: 'pass',
|
|
2262
2505
|
detail: undefined
|
|
2263
2506
|
});
|
|
2507
|
+
// Check execute permission on each shell script in project hooks
|
|
2508
|
+
try {
|
|
2509
|
+
const hookFiles = readdirSync(projectHooksPath).filter(f => f.endsWith('.sh'));
|
|
2510
|
+
for (const file of hookFiles) {
|
|
2511
|
+
const hookPath = join(projectHooksPath, file);
|
|
2512
|
+
const stats = statSync(hookPath);
|
|
2513
|
+
const isExecutable = (stats.mode & 0o111) !== 0;
|
|
2514
|
+
results.push({
|
|
2515
|
+
name: `layout/project-hooks/${file}`,
|
|
2516
|
+
status: isExecutable ? 'pass' : 'warn',
|
|
2517
|
+
detail: isExecutable ? undefined : 'Not executable — will cause Permission denied on session start',
|
|
2518
|
+
fix: isExecutable ? undefined : () => {
|
|
2519
|
+
chmodSync(hookPath, 0o755);
|
|
2520
|
+
}
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
catch {
|
|
2525
|
+
// Ignore read errors
|
|
2526
|
+
}
|
|
2264
2527
|
}
|
|
2265
2528
|
// 8. Old project hooks at .claude/project/hooks/
|
|
2266
2529
|
const oldProjectHooksPath = join(projectRoot, '.claude/project/hooks');
|
|
@@ -2290,6 +2553,17 @@ export function checkFileLayout(projectRoot) {
|
|
|
2290
2553
|
}
|
|
2291
2554
|
removeSync(oldProjectHooksPath);
|
|
2292
2555
|
}
|
|
2556
|
+
// Ensure migrated shell scripts are executable
|
|
2557
|
+
try {
|
|
2558
|
+
for (const file of readdirSync(projectHooksPath)) {
|
|
2559
|
+
if (file.endsWith('.sh')) {
|
|
2560
|
+
chmodSync(join(projectHooksPath, file), 0o755);
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
}
|
|
2564
|
+
catch {
|
|
2565
|
+
// Ignore
|
|
2566
|
+
}
|
|
2293
2567
|
}
|
|
2294
2568
|
});
|
|
2295
2569
|
}
|