@pennyfarthing/core 11.2.1 → 11.2.2

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 (467) hide show
  1. package/README.md +100 -40
  2. package/package.json +1 -1
  3. package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
  4. package/packages/core/dist/cli/commands/doctor.js +121 -28
  5. package/packages/core/dist/cli/commands/doctor.js.map +1 -1
  6. package/packages/core/dist/cli/utils/settings.d.ts +0 -4
  7. package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
  8. package/packages/core/dist/cli/utils/settings.js +31 -26
  9. package/packages/core/dist/cli/utils/settings.js.map +1 -1
  10. package/packages/core/dist/consultation/dialogue-manager.d.ts +1 -1
  11. package/packages/core/dist/consultation/dialogue-manager.d.ts.map +1 -1
  12. package/packages/core/dist/consultation/dialogue-manager.js +1 -1
  13. package/packages/core/dist/consultation/dialogue-manager.js.map +1 -1
  14. package/packages/core/dist/consultation/dialogue-manager.test.js.map +1 -1
  15. package/packages/core/dist/consultation/tandem-metrics.test.js.map +1 -1
  16. package/packages/core/dist/public/css/react.css +1 -1
  17. package/packages/core/dist/public/js/react/react.js +9 -9
  18. package/packages/core/dist/server/api/git.d.ts.map +1 -1
  19. package/packages/core/dist/server/api/git.js +0 -1
  20. package/packages/core/dist/server/api/git.js.map +1 -1
  21. package/packages/core/dist/server/api/index.d.ts +2 -0
  22. package/packages/core/dist/server/api/index.d.ts.map +1 -1
  23. package/packages/core/dist/server/api/index.js +2 -0
  24. package/packages/core/dist/server/api/index.js.map +1 -1
  25. package/packages/core/dist/server/api/project-info.d.ts +11 -0
  26. package/packages/core/dist/server/api/project-info.d.ts.map +1 -0
  27. package/packages/core/dist/server/api/project-info.js +18 -0
  28. package/packages/core/dist/server/api/project-info.js.map +1 -0
  29. package/packages/core/dist/server/otlp-receiver.d.ts.map +1 -1
  30. package/packages/core/dist/server/otlp-receiver.js +18 -1
  31. package/packages/core/dist/server/otlp-receiver.js.map +1 -1
  32. package/packages/core/dist/server/otlp-receiver.test.js +1 -1
  33. package/packages/core/dist/server/otlp-receiver.test.js.map +1 -1
  34. package/packages/core/dist/server/server.d.ts.map +1 -1
  35. package/packages/core/dist/server/server.js +3 -2
  36. package/packages/core/dist/server/server.js.map +1 -1
  37. package/packages/core/dist/server/server.test.d.ts +1 -1
  38. package/packages/core/dist/server/server.test.js +8 -8
  39. package/packages/core/dist/server/settings.d.ts +1 -0
  40. package/packages/core/dist/server/settings.d.ts.map +1 -1
  41. package/packages/core/dist/server/settings.js +13 -0
  42. package/packages/core/dist/server/settings.js.map +1 -1
  43. package/packages/core/dist/workflow/team-lifecycle.d.ts +169 -0
  44. package/packages/core/dist/workflow/team-lifecycle.d.ts.map +1 -0
  45. package/packages/core/dist/workflow/team-lifecycle.js +217 -0
  46. package/packages/core/dist/workflow/team-lifecycle.js.map +1 -0
  47. package/packages/core/dist/workflow/team-lifecycle.test.d.ts +20 -0
  48. package/packages/core/dist/workflow/team-lifecycle.test.d.ts.map +1 -0
  49. package/packages/core/dist/workflow/team-lifecycle.test.js +966 -0
  50. package/packages/core/dist/workflow/team-lifecycle.test.js.map +1 -0
  51. package/packages/core/dist/workflow/workflow-team-templates.test.d.ts +17 -0
  52. package/packages/core/dist/workflow/workflow-team-templates.test.d.ts.map +1 -0
  53. package/packages/core/dist/workflow/workflow-team-templates.test.js +275 -0
  54. package/packages/core/dist/workflow/workflow-team-templates.test.js.map +1 -0
  55. package/pennyfarthing-dist/agents/dev.md +15 -2
  56. package/pennyfarthing-dist/agents/reviewer.md +17 -4
  57. package/pennyfarthing-dist/agents/sm-finish.md +1 -1
  58. package/pennyfarthing-dist/agents/sm-setup.md +7 -7
  59. package/pennyfarthing-dist/agents/sm.md +12 -12
  60. package/pennyfarthing-dist/agents/tea.md +2 -2
  61. package/pennyfarthing-dist/agents/testing-runner.md +1 -1
  62. package/pennyfarthing-dist/commands/pf-architect.md +1 -1
  63. package/pennyfarthing-dist/commands/pf-ba.md +1 -1
  64. package/pennyfarthing-dist/commands/pf-chore.md +2 -2
  65. package/pennyfarthing-dist/commands/pf-dev.md +1 -1
  66. package/pennyfarthing-dist/commands/pf-devops.md +1 -1
  67. package/pennyfarthing-dist/commands/pf-epic.md +6 -6
  68. package/pennyfarthing-dist/commands/pf-git.md +10 -10
  69. package/pennyfarthing-dist/commands/pf-health-check.md +1 -1
  70. package/pennyfarthing-dist/commands/pf-help.md +12 -12
  71. package/pennyfarthing-dist/commands/pf-orchestrator.md +1 -1
  72. package/pennyfarthing-dist/commands/pf-pm.md +1 -1
  73. package/pennyfarthing-dist/commands/pf-prime.md +8 -8
  74. package/pennyfarthing-dist/commands/pf-reviewer.md +1 -1
  75. package/pennyfarthing-dist/commands/pf-session.md +7 -7
  76. package/pennyfarthing-dist/commands/pf-sm.md +1 -1
  77. package/pennyfarthing-dist/commands/pf-sprint.md +7 -7
  78. package/pennyfarthing-dist/commands/pf-tea.md +1 -1
  79. package/pennyfarthing-dist/commands/pf-tech-writer.md +1 -1
  80. package/pennyfarthing-dist/commands/pf-theme.md +9 -9
  81. package/pennyfarthing-dist/commands/pf-ux-designer.md +1 -1
  82. package/pennyfarthing-dist/commands/pf-work.md +1 -1
  83. package/pennyfarthing-dist/guides/agent-behavior.md +70 -19
  84. package/pennyfarthing-dist/guides/agent-coordination.md +10 -10
  85. package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +6 -6
  86. package/pennyfarthing-dist/guides/agent-template-tactical.md +1 -1
  87. package/pennyfarthing-dist/guides/bell-mode.md +1 -1
  88. package/pennyfarthing-dist/guides/bikerack.md +10 -10
  89. package/pennyfarthing-dist/guides/brownfield-tools.md +24 -24
  90. package/pennyfarthing-dist/guides/command-tag-taxonomy.md +1 -1
  91. package/pennyfarthing-dist/guides/gate-schema.md +2 -2
  92. package/pennyfarthing-dist/guides/gates.md +3 -3
  93. package/pennyfarthing-dist/guides/handoff-cli.md +8 -8
  94. package/pennyfarthing-dist/guides/hooks.md +27 -27
  95. package/pennyfarthing-dist/guides/prime.md +2 -2
  96. package/pennyfarthing-dist/guides/reflector.md +1 -1
  97. package/pennyfarthing-dist/guides/skill-schema.md +6 -6
  98. package/pennyfarthing-dist/guides/tandem-protocol.md +3 -3
  99. package/pennyfarthing-dist/guides/workflow-schema.md +1 -1
  100. package/pennyfarthing-dist/guides/worktree-mode.md +3 -3
  101. package/pennyfarthing-dist/guides/xml-tags.md +8 -8
  102. package/pennyfarthing-dist/scripts/README.md +4 -4
  103. package/pennyfarthing-dist/scripts/core/agent-session.sh +2 -5
  104. package/pennyfarthing-dist/scripts/core/check-context.sh +1 -1
  105. package/pennyfarthing-dist/scripts/core/pf.sh +5 -0
  106. package/pennyfarthing-dist/scripts/core/phase-check-start.sh +2 -5
  107. package/pennyfarthing-dist/scripts/core/prime.sh +2 -25
  108. package/pennyfarthing-dist/scripts/git/README.md +14 -14
  109. package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +2 -3
  110. package/pennyfarthing-dist/scripts/git/git-status-all.sh +2 -3
  111. package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +2 -3
  112. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +2 -4
  113. package/pennyfarthing-dist/scripts/hooks/README.md +6 -6
  114. package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +3 -3
  115. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +3 -3
  116. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +3 -3
  117. package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +3 -3
  118. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +5 -4
  119. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +2 -1
  120. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +3 -3
  121. package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +3 -3
  122. package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +3 -3
  123. package/pennyfarthing-dist/scripts/hooks/session-start.sh +3 -3
  124. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +3 -3
  125. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +3 -3
  126. package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +3 -4
  127. package/pennyfarthing-dist/scripts/lib/env.sh +34 -0
  128. package/pennyfarthing-dist/scripts/lib/run-pf.sh +39 -0
  129. package/pennyfarthing-dist/scripts/misc/README.md +1 -1
  130. package/pennyfarthing-dist/scripts/misc/statusline.sh +3 -3
  131. package/pennyfarthing-dist/scripts/sprint/README.md +21 -21
  132. package/pennyfarthing-dist/scripts/workflow/README.md +2 -2
  133. package/pennyfarthing-dist/scripts/workflow/finish-story.sh +2 -16
  134. package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +3 -3
  135. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +3 -3
  136. package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +3 -3
  137. package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +3 -3
  138. package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +3 -3
  139. package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +3 -3
  140. package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +3 -3
  141. package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +3 -3
  142. package/pennyfarthing-dist/skills/pf-bc/examples.md +23 -23
  143. package/pennyfarthing-dist/skills/pf-bc/skill.md +17 -17
  144. package/pennyfarthing-dist/skills/pf-bc/usage.md +8 -8
  145. package/pennyfarthing-dist/skills/pf-jira/SKILL.md +15 -15
  146. package/pennyfarthing-dist/skills/pf-jira/examples.md +48 -48
  147. package/pennyfarthing-dist/skills/pf-jira/usage.md +15 -15
  148. package/pennyfarthing-dist/skills/pf-sprint/examples.md +80 -80
  149. package/pennyfarthing-dist/skills/pf-sprint/skill.md +35 -35
  150. package/pennyfarthing-dist/skills/pf-sprint/usage.md +30 -30
  151. package/pennyfarthing-dist/skills/pf-theme/examples.md +15 -15
  152. package/pennyfarthing-dist/skills/pf-theme/skill.md +6 -6
  153. package/pennyfarthing-dist/skills/pf-theme/usage.md +5 -5
  154. package/pennyfarthing-dist/skills/pf-workflow/examples.md +27 -27
  155. package/pennyfarthing-dist/skills/pf-workflow/skill.md +11 -11
  156. package/pennyfarthing-dist/skills/pf-workflow/usage.md +11 -11
  157. package/pennyfarthing-dist/skills/skill-registry.yaml +19 -19
  158. package/pennyfarthing-dist/templates/settings.local.json.template +11 -11
  159. package/pennyfarthing-dist/workflows/bdd-team.yaml +89 -0
  160. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +1 -1
  161. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +1 -1
  162. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +1 -1
  163. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +1 -1
  164. package/pennyfarthing-dist/workflows/project-setup/steps/step-01-discover.md +47 -0
  165. package/pennyfarthing-dist/workflows/tdd-team.yaml +80 -0
  166. package/pennyfarthing_scripts/__init__.py +1 -1
  167. package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  168. package/pennyfarthing_scripts/__pycache__/bellmode_hook.cpython-314.pyc +0 -0
  169. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  170. package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
  171. package/pennyfarthing_scripts/__pycache__/context.cpython-314.pyc +0 -0
  172. package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
  174. package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
  179. package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
  180. package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
  181. package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
  182. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  183. package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-314.pyc +0 -0
  184. package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
  185. package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
  186. package/pennyfarthing_scripts/bc/__pycache__/split.cpython-314.pyc +0 -0
  187. package/pennyfarthing_scripts/bc/cli.py +2 -2
  188. package/pennyfarthing_scripts/bellmode_hook.py +2 -5
  189. package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
  190. package/pennyfarthing_scripts/bikerack/__pycache__/__main__.cpython-314.pyc +0 -0
  191. package/pennyfarthing_scripts/bikerack/__pycache__/audit_log_panel.cpython-314.pyc +0 -0
  192. package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
  193. package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
  194. package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
  195. package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
  196. package/pennyfarthing_scripts/bikerack/__pycache__/context_meter_footer.cpython-314.pyc +0 -0
  197. package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
  198. package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
  199. package/pennyfarthing_scripts/bikerack/__pycache__/events.cpython-314.pyc +0 -0
  200. package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
  201. package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
  202. package/pennyfarthing_scripts/bikerack/__pycache__/portrait.cpython-314.pyc +0 -0
  203. package/pennyfarthing_scripts/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
  204. package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
  205. package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
  206. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
  207. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
  208. package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
  209. package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
  210. package/pennyfarthing_scripts/bikerack/audit_log_panel.py +48 -6
  211. package/pennyfarthing_scripts/bikerack/launcher.py +6 -6
  212. package/pennyfarthing_scripts/bikerack/progress_panel.py +0 -1
  213. package/pennyfarthing_scripts/bikerack/sprint_panel.py +1 -1
  214. package/pennyfarthing_scripts/bikerack/story_detail_data.py +4 -1
  215. package/pennyfarthing_scripts/bikerack/story_detail_screen.py +2 -1
  216. package/pennyfarthing_scripts/bikerack/tui.py +12 -2
  217. package/pennyfarthing_scripts/bikerack/ws_client.py +2 -2
  218. package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
  219. package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
  220. package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
  221. package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
  222. package/pennyfarthing_scripts/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
  223. package/pennyfarthing_scripts/codemarkers/__pycache__/__main__.cpython-314.pyc +0 -0
  224. package/pennyfarthing_scripts/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
  225. package/pennyfarthing_scripts/codemarkers/__pycache__/cli.cpython-314.pyc +0 -0
  226. package/pennyfarthing_scripts/codemarkers/__pycache__/formatters.cpython-314.pyc +0 -0
  227. package/pennyfarthing_scripts/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
  228. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
  229. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  230. package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
  231. package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
  232. package/pennyfarthing_scripts/common/config.py +29 -2
  233. package/pennyfarthing_scripts/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
  234. package/pennyfarthing_scripts/complexity/__pycache__/__main__.cpython-314.pyc +0 -0
  235. package/pennyfarthing_scripts/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
  236. package/pennyfarthing_scripts/complexity/__pycache__/cli.cpython-314.pyc +0 -0
  237. package/pennyfarthing_scripts/complexity/__pycache__/formatters.cpython-314.pyc +0 -0
  238. package/pennyfarthing_scripts/complexity/__pycache__/models.cpython-314.pyc +0 -0
  239. package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
  240. package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
  241. package/pennyfarthing_scripts/consultation/cli.py +3 -3
  242. package/pennyfarthing_scripts/context.py +3 -3
  243. package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-314.pyc +0 -0
  244. package/pennyfarthing_scripts/deadcode/__pycache__/__main__.cpython-314.pyc +0 -0
  245. package/pennyfarthing_scripts/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
  246. package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
  247. package/pennyfarthing_scripts/deadcode/__pycache__/formatters.cpython-314.pyc +0 -0
  248. package/pennyfarthing_scripts/deadcode/__pycache__/models.cpython-314.pyc +0 -0
  249. package/pennyfarthing_scripts/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
  250. package/pennyfarthing_scripts/dependencies/__pycache__/__main__.cpython-314.pyc +0 -0
  251. package/pennyfarthing_scripts/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
  252. package/pennyfarthing_scripts/dependencies/__pycache__/cli.cpython-314.pyc +0 -0
  253. package/pennyfarthing_scripts/dependencies/__pycache__/formatters.cpython-314.pyc +0 -0
  254. package/pennyfarthing_scripts/dependencies/__pycache__/models.cpython-314.pyc +0 -0
  255. package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-314.pyc +0 -0
  256. package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-314.pyc +0 -0
  257. package/pennyfarthing_scripts/gate/__pycache__/__init__.cpython-314.pyc +0 -0
  258. package/pennyfarthing_scripts/gate/__pycache__/cli.cpython-314.pyc +0 -0
  259. package/pennyfarthing_scripts/gate/__pycache__/validate.cpython-314.pyc +0 -0
  260. package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
  261. package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
  262. package/pennyfarthing_scripts/git/__pycache__/hooks_installer.cpython-314.pyc +0 -0
  263. package/pennyfarthing_scripts/git/__pycache__/repos.cpython-314.pyc +0 -0
  264. package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
  265. package/pennyfarthing_scripts/git/__pycache__/worktree.cpython-314.pyc +0 -0
  266. package/pennyfarthing_scripts/git/hooks_installer.py +2 -3
  267. package/pennyfarthing_scripts/git/status_all.py +1 -1
  268. package/pennyfarthing_scripts/git/worktree.py +2 -2
  269. package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-314.pyc +0 -0
  270. package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
  271. package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
  272. package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
  273. package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
  274. package/pennyfarthing_scripts/handoff/__pycache__/gate_file.cpython-314.pyc +0 -0
  275. package/pennyfarthing_scripts/handoff/__pycache__/gate_runner.cpython-314.pyc +0 -0
  276. package/pennyfarthing_scripts/handoff/__pycache__/marker.cpython-314.pyc +0 -0
  277. package/pennyfarthing_scripts/handoff/__pycache__/phase_check.cpython-314.pyc +0 -0
  278. package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
  279. package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
  280. package/pennyfarthing_scripts/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
  281. package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
  282. package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
  283. package/pennyfarthing_scripts/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
  284. package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-314.pyc +0 -0
  285. package/pennyfarthing_scripts/hooks/__init__.py +8 -3
  286. package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  287. package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
  288. package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-314.pyc +0 -0
  289. package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
  290. package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
  291. package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
  292. package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
  293. package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
  294. package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
  295. package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
  296. package/pennyfarthing_scripts/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
  297. package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
  298. package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
  299. package/pennyfarthing_scripts/hooks/bell_mode.py +0 -1
  300. package/pennyfarthing_scripts/hooks/pre_edit_check.py +0 -1
  301. package/pennyfarthing_scripts/hooks/reflector_check.py +1 -2
  302. package/pennyfarthing_scripts/hooks/schema_validation.py +0 -1
  303. package/pennyfarthing_scripts/hooks/session_start.py +6 -8
  304. package/pennyfarthing_scripts/hooks/statusline.py +10 -1
  305. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
  306. package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
  307. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
  308. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
  309. package/pennyfarthing_scripts/hotspots/__pycache__/formatters.cpython-314.pyc +0 -0
  310. package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
  311. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  312. package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
  313. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  314. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
  315. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  316. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  317. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
  318. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
  319. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
  320. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  321. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
  322. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
  323. package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-314.pyc +0 -0
  324. package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-314.pyc +0 -0
  325. package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
  326. package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
  327. package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
  328. package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
  329. package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
  330. package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
  331. package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
  332. package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
  333. package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
  334. package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  335. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  336. package/pennyfarthing_scripts/prime/__pycache__/heatmap.cpython-314.pyc +0 -0
  337. package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
  338. package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
  339. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  340. package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
  341. package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  342. package/pennyfarthing_scripts/prime/__pycache__/version_sentinel.cpython-314.pyc +0 -0
  343. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  344. package/pennyfarthing_scripts/prime/heatmap.py +3 -15
  345. package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-314.pyc +0 -0
  346. package/pennyfarthing_scripts/session/__pycache__/cli.cpython-314.pyc +0 -0
  347. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  348. package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
  349. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  350. package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  351. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  352. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  353. package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-314.pyc +0 -0
  354. package/pennyfarthing_scripts/sprint/__pycache__/import_epic.cpython-314.pyc +0 -0
  355. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  356. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
  357. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
  358. package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
  359. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  360. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  361. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  362. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  363. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  364. package/pennyfarthing_scripts/sprint/cli.py +121 -0
  365. package/pennyfarthing_scripts/sprint/loader.py +154 -3
  366. package/pennyfarthing_scripts/sprint/story_update.py +7 -0
  367. package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
  368. package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
  369. package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
  370. package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
  371. package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
  372. package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
  373. package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
  374. package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  375. package/pennyfarthing_scripts/tests/__pycache__/test_108_2_remove_handoff_fallback.cpython-314-pytest-9.0.2.pyc +0 -0
  376. package/pennyfarthing_scripts/tests/__pycache__/test_archive_epic.cpython-314-pytest-9.0.2.pyc +0 -0
  377. package/pennyfarthing_scripts/tests/__pycache__/test_bc.cpython-314-pytest-9.0.2.pyc +0 -0
  378. package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
  379. package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
  380. package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
  381. package/pennyfarthing_scripts/tests/__pycache__/test_cli_normalization.cpython-314-pytest-9.0.2.pyc +0 -0
  382. package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
  383. package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
  384. package/pennyfarthing_scripts/tests/__pycache__/test_epic_shard_validation.cpython-314-pytest-9.0.2.pyc +0 -0
  385. package/pennyfarthing_scripts/tests/__pycache__/test_gate_file_resolution.cpython-314-pytest-9.0.2.pyc +0 -0
  386. package/pennyfarthing_scripts/tests/__pycache__/test_gate_runner.cpython-314-pytest-9.0.2.pyc +0 -0
  387. package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
  388. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  389. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_e2e.cpython-314-pytest-9.0.2.pyc +0 -0
  390. package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
  391. package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
  392. package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
  393. package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
  394. package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
  395. package/pennyfarthing_scripts/tests/__pycache__/test_resolve_gate_file_field.cpython-314-pytest-9.0.2.pyc +0 -0
  396. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
  397. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_panel.cpython-314-pytest-9.0.2.pyc +0 -0
  398. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
  399. package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
  400. package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
  401. package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
  402. package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
  403. package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
  404. package/pennyfarthing_scripts/tests/__pycache__/test_topology_loader.cpython-314-pytest-9.0.2.pyc +0 -0
  405. package/pennyfarthing_scripts/tests/__pycache__/test_tui_focus.cpython-314-pytest-9.0.2.pyc +0 -0
  406. package/pennyfarthing_scripts/tests/__pycache__/test_tui_panel_persistence.cpython-314-pytest-9.0.2.pyc +0 -0
  407. package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
  408. package/pennyfarthing_scripts/tests/__pycache__/test_version_sentinel.cpython-314-pytest-9.0.2.pyc +0 -0
  409. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
  410. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_list_team.cpython-314-pytest-9.0.2.pyc +0 -0
  411. package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
  412. package/pennyfarthing_scripts/tests/test_bikerack.py +26 -26
  413. package/pennyfarthing_scripts/tests/test_dialogue_manager.py +0 -1
  414. package/pennyfarthing_scripts/tests/test_workflow_list_team.py +147 -0
  415. package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-314.pyc +0 -0
  416. package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
  417. package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-314.pyc +0 -0
  418. package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
  419. package/pennyfarthing_scripts/validate/adapters/__pycache__/__init__.cpython-314.pyc +0 -0
  420. package/pennyfarthing_scripts/validate/adapters/__pycache__/agent.cpython-314.pyc +0 -0
  421. package/pennyfarthing_scripts/validate/adapters/__pycache__/schema.cpython-314.pyc +0 -0
  422. package/pennyfarthing_scripts/validate/adapters/__pycache__/skill_command.cpython-314.pyc +0 -0
  423. package/pennyfarthing_scripts/validate/adapters/__pycache__/sprint.cpython-314.pyc +0 -0
  424. package/pennyfarthing_scripts/validate/adapters/__pycache__/tandem_awareness.cpython-314.pyc +0 -0
  425. package/pennyfarthing_scripts/validate/adapters/__pycache__/team_mode.cpython-314.pyc +0 -0
  426. package/pennyfarthing_scripts/validate/adapters/__pycache__/workflow.cpython-314.pyc +0 -0
  427. package/pennyfarthing_scripts/validate/adapters/team_mode.py +323 -0
  428. package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
  429. package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
  430. package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
  431. package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
  432. package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
  433. package/pennyfarthing_scripts/workflow/__pycache__/team_lifecycle.cpython-314.pyc +0 -0
  434. package/pennyfarthing_scripts/workflow/cli.py +15 -14
  435. package/pennyfarthing_scripts/workflow/state.py +0 -1
  436. package/pennyfarthing_scripts/workflow/team_lifecycle.py +3 -4
  437. package/packages/core/dist/cli/cyclist-migration.test.d.ts +0 -16
  438. package/packages/core/dist/cli/cyclist-migration.test.d.ts.map +0 -1
  439. package/packages/core/dist/cli/cyclist-migration.test.js +0 -229
  440. package/packages/core/dist/cli/cyclist-migration.test.js.map +0 -1
  441. package/packages/core/dist/scripts/benchmark-integration.d.ts +0 -182
  442. package/packages/core/dist/scripts/benchmark-integration.d.ts.map +0 -1
  443. package/packages/core/dist/scripts/benchmark-integration.js +0 -691
  444. package/packages/core/dist/scripts/benchmark-integration.js.map +0 -1
  445. package/packages/core/dist/scripts/job-fair-aggregator.d.ts +0 -150
  446. package/packages/core/dist/scripts/job-fair-aggregator.d.ts.map +0 -1
  447. package/packages/core/dist/scripts/job-fair-aggregator.js +0 -547
  448. package/packages/core/dist/scripts/job-fair-aggregator.js.map +0 -1
  449. package/packages/core/dist/scripts/theme-detail.test.d.ts.map +0 -1
  450. package/packages/core/dist/scripts/theme-detail.test.js.map +0 -1
  451. package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
  452. package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  453. package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
  454. package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
  455. package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
  456. package/pennyfarthing_scripts/consultation/__pycache__/dialogue_manager.cpython-314.pyc +0 -0
  457. package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
  458. package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
  459. package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
  460. package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
  461. package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
  462. package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
  463. package/pennyfarthing_scripts/tests/__pycache__/test_108_1_gate_migration.cpython-314-pytest-9.0.2.pyc +0 -0
  464. package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_evaluation.cpython-314-pytest-9.0.2.pyc +0 -0
  465. package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_gate.cpython-314-pytest-9.0.2.pyc +0 -0
  466. package/pennyfarthing_scripts/tests/__pycache__/test_dialogue_manager.cpython-314-pytest-9.0.2.pyc +0 -0
  467. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
@@ -1,15 +1,23 @@
1
1
  """
2
2
  Sprint YAML parsing utilities for Pennyfarthing scripts.
3
3
 
4
- Provides access to sprint/current-sprint.yaml data.
5
- Supports sharded per-epic format (epic-{ref}.yaml shard files).
4
+ Provides access to sprint data with support for:
5
+ - Default sprint: sprint/current-sprint.yaml
6
+ - Multi-sprint registry: sprint/sprints.yaml with per-user preference
7
+ stored in .pennyfarthing/config.local.yaml
8
+ - Sharded per-epic format: epic-{ref}.yaml shard files
6
9
  """
7
10
 
8
11
  import warnings
9
12
  from pathlib import Path
10
13
  from typing import Any
11
14
 
12
- from pennyfarthing_scripts.common.config import get_project_root, load_yaml_config
15
+ from pennyfarthing_scripts.common.config import (
16
+ get_project_root,
17
+ load_pennyfarthing_config,
18
+ load_yaml_config,
19
+ save_pennyfarthing_config_key,
20
+ )
13
21
 
14
22
 
15
23
  def _merge_epic_shards(data: dict[str, Any], sprint_dir: Path) -> dict[str, Any]:
@@ -101,6 +109,12 @@ def _merge_epic_shards(data: dict[str, Any], sprint_dir: Path) -> dict[str, Any]
101
109
  def load_sprint(project_root: Path | None = None) -> dict[str, Any] | None:
102
110
  """Load sprint data from project root.
103
111
 
112
+ Resolution order:
113
+ 1. Check .pennyfarthing/config.local.yaml for sprint.active preference
114
+ 2. If set, look up the sprint in sprint/sprints.yaml registry
115
+ 3. Load the referenced sprint file (resolved relative to sprint/)
116
+ 4. If no preference or no registry, fall back to sprint/current-sprint.yaml
117
+
104
118
  Supports both monolithic and sharded epic formats. When epics are
105
119
  string references, the corresponding epic-{ref}.yaml files are
106
120
  loaded and merged transparently.
@@ -113,6 +127,30 @@ def load_sprint(project_root: Path | None = None) -> dict[str, Any] | None:
113
127
  """
114
128
  root = project_root or get_project_root()
115
129
  sprint_dir = root / "sprint"
130
+
131
+ # Check for per-user sprint preference
132
+ active_name = get_active_sprint_name(root)
133
+ if active_name:
134
+ registry = load_sprint_registry(root)
135
+ if registry:
136
+ sprints = registry.get("sprints", {})
137
+ sprint_entry = sprints.get(active_name)
138
+ if sprint_entry and sprint_entry.get("file"):
139
+ sprint_path = (sprint_dir / sprint_entry["file"]).resolve()
140
+ if sprint_path.exists():
141
+ data = load_yaml_config(sprint_path)
142
+ if data is not None:
143
+ # Inject registry metadata for downstream consumers
144
+ data["_registry"] = {
145
+ "name": active_name,
146
+ "type": sprint_entry.get("type", "project"),
147
+ "context_root": sprint_entry.get("context_root"),
148
+ "session_root": sprint_entry.get("session_root"),
149
+ "docs": sprint_entry.get("docs", {}),
150
+ }
151
+ return _merge_epic_shards(data, sprint_path.parent)
152
+
153
+ # Default: load sprint/current-sprint.yaml
116
154
  sprint_path = sprint_dir / "current-sprint.yaml"
117
155
  data = load_yaml_config(sprint_path)
118
156
  if data is None:
@@ -121,6 +159,119 @@ def load_sprint(project_root: Path | None = None) -> dict[str, Any] | None:
121
159
  return _merge_epic_shards(data, sprint_dir)
122
160
 
123
161
 
162
+ def load_sprint_registry(project_root: Path | None = None) -> dict[str, Any] | None:
163
+ """Load sprint registry from sprint/sprints.yaml.
164
+
165
+ The sprint registry indexes multiple parallel sprints (e.g., a main
166
+ project sprint and research spike sprints). Each entry maps a sprint
167
+ name to its YAML file path, type, and metadata.
168
+
169
+ Args:
170
+ project_root: Project root path (defaults to auto-detect)
171
+
172
+ Returns:
173
+ Registry data as dict, or None if no registry exists
174
+ """
175
+ root = project_root or get_project_root()
176
+ registry_path = root / "sprint" / "sprints.yaml"
177
+ return load_yaml_config(registry_path)
178
+
179
+
180
+ def get_active_sprint_name(project_root: Path | None = None) -> str | None:
181
+ """Get the name of the currently active sprint.
182
+
183
+ Reads the per-user preference from .pennyfarthing/config.local.yaml
184
+ (sprint.active key). Returns None if no preference is set, meaning
185
+ the default sprint/current-sprint.yaml should be used.
186
+
187
+ Args:
188
+ project_root: Project root path (defaults to auto-detect)
189
+
190
+ Returns:
191
+ Active sprint name, or None if using the default sprint
192
+ """
193
+ root = project_root or get_project_root()
194
+ config = load_pennyfarthing_config(root)
195
+ sprint_config = config.get("sprint", {})
196
+ if isinstance(sprint_config, dict):
197
+ return sprint_config.get("active")
198
+ return None
199
+
200
+
201
+ def switch_sprint(name: str, project_root: Path | None = None) -> dict[str, Any]:
202
+ """Switch the active sprint by updating the per-user preference.
203
+
204
+ Validates the sprint name against sprint/sprints.yaml, then writes
205
+ the selection to .pennyfarthing/config.local.yaml (gitignored,
206
+ per-user). Does not modify any shared repo files.
207
+
208
+ Use name "default" to clear the preference and revert to the
209
+ project's sprint/current-sprint.yaml.
210
+
211
+ Args:
212
+ name: Sprint name from the registry (e.g., "main", "ocsf-rs1")
213
+ or "default" to clear the preference
214
+ project_root: Project root path (defaults to auto-detect)
215
+
216
+ Returns:
217
+ Dict with 'success', 'message', and optional 'error' or 'sprint'
218
+ """
219
+ root = project_root or get_project_root()
220
+
221
+ # "default" clears the preference
222
+ if name == "default":
223
+ config = load_pennyfarthing_config(root)
224
+ sprint_config = config.get("sprint", {})
225
+ if isinstance(sprint_config, dict) and "active" in sprint_config:
226
+ del sprint_config["active"]
227
+ if not sprint_config:
228
+ save_pennyfarthing_config_key("sprint", {}, root)
229
+ else:
230
+ save_pennyfarthing_config_key("sprint", sprint_config, root)
231
+ return {
232
+ "success": True,
233
+ "message": "Cleared sprint preference — using default sprint/current-sprint.yaml",
234
+ }
235
+
236
+ registry = load_sprint_registry(root)
237
+
238
+ if registry is None:
239
+ return {"success": False, "error": "No sprint registry found (sprint/sprints.yaml)"}
240
+
241
+ sprints = registry.get("sprints", {})
242
+ if name not in sprints:
243
+ available = ", ".join(sprints.keys())
244
+ return {"success": False, "error": f"Unknown sprint: {name}. Available: {available}"}
245
+
246
+ sprint_entry = sprints[name]
247
+ sprint_file = sprint_entry.get("file")
248
+ if not sprint_file:
249
+ return {"success": False, "error": f"Sprint '{name}' has no file configured"}
250
+
251
+ # Verify the target sprint file exists
252
+ sprint_dir = root / "sprint"
253
+ target_path = (sprint_dir / sprint_file).resolve()
254
+ if not target_path.exists():
255
+ return {
256
+ "success": False,
257
+ "error": f"Sprint file not found: {sprint_file} (resolved to {target_path})",
258
+ }
259
+
260
+ # Write preference to config.local.yaml (per-user, gitignored)
261
+ config = load_pennyfarthing_config(root)
262
+ sprint_config = config.get("sprint", {})
263
+ if not isinstance(sprint_config, dict):
264
+ sprint_config = {}
265
+ sprint_config["active"] = name
266
+ save_pennyfarthing_config_key("sprint", sprint_config, root)
267
+
268
+ return {
269
+ "success": True,
270
+ "message": f"Switched to sprint: {name}",
271
+ "sprint": sprint_entry,
272
+ }
273
+
274
+
124
275
  def find_epic(sprint_data: dict[str, Any], epic_num: str) -> dict[str, Any] | None:
125
276
  """Find epic in sprint data (handles various ID formats).
126
277
 
@@ -30,6 +30,7 @@ def update_story(
30
30
  completed_date: str | None = None,
31
31
  started_date: str | None = None,
32
32
  workflow: str | None = None,
33
+ description: str | None = None,
33
34
  review_findings: str | None = None,
34
35
  review_verdict: str | None = None,
35
36
  dry_run: bool = False,
@@ -46,6 +47,7 @@ def update_story(
46
47
  completed_date: Completed date (ISO format)
47
48
  started_date: Started date (ISO format)
48
49
  workflow: Workflow type (tdd, trivial, bdd, agent-docs)
50
+ description: Story description text
49
51
  review_findings: Reviewer findings text
50
52
  review_verdict: Review verdict (approved, rejected, pending)
51
53
  dry_run: If True, report changes without writing
@@ -101,6 +103,8 @@ def update_story(
101
103
  story["started"] = started_date
102
104
  if workflow is not None:
103
105
  story["workflow"] = workflow
106
+ if description is not None:
107
+ story["description"] = description
104
108
  if review_findings is not None:
105
109
  story["review_findings"] = review_findings
106
110
  if review_verdict is not None:
@@ -166,6 +170,7 @@ def update_story(
166
170
  @click.option("--priority", default=None)
167
171
  @click.option("--started", "started_date", default=None)
168
172
  @click.option("--workflow", default=None)
173
+ @click.option("--description", default=None, help="Story description text")
169
174
  @click.option("--review-findings", default=None, help="Reviewer findings text")
170
175
  @click.option("--review-verdict", type=click.Choice(["approved", "rejected", "pending"]), default=None)
171
176
  @click.option("--dry-run", is_flag=True)
@@ -179,6 +184,7 @@ def story_update_command(
179
184
  priority: str | None,
180
185
  started_date: str | None,
181
186
  workflow: str | None,
187
+ description: str | None,
182
188
  review_findings: str | None,
183
189
  review_verdict: str | None,
184
190
  dry_run: bool,
@@ -201,6 +207,7 @@ def story_update_command(
201
207
  completed_date=completed_date,
202
208
  started_date=started_date,
203
209
  workflow=workflow,
210
+ description=description,
204
211
  review_findings=review_findings,
205
212
  review_verdict=review_verdict,
206
213
  dry_run=dry_run,
@@ -5,14 +5,14 @@ Epic: 101 — BikeRack Mode (ADR-0024)
5
5
 
6
6
  Acceptance Criteria:
7
7
  - [AC1] `pf bikerack start` starts WheelHub background with IS_BIKERACK=1
8
- - [AC2] Polls for .wheelhub-port file (100ms interval, 5s timeout)
8
+ - [AC2] Polls for .bikerack-port file (100ms interval, 5s timeout)
9
9
  - [AC3] Sets exactly 5 OTEL env vars from discovered port (Rule 5)
10
10
  - [AC4] Uses exec (not spawn) for Claude CLI (CE-4)
11
11
  - [AC5] trap EXIT registered before exec to kill WheelHub PID (Rule 8)
12
12
  - [AC6] Writes .wheelhub-pid after spawning WheelHub
13
13
  - [AC7] `pf bikerack stop` reads PID, sends SIGTERM, deletes files
14
14
  - [AC8] `pf bikerack status` shows running state (PID, port, uptime)
15
- - [AC9] Error if already running (.wheelhub-port exists with live PID)
15
+ - [AC9] Error if already running (.bikerack-port exists with live PID)
16
16
  - [AC10] Exit code 1 if WheelHub fails to start, 2 if already running
17
17
  - [AC11] Prints dashboard URL on startup
18
18
  - [AC12] `just bikerack` works as alias
@@ -101,7 +101,7 @@ class TestStartWheelHub:
101
101
 
102
102
 
103
103
  # ---------------------------------------------------------------------------
104
- # AC2: Polls for .wheelhub-port file (100ms interval, 5s timeout)
104
+ # AC2: Polls for .bikerack-port file (100ms interval, 5s timeout)
105
105
  # ---------------------------------------------------------------------------
106
106
 
107
107
 
@@ -110,7 +110,7 @@ class TestPortFilePolling:
110
110
 
111
111
  def test_returns_port_when_file_exists(self, tmp_path: Path) -> None:
112
112
  """poll_for_port_file should return port number from file."""
113
- port_file = tmp_path / ".wheelhub-port"
113
+ port_file = tmp_path / ".bikerack-port"
114
114
  port_file.write_text("2898")
115
115
 
116
116
  result = poll_for_port_file(tmp_path)
@@ -125,7 +125,7 @@ class TestPortFilePolling:
125
125
 
126
126
  def test_waits_for_file_to_appear(self, tmp_path: Path) -> None:
127
127
  """poll_for_port_file should poll until file appears."""
128
- port_file = tmp_path / ".wheelhub-port"
128
+ port_file = tmp_path / ".bikerack-port"
129
129
 
130
130
  # Simulate file appearing after short delay
131
131
  call_count = [0]
@@ -160,7 +160,7 @@ class TestPortFilePolling:
160
160
 
161
161
  def test_reads_integer_port(self, tmp_path: Path) -> None:
162
162
  """poll_for_port_file should parse port as integer."""
163
- port_file = tmp_path / ".wheelhub-port"
163
+ port_file = tmp_path / ".bikerack-port"
164
164
  port_file.write_text("3000\n") # Trailing newline should be handled
165
165
 
166
166
  result = poll_for_port_file(tmp_path)
@@ -340,8 +340,8 @@ class TestCleanupRegistration:
340
340
  assert kill_args[1] == signal.SIGTERM
341
341
 
342
342
  def test_cleanup_removes_port_file(self, tmp_path: Path) -> None:
343
- """Registered cleanup should delete .wheelhub-port file."""
344
- port_file = tmp_path / ".wheelhub-port"
343
+ """Registered cleanup should delete .bikerack-port file."""
344
+ port_file = tmp_path / ".bikerack-port"
345
345
  port_file.write_text("2898")
346
346
 
347
347
  cleanup_func = None
@@ -363,7 +363,7 @@ class TestCleanupRegistration:
363
363
  except (ProcessLookupError, OSError):
364
364
  pass
365
365
 
366
- assert not port_file.exists(), ".wheelhub-port should be deleted by cleanup"
366
+ assert not port_file.exists(), ".bikerack-port should be deleted by cleanup"
367
367
 
368
368
  def test_cleanup_removes_pid_file(self, tmp_path: Path) -> None:
369
369
  """Registered cleanup should delete .wheelhub-pid file."""
@@ -443,7 +443,7 @@ class TestStopBikeRack:
443
443
  def test_sends_sigterm_to_pid(self, tmp_path: Path) -> None:
444
444
  """stop_bikerack should send SIGTERM to the WheelHub PID."""
445
445
  # Setup: create port and pid files
446
- (tmp_path / ".wheelhub-port").write_text("2898")
446
+ (tmp_path / ".bikerack-port").write_text("2898")
447
447
  (tmp_path / ".wheelhub-pid").write_text("12345")
448
448
 
449
449
  with patch("pennyfarthing_scripts.bikerack.launcher.os.kill") as mock_kill:
@@ -453,8 +453,8 @@ class TestStopBikeRack:
453
453
  mock_kill.assert_called_with(12345, signal.SIGTERM)
454
454
 
455
455
  def test_deletes_port_file(self, tmp_path: Path) -> None:
456
- """stop_bikerack should delete .wheelhub-port."""
457
- port_file = tmp_path / ".wheelhub-port"
456
+ """stop_bikerack should delete .bikerack-port."""
457
+ port_file = tmp_path / ".bikerack-port"
458
458
  port_file.write_text("2898")
459
459
  (tmp_path / ".wheelhub-pid").write_text("12345")
460
460
 
@@ -466,7 +466,7 @@ class TestStopBikeRack:
466
466
 
467
467
  def test_deletes_pid_file(self, tmp_path: Path) -> None:
468
468
  """stop_bikerack should delete .wheelhub-pid."""
469
- (tmp_path / ".wheelhub-port").write_text("2898")
469
+ (tmp_path / ".bikerack-port").write_text("2898")
470
470
  pid_file = tmp_path / ".wheelhub-pid"
471
471
  pid_file.write_text("12345")
472
472
 
@@ -478,7 +478,7 @@ class TestStopBikeRack:
478
478
 
479
479
  def test_returns_success_dict(self, tmp_path: Path) -> None:
480
480
  """stop_bikerack should return {success: True, pid: N, message: str}."""
481
- (tmp_path / ".wheelhub-port").write_text("2898")
481
+ (tmp_path / ".bikerack-port").write_text("2898")
482
482
  (tmp_path / ".wheelhub-pid").write_text("12345")
483
483
 
484
484
  with patch("pennyfarthing_scripts.bikerack.launcher.os.kill"):
@@ -506,7 +506,7 @@ class TestStatus:
506
506
 
507
507
  def test_returns_running_state(self, tmp_path: Path) -> None:
508
508
  """get_status should detect running BikeRack."""
509
- (tmp_path / ".wheelhub-port").write_text("2898")
509
+ (tmp_path / ".bikerack-port").write_text("2898")
510
510
  (tmp_path / ".wheelhub-pid").write_text("12345")
511
511
 
512
512
  with patch("pennyfarthing_scripts.bikerack.launcher.is_process_alive", return_value=True):
@@ -524,7 +524,7 @@ class TestStatus:
524
524
 
525
525
  def test_includes_dashboard_url(self, tmp_path: Path) -> None:
526
526
  """get_status should include dashboard URL when running."""
527
- (tmp_path / ".wheelhub-port").write_text("2898")
527
+ (tmp_path / ".bikerack-port").write_text("2898")
528
528
  (tmp_path / ".wheelhub-pid").write_text("12345")
529
529
 
530
530
  with patch("pennyfarthing_scripts.bikerack.launcher.is_process_alive", return_value=True):
@@ -534,7 +534,7 @@ class TestStatus:
534
534
 
535
535
  def test_detects_stale_pid(self, tmp_path: Path) -> None:
536
536
  """get_status should detect stale PID (file exists, process dead)."""
537
- (tmp_path / ".wheelhub-port").write_text("2898")
537
+ (tmp_path / ".bikerack-port").write_text("2898")
538
538
  (tmp_path / ".wheelhub-pid").write_text("99999")
539
539
 
540
540
  with patch("pennyfarthing_scripts.bikerack.launcher.is_process_alive", return_value=False):
@@ -544,7 +544,7 @@ class TestStatus:
544
544
 
545
545
 
546
546
  # ---------------------------------------------------------------------------
547
- # AC9: Error if already running (.wheelhub-port exists with live PID)
547
+ # AC9: Error if already running (.bikerack-port exists with live PID)
548
548
  # ---------------------------------------------------------------------------
549
549
 
550
550
 
@@ -553,7 +553,7 @@ class TestAlreadyRunning:
553
553
 
554
554
  def test_detects_running_instance(self, tmp_path: Path) -> None:
555
555
  """is_already_running should return True when port file + live PID."""
556
- (tmp_path / ".wheelhub-port").write_text("2898")
556
+ (tmp_path / ".bikerack-port").write_text("2898")
557
557
  (tmp_path / ".wheelhub-pid").write_text("12345")
558
558
 
559
559
  with patch("pennyfarthing_scripts.bikerack.launcher.is_process_alive", return_value=True):
@@ -573,7 +573,7 @@ class TestAlreadyRunning:
573
573
 
574
574
  def test_not_running_when_stale_pid(self, tmp_path: Path) -> None:
575
575
  """is_already_running should return False when PID is dead (stale)."""
576
- (tmp_path / ".wheelhub-port").write_text("2898")
576
+ (tmp_path / ".bikerack-port").write_text("2898")
577
577
  (tmp_path / ".wheelhub-pid").write_text("99999")
578
578
 
579
579
  with patch("pennyfarthing_scripts.bikerack.launcher.is_process_alive", return_value=False):
@@ -583,7 +583,7 @@ class TestAlreadyRunning:
583
583
 
584
584
  def test_cleans_stale_files(self, tmp_path: Path) -> None:
585
585
  """is_already_running should clean up stale files when PID is dead."""
586
- port_file = tmp_path / ".wheelhub-port"
586
+ port_file = tmp_path / ".bikerack-port"
587
587
  pid_file = tmp_path / ".wheelhub-pid"
588
588
  port_file.write_text("2898")
589
589
  pid_file.write_text("99999")
@@ -605,7 +605,7 @@ class TestExitCodes:
605
605
 
606
606
  def test_exit_code_2_when_already_running(self, tmp_path: Path) -> None:
607
607
  """Start should raise SystemExit(2) when already running."""
608
- (tmp_path / ".wheelhub-port").write_text("2898")
608
+ (tmp_path / ".bikerack-port").write_text("2898")
609
609
  (tmp_path / ".wheelhub-pid").write_text("12345")
610
610
 
611
611
  with patch("pennyfarthing_scripts.bikerack.launcher.is_process_alive", return_value=True):
@@ -736,8 +736,8 @@ class TestCleanupFiles:
736
736
  """Utility: cleanup_files removes port and PID files."""
737
737
 
738
738
  def test_removes_port_file(self, tmp_path: Path) -> None:
739
- """cleanup_files should remove .wheelhub-port."""
740
- port_file = tmp_path / ".wheelhub-port"
739
+ """cleanup_files should remove .bikerack-port."""
740
+ port_file = tmp_path / ".bikerack-port"
741
741
  port_file.write_text("2898")
742
742
 
743
743
  cleanup_files(tmp_path)
@@ -764,7 +764,7 @@ class TestReadPortFile:
764
764
 
765
765
  def test_reads_port(self, tmp_path: Path) -> None:
766
766
  """read_port_file should return port as integer."""
767
- (tmp_path / ".wheelhub-port").write_text("2898")
767
+ (tmp_path / ".bikerack-port").write_text("2898")
768
768
 
769
769
  result = read_port_file(tmp_path)
770
770
 
@@ -778,7 +778,7 @@ class TestReadPortFile:
778
778
 
779
779
  def test_handles_trailing_whitespace(self, tmp_path: Path) -> None:
780
780
  """read_port_file should handle trailing newlines/spaces."""
781
- (tmp_path / ".wheelhub-port").write_text("2898\n")
781
+ (tmp_path / ".bikerack-port").write_text("2898\n")
782
782
 
783
783
  result = read_port_file(tmp_path)
784
784
 
@@ -19,7 +19,6 @@ from __future__ import annotations
19
19
 
20
20
  from pathlib import Path
21
21
 
22
- import pytest
23
22
  from click.testing import CliRunner
24
23
 
25
24
  from pennyfarthing_scripts.consultation.dialogue_manager import (