@pennyfarthing/core 11.2.0 → 11.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (403) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -1
  3. package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
  4. package/packages/core/dist/cli/commands/doctor.js +381 -66
  5. package/packages/core/dist/cli/commands/doctor.js.map +1 -1
  6. package/packages/core/dist/cli/commands/init.js +4 -4
  7. package/packages/core/dist/cli/commands/init.js.map +1 -1
  8. package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
  9. package/packages/core/dist/cli/commands/update.js +4 -5
  10. package/packages/core/dist/cli/commands/update.js.map +1 -1
  11. package/packages/core/dist/cli/utils/constants.d.ts +3 -8
  12. package/packages/core/dist/cli/utils/constants.d.ts.map +1 -1
  13. package/packages/core/dist/cli/utils/constants.js +3 -4
  14. package/packages/core/dist/cli/utils/constants.js.map +1 -1
  15. package/packages/core/dist/cli/utils/settings.d.ts +11 -0
  16. package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
  17. package/packages/core/dist/cli/utils/settings.js +65 -29
  18. package/packages/core/dist/cli/utils/settings.js.map +1 -1
  19. package/packages/core/dist/cli/utils/symlinks.js +16 -16
  20. package/packages/core/dist/cli/utils/symlinks.js.map +1 -1
  21. package/packages/core/dist/consultation/tandem-metrics.d.ts +91 -0
  22. package/packages/core/dist/consultation/tandem-metrics.d.ts.map +1 -0
  23. package/packages/core/dist/consultation/tandem-metrics.js +131 -0
  24. package/packages/core/dist/consultation/tandem-metrics.js.map +1 -0
  25. package/packages/core/dist/consultation/tandem-metrics.test.d.ts +18 -0
  26. package/packages/core/dist/consultation/tandem-metrics.test.d.ts.map +1 -0
  27. package/packages/core/dist/consultation/tandem-metrics.test.js +457 -0
  28. package/packages/core/dist/consultation/tandem-metrics.test.js.map +1 -0
  29. package/packages/core/dist/public/js/react/react.js +14 -14
  30. package/packages/core/dist/scripts/benchmark-integration.d.ts +182 -0
  31. package/packages/core/dist/scripts/benchmark-integration.d.ts.map +1 -0
  32. package/packages/core/dist/scripts/benchmark-integration.js +691 -0
  33. package/packages/core/dist/scripts/benchmark-integration.js.map +1 -0
  34. package/packages/core/dist/scripts/job-fair-aggregator.d.ts +150 -0
  35. package/packages/core/dist/scripts/job-fair-aggregator.d.ts.map +1 -0
  36. package/packages/core/dist/scripts/job-fair-aggregator.js +547 -0
  37. package/packages/core/dist/scripts/job-fair-aggregator.js.map +1 -0
  38. package/packages/core/dist/server/api/agent-load.js +1 -1
  39. package/packages/core/dist/server/api/agent-load.js.map +1 -1
  40. package/packages/core/dist/server/server.d.ts +0 -3
  41. package/packages/core/dist/server/server.d.ts.map +1 -1
  42. package/packages/core/dist/server/server.js +3 -37
  43. package/packages/core/dist/server/server.js.map +1 -1
  44. package/packages/core/dist/server/server.test.d.ts +1 -1
  45. package/packages/core/dist/server/server.test.js +12 -23
  46. package/packages/core/dist/server/server.test.js.map +1 -1
  47. package/packages/core/dist/shared/capabilities.d.ts +88 -0
  48. package/packages/core/dist/shared/capabilities.d.ts.map +1 -0
  49. package/packages/core/dist/shared/capabilities.js +133 -0
  50. package/packages/core/dist/shared/capabilities.js.map +1 -0
  51. package/packages/core/dist/shared/capabilities.test.d.ts +2 -0
  52. package/packages/core/dist/shared/capabilities.test.d.ts.map +1 -0
  53. package/packages/core/dist/shared/capabilities.test.js +217 -0
  54. package/packages/core/dist/shared/capabilities.test.js.map +1 -0
  55. package/packages/core/dist/shared/spawn-prompt.d.ts +47 -0
  56. package/packages/core/dist/shared/spawn-prompt.d.ts.map +1 -0
  57. package/packages/core/dist/shared/spawn-prompt.js +82 -0
  58. package/packages/core/dist/shared/spawn-prompt.js.map +1 -0
  59. package/packages/core/dist/shared/spawn-prompt.test.d.ts +2 -0
  60. package/packages/core/dist/shared/spawn-prompt.test.d.ts.map +1 -0
  61. package/packages/core/dist/shared/spawn-prompt.test.js +251 -0
  62. package/packages/core/dist/shared/spawn-prompt.test.js.map +1 -0
  63. package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts +18 -0
  64. package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts.map +1 -0
  65. package/packages/core/dist/workflow/tandem-workflow-templates.test.js +434 -0
  66. package/packages/core/dist/workflow/tandem-workflow-templates.test.js.map +1 -0
  67. package/packages/core/dist/workflow/workflow-schema.d.ts +32 -0
  68. package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -1
  69. package/packages/core/dist/workflow/workflow-schema.js +120 -0
  70. package/packages/core/dist/workflow/workflow-schema.js.map +1 -1
  71. package/packages/core/dist/workflow/workflow-schema.test.d.ts.map +1 -1
  72. package/packages/core/dist/workflow/workflow-schema.test.js +570 -1
  73. package/packages/core/dist/workflow/workflow-schema.test.js.map +1 -1
  74. package/pennyfarthing-dist/agents/dev.md +6 -10
  75. package/pennyfarthing-dist/agents/reviewer.md +8 -2
  76. package/pennyfarthing-dist/agents/sm-finish.md +18 -1
  77. package/pennyfarthing-dist/commands/pf-git.md +4 -2
  78. package/pennyfarthing-dist/gates/approval.md +63 -0
  79. package/pennyfarthing-dist/gates/confidence-sm.md +71 -0
  80. package/pennyfarthing-dist/gates/context-ok.md +56 -0
  81. package/pennyfarthing-dist/gates/evaluations/confidence-sm.md +54 -0
  82. package/pennyfarthing-dist/gates/quality-pass.md +67 -0
  83. package/pennyfarthing-dist/gates/tests-fail.md +84 -0
  84. package/pennyfarthing-dist/gates/tests-pass.md +79 -0
  85. package/pennyfarthing-dist/guides/agent-behavior.md +23 -19
  86. package/pennyfarthing-dist/guides/bell-mode.md +1 -1
  87. package/pennyfarthing-dist/guides/hooks.md +28 -28
  88. package/pennyfarthing-dist/guides/reflector.md +1 -1
  89. package/pennyfarthing-dist/guides/tandem-protocol.md +3 -3
  90. package/pennyfarthing-dist/scripts/core/check-context.sh +2 -0
  91. package/pennyfarthing-dist/scripts/core/phase-check-start.sh +5 -87
  92. package/pennyfarthing-dist/scripts/hooks/README.md +5 -5
  93. package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
  94. package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +4 -183
  95. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +4 -95
  96. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +4 -65
  97. package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +3 -31
  98. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +27 -33
  99. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +4 -71
  100. package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +3 -19
  101. package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +4 -30
  102. package/pennyfarthing-dist/scripts/hooks/session-start.sh +3 -32
  103. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +4 -65
  104. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +4 -78
  105. package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +4 -93
  106. package/pennyfarthing-dist/scripts/misc/README.md +1 -1
  107. package/pennyfarthing-dist/scripts/misc/statusline.sh +4 -301
  108. package/pennyfarthing-dist/templates/settings.local.json.template +19 -10
  109. package/pennyfarthing-dist/workflows/tdd.yaml +11 -2
  110. package/pennyfarthing_scripts/CLAUDE.md +19 -10
  111. package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  112. package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  113. package/pennyfarthing_scripts/__pycache__/bellmode_hook.cpython-314.pyc +0 -0
  114. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  115. package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
  116. package/pennyfarthing_scripts/__pycache__/context.cpython-314.pyc +0 -0
  117. package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
  118. package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
  119. package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
  120. package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
  121. package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
  122. package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
  123. package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
  124. package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
  125. package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
  126. package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
  127. package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
  128. package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
  129. package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
  130. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  131. package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-314.pyc +0 -0
  132. package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
  133. package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
  134. package/pennyfarthing_scripts/bellmode_hook.py +12 -296
  135. package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
  136. package/pennyfarthing_scripts/bikerack/__pycache__/__main__.cpython-314.pyc +0 -0
  137. package/pennyfarthing_scripts/bikerack/__pycache__/audit_log_panel.cpython-314.pyc +0 -0
  138. package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
  139. package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
  140. package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
  141. package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
  142. package/pennyfarthing_scripts/bikerack/__pycache__/context_meter_footer.cpython-314.pyc +0 -0
  143. package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
  144. package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
  145. package/pennyfarthing_scripts/bikerack/__pycache__/events.cpython-314.pyc +0 -0
  146. package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
  147. package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
  148. package/pennyfarthing_scripts/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
  149. package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
  150. package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
  151. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
  152. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
  153. package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
  154. package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
  155. package/pennyfarthing_scripts/bikerack/audit_log_panel.py +119 -0
  156. package/pennyfarthing_scripts/bikerack/base_panel.py +27 -4
  157. package/pennyfarthing_scripts/bikerack/changed_panel.py +96 -4
  158. package/pennyfarthing_scripts/bikerack/context_meter_footer.py +88 -0
  159. package/pennyfarthing_scripts/bikerack/debug_panel.py +1 -1
  160. package/pennyfarthing_scripts/bikerack/diffs_panel.py +30 -0
  161. package/pennyfarthing_scripts/bikerack/events.py +28 -0
  162. package/pennyfarthing_scripts/bikerack/portrait_resolver.py +139 -0
  163. package/pennyfarthing_scripts/bikerack/sprint_panel.py +373 -142
  164. package/pennyfarthing_scripts/bikerack/story_detail_data.py +244 -0
  165. package/pennyfarthing_scripts/bikerack/story_detail_screen.py +176 -0
  166. package/pennyfarthing_scripts/bikerack/tui.py +293 -61
  167. package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
  168. package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
  169. package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
  170. package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
  171. package/pennyfarthing_scripts/cli.py +5 -0
  172. package/pennyfarthing_scripts/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/codemarkers/__pycache__/__main__.cpython-314.pyc +0 -0
  174. package/pennyfarthing_scripts/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/codemarkers/__pycache__/cli.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/codemarkers/__pycache__/formatters.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
  179. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  180. package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
  181. package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
  182. package/pennyfarthing_scripts/common/pr_config.py +38 -0
  183. package/pennyfarthing_scripts/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
  184. package/pennyfarthing_scripts/complexity/__pycache__/__main__.cpython-314.pyc +0 -0
  185. package/pennyfarthing_scripts/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
  186. package/pennyfarthing_scripts/complexity/__pycache__/cli.cpython-314.pyc +0 -0
  187. package/pennyfarthing_scripts/complexity/__pycache__/formatters.cpython-314.pyc +0 -0
  188. package/pennyfarthing_scripts/complexity/__pycache__/models.cpython-314.pyc +0 -0
  189. package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
  190. package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
  191. package/pennyfarthing_scripts/consultation/__pycache__/dialogue_manager.cpython-314.pyc +0 -0
  192. package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-314.pyc +0 -0
  193. package/pennyfarthing_scripts/deadcode/__pycache__/__main__.cpython-314.pyc +0 -0
  194. package/pennyfarthing_scripts/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
  195. package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
  196. package/pennyfarthing_scripts/deadcode/__pycache__/formatters.cpython-314.pyc +0 -0
  197. package/pennyfarthing_scripts/deadcode/__pycache__/models.cpython-314.pyc +0 -0
  198. package/pennyfarthing_scripts/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
  199. package/pennyfarthing_scripts/dependencies/__pycache__/__main__.cpython-314.pyc +0 -0
  200. package/pennyfarthing_scripts/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
  201. package/pennyfarthing_scripts/dependencies/__pycache__/cli.cpython-314.pyc +0 -0
  202. package/pennyfarthing_scripts/dependencies/__pycache__/formatters.cpython-314.pyc +0 -0
  203. package/pennyfarthing_scripts/dependencies/__pycache__/models.cpython-314.pyc +0 -0
  204. package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-314.pyc +0 -0
  205. package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-314.pyc +0 -0
  206. package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
  207. package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
  208. package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
  209. package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-314.pyc +0 -0
  210. package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
  211. package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
  212. package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
  213. package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
  214. package/pennyfarthing_scripts/handoff/__pycache__/gate_file.cpython-314.pyc +0 -0
  215. package/pennyfarthing_scripts/handoff/__pycache__/gate_runner.cpython-314.pyc +0 -0
  216. package/pennyfarthing_scripts/handoff/__pycache__/marker.cpython-314.pyc +0 -0
  217. package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
  218. package/pennyfarthing_scripts/handoff/cli.py +33 -1
  219. package/pennyfarthing_scripts/handoff/complete_phase.py +28 -0
  220. package/pennyfarthing_scripts/handoff/marker.py +15 -15
  221. package/pennyfarthing_scripts/handoff/phase_check.py +96 -0
  222. package/pennyfarthing_scripts/handoff/resolve_gate.py +13 -1
  223. package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
  224. package/pennyfarthing_scripts/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
  225. package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
  226. package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
  227. package/pennyfarthing_scripts/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
  228. package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-314.pyc +0 -0
  229. package/pennyfarthing_scripts/hooks/__init__.py +437 -0
  230. package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  231. package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
  232. package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-314.pyc +0 -0
  233. package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
  234. package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
  235. package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
  236. package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
  237. package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
  238. package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
  239. package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
  240. package/pennyfarthing_scripts/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
  241. package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
  242. package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
  243. package/pennyfarthing_scripts/hooks/bell_mode.py +215 -0
  244. package/pennyfarthing_scripts/hooks/cli.py +96 -0
  245. package/pennyfarthing_scripts/hooks/context_breaker.py +104 -0
  246. package/pennyfarthing_scripts/hooks/context_warning.py +66 -0
  247. package/pennyfarthing_scripts/hooks/cyclist_pretooluse.py +129 -0
  248. package/pennyfarthing_scripts/hooks/pre_edit_check.py +78 -0
  249. package/pennyfarthing_scripts/hooks/reflector_check.py +271 -0
  250. package/pennyfarthing_scripts/hooks/schema_validation.py +203 -0
  251. package/pennyfarthing_scripts/hooks/session_start.py +296 -0
  252. package/pennyfarthing_scripts/hooks/session_stop.py +111 -0
  253. package/pennyfarthing_scripts/hooks/sprint_yaml_validation.py +97 -0
  254. package/pennyfarthing_scripts/hooks/statusline.py +420 -0
  255. package/pennyfarthing_scripts/hooks.py +27 -432
  256. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
  257. package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
  258. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.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-314.pyc +0 -0
  262. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  263. package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
  264. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  265. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
  266. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  267. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  268. package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
  269. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
  270. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
  271. package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
  272. package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
  273. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
  274. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  275. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
  276. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
  277. package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-314.pyc +0 -0
  278. package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-314.pyc +0 -0
  279. package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
  280. package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
  281. package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
  282. package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
  283. package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
  284. package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
  285. package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
  286. package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
  287. package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
  288. package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
  289. package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
  290. package/pennyfarthing_scripts/pretooluse_hook.py +3 -185
  291. package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  292. package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
  293. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  294. package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
  295. package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
  296. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  297. package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
  298. package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  299. package/pennyfarthing_scripts/prime/__pycache__/version_sentinel.cpython-314.pyc +0 -0
  300. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  301. package/pennyfarthing_scripts/prime/workflow.py +2 -1
  302. package/pennyfarthing_scripts/schema_validation_hook.py +3 -298
  303. package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-314.pyc +0 -0
  304. package/pennyfarthing_scripts/session/__pycache__/cli.cpython-314.pyc +0 -0
  305. package/pennyfarthing_scripts/session_start_hook.py +4 -186
  306. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  307. package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
  308. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  309. package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  310. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  311. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  312. package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-314.pyc +0 -0
  313. package/pennyfarthing_scripts/sprint/__pycache__/import_epic.cpython-314.pyc +0 -0
  314. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  315. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
  316. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
  317. package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
  318. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  319. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  320. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  321. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  322. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  323. package/pennyfarthing_scripts/sprint/story_update.py +19 -0
  324. package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
  325. package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
  326. package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
  327. package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
  328. package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
  329. package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
  330. package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
  331. package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  332. package/pennyfarthing_scripts/tests/__pycache__/test_108_1_gate_migration.cpython-314-pytest-9.0.2.pyc +0 -0
  333. package/pennyfarthing_scripts/tests/__pycache__/test_archive_epic.cpython-314-pytest-9.0.2.pyc +0 -0
  334. package/pennyfarthing_scripts/tests/__pycache__/test_bc.cpython-314-pytest-9.0.2.pyc +0 -0
  335. package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
  336. package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
  337. package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
  338. package/pennyfarthing_scripts/tests/__pycache__/test_cli_normalization.cpython-314-pytest-9.0.2.pyc +0 -0
  339. package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
  340. package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
  341. package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_evaluation.cpython-314-pytest-9.0.2.pyc +0 -0
  342. package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_gate.cpython-314-pytest-9.0.2.pyc +0 -0
  343. package/pennyfarthing_scripts/tests/__pycache__/test_dialogue_manager.cpython-314-pytest-9.0.2.pyc +0 -0
  344. package/pennyfarthing_scripts/tests/__pycache__/test_epic_shard_validation.cpython-314-pytest-9.0.2.pyc +0 -0
  345. package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
  346. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  347. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_e2e.cpython-314-pytest-9.0.2.pyc +0 -0
  348. package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
  349. package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
  350. package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
  351. package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
  352. package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
  353. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
  354. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_panel.cpython-314-pytest-9.0.2.pyc +0 -0
  355. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
  356. package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
  357. package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
  358. package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
  359. package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
  360. package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
  361. package/pennyfarthing_scripts/tests/__pycache__/test_topology_loader.cpython-314-pytest-9.0.2.pyc +0 -0
  362. package/pennyfarthing_scripts/tests/__pycache__/test_tui_focus.cpython-314-pytest-9.0.2.pyc +0 -0
  363. package/pennyfarthing_scripts/tests/__pycache__/test_tui_panel_persistence.cpython-314-pytest-9.0.2.pyc +0 -0
  364. package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
  365. package/pennyfarthing_scripts/tests/__pycache__/test_version_sentinel.cpython-314-pytest-9.0.2.pyc +0 -0
  366. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
  367. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  368. package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
  369. package/pennyfarthing_scripts/tests/test_sprint_panel.py +344 -265
  370. package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-314.pyc +0 -0
  371. package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
  372. package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-314.pyc +0 -0
  373. package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
  374. package/pennyfarthing_scripts/validate/adapters/__pycache__/__init__.cpython-314.pyc +0 -0
  375. package/pennyfarthing_scripts/validate/adapters/__pycache__/agent.cpython-314.pyc +0 -0
  376. package/pennyfarthing_scripts/validate/adapters/__pycache__/schema.cpython-314.pyc +0 -0
  377. package/pennyfarthing_scripts/validate/adapters/__pycache__/skill_command.cpython-314.pyc +0 -0
  378. package/pennyfarthing_scripts/validate/adapters/__pycache__/sprint.cpython-314.pyc +0 -0
  379. package/pennyfarthing_scripts/validate/adapters/__pycache__/tandem_awareness.cpython-314.pyc +0 -0
  380. package/pennyfarthing_scripts/validate/adapters/__pycache__/workflow.cpython-314.pyc +0 -0
  381. package/pennyfarthing_scripts/validate/adapters/workflow.py +19 -0
  382. package/pennyfarthing_scripts/welcome_hook.py +3 -149
  383. package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
  384. package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
  385. package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
  386. package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
  387. package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
  388. package/pennyfarthing_scripts/workflow/cli.py +7 -6
  389. package/pennyfarthing_scripts/workflow/team_lifecycle.py +257 -0
  390. package/packages/core/dist/scripts/theme-detail.test.d.ts +0 -10
  391. package/packages/core/dist/scripts/theme-detail.test.js +0 -199
  392. package/pennyfarthing_scripts/bikerack/__pycache__/portrait.cpython-314.pyc +0 -0
  393. package/pennyfarthing_scripts/gate/__pycache__/__init__.cpython-314.pyc +0 -0
  394. package/pennyfarthing_scripts/gate/__pycache__/cli.cpython-314.pyc +0 -0
  395. package/pennyfarthing_scripts/gate/__pycache__/validate.cpython-314.pyc +0 -0
  396. package/pennyfarthing_scripts/git/__pycache__/hooks_installer.cpython-314.pyc +0 -0
  397. package/pennyfarthing_scripts/git/__pycache__/repos.cpython-314.pyc +0 -0
  398. package/pennyfarthing_scripts/git/__pycache__/worktree.cpython-314.pyc +0 -0
  399. package/pennyfarthing_scripts/prime/__pycache__/heatmap.cpython-314.pyc +0 -0
  400. package/pennyfarthing_scripts/tests/__pycache__/test_108_2_remove_handoff_fallback.cpython-314-pytest-9.0.2.pyc +0 -0
  401. package/pennyfarthing_scripts/tests/__pycache__/test_gate_file_resolution.cpython-314-pytest-9.0.2.pyc +0 -0
  402. package/pennyfarthing_scripts/tests/__pycache__/test_gate_runner.cpython-314-pytest-9.0.2.pyc +0 -0
  403. package/pennyfarthing_scripts/tests/__pycache__/test_resolve_gate_file_field.cpython-314-pytest-9.0.2.pyc +0 -0
@@ -0,0 +1,79 @@
1
+ <gate name="tests-pass" model="haiku">
2
+
3
+ <purpose>
4
+ Verify that all tests pass and the working tree is clean before handing off
5
+ to the reviewer. This gate runs after the Dev agent's implementation phase
6
+ to confirm the codebase is in a GREEN state.
7
+ </purpose>
8
+
9
+ <pass>
10
+ Run these checks and report results:
11
+
12
+ 1. **Test suite:** Run the project test suite for the repos listed in the session file.
13
+ - For `pennyfarthing` repo: `cd pennyfarthing && pnpm test`
14
+ - For `orchestrator` repo: tests in the orchestrator root if applicable
15
+ - Record: total tests, passed, failed, skipped
16
+
17
+ 2. **Working tree:** Run `git status --porcelain` in each repo listed in session `**Repos:**`.
18
+ - Verify no uncommitted or untracked files (empty output = clean)
19
+
20
+ 3. **Branch status:** Run `git branch --show-current` and `git log --oneline -1`.
21
+ - Confirm on the expected feature branch from session `**Branch:**`
22
+
23
+ If ALL checks pass, return:
24
+
25
+ ```yaml
26
+ GATE_RESULT:
27
+ status: pass
28
+ gate: tests-pass
29
+ message: "All {N} tests passing. Working tree clean. Branch: {branch}"
30
+ checks:
31
+ - name: test-suite
32
+ status: pass
33
+ detail: "{passed}/{total} tests passing ({skipped} skipped)"
34
+ - name: working-tree
35
+ status: pass
36
+ detail: "No uncommitted changes"
37
+ - name: branch-status
38
+ status: pass
39
+ detail: "On branch {branch}, HEAD at {short-sha}"
40
+ ```
41
+ </pass>
42
+
43
+ <fail>
44
+ If ANY check fails, diagnose and report:
45
+
46
+ 1. **Failing tests:** List each failing test file and line number.
47
+ - Run tests with verbose output to capture failure details.
48
+ - Group failures by file.
49
+
50
+ 2. **Dirty working tree:** List uncommitted and untracked files.
51
+ - Run `git status --porcelain` and report each file with its status code.
52
+
53
+ 3. **Wrong branch:** Report actual vs expected branch name.
54
+
55
+ Return with actionable recovery guidance:
56
+
57
+ ```yaml
58
+ GATE_RESULT:
59
+ status: fail
60
+ gate: tests-pass
61
+ message: "Gate failed: {summary of failures}"
62
+ checks:
63
+ - name: test-suite
64
+ status: pass | fail
65
+ detail: "{description of test results or failures}"
66
+ - name: working-tree
67
+ status: pass | fail
68
+ detail: "{list of uncommitted files, or 'clean'}"
69
+ - name: branch-status
70
+ status: pass | fail
71
+ detail: "{branch info or mismatch details}"
72
+ recovery:
73
+ - "Fix failing tests in: {file1}, {file2}"
74
+ - "Commit or stash uncommitted changes before handoff"
75
+ - "Switch to correct branch: git checkout {expected-branch}"
76
+ ```
77
+ </fail>
78
+
79
+ </gate>
@@ -49,7 +49,7 @@ On activation, check session file for a `**Tandem:**` line (e.g., `**Tandem:** a
49
49
 
50
50
  **If tandem is configured:**
51
51
 
52
- 1. **Resolve backseat persona** from theme:
52
+ 1. **Resolve backseat persona** from theme using the `pf theme`
53
53
  ```bash
54
54
  THEME=$(yq '.theme' .pennyfarthing/config.local.yaml)
55
55
  PARTNER_CHARACTER=$(yq ".agents.{PARTNER}.character" .pennyfarthing/personas/themes/${THEME}.yaml)
@@ -98,16 +98,17 @@ See `.pennyfarthing/guides/tandem-protocol.md` for full protocol details.
98
98
  ## Reflector
99
99
 
100
100
  <critical>
101
- **EVERY TURN MUST END WITH A CYCLIST MARKER.** Stop hook enforces this.
102
-
103
- | Situation | Marker |
104
- |-----------|--------|
105
- | Workflow handoff | `<!-- CYCLIST:HANDOFF:/agent -->` |
106
- | Handoff + context >80% | `<!-- CYCLIST:CONTEXT_CLEAR:/agent -->` |
107
- | Yes/no question | `<!-- CYCLIST:QUESTION:yesno -->` |
108
- | Open-ended question | `<!-- CYCLIST:QUESTION:open -->` |
109
- | Multiple choice | `<!-- CYCLIST:CHOICES:a,b,c -->` |
110
- | Everything else | `<!-- CYCLIST:CONTINUE -->` |
101
+ **Cyclist only:** EVERY TURN MUST END WITH A CYCLIST MARKER. Stop hook enforces this.
102
+ **CLI mode:** Do NOT emit CYCLIST markers — they are inert outside Cyclist.
103
+
104
+ | Situation | Cyclist Marker | CLI Behavior |
105
+ |-----------|---------------|--------------|
106
+ | Workflow handoff | `<!-- CYCLIST:HANDOFF:/agent -->` | Use AGENT_COMMAND `action` field |
107
+ | Handoff + context >80% | `<!-- CYCLIST:CONTEXT_CLEAR:/agent -->` | Tell user to `/clear` then run agent |
108
+ | Yes/no question | `<!-- CYCLIST:QUESTION:yesno -->` | Ask user directly |
109
+ | Open-ended question | `<!-- CYCLIST:QUESTION:open -->` | Ask user directly |
110
+ | Multiple choice | `<!-- CYCLIST:CHOICES:a,b,c -->` | Ask user directly |
111
+ | Everything else | `<!-- CYCLIST:CONTINUE -->` | (no marker needed) |
111
112
  </critical>
112
113
 
113
114
  ---
@@ -124,7 +125,12 @@ See `.pennyfarthing/guides/tandem-protocol.md` for full protocol details.
124
125
  - If fail → fix issues, retry from step 3 (max 3 retries)
125
126
  - If pass → continue
126
127
  7. `pf handoff complete-phase {story-id} {workflow} {from} {to} {gate-type}`
127
- 8. `pf handoff marker {next_agent}` → emit marker → EXIT
128
+ 8. `pf handoff marker {next_agent}` → AGENT_COMMAND block
129
+ 9. **Act on AGENT_COMMAND:**
130
+ - Has `marker:` field → emit the CYCLIST marker (Cyclist path)
131
+ - `action: "inline_handoff"` → run `activation_command` via Bash, output result, adopt new agent identity
132
+ - `action: "tirepump_handoff"` → tell user: "Context is high. Run `/clear` then `{fallback}`"
133
+ - No action, no marker → output `fallback` text and EXIT
128
134
 
129
135
  **Agents drive exit directly — no handoff subagent.** Scripts handle routing and session updates atomically.
130
136
  </agent-exit-protocol>
@@ -135,14 +141,12 @@ See `.pennyfarthing/guides/tandem-protocol.md` for full protocol details.
135
141
  On activation, check if story phase belongs to you:
136
142
 
137
143
  ```bash
138
- OWNER=$(pf workflow phase-check {workflow} {phase})
139
- # If OWNER != your agent → emit handoff marker and EXIT
144
+ pf handoff phase-check {your_agent_name}
140
145
  ```
141
146
 
142
- Output:
143
- ```
144
- <!-- CYCLIST:HANDOFF:/{OWNER} -->
147
+ If result has `action: "redirect"`:
145
148
 
146
- Run `/pf-{OWNER}` to continue
147
- ```
149
+ - **Cyclist:** Emit `<!-- CYCLIST:HANDOFF:/{phase_owner} -->` and EXIT
150
+ - **CLI + relay ON:** Run `pf agent start {phase_owner} --tier handoff --quiet` via Bash, adopt new identity
151
+ - **CLI + relay OFF:** Output `Run /pf-{phase_owner} to continue` and EXIT
148
152
  </wrong-phase-detection>
@@ -26,7 +26,7 @@ User queues message in Editor
26
26
  |------|---------|
27
27
  | `packages/cyclist/src/bell-mode.ts` | State management: `isBellModeEnabled()`, `setBellMode()`, `toggleBellMode()` |
28
28
  | `packages/cyclist/src/api/bell.ts` | WebSocket broadcast of bell-consumed events |
29
- | `pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh` | PostToolUse hook — reads queue, returns `additionalContext` |
29
+ | `pf hooks bell-mode` | PostToolUse hook — reads queue, returns `additionalContext` |
30
30
  | `packages/cyclist/src/public/hooks/useMessageQueue.ts` | React hook: `queueMessage()`, `dequeueMessage()`, `injectMessage()`, `handleTurnComplete()` |
31
31
  | `packages/cyclist/src/public/contexts/MessageQueueContext.tsx` | Shared React context (single queue instance across components) |
32
32
  | `packages/cyclist/src/public/components/ControlBar.tsx` | Bell mode toggle button |
@@ -4,7 +4,7 @@ Pennyfarthing uses Claude Code hooks to integrate with session lifecycle events
4
4
 
5
5
  ## Overview
6
6
 
7
- Hooks are shell scripts that Claude Code runs at specific events:
7
+ Hooks are commands that Claude Code runs at specific events:
8
8
 
9
9
  | Hook Type | When It Runs | Purpose |
10
10
  |-----------|--------------|---------|
@@ -16,18 +16,18 @@ Hooks are shell scripts that Claude Code runs at specific events:
16
16
 
17
17
  ### SessionStart Hooks
18
18
 
19
- #### session-start.sh
19
+ #### pf hooks session-start
20
20
 
21
- **Location:** `.pennyfarthing/scripts/hooks/session-start.sh`
21
+ **Location:** `pf hooks session-start`
22
22
 
23
23
  Initializes the Pennyfarthing environment:
24
24
  - Creates `.session/` directory structure
25
25
  - Clears stale agent state from previous sessions
26
26
  - Sets `PROJECT_ROOT` and `SESSION_ID` environment variables
27
27
 
28
- #### session-stop.sh
28
+ #### pf hooks session-stop
29
29
 
30
- **Location:** `.pennyfarthing/scripts/hooks/session-stop.sh`
30
+ **Location:** `pf hooks session-stop`
31
31
 
32
32
  Cleans up session state when Claude Code exits.
33
33
 
@@ -46,66 +46,66 @@ Project-specific environment setup. Edit this file to:
46
46
 
47
47
  Auto-configures OTEL telemetry for Cyclist web mode. Checks for a `.wheelhub-port` file and sets `OTEL_EXPORTER_OTLP_PROTOCOL` and `OTEL_EXPORTER_OTLP_ENDPOINT` to route Claude Code telemetry to the running Cyclist/BikeRack server.
48
48
 
49
- #### welcome-hook.sh
49
+ #### pf hooks session-start (welcome)
50
50
 
51
- **Location:** `.pennyfarthing/scripts/hooks/welcome-hook.sh`
51
+ **Location:** `pf hooks session-start`
52
52
 
53
- Displays a welcome message on session start. In CLI mode, shows ASCII art. In Cyclist mode, sends a WebSocket message to display the logo. Runs once per session (lock file guard).
53
+ Welcome display is now folded into `pf hooks session-start`. In CLI mode, shows ASCII art. In Cyclist mode, sends a WebSocket message to display the logo. Runs once per session (lock file guard).
54
54
 
55
55
  ### PreToolUse Hooks
56
56
 
57
- #### pre-edit-check.sh
57
+ #### pf hooks pre-edit-check
58
58
 
59
- **Location:** `.pennyfarthing/scripts/hooks/pre-edit-check.sh`
59
+ **Location:** `pf hooks pre-edit-check`
60
60
 
61
61
  Protects sensitive files from accidental edits:
62
62
  - Blocks: `.env`, `.pem`, `.key`, credentials, secrets
63
63
  - Blocks: `.git/`, `node_modules/`, `vendor/`
64
64
  - Blocks: `.pennyfarthing/*` (managed files)
65
65
 
66
- #### cyclist-pretooluse-hook.sh
66
+ #### pf hooks cyclist-pretooluse
67
67
 
68
- **Location:** `.pennyfarthing/scripts/hooks/cyclist-pretooluse-hook.sh`
68
+ **Location:** `pf hooks cyclist-pretooluse`
69
69
 
70
70
  Cyclist-specific pre-tool validation. Runs additional safety checks when operating inside Cyclist.
71
71
 
72
- #### context-warning.sh
72
+ #### pf hooks context-warning
73
73
 
74
- **Location:** `.pennyfarthing/scripts/hooks/context-warning.sh`
74
+ **Location:** `pf hooks context-warning`
75
75
 
76
76
  Warns agents when context usage is high. Outputs a warning at 60% usage and a critical warning at 85%. Never blocks — warning only (always exits 0).
77
77
 
78
- #### context-circuit-breaker.sh
78
+ #### pf hooks context-breaker
79
79
 
80
- **Location:** `.pennyfarthing/scripts/hooks/context-circuit-breaker.sh`
80
+ **Location:** `pf hooks context-breaker`
81
81
 
82
- Hard stop when context reaches 80% (configurable via `CRITICAL_THRESHOLD`). Unlike `context-warning.sh`, this **blocks tool execution** (exit 2). Auto-saves the active agent to a checkpoint so `/pf-session continue` can restore it with FULL tier context.
82
+ Hard stop when context reaches 80% (configurable via `CRITICAL_THRESHOLD`). Unlike `pf hooks context-warning`, this **blocks tool execution** (exit 2). Auto-saves the active agent to a checkpoint so `/pf-session continue` can restore it with FULL tier context.
83
83
 
84
- #### schema-validation.sh
84
+ #### pf hooks schema-validation
85
85
 
86
- **Location:** `.pennyfarthing/scripts/hooks/schema-validation.sh`
86
+ **Location:** `pf hooks schema-validation`
87
87
 
88
88
  Validates file writes against XML schema rules for agent definitions, workflow files, and other structured content.
89
89
 
90
- #### sprint-yaml-validation.sh
90
+ #### pf hooks sprint-yaml
91
91
 
92
- **Location:** `.pennyfarthing/scripts/hooks/sprint-yaml-validation.sh`
92
+ **Location:** `pf hooks sprint-yaml`
93
93
 
94
94
  Validates sprint YAML files on write to prevent structural corruption.
95
95
 
96
96
  ### PostToolUse Hooks
97
97
 
98
- #### bell-mode-hook.sh
98
+ #### pf hooks bell-mode
99
99
 
100
- **Location:** `.pennyfarthing/scripts/hooks/bell-mode-hook.sh`
100
+ **Location:** `pf hooks bell-mode`
101
101
 
102
102
  Bell mode message injection. Checks the bell mode queue and injects queued messages into the agent's context at the next tool execution. Also handles tandem observation injection.
103
103
 
104
- #### question-reflector-check.sh / question_reflector_check.py
104
+ #### pf hooks reflector-check
105
105
 
106
- **Location:** `.pennyfarthing/scripts/hooks/question-reflector-check.sh`
106
+ **Location:** `pf hooks reflector-check`
107
107
 
108
- Stop hook enforcing that every agent turn ends with a CYCLIST marker. Detects questions, handoff phrases, and validates marker presence. Blocks turns without valid markers in Cyclist mode. The `.sh` file wraps the Python implementation.
108
+ Stop hook enforcing that every agent turn ends with a CYCLIST marker. Detects questions, handoff phrases, and validates marker presence. Blocks turns without valid markers in Cyclist mode.
109
109
 
110
110
  ### Git Hooks
111
111
 
@@ -133,7 +133,7 @@ Hooks are configured in `.claude/settings.local.json`:
133
133
  "hooks": [
134
134
  {
135
135
  "type": "command",
136
- "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/pennyfarthing/scripts/hooks/session-start.sh"
136
+ "command": "pf hooks session-start"
137
137
  }
138
138
  ]
139
139
  }
@@ -144,7 +144,7 @@ Hooks are configured in `.claude/settings.local.json`:
144
144
  "hooks": [
145
145
  {
146
146
  "type": "command",
147
- "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/pennyfarthing/scripts/hooks/pre-edit-check.sh"
147
+ "command": "pf hooks pre-edit-check"
148
148
  }
149
149
  ]
150
150
  }
@@ -41,7 +41,7 @@ Marker pattern: /<!--\s*CYCLIST:(\w+)(?::([^>]+?))?\s*-->/gi
41
41
  | `packages/cyclist/src/public/components/QuickActions.tsx` | Renders action buttons from detected markers |
42
42
  | `packages/cyclist/src/public/hooks/useMarkerActions.ts` | Detects markers, builds action metadata |
43
43
  | `pennyfarthing-dist/scripts/hooks/question_reflector_check.py` | Stop hook — enforces marker presence |
44
- | `pennyfarthing-dist/scripts/hooks/question-reflector-check.sh` | Bash wrapper for stop hook |
44
+ | `pf hooks reflector-check` | CLI entry point for stop hook |
45
45
 
46
46
  ## Enforcement Hook
47
47
 
@@ -13,7 +13,7 @@ Primary Agent (Opus) Backseat Agent (Haiku, background)
13
13
  │ │ .session/{story}-tandem-{partner}.md
14
14
  │ │
15
15
  ├── PostToolUse hook fires ────┤
16
- │ bell-mode-hook.sh detects
16
+ pf hooks bell-mode detects
17
17
  │ new observation, injects │
18
18
  │ "[Tandem] Character: ..." │
19
19
  │ │
@@ -163,8 +163,8 @@ For active, synchronous agent-to-agent questions (as opposed to passive observat
163
163
  | `observation-writer.ts` | Built | TypeScript API for observation file I/O |
164
164
  | `file-watch.ts` | Built | File system change detection |
165
165
  | `tool-watch.ts` | Built | Tool call log monitoring |
166
- | `bell-mode-hook.sh` | Built | PostToolUse hook with tandem injection |
166
+ | `pf hooks bell-mode` | Built | PostToolUse hook with tandem injection |
167
167
  | `bellmode_hook.py` | Built | Python implementation of bell mode hook |
168
- | `statusline.sh` | Built | CLI statusline with tandem indicator |
168
+ | `pf hooks statusline` | Built | CLI statusline with tandem indicator |
169
169
  | `tandem-backseat.md` | Built | Backseat agent prompt template |
170
170
  | `agent-behavior.md` | Built | Shared agent behavior with tandem protocol |
@@ -12,6 +12,8 @@
12
12
 
13
13
  set -euo pipefail
14
14
 
15
+ echo "DEPRECATED: check-context.sh — use 'pf context' instead" >&2
16
+
15
17
  # Find project root (where pennyfarthing_scripts lives)
16
18
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
17
19
 
@@ -1,90 +1,8 @@
1
1
  #!/bin/bash
2
- # Start an agent with phase check
3
- # If the current story's phase belongs to a different agent, emit handoff marker instead
2
+ # DEPRECATED: Use `pf handoff phase-check <agent>` instead.
3
+ # This shim delegates to the Python implementation.
4
4
  #
5
- # Usage: .pennyfarthing/scripts/core/phase-check-start.sh <agent>
6
- # Example: phase-check-start.sh dev
5
+ # Usage: phase-check-start.sh <agent>
7
6
 
8
- set -euo pipefail
9
-
10
- AGENT="${1:-}"
11
-
12
- if [[ -z "$AGENT" ]]; then
13
- echo "Usage: phase-check-start.sh <agent>" >&2
14
- exit 1
15
- fi
16
-
17
- # Self-locate and set up PROJECT_ROOT
18
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
19
- source "$SCRIPT_DIR/../lib/find-root.sh"
20
-
21
- SCRIPTS_DIR="$SCRIPT_DIR/.."
22
- SESSION_DIR="$PROJECT_ROOT/.session"
23
-
24
- # Find active session file
25
- SESSION_FILE=$(find "$SESSION_DIR" -maxdepth 1 -name "*-session.md" 2>/dev/null | head -1)
26
-
27
- if [[ -z "$SESSION_FILE" || ! -f "$SESSION_FILE" ]]; then
28
- # No session - just start the agent normally
29
- exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
30
- fi
31
-
32
- # Extract workflow and phase from session (handles multiple formats)
33
- # Format 1: **Workflow:** value
34
- # Format 2: - **Workflow**: value
35
- WORKFLOW=$(grep -E "\*\*Workflow\*?\*?:" "$SESSION_FILE" 2>/dev/null | head -1 | sed 's/.*\*\*Workflow\*\*[:\*]* *//' | tr -d ' ' || echo "")
36
- PHASE=$(grep -E "\*\*Phase\*?\*?:" "$SESSION_FILE" 2>/dev/null | head -1 | sed 's/.*\*\*Phase\*\*[:\*]* *//' | tr -d ' ' || echo "")
37
-
38
- if [[ -z "$WORKFLOW" ]]; then
39
- # Can't determine workflow - start normally
40
- exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
41
- fi
42
-
43
- # If no Phase field, try to infer from status patterns
44
- if [[ -z "$PHASE" ]]; then
45
- # Check for approval status (story is done, needs SM to close)
46
- if grep -qE "\*\*Status\*\*:.*APPROVED" "$SESSION_FILE" 2>/dev/null; then
47
- PHASE="approved"
48
- # Check for review status
49
- elif grep -qE "Reviewer Assessment|Review.*REJECTED\|Review.*APPROVED" "$SESSION_FILE" 2>/dev/null; then
50
- PHASE="review"
51
- # Check for green/implementation complete
52
- elif grep -qE "Dev Assessment|\*\*Status\*\*:.*GREEN" "$SESSION_FILE" 2>/dev/null; then
53
- # Has dev assessment - could be in review or approved
54
- if grep -qE "Reviewer Assessment" "$SESSION_FILE" 2>/dev/null; then
55
- PHASE="approved" # Reviewer already assessed
56
- else
57
- PHASE="review" # Needs reviewer
58
- fi
59
- # Check for red/test phase
60
- elif grep -qE "TEA Assessment|\*\*Status\*\*:.*RED" "$SESSION_FILE" 2>/dev/null; then
61
- PHASE="green" # TEA done, Dev's turn
62
- else
63
- # Can't determine phase - start normally
64
- exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
65
- fi
66
- fi
67
-
68
- # Get the owner of this phase
69
- OWNER=$("$SCRIPTS_DIR/workflow/phase-owner.sh" "$WORKFLOW" "$PHASE" 2>/dev/null || echo "")
70
-
71
- if [[ -z "$OWNER" ]]; then
72
- # Phase owner lookup failed - start normally
73
- exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
74
- fi
75
-
76
- # Check if this agent owns the phase
77
- if [[ "$OWNER" == "$AGENT" ]]; then
78
- # Correct agent - start normally
79
- exec "$SCRIPTS_DIR/core/agent-session.sh" start "$AGENT"
80
- fi
81
-
82
- # Wrong agent! Output the handoff marker and info
83
- STORY_ID=$(basename "$SESSION_FILE" -session.md)
84
-
85
- echo "Phase check: Story $STORY_ID is in '$PHASE' phase (workflow: $WORKFLOW)"
86
- echo "Phase owner: $OWNER (you requested: $AGENT)"
87
- echo ""
88
-
89
- # Generate and output the handoff marker
90
- pf handoff marker "$OWNER"
7
+ echo "DEPRECATED: phase-check-start.sh — use 'pf handoff phase-check $1' instead" >&2
8
+ exec pf handoff phase-check "$@"
@@ -6,15 +6,15 @@ Git hooks and Claude Code hooks.
6
6
 
7
7
  | Script | Purpose |
8
8
  |--------|---------|
9
- | `context-circuit-breaker.sh` | Claude hook: halt at context limit |
10
- | `context-warning.sh` | Claude hook: warn on high context |
9
+ | `pf hooks context-breaker` | Claude hook: halt at context limit |
10
+ | `pf hooks context-warning` | Claude hook: warn on high context |
11
11
  | `otel-auto-config.sh` | Claude hook: configure OTEL |
12
12
  | `post-merge.sh` | Git hook: post-merge actions |
13
13
  | `pre-commit.sh` | Git hook: branch protection, agent validation, sprint YAML validation |
14
- | `pre-edit-check.sh` | Claude hook: validate before edit |
14
+ | `pf hooks pre-edit-check` | Claude hook: validate before edit |
15
15
  | `pre-push.sh` | Git hook: pre-push validation |
16
- | `session-start.sh` | Claude hook: session start |
17
- | `session-stop.sh` | Claude hook: session stop |
16
+ | `pf hooks session-start` | Claude hook: session start |
17
+ | `pf hooks session-stop` | Claude hook: session stop |
18
18
 
19
19
  ## Installation
20
20
 
@@ -1,183 +1,4 @@
1
- #!/bin/bash
2
- #
3
- # PostToolUse Hook Bell Mode + Tandem Injection
4
- #
5
- # Called by Claude Code after each tool execution. Handles two independent
6
- # injection systems:
7
- #
8
- # 1. Bell queue (Cyclist only) — injects queued user messages when Cyclist
9
- # is running and bell_mode is enabled. In CLI sessions this is a no-op.
10
- # 2. Tandem observations (always active) — injects backseat agent observations
11
- # when tandem observation files exist. No configuration required.
12
- #
13
- # Bell queue takes precedence: if a queued message exists, tandem is
14
- # deferred to the next hook invocation.
15
- #
16
- # Output format (when injecting):
17
- # {
18
- # "hookSpecificOutput": {
19
- # "hookEventName": "PostToolUse",
20
- # "additionalContext": "<message>"
21
- # }
22
- # }
23
- #
24
- # Output when nothing to inject: (nothing - exit 0)
25
-
26
- # Find project root (walk up to find .pennyfarthing)
27
- PROJECT_ROOT="$PWD"
28
- while [[ "$PROJECT_ROOT" != "/" ]]; do
29
- if [[ -d "$PROJECT_ROOT/.pennyfarthing" ]]; then
30
- break
31
- fi
32
- PROJECT_ROOT="$(dirname "$PROJECT_ROOT")"
33
- done
34
-
35
- if [[ ! -d "$PROJECT_ROOT/.pennyfarthing" ]]; then
36
- exit 0
37
- fi
38
-
39
- CONFIG_LOCAL_YAML="$PROJECT_ROOT/.pennyfarthing/config.local.yaml"
40
- BELL_QUEUE_FILE="$PROJECT_ROOT/.pennyfarthing/bell-queue.json"
41
-
42
- # Detect Cyclist — bell queue is a Cyclist-only feature
43
- IS_CYCLIST=false
44
- CYCLIST_PORT=""
45
- PORT_FILE="$PROJECT_ROOT/.wheelhub-port"
46
- if [[ -f "$PORT_FILE" ]]; then
47
- CYCLIST_PORT=$(cat "$PORT_FILE" 2>/dev/null)
48
- if [[ -n "$CYCLIST_PORT" ]] && [[ "$CYCLIST_PORT" =~ ^[0-9]+$ ]]; then
49
- IS_CYCLIST=true
50
- fi
51
- fi
52
-
53
- # --- Bell queue check (Cyclist only, requires bell_mode: true) ---
54
- # Takes precedence over tandem injection when active.
55
-
56
- if [[ "$IS_CYCLIST" == "true" ]] && [[ -f "$CONFIG_LOCAL_YAML" ]]; then
57
- BELL_ENABLED=$(grep -E '^\s*bell_mode:\s*true' "$CONFIG_LOCAL_YAML" 2>/dev/null || true)
58
-
59
- if [[ -n "$BELL_ENABLED" ]] && [[ -f "$BELL_QUEUE_FILE" ]]; then
60
- QUEUE_CONTENT=$(cat "$BELL_QUEUE_FILE" 2>/dev/null)
61
- if [[ -n "$QUEUE_CONTENT" ]] && [[ "$QUEUE_CONTENT" != "[]" ]]; then
62
- FIRST_MESSAGE_TEXT=$(echo "$QUEUE_CONTENT" | sed -n 's/.*"text"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -1)
63
-
64
- if [[ -n "$FIRST_MESSAGE_TEXT" ]]; then
65
- cat << EOF
66
- {
67
- "hookSpecificOutput": {
68
- "hookEventName": "PostToolUse",
69
- "additionalContext": "User feedback: $FIRST_MESSAGE_TEXT"
70
- }
71
- }
72
- EOF
73
-
74
- # Dequeue and notify Cyclist in background
75
- (
76
- if command -v jq &> /dev/null; then
77
- jq 'if length > 0 then .[1:] else [] end' "$BELL_QUEUE_FILE" > "$BELL_QUEUE_FILE.tmp" 2>/dev/null && mv "$BELL_QUEUE_FILE.tmp" "$BELL_QUEUE_FILE"
78
- fi
79
-
80
- curl -s -X POST "http://localhost:$CYCLIST_PORT/api/bell-consumed" \
81
- -H "Content-Type: application/json" \
82
- -d "{\"text\": \"$FIRST_MESSAGE_TEXT\"}" \
83
- >/dev/null 2>&1 || true
84
- ) &
85
-
86
- exit 0
87
- fi
88
- fi
89
- fi
90
- fi
91
-
92
- # --- Tandem observation injection ---
93
- # Always active. No configuration required.
94
- # Checks .session/*-tandem-*.md files for new observations via mtime comparison.
95
-
96
- SESSION_DIR="$PROJECT_ROOT/.session"
97
- if [[ ! -d "$SESSION_DIR" ]]; then
98
- exit 0
99
- fi
100
-
101
- # Find tandem observation files
102
- TANDEM_FILES=$(find "$SESSION_DIR" -maxdepth 1 -name "*-tandem-*.md" 2>/dev/null)
103
- if [[ -z "$TANDEM_FILES" ]]; then
104
- exit 0
105
- fi
106
-
107
- # Check each tandem file for new content
108
- for TANDEM_FILE in $TANDEM_FILES; do
109
- # Extract agent name from filename: *-tandem-{agent}.md
110
- AGENT=$(echo "$TANDEM_FILE" | sed -n 's/.*-tandem-\([a-zA-Z_]*\)\.md$/\1/p')
111
- if [[ -z "$AGENT" ]]; then
112
- continue
113
- fi
114
-
115
- # Get file mtime (portable: stat -f %m on macOS, stat -c %Y on Linux)
116
- if [[ "$(uname)" == "Darwin" ]]; then
117
- FILE_MTIME=$(stat -f %m "$TANDEM_FILE" 2>/dev/null)
118
- else
119
- FILE_MTIME=$(stat -c %Y "$TANDEM_FILE" 2>/dev/null)
120
- fi
121
- if [[ -z "$FILE_MTIME" ]]; then
122
- continue
123
- fi
124
-
125
- # Compare with saved mtime sidecar
126
- MTIME_SIDECAR="$SESSION_DIR/.tandem-mtime-$AGENT"
127
- SAVED_MTIME="0"
128
- if [[ -f "$MTIME_SIDECAR" ]]; then
129
- SAVED_MTIME=$(cat "$MTIME_SIDECAR" 2>/dev/null)
130
- fi
131
-
132
- if [[ "$FILE_MTIME" == "$SAVED_MTIME" ]]; then
133
- continue
134
- fi
135
-
136
- # Read tandem file and extract latest observation
137
- CONTENT=$(cat "$TANDEM_FILE" 2>/dev/null)
138
- if [[ -z "$CONTENT" ]]; then
139
- continue
140
- fi
141
-
142
- # Extract persona from header: **Observer:** agent (Persona Name)
143
- PERSONA=$(echo "$CONTENT" | sed -n 's/.*\*\*Observer:\*\*[[:space:]]*[a-zA-Z_]*[[:space:]]*(\([^)]*\)).*/\1/p' | head -1)
144
- if [[ -z "$PERSONA" ]]; then
145
- PERSONA="Unknown"
146
- fi
147
-
148
- # Extract latest observation text (last ## [HH:MM] Observation block)
149
- # Get text between last observation header and trailing ---
150
- OBS_TEXT=$(echo "$CONTENT" | awk '
151
- /^## \[[0-9]+:[0-9]+\] Observation/ { found=1; text=""; next }
152
- found && /^---/ { next }
153
- found && /^\*\*Trigger:\*\*/ { next }
154
- found { text = text (text ? "\n" : "") $0 }
155
- END { if (text) print text }
156
- ' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
157
-
158
- if [[ -z "$OBS_TEXT" ]]; then
159
- # Update mtime even if no parseable observation
160
- echo "$FILE_MTIME" > "$MTIME_SIDECAR"
161
- continue
162
- fi
163
-
164
- # Format as [Tandem] prefix and output
165
- TANDEM_MSG="[Tandem] $PERSONA: $OBS_TEXT"
166
-
167
- cat << EOF
168
- {
169
- "hookSpecificOutput": {
170
- "hookEventName": "PostToolUse",
171
- "additionalContext": "$TANDEM_MSG"
172
- }
173
- }
174
- EOF
175
-
176
- # Save mtime sidecar
177
- echo "$FILE_MTIME" > "$MTIME_SIDECAR"
178
-
179
- # Only inject one tandem observation per hook invocation
180
- exit 0
181
- done
182
-
183
- exit 0
1
+ #!/usr/bin/env bash
2
+ # DEPRECATED: This script is a shim. Logic has moved to Python.
3
+ # Use: pf hooks bell-mode
4
+ exec pf hooks bell-mode