@pennyfarthing/core 11.1.1 → 11.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/package.json +2 -1
- package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/doctor.js +381 -66
- package/packages/core/dist/cli/commands/doctor.js.map +1 -1
- package/packages/core/dist/cli/commands/init.js +4 -4
- package/packages/core/dist/cli/commands/init.js.map +1 -1
- package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/update.js +4 -5
- package/packages/core/dist/cli/commands/update.js.map +1 -1
- package/packages/core/dist/cli/utils/constants.d.ts +3 -8
- package/packages/core/dist/cli/utils/constants.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/constants.js +3 -4
- package/packages/core/dist/cli/utils/constants.js.map +1 -1
- package/packages/core/dist/cli/utils/settings.d.ts +11 -0
- package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/settings.js +65 -29
- package/packages/core/dist/cli/utils/settings.js.map +1 -1
- package/packages/core/dist/cli/utils/symlinks.js +16 -16
- package/packages/core/dist/cli/utils/symlinks.js.map +1 -1
- package/packages/core/dist/consultation/tandem-metrics.d.ts +91 -0
- package/packages/core/dist/consultation/tandem-metrics.d.ts.map +1 -0
- package/packages/core/dist/consultation/tandem-metrics.js +131 -0
- package/packages/core/dist/consultation/tandem-metrics.js.map +1 -0
- package/packages/core/dist/consultation/tandem-metrics.test.d.ts +18 -0
- package/packages/core/dist/consultation/tandem-metrics.test.d.ts.map +1 -0
- package/packages/core/dist/consultation/tandem-metrics.test.js +457 -0
- package/packages/core/dist/consultation/tandem-metrics.test.js.map +1 -0
- package/packages/core/dist/public/js/react/react.js +14 -14
- package/packages/core/dist/scripts/benchmark-integration.d.ts +182 -0
- package/packages/core/dist/scripts/benchmark-integration.d.ts.map +1 -0
- package/packages/core/dist/scripts/benchmark-integration.js +691 -0
- package/packages/core/dist/scripts/benchmark-integration.js.map +1 -0
- package/packages/core/dist/scripts/job-fair-aggregator.d.ts +150 -0
- package/packages/core/dist/scripts/job-fair-aggregator.d.ts.map +1 -0
- package/packages/core/dist/scripts/job-fair-aggregator.js +547 -0
- package/packages/core/dist/scripts/job-fair-aggregator.js.map +1 -0
- package/packages/core/dist/server/api/agent-load.js +1 -1
- package/packages/core/dist/server/api/agent-load.js.map +1 -1
- package/packages/core/dist/server/otlp-receiver.d.ts +16 -11
- package/packages/core/dist/server/otlp-receiver.d.ts.map +1 -1
- package/packages/core/dist/server/otlp-receiver.js +185 -24
- package/packages/core/dist/server/otlp-receiver.js.map +1 -1
- package/packages/core/dist/server/otlp-receiver.test.d.ts +21 -0
- package/packages/core/dist/server/otlp-receiver.test.d.ts.map +1 -0
- package/packages/core/dist/server/otlp-receiver.test.js +446 -0
- package/packages/core/dist/server/otlp-receiver.test.js.map +1 -0
- package/packages/core/dist/server/server.d.ts +0 -3
- package/packages/core/dist/server/server.d.ts.map +1 -1
- package/packages/core/dist/server/server.js +3 -37
- package/packages/core/dist/server/server.js.map +1 -1
- package/packages/core/dist/server/server.test.d.ts +1 -1
- package/packages/core/dist/server/server.test.js +12 -23
- package/packages/core/dist/server/server.test.js.map +1 -1
- package/packages/core/dist/shared/capabilities.d.ts +88 -0
- package/packages/core/dist/shared/capabilities.d.ts.map +1 -0
- package/packages/core/dist/shared/capabilities.js +133 -0
- package/packages/core/dist/shared/capabilities.js.map +1 -0
- package/packages/core/dist/shared/capabilities.test.d.ts +2 -0
- package/packages/core/dist/shared/capabilities.test.d.ts.map +1 -0
- package/packages/core/dist/shared/capabilities.test.js +217 -0
- package/packages/core/dist/shared/capabilities.test.js.map +1 -0
- package/packages/core/dist/shared/portrait-resolver.d.ts +9 -0
- package/packages/core/dist/shared/portrait-resolver.d.ts.map +1 -1
- package/packages/core/dist/shared/portrait-resolver.js +27 -0
- package/packages/core/dist/shared/portrait-resolver.js.map +1 -1
- package/packages/core/dist/shared/portrait-resolver.test.js +47 -1
- package/packages/core/dist/shared/portrait-resolver.test.js.map +1 -1
- package/packages/core/dist/shared/spawn-prompt.d.ts +47 -0
- package/packages/core/dist/shared/spawn-prompt.d.ts.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.js +82 -0
- package/packages/core/dist/shared/spawn-prompt.js.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.test.d.ts +2 -0
- package/packages/core/dist/shared/spawn-prompt.test.d.ts.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.test.js +251 -0
- package/packages/core/dist/shared/spawn-prompt.test.js.map +1 -0
- package/packages/core/dist/shared/tandem-portrait-inventory.test.d.ts +13 -0
- package/packages/core/dist/shared/tandem-portrait-inventory.test.d.ts.map +1 -0
- package/packages/core/dist/shared/tandem-portrait-inventory.test.js +126 -0
- package/packages/core/dist/shared/tandem-portrait-inventory.test.js.map +1 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts +18 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.js +434 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.js.map +1 -0
- package/packages/core/dist/workflow/workflow-schema.d.ts +32 -0
- package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.js +120 -0
- package/packages/core/dist/workflow/workflow-schema.js.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.test.d.ts.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.test.js +570 -1
- package/packages/core/dist/workflow/workflow-schema.test.js.map +1 -1
- package/pennyfarthing-dist/agents/dev.md +7 -11
- package/pennyfarthing-dist/agents/reviewer.md +9 -3
- package/pennyfarthing-dist/agents/sm-finish.md +18 -1
- package/pennyfarthing-dist/agents/sm-setup.md +1 -1
- package/pennyfarthing-dist/agents/sm.md +2 -2
- package/pennyfarthing-dist/agents/tea.md +1 -1
- package/pennyfarthing-dist/agents/testing-runner.md +2 -1
- package/pennyfarthing-dist/commands/pf-chore.md +2 -2
- package/pennyfarthing-dist/commands/pf-git.md +4 -2
- package/pennyfarthing-dist/commands/pf-standalone.md +7 -2
- package/pennyfarthing-dist/gates/approval.md +63 -0
- package/pennyfarthing-dist/gates/confidence-sm.md +71 -0
- package/pennyfarthing-dist/gates/context-ok.md +56 -0
- package/pennyfarthing-dist/gates/evaluations/confidence-sm.md +54 -0
- package/pennyfarthing-dist/gates/quality-pass.md +67 -0
- package/pennyfarthing-dist/gates/tests-fail.md +84 -0
- package/pennyfarthing-dist/gates/tests-pass.md +79 -0
- package/pennyfarthing-dist/guides/agent-behavior.md +23 -19
- package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +1 -1
- package/pennyfarthing-dist/guides/bell-mode.md +1 -1
- package/pennyfarthing-dist/guides/bikerack.md +3 -3
- package/pennyfarthing-dist/guides/hooks.md +29 -29
- package/pennyfarthing-dist/guides/reflector.md +1 -1
- package/pennyfarthing-dist/guides/tandem-protocol.md +3 -3
- package/pennyfarthing-dist/guides/worktree-mode.md +3 -3
- package/pennyfarthing-dist/guides/xml-tags.md +2 -2
- package/pennyfarthing-dist/scripts/README.md +1 -1
- package/pennyfarthing-dist/scripts/core/check-context.sh +3 -1
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +5 -87
- package/pennyfarthing-dist/scripts/git/README.md +24 -14
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +5 -266
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +5 -151
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +6 -144
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +5 -496
- package/pennyfarthing-dist/scripts/hooks/README.md +6 -6
- package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +4 -183
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +4 -95
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +4 -65
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +3 -31
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +9 -11
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +27 -33
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +4 -71
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +3 -19
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +4 -30
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +3 -32
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +4 -65
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +4 -78
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +4 -93
- package/pennyfarthing-dist/scripts/misc/README.md +1 -1
- package/pennyfarthing-dist/scripts/misc/statusline.sh +4 -301
- package/pennyfarthing-dist/scripts/portraits/generate-tandem-portraits.sh +76 -0
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +4 -221
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +5 -13
- package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +4 -123
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +4 -33
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +4 -156
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +4 -131
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +4 -249
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +4 -160
- package/pennyfarthing-dist/skills/pf-bc/usage.md +1 -1
- package/pennyfarthing-dist/skills/pf-jira/examples.md +5 -2
- package/pennyfarthing-dist/skills/pf-workflow/examples.md +27 -16
- package/pennyfarthing-dist/skills/pf-workflow/skill.md +9 -12
- package/pennyfarthing-dist/skills/pf-workflow/usage.md +33 -8
- package/pennyfarthing-dist/templates/settings.local.json.template +19 -10
- package/pennyfarthing-dist/workflows/bdd-tandem.yaml +18 -6
- 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/review-tandem.yaml +65 -0
- package/pennyfarthing-dist/workflows/tdd-tandem.yaml +16 -8
- package/pennyfarthing-dist/workflows/tdd.yaml +11 -2
- package/pennyfarthing_scripts/CLAUDE.md +45 -14
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/bellmode_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/context.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/cli.py +3 -5
- package/pennyfarthing_scripts/bellmode_hook.py +12 -296
- package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/audit_log_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/context_meter_footer.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/events.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/audit_log_panel.py +119 -0
- package/pennyfarthing_scripts/bikerack/background_panel.py +86 -5
- package/pennyfarthing_scripts/bikerack/base_panel.py +87 -2
- package/pennyfarthing_scripts/bikerack/changed_panel.py +125 -29
- package/pennyfarthing_scripts/bikerack/context_meter_footer.py +88 -0
- package/pennyfarthing_scripts/bikerack/debug_panel.py +32 -2
- package/pennyfarthing_scripts/bikerack/diffs_panel.py +104 -17
- package/pennyfarthing_scripts/bikerack/events.py +28 -0
- package/pennyfarthing_scripts/bikerack/git_panel.py +103 -33
- package/pennyfarthing_scripts/bikerack/launcher.py +15 -15
- package/pennyfarthing_scripts/bikerack/portrait_resolver.py +139 -0
- package/pennyfarthing_scripts/bikerack/progress_panel.py +315 -0
- package/pennyfarthing_scripts/bikerack/sprint_panel.py +395 -32
- package/pennyfarthing_scripts/bikerack/story_detail_data.py +244 -0
- package/pennyfarthing_scripts/bikerack/story_detail_screen.py +176 -0
- package/pennyfarthing_scripts/bikerack/tui.py +575 -37
- package/pennyfarthing_scripts/bikerack/ws_client.py +2 -2
- package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/cli.py +42 -65
- package/pennyfarthing_scripts/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/pr_config.py +38 -0
- package/pennyfarthing_scripts/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__init__.py +1 -0
- package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__pycache__/dialogue_manager.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/cli.py +149 -0
- package/pennyfarthing_scripts/consultation/dialogue_manager.py +417 -0
- package/pennyfarthing_scripts/context.py +3 -3
- package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__init__.py +12 -1
- package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/create_branches.py +3 -4
- package/pennyfarthing_scripts/git/hooks_installer.py +152 -0
- package/pennyfarthing_scripts/git/repos.py +196 -0
- package/pennyfarthing_scripts/git/status_all.py +27 -11
- package/pennyfarthing_scripts/git/worktree.py +302 -0
- package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git_group/cli.py +143 -40
- package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/gate_file.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/gate_runner.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/marker.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/cli.py +33 -1
- package/pennyfarthing_scripts/handoff/complete_phase.py +40 -0
- package/pennyfarthing_scripts/handoff/marker.py +15 -15
- package/pennyfarthing_scripts/handoff/phase_check.py +96 -0
- package/pennyfarthing_scripts/handoff/resolve_gate.py +18 -15
- package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__init__.py +437 -0
- package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/bell_mode.py +215 -0
- package/pennyfarthing_scripts/hooks/cli.py +96 -0
- package/pennyfarthing_scripts/hooks/context_breaker.py +104 -0
- package/pennyfarthing_scripts/hooks/context_warning.py +66 -0
- package/pennyfarthing_scripts/hooks/cyclist_pretooluse.py +129 -0
- package/pennyfarthing_scripts/hooks/pre_edit_check.py +78 -0
- package/pennyfarthing_scripts/hooks/reflector_check.py +271 -0
- package/pennyfarthing_scripts/hooks/schema_validation.py +203 -0
- package/pennyfarthing_scripts/hooks/session_start.py +296 -0
- package/pennyfarthing_scripts/hooks/session_stop.py +111 -0
- package/pennyfarthing_scripts/hooks/sprint_yaml_validation.py +97 -0
- package/pennyfarthing_scripts/hooks/statusline.py +420 -0
- package/pennyfarthing_scripts/hooks.py +27 -446
- package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/pretooluse_hook.py +3 -185
- package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/version_sentinel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/heatmap.py +655 -0
- package/pennyfarthing_scripts/prime/workflow.py +2 -1
- package/pennyfarthing_scripts/schema_validation_hook.py +3 -298
- package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/session/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/session_start_hook.py +4 -186
- package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/import_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/loader.py +15 -1
- package/pennyfarthing_scripts/sprint/story_update.py +19 -0
- package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_108_1_gate_migration.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_archive_epic.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bc.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_cli_normalization.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_evaluation.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_gate.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_dialogue_manager.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_epic_shard_validation.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_handoff_e2e.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_panel.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_topology_loader.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tui_focus.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tui_panel_persistence.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_version_sentinel.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/test_bikerack.py +51 -51
- package/pennyfarthing_scripts/tests/test_dialogue_manager.py +811 -0
- package/pennyfarthing_scripts/tests/test_handoff_cli.py +16 -11
- package/pennyfarthing_scripts/tests/test_sprint_panel.py +344 -265
- package/pennyfarthing_scripts/tests/test_workflow_check.py +2 -3
- package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/agent.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/schema.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/skill_command.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/sprint.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/tandem_awareness.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/tandem_awareness.py +254 -0
- package/pennyfarthing_scripts/validate/adapters/workflow.py +19 -0
- package/pennyfarthing_scripts/validate/cli.py +17 -5
- package/pennyfarthing_scripts/welcome_hook.py +3 -149
- package/pennyfarthing_scripts/workflow/__init__.py +40 -0
- package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/cli.py +1100 -0
- package/pennyfarthing_scripts/workflow/helpers.py +241 -0
- package/pennyfarthing_scripts/{workflow.py → workflow/scale.py} +0 -104
- package/pennyfarthing_scripts/workflow/state.py +112 -0
- package/pennyfarthing_scripts/workflow/team_lifecycle.py +257 -0
- package/packages/core/dist/scripts/theme-detail.test.d.ts +0 -10
- package/packages/core/dist/scripts/theme-detail.test.js +0 -199
- package/pennyfarthing-dist/skills/pf-workflow/scripts/list-workflows.sh +0 -91
- package/pennyfarthing-dist/skills/pf-workflow/scripts/resume-workflow.sh +0 -163
- package/pennyfarthing-dist/skills/pf-workflow/scripts/show-workflow.sh +0 -138
- package/pennyfarthing-dist/skills/pf-workflow/scripts/start-workflow.sh +0 -273
- package/pennyfarthing-dist/skills/pf-workflow/scripts/workflow-status.sh +0 -167
- package/pennyfarthing_scripts/gate/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/gate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/gate/__pycache__/validate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_108_2_remove_handoff_fallback.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_gate_file_resolution.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_gate_runner.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_resolve_gate_file_field.cpython-314-pytest-9.0.2.pyc +0 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Repos.yaml loader — Python replacement for repo-utils.sh (778 lines).
|
|
3
|
+
|
|
4
|
+
Reads .pennyfarthing/repos.yaml and provides structured access to repo
|
|
5
|
+
configuration: paths, types, branches, build/test commands, dependencies.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
from pennyfarthing_scripts.git.repos import load_repos_config, get_repo_paths
|
|
9
|
+
|
|
10
|
+
config = load_repos_config()
|
|
11
|
+
for name, repo in config.items():
|
|
12
|
+
print(f"{name}: {repo.path} ({repo.default_branch})")
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from dataclasses import dataclass, field
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
import yaml
|
|
22
|
+
|
|
23
|
+
from pennyfarthing_scripts.common.config import get_project_root
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass
|
|
27
|
+
class RepoConfig:
|
|
28
|
+
"""Configuration for a single repository."""
|
|
29
|
+
|
|
30
|
+
name: str
|
|
31
|
+
path: str # Relative to project root (e.g., "." or "pennyfarthing")
|
|
32
|
+
repo_type: str # "orchestrator", "framework", "api", "ui", etc.
|
|
33
|
+
default_branch: str # "main" for trunk-based, "develop" for gitflow
|
|
34
|
+
branch_strategy: str # "trunk-based" or "gitflow"
|
|
35
|
+
description: str = ""
|
|
36
|
+
language: str = "unknown"
|
|
37
|
+
test_command: str = ""
|
|
38
|
+
build_command: str = ""
|
|
39
|
+
lint_command: str = ""
|
|
40
|
+
test_filter_flag: str = ""
|
|
41
|
+
dependencies: list[str] = field(default_factory=list)
|
|
42
|
+
owns: list[str] = field(default_factory=list)
|
|
43
|
+
never_edit: list[str] = field(default_factory=list)
|
|
44
|
+
ui_layer: str = "none"
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def is_gitflow(self) -> bool:
|
|
48
|
+
return self.branch_strategy == "gitflow"
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def upstream_ref(self) -> str:
|
|
52
|
+
"""Remote ref to compare against for unpushed commits."""
|
|
53
|
+
return f"origin/{self.default_branch}"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _parse_repo_entry(name: str, data: dict[str, Any] | None) -> RepoConfig:
|
|
57
|
+
"""Parse a single repo entry from repos.yaml."""
|
|
58
|
+
if data is None:
|
|
59
|
+
data = {}
|
|
60
|
+
return RepoConfig(
|
|
61
|
+
name=name,
|
|
62
|
+
path=data.get("path", name),
|
|
63
|
+
repo_type=data.get("type", "unknown"),
|
|
64
|
+
default_branch=data.get("default_branch", "main"),
|
|
65
|
+
branch_strategy=data.get("branch_strategy", "trunk-based"),
|
|
66
|
+
description=data.get("description", ""),
|
|
67
|
+
language=data.get("language", "unknown"),
|
|
68
|
+
test_command=data.get("test_command", ""),
|
|
69
|
+
build_command=data.get("build_command", ""),
|
|
70
|
+
lint_command=data.get("lint_command", ""),
|
|
71
|
+
test_filter_flag=data.get("test_filter_flag", ""),
|
|
72
|
+
dependencies=data.get("dependencies", []) or [],
|
|
73
|
+
owns=data.get("owns", []) or [],
|
|
74
|
+
never_edit=data.get("never_edit", []) or [],
|
|
75
|
+
ui_layer=data.get("ui_layer", "none"),
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def load_repos_config(project_root: Path | None = None) -> dict[str, RepoConfig]:
|
|
80
|
+
"""Load repos.yaml and return a dict of name -> RepoConfig.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
project_root: Project root directory. Auto-detected if not provided.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Ordered dict of repo name -> RepoConfig.
|
|
87
|
+
Empty dict if repos.yaml not found.
|
|
88
|
+
"""
|
|
89
|
+
if project_root is None:
|
|
90
|
+
project_root = get_project_root()
|
|
91
|
+
|
|
92
|
+
repos_path = project_root / ".pennyfarthing" / "repos.yaml"
|
|
93
|
+
if not repos_path.exists():
|
|
94
|
+
return {}
|
|
95
|
+
|
|
96
|
+
with open(repos_path) as f:
|
|
97
|
+
config = yaml.safe_load(f)
|
|
98
|
+
|
|
99
|
+
if not config or "repos" not in config:
|
|
100
|
+
return {}
|
|
101
|
+
|
|
102
|
+
repos: dict[str, RepoConfig] = {}
|
|
103
|
+
for name, data in config["repos"].items():
|
|
104
|
+
repos[name] = _parse_repo_entry(name, data)
|
|
105
|
+
|
|
106
|
+
return repos
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def get_repo_paths(project_root: Path | None = None) -> list[tuple[str, Path]]:
|
|
110
|
+
"""Get list of (name, absolute_path) tuples for all configured repos.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
project_root: Project root directory. Auto-detected if not provided.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
List of (repo_name, absolute_path) tuples.
|
|
117
|
+
"""
|
|
118
|
+
if project_root is None:
|
|
119
|
+
project_root = get_project_root()
|
|
120
|
+
|
|
121
|
+
repos = load_repos_config(project_root)
|
|
122
|
+
result = []
|
|
123
|
+
for name, repo in repos.items():
|
|
124
|
+
abs_path = (project_root / repo.path).resolve()
|
|
125
|
+
if abs_path.exists():
|
|
126
|
+
result.append((name, abs_path))
|
|
127
|
+
return result
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def get_default_branch(
|
|
131
|
+
repo_name: str, project_root: Path | None = None
|
|
132
|
+
) -> str:
|
|
133
|
+
"""Get the default branch for a specific repo.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
repo_name: Name of the repo in repos.yaml.
|
|
137
|
+
project_root: Project root directory. Auto-detected if not provided.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
Default branch name (e.g., "main" or "develop").
|
|
141
|
+
Falls back to "main" if repo not found.
|
|
142
|
+
"""
|
|
143
|
+
repos = load_repos_config(project_root)
|
|
144
|
+
if repo_name in repos:
|
|
145
|
+
return repos[repo_name].default_branch
|
|
146
|
+
return "main"
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def get_repo_config(
|
|
150
|
+
repo_name: str, project_root: Path | None = None
|
|
151
|
+
) -> RepoConfig | None:
|
|
152
|
+
"""Get the full config for a specific repo.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
repo_name: Name of the repo in repos.yaml.
|
|
156
|
+
project_root: Project root directory. Auto-detected if not provided.
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
RepoConfig or None if not found.
|
|
160
|
+
"""
|
|
161
|
+
repos = load_repos_config(project_root)
|
|
162
|
+
return repos.get(repo_name)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def get_build_order(project_root: Path | None = None) -> list[str]:
|
|
166
|
+
"""Get repos in build/dependency order.
|
|
167
|
+
|
|
168
|
+
Uses explicit build_order from repos.yaml if present,
|
|
169
|
+
otherwise returns repos in definition order.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
project_root: Project root directory. Auto-detected if not provided.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
List of repo names in build order.
|
|
176
|
+
"""
|
|
177
|
+
if project_root is None:
|
|
178
|
+
project_root = get_project_root()
|
|
179
|
+
|
|
180
|
+
repos_path = project_root / ".pennyfarthing" / "repos.yaml"
|
|
181
|
+
if not repos_path.exists():
|
|
182
|
+
return []
|
|
183
|
+
|
|
184
|
+
with open(repos_path) as f:
|
|
185
|
+
config = yaml.safe_load(f)
|
|
186
|
+
|
|
187
|
+
if not config:
|
|
188
|
+
return []
|
|
189
|
+
|
|
190
|
+
if "build_order" in config:
|
|
191
|
+
return config["build_order"]
|
|
192
|
+
|
|
193
|
+
if "repos" in config:
|
|
194
|
+
return list(config["repos"].keys())
|
|
195
|
+
|
|
196
|
+
return []
|
|
@@ -65,12 +65,15 @@ async def _run_git_command(args: list[str], cwd: Path) -> tuple[str, str, int]:
|
|
|
65
65
|
)
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
async def get_repo_status(
|
|
68
|
+
async def get_repo_status(
|
|
69
|
+
name: str, path: Path, upstream_ref: str = "origin/develop"
|
|
70
|
+
) -> RepoStatus:
|
|
69
71
|
"""Get git status for a single repository.
|
|
70
72
|
|
|
71
73
|
Args:
|
|
72
74
|
name: Display name for the repo
|
|
73
75
|
path: Path to the repository
|
|
76
|
+
upstream_ref: Remote ref to compare for unpushed commits (default: origin/develop)
|
|
74
77
|
|
|
75
78
|
Returns:
|
|
76
79
|
RepoStatus with current branch, changes, and unpushed commits
|
|
@@ -124,9 +127,9 @@ async def get_repo_status(name: str, path: Path) -> RepoStatus:
|
|
|
124
127
|
status_out, _, _ = await _run_git_command(["status", "--short"], path)
|
|
125
128
|
changes = [line for line in status_out.split("\n") if line.strip()]
|
|
126
129
|
|
|
127
|
-
# Get unpushed commits (comparing to
|
|
130
|
+
# Get unpushed commits (comparing to upstream ref)
|
|
128
131
|
unpushed_out, _, unpushed_rc = await _run_git_command(
|
|
129
|
-
["log", "
|
|
132
|
+
["log", f"{upstream_ref}..HEAD", "--oneline"], path
|
|
130
133
|
)
|
|
131
134
|
if unpushed_rc == 0 and unpushed_out:
|
|
132
135
|
unpushed_commits = [
|
|
@@ -154,11 +157,13 @@ async def get_repo_status(name: str, path: Path) -> RepoStatus:
|
|
|
154
157
|
)
|
|
155
158
|
|
|
156
159
|
|
|
157
|
-
async def get_all_repo_status(
|
|
160
|
+
async def get_all_repo_status(
|
|
161
|
+
repos: Sequence[tuple[str, Path, str] | tuple[str, Path]],
|
|
162
|
+
) -> list[RepoStatus]:
|
|
158
163
|
"""Get git status for all repos in parallel using asyncio.gather.
|
|
159
164
|
|
|
160
165
|
Args:
|
|
161
|
-
repos: Sequence of (name, path)
|
|
166
|
+
repos: Sequence of (name, path) or (name, path, upstream_ref) tuples
|
|
162
167
|
|
|
163
168
|
Returns:
|
|
164
169
|
List of RepoStatus objects in same order as input
|
|
@@ -166,7 +171,14 @@ async def get_all_repo_status(repos: Sequence[tuple[str, Path]]) -> list[RepoSta
|
|
|
166
171
|
if not repos:
|
|
167
172
|
return []
|
|
168
173
|
|
|
169
|
-
tasks = [
|
|
174
|
+
tasks = []
|
|
175
|
+
for entry in repos:
|
|
176
|
+
if len(entry) == 3:
|
|
177
|
+
name, path, upstream_ref = entry # type: ignore[misc]
|
|
178
|
+
tasks.append(get_repo_status(name, path, upstream_ref))
|
|
179
|
+
else:
|
|
180
|
+
name, path = entry # type: ignore[misc]
|
|
181
|
+
tasks.append(get_repo_status(name, path))
|
|
170
182
|
results = await asyncio.gather(*tasks, return_exceptions=False)
|
|
171
183
|
return list(results)
|
|
172
184
|
|
|
@@ -279,13 +291,17 @@ async def main(brief: bool = False) -> int:
|
|
|
279
291
|
Returns:
|
|
280
292
|
0 if all repos clean, 1 if any have changes/unpushed
|
|
281
293
|
"""
|
|
282
|
-
from pennyfarthing_scripts.
|
|
294
|
+
from pennyfarthing_scripts.git.repos import load_repos_config, get_repo_paths
|
|
295
|
+
|
|
296
|
+
repos_with_upstream: list[tuple[str, Path, str]] = []
|
|
297
|
+
repo_paths = get_repo_paths()
|
|
298
|
+
config = load_repos_config()
|
|
283
299
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
300
|
+
for name, path in repo_paths:
|
|
301
|
+
upstream = config[name].upstream_ref if name in config else "origin/develop"
|
|
302
|
+
repos_with_upstream.append((name, path, upstream))
|
|
287
303
|
|
|
288
|
-
statuses = await get_all_repo_status(
|
|
304
|
+
statuses = await get_all_repo_status(repos_with_upstream)
|
|
289
305
|
|
|
290
306
|
if brief:
|
|
291
307
|
print(format_status_brief(statuses))
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Git worktree management — Python replacement for worktree-manager.sh (498 lines).
|
|
3
|
+
|
|
4
|
+
Manages git worktrees for parallel development across multiple repos.
|
|
5
|
+
|
|
6
|
+
Usage via CLI:
|
|
7
|
+
pf git worktree create <name> <branch> [--repos all|api|ui|name1,name2]
|
|
8
|
+
pf git worktree remove <name>
|
|
9
|
+
pf git worktree list
|
|
10
|
+
pf git worktree status
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import subprocess
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from pennyfarthing_scripts.common.config import get_project_root
|
|
20
|
+
from pennyfarthing_scripts.git.repos import load_repos_config
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _git(args: list[str], cwd: Path) -> tuple[str, int]:
|
|
24
|
+
"""Run a git command synchronously.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Tuple of (stdout, return_code)
|
|
28
|
+
"""
|
|
29
|
+
result = subprocess.run(
|
|
30
|
+
["git", *args],
|
|
31
|
+
cwd=cwd,
|
|
32
|
+
capture_output=True,
|
|
33
|
+
text=True,
|
|
34
|
+
)
|
|
35
|
+
return result.stdout.strip(), result.returncode
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _get_worktree_root(project_root: Path | None = None) -> Path:
|
|
39
|
+
"""Get worktree root directory."""
|
|
40
|
+
if project_root is None:
|
|
41
|
+
project_root = get_project_root()
|
|
42
|
+
env_root = os.environ.get("WORKTREE_ROOT")
|
|
43
|
+
if env_root:
|
|
44
|
+
return Path(env_root)
|
|
45
|
+
return project_root / "worktrees"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _filter_repos(
|
|
49
|
+
repos: dict[str, object], filter_str: str
|
|
50
|
+
) -> list[str]:
|
|
51
|
+
"""Filter repo names by type or comma-separated list."""
|
|
52
|
+
from pennyfarthing_scripts.git.repos import RepoConfig
|
|
53
|
+
|
|
54
|
+
if filter_str in ("all", "both"):
|
|
55
|
+
return list(repos.keys())
|
|
56
|
+
|
|
57
|
+
# Check if it's a type filter
|
|
58
|
+
if filter_str in ("api", "ui", "adapter", "service"):
|
|
59
|
+
return [
|
|
60
|
+
name
|
|
61
|
+
for name, cfg in repos.items()
|
|
62
|
+
if isinstance(cfg, RepoConfig) and cfg.repo_type == filter_str
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
# Comma-separated list of names
|
|
66
|
+
return [n.strip() for n in filter_str.split(",") if n.strip()]
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def create_worktree(name: str, branch: str, repos_filter: str = "all") -> int:
|
|
70
|
+
"""Create worktree(s) for parallel work.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
name: Worktree name (e.g., wt-5-3a)
|
|
74
|
+
branch: Branch name (e.g., feat/5-3a-file-upload)
|
|
75
|
+
repos_filter: Which repos to target (all, api, ui, or comma-separated)
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
0 on success, 1 on error
|
|
79
|
+
"""
|
|
80
|
+
project_root = get_project_root()
|
|
81
|
+
wt_root = _get_worktree_root(project_root)
|
|
82
|
+
wt_path = wt_root / name
|
|
83
|
+
|
|
84
|
+
if wt_path.exists():
|
|
85
|
+
print(f"Error: Worktree '{name}' already exists at {wt_path}")
|
|
86
|
+
return 1
|
|
87
|
+
|
|
88
|
+
repos = load_repos_config(project_root)
|
|
89
|
+
if not repos:
|
|
90
|
+
print("Error: No repositories configured in repos.yaml")
|
|
91
|
+
return 1
|
|
92
|
+
|
|
93
|
+
target_names = _filter_repos(repos, repos_filter)
|
|
94
|
+
if not target_names:
|
|
95
|
+
print(f"No repos match filter: {repos_filter}")
|
|
96
|
+
return 1
|
|
97
|
+
|
|
98
|
+
wt_path.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
|
|
100
|
+
print(f"Creating worktree: {name}")
|
|
101
|
+
print(f" Branch: {branch}")
|
|
102
|
+
print(f" Path: {wt_path}")
|
|
103
|
+
print(f" Repos: {repos_filter}")
|
|
104
|
+
print()
|
|
105
|
+
|
|
106
|
+
created = []
|
|
107
|
+
for repo_name in target_names:
|
|
108
|
+
if repo_name not in repos:
|
|
109
|
+
print(f" SKIP {repo_name} (not in config)")
|
|
110
|
+
continue
|
|
111
|
+
|
|
112
|
+
cfg = repos[repo_name]
|
|
113
|
+
full_path = (project_root / cfg.path).resolve()
|
|
114
|
+
|
|
115
|
+
if not full_path.exists():
|
|
116
|
+
print(f" SKIP {repo_name} (path not found: {full_path})")
|
|
117
|
+
continue
|
|
118
|
+
|
|
119
|
+
print(f"Creating worktree for {repo_name} ({cfg.repo_type})...")
|
|
120
|
+
repo_wt = wt_path / repo_name
|
|
121
|
+
|
|
122
|
+
# Check if branch exists locally or remotely
|
|
123
|
+
_, local_rc = _git(
|
|
124
|
+
["show-ref", "--verify", "--quiet", f"refs/heads/{branch}"],
|
|
125
|
+
full_path,
|
|
126
|
+
)
|
|
127
|
+
_, remote_rc = _git(
|
|
128
|
+
["show-ref", "--verify", "--quiet", f"refs/remotes/origin/{branch}"],
|
|
129
|
+
full_path,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if local_rc == 0 or remote_rc == 0:
|
|
133
|
+
_, rc = _git(["worktree", "add", str(repo_wt), branch], full_path)
|
|
134
|
+
else:
|
|
135
|
+
# Create new branch from default branch
|
|
136
|
+
base = cfg.default_branch
|
|
137
|
+
_, base_rc = _git(
|
|
138
|
+
["show-ref", "--verify", "--quiet", f"refs/heads/{base}"],
|
|
139
|
+
full_path,
|
|
140
|
+
)
|
|
141
|
+
if base_rc != 0:
|
|
142
|
+
base = "main"
|
|
143
|
+
_, rc = _git(
|
|
144
|
+
["worktree", "add", "-b", branch, str(repo_wt), base],
|
|
145
|
+
full_path,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
if rc == 0:
|
|
149
|
+
print(f" OK {repo_name}")
|
|
150
|
+
created.append(repo_name)
|
|
151
|
+
else:
|
|
152
|
+
print(f" FAIL {repo_name}")
|
|
153
|
+
|
|
154
|
+
print()
|
|
155
|
+
if created:
|
|
156
|
+
print(f"Worktree '{name}' created successfully!")
|
|
157
|
+
print()
|
|
158
|
+
print("Next steps:")
|
|
159
|
+
for repo_name in created:
|
|
160
|
+
print(f" cd {wt_path / repo_name}")
|
|
161
|
+
else:
|
|
162
|
+
print("No worktrees created.")
|
|
163
|
+
return 1
|
|
164
|
+
|
|
165
|
+
return 0
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def remove_worktree(name: str) -> int:
|
|
169
|
+
"""Remove worktree and clean up.
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
name: Worktree name to remove
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
0 on success, 1 on error
|
|
176
|
+
"""
|
|
177
|
+
project_root = get_project_root()
|
|
178
|
+
wt_root = _get_worktree_root(project_root)
|
|
179
|
+
wt_path = wt_root / name
|
|
180
|
+
|
|
181
|
+
if not wt_path.exists():
|
|
182
|
+
print(f"Error: Worktree '{name}' not found at {wt_path}")
|
|
183
|
+
return 1
|
|
184
|
+
|
|
185
|
+
print(f"Removing worktree: {name}")
|
|
186
|
+
|
|
187
|
+
repos = load_repos_config(project_root)
|
|
188
|
+
for repo_name, cfg in repos.items():
|
|
189
|
+
repo_wt = wt_path / repo_name
|
|
190
|
+
if repo_wt.exists():
|
|
191
|
+
full_path = (project_root / cfg.path).resolve()
|
|
192
|
+
print(f" Removing {repo_name} worktree...")
|
|
193
|
+
_git(["worktree", "remove", str(repo_wt), "--force"], full_path)
|
|
194
|
+
|
|
195
|
+
# Clean up directory
|
|
196
|
+
import shutil
|
|
197
|
+
|
|
198
|
+
if wt_path.exists():
|
|
199
|
+
shutil.rmtree(wt_path)
|
|
200
|
+
|
|
201
|
+
# Prune worktree references
|
|
202
|
+
for repo_name, cfg in repos.items():
|
|
203
|
+
full_path = (project_root / cfg.path).resolve()
|
|
204
|
+
if full_path.exists():
|
|
205
|
+
_git(["worktree", "prune"], full_path)
|
|
206
|
+
|
|
207
|
+
print()
|
|
208
|
+
print("Note: Session file (if any) should be archived via /sm finish")
|
|
209
|
+
print()
|
|
210
|
+
print(f"Worktree '{name}' removed successfully!")
|
|
211
|
+
return 0
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def list_worktrees() -> int:
|
|
215
|
+
"""List all active worktrees.
|
|
216
|
+
|
|
217
|
+
Returns:
|
|
218
|
+
0 always
|
|
219
|
+
"""
|
|
220
|
+
project_root = get_project_root()
|
|
221
|
+
wt_root = _get_worktree_root(project_root)
|
|
222
|
+
repos = load_repos_config(project_root)
|
|
223
|
+
|
|
224
|
+
print("=== Active Worktrees ===")
|
|
225
|
+
print()
|
|
226
|
+
|
|
227
|
+
for repo_name, cfg in repos.items():
|
|
228
|
+
full_path = (project_root / cfg.path).resolve()
|
|
229
|
+
if full_path.exists():
|
|
230
|
+
print(f"{repo_name} ({cfg.repo_type}):")
|
|
231
|
+
output, _ = _git(["worktree", "list"], full_path)
|
|
232
|
+
if output:
|
|
233
|
+
print(output)
|
|
234
|
+
print()
|
|
235
|
+
|
|
236
|
+
print("Worktree Directory:")
|
|
237
|
+
if wt_root.exists() and any(wt_root.iterdir()):
|
|
238
|
+
for item in sorted(wt_root.iterdir()):
|
|
239
|
+
if item.is_dir():
|
|
240
|
+
print(f" {item.name}/")
|
|
241
|
+
else:
|
|
242
|
+
print(" (empty)")
|
|
243
|
+
|
|
244
|
+
return 0
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def show_worktree_status() -> int:
|
|
248
|
+
"""Show detailed worktree status.
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
0 always
|
|
252
|
+
"""
|
|
253
|
+
project_root = get_project_root()
|
|
254
|
+
wt_root = _get_worktree_root(project_root)
|
|
255
|
+
repos = load_repos_config(project_root)
|
|
256
|
+
|
|
257
|
+
print("=== Worktree Status ===")
|
|
258
|
+
print()
|
|
259
|
+
|
|
260
|
+
if not wt_root.exists() or not any(wt_root.iterdir()):
|
|
261
|
+
print("No active worktrees.")
|
|
262
|
+
print()
|
|
263
|
+
print("Create one with:")
|
|
264
|
+
print(" pf git worktree create <name> <branch>")
|
|
265
|
+
return 0
|
|
266
|
+
|
|
267
|
+
for wt_dir in sorted(wt_root.iterdir()):
|
|
268
|
+
if not wt_dir.is_dir():
|
|
269
|
+
continue
|
|
270
|
+
|
|
271
|
+
wt_name = wt_dir.name
|
|
272
|
+
print(f"{wt_name}")
|
|
273
|
+
print(f" Path: {wt_dir}")
|
|
274
|
+
|
|
275
|
+
for repo_name, cfg in repos.items():
|
|
276
|
+
repo_wt = wt_dir / repo_name
|
|
277
|
+
if repo_wt.exists():
|
|
278
|
+
branch, _ = _git(["branch", "--show-current"], repo_wt)
|
|
279
|
+
status_out, _ = _git(["status", "--short"], repo_wt)
|
|
280
|
+
count = len([l for l in status_out.split("\n") if l.strip()]) if status_out else 0
|
|
281
|
+
print(f" {repo_name} ({cfg.repo_type}): {branch} ({count} uncommitted)")
|
|
282
|
+
|
|
283
|
+
# Check for session files referencing this worktree
|
|
284
|
+
session_dir = project_root / ".session"
|
|
285
|
+
found_session = None
|
|
286
|
+
if session_dir.exists():
|
|
287
|
+
for sf in session_dir.glob("*-session.md"):
|
|
288
|
+
try:
|
|
289
|
+
content = sf.read_text()
|
|
290
|
+
if f"worktree: {wt_name}" in content:
|
|
291
|
+
found_session = sf.name
|
|
292
|
+
break
|
|
293
|
+
except OSError:
|
|
294
|
+
pass
|
|
295
|
+
|
|
296
|
+
if found_session:
|
|
297
|
+
print(f" Session: .session/{found_session}")
|
|
298
|
+
else:
|
|
299
|
+
print(" Session: (no session file references this worktree)")
|
|
300
|
+
print()
|
|
301
|
+
|
|
302
|
+
return 0
|
|
Binary file
|