@pennyfarthing/core 10.2.0 → 10.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 +11 -8
- package/package.json +14 -16
- package/packages/core/dist/cli/commands/e2e-fresh-install.test.js +1 -1
- package/packages/core/dist/cli/commands/e2e-fresh-install.test.js.map +1 -1
- package/packages/core/dist/cli/commands/e2e-upgrade.test.js +1 -1
- package/packages/core/dist/cli/commands/e2e-upgrade.test.js.map +1 -1
- package/packages/core/dist/cli/commands/theme.js +1 -1
- package/packages/core/dist/cli/commands/theme.js.map +1 -1
- package/packages/core/dist/cli/utils/themes.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/themes.js +3 -2
- package/packages/core/dist/cli/utils/themes.js.map +1 -1
- package/packages/core/dist/scripts/add-ocean-profiles.js +1 -1
- package/packages/core/dist/scripts/add-ocean-profiles.js.map +1 -1
- package/packages/core/dist/scripts/generate-all-spiders.js +2 -0
- package/packages/core/dist/scripts/generate-all-spiders.js.map +1 -1
- package/packages/core/dist/scripts/generate-report.d.ts.map +1 -1
- package/packages/core/dist/scripts/generate-report.js +2 -0
- package/packages/core/dist/scripts/generate-report.js.map +1 -1
- package/packages/core/dist/scripts/generate-spider-report.d.ts.map +1 -1
- package/packages/core/dist/scripts/generate-spider-report.js +2 -0
- package/packages/core/dist/scripts/generate-spider-report.js.map +1 -1
- package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -1
- package/packages/core/dist/scripts/generate-spider.js +3 -0
- package/packages/core/dist/scripts/generate-spider.js.map +1 -1
- package/packages/core/dist/scripts/validate-ocean-profiles.js +1 -1
- package/packages/core/dist/scripts/validate-ocean-profiles.js.map +1 -1
- package/packages/core/dist/workflow/file-watch.test.js.map +1 -1
- package/packages/core/dist/workflow/output-path-normalizer.d.ts +47 -0
- package/packages/core/dist/workflow/output-path-normalizer.d.ts.map +1 -0
- package/packages/core/dist/workflow/output-path-normalizer.js +79 -0
- package/packages/core/dist/workflow/output-path-normalizer.js.map +1 -0
- package/packages/core/dist/workflow/output-path-normalizer.test.d.ts +16 -0
- package/packages/core/dist/workflow/output-path-normalizer.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/output-path-normalizer.test.js +157 -0
- package/packages/core/dist/workflow/output-path-normalizer.test.js.map +1 -0
- package/packages/core/dist/workflow/tool-watch.test.js +1 -2
- package/packages/core/dist/workflow/tool-watch.test.js.map +1 -1
- package/packages/core/dist/workflow/variable-resolver.js +1 -1
- package/packages/core/dist/workflow/variable-resolver.js.map +1 -1
- package/pennyfarthing-dist/agents/README.md +3 -1
- package/pennyfarthing-dist/agents/ba.md +165 -0
- package/pennyfarthing-dist/commands/ba.md +17 -0
- package/pennyfarthing-dist/guides/workflow-schema.md +1 -1
- package/pennyfarthing-dist/personas/themes/a-team.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/alice-in-wonderland.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/blade-runner.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/catch-22.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/control.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/cowboy-bebop.yaml +31 -0
- package/pennyfarthing-dist/personas/themes/discworld.yaml +31 -0
- package/pennyfarthing-dist/personas/themes/doctor-who.yaml +31 -0
- package/pennyfarthing-dist/personas/themes/dune.yaml +32 -0
- package/pennyfarthing-dist/personas/themes/fifth-element.yaml +31 -0
- package/pennyfarthing-dist/personas/themes/firefly.yaml +31 -0
- package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/harry-potter.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/lord-of-the-rings.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/mad-max.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/mash.yaml +33 -0
- package/pennyfarthing-dist/personas/themes/princess-bride.yaml +34 -0
- package/pennyfarthing-dist/personas/themes/sandman.yaml +33 -0
- package/pennyfarthing-dist/personas/themes/star-trek-tng.yaml +34 -0
- package/pennyfarthing-dist/personas/themes/star-wars.yaml +33 -0
- package/pennyfarthing-dist/personas/themes/the-expanse.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/the-matrix.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/watchmen.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/west-wing.yaml +30 -0
- package/pennyfarthing-dist/personas/themes/x-files.yaml +30 -0
- package/pennyfarthing-dist/scripts/core/agent-session.sh +1 -1
- package/pennyfarthing-dist/scripts/core/check-context.sh +0 -0
- package/pennyfarthing-dist/scripts/core/handoff-marker.sh +0 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +0 -0
- package/pennyfarthing-dist/scripts/core/prime.sh +0 -0
- package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +0 -0
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +0 -0
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +0 -0
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +0 -0
- package/pennyfarthing-dist/scripts/git/release.sh +0 -0
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +0 -0
- package/pennyfarthing-dist/scripts/health/drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/post-merge.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +0 -0
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/background-tasks.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/common.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/file-lock.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/logging.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/retry.sh +0 -0
- package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +0 -0
- package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add-short-names.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add_short_names.py +0 -0
- package/pennyfarthing-dist/scripts/misc/backlog.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/check-status.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/find-related-work.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-scan.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-utils.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-ci.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/statusline.sh +2 -0
- package/pennyfarthing-dist/scripts/misc/uninstall.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +0 -0
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.py +2 -2
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +0 -0
- package/pennyfarthing-dist/scripts/story/create-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/size-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/story-template.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/list-themes.sh +0 -0
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +1 -0
- package/pennyfarthing-dist/scripts/workflow/check.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/check.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/complete-step.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +0 -0
- package/pennyfarthing-dist/skills/story/scripts/create-story.sh +0 -0
- package/pennyfarthing-dist/skills/story/scripts/size-story.sh +0 -0
- package/pennyfarthing-dist/skills/story/scripts/story-template.sh +0 -0
- package/pennyfarthing-dist/skills/theme/skill.md +1 -1
- package/pennyfarthing-dist/skills/workflow/scripts/list-workflows.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/resume-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/show-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/start-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/workflow/scripts/workflow-status.sh +0 -0
- package/pennyfarthing-dist/workflows/architecture/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/architecture.yaml +2 -2
- package/pennyfarthing-dist/workflows/epics-and-stories/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/implementation-readiness/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/prd/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/product-brief/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/project-context/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/quick-dev/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/research/workflow.yaml +2 -2
- package/pennyfarthing-dist/workflows/retrospective/workflow.yaml +1 -1
- package/pennyfarthing-dist/workflows/sprint-planning/workflow.yaml +3 -3
- package/pennyfarthing-dist/workflows/ux-design/workflow.yaml +2 -2
- 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-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/jira.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__/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/bellmode_hook.py +1 -1
- package/pennyfarthing_scripts/bikerack/__init__.py +36 -0
- package/pennyfarthing_scripts/bikerack/__main__.py +5 -0
- 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__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/cli.py +148 -0
- package/pennyfarthing_scripts/bikerack/launcher.py +181 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/cli.py +5 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/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/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/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/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/analyze.py +2 -1
- package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/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/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/prime/__init__.py +2 -0
- 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__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/cli.py +13 -0
- package/pennyfarthing_scripts/prime/loader.py +70 -0
- package/pennyfarthing_scripts/prime/persona.py +2 -1
- package/pennyfarthing_scripts/prime/tiers.py +13 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/import_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/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_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_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_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_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_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 +785 -0
- package/pennyfarthing_scripts/tests/test_topology_loader.py +620 -0
- package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/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__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/skill_command.py +0 -1
- package/packages/core/dist/workflow/context-watch.d.ts +0 -80
- package/packages/core/dist/workflow/context-watch.d.ts.map +0 -1
- package/packages/core/dist/workflow/context-watch.js +0 -235
- package/packages/core/dist/workflow/context-watch.js.map +0 -1
- package/packages/core/dist/workflow/context-watch.test.d.ts +0 -1
- package/packages/core/dist/workflow/context-watch.test.d.ts.map +0 -1
- package/packages/core/dist/workflow/context-watch.test.js +0 -746
- package/packages/core/dist/workflow/context-watch.test.js.map +0 -1
- package/pennyfarthing_scripts/__pycache__/bellmode_hook.cpython-314.pyc +0 -0
- package/scripts/README.md +0 -41
|
@@ -26,8 +26,8 @@ workflow:
|
|
|
26
26
|
|
|
27
27
|
# Variables available in step files
|
|
28
28
|
variables:
|
|
29
|
-
output_file: planning
|
|
30
|
-
planning_artifacts: planning
|
|
29
|
+
output_file: sprint/planning/architecture.md
|
|
30
|
+
planning_artifacts: sprint/planning/
|
|
31
31
|
input_required:
|
|
32
32
|
- prd
|
|
33
33
|
|
|
@@ -16,8 +16,8 @@ workflow:
|
|
|
16
16
|
# Variables available in step files
|
|
17
17
|
variables:
|
|
18
18
|
project_root: .
|
|
19
|
-
planning_artifacts:
|
|
20
|
-
output_file:
|
|
19
|
+
planning_artifacts: sprint/planning/
|
|
20
|
+
output_file: sprint/planning/create-epics-and-stories.md
|
|
21
21
|
|
|
22
22
|
# Agent assignment (customize as needed)
|
|
23
23
|
agent: architect
|
|
@@ -28,8 +28,8 @@ workflow:
|
|
|
28
28
|
# Variables available in step files
|
|
29
29
|
variables:
|
|
30
30
|
project_root: .
|
|
31
|
-
planning_artifacts:
|
|
32
|
-
output_file:
|
|
31
|
+
planning_artifacts: sprint/planning/
|
|
32
|
+
output_file: sprint/planning/implementation-readiness-report.md
|
|
33
33
|
|
|
34
34
|
# Agent assignment - PM/SM role for adversarial review
|
|
35
35
|
agent: sm
|
|
@@ -22,8 +22,8 @@ workflow:
|
|
|
22
22
|
# Variables available in step files
|
|
23
23
|
variables:
|
|
24
24
|
project_root: .
|
|
25
|
-
planning_artifacts:
|
|
26
|
-
output_file:
|
|
25
|
+
planning_artifacts: sprint/planning/
|
|
26
|
+
output_file: sprint/planning/prd.md
|
|
27
27
|
|
|
28
28
|
# Gates - pause for user approval at key decision points
|
|
29
29
|
gates:
|
|
@@ -16,8 +16,8 @@ workflow:
|
|
|
16
16
|
# Variables available in step files
|
|
17
17
|
variables:
|
|
18
18
|
project_root: .
|
|
19
|
-
planning_artifacts:
|
|
20
|
-
output_file:
|
|
19
|
+
planning_artifacts: sprint/planning/
|
|
20
|
+
output_file: sprint/planning/product-brief.md
|
|
21
21
|
|
|
22
22
|
# Template for product brief output
|
|
23
23
|
template: ./templates/product-brief.template.md
|
|
@@ -15,8 +15,8 @@ workflow:
|
|
|
15
15
|
# Variables available in step files
|
|
16
16
|
variables:
|
|
17
17
|
project_root: .
|
|
18
|
-
planning_artifacts:
|
|
19
|
-
output_file:
|
|
18
|
+
planning_artifacts: sprint/planning/
|
|
19
|
+
output_file: sprint/planning/generate-project-context.md
|
|
20
20
|
|
|
21
21
|
# Agent assignment (customize as needed)
|
|
22
22
|
agent: architect
|
|
@@ -15,8 +15,8 @@ workflow:
|
|
|
15
15
|
# Variables available in step files
|
|
16
16
|
variables:
|
|
17
17
|
project_root: .
|
|
18
|
-
planning_artifacts:
|
|
19
|
-
output_file:
|
|
18
|
+
planning_artifacts: sprint/planning/
|
|
19
|
+
output_file: sprint/planning/quick-dev.md
|
|
20
20
|
|
|
21
21
|
# Agent assignment (customize as needed)
|
|
22
22
|
agent: architect
|
|
@@ -23,8 +23,8 @@ workflow:
|
|
|
23
23
|
# Variables available in step files
|
|
24
24
|
variables:
|
|
25
25
|
project_root: .
|
|
26
|
-
planning_artifacts:
|
|
27
|
-
output_file:
|
|
26
|
+
planning_artifacts: sprint/planning/
|
|
27
|
+
output_file: sprint/planning/research.md
|
|
28
28
|
research_type: ""
|
|
29
29
|
research_topic: ""
|
|
30
30
|
research_goals: ""
|
|
@@ -38,7 +38,7 @@ workflow:
|
|
|
38
38
|
variables:
|
|
39
39
|
project_root: .
|
|
40
40
|
config_source: "./_bmad/bmm/config.yaml"
|
|
41
|
-
planning_artifacts:
|
|
41
|
+
planning_artifacts: sprint/planning/
|
|
42
42
|
implementation_artifacts: ./artifacts
|
|
43
43
|
sprint_status_file: ./artifacts/sprint-status.yaml
|
|
44
44
|
story_directory: ./artifacts/stories
|
|
@@ -15,12 +15,12 @@ workflow:
|
|
|
15
15
|
# Variables available in step files
|
|
16
16
|
variables:
|
|
17
17
|
project_root: .
|
|
18
|
-
planning_artifacts:
|
|
18
|
+
planning_artifacts: sprint/planning/
|
|
19
19
|
implementation_artifacts: ./artifacts
|
|
20
20
|
epics_location: ./artifacts
|
|
21
21
|
epics_pattern: "epic*.md"
|
|
22
|
-
status_file:
|
|
23
|
-
output_file:
|
|
22
|
+
status_file: sprint/planning/sprint-status.yaml
|
|
23
|
+
output_file: sprint/planning/sprint-status.yaml
|
|
24
24
|
|
|
25
25
|
# Agent assignment - SM handles sprint planning
|
|
26
26
|
agent: sm
|
|
@@ -29,8 +29,8 @@ workflow:
|
|
|
29
29
|
# Variables available in step files
|
|
30
30
|
variables:
|
|
31
31
|
project_root: .
|
|
32
|
-
planning_artifacts:
|
|
33
|
-
output_file:
|
|
32
|
+
planning_artifacts: sprint/planning/
|
|
33
|
+
output_file: sprint/planning/ux-design-specification.md
|
|
34
34
|
|
|
35
35
|
# Agent assignment - UX Designer for visual design workflow
|
|
36
36
|
agent: ux-designer
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -150,7 +150,7 @@ def get_latest_observation(file_content: str) -> dict | None:
|
|
|
150
150
|
last_entry = re.sub(r"\n---\s*$", "", last_entry).strip()
|
|
151
151
|
# Remove the **Trigger:** line
|
|
152
152
|
lines = last_entry.split("\n")
|
|
153
|
-
text_lines = [
|
|
153
|
+
text_lines = [line for line in lines if not line.startswith("**Trigger:**")]
|
|
154
154
|
text = "\n".join(text_lines).strip()
|
|
155
155
|
|
|
156
156
|
if not text:
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""BikeRack Mode — Decoupled WheelHub launcher for CLI-first developers.
|
|
2
|
+
|
|
3
|
+
Story 101-5: BikeRack launcher CLI (pf bikerack start/stop/status)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pennyfarthing_scripts.bikerack.launcher import (
|
|
7
|
+
build_otel_env,
|
|
8
|
+
cleanup_files,
|
|
9
|
+
exec_claude,
|
|
10
|
+
get_status,
|
|
11
|
+
is_already_running,
|
|
12
|
+
is_process_alive,
|
|
13
|
+
poll_for_port_file,
|
|
14
|
+
read_pid_file,
|
|
15
|
+
read_port_file,
|
|
16
|
+
register_cleanup,
|
|
17
|
+
start_wheelhub,
|
|
18
|
+
stop_bikerack,
|
|
19
|
+
write_pid_file,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
__all__ = [
|
|
23
|
+
"build_otel_env",
|
|
24
|
+
"cleanup_files",
|
|
25
|
+
"exec_claude",
|
|
26
|
+
"get_status",
|
|
27
|
+
"is_already_running",
|
|
28
|
+
"is_process_alive",
|
|
29
|
+
"poll_for_port_file",
|
|
30
|
+
"read_pid_file",
|
|
31
|
+
"read_port_file",
|
|
32
|
+
"register_cleanup",
|
|
33
|
+
"start_wheelhub",
|
|
34
|
+
"stop_bikerack",
|
|
35
|
+
"write_pid_file",
|
|
36
|
+
]
|
|
Binary file
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""BikeRack CLI — Click-based CLI for bikerack operations.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
pf bikerack [COMMAND]
|
|
5
|
+
|
|
6
|
+
Commands:
|
|
7
|
+
start Start BikeRack mode (default)
|
|
8
|
+
stop Stop running BikeRack instance
|
|
9
|
+
status Show running state
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
import click
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@click.group(invoke_without_command=True)
|
|
20
|
+
@click.pass_context
|
|
21
|
+
def bikerack(ctx):
|
|
22
|
+
"""BikeRack Mode — Decoupled WheelHub dashboard launcher.
|
|
23
|
+
|
|
24
|
+
\b
|
|
25
|
+
Commands:
|
|
26
|
+
start - Start WheelHub + Claude CLI (default)
|
|
27
|
+
stop - Stop running BikeRack instance
|
|
28
|
+
status - Show running state (PID, port, uptime)
|
|
29
|
+
"""
|
|
30
|
+
if ctx.invoked_subcommand is None:
|
|
31
|
+
ctx.invoke(start)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@bikerack.command()
|
|
35
|
+
@click.option(
|
|
36
|
+
"--project-dir",
|
|
37
|
+
type=click.Path(exists=True, file_okay=False, resolve_path=True),
|
|
38
|
+
default=None,
|
|
39
|
+
help="Project directory (where .pennyfarthing/ lives). Falls back to CYCLIST_PROJECT_DIR env var, then cwd.",
|
|
40
|
+
)
|
|
41
|
+
def start(project_dir):
|
|
42
|
+
"""Start BikeRack mode.
|
|
43
|
+
|
|
44
|
+
Starts WheelHub in background, waits for readiness,
|
|
45
|
+
sets OTEL env vars, and execs Claude CLI.
|
|
46
|
+
"""
|
|
47
|
+
from pennyfarthing_scripts.bikerack.launcher import (
|
|
48
|
+
build_otel_env,
|
|
49
|
+
exec_claude,
|
|
50
|
+
is_already_running,
|
|
51
|
+
poll_for_port_file,
|
|
52
|
+
register_cleanup,
|
|
53
|
+
start_wheelhub,
|
|
54
|
+
write_pid_file,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
if project_dir:
|
|
58
|
+
project_dir = Path(project_dir)
|
|
59
|
+
elif os.environ.get("CYCLIST_PROJECT_DIR"):
|
|
60
|
+
project_dir = Path(os.environ["CYCLIST_PROJECT_DIR"])
|
|
61
|
+
else:
|
|
62
|
+
project_dir = Path.cwd()
|
|
63
|
+
|
|
64
|
+
running, pid, port = is_already_running(project_dir)
|
|
65
|
+
if running:
|
|
66
|
+
click.echo(
|
|
67
|
+
f"Error: BikeRack is already running (PID {pid}, port {port})",
|
|
68
|
+
err=True,
|
|
69
|
+
)
|
|
70
|
+
click.echo("Use 'pf bikerack stop' to stop it.", err=True)
|
|
71
|
+
sys.exit(2)
|
|
72
|
+
|
|
73
|
+
click.echo("Starting BikeRack mode...")
|
|
74
|
+
try:
|
|
75
|
+
proc = start_wheelhub(project_dir)
|
|
76
|
+
write_pid_file(project_dir, proc.pid)
|
|
77
|
+
|
|
78
|
+
port = poll_for_port_file(project_dir)
|
|
79
|
+
click.echo(f"WheelHub listening on http://localhost:{port}")
|
|
80
|
+
|
|
81
|
+
otel_env = build_otel_env(port)
|
|
82
|
+
click.echo("Setting OTEL environment variables...")
|
|
83
|
+
|
|
84
|
+
register_cleanup(project_dir, proc.pid)
|
|
85
|
+
|
|
86
|
+
click.echo(f"Dashboard: http://localhost:{port}/bikerack")
|
|
87
|
+
click.echo("Starting Claude CLI...")
|
|
88
|
+
exec_claude(otel_env, project_dir)
|
|
89
|
+
except TimeoutError as e:
|
|
90
|
+
click.echo(f"Error: {e}", err=True)
|
|
91
|
+
sys.exit(1)
|
|
92
|
+
except Exception as e:
|
|
93
|
+
click.echo(f"Error: {e}", err=True)
|
|
94
|
+
sys.exit(1)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@bikerack.command()
|
|
98
|
+
@click.option(
|
|
99
|
+
"--project-dir",
|
|
100
|
+
type=click.Path(exists=True, file_okay=False, resolve_path=True),
|
|
101
|
+
default=None,
|
|
102
|
+
help="Project directory. Falls back to CYCLIST_PROJECT_DIR env var, then cwd.",
|
|
103
|
+
)
|
|
104
|
+
def stop(project_dir):
|
|
105
|
+
"""Stop running BikeRack instance."""
|
|
106
|
+
from pennyfarthing_scripts.bikerack.launcher import stop_bikerack
|
|
107
|
+
|
|
108
|
+
if project_dir:
|
|
109
|
+
project_dir = Path(project_dir)
|
|
110
|
+
elif os.environ.get("CYCLIST_PROJECT_DIR"):
|
|
111
|
+
project_dir = Path(os.environ["CYCLIST_PROJECT_DIR"])
|
|
112
|
+
else:
|
|
113
|
+
project_dir = Path.cwd()
|
|
114
|
+
result = stop_bikerack(project_dir)
|
|
115
|
+
|
|
116
|
+
if result["success"]:
|
|
117
|
+
click.echo(result["message"])
|
|
118
|
+
else:
|
|
119
|
+
click.echo(result["message"], err=True)
|
|
120
|
+
sys.exit(1)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@bikerack.command()
|
|
124
|
+
@click.option(
|
|
125
|
+
"--project-dir",
|
|
126
|
+
type=click.Path(exists=True, file_okay=False, resolve_path=True),
|
|
127
|
+
default=None,
|
|
128
|
+
help="Project directory. Falls back to CYCLIST_PROJECT_DIR env var, then cwd.",
|
|
129
|
+
)
|
|
130
|
+
def status(project_dir):
|
|
131
|
+
"""Show BikeRack running state."""
|
|
132
|
+
from pennyfarthing_scripts.bikerack.launcher import get_status
|
|
133
|
+
|
|
134
|
+
if project_dir:
|
|
135
|
+
project_dir = Path(project_dir)
|
|
136
|
+
elif os.environ.get("CYCLIST_PROJECT_DIR"):
|
|
137
|
+
project_dir = Path(os.environ["CYCLIST_PROJECT_DIR"])
|
|
138
|
+
else:
|
|
139
|
+
project_dir = Path.cwd()
|
|
140
|
+
result = get_status(project_dir)
|
|
141
|
+
|
|
142
|
+
if result["running"]:
|
|
143
|
+
click.echo("BikeRack is running")
|
|
144
|
+
click.echo(f" PID: {result['pid']}")
|
|
145
|
+
click.echo(f" Port: {result['port']}")
|
|
146
|
+
click.echo(f" Dashboard: {result['dashboard']}")
|
|
147
|
+
else:
|
|
148
|
+
click.echo("BikeRack is not running")
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""BikeRack launcher — core lifecycle functions.
|
|
2
|
+
|
|
3
|
+
Story 101-5: BikeRack launcher CLI (pf bikerack start/stop/status)
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import atexit
|
|
9
|
+
import os
|
|
10
|
+
import signal
|
|
11
|
+
import subprocess
|
|
12
|
+
import time
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import NoReturn
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def is_process_alive(pid: int) -> bool:
|
|
18
|
+
"""Check if a process with given PID is alive."""
|
|
19
|
+
try:
|
|
20
|
+
os.kill(pid, 0)
|
|
21
|
+
return True
|
|
22
|
+
except (ProcessLookupError, PermissionError, OSError):
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def cleanup_files(project_dir: Path) -> None:
|
|
27
|
+
"""Clean up .bikerack-port and .bikerack-pid files."""
|
|
28
|
+
for name in (".bikerack-port", ".bikerack-pid"):
|
|
29
|
+
try:
|
|
30
|
+
(project_dir / name).unlink()
|
|
31
|
+
except FileNotFoundError:
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def read_port_file(project_dir: Path) -> int | None:
|
|
36
|
+
"""Read port from .bikerack-port file. Returns None if not found."""
|
|
37
|
+
try:
|
|
38
|
+
return int((project_dir / ".bikerack-port").read_text().strip())
|
|
39
|
+
except (FileNotFoundError, ValueError):
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def read_pid_file(project_dir: Path) -> int | None:
|
|
44
|
+
"""Read PID from .bikerack-pid file. Returns None if not found."""
|
|
45
|
+
try:
|
|
46
|
+
return int((project_dir / ".bikerack-pid").read_text().strip())
|
|
47
|
+
except (FileNotFoundError, ValueError):
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def write_pid_file(project_dir: Path, pid: int) -> None:
|
|
52
|
+
"""Write .bikerack-pid file."""
|
|
53
|
+
(project_dir / ".bikerack-pid").write_text(str(pid))
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def build_otel_env(port: int) -> dict[str, str]:
|
|
57
|
+
"""Build the 5 OTEL environment variables from discovered port (Rule 5)."""
|
|
58
|
+
return {
|
|
59
|
+
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
|
|
60
|
+
"OTEL_LOGS_EXPORTER": "otlp",
|
|
61
|
+
"OTEL_METRICS_EXPORTER": "otlp",
|
|
62
|
+
"OTEL_EXPORTER_OTLP_PROTOCOL": "http/json",
|
|
63
|
+
"OTEL_EXPORTER_OTLP_ENDPOINT": f"http://localhost:{port}",
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _find_framework_dir() -> Path:
|
|
68
|
+
"""Locate the pennyfarthing framework root from this package's location."""
|
|
69
|
+
# pennyfarthing_scripts/bikerack/launcher.py -> pennyfarthing/
|
|
70
|
+
return Path(__file__).resolve().parent.parent.parent
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def start_wheelhub(project_dir: Path) -> subprocess.Popen:
|
|
74
|
+
"""Start WheelHub server in background with IS_BIKERACK=1."""
|
|
75
|
+
framework_dir = _find_framework_dir()
|
|
76
|
+
bikerack_entry = framework_dir / "packages" / "cyclist" / "dist" / "bikerack.js"
|
|
77
|
+
|
|
78
|
+
env = os.environ.copy()
|
|
79
|
+
env["IS_BIKERACK"] = "1"
|
|
80
|
+
env["CYCLIST_PROJECT_DIR"] = str(project_dir)
|
|
81
|
+
|
|
82
|
+
return subprocess.Popen(
|
|
83
|
+
["node", str(bikerack_entry)],
|
|
84
|
+
env=env,
|
|
85
|
+
cwd=str(project_dir),
|
|
86
|
+
stdout=subprocess.DEVNULL,
|
|
87
|
+
stderr=subprocess.DEVNULL,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def poll_for_port_file(
|
|
92
|
+
project_dir: Path, timeout: float = 5.0, interval: float = 0.1
|
|
93
|
+
) -> int:
|
|
94
|
+
"""Poll for .bikerack-port file, return port number."""
|
|
95
|
+
port_file = project_dir / ".bikerack-port"
|
|
96
|
+
deadline = time.monotonic() + timeout
|
|
97
|
+
|
|
98
|
+
while True:
|
|
99
|
+
if port_file.exists():
|
|
100
|
+
return int(port_file.read_text().strip())
|
|
101
|
+
if time.monotonic() >= deadline:
|
|
102
|
+
raise TimeoutError(
|
|
103
|
+
f"Timed out waiting for {port_file} after {timeout}s"
|
|
104
|
+
)
|
|
105
|
+
time.sleep(interval)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def register_cleanup(project_dir: Path, pid: int) -> None:
|
|
109
|
+
"""Register atexit handler to kill WheelHub and clean up files (Rule 8)."""
|
|
110
|
+
|
|
111
|
+
def _cleanup(project_dir: Path, pid: int) -> None:
|
|
112
|
+
try:
|
|
113
|
+
os.kill(pid, signal.SIGTERM)
|
|
114
|
+
except (ProcessLookupError, OSError):
|
|
115
|
+
pass
|
|
116
|
+
cleanup_files(project_dir)
|
|
117
|
+
|
|
118
|
+
atexit.register(_cleanup, project_dir, pid)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def exec_claude(otel_env: dict[str, str], project_dir: Path | None = None) -> NoReturn:
|
|
122
|
+
"""Replace current process with Claude CLI using os.execvpe (CE-4)."""
|
|
123
|
+
env = os.environ.copy()
|
|
124
|
+
env.update(otel_env)
|
|
125
|
+
if project_dir:
|
|
126
|
+
os.chdir(project_dir)
|
|
127
|
+
os.execvpe("claude", ["claude"], env)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def is_already_running(project_dir: Path) -> tuple[bool, int | None, int | None]:
|
|
131
|
+
"""Check if BikeRack is already running.
|
|
132
|
+
|
|
133
|
+
Returns (is_running, pid_or_none, port_or_none).
|
|
134
|
+
Cleans up stale files if PID is dead.
|
|
135
|
+
"""
|
|
136
|
+
pid = read_pid_file(project_dir)
|
|
137
|
+
port = read_port_file(project_dir)
|
|
138
|
+
|
|
139
|
+
if pid is None or port is None:
|
|
140
|
+
return (False, None, None)
|
|
141
|
+
|
|
142
|
+
if is_process_alive(pid):
|
|
143
|
+
return (True, pid, port)
|
|
144
|
+
|
|
145
|
+
cleanup_files(project_dir)
|
|
146
|
+
return (False, None, None)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def stop_bikerack(project_dir: Path) -> dict:
|
|
150
|
+
"""Stop running BikeRack instance. Returns {success, pid, message}."""
|
|
151
|
+
pid = read_pid_file(project_dir)
|
|
152
|
+
|
|
153
|
+
if pid is None:
|
|
154
|
+
return {"success": False, "message": "BikeRack is not running"}
|
|
155
|
+
|
|
156
|
+
if not is_process_alive(pid):
|
|
157
|
+
cleanup_files(project_dir)
|
|
158
|
+
return {"success": False, "message": "BikeRack is not running (stale PID)"}
|
|
159
|
+
|
|
160
|
+
os.kill(pid, signal.SIGTERM)
|
|
161
|
+
cleanup_files(project_dir)
|
|
162
|
+
return {"success": True, "pid": pid, "message": f"Stopped BikeRack (PID {pid})"}
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def get_status(project_dir: Path) -> dict:
|
|
166
|
+
"""Get BikeRack running status. Returns {running, pid, port, dashboard}."""
|
|
167
|
+
pid = read_pid_file(project_dir)
|
|
168
|
+
port = read_port_file(project_dir)
|
|
169
|
+
|
|
170
|
+
if pid is None or port is None:
|
|
171
|
+
return {"running": False}
|
|
172
|
+
|
|
173
|
+
if not is_process_alive(pid):
|
|
174
|
+
return {"running": False}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
"running": True,
|
|
178
|
+
"pid": pid,
|
|
179
|
+
"port": port,
|
|
180
|
+
"dashboard": f"http://localhost:{port}/bikerack",
|
|
181
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -65,6 +65,11 @@ from pennyfarthing_scripts.validate.cli import validate # noqa: E402
|
|
|
65
65
|
|
|
66
66
|
cli.add_command(validate)
|
|
67
67
|
|
|
68
|
+
# Import and register bikerack group
|
|
69
|
+
from pennyfarthing_scripts.bikerack.cli import bikerack # noqa: E402
|
|
70
|
+
|
|
71
|
+
cli.add_command(bikerack)
|
|
72
|
+
|
|
68
73
|
|
|
69
74
|
@cli.group()
|
|
70
75
|
def agent():
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|