@pennyfarthing/core 10.2.0 → 10.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -8
- package/package.json +1 -1
- 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.d.ts.map +1 -1
- package/packages/core/dist/scripts/generate-spider.js +2 -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 +32 -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/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.py +2 -2
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +1 -0
- package/pennyfarthing-dist/skills/theme/skill.md +1 -1
- 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/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
|
@@ -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
|
|
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
|
|
@@ -490,7 +490,8 @@ async def _probe_agent_context_efficiency(target_path: Path) -> float | None:
|
|
|
490
490
|
from pennyfarthing_scripts.prime.tiers import ContextTier, load_tier_components
|
|
491
491
|
|
|
492
492
|
agents = ["sm", "tea", "dev", "reviewer", "architect",
|
|
493
|
-
"pm", "tech-writer", "ux-designer", "devops", "orchestrator"
|
|
493
|
+
"pm", "tech-writer", "ux-designer", "devops", "orchestrator",
|
|
494
|
+
"ba"]
|
|
494
495
|
|
|
495
496
|
target_budget = 4000
|
|
496
497
|
scores: list[float] = []
|
|
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
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -47,6 +47,7 @@ from pennyfarthing_scripts.prime.loader import (
|
|
|
47
47
|
load_agent_definition,
|
|
48
48
|
load_behavior_guide,
|
|
49
49
|
load_domain_docs,
|
|
50
|
+
load_repos_topology,
|
|
50
51
|
load_session_context,
|
|
51
52
|
load_sidecars,
|
|
52
53
|
load_sprint_context,
|
|
@@ -94,6 +95,7 @@ __all__ = [
|
|
|
94
95
|
"load_session_context",
|
|
95
96
|
"load_sidecars",
|
|
96
97
|
"load_domain_docs",
|
|
98
|
+
"load_repos_topology",
|
|
97
99
|
# Workflow detection
|
|
98
100
|
"detect_workflow_state",
|
|
99
101
|
"check_redirect",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -102,6 +102,7 @@ def _component_header(name: str, agent_name: str | None) -> str:
|
|
|
102
102
|
"persona_compressed": f"Persona: {agent_name} (compressed)",
|
|
103
103
|
"behavior_guide": "Agent Behavior Guide",
|
|
104
104
|
"sprint_context": "Sprint Context",
|
|
105
|
+
"repos_topology": "Repos Topology",
|
|
105
106
|
"session_header": "Active Session",
|
|
106
107
|
"session_assessment": "Session Assessment",
|
|
107
108
|
"sidecars": f"Agent Sidecar: {agent_name}",
|
|
@@ -118,6 +119,7 @@ def _component_source(name: str, agent_name: str | None, root: Path) -> str | No
|
|
|
118
119
|
"persona_compressed": None,
|
|
119
120
|
"behavior_guide": ".pennyfarthing/guides/agent-behavior.md",
|
|
120
121
|
"sprint_context": "sprint/current-sprint.yaml",
|
|
122
|
+
"repos_topology": ".pennyfarthing/repos.yaml",
|
|
121
123
|
"session_header": None,
|
|
122
124
|
"session_assessment": None,
|
|
123
125
|
"sidecars": f".pennyfarthing/sidecars/{agent_name}/",
|
|
@@ -474,6 +476,17 @@ def prime(
|
|
|
474
476
|
_print_header("Sprint Context", quiet)
|
|
475
477
|
print(sprint_content)
|
|
476
478
|
|
|
479
|
+
# ==========================================================================
|
|
480
|
+
# PRIORITY 5.5: Repos Topology
|
|
481
|
+
# ==========================================================================
|
|
482
|
+
if not json_output:
|
|
483
|
+
from pennyfarthing_scripts.prime.loader import load_repos_topology
|
|
484
|
+
|
|
485
|
+
topology_content = load_repos_topology(root)
|
|
486
|
+
if topology_content:
|
|
487
|
+
_print_header("Repos Topology", quiet)
|
|
488
|
+
print(topology_content)
|
|
489
|
+
|
|
477
490
|
# ==========================================================================
|
|
478
491
|
# PRIORITY 6: Session context
|
|
479
492
|
# ==========================================================================
|