@pennyfarthing/core 11.2.2 → 11.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/README.md +3 -3
  2. package/package.json +1 -1
  3. package/packages/core/dist/cli/commands/doctor-legacy.test.js +2 -2
  4. package/packages/core/dist/cli/commands/doctor-legacy.test.js.map +1 -1
  5. package/packages/core/dist/cli/commands/doctor.d.ts +55 -0
  6. package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
  7. package/packages/core/dist/cli/commands/doctor.js +204 -23
  8. package/packages/core/dist/cli/commands/doctor.js.map +1 -1
  9. package/packages/core/dist/cli/commands/init.d.ts +12 -0
  10. package/packages/core/dist/cli/commands/init.d.ts.map +1 -1
  11. package/packages/core/dist/cli/commands/init.js +45 -0
  12. package/packages/core/dist/cli/commands/init.js.map +1 -1
  13. package/packages/core/dist/cli/commands/pyproject-install.test.d.ts +19 -0
  14. package/packages/core/dist/cli/commands/pyproject-install.test.d.ts.map +1 -0
  15. package/packages/core/dist/cli/commands/pyproject-install.test.js +261 -0
  16. package/packages/core/dist/cli/commands/pyproject-install.test.js.map +1 -0
  17. package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.d.ts +17 -0
  18. package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.d.ts.map +1 -0
  19. package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.js +470 -0
  20. package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.js.map +1 -0
  21. package/packages/core/dist/cli/commands/update-consolidation.test.js +14 -6
  22. package/packages/core/dist/cli/commands/update-consolidation.test.js.map +1 -1
  23. package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
  24. package/packages/core/dist/cli/commands/update.js +31 -2
  25. package/packages/core/dist/cli/commands/update.js.map +1 -1
  26. package/packages/core/dist/cli/cyclist-migration.test.d.ts +16 -0
  27. package/packages/core/dist/cli/cyclist-migration.test.d.ts.map +1 -0
  28. package/packages/core/dist/cli/cyclist-migration.test.js +229 -0
  29. package/packages/core/dist/cli/cyclist-migration.test.js.map +1 -0
  30. package/packages/core/dist/cli/index.js +2 -0
  31. package/packages/core/dist/cli/index.js.map +1 -1
  32. package/packages/core/dist/cli/utils/python.d.ts.map +1 -1
  33. package/packages/core/dist/cli/utils/python.js +11 -0
  34. package/packages/core/dist/cli/utils/python.js.map +1 -1
  35. package/packages/core/dist/cli/utils/settings-hook-migration.test.d.ts +17 -0
  36. package/packages/core/dist/cli/utils/settings-hook-migration.test.d.ts.map +1 -0
  37. package/packages/core/dist/cli/utils/settings-hook-migration.test.js +382 -0
  38. package/packages/core/dist/cli/utils/settings-hook-migration.test.js.map +1 -0
  39. package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
  40. package/packages/core/dist/cli/utils/settings.js +15 -2
  41. package/packages/core/dist/cli/utils/settings.js.map +1 -1
  42. package/packages/core/dist/cli/utils/stale-artifacts.d.ts +59 -0
  43. package/packages/core/dist/cli/utils/stale-artifacts.d.ts.map +1 -0
  44. package/packages/core/dist/cli/utils/stale-artifacts.js +163 -0
  45. package/packages/core/dist/cli/utils/stale-artifacts.js.map +1 -0
  46. package/packages/core/dist/scripts/benchmark-integration.d.ts +182 -0
  47. package/packages/core/dist/scripts/benchmark-integration.d.ts.map +1 -0
  48. package/packages/core/dist/scripts/benchmark-integration.js +691 -0
  49. package/packages/core/dist/scripts/benchmark-integration.js.map +1 -0
  50. package/packages/core/dist/scripts/job-fair-aggregator.d.ts +150 -0
  51. package/packages/core/dist/scripts/job-fair-aggregator.d.ts.map +1 -0
  52. package/packages/core/dist/scripts/job-fair-aggregator.js +547 -0
  53. package/packages/core/dist/scripts/job-fair-aggregator.js.map +1 -0
  54. package/packages/core/dist/scripts/theme-detail.test.d.ts.map +1 -0
  55. package/packages/core/dist/scripts/theme-detail.test.js.map +1 -0
  56. package/packages/core/dist/server/settings.d.ts.map +1 -1
  57. package/packages/core/dist/server/settings.js +5 -0
  58. package/packages/core/dist/server/settings.js.map +1 -1
  59. package/packages/core/dist/workflow/tandem-workflow-templates.test.js +7 -5
  60. package/packages/core/dist/workflow/tandem-workflow-templates.test.js.map +1 -1
  61. package/packages/core/dist/workflow/workflow-migration.test.js +6 -5
  62. package/packages/core/dist/workflow/workflow-migration.test.js.map +1 -1
  63. package/pennyfarthing-dist/agents/dev.md +4 -2
  64. package/pennyfarthing-dist/agents/devops.md +2 -10
  65. package/pennyfarthing-dist/agents/reviewer-preflight.md +4 -5
  66. package/pennyfarthing-dist/agents/sm.md +4 -17
  67. package/pennyfarthing-dist/commands/pf-health-check.md +30 -11
  68. package/pennyfarthing-dist/gates/{confidence-sm.md → confidence.md} +16 -17
  69. package/pennyfarthing-dist/gates/dev-exit.md +75 -0
  70. package/pennyfarthing-dist/gates/merge-ready.md +49 -0
  71. package/pennyfarthing-dist/gates/release-ready.md +95 -0
  72. package/pennyfarthing-dist/gates/reviewer-preflight-check.md +90 -0
  73. package/pennyfarthing-dist/gates/sm-setup-exit.md +82 -0
  74. package/pennyfarthing-dist/guides/agent-behavior.md +88 -30
  75. package/pennyfarthing-dist/guides/gates.md +7 -2
  76. package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
  77. package/pennyfarthing-dist/scripts/lib/find-root.sh +5 -0
  78. package/pennyfarthing-dist/scripts/lib/run-pf.sh +4 -0
  79. package/pennyfarthing-dist/skills/pf-settings/skill.md +42 -0
  80. package/pennyfarthing-dist/skills/skill-registry.yaml +15 -0
  81. package/pennyfarthing-dist/templates/pyproject.toml +27 -0
  82. package/pennyfarthing-dist/workflows/bdd-tandem.yaml +7 -3
  83. package/pennyfarthing-dist/workflows/bdd.yaml +7 -3
  84. package/pennyfarthing-dist/workflows/installation-check/steps/step-01-foundation.md +77 -0
  85. package/pennyfarthing-dist/workflows/installation-check/steps/step-02-commands.md +82 -0
  86. package/pennyfarthing-dist/workflows/installation-check/steps/step-03-hooks.md +121 -0
  87. package/pennyfarthing-dist/workflows/installation-check/steps/step-04-scripts.md +83 -0
  88. package/pennyfarthing-dist/workflows/installation-check/steps/step-05-layout.md +81 -0
  89. package/pennyfarthing-dist/workflows/installation-check/steps/step-06-legacy.md +94 -0
  90. package/pennyfarthing-dist/workflows/installation-check/steps/step-07-tools.md +80 -0
  91. package/pennyfarthing-dist/workflows/installation-check/steps/step-08-summary.md +99 -0
  92. package/pennyfarthing-dist/workflows/installation-check/workflow.yaml +47 -0
  93. package/pennyfarthing-dist/workflows/tdd-tandem.yaml +7 -3
  94. package/pennyfarthing-dist/workflows/tdd.yaml +7 -3
  95. package/pennyfarthing-dist/workflows/trivial.yaml +7 -3
  96. package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  97. package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  98. package/pennyfarthing_scripts/__pycache__/bellmode_hook.cpython-314.pyc +0 -0
  99. package/pennyfarthing_scripts/__pycache__/cli.cpython-311.pyc +0 -0
  100. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  101. package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
  102. package/pennyfarthing_scripts/__pycache__/context.cpython-311.pyc +0 -0
  103. package/pennyfarthing_scripts/__pycache__/context.cpython-314.pyc +0 -0
  104. package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
  105. package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
  106. package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
  107. package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
  108. package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
  109. package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
  110. package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
  111. package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
  112. package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
  113. package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
  114. package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
  115. package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
  116. package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
  117. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  118. package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-311.pyc +0 -0
  119. package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-314.pyc +0 -0
  120. package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-311.pyc +0 -0
  121. package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
  122. package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-311.pyc +0 -0
  123. package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
  124. package/pennyfarthing_scripts/bc/__pycache__/split.cpython-314.pyc +0 -0
  125. package/pennyfarthing_scripts/bc/cli.py +21 -0
  126. package/pennyfarthing_scripts/bc/focus.py +1 -0
  127. package/pennyfarthing_scripts/bc/split.py +52 -0
  128. package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-311.pyc +0 -0
  129. package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
  130. package/pennyfarthing_scripts/bikerack/__pycache__/__main__.cpython-314.pyc +0 -0
  131. package/pennyfarthing_scripts/bikerack/__pycache__/audit_log_panel.cpython-314.pyc +0 -0
  132. package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
  133. package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
  134. package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
  135. package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-311.pyc +0 -0
  136. package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
  137. package/pennyfarthing_scripts/bikerack/__pycache__/context_meter_footer.cpython-314.pyc +0 -0
  138. package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
  139. package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
  140. package/pennyfarthing_scripts/bikerack/__pycache__/events.cpython-314.pyc +0 -0
  141. package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
  142. package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-311.pyc +0 -0
  143. package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
  144. package/pennyfarthing_scripts/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
  145. package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
  146. package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
  147. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
  148. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
  149. package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
  150. package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
  151. package/pennyfarthing_scripts/bikerack/context_meter_footer.py +53 -3
  152. package/pennyfarthing_scripts/bikerack/tui.py +202 -8
  153. package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
  154. package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
  155. package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
  156. package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
  157. package/pennyfarthing_scripts/cli.py +5 -0
  158. package/pennyfarthing_scripts/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
  159. package/pennyfarthing_scripts/codemarkers/__pycache__/__main__.cpython-314.pyc +0 -0
  160. package/pennyfarthing_scripts/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
  161. package/pennyfarthing_scripts/codemarkers/__pycache__/cli.cpython-314.pyc +0 -0
  162. package/pennyfarthing_scripts/codemarkers/__pycache__/formatters.cpython-314.pyc +0 -0
  163. package/pennyfarthing_scripts/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
  164. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-311.pyc +0 -0
  165. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
  166. package/pennyfarthing_scripts/common/__pycache__/config.cpython-311.pyc +0 -0
  167. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  168. package/pennyfarthing_scripts/common/__pycache__/output.cpython-311.pyc +0 -0
  169. package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
  170. package/pennyfarthing_scripts/common/__pycache__/pr_config.cpython-314.pyc +0 -0
  171. package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
  172. package/pennyfarthing_scripts/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/complexity/__pycache__/__main__.cpython-314.pyc +0 -0
  174. package/pennyfarthing_scripts/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/complexity/__pycache__/cli.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/complexity/__pycache__/formatters.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/complexity/__pycache__/models.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-311.pyc +0 -0
  179. package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
  180. package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-311.pyc +0 -0
  181. package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
  182. package/pennyfarthing_scripts/consultation/__pycache__/dialogue_manager.cpython-314.pyc +0 -0
  183. package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-311.pyc +0 -0
  184. package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-314.pyc +0 -0
  185. package/pennyfarthing_scripts/deadcode/__pycache__/__main__.cpython-314.pyc +0 -0
  186. package/pennyfarthing_scripts/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
  187. package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-311.pyc +0 -0
  188. package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
  189. package/pennyfarthing_scripts/deadcode/__pycache__/formatters.cpython-314.pyc +0 -0
  190. package/pennyfarthing_scripts/deadcode/__pycache__/models.cpython-314.pyc +0 -0
  191. package/pennyfarthing_scripts/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
  192. package/pennyfarthing_scripts/dependencies/__pycache__/__main__.cpython-314.pyc +0 -0
  193. package/pennyfarthing_scripts/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
  194. package/pennyfarthing_scripts/dependencies/__pycache__/cli.cpython-314.pyc +0 -0
  195. package/pennyfarthing_scripts/dependencies/__pycache__/formatters.cpython-314.pyc +0 -0
  196. package/pennyfarthing_scripts/dependencies/__pycache__/models.cpython-314.pyc +0 -0
  197. package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-311.pyc +0 -0
  198. package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-314.pyc +0 -0
  199. package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-311.pyc +0 -0
  200. package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-314.pyc +0 -0
  201. package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
  202. package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
  203. package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
  204. package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-311.pyc +0 -0
  205. package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-314.pyc +0 -0
  206. package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-311.pyc +0 -0
  207. package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
  208. package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-311.pyc +0 -0
  209. package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
  210. package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-311.pyc +0 -0
  211. package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
  212. package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
  213. package/pennyfarthing_scripts/handoff/__pycache__/gate_file.cpython-314.pyc +0 -0
  214. package/pennyfarthing_scripts/handoff/__pycache__/gate_runner.cpython-314.pyc +0 -0
  215. package/pennyfarthing_scripts/handoff/__pycache__/marker.cpython-314.pyc +0 -0
  216. package/pennyfarthing_scripts/handoff/__pycache__/phase_check.cpython-314.pyc +0 -0
  217. package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
  218. package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-311.pyc +0 -0
  219. package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
  220. package/pennyfarthing_scripts/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
  221. package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-311.pyc +0 -0
  222. package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
  223. package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-311.pyc +0 -0
  224. package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
  225. package/pennyfarthing_scripts/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
  226. package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-311.pyc +0 -0
  227. package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-314.pyc +0 -0
  228. package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  229. package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  230. package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-311.pyc +0 -0
  231. package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
  232. package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-311.pyc +0 -0
  233. package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-314.pyc +0 -0
  234. package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-311.pyc +0 -0
  235. package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
  236. package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-311.pyc +0 -0
  237. package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
  238. package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-311.pyc +0 -0
  239. package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
  240. package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-311.pyc +0 -0
  241. package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
  242. package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-311.pyc +0 -0
  243. package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
  244. package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-311.pyc +0 -0
  245. package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
  246. package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-311.pyc +0 -0
  247. package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
  248. package/pennyfarthing_scripts/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
  249. package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-311.pyc +0 -0
  250. package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
  251. package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-311.pyc +0 -0
  252. package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
  253. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-311.pyc +0 -0
  254. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
  255. package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
  256. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-311.pyc +0 -0
  257. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
  258. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-311.pyc +0 -0
  259. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
  260. package/pennyfarthing_scripts/hotspots/__pycache__/formatters.cpython-314.pyc +0 -0
  261. package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-311.pyc +0 -0
  262. package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
  263. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-311.pyc +0 -0
  264. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  265. package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
  266. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-311.pyc +0 -0
  267. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  268. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-311.pyc +0 -0
  269. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
  270. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-311.pyc +0 -0
  271. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  272. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-311.pyc +0 -0
  273. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  274. package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
  275. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-311.pyc +0 -0
  276. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
  277. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-311.pyc +0 -0
  278. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
  279. package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
  280. package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
  281. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-311.pyc +0 -0
  282. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
  283. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-311.pyc +0 -0
  284. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  285. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-311.pyc +0 -0
  286. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
  287. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-311.pyc +0 -0
  288. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
  289. package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-311.pyc +0 -0
  290. package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-314.pyc +0 -0
  291. package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-311.pyc +0 -0
  292. package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-314.pyc +0 -0
  293. package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
  294. package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
  295. package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
  296. package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
  297. package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
  298. package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
  299. package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
  300. package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
  301. package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
  302. package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
  303. package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
  304. package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  305. package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
  306. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  307. package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
  308. package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
  309. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  310. package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
  311. package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  312. package/pennyfarthing_scripts/prime/__pycache__/version_sentinel.cpython-314.pyc +0 -0
  313. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  314. package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-311.pyc +0 -0
  315. package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-314.pyc +0 -0
  316. package/pennyfarthing_scripts/session/__pycache__/cli.cpython-311.pyc +0 -0
  317. package/pennyfarthing_scripts/session/__pycache__/cli.cpython-314.pyc +0 -0
  318. package/pennyfarthing_scripts/settings/__init__.py +0 -0
  319. package/pennyfarthing_scripts/settings/__pycache__/__init__.cpython-314.pyc +0 -0
  320. package/pennyfarthing_scripts/settings/__pycache__/cli.cpython-314.pyc +0 -0
  321. package/pennyfarthing_scripts/settings/__pycache__/settings.cpython-314.pyc +0 -0
  322. package/pennyfarthing_scripts/settings/cli.py +55 -0
  323. package/pennyfarthing_scripts/settings/settings.py +98 -0
  324. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-311.pyc +0 -0
  325. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  326. package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
  327. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-311.pyc +0 -0
  328. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  329. package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  330. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-311.pyc +0 -0
  331. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  332. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-311.pyc +0 -0
  333. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  334. package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-311.pyc +0 -0
  335. package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-314.pyc +0 -0
  336. package/pennyfarthing_scripts/sprint/__pycache__/import_epic.cpython-314.pyc +0 -0
  337. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-311.pyc +0 -0
  338. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  339. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-311.pyc +0 -0
  340. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
  341. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-311.pyc +0 -0
  342. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
  343. package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
  344. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-311.pyc +0 -0
  345. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  346. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-311.pyc +0 -0
  347. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  348. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-311.pyc +0 -0
  349. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  350. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-311.pyc +0 -0
  351. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  352. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-311.pyc +0 -0
  353. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  354. package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
  355. package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
  356. package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
  357. package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
  358. package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
  359. package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
  360. package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
  361. package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  362. package/pennyfarthing_scripts/tests/__pycache__/test_108_1_gate_migration.cpython-314-pytest-9.0.2.pyc +0 -0
  363. package/pennyfarthing_scripts/tests/__pycache__/test_archive_epic.cpython-314-pytest-9.0.2.pyc +0 -0
  364. package/pennyfarthing_scripts/tests/__pycache__/test_bc.cpython-314-pytest-9.0.2.pyc +0 -0
  365. package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
  366. package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
  367. package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
  368. package/pennyfarthing_scripts/tests/__pycache__/test_cli_normalization.cpython-314-pytest-9.0.2.pyc +0 -0
  369. package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
  370. package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
  371. package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_evaluation.cpython-314-pytest-9.0.2.pyc +0 -0
  372. package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_gate.cpython-314-pytest-9.0.2.pyc +0 -0
  373. package/pennyfarthing_scripts/tests/__pycache__/test_dialogue_manager.cpython-314-pytest-9.0.2.pyc +0 -0
  374. package/pennyfarthing_scripts/tests/__pycache__/test_epic_shard_validation.cpython-314-pytest-9.0.2.pyc +0 -0
  375. package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
  376. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  377. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_e2e.cpython-314-pytest-9.0.2.pyc +0 -0
  378. package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
  379. package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
  380. package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
  381. package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
  382. package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
  383. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
  384. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_panel.cpython-314-pytest-9.0.2.pyc +0 -0
  385. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
  386. package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
  387. package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
  388. package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
  389. package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
  390. package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
  391. package/pennyfarthing_scripts/tests/__pycache__/test_topology_loader.cpython-314-pytest-9.0.2.pyc +0 -0
  392. package/pennyfarthing_scripts/tests/__pycache__/test_tui_focus.cpython-314-pytest-9.0.2.pyc +0 -0
  393. package/pennyfarthing_scripts/tests/__pycache__/test_tui_panel_persistence.cpython-314-pytest-9.0.2.pyc +0 -0
  394. package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
  395. package/pennyfarthing_scripts/tests/__pycache__/test_version_sentinel.cpython-314-pytest-9.0.2.pyc +0 -0
  396. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
  397. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  398. package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
  399. package/pennyfarthing_scripts/tests/test_confidence_sm_gate.py +17 -16
  400. package/pennyfarthing_scripts/tests/test_resolve_gate_file_field.py +45 -47
  401. package/pennyfarthing_scripts/tests/test_workflow_list_team.py +0 -4
  402. package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-311.pyc +0 -0
  403. package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-314.pyc +0 -0
  404. package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-311.pyc +0 -0
  405. package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
  406. package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-311.pyc +0 -0
  407. package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-314.pyc +0 -0
  408. package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-311.pyc +0 -0
  409. package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
  410. package/pennyfarthing_scripts/validate/adapters/__pycache__/__init__.cpython-314.pyc +0 -0
  411. package/pennyfarthing_scripts/validate/adapters/__pycache__/agent.cpython-314.pyc +0 -0
  412. package/pennyfarthing_scripts/validate/adapters/__pycache__/schema.cpython-314.pyc +0 -0
  413. package/pennyfarthing_scripts/validate/adapters/__pycache__/skill_command.cpython-314.pyc +0 -0
  414. package/pennyfarthing_scripts/validate/adapters/__pycache__/sprint.cpython-314.pyc +0 -0
  415. package/pennyfarthing_scripts/validate/adapters/__pycache__/tandem_awareness.cpython-314.pyc +0 -0
  416. package/pennyfarthing_scripts/validate/adapters/__pycache__/workflow.cpython-314.pyc +0 -0
  417. package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-311.pyc +0 -0
  418. package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
  419. package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-311.pyc +0 -0
  420. package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
  421. package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
  422. package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-311.pyc +0 -0
  423. package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
  424. package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-311.pyc +0 -0
  425. package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
  426. package/packages/core/dist/workflow/team-lifecycle.d.ts +0 -169
  427. package/packages/core/dist/workflow/team-lifecycle.d.ts.map +0 -1
  428. package/packages/core/dist/workflow/team-lifecycle.js +0 -217
  429. package/packages/core/dist/workflow/team-lifecycle.js.map +0 -1
  430. package/packages/core/dist/workflow/team-lifecycle.test.d.ts +0 -20
  431. package/packages/core/dist/workflow/team-lifecycle.test.d.ts.map +0 -1
  432. package/packages/core/dist/workflow/team-lifecycle.test.js +0 -966
  433. package/packages/core/dist/workflow/team-lifecycle.test.js.map +0 -1
  434. package/pennyfarthing_scripts/bikerack/__pycache__/portrait.cpython-314.pyc +0 -0
  435. package/pennyfarthing_scripts/gate/__pycache__/__init__.cpython-314.pyc +0 -0
  436. package/pennyfarthing_scripts/gate/__pycache__/cli.cpython-314.pyc +0 -0
  437. package/pennyfarthing_scripts/gate/__pycache__/validate.cpython-314.pyc +0 -0
  438. package/pennyfarthing_scripts/git/__pycache__/hooks_installer.cpython-314.pyc +0 -0
  439. package/pennyfarthing_scripts/git/__pycache__/repos.cpython-314.pyc +0 -0
  440. package/pennyfarthing_scripts/git/__pycache__/worktree.cpython-314.pyc +0 -0
  441. package/pennyfarthing_scripts/prime/__pycache__/heatmap.cpython-314.pyc +0 -0
  442. package/pennyfarthing_scripts/tests/__pycache__/test_108_2_remove_handoff_fallback.cpython-314-pytest-9.0.2.pyc +0 -0
  443. package/pennyfarthing_scripts/tests/__pycache__/test_gate_file_resolution.cpython-314-pytest-9.0.2.pyc +0 -0
  444. package/pennyfarthing_scripts/tests/__pycache__/test_gate_runner.cpython-314-pytest-9.0.2.pyc +0 -0
  445. package/pennyfarthing_scripts/tests/__pycache__/test_resolve_gate_file_field.cpython-314-pytest-9.0.2.pyc +0 -0
  446. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_list_team.cpython-314-pytest-9.0.2.pyc +0 -0
  447. package/pennyfarthing_scripts/validate/adapters/__pycache__/team_mode.cpython-314.pyc +0 -0
  448. package/pennyfarthing_scripts/workflow/__pycache__/team_lifecycle.cpython-314.pyc +0 -0
@@ -106,6 +106,14 @@ PANEL_DISPLAY_NAMES: dict[str, str] = {
106
106
  # Keys from PANEL_REGISTRY for fast lookup
107
107
  _PANEL_KEYS = [key for key, _ in PANEL_REGISTRY]
108
108
 
109
+ # Split-pane layout presets: name → (left_panel, right_panel)
110
+ # Story 110-4: Named presets for common side-by-side views.
111
+ SPLIT_PRESETS: dict[str, tuple[str, str]] = {
112
+ "sprint+diffs": ("sprint", "diffs"),
113
+ "changed+diffs": ("changed", "diffs"),
114
+ "progress+debug": ("progress", "debug"),
115
+ }
116
+
109
117
 
110
118
  class BindingFooter(Footer):
111
119
  """Footer subclass that exposes active binding text via render().
@@ -360,9 +368,10 @@ class BikeRackApp(App):
360
368
  class FocusUpdate(Message, bubble=False):
361
369
  """Focus change from WS — routed through Textual message system."""
362
370
 
363
- def __init__(self, focus: str | None) -> None:
371
+ def __init__(self, focus: str | None, split_config: dict | None = None) -> None:
364
372
  super().__init__()
365
373
  self.focus = focus
374
+ self.split_config = split_config
366
375
 
367
376
  class WsStateUpdate(Message, bubble=False):
368
377
  """WS connection state change — routed through Textual message system."""
@@ -413,12 +422,23 @@ class BikeRackApp(App):
413
422
  ContextMeterFooter {
414
423
  height: 1;
415
424
  }
425
+ #split-container {
426
+ display: none;
427
+ height: 1fr;
428
+ }
429
+ #split-left {
430
+ width: 1fr;
431
+ }
432
+ #split-right {
433
+ width: 1fr;
434
+ }
416
435
  """
417
436
 
418
437
  COMMANDS = App.COMMANDS | {PanelCommands}
419
438
 
420
439
  BINDINGS = [
421
440
  Binding("q", "quit", "Quit"),
441
+ Binding("shift+s", "toggle_split", "Split"),
422
442
  Binding("1", "switch_panel('sprint')", "Sprint", show=False),
423
443
  Binding("2", "switch_panel('git')", "Git", show=False),
424
444
  Binding("3", "switch_panel('diffs')", "Diffs", show=False),
@@ -429,8 +449,8 @@ class BikeRackApp(App):
429
449
  Binding("8", "switch_panel('progress')", "Progress", show=False),
430
450
  Binding("bracketright", "next_panel", "]Next"),
431
451
  Binding("bracketleft", "prev_panel", "[Prev"),
432
- Binding("tab", "next_panel", show=False),
433
- Binding("shift+tab", "prev_panel", show=False),
452
+ Binding("tab", "next_panel", show=False, priority=True),
453
+ Binding("shift+tab", "prev_panel", show=False, priority=True),
434
454
  Binding("n", "next_diff_file", "Next file", show=False),
435
455
  Binding("p", "prev_diff_file", "Prev file", show=False),
436
456
  Binding("j", "next_epic", show=False),
@@ -448,6 +468,12 @@ class BikeRackApp(App):
448
468
  self._focused_panel: str = "sprint"
449
469
  self._previous_panel: str | None = None
450
470
  self._programmatic_tab_count: int = 0
471
+ self._context_meter: ContextMeterFooter | None = None
472
+ # Split-pane state (Story 110-4)
473
+ self._split_mode: bool = False
474
+ self._active_split_pane: str = "left"
475
+ self._split_left_key: str = "sprint"
476
+ self._split_right_key: str = "diffs"
451
477
 
452
478
  def compose(self) -> ComposeResult:
453
479
  project_dir_name = Path(
@@ -470,7 +496,11 @@ class BikeRackApp(App):
470
496
  yield AuditLogPanel(client=self._client, id="panel-audit-log")
471
497
  yield DebugPanel(client=self._client, id="panel-debug")
472
498
  yield ProgressPanel(client=self._client, id="panel-progress")
473
- yield ContextMeterFooter(client=self._client)
499
+ with Horizontal(id="split-container"):
500
+ yield VerticalScroll(id="split-left")
501
+ yield VerticalScroll(id="split-right")
502
+ self._context_meter = ContextMeterFooter(client=self._client)
503
+ yield self._context_meter
474
504
  yield BindingFooter()
475
505
 
476
506
  async def on_mount(self) -> None:
@@ -543,8 +573,27 @@ class BikeRackApp(App):
543
573
  save_last_panel(key, project_dir=None)
544
574
  self._update_tab_bar(key)
545
575
 
576
+ # Refresh context meter on panel switch (110-12)
577
+ if self._context_meter is not None:
578
+ self._context_meter.request_refresh()
579
+
546
580
  def action_next_panel(self) -> None:
547
- """Cycle to the next panel."""
581
+ """Cycle to the next panel, or toggle pane focus in split mode."""
582
+ if self._split_mode:
583
+ # In split mode, Tab toggles between left and right pane
584
+ if self._active_split_pane == "left":
585
+ self._active_split_pane = "right"
586
+ try:
587
+ self.query_one("#split-right").focus()
588
+ except Exception:
589
+ pass
590
+ else:
591
+ self._active_split_pane = "left"
592
+ try:
593
+ self.query_one("#split-left").focus()
594
+ except Exception:
595
+ pass
596
+ return
548
597
  try:
549
598
  idx = _PANEL_KEYS.index(self._focused_panel)
550
599
  except ValueError:
@@ -606,6 +655,131 @@ class BikeRackApp(App):
606
655
  except Exception:
607
656
  pass
608
657
 
658
+ # ------------------------------------------------------------------
659
+ # Split-pane layout (Story 110-4)
660
+ # ------------------------------------------------------------------
661
+
662
+ def _sync_reparent(self, widget: Any, new_parent: Any) -> None:
663
+ """Move widget from current parent to new parent synchronously.
664
+
665
+ Uses internal Textual DOM API so the move is visible immediately
666
+ without awaiting an async mount/remove cycle.
667
+ """
668
+ old_parent = widget._parent
669
+ if old_parent is not None:
670
+ try:
671
+ old_parent._nodes._remove(widget)
672
+ except (ValueError, AttributeError):
673
+ # Fallback: remove from internal list directly
674
+ try:
675
+ old_parent._nodes._nodes.remove(widget)
676
+ except Exception:
677
+ pass
678
+ try:
679
+ new_parent._nodes._append(widget)
680
+ except AttributeError:
681
+ new_parent._nodes._nodes.append(widget)
682
+ widget._parent = new_parent
683
+
684
+ def _enter_split(self, left_key: str, right_key: str) -> None:
685
+ """Activate split mode with specified panels (synchronous)."""
686
+ if left_key not in _PANEL_KEYS or right_key not in _PANEL_KEYS:
687
+ return
688
+ if left_key == right_key:
689
+ return
690
+
691
+ self._split_mode = True
692
+ self._split_left_key = left_key
693
+ self._split_right_key = right_key
694
+ self._active_split_pane = "left"
695
+
696
+ try:
697
+ main_content = self.query_one("#main-content")
698
+ split_container = self.query_one("#split-container")
699
+ split_left = self.query_one("#split-left")
700
+ split_right = self.query_one("#split-right")
701
+ except Exception:
702
+ return
703
+
704
+ # Move left panel to split-left pane
705
+ try:
706
+ left_panel = self.query_one(f"#panel-{left_key}")
707
+ left_panel.display = True
708
+ self._sync_reparent(left_panel, split_left)
709
+ except Exception:
710
+ pass
711
+
712
+ # Move right panel to split-right pane
713
+ try:
714
+ right_panel = self.query_one(f"#panel-{right_key}")
715
+ right_panel.display = True
716
+ self._sync_reparent(right_panel, split_right)
717
+ except Exception:
718
+ pass
719
+
720
+ # Hide all other panels remaining in main-content
721
+ for panel_key in _PANEL_KEYS:
722
+ if panel_key not in (left_key, right_key):
723
+ try:
724
+ p = self.query_one(f"#panel-{panel_key}")
725
+ p.display = False
726
+ except Exception:
727
+ pass
728
+
729
+ main_content.display = False
730
+ split_container.display = True
731
+
732
+ def _exit_split(self) -> None:
733
+ """Deactivate split mode, return panels to main-content."""
734
+ self._split_mode = False
735
+
736
+ try:
737
+ main_content = self.query_one("#main-content")
738
+ split_container = self.query_one("#split-container")
739
+ split_left = self.query_one("#split-left")
740
+ split_right = self.query_one("#split-right")
741
+ except Exception:
742
+ return
743
+
744
+ # Move panels back from split panes to main-content
745
+ for pane in (split_left, split_right):
746
+ for child in list(pane.children):
747
+ self._sync_reparent(child, main_content)
748
+
749
+ split_container.display = False
750
+ main_content.display = True
751
+
752
+ # Restore single-panel visibility
753
+ for panel_key in _PANEL_KEYS:
754
+ try:
755
+ p = self.query_one(f"#panel-{panel_key}")
756
+ p.display = (panel_key == self._focused_panel)
757
+ except Exception:
758
+ pass
759
+
760
+ def action_toggle_split(self) -> None:
761
+ """Toggle split mode on/off (Shift+S keybinding)."""
762
+ if self._split_mode:
763
+ self._exit_split()
764
+ else:
765
+ # Default: current panel left, next panel right
766
+ left_key = self._focused_panel
767
+ try:
768
+ idx = _PANEL_KEYS.index(left_key)
769
+ except ValueError:
770
+ idx = 0
771
+ right_key = _PANEL_KEYS[(idx + 1) % len(_PANEL_KEYS)]
772
+ self._enter_split(left_key, right_key)
773
+
774
+ def action_apply_split_preset(self, name: str) -> None:
775
+ """Apply a named split preset (synchronous)."""
776
+ if name not in SPLIT_PRESETS:
777
+ return
778
+ left_key, right_key = SPLIT_PRESETS[name]
779
+ if self._split_mode:
780
+ self._exit_split()
781
+ self._enter_split(left_key, right_key)
782
+
609
783
  def _update_tab_bar(self, panel_key: str) -> None:
610
784
  """Update the tab bar widget with the given panel key.
611
785
 
@@ -638,7 +812,10 @@ class BikeRackApp(App):
638
812
  def _handle_focus_message(self, message: dict[str, Any] | None) -> None:
639
813
  """Handle incoming focus channel messages.
640
814
 
641
- Expected format: {type: 'init'|'update', focus: '<panel>'|null}
815
+ Expected format:
816
+ Single panel: {type: 'update', focus: '<panel>'}
817
+ Split layout: {type: 'update', focus: 'split', split: {left: ..., right: ...}}
818
+ Split preset: {type: 'update', focus: 'split:<preset-name>'}
642
819
  Only 'update' messages trigger panel switches (matching React hook).
643
820
  Routes through Textual message system via post_message for proper repaint.
644
821
  """
@@ -648,7 +825,8 @@ class BikeRackApp(App):
648
825
  return
649
826
  if "focus" not in message:
650
827
  return
651
- self.post_message(self.FocusUpdate(message["focus"]))
828
+ split_config = message.get("split")
829
+ self.post_message(self.FocusUpdate(message["focus"], split_config=split_config))
652
830
 
653
831
  def _handle_persona_message(self, message: dict[str, Any] | None) -> None:
654
832
  """Handle incoming persona channel messages.
@@ -677,7 +855,23 @@ class BikeRackApp(App):
677
855
  def on_bike_rack_app_focus_update(self, event: FocusUpdate) -> None:
678
856
  """Apply focus change in Textual message context."""
679
857
  focus = event.focus
680
- if focus is not None and focus in _PANEL_KEYS:
858
+ split_config = event.split_config
859
+
860
+ if focus == "split" and split_config:
861
+ # Explicit split layout: {focus: "split", split: {left: ..., right: ...}}
862
+ left = split_config.get("left", "sprint")
863
+ right = split_config.get("right", "diffs")
864
+ if self._split_mode:
865
+ self._exit_split()
866
+ self._enter_split(left, right)
867
+ elif focus is not None and focus.startswith("split:"):
868
+ # Preset reference: {focus: "split:progress+debug"}
869
+ preset_name = focus[len("split:"):]
870
+ self.action_apply_split_preset(preset_name)
871
+ elif focus is not None and focus in _PANEL_KEYS:
872
+ # Single panel focus — exit split if active
873
+ if self._split_mode:
874
+ self._exit_split()
681
875
  self.action_switch_panel(focus)
682
876
  elif focus is not None:
683
877
  self._previous_panel = self._focused_panel
@@ -147,6 +147,11 @@ from pennyfarthing_scripts.hooks.cli import hooks # noqa: E402
147
147
 
148
148
  cli.add_command(hooks)
149
149
 
150
+ # Import and register settings group
151
+ from pennyfarthing_scripts.settings.cli import settings # noqa: E402
152
+
153
+ cli.add_command(settings)
154
+
150
155
 
151
156
  @cli.group()
152
157
  def agent():