@pennyfarthing/core 10.0.2 → 10.0.5

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 (722) hide show
  1. package/README.md +287 -0
  2. package/package.json +29 -41
  3. package/{dist → packages/core/dist}/cli/commands/cyclist.d.ts +5 -1
  4. package/packages/core/dist/cli/commands/cyclist.d.ts.map +1 -0
  5. package/{dist → packages/core/dist}/cli/commands/cyclist.js +4 -4
  6. package/packages/core/dist/cli/commands/cyclist.js.map +1 -0
  7. package/{dist → packages/core/dist}/cli/commands/cyclist.test.js +2 -2
  8. package/packages/core/dist/cli/commands/cyclist.test.js.map +1 -0
  9. package/packages/core/dist/cli/commands/doctor-file-layout.test.d.ts +13 -0
  10. package/packages/core/dist/cli/commands/doctor-file-layout.test.d.ts.map +1 -0
  11. package/packages/core/dist/cli/commands/doctor-file-layout.test.js +234 -0
  12. package/packages/core/dist/cli/commands/doctor-file-layout.test.js.map +1 -0
  13. package/{dist → packages/core/dist}/cli/commands/doctor-legacy.test.js +17 -16
  14. package/{dist → packages/core/dist}/cli/commands/doctor-legacy.test.js.map +1 -1
  15. package/{dist → packages/core/dist}/cli/commands/doctor.d.ts +8 -0
  16. package/{dist → packages/core/dist}/cli/commands/doctor.d.ts.map +1 -1
  17. package/{dist → packages/core/dist}/cli/commands/doctor.js +224 -3
  18. package/packages/core/dist/cli/commands/doctor.js.map +1 -0
  19. package/{dist → packages/core/dist}/cli/commands/e2e-fresh-install.test.js +1 -1
  20. package/{dist → packages/core/dist}/cli/commands/e2e-fresh-install.test.js.map +1 -1
  21. package/{dist → packages/core/dist}/cli/commands/e2e-upgrade.test.js +1 -1
  22. package/{dist → packages/core/dist}/cli/commands/e2e-upgrade.test.js.map +1 -1
  23. package/packages/core/dist/cli/commands/hooks-consolidation.test.d.ts +19 -0
  24. package/packages/core/dist/cli/commands/hooks-consolidation.test.d.ts.map +1 -0
  25. package/packages/core/dist/cli/commands/hooks-consolidation.test.js +358 -0
  26. package/packages/core/dist/cli/commands/hooks-consolidation.test.js.map +1 -0
  27. package/{dist → packages/core/dist}/cli/commands/init.d.ts.map +1 -1
  28. package/{dist → packages/core/dist}/cli/commands/init.js +3 -0
  29. package/packages/core/dist/cli/commands/init.js.map +1 -0
  30. package/{dist → packages/core/dist}/cli/commands/update.d.ts.map +1 -1
  31. package/{dist → packages/core/dist}/cli/commands/update.js +53 -1
  32. package/{dist → packages/core/dist}/cli/commands/update.js.map +1 -1
  33. package/{dist → packages/core/dist}/cli/ocean-profiles.test.js +1 -1
  34. package/{dist → packages/core/dist}/cli/ocean-profiles.test.js.map +1 -1
  35. package/{dist → packages/core/dist}/cli/utils/files.d.ts +10 -0
  36. package/{dist → packages/core/dist}/cli/utils/files.d.ts.map +1 -1
  37. package/{dist → packages/core/dist}/cli/utils/files.js +35 -0
  38. package/{dist → packages/core/dist}/cli/utils/files.js.map +1 -1
  39. package/{dist → packages/core/dist}/cli/utils/settings.d.ts.map +1 -1
  40. package/{dist → packages/core/dist}/cli/utils/settings.js +24 -0
  41. package/packages/core/dist/cli/utils/settings.js.map +1 -0
  42. package/{dist → packages/core/dist}/cli/utils/themes.d.ts +1 -0
  43. package/packages/core/dist/cli/utils/themes.d.ts.map +1 -0
  44. package/{dist → packages/core/dist}/cli/utils/themes.js.map +1 -1
  45. package/{dist → packages/core/dist}/scripts/generate-report.d.ts.map +1 -1
  46. package/{dist → packages/core/dist}/scripts/generate-report.js +11 -7
  47. package/packages/core/dist/scripts/generate-report.js.map +1 -0
  48. package/{dist → packages/core/dist}/scripts/generate-spider-report.d.ts.map +1 -1
  49. package/{dist → packages/core/dist}/scripts/generate-spider-report.js +12 -8
  50. package/packages/core/dist/scripts/generate-spider-report.js.map +1 -0
  51. package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -0
  52. package/{dist → packages/core/dist}/scripts/generate-spider.js +6 -4
  53. package/packages/core/dist/scripts/generate-spider.js.map +1 -0
  54. package/{dist → packages/core/dist}/scripts/generate-spider.test.js +2 -2
  55. package/packages/core/dist/scripts/generate-spider.test.js.map +1 -0
  56. package/pennyfarthing-dist/agents/pm.md +1 -1
  57. package/pennyfarthing-dist/agents/sm-finish.md +1 -1
  58. package/pennyfarthing-dist/agents/sm-setup.md +6 -6
  59. package/pennyfarthing-dist/agents/sm.md +12 -6
  60. package/pennyfarthing-dist/agents/workflow-status-check.md +1 -1
  61. package/pennyfarthing-dist/commands/repo-status.md +2 -2
  62. package/pennyfarthing-dist/commands/sprint.md +8 -8
  63. package/pennyfarthing-dist/guides/bell-mode.md +65 -0
  64. package/pennyfarthing-dist/guides/benchmarks.md +62 -0
  65. package/pennyfarthing-dist/guides/bikelane.md +86 -0
  66. package/pennyfarthing-dist/guides/prime.md +72 -0
  67. package/pennyfarthing-dist/guides/reflector.md +59 -0
  68. package/pennyfarthing-dist/guides/relay-mode.md +53 -0
  69. package/pennyfarthing-dist/guides/skill-schema.md +25 -26
  70. package/pennyfarthing-dist/guides/tirepump.md +54 -0
  71. package/pennyfarthing-dist/guides/xml-tags.md +2 -2
  72. package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +59 -58
  73. package/pennyfarthing-dist/personas/themes/blade-runner.yaml +10 -10
  74. package/pennyfarthing-dist/personas/themes/doctor-who.yaml +10 -10
  75. package/pennyfarthing-dist/personas/themes/dune.yaml +64 -69
  76. package/pennyfarthing-dist/personas/themes/firefly.yaml +60 -73
  77. package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +60 -69
  78. package/pennyfarthing-dist/personas/themes/harry-potter.yaml +59 -73
  79. package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +45 -57
  80. package/pennyfarthing-dist/personas/themes/mad-max.yaml +5 -11
  81. package/pennyfarthing-dist/personas/themes/princess-bride.yaml +53 -63
  82. package/pennyfarthing-dist/personas/themes/sandman.yaml +59 -59
  83. package/pennyfarthing-dist/personas/themes/the-matrix.yaml +61 -62
  84. package/pennyfarthing-dist/personas/themes/west-wing.yaml +8 -9
  85. package/pennyfarthing-dist/scripts/README.md +2 -2
  86. package/pennyfarthing-dist/scripts/git/git-status-all.sh +1 -1
  87. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +3 -3
  88. package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +32 -0
  89. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +2 -7
  90. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +1 -1
  91. package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +12 -91
  92. package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +11 -86
  93. package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +11 -255
  94. package/pennyfarthing-dist/scripts/misc/repo-utils.sh +3 -3
  95. package/pennyfarthing-dist/scripts/sprint/README.md +32 -17
  96. package/pennyfarthing-dist/scripts/story/README.md +1 -1
  97. package/pennyfarthing-dist/scripts/test/test-setup.sh +1 -1
  98. package/pennyfarthing-dist/skills/jira/SKILL.md +107 -408
  99. package/pennyfarthing-dist/skills/skill-registry.yaml +21 -12
  100. package/pennyfarthing-dist/skills/sprint/skill.md +386 -68
  101. package/pennyfarthing-dist/skills/story/skill.md +14 -206
  102. package/pennyfarthing-dist/templates/settings.local.json.template +9 -1
  103. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +1 -1
  104. package/pennyfarthing-dist/workflows/git-cleanup.yaml +1 -1
  105. package/pennyfarthing-dist/workflows/project-setup/steps/step-10-complete.md +1 -1
  106. package/pennyfarthing_scripts/README.md +66 -0
  107. package/pennyfarthing_scripts/__init__.py +17 -0
  108. package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  109. package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  110. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  111. package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
  112. package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
  113. package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
  114. package/pennyfarthing_scripts/__pycache__/jira_bidirectional_sync.cpython-314.pyc +0 -0
  115. package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
  116. package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
  117. package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
  118. package/pennyfarthing_scripts/__pycache__/output.cpython-314.pyc +0 -0
  119. package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
  120. package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
  121. package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
  122. package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
  123. package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
  124. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  125. package/pennyfarthing_scripts/bellmode_hook.py +154 -0
  126. package/pennyfarthing_scripts/brownfield/__init__.py +35 -0
  127. package/pennyfarthing_scripts/brownfield/__main__.py +7 -0
  128. package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
  129. package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
  130. package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
  131. package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
  132. package/pennyfarthing_scripts/brownfield/cli.py +131 -0
  133. package/pennyfarthing_scripts/brownfield/discover.py +753 -0
  134. package/pennyfarthing_scripts/cli.py +184 -0
  135. package/pennyfarthing_scripts/common/__init__.py +49 -0
  136. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
  137. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  138. package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
  139. package/pennyfarthing_scripts/common/__pycache__/themes.cpython-314.pyc +0 -0
  140. package/pennyfarthing_scripts/common/config.py +92 -0
  141. package/pennyfarthing_scripts/common/output.py +180 -0
  142. package/pennyfarthing_scripts/common/themes.py +253 -0
  143. package/pennyfarthing_scripts/config.py +21 -0
  144. package/pennyfarthing_scripts/context.py +414 -0
  145. package/pennyfarthing_scripts/git/__init__.py +29 -0
  146. package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
  147. package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
  148. package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
  149. package/pennyfarthing_scripts/git/create_branches.py +439 -0
  150. package/pennyfarthing_scripts/git/status_all.py +310 -0
  151. package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +7 -0
  152. package/pennyfarthing_scripts/hooks.py +454 -0
  153. package/pennyfarthing_scripts/hotspots/__init__.py +31 -0
  154. package/pennyfarthing_scripts/hotspots/__main__.py +6 -0
  155. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
  156. package/pennyfarthing_scripts/hotspots/__pycache__/__main__.cpython-314.pyc +0 -0
  157. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
  158. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
  159. package/pennyfarthing_scripts/hotspots/__pycache__/formatters.cpython-314.pyc +0 -0
  160. package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
  161. package/pennyfarthing_scripts/hotspots/analyze.py +472 -0
  162. package/pennyfarthing_scripts/hotspots/cli.py +152 -0
  163. package/pennyfarthing_scripts/hotspots/formatters.py +109 -0
  164. package/pennyfarthing_scripts/hotspots/models.py +60 -0
  165. package/pennyfarthing_scripts/jira/__init__.py +99 -0
  166. package/pennyfarthing_scripts/jira/__main__.py +10 -0
  167. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  168. package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
  169. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  170. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
  171. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  172. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
  174. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/jira/__pycache__/operations.cpython-314.pyc +0 -0
  179. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  180. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
  181. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
  182. package/pennyfarthing_scripts/jira/bidirectional.py +561 -0
  183. package/pennyfarthing_scripts/jira/claim.py +211 -0
  184. package/pennyfarthing_scripts/jira/cli.py +351 -0
  185. package/pennyfarthing_scripts/jira/client.py +762 -0
  186. package/pennyfarthing_scripts/jira/create.py +267 -0
  187. package/pennyfarthing_scripts/jira/epic.py +176 -0
  188. package/pennyfarthing_scripts/jira/operations.py +124 -0
  189. package/pennyfarthing_scripts/jira/reconcile.py +277 -0
  190. package/pennyfarthing_scripts/jira/story.py +219 -0
  191. package/pennyfarthing_scripts/jira/sync.py +350 -0
  192. package/pennyfarthing_scripts/jira_bidirectional_sync.py +37 -0
  193. package/pennyfarthing_scripts/jira_epic_creation.py +30 -0
  194. package/pennyfarthing_scripts/jira_sync.py +36 -0
  195. package/pennyfarthing_scripts/jira_sync_story.py +30 -0
  196. package/pennyfarthing_scripts/migration/__init__.py +39 -0
  197. package/pennyfarthing_scripts/migration/__main__.py +10 -0
  198. package/pennyfarthing_scripts/migration/__pycache__/__init__.cpython-314.pyc +0 -0
  199. package/pennyfarthing_scripts/migration/__pycache__/__main__.cpython-314.pyc +0 -0
  200. package/pennyfarthing_scripts/migration/__pycache__/cli.cpython-314.pyc +0 -0
  201. package/pennyfarthing_scripts/migration/__pycache__/session.cpython-314.pyc +0 -0
  202. package/pennyfarthing_scripts/migration/__pycache__/skill.cpython-314.pyc +0 -0
  203. package/pennyfarthing_scripts/migration/__pycache__/step.cpython-314.pyc +0 -0
  204. package/pennyfarthing_scripts/migration/__pycache__/validate.cpython-314.pyc +0 -0
  205. package/pennyfarthing_scripts/migration/cli.py +304 -0
  206. package/pennyfarthing_scripts/migration/session.py +384 -0
  207. package/pennyfarthing_scripts/migration/skill.py +188 -0
  208. package/pennyfarthing_scripts/migration/step.py +229 -0
  209. package/pennyfarthing_scripts/migration/validate.py +282 -0
  210. package/pennyfarthing_scripts/output.py +37 -0
  211. package/pennyfarthing_scripts/patch_mode.py +449 -0
  212. package/pennyfarthing_scripts/preflight/__init__.py +17 -0
  213. package/pennyfarthing_scripts/preflight/__main__.py +10 -0
  214. package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
  215. package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
  216. package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
  217. package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
  218. package/pennyfarthing_scripts/preflight/cli.py +141 -0
  219. package/pennyfarthing_scripts/preflight/finish.py +382 -0
  220. package/pennyfarthing_scripts/pretooluse_hook.py +193 -0
  221. package/pennyfarthing_scripts/prime/__init__.py +125 -0
  222. package/pennyfarthing_scripts/prime/__main__.py +8 -0
  223. package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  224. package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
  225. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  226. package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
  227. package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
  228. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  229. package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
  230. package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  231. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  232. package/pennyfarthing_scripts/prime/cli.py +645 -0
  233. package/pennyfarthing_scripts/prime/loader.py +239 -0
  234. package/pennyfarthing_scripts/prime/models.py +206 -0
  235. package/pennyfarthing_scripts/prime/persona.py +309 -0
  236. package/pennyfarthing_scripts/prime/session.py +183 -0
  237. package/pennyfarthing_scripts/prime/tiers.py +201 -0
  238. package/pennyfarthing_scripts/prime/workflow.py +277 -0
  239. package/pennyfarthing_scripts/schema_validation_hook.py +306 -0
  240. package/pennyfarthing_scripts/sprint/__init__.py +66 -0
  241. package/pennyfarthing_scripts/sprint/__main__.py +10 -0
  242. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  243. package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
  244. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  245. package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  246. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  247. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  248. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  249. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
  250. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
  251. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  252. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  253. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  254. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  255. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  256. package/pennyfarthing_scripts/sprint/archive.py +165 -0
  257. package/pennyfarthing_scripts/sprint/archive_epic.py +408 -0
  258. package/pennyfarthing_scripts/sprint/cli.py +1863 -0
  259. package/pennyfarthing_scripts/sprint/epic_add.py +173 -0
  260. package/pennyfarthing_scripts/sprint/import_epic.py +431 -0
  261. package/pennyfarthing_scripts/sprint/loader.py +237 -0
  262. package/pennyfarthing_scripts/sprint/status.py +122 -0
  263. package/pennyfarthing_scripts/sprint/story_add.py +187 -0
  264. package/pennyfarthing_scripts/sprint/story_update.py +181 -0
  265. package/pennyfarthing_scripts/sprint/validate_cmd.py +307 -0
  266. package/pennyfarthing_scripts/sprint/validator.py +580 -0
  267. package/pennyfarthing_scripts/sprint/work.py +208 -0
  268. package/pennyfarthing_scripts/sprint/yaml_io.py +367 -0
  269. package/pennyfarthing_scripts/story/__init__.py +67 -0
  270. package/pennyfarthing_scripts/story/__main__.py +10 -0
  271. package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
  272. package/pennyfarthing_scripts/story/__pycache__/__main__.cpython-314.pyc +0 -0
  273. package/pennyfarthing_scripts/story/__pycache__/cli.cpython-314.pyc +0 -0
  274. package/pennyfarthing_scripts/story/__pycache__/create.cpython-314.pyc +0 -0
  275. package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
  276. package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
  277. package/pennyfarthing_scripts/story/cli.py +105 -0
  278. package/pennyfarthing_scripts/story/create.py +167 -0
  279. package/pennyfarthing_scripts/story/size.py +113 -0
  280. package/pennyfarthing_scripts/story/template.py +151 -0
  281. package/pennyfarthing_scripts/swebench.py +216 -0
  282. package/pennyfarthing_scripts/tests/__init__.py +1 -0
  283. package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
  284. package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  285. package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
  286. package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
  287. package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
  288. package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
  289. package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
  290. package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
  291. package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
  292. package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
  293. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
  294. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
  295. package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
  296. package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
  297. package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
  298. package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
  299. package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
  300. package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
  301. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
  302. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  303. package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
  304. package/pennyfarthing_scripts/tests/conftest.py +106 -0
  305. package/pennyfarthing_scripts/tests/test_brownfield.py +842 -0
  306. package/pennyfarthing_scripts/tests/test_cli_modules.py +245 -0
  307. package/pennyfarthing_scripts/tests/test_common.py +180 -0
  308. package/pennyfarthing_scripts/tests/test_git_utils.py +866 -0
  309. package/pennyfarthing_scripts/tests/test_jira_package.py +334 -0
  310. package/pennyfarthing_scripts/tests/test_package_structure.py +372 -0
  311. package/pennyfarthing_scripts/tests/test_patch_mode.py +830 -0
  312. package/pennyfarthing_scripts/tests/test_prime.py +1050 -0
  313. package/pennyfarthing_scripts/tests/test_sprint_package.py +402 -0
  314. package/pennyfarthing_scripts/tests/test_sprint_validator.py +731 -0
  315. package/pennyfarthing_scripts/tests/test_story_add.py +921 -0
  316. package/pennyfarthing_scripts/tests/test_story_package.py +156 -0
  317. package/pennyfarthing_scripts/tests/test_story_update.py +769 -0
  318. package/pennyfarthing_scripts/tests/test_tiers.py +1090 -0
  319. package/pennyfarthing_scripts/tests/test_token_counting.py +559 -0
  320. package/pennyfarthing_scripts/tests/test_validate_cmd.py +500 -0
  321. package/pennyfarthing_scripts/tests/test_workflow_check.py +341 -0
  322. package/pennyfarthing_scripts/tests/test_yaml_io.py +815 -0
  323. package/pennyfarthing_scripts/welcome_hook.py +157 -0
  324. package/pennyfarthing_scripts/workflow.py +287 -0
  325. package/scripts/postinstall.cjs +34 -0
  326. package/dist/cli/commands/cyclist.d.ts.map +0 -1
  327. package/dist/cli/commands/cyclist.js.map +0 -1
  328. package/dist/cli/commands/cyclist.test.js.map +0 -1
  329. package/dist/cli/commands/doctor.js.map +0 -1
  330. package/dist/cli/commands/init.js.map +0 -1
  331. package/dist/cli/utils/settings.js.map +0 -1
  332. package/dist/cli/utils/themes.d.ts.map +0 -1
  333. package/dist/scripts/generate-report.js.map +0 -1
  334. package/dist/scripts/generate-spider-report.js.map +0 -1
  335. package/dist/scripts/generate-spider.d.ts.map +0 -1
  336. package/dist/scripts/generate-spider.js.map +0 -1
  337. package/dist/scripts/generate-spider.test.js.map +0 -1
  338. package/pennyfarthing-dist/scripts/jira/jira-lib.sh +0 -464
  339. package/pennyfarthing-dist/scripts/jira/jira-sync.sh +0 -16
  340. package/pennyfarthing-dist/scripts/jira/sync-epic-to-jira.sh +0 -16
  341. package/pennyfarthing-dist/scripts/sprint/archive-story.sh +0 -133
  342. package/pennyfarthing-dist/scripts/sprint/available-stories.sh +0 -91
  343. package/pennyfarthing-dist/scripts/sprint/check-story.sh +0 -158
  344. package/pennyfarthing-dist/scripts/sprint/get-epic-field.sh +0 -52
  345. package/pennyfarthing-dist/scripts/sprint/get-story-field.sh +0 -63
  346. package/pennyfarthing-dist/scripts/sprint/list-future.sh +0 -145
  347. package/pennyfarthing-dist/scripts/sprint/new-sprint.sh +0 -110
  348. package/pennyfarthing-dist/scripts/sprint/promote-epic.sh +0 -148
  349. package/pennyfarthing-dist/scripts/sprint/sprint-common.sh +0 -415
  350. package/pennyfarthing-dist/scripts/sprint/sprint-info.sh +0 -33
  351. package/pennyfarthing-dist/scripts/sprint/sprint-metrics.sh +0 -230
  352. package/pennyfarthing-dist/scripts/sprint/sprint-status.sh +0 -134
  353. package/pennyfarthing-dist/scripts/sprint/validate-sprint-yaml.sh +0 -139
  354. package/pennyfarthing-dist/skills/sprint/scripts/archive-story.sh +0 -101
  355. package/pennyfarthing-dist/skills/sprint/scripts/available-stories.sh +0 -97
  356. package/pennyfarthing-dist/skills/sprint/scripts/check-story.sh +0 -164
  357. package/pennyfarthing-dist/skills/sprint/scripts/create-jira-epic.sh +0 -101
  358. package/pennyfarthing-dist/skills/sprint/scripts/new-sprint.sh +0 -116
  359. package/pennyfarthing-dist/skills/sprint/scripts/promote-epic.sh +0 -164
  360. package/pennyfarthing-dist/skills/sprint/scripts/sprint-info.sh +0 -39
  361. package/pennyfarthing-dist/skills/sprint/scripts/sprint-status.sh +0 -147
  362. package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +0 -93
  363. /package/{bin → packages/core/bin}/pennyfarthing.js +0 -0
  364. /package/{dist → packages/core/dist}/bmad/context-reader.d.ts +0 -0
  365. /package/{dist → packages/core/dist}/bmad/context-reader.d.ts.map +0 -0
  366. /package/{dist → packages/core/dist}/bmad/context-reader.js +0 -0
  367. /package/{dist → packages/core/dist}/bmad/context-reader.js.map +0 -0
  368. /package/{dist → packages/core/dist}/bmad/context-reader.test.d.ts +0 -0
  369. /package/{dist → packages/core/dist}/bmad/context-reader.test.d.ts.map +0 -0
  370. /package/{dist → packages/core/dist}/bmad/context-reader.test.js +0 -0
  371. /package/{dist → packages/core/dist}/bmad/context-reader.test.js.map +0 -0
  372. /package/{dist → packages/core/dist}/bmad/epics-parser.d.ts +0 -0
  373. /package/{dist → packages/core/dist}/bmad/epics-parser.d.ts.map +0 -0
  374. /package/{dist → packages/core/dist}/bmad/epics-parser.js +0 -0
  375. /package/{dist → packages/core/dist}/bmad/epics-parser.js.map +0 -0
  376. /package/{dist → packages/core/dist}/bmad/epics-parser.test.d.ts +0 -0
  377. /package/{dist → packages/core/dist}/bmad/epics-parser.test.d.ts.map +0 -0
  378. /package/{dist → packages/core/dist}/bmad/epics-parser.test.js +0 -0
  379. /package/{dist → packages/core/dist}/bmad/epics-parser.test.js.map +0 -0
  380. /package/{dist → packages/core/dist}/bmad/index.d.ts +0 -0
  381. /package/{dist → packages/core/dist}/bmad/index.d.ts.map +0 -0
  382. /package/{dist → packages/core/dist}/bmad/index.js +0 -0
  383. /package/{dist → packages/core/dist}/bmad/index.js.map +0 -0
  384. /package/{dist → packages/core/dist}/bmad/status-sync.d.ts +0 -0
  385. /package/{dist → packages/core/dist}/bmad/status-sync.d.ts.map +0 -0
  386. /package/{dist → packages/core/dist}/bmad/status-sync.js +0 -0
  387. /package/{dist → packages/core/dist}/bmad/status-sync.js.map +0 -0
  388. /package/{dist → packages/core/dist}/bmad/status-sync.test.d.ts +0 -0
  389. /package/{dist → packages/core/dist}/bmad/status-sync.test.d.ts.map +0 -0
  390. /package/{dist → packages/core/dist}/bmad/status-sync.test.js +0 -0
  391. /package/{dist → packages/core/dist}/bmad/status-sync.test.js.map +0 -0
  392. /package/{dist → packages/core/dist}/bmad/story-exporter.d.ts +0 -0
  393. /package/{dist → packages/core/dist}/bmad/story-exporter.d.ts.map +0 -0
  394. /package/{dist → packages/core/dist}/bmad/story-exporter.js +0 -0
  395. /package/{dist → packages/core/dist}/bmad/story-exporter.js.map +0 -0
  396. /package/{dist → packages/core/dist}/bmad/story-exporter.test.d.ts +0 -0
  397. /package/{dist → packages/core/dist}/bmad/story-exporter.test.d.ts.map +0 -0
  398. /package/{dist → packages/core/dist}/bmad/story-exporter.test.js +0 -0
  399. /package/{dist → packages/core/dist}/bmad/story-exporter.test.js.map +0 -0
  400. /package/{dist → packages/core/dist}/bmad/story-parser.d.ts +0 -0
  401. /package/{dist → packages/core/dist}/bmad/story-parser.d.ts.map +0 -0
  402. /package/{dist → packages/core/dist}/bmad/story-parser.js +0 -0
  403. /package/{dist → packages/core/dist}/bmad/story-parser.js.map +0 -0
  404. /package/{dist → packages/core/dist}/bmad/story-parser.test.d.ts +0 -0
  405. /package/{dist → packages/core/dist}/bmad/story-parser.test.d.ts.map +0 -0
  406. /package/{dist → packages/core/dist}/bmad/story-parser.test.js +0 -0
  407. /package/{dist → packages/core/dist}/bmad/story-parser.test.js.map +0 -0
  408. /package/{dist → packages/core/dist}/cli/commands/command.d.ts +0 -0
  409. /package/{dist → packages/core/dist}/cli/commands/command.d.ts.map +0 -0
  410. /package/{dist → packages/core/dist}/cli/commands/command.js +0 -0
  411. /package/{dist → packages/core/dist}/cli/commands/command.js.map +0 -0
  412. /package/{dist → packages/core/dist}/cli/commands/cyclist.test.d.ts +0 -0
  413. /package/{dist → packages/core/dist}/cli/commands/cyclist.test.d.ts.map +0 -0
  414. /package/{dist → packages/core/dist}/cli/commands/doctor-legacy.test.d.ts +0 -0
  415. /package/{dist → packages/core/dist}/cli/commands/doctor-legacy.test.d.ts.map +0 -0
  416. /package/{dist → packages/core/dist}/cli/commands/e2e-fresh-install.test.d.ts +0 -0
  417. /package/{dist → packages/core/dist}/cli/commands/e2e-fresh-install.test.d.ts.map +0 -0
  418. /package/{dist → packages/core/dist}/cli/commands/e2e-upgrade.test.d.ts +0 -0
  419. /package/{dist → packages/core/dist}/cli/commands/e2e-upgrade.test.d.ts.map +0 -0
  420. /package/{dist → packages/core/dist}/cli/commands/init-consolidation.test.d.ts +0 -0
  421. /package/{dist → packages/core/dist}/cli/commands/init-consolidation.test.d.ts.map +0 -0
  422. /package/{dist → packages/core/dist}/cli/commands/init-consolidation.test.js +0 -0
  423. /package/{dist → packages/core/dist}/cli/commands/init-consolidation.test.js.map +0 -0
  424. /package/{dist → packages/core/dist}/cli/commands/init.d.ts +0 -0
  425. /package/{dist → packages/core/dist}/cli/commands/persona-config-consolidation.test.d.ts +0 -0
  426. /package/{dist → packages/core/dist}/cli/commands/persona-config-consolidation.test.d.ts.map +0 -0
  427. /package/{dist → packages/core/dist}/cli/commands/persona-config-consolidation.test.js +0 -0
  428. /package/{dist → packages/core/dist}/cli/commands/persona-config-consolidation.test.js.map +0 -0
  429. /package/{dist → packages/core/dist}/cli/commands/skill.d.ts +0 -0
  430. /package/{dist → packages/core/dist}/cli/commands/skill.d.ts.map +0 -0
  431. /package/{dist → packages/core/dist}/cli/commands/skill.js +0 -0
  432. /package/{dist → packages/core/dist}/cli/commands/skill.js.map +0 -0
  433. /package/{dist → packages/core/dist}/cli/commands/theme.d.ts +0 -0
  434. /package/{dist → packages/core/dist}/cli/commands/theme.d.ts.map +0 -0
  435. /package/{dist → packages/core/dist}/cli/commands/theme.js +0 -0
  436. /package/{dist → packages/core/dist}/cli/commands/theme.js.map +0 -0
  437. /package/{dist → packages/core/dist}/cli/commands/uninstall.d.ts +0 -0
  438. /package/{dist → packages/core/dist}/cli/commands/uninstall.d.ts.map +0 -0
  439. /package/{dist → packages/core/dist}/cli/commands/uninstall.js +0 -0
  440. /package/{dist → packages/core/dist}/cli/commands/uninstall.js.map +0 -0
  441. /package/{dist → packages/core/dist}/cli/commands/update-consolidation.test.d.ts +0 -0
  442. /package/{dist → packages/core/dist}/cli/commands/update-consolidation.test.d.ts.map +0 -0
  443. /package/{dist → packages/core/dist}/cli/commands/update-consolidation.test.js +0 -0
  444. /package/{dist → packages/core/dist}/cli/commands/update-consolidation.test.js.map +0 -0
  445. /package/{dist → packages/core/dist}/cli/commands/update.d.ts +0 -0
  446. /package/{dist → packages/core/dist}/cli/commands/version.d.ts +0 -0
  447. /package/{dist → packages/core/dist}/cli/commands/version.d.ts.map +0 -0
  448. /package/{dist → packages/core/dist}/cli/commands/version.js +0 -0
  449. /package/{dist → packages/core/dist}/cli/commands/version.js.map +0 -0
  450. /package/{dist → packages/core/dist}/cli/customization.test.d.ts +0 -0
  451. /package/{dist → packages/core/dist}/cli/customization.test.d.ts.map +0 -0
  452. /package/{dist → packages/core/dist}/cli/customization.test.js +0 -0
  453. /package/{dist → packages/core/dist}/cli/customization.test.js.map +0 -0
  454. /package/{dist → packages/core/dist}/cli/cyclist-migration.test.d.ts +0 -0
  455. /package/{dist → packages/core/dist}/cli/cyclist-migration.test.d.ts.map +0 -0
  456. /package/{dist → packages/core/dist}/cli/cyclist-migration.test.js +0 -0
  457. /package/{dist → packages/core/dist}/cli/cyclist-migration.test.js.map +0 -0
  458. /package/{dist → packages/core/dist}/cli/index.d.ts +0 -0
  459. /package/{dist → packages/core/dist}/cli/index.d.ts.map +0 -0
  460. /package/{dist → packages/core/dist}/cli/index.js +0 -0
  461. /package/{dist → packages/core/dist}/cli/index.js.map +0 -0
  462. /package/{dist → packages/core/dist}/cli/ocean-profiles.test.d.ts +0 -0
  463. /package/{dist → packages/core/dist}/cli/ocean-profiles.test.d.ts.map +0 -0
  464. /package/{dist → packages/core/dist}/cli/theme-maker.test.d.ts +0 -0
  465. /package/{dist → packages/core/dist}/cli/theme-maker.test.d.ts.map +0 -0
  466. /package/{dist → packages/core/dist}/cli/theme-maker.test.js +0 -0
  467. /package/{dist → packages/core/dist}/cli/theme-maker.test.js.map +0 -0
  468. /package/{dist → packages/core/dist}/cli/utils/constants.d.ts +0 -0
  469. /package/{dist → packages/core/dist}/cli/utils/constants.d.ts.map +0 -0
  470. /package/{dist → packages/core/dist}/cli/utils/constants.js +0 -0
  471. /package/{dist → packages/core/dist}/cli/utils/constants.js.map +0 -0
  472. /package/{dist → packages/core/dist}/cli/utils/logger.d.ts +0 -0
  473. /package/{dist → packages/core/dist}/cli/utils/logger.d.ts.map +0 -0
  474. /package/{dist → packages/core/dist}/cli/utils/logger.js +0 -0
  475. /package/{dist → packages/core/dist}/cli/utils/logger.js.map +0 -0
  476. /package/{dist → packages/core/dist}/cli/utils/manifest.d.ts +0 -0
  477. /package/{dist → packages/core/dist}/cli/utils/manifest.d.ts.map +0 -0
  478. /package/{dist → packages/core/dist}/cli/utils/manifest.js +0 -0
  479. /package/{dist → packages/core/dist}/cli/utils/manifest.js.map +0 -0
  480. /package/{dist → packages/core/dist}/cli/utils/node-modules.d.ts +0 -0
  481. /package/{dist → packages/core/dist}/cli/utils/node-modules.d.ts.map +0 -0
  482. /package/{dist → packages/core/dist}/cli/utils/node-modules.js +0 -0
  483. /package/{dist → packages/core/dist}/cli/utils/node-modules.js.map +0 -0
  484. /package/{dist → packages/core/dist}/cli/utils/prompts.d.ts +0 -0
  485. /package/{dist → packages/core/dist}/cli/utils/prompts.d.ts.map +0 -0
  486. /package/{dist → packages/core/dist}/cli/utils/prompts.js +0 -0
  487. /package/{dist → packages/core/dist}/cli/utils/prompts.js.map +0 -0
  488. /package/{dist → packages/core/dist}/cli/utils/settings-consolidation.test.d.ts +0 -0
  489. /package/{dist → packages/core/dist}/cli/utils/settings-consolidation.test.d.ts.map +0 -0
  490. /package/{dist → packages/core/dist}/cli/utils/settings-consolidation.test.js +0 -0
  491. /package/{dist → packages/core/dist}/cli/utils/settings-consolidation.test.js.map +0 -0
  492. /package/{dist → packages/core/dist}/cli/utils/settings.d.ts +0 -0
  493. /package/{dist → packages/core/dist}/cli/utils/symlinks.d.ts +0 -0
  494. /package/{dist → packages/core/dist}/cli/utils/symlinks.d.ts.map +0 -0
  495. /package/{dist → packages/core/dist}/cli/utils/symlinks.js +0 -0
  496. /package/{dist → packages/core/dist}/cli/utils/symlinks.js.map +0 -0
  497. /package/{dist → packages/core/dist}/cli/utils/themes.js +0 -0
  498. /package/{dist → packages/core/dist}/cli/utils/themes.test.d.ts +0 -0
  499. /package/{dist → packages/core/dist}/cli/utils/themes.test.d.ts.map +0 -0
  500. /package/{dist → packages/core/dist}/cli/utils/themes.test.js +0 -0
  501. /package/{dist → packages/core/dist}/cli/utils/themes.test.js.map +0 -0
  502. /package/{dist → packages/core/dist}/cli/utils/version.d.ts +0 -0
  503. /package/{dist → packages/core/dist}/cli/utils/version.d.ts.map +0 -0
  504. /package/{dist → packages/core/dist}/cli/utils/version.js +0 -0
  505. /package/{dist → packages/core/dist}/cli/utils/version.js.map +0 -0
  506. /package/{dist → packages/core/dist}/cli/workspace.test.d.ts +0 -0
  507. /package/{dist → packages/core/dist}/cli/workspace.test.d.ts.map +0 -0
  508. /package/{dist → packages/core/dist}/cli/workspace.test.js +0 -0
  509. /package/{dist → packages/core/dist}/cli/workspace.test.js.map +0 -0
  510. /package/{dist → packages/core/dist}/index.d.ts +0 -0
  511. /package/{dist → packages/core/dist}/index.d.ts.map +0 -0
  512. /package/{dist → packages/core/dist}/index.js +0 -0
  513. /package/{dist → packages/core/dist}/index.js.map +0 -0
  514. /package/{dist → packages/core/dist}/jira/jira-epic-creation.d.ts +0 -0
  515. /package/{dist → packages/core/dist}/jira/jira-epic-creation.d.ts.map +0 -0
  516. /package/{dist → packages/core/dist}/jira/jira-epic-creation.js +0 -0
  517. /package/{dist → packages/core/dist}/jira/jira-epic-creation.js.map +0 -0
  518. /package/{dist → packages/core/dist}/jira/jira-epic-creation.test.d.ts +0 -0
  519. /package/{dist → packages/core/dist}/jira/jira-epic-creation.test.d.ts.map +0 -0
  520. /package/{dist → packages/core/dist}/jira/jira-epic-creation.test.js +0 -0
  521. /package/{dist → packages/core/dist}/jira/jira-epic-creation.test.js.map +0 -0
  522. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.d.ts +0 -0
  523. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.d.ts.map +0 -0
  524. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.js +0 -0
  525. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.js.map +0 -0
  526. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.test.d.ts +0 -0
  527. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.test.d.ts.map +0 -0
  528. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.test.js +0 -0
  529. /package/{dist → packages/core/dist}/jira/jira-sprint-sync.test.js.map +0 -0
  530. /package/{dist → packages/core/dist}/permissions/index.d.ts +0 -0
  531. /package/{dist → packages/core/dist}/permissions/index.d.ts.map +0 -0
  532. /package/{dist → packages/core/dist}/permissions/index.js +0 -0
  533. /package/{dist → packages/core/dist}/permissions/index.js.map +0 -0
  534. /package/{dist → packages/core/dist}/permissions/permission-schema.d.ts +0 -0
  535. /package/{dist → packages/core/dist}/permissions/permission-schema.d.ts.map +0 -0
  536. /package/{dist → packages/core/dist}/permissions/permission-schema.js +0 -0
  537. /package/{dist → packages/core/dist}/permissions/permission-schema.js.map +0 -0
  538. /package/{dist → packages/core/dist}/permissions/permission-schema.test.d.ts +0 -0
  539. /package/{dist → packages/core/dist}/permissions/permission-schema.test.d.ts.map +0 -0
  540. /package/{dist → packages/core/dist}/permissions/permission-schema.test.js +0 -0
  541. /package/{dist → packages/core/dist}/permissions/permission-schema.test.js.map +0 -0
  542. /package/{dist → packages/core/dist}/scripts/add-ocean-profiles.d.ts +0 -0
  543. /package/{dist → packages/core/dist}/scripts/add-ocean-profiles.d.ts.map +0 -0
  544. /package/{dist → packages/core/dist}/scripts/add-ocean-profiles.js +0 -0
  545. /package/{dist → packages/core/dist}/scripts/add-ocean-profiles.js.map +0 -0
  546. /package/{dist → packages/core/dist}/scripts/benchmark-integration.d.ts +0 -0
  547. /package/{dist → packages/core/dist}/scripts/benchmark-integration.d.ts.map +0 -0
  548. /package/{dist → packages/core/dist}/scripts/benchmark-integration.js +0 -0
  549. /package/{dist → packages/core/dist}/scripts/benchmark-integration.js.map +0 -0
  550. /package/{dist → packages/core/dist}/scripts/benchmark-integration.test.d.ts +0 -0
  551. /package/{dist → packages/core/dist}/scripts/benchmark-integration.test.d.ts.map +0 -0
  552. /package/{dist → packages/core/dist}/scripts/benchmark-integration.test.js +0 -0
  553. /package/{dist → packages/core/dist}/scripts/benchmark-integration.test.js.map +0 -0
  554. /package/{dist → packages/core/dist}/scripts/debugging-scenarios.test.d.ts +0 -0
  555. /package/{dist → packages/core/dist}/scripts/debugging-scenarios.test.d.ts.map +0 -0
  556. /package/{dist → packages/core/dist}/scripts/debugging-scenarios.test.js +0 -0
  557. /package/{dist → packages/core/dist}/scripts/debugging-scenarios.test.js.map +0 -0
  558. /package/{dist → packages/core/dist}/scripts/generate-all-spiders.d.ts +0 -0
  559. /package/{dist → packages/core/dist}/scripts/generate-all-spiders.d.ts.map +0 -0
  560. /package/{dist → packages/core/dist}/scripts/generate-all-spiders.js +0 -0
  561. /package/{dist → packages/core/dist}/scripts/generate-all-spiders.js.map +0 -0
  562. /package/{dist → packages/core/dist}/scripts/generate-report.d.ts +0 -0
  563. /package/{dist → packages/core/dist}/scripts/generate-report.test.d.ts +0 -0
  564. /package/{dist → packages/core/dist}/scripts/generate-report.test.d.ts.map +0 -0
  565. /package/{dist → packages/core/dist}/scripts/generate-report.test.js +0 -0
  566. /package/{dist → packages/core/dist}/scripts/generate-report.test.js.map +0 -0
  567. /package/{dist → packages/core/dist}/scripts/generate-spider-report.d.ts +0 -0
  568. /package/{dist → packages/core/dist}/scripts/generate-spider-report.test.d.ts +0 -0
  569. /package/{dist → packages/core/dist}/scripts/generate-spider-report.test.d.ts.map +0 -0
  570. /package/{dist → packages/core/dist}/scripts/generate-spider-report.test.js +0 -0
  571. /package/{dist → packages/core/dist}/scripts/generate-spider-report.test.js.map +0 -0
  572. /package/{dist → packages/core/dist}/scripts/generate-spider.d.ts +0 -0
  573. /package/{dist → packages/core/dist}/scripts/generate-spider.test.d.ts +0 -0
  574. /package/{dist → packages/core/dist}/scripts/generate-spider.test.d.ts.map +0 -0
  575. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.d.ts +0 -0
  576. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.d.ts.map +0 -0
  577. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.js +0 -0
  578. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.js.map +0 -0
  579. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.test.d.ts +0 -0
  580. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.test.d.ts.map +0 -0
  581. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.test.js +0 -0
  582. /package/{dist → packages/core/dist}/scripts/job-fair-aggregator.test.js.map +0 -0
  583. /package/{dist → packages/core/dist}/scripts/run-ci.test.d.ts +0 -0
  584. /package/{dist → packages/core/dist}/scripts/run-ci.test.d.ts.map +0 -0
  585. /package/{dist → packages/core/dist}/scripts/run-ci.test.js +0 -0
  586. /package/{dist → packages/core/dist}/scripts/run-ci.test.js.map +0 -0
  587. /package/{dist → packages/core/dist}/scripts/theme-detail.test.d.ts +0 -0
  588. /package/{dist → packages/core/dist}/scripts/theme-detail.test.d.ts.map +0 -0
  589. /package/{dist → packages/core/dist}/scripts/theme-detail.test.js +0 -0
  590. /package/{dist → packages/core/dist}/scripts/theme-detail.test.js.map +0 -0
  591. /package/{dist → packages/core/dist}/scripts/validate-ocean-profiles.d.ts +0 -0
  592. /package/{dist → packages/core/dist}/scripts/validate-ocean-profiles.d.ts.map +0 -0
  593. /package/{dist → packages/core/dist}/scripts/validate-ocean-profiles.js +0 -0
  594. /package/{dist → packages/core/dist}/scripts/validate-ocean-profiles.js.map +0 -0
  595. /package/{dist → packages/core/dist}/workflow/complete-step-integration.test.d.ts +0 -0
  596. /package/{dist → packages/core/dist}/workflow/complete-step-integration.test.d.ts.map +0 -0
  597. /package/{dist → packages/core/dist}/workflow/complete-step-integration.test.js +0 -0
  598. /package/{dist → packages/core/dist}/workflow/complete-step-integration.test.js.map +0 -0
  599. /package/{dist → packages/core/dist}/workflow/gate-handler.d.ts +0 -0
  600. /package/{dist → packages/core/dist}/workflow/gate-handler.d.ts.map +0 -0
  601. /package/{dist → packages/core/dist}/workflow/gate-handler.js +0 -0
  602. /package/{dist → packages/core/dist}/workflow/gate-handler.js.map +0 -0
  603. /package/{dist → packages/core/dist}/workflow/gate-handler.test.d.ts +0 -0
  604. /package/{dist → packages/core/dist}/workflow/gate-handler.test.d.ts.map +0 -0
  605. /package/{dist → packages/core/dist}/workflow/gate-handler.test.js +0 -0
  606. /package/{dist → packages/core/dist}/workflow/gate-handler.test.js.map +0 -0
  607. /package/{dist → packages/core/dist}/workflow/generic-sm-finish.d.ts +0 -0
  608. /package/{dist → packages/core/dist}/workflow/generic-sm-finish.d.ts.map +0 -0
  609. /package/{dist → packages/core/dist}/workflow/generic-sm-finish.js +0 -0
  610. /package/{dist → packages/core/dist}/workflow/generic-sm-finish.js.map +0 -0
  611. /package/{dist → packages/core/dist}/workflow/generic-sm-setup.d.ts +0 -0
  612. /package/{dist → packages/core/dist}/workflow/generic-sm-setup.d.ts.map +0 -0
  613. /package/{dist → packages/core/dist}/workflow/generic-sm-setup.js +0 -0
  614. /package/{dist → packages/core/dist}/workflow/generic-sm-setup.js.map +0 -0
  615. /package/{dist → packages/core/dist}/workflow/handoff.d.ts +0 -0
  616. /package/{dist → packages/core/dist}/workflow/handoff.d.ts.map +0 -0
  617. /package/{dist → packages/core/dist}/workflow/handoff.js +0 -0
  618. /package/{dist → packages/core/dist}/workflow/handoff.js.map +0 -0
  619. /package/{dist → packages/core/dist}/workflow/handoff.test.d.ts +0 -0
  620. /package/{dist → packages/core/dist}/workflow/handoff.test.d.ts.map +0 -0
  621. /package/{dist → packages/core/dist}/workflow/handoff.test.js +0 -0
  622. /package/{dist → packages/core/dist}/workflow/handoff.test.js.map +0 -0
  623. /package/{dist → packages/core/dist}/workflow/index.d.ts +0 -0
  624. /package/{dist → packages/core/dist}/workflow/index.d.ts.map +0 -0
  625. /package/{dist → packages/core/dist}/workflow/index.js +0 -0
  626. /package/{dist → packages/core/dist}/workflow/index.js.map +0 -0
  627. /package/{dist → packages/core/dist}/workflow/session-state.d.ts +0 -0
  628. /package/{dist → packages/core/dist}/workflow/session-state.d.ts.map +0 -0
  629. /package/{dist → packages/core/dist}/workflow/session-state.js +0 -0
  630. /package/{dist → packages/core/dist}/workflow/session-state.js.map +0 -0
  631. /package/{dist → packages/core/dist}/workflow/session-state.test.d.ts +0 -0
  632. /package/{dist → packages/core/dist}/workflow/session-state.test.d.ts.map +0 -0
  633. /package/{dist → packages/core/dist}/workflow/session-state.test.js +0 -0
  634. /package/{dist → packages/core/dist}/workflow/session-state.test.js.map +0 -0
  635. /package/{dist → packages/core/dist}/workflow/sm-subagents.test.d.ts +0 -0
  636. /package/{dist → packages/core/dist}/workflow/sm-subagents.test.d.ts.map +0 -0
  637. /package/{dist → packages/core/dist}/workflow/sm-subagents.test.js +0 -0
  638. /package/{dist → packages/core/dist}/workflow/sm-subagents.test.js.map +0 -0
  639. /package/{dist → packages/core/dist}/workflow/step-parser.d.ts +0 -0
  640. /package/{dist → packages/core/dist}/workflow/step-parser.d.ts.map +0 -0
  641. /package/{dist → packages/core/dist}/workflow/step-parser.js +0 -0
  642. /package/{dist → packages/core/dist}/workflow/step-parser.js.map +0 -0
  643. /package/{dist → packages/core/dist}/workflow/step-parser.test.d.ts +0 -0
  644. /package/{dist → packages/core/dist}/workflow/step-parser.test.d.ts.map +0 -0
  645. /package/{dist → packages/core/dist}/workflow/step-parser.test.js +0 -0
  646. /package/{dist → packages/core/dist}/workflow/step-parser.test.js.map +0 -0
  647. /package/{dist → packages/core/dist}/workflow/story-workflow-routing.test.d.ts +0 -0
  648. /package/{dist → packages/core/dist}/workflow/story-workflow-routing.test.d.ts.map +0 -0
  649. /package/{dist → packages/core/dist}/workflow/story-workflow-routing.test.js +0 -0
  650. /package/{dist → packages/core/dist}/workflow/story-workflow-routing.test.js.map +0 -0
  651. /package/{dist → packages/core/dist}/workflow/test-cache.d.ts +0 -0
  652. /package/{dist → packages/core/dist}/workflow/test-cache.d.ts.map +0 -0
  653. /package/{dist → packages/core/dist}/workflow/test-cache.js +0 -0
  654. /package/{dist → packages/core/dist}/workflow/test-cache.js.map +0 -0
  655. /package/{dist → packages/core/dist}/workflow/test-cache.test.d.ts +0 -0
  656. /package/{dist → packages/core/dist}/workflow/test-cache.test.d.ts.map +0 -0
  657. /package/{dist → packages/core/dist}/workflow/test-cache.test.js +0 -0
  658. /package/{dist → packages/core/dist}/workflow/test-cache.test.js.map +0 -0
  659. /package/{dist → packages/core/dist}/workflow/trimodal.d.ts +0 -0
  660. /package/{dist → packages/core/dist}/workflow/trimodal.d.ts.map +0 -0
  661. /package/{dist → packages/core/dist}/workflow/trimodal.js +0 -0
  662. /package/{dist → packages/core/dist}/workflow/trimodal.js.map +0 -0
  663. /package/{dist → packages/core/dist}/workflow/trimodal.test.d.ts +0 -0
  664. /package/{dist → packages/core/dist}/workflow/trimodal.test.d.ts.map +0 -0
  665. /package/{dist → packages/core/dist}/workflow/trimodal.test.js +0 -0
  666. /package/{dist → packages/core/dist}/workflow/trimodal.test.js.map +0 -0
  667. /package/{dist → packages/core/dist}/workflow/variable-resolver.d.ts +0 -0
  668. /package/{dist → packages/core/dist}/workflow/variable-resolver.d.ts.map +0 -0
  669. /package/{dist → packages/core/dist}/workflow/variable-resolver.js +0 -0
  670. /package/{dist → packages/core/dist}/workflow/variable-resolver.js.map +0 -0
  671. /package/{dist → packages/core/dist}/workflow/variable-resolver.test.d.ts +0 -0
  672. /package/{dist → packages/core/dist}/workflow/variable-resolver.test.d.ts.map +0 -0
  673. /package/{dist → packages/core/dist}/workflow/variable-resolver.test.js +0 -0
  674. /package/{dist → packages/core/dist}/workflow/variable-resolver.test.js.map +0 -0
  675. /package/{dist → packages/core/dist}/workflow/workflow-executor.d.ts +0 -0
  676. /package/{dist → packages/core/dist}/workflow/workflow-executor.d.ts.map +0 -0
  677. /package/{dist → packages/core/dist}/workflow/workflow-executor.js +0 -0
  678. /package/{dist → packages/core/dist}/workflow/workflow-executor.js.map +0 -0
  679. /package/{dist → packages/core/dist}/workflow/workflow-executor.test.d.ts +0 -0
  680. /package/{dist → packages/core/dist}/workflow/workflow-executor.test.d.ts.map +0 -0
  681. /package/{dist → packages/core/dist}/workflow/workflow-executor.test.js +0 -0
  682. /package/{dist → packages/core/dist}/workflow/workflow-executor.test.js.map +0 -0
  683. /package/{dist → packages/core/dist}/workflow/workflow-loader.d.ts +0 -0
  684. /package/{dist → packages/core/dist}/workflow/workflow-loader.d.ts.map +0 -0
  685. /package/{dist → packages/core/dist}/workflow/workflow-loader.js +0 -0
  686. /package/{dist → packages/core/dist}/workflow/workflow-loader.js.map +0 -0
  687. /package/{dist → packages/core/dist}/workflow/workflow-loader.test.d.ts +0 -0
  688. /package/{dist → packages/core/dist}/workflow/workflow-loader.test.d.ts.map +0 -0
  689. /package/{dist → packages/core/dist}/workflow/workflow-loader.test.js +0 -0
  690. /package/{dist → packages/core/dist}/workflow/workflow-loader.test.js.map +0 -0
  691. /package/{dist → packages/core/dist}/workflow/workflow-migration.test.d.ts +0 -0
  692. /package/{dist → packages/core/dist}/workflow/workflow-migration.test.d.ts.map +0 -0
  693. /package/{dist → packages/core/dist}/workflow/workflow-migration.test.js +0 -0
  694. /package/{dist → packages/core/dist}/workflow/workflow-migration.test.js.map +0 -0
  695. /package/{dist → packages/core/dist}/workflow/workflow-permissions.d.ts +0 -0
  696. /package/{dist → packages/core/dist}/workflow/workflow-permissions.d.ts.map +0 -0
  697. /package/{dist → packages/core/dist}/workflow/workflow-permissions.js +0 -0
  698. /package/{dist → packages/core/dist}/workflow/workflow-permissions.js.map +0 -0
  699. /package/{dist → packages/core/dist}/workflow/workflow-permissions.test.d.ts +0 -0
  700. /package/{dist → packages/core/dist}/workflow/workflow-permissions.test.d.ts.map +0 -0
  701. /package/{dist → packages/core/dist}/workflow/workflow-permissions.test.js +0 -0
  702. /package/{dist → packages/core/dist}/workflow/workflow-permissions.test.js.map +0 -0
  703. /package/{dist → packages/core/dist}/workflow/workflow-router.d.ts +0 -0
  704. /package/{dist → packages/core/dist}/workflow/workflow-router.d.ts.map +0 -0
  705. /package/{dist → packages/core/dist}/workflow/workflow-router.js +0 -0
  706. /package/{dist → packages/core/dist}/workflow/workflow-router.js.map +0 -0
  707. /package/{dist → packages/core/dist}/workflow/workflow-router.test.d.ts +0 -0
  708. /package/{dist → packages/core/dist}/workflow/workflow-router.test.d.ts.map +0 -0
  709. /package/{dist → packages/core/dist}/workflow/workflow-router.test.js +0 -0
  710. /package/{dist → packages/core/dist}/workflow/workflow-router.test.js.map +0 -0
  711. /package/{dist → packages/core/dist}/workflow/workflow-schema.d.ts +0 -0
  712. /package/{dist → packages/core/dist}/workflow/workflow-schema.d.ts.map +0 -0
  713. /package/{dist → packages/core/dist}/workflow/workflow-schema.js +0 -0
  714. /package/{dist → packages/core/dist}/workflow/workflow-schema.js.map +0 -0
  715. /package/{dist → packages/core/dist}/workflow/workflow-schema.test.d.ts +0 -0
  716. /package/{dist → packages/core/dist}/workflow/workflow-schema.test.d.ts.map +0 -0
  717. /package/{dist → packages/core/dist}/workflow/workflow-schema.test.js +0 -0
  718. /package/{dist → packages/core/dist}/workflow/workflow-schema.test.js.map +0 -0
  719. /package/{dist → packages/core/dist}/workflow/workflow-stepped-schema.test.d.ts +0 -0
  720. /package/{dist → packages/core/dist}/workflow/workflow-stepped-schema.test.d.ts.map +0 -0
  721. /package/{dist → packages/core/dist}/workflow/workflow-stepped-schema.test.js +0 -0
  722. /package/{dist → packages/core/dist}/workflow/workflow-stepped-schema.test.js.map +0 -0
@@ -0,0 +1,277 @@
1
+ """
2
+ Workflow state detection for Prime v2.
3
+
4
+ Detects current workflow state by analyzing:
5
+ - Active session files in .session/
6
+ - Session headers for phase and workflow
7
+ - Sprint backlog for available stories
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import re
13
+ from pathlib import Path
14
+ from typing import Any
15
+
16
+ import yaml
17
+
18
+ from pennyfarthing_scripts.common.config import get_project_root
19
+ from pennyfarthing_scripts.prime.models import WorkflowState, WorkflowStatus
20
+
21
+
22
+ def find_active_session(project_root: Path) -> Path | None:
23
+ """Find the active session file.
24
+
25
+ Looks in .session/ for *-session.md files, excluding context-*.md.
26
+ Returns the most recently modified session file.
27
+
28
+ Args:
29
+ project_root: Project root path
30
+
31
+ Returns:
32
+ Path to active session file, or None if not found
33
+ """
34
+ session_dir = project_root / ".session"
35
+ if not session_dir.is_dir():
36
+ return None
37
+
38
+ # Find *-session.md files (not context-*)
39
+ session_files = [
40
+ f for f in session_dir.glob("*-session.md")
41
+ if not f.name.startswith("context-")
42
+ ]
43
+
44
+ if not session_files:
45
+ return None
46
+
47
+ # Return the most recently modified one
48
+ return max(session_files, key=lambda f: f.stat().st_mtime)
49
+
50
+
51
+ def parse_session_header(session_path: Path) -> dict[str, Any]:
52
+ """Parse session file header to extract metadata.
53
+
54
+ Looks for key: value patterns throughout the session file header sections.
55
+ Extracts workflow, phase, story_id, status from:
56
+ - ## Story Context section
57
+ - ## Workflow Phase section
58
+
59
+ Args:
60
+ session_path: Path to session file
61
+
62
+ Returns:
63
+ Dict with extracted metadata (workflow, phase, story_id, status)
64
+ """
65
+ content = session_path.read_text()
66
+ lines = content.split("\n")
67
+
68
+ result: dict[str, Any] = {}
69
+
70
+ # Extract story ID from filename (e.g., MSSCI-12419-session.md -> MSSCI-12419)
71
+ filename = session_path.stem
72
+ if filename.endswith("-session"):
73
+ result["story_id"] = filename[:-8] # Remove "-session"
74
+
75
+ # Track which sections we're in (we care about Story Context and Workflow Phase)
76
+ in_relevant_section = True # Start True to capture content before any ##
77
+
78
+ for line in lines:
79
+ # Track section headers
80
+ if line.startswith("## "):
81
+ # We care about Story Context and Workflow Phase sections
82
+ section_name = line[3:].strip().lower()
83
+ in_relevant_section = (
84
+ "story context" in section_name or
85
+ "workflow phase" in section_name or
86
+ "branch" in section_name
87
+ )
88
+ # Stop at assessment sections (too far down)
89
+ if "assessment" in section_name:
90
+ break
91
+ continue
92
+
93
+ # Only parse lines in relevant sections
94
+ if not in_relevant_section:
95
+ continue
96
+
97
+ # Look for key-value patterns
98
+ # Format is "**Key:** Value" (colon inside the bold)
99
+ # e.g., "- **Workflow:** tdd" or "- **Current Phase:** green"
100
+ match = re.search(r"\*\*([^*:]+):\*\*\s*(.+)", line)
101
+ if match:
102
+ key = match.group(1).lower().strip()
103
+ value = match.group(2).strip()
104
+
105
+ if key == "workflow":
106
+ result["workflow"] = value.lower()
107
+ elif key == "current phase":
108
+ # Extract phase name, handling "(APPROVED)" suffix
109
+ phase_match = re.match(r"(\w+)(?:\s*\(([^)]+)\))?", value)
110
+ if phase_match:
111
+ result["phase"] = phase_match.group(1).lower()
112
+ if phase_match.group(2):
113
+ result["phase_status"] = phase_match.group(2).lower()
114
+ elif key == "id" and "story_id" not in result:
115
+ result["story_id"] = value
116
+ elif key == "status":
117
+ result["status"] = value.lower()
118
+
119
+ return result
120
+
121
+
122
+ def get_phase_owner(workflow: str, phase: str, project_root: Path) -> str | None:
123
+ """Look up the agent that owns a workflow phase.
124
+
125
+ Reads the workflow YAML and finds the agent for the given phase.
126
+
127
+ Args:
128
+ workflow: Workflow name (tdd, trivial, bdd, etc.)
129
+ phase: Phase name (setup, red, green, review, finish)
130
+ project_root: Project root path
131
+
132
+ Returns:
133
+ Agent name (sm, tea, dev, reviewer), or None if not found
134
+ """
135
+ workflow_path = project_root / "pennyfarthing-dist" / "workflows" / f"{workflow}.yaml"
136
+
137
+ if not workflow_path.exists():
138
+ # Fallback to symlinked location
139
+ workflow_path = project_root / ".pennyfarthing" / "workflows" / f"{workflow}.yaml"
140
+ if not workflow_path.exists():
141
+ return None
142
+
143
+ try:
144
+ data = yaml.safe_load(workflow_path.read_text())
145
+ phases = data.get("workflow", {}).get("phases", [])
146
+
147
+ for p in phases:
148
+ if p.get("name") == phase:
149
+ return p.get("agent")
150
+
151
+ return None
152
+ except Exception:
153
+ return None
154
+
155
+
156
+ def get_backlog_count(project_root: Path) -> int:
157
+ """Count stories in backlog, ready, or planning status.
158
+
159
+ Args:
160
+ project_root: Project root path
161
+
162
+ Returns:
163
+ Number of stories available for work
164
+ """
165
+ # Import here to avoid circular imports
166
+ from pennyfarthing_scripts.sprint.loader import load_sprint
167
+
168
+ sprint = load_sprint(project_root)
169
+ if not sprint or "epics" not in sprint:
170
+ return 0
171
+
172
+ count = 0
173
+ for epic in sprint["epics"]:
174
+ if not isinstance(epic, dict):
175
+ continue # Skip string refs (defensive)
176
+ for story in epic.get("stories", []):
177
+ status = story.get("status", "").lower()
178
+ if status in ("backlog", "ready", "planning"):
179
+ count += 1
180
+
181
+ return count
182
+
183
+
184
+ def detect_workflow_state(project_root: Path | None = None) -> WorkflowStatus:
185
+ """Detect the current workflow state.
186
+
187
+ Returns one of:
188
+ - FINISH_STATE: Session exists with phase=approved or review-approved
189
+ - IN_PROGRESS_STATE: Session exists with active phase
190
+ - NEW_WORK_STATE: No session and backlog has stories
191
+ - EMPTY_BACKLOG_STATE: No session and backlog is empty
192
+
193
+ Args:
194
+ project_root: Project root path (auto-detected if not provided)
195
+
196
+ Returns:
197
+ WorkflowStatus with detected state and metadata
198
+ """
199
+ root = project_root or get_project_root()
200
+ session_file = find_active_session(root)
201
+
202
+ if session_file:
203
+ header = parse_session_header(session_file)
204
+ story_id = header.get("story_id")
205
+ workflow = header.get("workflow", "tdd")
206
+ phase = header.get("phase")
207
+ phase_status = header.get("phase_status", "")
208
+
209
+ # Check for finish state
210
+ if phase in ("approved", "review-approved", "finish"):
211
+ return WorkflowStatus(
212
+ state=WorkflowState.FINISH_STATE,
213
+ story_id=story_id,
214
+ phase=phase,
215
+ phase_owner="sm",
216
+ workflow=workflow,
217
+ session_file=str(session_file),
218
+ )
219
+
220
+ # Check if phase is approved (e.g., "REVIEW (APPROVED)")
221
+ if phase_status == "approved":
222
+ return WorkflowStatus(
223
+ state=WorkflowState.FINISH_STATE,
224
+ story_id=story_id,
225
+ phase=phase,
226
+ phase_owner="sm",
227
+ workflow=workflow,
228
+ session_file=str(session_file),
229
+ )
230
+
231
+ # In progress state - look up phase owner
232
+ owner = get_phase_owner(workflow, phase, root) if phase else None
233
+
234
+ return WorkflowStatus(
235
+ state=WorkflowState.IN_PROGRESS_STATE,
236
+ story_id=story_id,
237
+ phase=phase,
238
+ phase_owner=owner,
239
+ workflow=workflow,
240
+ session_file=str(session_file),
241
+ )
242
+
243
+ # No active session - check backlog
244
+ backlog_count = get_backlog_count(root)
245
+
246
+ if backlog_count > 0:
247
+ return WorkflowStatus(
248
+ state=WorkflowState.NEW_WORK_STATE,
249
+ backlog_count=backlog_count,
250
+ )
251
+
252
+ return WorkflowStatus(
253
+ state=WorkflowState.EMPTY_BACKLOG_STATE,
254
+ )
255
+
256
+
257
+ def check_redirect(workflow_status: WorkflowStatus, agent_name: str) -> tuple[str, str] | None:
258
+ """Check if the activated agent should redirect to another agent.
259
+
260
+ Returns redirect info if:
261
+ - IN_PROGRESS_STATE and agent_name != phase_owner
262
+
263
+ Args:
264
+ workflow_status: Current workflow status
265
+ agent_name: Name of the activated agent
266
+
267
+ Returns:
268
+ Tuple of (target_agent, reason) if redirect needed, None otherwise
269
+ """
270
+ if workflow_status.state == WorkflowState.IN_PROGRESS_STATE:
271
+ if workflow_status.phase_owner and workflow_status.phase_owner != agent_name:
272
+ return (
273
+ workflow_status.phase_owner,
274
+ f"Phase '{workflow_status.phase}' is owned by '{workflow_status.phase_owner}'",
275
+ )
276
+
277
+ return None
@@ -0,0 +1,306 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ XML Schema Validation Hook for PreToolUse.
4
+
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
22
+ """
23
+
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
+ read_stdin_json,
33
+ output_hook_response,
34
+ HookResponse,
35
+ )
36
+
37
+
38
+ # =============================================================================
39
+ # File Type Detection
40
+ # =============================================================================
41
+
42
+
43
+ def is_session_file(file_path: str) -> bool:
44
+ """Check if path is a session file."""
45
+ return file_path.endswith("-session.md") and ".session/" in file_path
46
+
47
+
48
+ def is_skill_file(file_path: str) -> bool:
49
+ """Check if path is a skill SKILL.md file."""
50
+ return file_path.endswith("/SKILL.md") and "/skills/" in file_path
51
+
52
+
53
+ def is_step_file(file_path: str) -> bool:
54
+ """Check if path is a workflow step file."""
55
+ path = Path(file_path)
56
+ return (
57
+ path.name.startswith("step-")
58
+ and path.name.endswith(".md")
59
+ and "/workflows/" in file_path
60
+ and "/steps/" in file_path
61
+ )
62
+
63
+
64
+ def get_file_type(file_path: str) -> str | None:
65
+ """Detect file type from path."""
66
+ if is_session_file(file_path):
67
+ return "session"
68
+ elif is_skill_file(file_path):
69
+ return "skill"
70
+ elif is_step_file(file_path):
71
+ return "step"
72
+ return None
73
+
74
+
75
+ # =============================================================================
76
+ # Content-Based Validation (inline to avoid import issues)
77
+ # =============================================================================
78
+
79
+ # Skill required tags
80
+ SKILL_REQUIRED_TAGS = ["run", "output"]
81
+
82
+ # Workflow step required tags
83
+ STEP_REQUIRED_TAGS = ["purpose", "instructions", "output"]
84
+
85
+ # Step meta required fields
86
+ STEP_META_FIELDS = ["step", "workflow", "agent", "next"]
87
+
88
+
89
+ def _has_tag(content: str, tag: str) -> bool:
90
+ """Check if content contains a specific XML tag."""
91
+ return f"<{tag}>" in content or f"<{tag} " in content
92
+
93
+
94
+ def validate_session_content(content: str) -> list[str]:
95
+ """Validate session file content.
96
+
97
+ Args:
98
+ content: File content to validate
99
+
100
+ Returns:
101
+ List of error messages (empty if valid)
102
+ """
103
+ errors = []
104
+
105
+ # Check for XML format indicator
106
+ if "<session" not in content:
107
+ # Old markdown format - warn but don't block during migration
108
+ return []
109
+
110
+ # Validate <session> root with attributes
111
+ if not re.search(r'<session\s+story="[^"]+"', content):
112
+ errors.append("Missing story attribute on <session>")
113
+
114
+ if not re.search(r'<session[^>]+workflow="[^"]+"', content):
115
+ errors.append("Missing workflow attribute on <session>")
116
+
117
+ # Validate <meta> section
118
+ if not _has_tag(content, "meta"):
119
+ errors.append("Missing <meta> section")
120
+ else:
121
+ if "<jira>" not in content:
122
+ errors.append("Missing <jira> in <meta>")
123
+ if "<started>" not in content:
124
+ errors.append("Missing <started> in <meta>")
125
+
126
+ # Validate <status> element
127
+ if not _has_tag(content, "status"):
128
+ errors.append("Missing <status> element")
129
+ else:
130
+ if 'phase="' not in content:
131
+ errors.append("Missing phase attribute on <status>")
132
+
133
+ return errors
134
+
135
+
136
+ def validate_skill_content(content: str) -> list[str]:
137
+ """Validate skill file content.
138
+
139
+ Args:
140
+ content: File content to validate
141
+
142
+ Returns:
143
+ List of error messages (empty if valid)
144
+ """
145
+ errors = []
146
+
147
+ # Check YAML frontmatter
148
+ if not content.startswith("---\n"):
149
+ errors.append("Missing YAML frontmatter")
150
+ else:
151
+ parts = content.split("---", 2)
152
+ if len(parts) >= 2:
153
+ frontmatter = parts[1]
154
+ if "name:" not in frontmatter:
155
+ errors.append("Missing 'name' in frontmatter")
156
+ if "description:" not in frontmatter:
157
+ errors.append("Missing 'description' in frontmatter")
158
+
159
+ # Check required tags
160
+ for tag in SKILL_REQUIRED_TAGS:
161
+ if not _has_tag(content, tag):
162
+ errors.append(f"Missing <{tag}> tag (required)")
163
+
164
+ return errors
165
+
166
+
167
+ def validate_step_content(content: str) -> list[str]:
168
+ """Validate workflow step file content.
169
+
170
+ Args:
171
+ content: File content to validate
172
+
173
+ Returns:
174
+ List of error messages (empty if valid)
175
+ """
176
+ errors = []
177
+
178
+ # Check required tags
179
+ for tag in STEP_REQUIRED_TAGS:
180
+ if not _has_tag(content, tag):
181
+ errors.append(f"Missing <{tag}> tag")
182
+
183
+ # Check step-meta fields if tag exists
184
+ if _has_tag(content, "step-meta"):
185
+ meta_match = re.search(r"<step-meta>(.+?)</step-meta>", content, re.DOTALL)
186
+ if meta_match:
187
+ meta_content = meta_match.group(1)
188
+ for field_name in STEP_META_FIELDS:
189
+ if f"{field_name}:" not in meta_content:
190
+ errors.append(f"Missing '{field_name}' in step-meta")
191
+
192
+ return errors
193
+
194
+
195
+ def validate_content(file_path: str, content: str) -> list[str]:
196
+ """Validate content based on file type.
197
+
198
+ Args:
199
+ file_path: Path to file being written
200
+ content: Content being written
201
+
202
+ Returns:
203
+ List of error messages (empty if valid)
204
+ """
205
+ file_type = get_file_type(file_path)
206
+
207
+ if file_type == "session":
208
+ return validate_session_content(content)
209
+ elif file_type == "skill":
210
+ return validate_skill_content(content)
211
+ elif file_type == "step":
212
+ return validate_step_content(content)
213
+
214
+ return []
215
+
216
+
217
+ # =============================================================================
218
+ # Hook Entry Point
219
+ # =============================================================================
220
+
221
+
222
+ def main() -> None:
223
+ """Main entry point for schema validation hook."""
224
+ try:
225
+ # Read tool data from Claude Code
226
+ tool_data = read_stdin_json()
227
+
228
+ tool_name = tool_data.get("tool_name", "")
229
+ tool_input = tool_data.get("tool_input", {})
230
+
231
+ # Only process Write and Edit tools
232
+ if tool_name not in ("Write", "Edit"):
233
+ output_hook_response(HookResponse(
234
+ event_name="PreToolUse",
235
+ decision="allow",
236
+ reason="Not a Write/Edit operation",
237
+ ))
238
+ sys.exit(0)
239
+
240
+ # Get file path
241
+ file_path = tool_input.get("file_path", "")
242
+ if not file_path:
243
+ output_hook_response(HookResponse(
244
+ event_name="PreToolUse",
245
+ decision="allow",
246
+ reason="No file path",
247
+ ))
248
+ sys.exit(0)
249
+
250
+ # Check if this is a file we care about
251
+ file_type = get_file_type(file_path)
252
+ if not file_type:
253
+ output_hook_response(HookResponse(
254
+ event_name="PreToolUse",
255
+ decision="allow",
256
+ reason="Not a session/skill/step file",
257
+ ))
258
+ sys.exit(0)
259
+
260
+ # Get content to validate
261
+ # For Write: use 'content'
262
+ # For Edit: we need to simulate the edit result
263
+ if tool_name == "Write":
264
+ content = tool_input.get("content", "")
265
+ else:
266
+ # Edit operation - we can't easily validate without reading the file
267
+ # For now, allow Edits and validate on Write only
268
+ output_hook_response(HookResponse(
269
+ event_name="PreToolUse",
270
+ decision="allow",
271
+ reason="Edit operations validated post-hoc",
272
+ ))
273
+ sys.exit(0)
274
+
275
+ # Validate content
276
+ errors = validate_content(file_path, content)
277
+
278
+ if errors:
279
+ # Block the write
280
+ error_msg = f"Schema validation failed for {file_type} file:\n"
281
+ error_msg += "\n".join(f" - {e}" for e in errors)
282
+ error_msg += f"\n\nFile: {file_path}"
283
+
284
+ output_hook_response(HookResponse(
285
+ event_name="PreToolUse",
286
+ decision="deny",
287
+ reason=error_msg,
288
+ ))
289
+ sys.exit(0)
290
+
291
+ # Validation passed
292
+ output_hook_response(HookResponse(
293
+ event_name="PreToolUse",
294
+ decision="allow",
295
+ reason=f"Schema validation passed for {file_type} file",
296
+ ))
297
+ sys.exit(0)
298
+
299
+ except Exception as e:
300
+ # On error, allow to avoid blocking legitimate work
301
+ print(f"[schema-validation-hook] Error: {e}", file=sys.stderr)
302
+ sys.exit(0)
303
+
304
+
305
+ if __name__ == "__main__":
306
+ main()
@@ -0,0 +1,66 @@
1
+ """
2
+ Sprint management package for Pennyfarthing scripts.
3
+
4
+ This package provides:
5
+ - loader: Sprint YAML loading and parsing
6
+ - status: Sprint status operations
7
+ - work: Work session management
8
+ - archive: Story archiving
9
+
10
+ Usage:
11
+ # Use the loader module
12
+ from pennyfarthing_scripts.sprint import load_sprint, find_epic
13
+ sprint_data = load_sprint()
14
+ epic = find_epic(sprint_data, "63")
15
+
16
+ # Use CLI
17
+ python -m pennyfarthing_scripts.sprint <subcommand> [args]
18
+ """
19
+
20
+ # Re-export from loader for backwards compatibility
21
+ from pennyfarthing_scripts.sprint.loader import (
22
+ find_epic,
23
+ find_story,
24
+ get_all_stories,
25
+ get_epic_by_id,
26
+ get_sprint_info,
27
+ get_stories_by_status,
28
+ get_story_by_id,
29
+ get_story_field,
30
+ load_current_sprint,
31
+ load_sprint,
32
+ )
33
+
34
+ # Import submodules to make them accessible
35
+ from pennyfarthing_scripts.sprint import (
36
+ archive,
37
+ loader,
38
+ status,
39
+ work,
40
+ )
41
+
42
+ # CLI entry point - import module, not function, so "from sprint import cli" gets the module
43
+ from pennyfarthing_scripts.sprint import cli
44
+ from pennyfarthing_scripts.sprint.cli import main
45
+
46
+ __all__ = [
47
+ # Loader functions
48
+ "find_epic",
49
+ "find_story",
50
+ "get_all_stories",
51
+ "get_epic_by_id",
52
+ "get_sprint_info",
53
+ "get_stories_by_status",
54
+ "get_story_by_id",
55
+ "get_story_field",
56
+ "load_current_sprint",
57
+ "load_sprint",
58
+ # Submodules
59
+ "archive",
60
+ "loader",
61
+ "status",
62
+ "work",
63
+ # CLI
64
+ "cli",
65
+ "main",
66
+ ]
@@ -0,0 +1,10 @@
1
+ """
2
+ Entry point for python -m pennyfarthing_scripts.sprint
3
+ """
4
+
5
+ import sys
6
+
7
+ from pennyfarthing_scripts.sprint.cli import cli
8
+
9
+ if __name__ == "__main__":
10
+ sys.exit(cli())