@pennyfarthing/core 11.1.1 → 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 (487) hide show
  1. package/README.md +8 -8
  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/otlp-receiver.d.ts +16 -11
  41. package/packages/core/dist/server/otlp-receiver.d.ts.map +1 -1
  42. package/packages/core/dist/server/otlp-receiver.js +185 -24
  43. package/packages/core/dist/server/otlp-receiver.js.map +1 -1
  44. package/packages/core/dist/server/otlp-receiver.test.d.ts +21 -0
  45. package/packages/core/dist/server/otlp-receiver.test.d.ts.map +1 -0
  46. package/packages/core/dist/server/otlp-receiver.test.js +446 -0
  47. package/packages/core/dist/server/otlp-receiver.test.js.map +1 -0
  48. package/packages/core/dist/server/server.d.ts +0 -3
  49. package/packages/core/dist/server/server.d.ts.map +1 -1
  50. package/packages/core/dist/server/server.js +3 -37
  51. package/packages/core/dist/server/server.js.map +1 -1
  52. package/packages/core/dist/server/server.test.d.ts +1 -1
  53. package/packages/core/dist/server/server.test.js +12 -23
  54. package/packages/core/dist/server/server.test.js.map +1 -1
  55. package/packages/core/dist/shared/capabilities.d.ts +88 -0
  56. package/packages/core/dist/shared/capabilities.d.ts.map +1 -0
  57. package/packages/core/dist/shared/capabilities.js +133 -0
  58. package/packages/core/dist/shared/capabilities.js.map +1 -0
  59. package/packages/core/dist/shared/capabilities.test.d.ts +2 -0
  60. package/packages/core/dist/shared/capabilities.test.d.ts.map +1 -0
  61. package/packages/core/dist/shared/capabilities.test.js +217 -0
  62. package/packages/core/dist/shared/capabilities.test.js.map +1 -0
  63. package/packages/core/dist/shared/portrait-resolver.d.ts +9 -0
  64. package/packages/core/dist/shared/portrait-resolver.d.ts.map +1 -1
  65. package/packages/core/dist/shared/portrait-resolver.js +27 -0
  66. package/packages/core/dist/shared/portrait-resolver.js.map +1 -1
  67. package/packages/core/dist/shared/portrait-resolver.test.js +47 -1
  68. package/packages/core/dist/shared/portrait-resolver.test.js.map +1 -1
  69. package/packages/core/dist/shared/spawn-prompt.d.ts +47 -0
  70. package/packages/core/dist/shared/spawn-prompt.d.ts.map +1 -0
  71. package/packages/core/dist/shared/spawn-prompt.js +82 -0
  72. package/packages/core/dist/shared/spawn-prompt.js.map +1 -0
  73. package/packages/core/dist/shared/spawn-prompt.test.d.ts +2 -0
  74. package/packages/core/dist/shared/spawn-prompt.test.d.ts.map +1 -0
  75. package/packages/core/dist/shared/spawn-prompt.test.js +251 -0
  76. package/packages/core/dist/shared/spawn-prompt.test.js.map +1 -0
  77. package/packages/core/dist/shared/tandem-portrait-inventory.test.d.ts +13 -0
  78. package/packages/core/dist/shared/tandem-portrait-inventory.test.d.ts.map +1 -0
  79. package/packages/core/dist/shared/tandem-portrait-inventory.test.js +126 -0
  80. package/packages/core/dist/shared/tandem-portrait-inventory.test.js.map +1 -0
  81. package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts +18 -0
  82. package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts.map +1 -0
  83. package/packages/core/dist/workflow/tandem-workflow-templates.test.js +434 -0
  84. package/packages/core/dist/workflow/tandem-workflow-templates.test.js.map +1 -0
  85. package/packages/core/dist/workflow/workflow-schema.d.ts +32 -0
  86. package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -1
  87. package/packages/core/dist/workflow/workflow-schema.js +120 -0
  88. package/packages/core/dist/workflow/workflow-schema.js.map +1 -1
  89. package/packages/core/dist/workflow/workflow-schema.test.d.ts.map +1 -1
  90. package/packages/core/dist/workflow/workflow-schema.test.js +570 -1
  91. package/packages/core/dist/workflow/workflow-schema.test.js.map +1 -1
  92. package/pennyfarthing-dist/agents/dev.md +7 -11
  93. package/pennyfarthing-dist/agents/reviewer.md +9 -3
  94. package/pennyfarthing-dist/agents/sm-finish.md +18 -1
  95. package/pennyfarthing-dist/agents/sm-setup.md +1 -1
  96. package/pennyfarthing-dist/agents/sm.md +2 -2
  97. package/pennyfarthing-dist/agents/tea.md +1 -1
  98. package/pennyfarthing-dist/agents/testing-runner.md +2 -1
  99. package/pennyfarthing-dist/commands/pf-chore.md +2 -2
  100. package/pennyfarthing-dist/commands/pf-git.md +4 -2
  101. package/pennyfarthing-dist/commands/pf-standalone.md +7 -2
  102. package/pennyfarthing-dist/gates/approval.md +63 -0
  103. package/pennyfarthing-dist/gates/confidence-sm.md +71 -0
  104. package/pennyfarthing-dist/gates/context-ok.md +56 -0
  105. package/pennyfarthing-dist/gates/evaluations/confidence-sm.md +54 -0
  106. package/pennyfarthing-dist/gates/quality-pass.md +67 -0
  107. package/pennyfarthing-dist/gates/tests-fail.md +84 -0
  108. package/pennyfarthing-dist/gates/tests-pass.md +79 -0
  109. package/pennyfarthing-dist/guides/agent-behavior.md +23 -19
  110. package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +1 -1
  111. package/pennyfarthing-dist/guides/bell-mode.md +1 -1
  112. package/pennyfarthing-dist/guides/bikerack.md +3 -3
  113. package/pennyfarthing-dist/guides/hooks.md +29 -29
  114. package/pennyfarthing-dist/guides/reflector.md +1 -1
  115. package/pennyfarthing-dist/guides/tandem-protocol.md +3 -3
  116. package/pennyfarthing-dist/guides/worktree-mode.md +3 -3
  117. package/pennyfarthing-dist/guides/xml-tags.md +2 -2
  118. package/pennyfarthing-dist/scripts/README.md +1 -1
  119. package/pennyfarthing-dist/scripts/core/check-context.sh +3 -1
  120. package/pennyfarthing-dist/scripts/core/phase-check-start.sh +5 -87
  121. package/pennyfarthing-dist/scripts/git/README.md +24 -14
  122. package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +5 -266
  123. package/pennyfarthing-dist/scripts/git/git-status-all.sh +5 -151
  124. package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +6 -144
  125. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +5 -496
  126. package/pennyfarthing-dist/scripts/hooks/README.md +6 -6
  127. package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
  128. package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +4 -183
  129. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +4 -95
  130. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +4 -65
  131. package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +3 -31
  132. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +9 -11
  133. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +27 -33
  134. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +4 -71
  135. package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +3 -19
  136. package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +4 -30
  137. package/pennyfarthing-dist/scripts/hooks/session-start.sh +3 -32
  138. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +4 -65
  139. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +4 -78
  140. package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +4 -93
  141. package/pennyfarthing-dist/scripts/misc/README.md +1 -1
  142. package/pennyfarthing-dist/scripts/misc/statusline.sh +4 -301
  143. package/pennyfarthing-dist/scripts/portraits/generate-tandem-portraits.sh +76 -0
  144. package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +4 -221
  145. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +5 -13
  146. package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +4 -123
  147. package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +4 -33
  148. package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +4 -156
  149. package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +4 -131
  150. package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +4 -249
  151. package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +4 -160
  152. package/pennyfarthing-dist/skills/pf-bc/usage.md +1 -1
  153. package/pennyfarthing-dist/skills/pf-jira/examples.md +5 -2
  154. package/pennyfarthing-dist/skills/pf-workflow/examples.md +27 -16
  155. package/pennyfarthing-dist/skills/pf-workflow/skill.md +9 -12
  156. package/pennyfarthing-dist/skills/pf-workflow/usage.md +33 -8
  157. package/pennyfarthing-dist/templates/settings.local.json.template +19 -10
  158. package/pennyfarthing-dist/workflows/bdd-tandem.yaml +18 -6
  159. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +1 -1
  160. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +1 -1
  161. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +1 -1
  162. package/pennyfarthing-dist/workflows/review-tandem.yaml +65 -0
  163. package/pennyfarthing-dist/workflows/tdd-tandem.yaml +16 -8
  164. package/pennyfarthing-dist/workflows/tdd.yaml +11 -2
  165. package/pennyfarthing_scripts/CLAUDE.md +45 -14
  166. package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  167. package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  168. package/pennyfarthing_scripts/__pycache__/bellmode_hook.cpython-314.pyc +0 -0
  169. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  170. package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
  171. package/pennyfarthing_scripts/__pycache__/context.cpython-314.pyc +0 -0
  172. package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
  174. package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
  179. package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
  180. package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
  181. package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
  182. package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
  183. package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
  184. package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
  185. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  186. package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-314.pyc +0 -0
  187. package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
  188. package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
  189. package/pennyfarthing_scripts/bc/cli.py +3 -5
  190. package/pennyfarthing_scripts/bellmode_hook.py +12 -296
  191. package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
  192. package/pennyfarthing_scripts/bikerack/__pycache__/__main__.cpython-314.pyc +0 -0
  193. package/pennyfarthing_scripts/bikerack/__pycache__/audit_log_panel.cpython-314.pyc +0 -0
  194. package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
  195. package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
  196. package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
  197. package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
  198. package/pennyfarthing_scripts/bikerack/__pycache__/context_meter_footer.cpython-314.pyc +0 -0
  199. package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
  200. package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
  201. package/pennyfarthing_scripts/bikerack/__pycache__/events.cpython-314.pyc +0 -0
  202. package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
  203. package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
  204. package/pennyfarthing_scripts/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
  205. package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
  206. package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
  207. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
  208. package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
  209. package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
  210. package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
  211. package/pennyfarthing_scripts/bikerack/audit_log_panel.py +119 -0
  212. package/pennyfarthing_scripts/bikerack/background_panel.py +86 -5
  213. package/pennyfarthing_scripts/bikerack/base_panel.py +87 -2
  214. package/pennyfarthing_scripts/bikerack/changed_panel.py +125 -29
  215. package/pennyfarthing_scripts/bikerack/context_meter_footer.py +88 -0
  216. package/pennyfarthing_scripts/bikerack/debug_panel.py +32 -2
  217. package/pennyfarthing_scripts/bikerack/diffs_panel.py +104 -17
  218. package/pennyfarthing_scripts/bikerack/events.py +28 -0
  219. package/pennyfarthing_scripts/bikerack/git_panel.py +103 -33
  220. package/pennyfarthing_scripts/bikerack/launcher.py +15 -15
  221. package/pennyfarthing_scripts/bikerack/portrait_resolver.py +139 -0
  222. package/pennyfarthing_scripts/bikerack/progress_panel.py +315 -0
  223. package/pennyfarthing_scripts/bikerack/sprint_panel.py +395 -32
  224. package/pennyfarthing_scripts/bikerack/story_detail_data.py +244 -0
  225. package/pennyfarthing_scripts/bikerack/story_detail_screen.py +176 -0
  226. package/pennyfarthing_scripts/bikerack/tui.py +575 -37
  227. package/pennyfarthing_scripts/bikerack/ws_client.py +2 -2
  228. package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
  229. package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
  230. package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
  231. package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
  232. package/pennyfarthing_scripts/cli.py +42 -65
  233. package/pennyfarthing_scripts/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
  234. package/pennyfarthing_scripts/codemarkers/__pycache__/__main__.cpython-314.pyc +0 -0
  235. package/pennyfarthing_scripts/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
  236. package/pennyfarthing_scripts/codemarkers/__pycache__/cli.cpython-314.pyc +0 -0
  237. package/pennyfarthing_scripts/codemarkers/__pycache__/formatters.cpython-314.pyc +0 -0
  238. package/pennyfarthing_scripts/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
  239. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
  240. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  241. package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
  242. package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
  243. package/pennyfarthing_scripts/common/pr_config.py +38 -0
  244. package/pennyfarthing_scripts/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
  245. package/pennyfarthing_scripts/complexity/__pycache__/__main__.cpython-314.pyc +0 -0
  246. package/pennyfarthing_scripts/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
  247. package/pennyfarthing_scripts/complexity/__pycache__/cli.cpython-314.pyc +0 -0
  248. package/pennyfarthing_scripts/complexity/__pycache__/formatters.cpython-314.pyc +0 -0
  249. package/pennyfarthing_scripts/complexity/__pycache__/models.cpython-314.pyc +0 -0
  250. package/pennyfarthing_scripts/consultation/__init__.py +1 -0
  251. package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
  252. package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
  253. package/pennyfarthing_scripts/consultation/__pycache__/dialogue_manager.cpython-314.pyc +0 -0
  254. package/pennyfarthing_scripts/consultation/cli.py +149 -0
  255. package/pennyfarthing_scripts/consultation/dialogue_manager.py +417 -0
  256. package/pennyfarthing_scripts/context.py +3 -3
  257. package/pennyfarthing_scripts/deadcode/__pycache__/__init__.cpython-314.pyc +0 -0
  258. package/pennyfarthing_scripts/deadcode/__pycache__/__main__.cpython-314.pyc +0 -0
  259. package/pennyfarthing_scripts/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
  260. package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
  261. package/pennyfarthing_scripts/deadcode/__pycache__/formatters.cpython-314.pyc +0 -0
  262. package/pennyfarthing_scripts/deadcode/__pycache__/models.cpython-314.pyc +0 -0
  263. package/pennyfarthing_scripts/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
  264. package/pennyfarthing_scripts/dependencies/__pycache__/__main__.cpython-314.pyc +0 -0
  265. package/pennyfarthing_scripts/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
  266. package/pennyfarthing_scripts/dependencies/__pycache__/cli.cpython-314.pyc +0 -0
  267. package/pennyfarthing_scripts/dependencies/__pycache__/formatters.cpython-314.pyc +0 -0
  268. package/pennyfarthing_scripts/dependencies/__pycache__/models.cpython-314.pyc +0 -0
  269. package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-314.pyc +0 -0
  270. package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-314.pyc +0 -0
  271. package/pennyfarthing_scripts/git/__init__.py +12 -1
  272. package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
  273. package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
  274. package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
  275. package/pennyfarthing_scripts/git/create_branches.py +3 -4
  276. package/pennyfarthing_scripts/git/hooks_installer.py +152 -0
  277. package/pennyfarthing_scripts/git/repos.py +196 -0
  278. package/pennyfarthing_scripts/git/status_all.py +27 -11
  279. package/pennyfarthing_scripts/git/worktree.py +302 -0
  280. package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-314.pyc +0 -0
  281. package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
  282. package/pennyfarthing_scripts/git_group/cli.py +143 -40
  283. package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
  284. package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
  285. package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
  286. package/pennyfarthing_scripts/handoff/__pycache__/gate_file.cpython-314.pyc +0 -0
  287. package/pennyfarthing_scripts/handoff/__pycache__/gate_runner.cpython-314.pyc +0 -0
  288. package/pennyfarthing_scripts/handoff/__pycache__/marker.cpython-314.pyc +0 -0
  289. package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
  290. package/pennyfarthing_scripts/handoff/cli.py +33 -1
  291. package/pennyfarthing_scripts/handoff/complete_phase.py +40 -0
  292. package/pennyfarthing_scripts/handoff/marker.py +15 -15
  293. package/pennyfarthing_scripts/handoff/phase_check.py +96 -0
  294. package/pennyfarthing_scripts/handoff/resolve_gate.py +18 -15
  295. package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
  296. package/pennyfarthing_scripts/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
  297. package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
  298. package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
  299. package/pennyfarthing_scripts/healthscore/__pycache__/formatters.cpython-314.pyc +0 -0
  300. package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-314.pyc +0 -0
  301. package/pennyfarthing_scripts/hooks/__init__.py +437 -0
  302. package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
  303. package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
  304. package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-314.pyc +0 -0
  305. package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
  306. package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
  307. package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
  308. package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
  309. package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
  310. package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
  311. package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
  312. package/pennyfarthing_scripts/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
  313. package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
  314. package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
  315. package/pennyfarthing_scripts/hooks/bell_mode.py +215 -0
  316. package/pennyfarthing_scripts/hooks/cli.py +96 -0
  317. package/pennyfarthing_scripts/hooks/context_breaker.py +104 -0
  318. package/pennyfarthing_scripts/hooks/context_warning.py +66 -0
  319. package/pennyfarthing_scripts/hooks/cyclist_pretooluse.py +129 -0
  320. package/pennyfarthing_scripts/hooks/pre_edit_check.py +78 -0
  321. package/pennyfarthing_scripts/hooks/reflector_check.py +271 -0
  322. package/pennyfarthing_scripts/hooks/schema_validation.py +203 -0
  323. package/pennyfarthing_scripts/hooks/session_start.py +296 -0
  324. package/pennyfarthing_scripts/hooks/session_stop.py +111 -0
  325. package/pennyfarthing_scripts/hooks/sprint_yaml_validation.py +97 -0
  326. package/pennyfarthing_scripts/hooks/statusline.py +420 -0
  327. package/pennyfarthing_scripts/hooks.py +27 -446
  328. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
  329. package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
  330. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
  331. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
  332. package/pennyfarthing_scripts/hotspots/__pycache__/formatters.cpython-314.pyc +0 -0
  333. package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
  334. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  335. package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
  336. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  337. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
  338. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  339. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  340. package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
  341. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
  342. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
  343. package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
  344. package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
  345. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
  346. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  347. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
  348. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
  349. package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-314.pyc +0 -0
  350. package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-314.pyc +0 -0
  351. package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
  352. package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
  353. package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
  354. package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
  355. package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
  356. package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
  357. package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
  358. package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
  359. package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
  360. package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
  361. package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
  362. package/pennyfarthing_scripts/pretooluse_hook.py +3 -185
  363. package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  364. package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
  365. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  366. package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
  367. package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
  368. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  369. package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
  370. package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  371. package/pennyfarthing_scripts/prime/__pycache__/version_sentinel.cpython-314.pyc +0 -0
  372. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  373. package/pennyfarthing_scripts/prime/heatmap.py +655 -0
  374. package/pennyfarthing_scripts/prime/workflow.py +2 -1
  375. package/pennyfarthing_scripts/schema_validation_hook.py +3 -298
  376. package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-314.pyc +0 -0
  377. package/pennyfarthing_scripts/session/__pycache__/cli.cpython-314.pyc +0 -0
  378. package/pennyfarthing_scripts/session_start_hook.py +4 -186
  379. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  380. package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
  381. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  382. package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  383. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  384. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  385. package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-314.pyc +0 -0
  386. package/pennyfarthing_scripts/sprint/__pycache__/import_epic.cpython-314.pyc +0 -0
  387. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  388. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
  389. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
  390. package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
  391. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  392. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  393. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  394. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  395. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  396. package/pennyfarthing_scripts/sprint/loader.py +15 -1
  397. package/pennyfarthing_scripts/sprint/story_update.py +19 -0
  398. package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
  399. package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
  400. package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
  401. package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
  402. package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
  403. package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
  404. package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
  405. package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  406. package/pennyfarthing_scripts/tests/__pycache__/test_108_1_gate_migration.cpython-314-pytest-9.0.2.pyc +0 -0
  407. package/pennyfarthing_scripts/tests/__pycache__/test_archive_epic.cpython-314-pytest-9.0.2.pyc +0 -0
  408. package/pennyfarthing_scripts/tests/__pycache__/test_bc.cpython-314-pytest-9.0.2.pyc +0 -0
  409. package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
  410. package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
  411. package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
  412. package/pennyfarthing_scripts/tests/__pycache__/test_cli_normalization.cpython-314-pytest-9.0.2.pyc +0 -0
  413. package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
  414. package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
  415. package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_evaluation.cpython-314-pytest-9.0.2.pyc +0 -0
  416. package/pennyfarthing_scripts/tests/__pycache__/test_confidence_sm_gate.cpython-314-pytest-9.0.2.pyc +0 -0
  417. package/pennyfarthing_scripts/tests/__pycache__/test_dialogue_manager.cpython-314-pytest-9.0.2.pyc +0 -0
  418. package/pennyfarthing_scripts/tests/__pycache__/test_epic_shard_validation.cpython-314-pytest-9.0.2.pyc +0 -0
  419. package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
  420. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  421. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_e2e.cpython-314-pytest-9.0.2.pyc +0 -0
  422. package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
  423. package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
  424. package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
  425. package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
  426. package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
  427. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
  428. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_panel.cpython-314-pytest-9.0.2.pyc +0 -0
  429. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
  430. package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
  431. package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
  432. package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
  433. package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
  434. package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
  435. package/pennyfarthing_scripts/tests/__pycache__/test_topology_loader.cpython-314-pytest-9.0.2.pyc +0 -0
  436. package/pennyfarthing_scripts/tests/__pycache__/test_tui_focus.cpython-314-pytest-9.0.2.pyc +0 -0
  437. package/pennyfarthing_scripts/tests/__pycache__/test_tui_panel_persistence.cpython-314-pytest-9.0.2.pyc +0 -0
  438. package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
  439. package/pennyfarthing_scripts/tests/__pycache__/test_version_sentinel.cpython-314-pytest-9.0.2.pyc +0 -0
  440. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
  441. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  442. package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
  443. package/pennyfarthing_scripts/tests/test_bikerack.py +51 -51
  444. package/pennyfarthing_scripts/tests/test_dialogue_manager.py +811 -0
  445. package/pennyfarthing_scripts/tests/test_handoff_cli.py +16 -11
  446. package/pennyfarthing_scripts/tests/test_sprint_panel.py +344 -265
  447. package/pennyfarthing_scripts/tests/test_workflow_check.py +2 -3
  448. package/pennyfarthing_scripts/theme/__pycache__/__init__.cpython-314.pyc +0 -0
  449. package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
  450. package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-314.pyc +0 -0
  451. package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
  452. package/pennyfarthing_scripts/validate/adapters/__pycache__/__init__.cpython-314.pyc +0 -0
  453. package/pennyfarthing_scripts/validate/adapters/__pycache__/agent.cpython-314.pyc +0 -0
  454. package/pennyfarthing_scripts/validate/adapters/__pycache__/schema.cpython-314.pyc +0 -0
  455. package/pennyfarthing_scripts/validate/adapters/__pycache__/skill_command.cpython-314.pyc +0 -0
  456. package/pennyfarthing_scripts/validate/adapters/__pycache__/sprint.cpython-314.pyc +0 -0
  457. package/pennyfarthing_scripts/validate/adapters/__pycache__/tandem_awareness.cpython-314.pyc +0 -0
  458. package/pennyfarthing_scripts/validate/adapters/__pycache__/workflow.cpython-314.pyc +0 -0
  459. package/pennyfarthing_scripts/validate/adapters/tandem_awareness.py +254 -0
  460. package/pennyfarthing_scripts/validate/adapters/workflow.py +19 -0
  461. package/pennyfarthing_scripts/validate/cli.py +17 -5
  462. package/pennyfarthing_scripts/welcome_hook.py +3 -149
  463. package/pennyfarthing_scripts/workflow/__init__.py +40 -0
  464. package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
  465. package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
  466. package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
  467. package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
  468. package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
  469. package/pennyfarthing_scripts/workflow/cli.py +1100 -0
  470. package/pennyfarthing_scripts/workflow/helpers.py +241 -0
  471. package/pennyfarthing_scripts/{workflow.py → workflow/scale.py} +0 -104
  472. package/pennyfarthing_scripts/workflow/state.py +112 -0
  473. package/pennyfarthing_scripts/workflow/team_lifecycle.py +257 -0
  474. package/packages/core/dist/scripts/theme-detail.test.d.ts +0 -10
  475. package/packages/core/dist/scripts/theme-detail.test.js +0 -199
  476. package/pennyfarthing-dist/skills/pf-workflow/scripts/list-workflows.sh +0 -91
  477. package/pennyfarthing-dist/skills/pf-workflow/scripts/resume-workflow.sh +0 -163
  478. package/pennyfarthing-dist/skills/pf-workflow/scripts/show-workflow.sh +0 -138
  479. package/pennyfarthing-dist/skills/pf-workflow/scripts/start-workflow.sh +0 -273
  480. package/pennyfarthing-dist/skills/pf-workflow/scripts/workflow-status.sh +0 -167
  481. package/pennyfarthing_scripts/gate/__pycache__/__init__.cpython-314.pyc +0 -0
  482. package/pennyfarthing_scripts/gate/__pycache__/cli.cpython-314.pyc +0 -0
  483. package/pennyfarthing_scripts/gate/__pycache__/validate.cpython-314.pyc +0 -0
  484. package/pennyfarthing_scripts/tests/__pycache__/test_108_2_remove_handoff_fallback.cpython-314-pytest-9.0.2.pyc +0 -0
  485. package/pennyfarthing_scripts/tests/__pycache__/test_gate_file_resolution.cpython-314-pytest-9.0.2.pyc +0 -0
  486. package/pennyfarthing_scripts/tests/__pycache__/test_gate_runner.cpython-314-pytest-9.0.2.pyc +0 -0
  487. package/pennyfarthing_scripts/tests/__pycache__/test_resolve_gate_file_field.cpython-314-pytest-9.0.2.pyc +0 -0
@@ -1,305 +1,10 @@
1
- #!/usr/bin/env python3
2
1
  """
3
- XML Schema Validation Hook for PreToolUse.
2
+ Backward-compatibility shim schema validation hook moved to hooks/schema_validation.py.
4
3
 
5
- Validates session, skill, and workflow step files on Write/Edit operations.
6
- Blocks the tool call if validation fails, providing immediate feedback.
7
-
8
- Usage in settings.json:
9
- {
10
- "hooks": {
11
- "PreToolUse": [{
12
- "matcher": "Write|Edit",
13
- "hooks": [{
14
- "type": "command",
15
- "command": "python3 -m pennyfarthing_scripts.schema_validation_hook"
16
- }]
17
- }]
18
- }
19
- }
20
-
21
- Story: XML Schema Migration Tools
4
+ This file will be removed in a future version.
22
5
  """
23
6
 
24
- import re
25
- import sys
26
- from pathlib import Path
27
-
28
- # Add parent directory to path for imports
29
- sys.path.insert(0, str(Path(__file__).parent))
30
-
31
- from hooks import (
32
- HookResponse,
33
- output_hook_response,
34
- read_stdin_json,
35
- )
36
-
37
- # =============================================================================
38
- # File Type Detection
39
- # =============================================================================
40
-
41
-
42
- def is_session_file(file_path: str) -> bool:
43
- """Check if path is a session file."""
44
- return file_path.endswith("-session.md") and ".session/" in file_path
45
-
46
-
47
- def is_skill_file(file_path: str) -> bool:
48
- """Check if path is a skill SKILL.md file."""
49
- return file_path.endswith("/SKILL.md") and "/skills/" in file_path
50
-
51
-
52
- def is_step_file(file_path: str) -> bool:
53
- """Check if path is a workflow step file."""
54
- path = Path(file_path)
55
- return (
56
- path.name.startswith("step-")
57
- and path.name.endswith(".md")
58
- and "/workflows/" in file_path
59
- and "/steps/" in file_path
60
- )
61
-
62
-
63
- def get_file_type(file_path: str) -> str | None:
64
- """Detect file type from path."""
65
- if is_session_file(file_path):
66
- return "session"
67
- elif is_skill_file(file_path):
68
- return "skill"
69
- elif is_step_file(file_path):
70
- return "step"
71
- return None
72
-
73
-
74
- # =============================================================================
75
- # Content-Based Validation (inline to avoid import issues)
76
- # =============================================================================
77
-
78
- # Skill required tags
79
- SKILL_REQUIRED_TAGS = ["run", "output"]
80
-
81
- # Workflow step required tags
82
- STEP_REQUIRED_TAGS = ["purpose", "instructions", "output"]
83
-
84
- # Step meta required fields
85
- STEP_META_FIELDS = ["step", "workflow", "agent", "next"]
86
-
87
-
88
- def _has_tag(content: str, tag: str) -> bool:
89
- """Check if content contains a specific XML tag."""
90
- return f"<{tag}>" in content or f"<{tag} " in content
91
-
92
-
93
- def validate_session_content(content: str) -> list[str]:
94
- """Validate session file content.
95
-
96
- Args:
97
- content: File content to validate
98
-
99
- Returns:
100
- List of error messages (empty if valid)
101
- """
102
- errors = []
103
-
104
- # Check for XML format indicator
105
- if "<session" not in content:
106
- # Old markdown format - warn but don't block during migration
107
- return []
108
-
109
- # Validate <session> root with attributes
110
- if not re.search(r'<session\s+story="[^"]+"', content):
111
- errors.append("Missing story attribute on <session>")
112
-
113
- if not re.search(r'<session[^>]+workflow="[^"]+"', content):
114
- errors.append("Missing workflow attribute on <session>")
115
-
116
- # Validate <meta> section
117
- if not _has_tag(content, "meta"):
118
- errors.append("Missing <meta> section")
119
- else:
120
- if "<jira>" not in content:
121
- errors.append("Missing <jira> in <meta>")
122
- if "<started>" not in content:
123
- errors.append("Missing <started> in <meta>")
124
-
125
- # Validate <status> element
126
- if not _has_tag(content, "status"):
127
- errors.append("Missing <status> element")
128
- else:
129
- if 'phase="' not in content:
130
- errors.append("Missing phase attribute on <status>")
131
-
132
- return errors
133
-
134
-
135
- def validate_skill_content(content: str) -> list[str]:
136
- """Validate skill file content.
137
-
138
- Args:
139
- content: File content to validate
140
-
141
- Returns:
142
- List of error messages (empty if valid)
143
- """
144
- errors = []
145
-
146
- # Check YAML frontmatter
147
- if not content.startswith("---\n"):
148
- errors.append("Missing YAML frontmatter")
149
- else:
150
- parts = content.split("---", 2)
151
- if len(parts) >= 2:
152
- frontmatter = parts[1]
153
- if "name:" not in frontmatter:
154
- errors.append("Missing 'name' in frontmatter")
155
- if "description:" not in frontmatter:
156
- errors.append("Missing 'description' in frontmatter")
157
-
158
- # Check required tags
159
- for tag in SKILL_REQUIRED_TAGS:
160
- if not _has_tag(content, tag):
161
- errors.append(f"Missing <{tag}> tag (required)")
162
-
163
- return errors
164
-
165
-
166
- def validate_step_content(content: str) -> list[str]:
167
- """Validate workflow step file content.
168
-
169
- Args:
170
- content: File content to validate
171
-
172
- Returns:
173
- List of error messages (empty if valid)
174
- """
175
- errors = []
176
-
177
- # Check required tags
178
- for tag in STEP_REQUIRED_TAGS:
179
- if not _has_tag(content, tag):
180
- errors.append(f"Missing <{tag}> tag")
181
-
182
- # Check step-meta fields if tag exists
183
- if _has_tag(content, "step-meta"):
184
- meta_match = re.search(r"<step-meta>(.+?)</step-meta>", content, re.DOTALL)
185
- if meta_match:
186
- meta_content = meta_match.group(1)
187
- for field_name in STEP_META_FIELDS:
188
- if f"{field_name}:" not in meta_content:
189
- errors.append(f"Missing '{field_name}' in step-meta")
190
-
191
- return errors
192
-
193
-
194
- def validate_content(file_path: str, content: str) -> list[str]:
195
- """Validate content based on file type.
196
-
197
- Args:
198
- file_path: Path to file being written
199
- content: Content being written
200
-
201
- Returns:
202
- List of error messages (empty if valid)
203
- """
204
- file_type = get_file_type(file_path)
205
-
206
- if file_type == "session":
207
- return validate_session_content(content)
208
- elif file_type == "skill":
209
- return validate_skill_content(content)
210
- elif file_type == "step":
211
- return validate_step_content(content)
212
-
213
- return []
214
-
215
-
216
- # =============================================================================
217
- # Hook Entry Point
218
- # =============================================================================
219
-
220
-
221
- def main() -> None:
222
- """Main entry point for schema validation hook."""
223
- try:
224
- # Read tool data from Claude Code
225
- tool_data = read_stdin_json()
226
-
227
- tool_name = tool_data.get("tool_name", "")
228
- tool_input = tool_data.get("tool_input", {})
229
-
230
- # Only process Write and Edit tools
231
- if tool_name not in ("Write", "Edit"):
232
- output_hook_response(HookResponse(
233
- event_name="PreToolUse",
234
- decision="allow",
235
- reason="Not a Write/Edit operation",
236
- ))
237
- sys.exit(0)
238
-
239
- # Get file path
240
- file_path = tool_input.get("file_path", "")
241
- if not file_path:
242
- output_hook_response(HookResponse(
243
- event_name="PreToolUse",
244
- decision="allow",
245
- reason="No file path",
246
- ))
247
- sys.exit(0)
248
-
249
- # Check if this is a file we care about
250
- file_type = get_file_type(file_path)
251
- if not file_type:
252
- output_hook_response(HookResponse(
253
- event_name="PreToolUse",
254
- decision="allow",
255
- reason="Not a session/skill/step file",
256
- ))
257
- sys.exit(0)
258
-
259
- # Get content to validate
260
- # For Write: use 'content'
261
- # For Edit: we need to simulate the edit result
262
- if tool_name == "Write":
263
- content = tool_input.get("content", "")
264
- else:
265
- # Edit operation - we can't easily validate without reading the file
266
- # For now, allow Edits and validate on Write only
267
- output_hook_response(HookResponse(
268
- event_name="PreToolUse",
269
- decision="allow",
270
- reason="Edit operations validated post-hoc",
271
- ))
272
- sys.exit(0)
273
-
274
- # Validate content
275
- errors = validate_content(file_path, content)
276
-
277
- if errors:
278
- # Block the write
279
- error_msg = f"Schema validation failed for {file_type} file:\n"
280
- error_msg += "\n".join(f" - {e}" for e in errors)
281
- error_msg += f"\n\nFile: {file_path}"
282
-
283
- output_hook_response(HookResponse(
284
- event_name="PreToolUse",
285
- decision="deny",
286
- reason=error_msg,
287
- ))
288
- sys.exit(0)
289
-
290
- # Validation passed
291
- output_hook_response(HookResponse(
292
- event_name="PreToolUse",
293
- decision="allow",
294
- reason=f"Schema validation passed for {file_type} file",
295
- ))
296
- sys.exit(0)
297
-
298
- except Exception as e:
299
- # On error, allow to avoid blocking legitimate work
300
- print(f"[schema-validation-hook] Error: {e}", file=sys.stderr)
301
- sys.exit(0)
302
-
7
+ from pennyfarthing_scripts.hooks.schema_validation import main # noqa: F401
303
8
 
304
9
  if __name__ == "__main__":
305
10
  main()
@@ -1,192 +1,10 @@
1
- #!/usr/bin/env python3
2
- """Session start hook — initialize environment for Claude Code session.
3
-
4
- Handles:
5
- 1. Session directory setup and logging
6
- 2. Checkpoint validation (cross-session drift detection)
7
- 3. WheelHub auto-start (ensure BikeRack server is running)
8
- 4. OTEL auto-configuration via CLAUDE_ENV_FILE
9
-
10
- Called by Claude Code SessionStart hook via shell wrapper.
11
1
  """
2
+ Backward-compatibility shim — session start hook moved to hooks/session_start.py.
12
3
 
13
- from __future__ import annotations
14
-
15
- import json
16
- import os
17
- import sys
18
- from pathlib import Path
19
-
20
-
21
- def _read_input() -> dict:
22
- """Read JSON from stdin (hook protocol)."""
23
- raw = sys.stdin.read()
24
- try:
25
- return json.loads(raw)
26
- except (json.JSONDecodeError, ValueError):
27
- return {}
28
-
29
-
30
- def _setup_session_dir(project_dir: Path, session_id: str, source_type: str) -> None:
31
- """Ensure .session directory exists and log session start."""
32
- session_dir = project_dir / ".session"
33
- session_dir.mkdir(parents=True, exist_ok=True)
34
- (session_dir / "agents").mkdir(exist_ok=True)
35
-
36
- from datetime import UTC, datetime
37
-
38
- timestamp = datetime.now(UTC).isoformat()
39
- log_file = session_dir / "session-log.txt"
40
- with open(log_file, "a") as f:
41
- f.write(f"{timestamp} | Session {source_type}: {session_id}\n")
42
-
43
-
44
- def _validate_checkpoint(project_dir: Path) -> None:
45
- """Validate previous session checkpoint for cross-session drift detection."""
46
- try:
47
- import subprocess
48
-
49
- script_dir = Path(__file__).resolve().parent.parent
50
- checkpoint_lib = script_dir / "pennyfarthing-dist" / "scripts" / "lib" / "checkpoint.sh"
51
-
52
- if not checkpoint_lib.exists():
53
- return
54
-
55
- result = subprocess.run(
56
- ["bash", "-c", f'source "{checkpoint_lib}" && checkpoint_restore session_state'],
57
- capture_output=True,
58
- text=True,
59
- cwd=str(project_dir),
60
- timeout=5,
61
- )
62
-
63
- prev_state = result.stdout.strip()
64
- if not prev_state:
65
- return
66
-
67
- # Parse checkpoint data
68
- fields = {}
69
- for part in prev_state.split(";"):
70
- if "=" in part:
71
- k, v = part.split("=", 1)
72
- fields[k] = v
73
-
74
- prev_sha = fields.get("sha", "")
75
- if not prev_sha:
76
- return
77
-
78
- # Get current git SHA
79
- result = subprocess.run(
80
- ["git", "rev-parse", "--short", "HEAD"],
81
- capture_output=True,
82
- text=True,
83
- cwd=str(project_dir),
84
- timeout=5,
85
- )
86
- current_sha = result.stdout.strip()
87
- if not current_sha or current_sha == prev_sha:
88
- return
89
-
90
- # Log drift
91
- from datetime import UTC, datetime
92
-
93
- timestamp = datetime.now(UTC).isoformat()
94
- session_dir = project_dir / ".session"
95
-
96
- warning = f"CROSS_SESSION_DRIFT: Git changed (was: {prev_sha}, now: {current_sha})"
97
- if fields.get("story"):
98
- warning += f" | Story: {fields['story']}"
99
- if fields.get("agent"):
100
- warning += f" | Agent: {fields['agent']}"
101
-
102
- with open(session_dir / "session-log.txt", "a") as f:
103
- f.write(f"{timestamp} | {warning}\n")
104
-
105
- drift_entry = f"{timestamp} | prev_sha={prev_sha} | current_sha={current_sha}"
106
- for key in ("story", "agent", "phase"):
107
- if fields.get(key):
108
- drift_entry += f" | {key}={fields[key]}"
109
- with open(session_dir / "drift-log.txt", "a") as f:
110
- f.write(drift_entry + "\n")
111
-
112
- except Exception:
113
- pass
114
-
115
-
116
- def _ensure_wheelhub(project_dir: Path) -> int | None:
117
- """Auto-start WheelHub if not already running. Returns port or None."""
118
- from pennyfarthing_scripts.bikerack.launcher import (
119
- is_already_running,
120
- poll_for_port_file,
121
- start_wheelhub,
122
- write_pid_file,
123
- )
124
-
125
- # Skip if full Cyclist is running
126
- cyclist_port_file = project_dir / ".cyclist-port"
127
- if cyclist_port_file.exists():
128
- try:
129
- return int(cyclist_port_file.read_text().strip())
130
- except (ValueError, OSError):
131
- return None
132
-
133
- # Check if BikeRack WheelHub is already running
134
- running, _pid, port = is_already_running(project_dir)
135
- if running:
136
- return port
137
-
138
- # Start WheelHub
139
- try:
140
- proc = start_wheelhub(project_dir)
141
- write_pid_file(project_dir, proc.pid)
142
- return poll_for_port_file(project_dir)
143
- except Exception:
144
- return None
145
-
146
-
147
- def _write_env_file(project_dir: Path, session_id: str, otel_port: int | None) -> None:
148
- """Write environment variables to CLAUDE_ENV_FILE."""
149
- env_file = os.environ.get("CLAUDE_ENV_FILE")
150
- if not env_file:
151
- return
152
-
153
- lines = [
154
- "# Pennyfarthing core environment",
155
- f'export PROJECT_ROOT="{project_dir}"',
156
- f'export SESSION_ID="{session_id}"',
157
- ]
158
-
159
- if otel_port is not None:
160
- lines.extend([
161
- "# OTEL auto-configuration for Cyclist/WheelHub",
162
- 'export OTEL_EXPORTER_OTLP_PROTOCOL="http/json"',
163
- f'export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:{otel_port}"',
164
- ])
165
-
166
- with open(env_file, "a") as f:
167
- f.write("\n".join(lines) + "\n")
168
-
169
-
170
- def main() -> None:
171
- """Entry point for SessionStart hook."""
172
- try:
173
- input_data = _read_input()
174
- session_id = input_data.get("session_id", "unknown")
175
- source_type = input_data.get("source", "unknown")
176
-
177
- project_dir = Path(os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd()))
178
-
179
- _setup_session_dir(project_dir, session_id, source_type)
180
- _validate_checkpoint(project_dir)
181
-
182
- otel_port = _ensure_wheelhub(project_dir)
183
- _write_env_file(project_dir, session_id, otel_port)
184
-
185
- except Exception:
186
- pass
187
-
188
- sys.exit(0)
4
+ This file will be removed in a future version.
5
+ """
189
6
 
7
+ from pennyfarthing_scripts.hooks.session_start import main # noqa: F401
190
8
 
191
9
  if __name__ == "__main__":
192
10
  main()
@@ -62,6 +62,17 @@ def _merge_epic_shards(data: dict[str, Any], sprint_dir: Path) -> dict[str, Any]
62
62
  stacklevel=2,
63
63
  )
64
64
 
65
+ # Collect epic refs owned by initiatives so we don't warn about them.
66
+ initiative_refs: set[str] = set()
67
+ for init_file in sorted(sprint_dir.glob("initiative-*.yaml")):
68
+ init_data = load_yaml_config(init_file)
69
+ if init_data and isinstance(init_data, dict):
70
+ for ref in init_data.get("epics", []):
71
+ if isinstance(ref, str):
72
+ initiative_refs.add(ref)
73
+ # Also add normalized form (strip "epic-" prefix)
74
+ initiative_refs.add(ref.replace("epic-", ""))
75
+
65
76
  # Log unindexed shard files on disk (but do NOT auto-merge —
66
77
  # orphan shards may belong to future initiatives).
67
78
  for shard_file in sorted(sprint_dir.glob("epic-*.yaml")):
@@ -74,7 +85,10 @@ def _merge_epic_shards(data: dict[str, Any], sprint_dir: Path) -> dict[str, Any]
74
85
  jira_key = str(epic_data.get("jira", ""))
75
86
  if eid in loaded_epic_ids or (jira_key and jira_key in loaded_epic_ids):
76
87
  continue
77
- # Warn but don't merge
88
+ # Skip shards owned by initiatives (not orphans)
89
+ if eid in initiative_refs or jira_key in initiative_refs:
90
+ continue
91
+ # Warn only about truly orphaned shards
78
92
  warnings.warn(
79
93
  f"Unindexed shard {shard_file.name} (epic {eid}) not in epics list — skipping",
80
94
  stacklevel=2,
@@ -30,6 +30,8 @@ def update_story(
30
30
  completed_date: str | None = None,
31
31
  started_date: str | None = None,
32
32
  workflow: str | None = None,
33
+ review_findings: str | None = None,
34
+ review_verdict: str | None = None,
33
35
  dry_run: bool = False,
34
36
  ) -> dict[str, Any]:
35
37
  """Update fields on a story in the sprint YAML.
@@ -44,6 +46,8 @@ def update_story(
44
46
  completed_date: Completed date (ISO format)
45
47
  started_date: Started date (ISO format)
46
48
  workflow: Workflow type (tdd, trivial, bdd, agent-docs)
49
+ review_findings: Reviewer findings text
50
+ review_verdict: Review verdict (approved, rejected, pending)
47
51
  dry_run: If True, report changes without writing
48
52
 
49
53
  Returns:
@@ -97,6 +101,15 @@ def update_story(
97
101
  story["started"] = started_date
98
102
  if workflow is not None:
99
103
  story["workflow"] = workflow
104
+ if review_findings is not None:
105
+ story["review_findings"] = review_findings
106
+ if review_verdict is not None:
107
+ if review_verdict not in ("approved", "rejected", "pending"):
108
+ return {
109
+ "success": False,
110
+ "error": f"Invalid review_verdict '{review_verdict}'. Must be one of: approved, rejected, pending",
111
+ }
112
+ story["review_verdict"] = review_verdict
100
113
 
101
114
  # Auto-cleanup rules
102
115
  if status == "done":
@@ -153,6 +166,8 @@ def update_story(
153
166
  @click.option("--priority", default=None)
154
167
  @click.option("--started", "started_date", default=None)
155
168
  @click.option("--workflow", default=None)
169
+ @click.option("--review-findings", default=None, help="Reviewer findings text")
170
+ @click.option("--review-verdict", type=click.Choice(["approved", "rejected", "pending"]), default=None)
156
171
  @click.option("--dry-run", is_flag=True)
157
172
  @click.option("--sprint-file", type=click.Path(), default=None, help="Path to sprint YAML file")
158
173
  def story_update_command(
@@ -164,6 +179,8 @@ def story_update_command(
164
179
  priority: str | None,
165
180
  started_date: str | None,
166
181
  workflow: str | None,
182
+ review_findings: str | None,
183
+ review_verdict: str | None,
167
184
  dry_run: bool,
168
185
  sprint_file: str | None,
169
186
  ) -> None:
@@ -184,6 +201,8 @@ def story_update_command(
184
201
  completed_date=completed_date,
185
202
  started_date=started_date,
186
203
  workflow=workflow,
204
+ review_findings=review_findings,
205
+ review_verdict=review_verdict,
187
206
  dry_run=dry_run,
188
207
  )
189
208