@pennyfarthing/core 11.2.1 → 11.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (405) hide show
  1. package/README.md +102 -42
  2. package/package.json +1 -1
  3. package/packages/core/dist/cli/commands/doctor-legacy.test.js +2 -2
  4. package/packages/core/dist/cli/commands/doctor-legacy.test.js.map +1 -1
  5. package/packages/core/dist/cli/commands/doctor.d.ts +55 -0
  6. package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
  7. package/packages/core/dist/cli/commands/doctor.js +324 -50
  8. package/packages/core/dist/cli/commands/doctor.js.map +1 -1
  9. package/packages/core/dist/cli/commands/init.d.ts +12 -0
  10. package/packages/core/dist/cli/commands/init.d.ts.map +1 -1
  11. package/packages/core/dist/cli/commands/init.js +45 -0
  12. package/packages/core/dist/cli/commands/init.js.map +1 -1
  13. package/packages/core/dist/cli/commands/pyproject-install.test.d.ts +19 -0
  14. package/packages/core/dist/cli/commands/pyproject-install.test.d.ts.map +1 -0
  15. package/packages/core/dist/cli/commands/pyproject-install.test.js +261 -0
  16. package/packages/core/dist/cli/commands/pyproject-install.test.js.map +1 -0
  17. package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.d.ts +17 -0
  18. package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.d.ts.map +1 -0
  19. package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.js +470 -0
  20. package/packages/core/dist/cli/commands/stale-artifacts-cleanup.test.js.map +1 -0
  21. package/packages/core/dist/cli/commands/update-consolidation.test.js +14 -6
  22. package/packages/core/dist/cli/commands/update-consolidation.test.js.map +1 -1
  23. package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
  24. package/packages/core/dist/cli/commands/update.js +31 -2
  25. package/packages/core/dist/cli/commands/update.js.map +1 -1
  26. package/packages/core/dist/cli/index.js +2 -0
  27. package/packages/core/dist/cli/index.js.map +1 -1
  28. package/packages/core/dist/cli/utils/python.d.ts.map +1 -1
  29. package/packages/core/dist/cli/utils/python.js +11 -0
  30. package/packages/core/dist/cli/utils/python.js.map +1 -1
  31. package/packages/core/dist/cli/utils/settings-hook-migration.test.d.ts +17 -0
  32. package/packages/core/dist/cli/utils/settings-hook-migration.test.d.ts.map +1 -0
  33. package/packages/core/dist/cli/utils/settings-hook-migration.test.js +382 -0
  34. package/packages/core/dist/cli/utils/settings-hook-migration.test.js.map +1 -0
  35. package/packages/core/dist/cli/utils/settings.d.ts +0 -4
  36. package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
  37. package/packages/core/dist/cli/utils/settings.js +45 -27
  38. package/packages/core/dist/cli/utils/settings.js.map +1 -1
  39. package/packages/core/dist/cli/utils/stale-artifacts.d.ts +59 -0
  40. package/packages/core/dist/cli/utils/stale-artifacts.d.ts.map +1 -0
  41. package/packages/core/dist/cli/utils/stale-artifacts.js +163 -0
  42. package/packages/core/dist/cli/utils/stale-artifacts.js.map +1 -0
  43. package/packages/core/dist/consultation/dialogue-manager.d.ts +1 -1
  44. package/packages/core/dist/consultation/dialogue-manager.d.ts.map +1 -1
  45. package/packages/core/dist/consultation/dialogue-manager.js +1 -1
  46. package/packages/core/dist/consultation/dialogue-manager.js.map +1 -1
  47. package/packages/core/dist/consultation/dialogue-manager.test.js.map +1 -1
  48. package/packages/core/dist/consultation/tandem-metrics.test.js.map +1 -1
  49. package/packages/core/dist/public/css/react.css +1 -1
  50. package/packages/core/dist/public/js/react/react.js +9 -9
  51. package/packages/core/dist/server/api/git.d.ts.map +1 -1
  52. package/packages/core/dist/server/api/git.js +0 -1
  53. package/packages/core/dist/server/api/git.js.map +1 -1
  54. package/packages/core/dist/server/api/index.d.ts +2 -0
  55. package/packages/core/dist/server/api/index.d.ts.map +1 -1
  56. package/packages/core/dist/server/api/index.js +2 -0
  57. package/packages/core/dist/server/api/index.js.map +1 -1
  58. package/packages/core/dist/server/api/project-info.d.ts +11 -0
  59. package/packages/core/dist/server/api/project-info.d.ts.map +1 -0
  60. package/packages/core/dist/server/api/project-info.js +18 -0
  61. package/packages/core/dist/server/api/project-info.js.map +1 -0
  62. package/packages/core/dist/server/otlp-receiver.d.ts.map +1 -1
  63. package/packages/core/dist/server/otlp-receiver.js +18 -1
  64. package/packages/core/dist/server/otlp-receiver.js.map +1 -1
  65. package/packages/core/dist/server/otlp-receiver.test.js +1 -1
  66. package/packages/core/dist/server/otlp-receiver.test.js.map +1 -1
  67. package/packages/core/dist/server/server.d.ts.map +1 -1
  68. package/packages/core/dist/server/server.js +3 -2
  69. package/packages/core/dist/server/server.js.map +1 -1
  70. package/packages/core/dist/server/server.test.d.ts +1 -1
  71. package/packages/core/dist/server/server.test.js +8 -8
  72. package/packages/core/dist/server/settings.d.ts +1 -0
  73. package/packages/core/dist/server/settings.d.ts.map +1 -1
  74. package/packages/core/dist/server/settings.js +18 -0
  75. package/packages/core/dist/server/settings.js.map +1 -1
  76. package/packages/core/dist/workflow/tandem-workflow-templates.test.js +7 -5
  77. package/packages/core/dist/workflow/tandem-workflow-templates.test.js.map +1 -1
  78. package/packages/core/dist/workflow/workflow-migration.test.js +6 -5
  79. package/packages/core/dist/workflow/workflow-migration.test.js.map +1 -1
  80. package/packages/core/dist/workflow/workflow-team-templates.test.d.ts +17 -0
  81. package/packages/core/dist/workflow/workflow-team-templates.test.d.ts.map +1 -0
  82. package/packages/core/dist/workflow/workflow-team-templates.test.js +275 -0
  83. package/packages/core/dist/workflow/workflow-team-templates.test.js.map +1 -0
  84. package/pennyfarthing-dist/agents/dev.md +19 -4
  85. package/pennyfarthing-dist/agents/devops.md +2 -10
  86. package/pennyfarthing-dist/agents/reviewer-preflight.md +4 -5
  87. package/pennyfarthing-dist/agents/reviewer.md +17 -4
  88. package/pennyfarthing-dist/agents/sm-finish.md +1 -1
  89. package/pennyfarthing-dist/agents/sm-setup.md +7 -7
  90. package/pennyfarthing-dist/agents/sm.md +16 -29
  91. package/pennyfarthing-dist/agents/tea.md +2 -2
  92. package/pennyfarthing-dist/agents/testing-runner.md +1 -1
  93. package/pennyfarthing-dist/commands/pf-architect.md +1 -1
  94. package/pennyfarthing-dist/commands/pf-ba.md +1 -1
  95. package/pennyfarthing-dist/commands/pf-chore.md +2 -2
  96. package/pennyfarthing-dist/commands/pf-dev.md +1 -1
  97. package/pennyfarthing-dist/commands/pf-devops.md +1 -1
  98. package/pennyfarthing-dist/commands/pf-epic.md +6 -6
  99. package/pennyfarthing-dist/commands/pf-git.md +10 -10
  100. package/pennyfarthing-dist/commands/pf-health-check.md +31 -12
  101. package/pennyfarthing-dist/commands/pf-help.md +12 -12
  102. package/pennyfarthing-dist/commands/pf-orchestrator.md +1 -1
  103. package/pennyfarthing-dist/commands/pf-pm.md +1 -1
  104. package/pennyfarthing-dist/commands/pf-prime.md +8 -8
  105. package/pennyfarthing-dist/commands/pf-reviewer.md +1 -1
  106. package/pennyfarthing-dist/commands/pf-session.md +7 -7
  107. package/pennyfarthing-dist/commands/pf-sm.md +1 -1
  108. package/pennyfarthing-dist/commands/pf-sprint.md +7 -7
  109. package/pennyfarthing-dist/commands/pf-tea.md +1 -1
  110. package/pennyfarthing-dist/commands/pf-tech-writer.md +1 -1
  111. package/pennyfarthing-dist/commands/pf-theme.md +9 -9
  112. package/pennyfarthing-dist/commands/pf-ux-designer.md +1 -1
  113. package/pennyfarthing-dist/commands/pf-work.md +1 -1
  114. package/pennyfarthing-dist/gates/{confidence-sm.md → confidence.md} +16 -17
  115. package/pennyfarthing-dist/gates/dev-exit.md +75 -0
  116. package/pennyfarthing-dist/gates/merge-ready.md +49 -0
  117. package/pennyfarthing-dist/gates/release-ready.md +95 -0
  118. package/pennyfarthing-dist/gates/reviewer-preflight-check.md +90 -0
  119. package/pennyfarthing-dist/gates/sm-setup-exit.md +82 -0
  120. package/pennyfarthing-dist/guides/agent-behavior.md +129 -20
  121. package/pennyfarthing-dist/guides/agent-coordination.md +10 -10
  122. package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +6 -6
  123. package/pennyfarthing-dist/guides/agent-template-tactical.md +1 -1
  124. package/pennyfarthing-dist/guides/bell-mode.md +1 -1
  125. package/pennyfarthing-dist/guides/bikerack.md +10 -10
  126. package/pennyfarthing-dist/guides/brownfield-tools.md +24 -24
  127. package/pennyfarthing-dist/guides/command-tag-taxonomy.md +1 -1
  128. package/pennyfarthing-dist/guides/gate-schema.md +2 -2
  129. package/pennyfarthing-dist/guides/gates.md +10 -5
  130. package/pennyfarthing-dist/guides/handoff-cli.md +8 -8
  131. package/pennyfarthing-dist/guides/hooks.md +27 -27
  132. package/pennyfarthing-dist/guides/prime.md +2 -2
  133. package/pennyfarthing-dist/guides/reflector.md +1 -1
  134. package/pennyfarthing-dist/guides/skill-schema.md +6 -6
  135. package/pennyfarthing-dist/guides/tandem-protocol.md +3 -3
  136. package/pennyfarthing-dist/guides/workflow-schema.md +1 -1
  137. package/pennyfarthing-dist/guides/worktree-mode.md +3 -3
  138. package/pennyfarthing-dist/guides/xml-tags.md +8 -8
  139. package/pennyfarthing-dist/scripts/README.md +4 -4
  140. package/pennyfarthing-dist/scripts/core/agent-session.sh +2 -5
  141. package/pennyfarthing-dist/scripts/core/check-context.sh +1 -1
  142. package/pennyfarthing-dist/scripts/core/pf.sh +5 -0
  143. package/pennyfarthing-dist/scripts/core/phase-check-start.sh +2 -5
  144. package/pennyfarthing-dist/scripts/core/prime.sh +2 -25
  145. package/pennyfarthing-dist/scripts/git/README.md +14 -14
  146. package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +2 -3
  147. package/pennyfarthing-dist/scripts/git/git-status-all.sh +2 -3
  148. package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +2 -3
  149. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +2 -4
  150. package/pennyfarthing-dist/scripts/hooks/README.md +6 -6
  151. package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +3 -3
  152. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +3 -3
  153. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +3 -3
  154. package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +3 -3
  155. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +5 -4
  156. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +2 -1
  157. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +3 -3
  158. package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +3 -3
  159. package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +3 -3
  160. package/pennyfarthing-dist/scripts/hooks/session-start.sh +3 -3
  161. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +3 -3
  162. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +3 -3
  163. package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +3 -4
  164. package/pennyfarthing-dist/scripts/lib/env.sh +34 -0
  165. package/pennyfarthing-dist/scripts/lib/find-root.sh +5 -0
  166. package/pennyfarthing-dist/scripts/lib/run-pf.sh +43 -0
  167. package/pennyfarthing-dist/scripts/misc/README.md +1 -1
  168. package/pennyfarthing-dist/scripts/misc/statusline.sh +3 -3
  169. package/pennyfarthing-dist/scripts/sprint/README.md +21 -21
  170. package/pennyfarthing-dist/scripts/workflow/README.md +2 -2
  171. package/pennyfarthing-dist/scripts/workflow/finish-story.sh +2 -16
  172. package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +3 -3
  173. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +3 -3
  174. package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +3 -3
  175. package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +3 -3
  176. package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +3 -3
  177. package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +3 -3
  178. package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +3 -3
  179. package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +3 -3
  180. package/pennyfarthing-dist/skills/pf-bc/examples.md +23 -23
  181. package/pennyfarthing-dist/skills/pf-bc/skill.md +17 -17
  182. package/pennyfarthing-dist/skills/pf-bc/usage.md +8 -8
  183. package/pennyfarthing-dist/skills/pf-jira/SKILL.md +15 -15
  184. package/pennyfarthing-dist/skills/pf-jira/examples.md +48 -48
  185. package/pennyfarthing-dist/skills/pf-jira/usage.md +15 -15
  186. package/pennyfarthing-dist/skills/pf-settings/skill.md +42 -0
  187. package/pennyfarthing-dist/skills/pf-sprint/examples.md +80 -80
  188. package/pennyfarthing-dist/skills/pf-sprint/skill.md +35 -35
  189. package/pennyfarthing-dist/skills/pf-sprint/usage.md +30 -30
  190. package/pennyfarthing-dist/skills/pf-theme/examples.md +15 -15
  191. package/pennyfarthing-dist/skills/pf-theme/skill.md +6 -6
  192. package/pennyfarthing-dist/skills/pf-theme/usage.md +5 -5
  193. package/pennyfarthing-dist/skills/pf-workflow/examples.md +27 -27
  194. package/pennyfarthing-dist/skills/pf-workflow/skill.md +11 -11
  195. package/pennyfarthing-dist/skills/pf-workflow/usage.md +11 -11
  196. package/pennyfarthing-dist/skills/skill-registry.yaml +34 -19
  197. package/pennyfarthing-dist/templates/pyproject.toml +27 -0
  198. package/pennyfarthing-dist/templates/settings.local.json.template +11 -11
  199. package/pennyfarthing-dist/workflows/bdd-tandem.yaml +7 -3
  200. package/pennyfarthing-dist/workflows/bdd-team.yaml +89 -0
  201. package/pennyfarthing-dist/workflows/bdd.yaml +7 -3
  202. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +1 -1
  203. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +1 -1
  204. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +1 -1
  205. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +1 -1
  206. package/pennyfarthing-dist/workflows/installation-check/steps/step-01-foundation.md +77 -0
  207. package/pennyfarthing-dist/workflows/installation-check/steps/step-02-commands.md +82 -0
  208. package/pennyfarthing-dist/workflows/installation-check/steps/step-03-hooks.md +121 -0
  209. package/pennyfarthing-dist/workflows/installation-check/steps/step-04-scripts.md +83 -0
  210. package/pennyfarthing-dist/workflows/installation-check/steps/step-05-layout.md +81 -0
  211. package/pennyfarthing-dist/workflows/installation-check/steps/step-06-legacy.md +94 -0
  212. package/pennyfarthing-dist/workflows/installation-check/steps/step-07-tools.md +80 -0
  213. package/pennyfarthing-dist/workflows/installation-check/steps/step-08-summary.md +99 -0
  214. package/pennyfarthing-dist/workflows/installation-check/workflow.yaml +47 -0
  215. package/pennyfarthing-dist/workflows/project-setup/steps/step-01-discover.md +47 -0
  216. package/pennyfarthing-dist/workflows/tdd-tandem.yaml +7 -3
  217. package/pennyfarthing-dist/workflows/tdd-team.yaml +80 -0
  218. package/pennyfarthing-dist/workflows/tdd.yaml +7 -3
  219. package/pennyfarthing-dist/workflows/trivial.yaml +7 -3
  220. package/pennyfarthing_scripts/__init__.py +1 -1
  221. package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  222. package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  223. package/pennyfarthing_scripts/__pycache__/cli.cpython-311.pyc +0 -0
  224. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  225. package/pennyfarthing_scripts/__pycache__/context.cpython-311.pyc +0 -0
  226. package/pennyfarthing_scripts/__pycache__/context.cpython-314.pyc +0 -0
  227. package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-311.pyc +0 -0
  228. package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-311.pyc +0 -0
  229. package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
  230. package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-311.pyc +0 -0
  231. package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
  232. package/pennyfarthing_scripts/bc/__pycache__/split.cpython-314.pyc +0 -0
  233. package/pennyfarthing_scripts/bc/cli.py +23 -2
  234. package/pennyfarthing_scripts/bc/focus.py +1 -0
  235. package/pennyfarthing_scripts/bc/split.py +52 -0
  236. package/pennyfarthing_scripts/bellmode_hook.py +2 -5
  237. package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-311.pyc +0 -0
  238. package/pennyfarthing_scripts/bikerack/__pycache__/audit_log_panel.cpython-314.pyc +0 -0
  239. package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
  240. package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
  241. package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
  242. package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-311.pyc +0 -0
  243. package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
  244. package/pennyfarthing_scripts/bikerack/__pycache__/context_meter_footer.cpython-314.pyc +0 -0
  245. package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
  246. package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
  247. package/pennyfarthing_scripts/bikerack/__pycache__/events.cpython-314.pyc +0 -0
  248. package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
  249. package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-311.pyc +0 -0
  250. package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
  251. package/pennyfarthing_scripts/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
  252. package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
  253. package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
  254. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
  255. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
  256. package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
  257. package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
  258. package/pennyfarthing_scripts/bikerack/audit_log_panel.py +48 -6
  259. package/pennyfarthing_scripts/bikerack/context_meter_footer.py +53 -3
  260. package/pennyfarthing_scripts/bikerack/launcher.py +6 -6
  261. package/pennyfarthing_scripts/bikerack/progress_panel.py +0 -1
  262. package/pennyfarthing_scripts/bikerack/sprint_panel.py +1 -1
  263. package/pennyfarthing_scripts/bikerack/story_detail_data.py +4 -1
  264. package/pennyfarthing_scripts/bikerack/story_detail_screen.py +2 -1
  265. package/pennyfarthing_scripts/bikerack/tui.py +214 -10
  266. package/pennyfarthing_scripts/bikerack/ws_client.py +2 -2
  267. package/pennyfarthing_scripts/cli.py +5 -0
  268. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-311.pyc +0 -0
  269. package/pennyfarthing_scripts/common/__pycache__/config.cpython-311.pyc +0 -0
  270. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  271. package/pennyfarthing_scripts/common/__pycache__/output.cpython-311.pyc +0 -0
  272. package/pennyfarthing_scripts/common/__pycache__/pr_config.cpython-314.pyc +0 -0
  273. package/pennyfarthing_scripts/common/config.py +29 -2
  274. package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-311.pyc +0 -0
  275. package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
  276. package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-311.pyc +0 -0
  277. package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
  278. package/pennyfarthing_scripts/consultation/cli.py +3 -3
  279. package/pennyfarthing_scripts/context.py +3 -3
  280. package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-311.pyc +0 -0
  281. package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-311.pyc +0 -0
  282. package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-311.pyc +0 -0
  283. package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-311.pyc +0 -0
  284. package/pennyfarthing_scripts/git/hooks_installer.py +2 -3
  285. package/pennyfarthing_scripts/git/status_all.py +1 -1
  286. package/pennyfarthing_scripts/git/worktree.py +2 -2
  287. package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-311.pyc +0 -0
  288. package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-311.pyc +0 -0
  289. package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
  290. package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-311.pyc +0 -0
  291. package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-311.pyc +0 -0
  292. package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
  293. package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
  294. package/pennyfarthing_scripts/handoff/__pycache__/marker.cpython-314.pyc +0 -0
  295. package/pennyfarthing_scripts/handoff/__pycache__/phase_check.cpython-314.pyc +0 -0
  296. package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
  297. package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-311.pyc +0 -0
  298. package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-311.pyc +0 -0
  299. package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-311.pyc +0 -0
  300. package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-311.pyc +0 -0
  301. package/pennyfarthing_scripts/hooks/__init__.py +8 -3
  302. package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-311.pyc +0 -0
  303. package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  304. package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-311.pyc +0 -0
  305. package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
  306. package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-311.pyc +0 -0
  307. package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-314.pyc +0 -0
  308. package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-311.pyc +0 -0
  309. package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
  310. package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-311.pyc +0 -0
  311. package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
  312. package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-311.pyc +0 -0
  313. package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
  314. package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-311.pyc +0 -0
  315. package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
  316. package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-311.pyc +0 -0
  317. package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
  318. package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-311.pyc +0 -0
  319. package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
  320. package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-311.pyc +0 -0
  321. package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
  322. package/pennyfarthing_scripts/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
  323. package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-311.pyc +0 -0
  324. package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
  325. package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-311.pyc +0 -0
  326. package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
  327. package/pennyfarthing_scripts/hooks/bell_mode.py +0 -1
  328. package/pennyfarthing_scripts/hooks/pre_edit_check.py +0 -1
  329. package/pennyfarthing_scripts/hooks/reflector_check.py +1 -2
  330. package/pennyfarthing_scripts/hooks/schema_validation.py +0 -1
  331. package/pennyfarthing_scripts/hooks/session_start.py +6 -8
  332. package/pennyfarthing_scripts/hooks/statusline.py +10 -1
  333. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-311.pyc +0 -0
  334. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-311.pyc +0 -0
  335. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-311.pyc +0 -0
  336. package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-311.pyc +0 -0
  337. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-311.pyc +0 -0
  338. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-311.pyc +0 -0
  339. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-311.pyc +0 -0
  340. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-311.pyc +0 -0
  341. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-311.pyc +0 -0
  342. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-311.pyc +0 -0
  343. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-311.pyc +0 -0
  344. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-311.pyc +0 -0
  345. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-311.pyc +0 -0
  346. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-311.pyc +0 -0
  347. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-311.pyc +0 -0
  348. package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-311.pyc +0 -0
  349. package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-311.pyc +0 -0
  350. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  351. package/pennyfarthing_scripts/prime/heatmap.py +3 -15
  352. package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-311.pyc +0 -0
  353. package/pennyfarthing_scripts/session/__pycache__/cli.cpython-311.pyc +0 -0
  354. package/pennyfarthing_scripts/settings/__init__.py +0 -0
  355. package/pennyfarthing_scripts/settings/__pycache__/__init__.cpython-314.pyc +0 -0
  356. package/pennyfarthing_scripts/settings/__pycache__/cli.cpython-314.pyc +0 -0
  357. package/pennyfarthing_scripts/settings/__pycache__/settings.cpython-314.pyc +0 -0
  358. package/pennyfarthing_scripts/settings/cli.py +55 -0
  359. package/pennyfarthing_scripts/settings/settings.py +98 -0
  360. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-311.pyc +0 -0
  361. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-311.pyc +0 -0
  362. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-311.pyc +0 -0
  363. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  364. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-311.pyc +0 -0
  365. package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-311.pyc +0 -0
  366. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-311.pyc +0 -0
  367. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  368. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-311.pyc +0 -0
  369. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-311.pyc +0 -0
  370. package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
  371. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-311.pyc +0 -0
  372. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  373. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-311.pyc +0 -0
  374. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-311.pyc +0 -0
  375. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-311.pyc +0 -0
  376. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-311.pyc +0 -0
  377. package/pennyfarthing_scripts/sprint/cli.py +121 -0
  378. package/pennyfarthing_scripts/sprint/loader.py +154 -3
  379. package/pennyfarthing_scripts/sprint/story_update.py +7 -0
  380. package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
  381. package/pennyfarthing_scripts/tests/__pycache__/test_tui_focus.cpython-314-pytest-9.0.2.pyc +0 -0
  382. package/pennyfarthing_scripts/tests/__pycache__/test_tui_panel_persistence.cpython-314-pytest-9.0.2.pyc +0 -0
  383. package/pennyfarthing_scripts/tests/test_bikerack.py +26 -26
  384. package/pennyfarthing_scripts/tests/test_confidence_sm_gate.py +17 -16
  385. package/pennyfarthing_scripts/tests/test_dialogue_manager.py +0 -1
  386. package/pennyfarthing_scripts/tests/test_resolve_gate_file_field.py +45 -47
  387. package/pennyfarthing_scripts/tests/test_workflow_list_team.py +143 -0
  388. package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-311.pyc +0 -0
  389. package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-311.pyc +0 -0
  390. package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-311.pyc +0 -0
  391. package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-311.pyc +0 -0
  392. package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
  393. package/pennyfarthing_scripts/validate/adapters/team_mode.py +323 -0
  394. package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-311.pyc +0 -0
  395. package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
  396. package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-311.pyc +0 -0
  397. package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
  398. package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
  399. package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-311.pyc +0 -0
  400. package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
  401. package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-311.pyc +0 -0
  402. package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
  403. package/pennyfarthing_scripts/workflow/cli.py +15 -14
  404. package/pennyfarthing_scripts/workflow/state.py +0 -1
  405. package/pennyfarthing_scripts/workflow/team_lifecycle.py +3 -4
@@ -0,0 +1,382 @@
1
+ /**
2
+ * Tests for Story 117-2: Generate hook commands with pf.sh wrapper path, not bare pf
3
+ *
4
+ * Bug: migrateHookPaths() only migrates .sh file hooks to pf.sh commands.
5
+ * It does NOT migrate bare `pf hooks X` commands to `pf.sh hooks X`.
6
+ * Additionally, mergeSettingsLocalJson() detects bare `pf hooks X` as
7
+ * "already configured" and skips them, leaving broken commands in place.
8
+ *
9
+ * Acceptance Criteria:
10
+ * AC1: Hook generation uses $CLAUDE_PROJECT_DIR/.pennyfarthing/scripts/core/pf.sh wrapper path
11
+ * AC2: Generated settings.local.json hooks work without pf being in PATH
12
+ * AC3: Existing hook functionality preserved
13
+ *
14
+ * Run with: cd packages/core && npm run build && npm test
15
+ */
16
+ import { describe, it, beforeEach, afterEach } from 'node:test';
17
+ import assert from 'node:assert';
18
+ import { existsSync, mkdirSync, writeFileSync, rmSync, readFileSync, } from 'fs';
19
+ import { join } from 'path';
20
+ import { tmpdir } from 'os';
21
+ import { migrateHookPaths, mergeSettingsLocalJson, LEGACY_HOOK_MIGRATIONS, } from './settings.js';
22
+ // =============================================================================
23
+ // Helpers
24
+ // =============================================================================
25
+ const PF_SH_PREFIX = '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh';
26
+ function makeHookEntry(command, matcher) {
27
+ return {
28
+ ...(matcher !== undefined ? { matcher } : {}),
29
+ hooks: [{ type: 'command', command }],
30
+ };
31
+ }
32
+ // =============================================================================
33
+ // AC1: PF_SH constant and template use wrapper path
34
+ // =============================================================================
35
+ describe('117-2 AC1: Hook generation uses pf.sh wrapper path', () => {
36
+ it('should have PF_SH prefix in all LEGACY_HOOK_MIGRATIONS values', () => {
37
+ for (const [shName, pfCommand] of Object.entries(LEGACY_HOOK_MIGRATIONS)) {
38
+ assert.ok(pfCommand.includes('.pennyfarthing/scripts/core/pf.sh'), `Migration for ${shName} should use pf.sh wrapper, got: ${pfCommand}`);
39
+ }
40
+ });
41
+ it('should use $CLAUDE_PROJECT_DIR in all LEGACY_HOOK_MIGRATIONS values', () => {
42
+ for (const [shName, pfCommand] of Object.entries(LEGACY_HOOK_MIGRATIONS)) {
43
+ assert.ok(pfCommand.includes('$CLAUDE_PROJECT_DIR'), `Migration for ${shName} should use $CLAUDE_PROJECT_DIR, got: ${pfCommand}`);
44
+ }
45
+ });
46
+ });
47
+ // =============================================================================
48
+ // AC2: migrateHookPaths migrates bare `pf` to `pf.sh` wrapper
49
+ // =============================================================================
50
+ describe('117-2 AC2: migrateHookPaths migrates bare pf commands', () => {
51
+ it('should migrate bare "pf hooks session-start" to pf.sh wrapper', () => {
52
+ const hooks = [
53
+ makeHookEntry('pf hooks session-start'),
54
+ ];
55
+ const migrated = migrateHookPaths(hooks);
56
+ assert.ok(migrated, 'Should report migration occurred');
57
+ assert.ok(hooks[0].hooks[0].command.includes('pf.sh hooks session-start'), `Should migrate to pf.sh wrapper, got: ${hooks[0].hooks[0].command}`);
58
+ assert.ok(hooks[0].hooks[0].command.includes('$CLAUDE_PROJECT_DIR'), `Should include $CLAUDE_PROJECT_DIR, got: ${hooks[0].hooks[0].command}`);
59
+ });
60
+ it('should migrate bare "pf hooks reflector-check" to pf.sh wrapper', () => {
61
+ const hooks = [
62
+ makeHookEntry('pf hooks reflector-check'),
63
+ ];
64
+ const migrated = migrateHookPaths(hooks);
65
+ assert.ok(migrated, 'Should report migration occurred');
66
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks reflector-check`, 'Should use full pf.sh wrapper path');
67
+ });
68
+ it('should migrate bare "pf hooks bell-mode" to pf.sh wrapper', () => {
69
+ const hooks = [
70
+ makeHookEntry('pf hooks bell-mode'),
71
+ ];
72
+ const migrated = migrateHookPaths(hooks);
73
+ assert.ok(migrated, 'Should report migration occurred');
74
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks bell-mode`);
75
+ });
76
+ it('should migrate bare "pf hooks context-breaker" to pf.sh wrapper', () => {
77
+ const hooks = [
78
+ makeHookEntry('pf hooks context-breaker'),
79
+ ];
80
+ const migrated = migrateHookPaths(hooks);
81
+ assert.ok(migrated, 'Should report migration occurred');
82
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks context-breaker`);
83
+ });
84
+ it('should migrate bare "pf hooks statusline" to pf.sh wrapper', () => {
85
+ const hooks = [
86
+ makeHookEntry('pf hooks statusline'),
87
+ ];
88
+ const migrated = migrateHookPaths(hooks);
89
+ assert.ok(migrated, 'Should report migration occurred');
90
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks statusline`);
91
+ });
92
+ it('should migrate all known bare pf hook commands', () => {
93
+ const bareCommands = [
94
+ 'pf hooks session-start',
95
+ 'pf hooks session-stop',
96
+ 'pf hooks reflector-check',
97
+ 'pf hooks pre-edit-check',
98
+ 'pf hooks context-warning',
99
+ 'pf hooks context-breaker',
100
+ 'pf hooks cyclist-pretooluse',
101
+ 'pf hooks schema-validation',
102
+ 'pf hooks bell-mode',
103
+ 'pf hooks sprint-yaml',
104
+ 'pf hooks statusline',
105
+ ];
106
+ for (const bareCmd of bareCommands) {
107
+ const hooks = [makeHookEntry(bareCmd)];
108
+ const migrated = migrateHookPaths(hooks);
109
+ const subcommand = bareCmd.replace('pf hooks ', '');
110
+ assert.ok(migrated, `Should migrate "${bareCmd}"`);
111
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks ${subcommand}`, `"${bareCmd}" should become "${PF_SH_PREFIX} hooks ${subcommand}"`);
112
+ }
113
+ });
114
+ it('should migrate multiple bare pf commands in same hook array', () => {
115
+ const hooks = [
116
+ makeHookEntry('pf hooks session-start'),
117
+ makeHookEntry('pf hooks bell-mode'),
118
+ makeHookEntry('pf hooks context-breaker'),
119
+ ];
120
+ const migrated = migrateHookPaths(hooks);
121
+ assert.ok(migrated, 'Should report migration occurred');
122
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks session-start`);
123
+ assert.strictEqual(hooks[1].hooks[0].command, `${PF_SH_PREFIX} hooks bell-mode`);
124
+ assert.strictEqual(hooks[2].hooks[0].command, `${PF_SH_PREFIX} hooks context-breaker`);
125
+ });
126
+ it('should NOT migrate commands that already use pf.sh wrapper', () => {
127
+ const hooks = [
128
+ makeHookEntry(`${PF_SH_PREFIX} hooks session-start`),
129
+ ];
130
+ const migrated = migrateHookPaths(hooks);
131
+ assert.ok(!migrated, 'Should NOT report migration for already-correct commands');
132
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks session-start`, 'Should leave correct commands unchanged');
133
+ });
134
+ it('should NOT migrate non-pf commands', () => {
135
+ const hooks = [
136
+ makeHookEntry('custom-hook.sh'),
137
+ makeHookEntry('.pennyfarthing/project/hooks/setup-env.sh'),
138
+ ];
139
+ const migrated = migrateHookPaths(hooks);
140
+ assert.ok(!migrated, 'Should NOT migrate non-pf commands');
141
+ assert.strictEqual(hooks[0].hooks[0].command, 'custom-hook.sh');
142
+ assert.strictEqual(hooks[1].hooks[0].command, '.pennyfarthing/project/hooks/setup-env.sh');
143
+ });
144
+ it('should preserve matcher when migrating bare pf commands', () => {
145
+ const hooks = [
146
+ makeHookEntry('pf hooks sprint-yaml', 'Edit|Write'),
147
+ ];
148
+ const migrated = migrateHookPaths(hooks);
149
+ assert.ok(migrated, 'Should report migration occurred');
150
+ assert.strictEqual(hooks[0].matcher, 'Edit|Write', 'Should preserve matcher');
151
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks sprint-yaml`);
152
+ });
153
+ });
154
+ // =============================================================================
155
+ // AC2: mergeSettingsLocalJson replaces bare pf commands during merge
156
+ // =============================================================================
157
+ describe('117-2 AC2: mergeSettingsLocalJson fixes bare pf commands', () => {
158
+ let testDir;
159
+ let assetsPath;
160
+ beforeEach(() => {
161
+ testDir = join(tmpdir(), `pf-hook-migration-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
162
+ const pennyfarthingDir = join(testDir, '.pennyfarthing');
163
+ assetsPath = join(testDir, 'assets');
164
+ mkdirSync(join(testDir, '.claude'), { recursive: true });
165
+ mkdirSync(pennyfarthingDir, { recursive: true });
166
+ mkdirSync(join(assetsPath, 'templates'), { recursive: true });
167
+ // Template with correct pf.sh wrapper paths
168
+ writeFileSync(join(assetsPath, 'templates/settings.local.json.template'), JSON.stringify({
169
+ hooks: {
170
+ SessionStart: [
171
+ {
172
+ hooks: [{
173
+ type: 'command',
174
+ command: `${PF_SH_PREFIX} hooks session-start`,
175
+ }],
176
+ },
177
+ ],
178
+ Stop: [
179
+ {
180
+ hooks: [{
181
+ type: 'command',
182
+ command: `${PF_SH_PREFIX} hooks reflector-check`,
183
+ }],
184
+ },
185
+ ],
186
+ PostToolUse: [
187
+ {
188
+ hooks: [{
189
+ type: 'command',
190
+ command: `${PF_SH_PREFIX} hooks bell-mode`,
191
+ }],
192
+ },
193
+ ],
194
+ PreToolUse: [
195
+ {
196
+ matcher: 'Edit|Write|Bash|Task',
197
+ hooks: [{
198
+ type: 'command',
199
+ command: `${PF_SH_PREFIX} hooks context-breaker`,
200
+ }],
201
+ },
202
+ ],
203
+ },
204
+ statusLine: {
205
+ type: 'command',
206
+ command: `${PF_SH_PREFIX} hooks statusline`,
207
+ },
208
+ }, null, 2));
209
+ });
210
+ afterEach(() => {
211
+ if (existsSync(testDir)) {
212
+ rmSync(testDir, { recursive: true, force: true });
213
+ }
214
+ });
215
+ it('should migrate bare pf SessionStart hooks to pf.sh wrapper during merge', async () => {
216
+ // Consumer has bare `pf hooks` commands from old installation
217
+ const existingSettings = {
218
+ hooks: {
219
+ SessionStart: [
220
+ {
221
+ hooks: [{
222
+ type: 'command',
223
+ command: 'pf hooks session-start',
224
+ }],
225
+ },
226
+ ],
227
+ },
228
+ };
229
+ writeFileSync(join(testDir, '.pennyfarthing/settings.local.json'), JSON.stringify(existingSettings, null, 2));
230
+ await mergeSettingsLocalJson(testDir, assetsPath, {});
231
+ const result = JSON.parse(readFileSync(join(testDir, '.pennyfarthing/settings.local.json'), 'utf8'));
232
+ // The bare `pf hooks session-start` should be migrated to use pf.sh wrapper
233
+ const sessionStartCommands = result.hooks.SessionStart
234
+ .flatMap((e) => e.hooks?.map(h => h.command) ?? []);
235
+ const hasBareCommand = sessionStartCommands.some((cmd) => cmd === 'pf hooks session-start');
236
+ const hasWrapperCommand = sessionStartCommands.some((cmd) => cmd.includes('pf.sh hooks session-start'));
237
+ assert.ok(!hasBareCommand, 'Bare "pf hooks session-start" should be migrated away');
238
+ assert.ok(hasWrapperCommand, 'Should have pf.sh wrapper command after migration');
239
+ });
240
+ it('should migrate bare pf PostToolUse hooks during merge', async () => {
241
+ const existingSettings = {
242
+ hooks: {
243
+ PostToolUse: [
244
+ {
245
+ matcher: '',
246
+ hooks: [{
247
+ type: 'command',
248
+ command: 'pf hooks bell-mode',
249
+ }],
250
+ },
251
+ ],
252
+ },
253
+ };
254
+ writeFileSync(join(testDir, '.pennyfarthing/settings.local.json'), JSON.stringify(existingSettings, null, 2));
255
+ await mergeSettingsLocalJson(testDir, assetsPath, {});
256
+ const result = JSON.parse(readFileSync(join(testDir, '.pennyfarthing/settings.local.json'), 'utf8'));
257
+ const bellModeCommands = result.hooks.PostToolUse
258
+ .flatMap((e) => e.hooks?.map(h => h.command) ?? []);
259
+ const hasBareCommand = bellModeCommands.some((cmd) => cmd === 'pf hooks bell-mode');
260
+ assert.ok(!hasBareCommand, 'Bare "pf hooks bell-mode" should be migrated');
261
+ });
262
+ it('should migrate bare pf Stop hooks during merge', async () => {
263
+ const existingSettings = {
264
+ hooks: {
265
+ Stop: [
266
+ {
267
+ hooks: [{
268
+ type: 'command',
269
+ command: 'pf hooks reflector-check',
270
+ }],
271
+ },
272
+ {
273
+ hooks: [{
274
+ type: 'command',
275
+ command: 'pf hooks session-stop',
276
+ }],
277
+ },
278
+ ],
279
+ },
280
+ };
281
+ writeFileSync(join(testDir, '.pennyfarthing/settings.local.json'), JSON.stringify(existingSettings, null, 2));
282
+ await mergeSettingsLocalJson(testDir, assetsPath, {});
283
+ const result = JSON.parse(readFileSync(join(testDir, '.pennyfarthing/settings.local.json'), 'utf8'));
284
+ const stopCommands = result.hooks.Stop
285
+ .flatMap((e) => e.hooks?.map(h => h.command) ?? []);
286
+ const hasBareCommand = stopCommands.some((cmd) => cmd.startsWith('pf hooks') && !cmd.includes('pf.sh'));
287
+ assert.ok(!hasBareCommand, 'All bare "pf hooks" Stop commands should be migrated');
288
+ });
289
+ it('should migrate bare pf PreToolUse hooks during merge', async () => {
290
+ const existingSettings = {
291
+ hooks: {
292
+ PreToolUse: [
293
+ {
294
+ matcher: 'Edit|Write',
295
+ hooks: [{
296
+ type: 'command',
297
+ command: 'pf hooks pre-edit-check',
298
+ }],
299
+ },
300
+ {
301
+ matcher: 'Edit|Write|Bash|Task',
302
+ hooks: [{
303
+ type: 'command',
304
+ command: 'pf hooks context-breaker',
305
+ }],
306
+ },
307
+ ],
308
+ },
309
+ };
310
+ writeFileSync(join(testDir, '.pennyfarthing/settings.local.json'), JSON.stringify(existingSettings, null, 2));
311
+ await mergeSettingsLocalJson(testDir, assetsPath, {});
312
+ const result = JSON.parse(readFileSync(join(testDir, '.pennyfarthing/settings.local.json'), 'utf8'));
313
+ const preToolUseCommands = result.hooks.PreToolUse
314
+ .flatMap((e) => e.hooks?.map(h => h.command) ?? []);
315
+ const hasBareCommand = preToolUseCommands.some((cmd) => cmd.startsWith('pf hooks') && !cmd.includes('pf.sh'));
316
+ assert.ok(!hasBareCommand, 'All bare "pf hooks" PreToolUse commands should be migrated');
317
+ });
318
+ it('should migrate bare pf statusLine command during merge', async () => {
319
+ const existingSettings = {
320
+ hooks: {},
321
+ statusLine: {
322
+ type: 'command',
323
+ command: 'pf hooks statusline',
324
+ },
325
+ };
326
+ writeFileSync(join(testDir, '.pennyfarthing/settings.local.json'), JSON.stringify(existingSettings, null, 2));
327
+ await mergeSettingsLocalJson(testDir, assetsPath, {});
328
+ const result = JSON.parse(readFileSync(join(testDir, '.pennyfarthing/settings.local.json'), 'utf8'));
329
+ assert.ok(result.statusLine.command.includes('pf.sh hooks statusline'), `statusLine should use pf.sh wrapper, got: ${result.statusLine.command}`);
330
+ assert.ok(result.statusLine.command !== 'pf hooks statusline', 'Bare "pf hooks statusline" should be migrated');
331
+ });
332
+ });
333
+ // =============================================================================
334
+ // AC3: Existing hook functionality preserved
335
+ // =============================================================================
336
+ describe('117-2 AC3: Existing hook functionality preserved', () => {
337
+ it('should still migrate .sh file hooks to pf.sh wrapper (legacy migration)', () => {
338
+ const hooks = [
339
+ makeHookEntry('session-start.sh'),
340
+ makeHookEntry('bell-mode-hook.sh'),
341
+ ];
342
+ const migrated = migrateHookPaths(hooks);
343
+ assert.ok(migrated, 'Should migrate .sh hooks');
344
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks session-start`, '.sh file should migrate to pf.sh wrapper');
345
+ assert.strictEqual(hooks[1].hooks[0].command, `${PF_SH_PREFIX} hooks bell-mode`, '.sh file should migrate to pf.sh wrapper');
346
+ });
347
+ it('should still migrate legacy directory paths', () => {
348
+ const hooks = [
349
+ makeHookEntry('.claude/pennyfarthing/scripts/custom-script.sh'),
350
+ ];
351
+ const migrated = migrateHookPaths(hooks);
352
+ assert.ok(migrated, 'Should migrate legacy paths');
353
+ assert.strictEqual(hooks[0].hooks[0].command, '.pennyfarthing/scripts/custom-script.sh', 'Legacy directory path should be migrated');
354
+ });
355
+ it('should handle mixed .sh, bare pf, and pf.sh commands in same array', () => {
356
+ const hooks = [
357
+ makeHookEntry('session-start.sh'), // legacy .sh
358
+ makeHookEntry('pf hooks bell-mode'), // bare pf
359
+ makeHookEntry(`${PF_SH_PREFIX} hooks context-breaker`), // already correct
360
+ makeHookEntry('.pennyfarthing/project/hooks/setup-env.sh'), // custom, leave alone
361
+ ];
362
+ const migrated = migrateHookPaths(hooks);
363
+ assert.ok(migrated, 'Should report migration for .sh and bare pf');
364
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks session-start`, '.sh file migrated');
365
+ assert.strictEqual(hooks[1].hooks[0].command, `${PF_SH_PREFIX} hooks bell-mode`, 'bare pf migrated');
366
+ assert.strictEqual(hooks[2].hooks[0].command, `${PF_SH_PREFIX} hooks context-breaker`, 'already correct left alone');
367
+ assert.strictEqual(hooks[3].hooks[0].command, '.pennyfarthing/project/hooks/setup-env.sh', 'custom hook left alone');
368
+ });
369
+ it('should not produce duplicate hooks after migration', () => {
370
+ // Consumer has BOTH bare pf and pf.sh for the same hook
371
+ const hooks = [
372
+ makeHookEntry('pf hooks session-start'),
373
+ makeHookEntry(`${PF_SH_PREFIX} hooks session-start`),
374
+ ];
375
+ migrateHookPaths(hooks);
376
+ // After migration, both should point to the same command
377
+ // The deduplication happens at a higher level, but migration should still work
378
+ assert.strictEqual(hooks[0].hooks[0].command, `${PF_SH_PREFIX} hooks session-start`);
379
+ assert.strictEqual(hooks[1].hooks[0].command, `${PF_SH_PREFIX} hooks session-start`);
380
+ });
381
+ });
382
+ //# sourceMappingURL=settings-hook-migration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-hook-migration.test.js","sourceRoot":"","sources":["../../../src/cli/utils/settings-hook-migration.test.ts"],"names":[],"mappings":"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"}
@@ -6,10 +6,6 @@
6
6
  * Get list of installed skill names from the skills directory
7
7
  */
8
8
  export declare function getInstalledSkillNames(projectRoot: string): string[];
9
- /**
10
- * Map of legacy .sh hook commands to their `pf hooks` replacements.
11
- * Used during init/update/doctor to migrate existing settings.
12
- */
13
9
  export declare const LEGACY_HOOK_MIGRATIONS: Record<string, string>;
14
10
  /**
15
11
  * Migrate hook paths from legacy locations to .pennyfarthing/scripts/
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/settings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBpE;AA+BD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAazD,CAAC;AAoBF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,OAAO,CAyC9D;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,GACtD,OAAO,CAAC,OAAO,CAAC,CA4PlB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAkB/D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CA8B7D"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/settings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAeH;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBpE;AAyCD,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAazD,CAAC;AAoBF;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,OAAO,EAAE,GAAG,OAAO,CAiD9D;AAED;;;;;;;;GAQG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,GACtD,OAAO,CAAC,OAAO,CAAC,CAiQlB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAkB/D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CA8B7D"}
@@ -65,19 +65,24 @@ const LEGACY_PROJECT_HOOK_PATHS = [
65
65
  * Map of legacy .sh hook commands to their `pf hooks` replacements.
66
66
  * Used during init/update/doctor to migrate existing settings.
67
67
  */
68
+ /**
69
+ * Canonical hook command prefix — uses pf.sh wrapper (no global pf install needed).
70
+ * $CLAUDE_PROJECT_DIR is set by Claude Code for hook execution contexts.
71
+ */
72
+ const PF_SH = '"$CLAUDE_PROJECT_DIR"/.pennyfarthing/scripts/core/pf.sh';
68
73
  export const LEGACY_HOOK_MIGRATIONS = {
69
- 'session-start.sh': 'pf hooks session-start',
70
- 'welcome-hook.sh': 'pf hooks session-start',
71
- 'question-reflector-check.sh': 'pf hooks reflector-check',
72
- 'session-stop.sh': 'pf hooks session-stop',
73
- 'pre-edit-check.sh': 'pf hooks pre-edit-check',
74
- 'context-warning.sh': 'pf hooks context-warning',
75
- 'context-circuit-breaker.sh': 'pf hooks context-breaker',
76
- 'cyclist-pretooluse-hook.sh': 'pf hooks cyclist-pretooluse',
77
- 'schema-validation.sh': 'pf hooks schema-validation',
78
- 'bell-mode-hook.sh': 'pf hooks bell-mode',
79
- 'sprint-yaml-validation.sh': 'pf hooks sprint-yaml',
80
- 'statusline.sh': 'pf hooks statusline',
74
+ 'session-start.sh': `${PF_SH} hooks session-start`,
75
+ 'welcome-hook.sh': `${PF_SH} hooks session-start`,
76
+ 'question-reflector-check.sh': `${PF_SH} hooks reflector-check`,
77
+ 'session-stop.sh': `${PF_SH} hooks session-stop`,
78
+ 'pre-edit-check.sh': `${PF_SH} hooks pre-edit-check`,
79
+ 'context-warning.sh': `${PF_SH} hooks context-warning`,
80
+ 'context-circuit-breaker.sh': `${PF_SH} hooks context-breaker`,
81
+ 'cyclist-pretooluse-hook.sh': `${PF_SH} hooks cyclist-pretooluse`,
82
+ 'schema-validation.sh': `${PF_SH} hooks schema-validation`,
83
+ 'bell-mode-hook.sh': `${PF_SH} hooks bell-mode`,
84
+ 'sprint-yaml-validation.sh': `${PF_SH} hooks sprint-yaml`,
85
+ 'statusline.sh': `${PF_SH} hooks statusline`,
81
86
  };
82
87
  /**
83
88
  * Check if a hook entry contains a specific hook by command substring
@@ -120,6 +125,13 @@ export function migrateHookPaths(hookArray) {
120
125
  }
121
126
  if (shMigrated)
122
127
  continue;
128
+ // Migrate bare `pf hooks X` commands to pf.sh wrapper path
129
+ if (h.command.startsWith('pf hooks ') && !h.command.includes('pf.sh')) {
130
+ const subcommand = h.command.replace('pf hooks ', '');
131
+ h.command = `${PF_SH} hooks ${subcommand}`;
132
+ migrated = true;
133
+ continue;
134
+ }
123
135
  // Legacy directory path migrations (for non-hook scripts)
124
136
  for (const legacyPath of LEGACY_SCRIPT_PATHS) {
125
137
  if (h.command.includes(legacyPath)) {
@@ -206,9 +218,9 @@ export async function mergeSettingsLocalJson(projectRoot, assetsPath, options) {
206
218
  logger.info('Added missing SessionStart hooks');
207
219
  }
208
220
  else if (Array.isArray(hooks.SessionStart)) {
209
- const hasSessionStartHook = hooks.SessionStart.some((entry) => hookEntryContains(entry, 'session-start.sh') || hookEntryContains(entry, 'pf hooks session-start'));
221
+ const hasSessionStartHook = hooks.SessionStart.some((entry) => hookEntryContains(entry, 'session-start.sh') || hookEntryContains(entry, 'pf.sh hooks session-start') || hookEntryContains(entry, 'pf hooks session-start'));
210
222
  if (!hasSessionStartHook && templateContent.hooks?.SessionStart) {
211
- const sessionStartEntry = findHookEntry(templateContent.hooks.SessionStart, 'pf hooks session-start');
223
+ const sessionStartEntry = findHookEntry(templateContent.hooks.SessionStart, 'pf.sh hooks session-start');
212
224
  if (sessionStartEntry) {
213
225
  hooks.SessionStart = [sessionStartEntry, ...hooks.SessionStart];
214
226
  modified = true;
@@ -239,9 +251,9 @@ export async function mergeSettingsLocalJson(projectRoot, assetsPath, options) {
239
251
  logger.info('Added missing Stop hooks');
240
252
  }
241
253
  else if (Array.isArray(hooks.Stop)) {
242
- const hasReflectorHook = hooks.Stop.some((entry) => hookEntryContains(entry, 'question-reflector-check') || hookEntryContains(entry, 'pf hooks reflector-check'));
254
+ const hasReflectorHook = hooks.Stop.some((entry) => hookEntryContains(entry, 'question-reflector-check') || hookEntryContains(entry, 'pf.sh hooks reflector-check') || hookEntryContains(entry, 'pf hooks reflector-check'));
243
255
  if (!hasReflectorHook && templateContent.hooks?.Stop) {
244
- const reflectorEntry = findHookEntry(templateContent.hooks.Stop, 'pf hooks reflector-check');
256
+ const reflectorEntry = findHookEntry(templateContent.hooks.Stop, 'pf.sh hooks reflector-check');
245
257
  if (reflectorEntry) {
246
258
  hooks.Stop = [reflectorEntry, ...hooks.Stop];
247
259
  modified = true;
@@ -256,9 +268,9 @@ export async function mergeSettingsLocalJson(projectRoot, assetsPath, options) {
256
268
  logger.info('Added missing PostToolUse hooks');
257
269
  }
258
270
  else if (Array.isArray(hooks.PostToolUse)) {
259
- const hasBellModeHook = hooks.PostToolUse.some((entry) => hookEntryContains(entry, 'bell-mode-hook') || hookEntryContains(entry, 'pf hooks bell-mode'));
271
+ const hasBellModeHook = hooks.PostToolUse.some((entry) => hookEntryContains(entry, 'bell-mode-hook') || hookEntryContains(entry, 'pf.sh hooks bell-mode') || hookEntryContains(entry, 'pf hooks bell-mode'));
260
272
  if (!hasBellModeHook && templateContent.hooks?.PostToolUse) {
261
- const bellModeEntry = findHookEntry(templateContent.hooks.PostToolUse, 'pf hooks bell-mode');
273
+ const bellModeEntry = findHookEntry(templateContent.hooks.PostToolUse, 'pf.sh hooks bell-mode');
262
274
  if (bellModeEntry) {
263
275
  hooks.PostToolUse = [bellModeEntry, ...hooks.PostToolUse];
264
276
  modified = true;
@@ -274,9 +286,9 @@ export async function mergeSettingsLocalJson(projectRoot, assetsPath, options) {
274
286
  }
275
287
  else if (Array.isArray(hooks.PreToolUse)) {
276
288
  // Check for context-circuit-breaker / context-breaker
277
- const hasCircuitBreaker = hooks.PreToolUse.some((entry) => hookEntryContains(entry, 'context-circuit-breaker') || hookEntryContains(entry, 'pf hooks context-breaker'));
289
+ const hasCircuitBreaker = hooks.PreToolUse.some((entry) => hookEntryContains(entry, 'context-circuit-breaker') || hookEntryContains(entry, 'pf.sh hooks context-breaker') || hookEntryContains(entry, 'pf hooks context-breaker'));
278
290
  if (!hasCircuitBreaker && templateContent.hooks?.PreToolUse) {
279
- const circuitBreakerEntry = findHookEntry(templateContent.hooks.PreToolUse, 'pf hooks context-breaker');
291
+ const circuitBreakerEntry = findHookEntry(templateContent.hooks.PreToolUse, 'pf.sh hooks context-breaker');
280
292
  if (circuitBreakerEntry) {
281
293
  hooks.PreToolUse = [...hooks.PreToolUse, circuitBreakerEntry];
282
294
  modified = true;
@@ -286,7 +298,7 @@ export async function mergeSettingsLocalJson(projectRoot, assetsPath, options) {
286
298
  // Check for schema-validation hook
287
299
  const hasSchemaValidation = hooks.PreToolUse.some((entry) => hookEntryContains(entry, 'schema-validation'));
288
300
  if (!hasSchemaValidation && templateContent.hooks?.PreToolUse) {
289
- const schemaValidationEntry = findHookEntry(templateContent.hooks.PreToolUse, 'pf hooks schema-validation');
301
+ const schemaValidationEntry = findHookEntry(templateContent.hooks.PreToolUse, 'pf.sh hooks schema-validation');
290
302
  if (schemaValidationEntry) {
291
303
  hooks.PreToolUse = [...hooks.PreToolUse, schemaValidationEntry];
292
304
  modified = true;
@@ -294,9 +306,9 @@ export async function mergeSettingsLocalJson(projectRoot, assetsPath, options) {
294
306
  }
295
307
  }
296
308
  // Check for cyclist-pretooluse hook (Cyclist permissions integration)
297
- const hasCyclistPreToolUse = hooks.PreToolUse.some((entry) => hookEntryContains(entry, 'cyclist-pretooluse') || hookEntryContains(entry, 'pf hooks cyclist-pretooluse'));
309
+ const hasCyclistPreToolUse = hooks.PreToolUse.some((entry) => hookEntryContains(entry, 'cyclist-pretooluse') || hookEntryContains(entry, 'pf.sh hooks cyclist-pretooluse') || hookEntryContains(entry, 'pf hooks cyclist-pretooluse'));
298
310
  if (!hasCyclistPreToolUse && templateContent.hooks?.PreToolUse) {
299
- const cyclistEntry = findHookEntry(templateContent.hooks.PreToolUse, 'pf hooks cyclist-pretooluse');
311
+ const cyclistEntry = findHookEntry(templateContent.hooks.PreToolUse, 'pf.sh hooks cyclist-pretooluse');
300
312
  if (cyclistEntry) {
301
313
  hooks.PreToolUse = [...hooks.PreToolUse, cyclistEntry];
302
314
  modified = true;
@@ -312,13 +324,19 @@ export async function mergeSettingsLocalJson(projectRoot, assetsPath, options) {
312
324
  logger.info('Added missing statusLine configuration');
313
325
  }
314
326
  else if (statusLine.command && typeof statusLine.command === 'string') {
315
- // Migrate from any legacy .sh path to pf hooks statusline
316
- if (statusLine.command !== 'pf hooks statusline') {
327
+ // Migrate bare `pf hooks statusline` to pf.sh wrapper path
328
+ if (statusLine.command === 'pf hooks statusline') {
329
+ statusLine.command = `${PF_SH} hooks statusline`;
330
+ modified = true;
331
+ logger.info('Migrated statusLine from bare pf to pf.sh wrapper');
332
+ }
333
+ else if (!statusLine.command.includes('pf.sh hooks statusline')) {
334
+ // Migrate from any legacy .sh path to pf.sh hooks statusline
317
335
  for (const legacyPath of LEGACY_STATUSLINE_PATHS) {
318
336
  if (statusLine.command.includes(legacyPath)) {
319
- statusLine.command = 'pf hooks statusline';
337
+ statusLine.command = `${PF_SH} hooks statusline`;
320
338
  modified = true;
321
- logger.info('Migrated statusLine from .sh to pf hooks statusline');
339
+ logger.info('Migrated statusLine to pf.sh hooks statusline');
322
340
  break;
323
341
  }
324
342
  }