@pennyfarthing/core 7.9.2 → 7.9.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 (538) hide show
  1. package/package.json +2 -2
  2. package/pennyfarthing-dist/agents/README.md +348 -0
  3. package/pennyfarthing-dist/agents/architect.md +180 -0
  4. package/pennyfarthing-dist/agents/dev.md +169 -0
  5. package/pennyfarthing-dist/agents/devops.md +203 -0
  6. package/pennyfarthing-dist/agents/handoff.md +235 -0
  7. package/pennyfarthing-dist/agents/orchestrator.md +182 -0
  8. package/pennyfarthing-dist/agents/pm.md +152 -0
  9. package/pennyfarthing-dist/agents/reviewer-preflight.md +129 -0
  10. package/pennyfarthing-dist/agents/reviewer.md +180 -0
  11. package/pennyfarthing-dist/agents/sm-file-summary.md +79 -0
  12. package/pennyfarthing-dist/agents/sm-finish.md +82 -0
  13. package/pennyfarthing-dist/agents/sm-handoff.md +129 -0
  14. package/pennyfarthing-dist/agents/sm-setup.md +251 -0
  15. package/pennyfarthing-dist/agents/sm.md +284 -0
  16. package/pennyfarthing-dist/agents/tea.md +161 -0
  17. package/pennyfarthing-dist/agents/tech-writer.md +226 -0
  18. package/pennyfarthing-dist/agents/testing-runner.md +184 -0
  19. package/pennyfarthing-dist/agents/ux-designer.md +236 -0
  20. package/pennyfarthing-dist/agents/workflow-status-check.md +96 -0
  21. package/pennyfarthing-dist/commands/architect.md +7 -0
  22. package/pennyfarthing-dist/commands/benchmark-control.md +69 -0
  23. package/pennyfarthing-dist/commands/benchmark.md +485 -0
  24. package/pennyfarthing-dist/commands/brainstorming.md +91 -0
  25. package/pennyfarthing-dist/commands/check.md +156 -0
  26. package/pennyfarthing-dist/commands/chore.md +178 -0
  27. package/pennyfarthing-dist/commands/close-epic.md +139 -0
  28. package/pennyfarthing-dist/commands/continue-session.md +184 -0
  29. package/pennyfarthing-dist/commands/create-branches-from-story.md +358 -0
  30. package/pennyfarthing-dist/commands/create-theme.md +29 -0
  31. package/pennyfarthing-dist/commands/dev.md +7 -0
  32. package/pennyfarthing-dist/commands/devops.md +7 -0
  33. package/pennyfarthing-dist/commands/git-cleanup.md +51 -0
  34. package/pennyfarthing-dist/commands/health-check.md +141 -0
  35. package/pennyfarthing-dist/commands/help.md +264 -0
  36. package/pennyfarthing-dist/commands/job-fair.md +102 -0
  37. package/pennyfarthing-dist/commands/list-themes.md +21 -0
  38. package/pennyfarthing-dist/commands/orchestrator.md +7 -0
  39. package/pennyfarthing-dist/commands/parallel-work.md +71 -0
  40. package/pennyfarthing-dist/commands/party-mode.md +77 -0
  41. package/pennyfarthing-dist/commands/permissions.md +193 -0
  42. package/pennyfarthing-dist/commands/pm.md +7 -0
  43. package/pennyfarthing-dist/commands/prime.md +140 -0
  44. package/pennyfarthing-dist/commands/release.md +58 -0
  45. package/pennyfarthing-dist/commands/repo-status.md +49 -0
  46. package/pennyfarthing-dist/commands/retro.md +200 -0
  47. package/pennyfarthing-dist/commands/reviewer.md +7 -0
  48. package/pennyfarthing-dist/commands/run-ci.md +116 -0
  49. package/pennyfarthing-dist/commands/set-theme.md +56 -0
  50. package/pennyfarthing-dist/commands/show-theme.md +21 -0
  51. package/pennyfarthing-dist/commands/sm.md +7 -0
  52. package/pennyfarthing-dist/commands/solo.md +447 -0
  53. package/pennyfarthing-dist/commands/sprint-planning.md +109 -0
  54. package/pennyfarthing-dist/commands/sprint.md +133 -0
  55. package/pennyfarthing-dist/commands/standalone.md +194 -0
  56. package/pennyfarthing-dist/commands/start-epic.md +168 -0
  57. package/pennyfarthing-dist/commands/sync-epic-to-jira.md +184 -0
  58. package/pennyfarthing-dist/commands/sync-work-with-sprint.md +373 -0
  59. package/pennyfarthing-dist/commands/tea.md +7 -0
  60. package/pennyfarthing-dist/commands/tech-writer.md +7 -0
  61. package/pennyfarthing-dist/commands/theme-maker.md +676 -0
  62. package/pennyfarthing-dist/commands/update-domain-docs.md +83 -0
  63. package/pennyfarthing-dist/commands/ux-designer.md +7 -0
  64. package/pennyfarthing-dist/commands/work.md +23 -0
  65. package/pennyfarthing-dist/commands/workflow.md +21 -0
  66. package/pennyfarthing-dist/guides/agent-behavior.md +311 -0
  67. package/pennyfarthing-dist/guides/agent-coordination.md +480 -0
  68. package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +432 -0
  69. package/pennyfarthing-dist/guides/agent-template-strategic.md +148 -0
  70. package/pennyfarthing-dist/guides/agent-template-tactical.md +162 -0
  71. package/pennyfarthing-dist/guides/hooks.md +230 -0
  72. package/pennyfarthing-dist/guides/measurement-framework.md +210 -0
  73. package/pennyfarthing-dist/guides/patterns/approval-gates-pattern.md +766 -0
  74. package/pennyfarthing-dist/guides/patterns/fan-out-fan-in-pattern.md +574 -0
  75. package/pennyfarthing-dist/guides/patterns/helper-delegation-pattern.md +488 -0
  76. package/pennyfarthing-dist/guides/patterns/tdd-flow-pattern.md +402 -0
  77. package/pennyfarthing-dist/guides/permission-protocol.md +188 -0
  78. package/pennyfarthing-dist/guides/persona-loading.md +46 -0
  79. package/pennyfarthing-dist/guides/prompt-patterns.md +338 -0
  80. package/pennyfarthing-dist/guides/scale-levels.md +114 -0
  81. package/pennyfarthing-dist/guides/session-artifacts.md +193 -0
  82. package/pennyfarthing-dist/guides/workflow-schema.md +257 -0
  83. package/pennyfarthing-dist/guides/worktree-mode.md +113 -0
  84. package/pennyfarthing-dist/guides/xml-tags.md +335 -0
  85. package/pennyfarthing-dist/output-styles/teaching.md +33 -0
  86. package/pennyfarthing-dist/output-styles/terse.md +20 -0
  87. package/pennyfarthing-dist/output-styles/verbose.md +28 -0
  88. package/pennyfarthing-dist/personas/BENCHMARK-METHODOLOGY.md +105 -0
  89. package/pennyfarthing-dist/personas/OCEAN-BENCHMARKING.md +210 -0
  90. package/pennyfarthing-dist/personas/TRAIL-OCEAN-MAPPING.md +168 -0
  91. package/pennyfarthing-dist/personas/ZEITGEIST-ANALYSIS.md +171 -0
  92. package/pennyfarthing-dist/personas/attributes.yaml +69 -0
  93. package/pennyfarthing-dist/personas/scripts/add-zeitgeist-calibrated.py +81 -0
  94. package/pennyfarthing-dist/personas/scripts/add-zeitgeist-scores.sh +56 -0
  95. package/pennyfarthing-dist/personas/themes/1984.yaml +304 -0
  96. package/pennyfarthing-dist/personas/themes/a-team.yaml +331 -0
  97. package/pennyfarthing-dist/personas/themes/agatha-christie.yaml +294 -0
  98. package/pennyfarthing-dist/personas/themes/alice-in-wonderland.yaml +324 -0
  99. package/pennyfarthing-dist/personas/themes/all-stars.yaml +326 -0
  100. package/pennyfarthing-dist/personas/themes/ancient-philosophers.yaml +312 -0
  101. package/pennyfarthing-dist/personas/themes/ancient-strategists.yaml +298 -0
  102. package/pennyfarthing-dist/personas/themes/arcane.yaml +282 -0
  103. package/pennyfarthing-dist/personas/themes/arthurian-mythos.yaml +327 -0
  104. package/pennyfarthing-dist/personas/themes/avatar-the-last-airbender.yaml +282 -0
  105. package/pennyfarthing-dist/personas/themes/babylon-5.yaml +282 -0
  106. package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +282 -0
  107. package/pennyfarthing-dist/personas/themes/better-call-saul.yaml +282 -0
  108. package/pennyfarthing-dist/personas/themes/big-lebowski.yaml +294 -0
  109. package/pennyfarthing-dist/personas/themes/black-sails.yaml +294 -0
  110. package/pennyfarthing-dist/personas/themes/blade-runner.yaml +289 -0
  111. package/pennyfarthing-dist/personas/themes/bobiverse.yaml +282 -0
  112. package/pennyfarthing-dist/personas/themes/breaking-bad.yaml +319 -0
  113. package/pennyfarthing-dist/personas/themes/catch-22.yaml +304 -0
  114. package/pennyfarthing-dist/personas/themes/classical-composers.yaml +302 -0
  115. package/pennyfarthing-dist/personas/themes/control.yaml +201 -0
  116. package/pennyfarthing-dist/personas/themes/count-of-monte-cristo.yaml +312 -0
  117. package/pennyfarthing-dist/personas/themes/cowboy-bebop.yaml +315 -0
  118. package/pennyfarthing-dist/personas/themes/deadwood.yaml +294 -0
  119. package/pennyfarthing-dist/personas/themes/dickens.yaml +312 -0
  120. package/pennyfarthing-dist/personas/themes/discworld.yaml +334 -0
  121. package/pennyfarthing-dist/personas/themes/doctor-who.yaml +284 -0
  122. package/pennyfarthing-dist/personas/themes/don-quixote.yaml +312 -0
  123. package/pennyfarthing-dist/personas/themes/dune.yaml +301 -0
  124. package/pennyfarthing-dist/personas/themes/enlightenment-thinkers.yaml +312 -0
  125. package/pennyfarthing-dist/personas/themes/expeditionary-force.yaml +282 -0
  126. package/pennyfarthing-dist/personas/themes/fargo.yaml +322 -0
  127. package/pennyfarthing-dist/personas/themes/film-auteurs.yaml +304 -0
  128. package/pennyfarthing-dist/personas/themes/firefly.yaml +320 -0
  129. package/pennyfarthing-dist/personas/themes/foundation.yaml +284 -0
  130. package/pennyfarthing-dist/personas/themes/futurama.yaml +313 -0
  131. package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +284 -0
  132. package/pennyfarthing-dist/personas/themes/gilligans-island.yaml +365 -0
  133. package/pennyfarthing-dist/personas/themes/gothic-literature.yaml +300 -0
  134. package/pennyfarthing-dist/personas/themes/great-gatsby.yaml +300 -0
  135. package/pennyfarthing-dist/personas/themes/greek-mythology.yaml +326 -0
  136. package/pennyfarthing-dist/personas/themes/hannibal.yaml +294 -0
  137. package/pennyfarthing-dist/personas/themes/harry-potter.yaml +316 -0
  138. package/pennyfarthing-dist/personas/themes/his-dark-materials.yaml +285 -0
  139. package/pennyfarthing-dist/personas/themes/historical-figures.yaml +282 -0
  140. package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +323 -0
  141. package/pennyfarthing-dist/personas/themes/house-md.yaml +313 -0
  142. package/pennyfarthing-dist/personas/themes/imperial-radch.yaml +283 -0
  143. package/pennyfarthing-dist/personas/themes/inspector-morse.yaml +294 -0
  144. package/pennyfarthing-dist/personas/themes/jane-austen.yaml +281 -0
  145. package/pennyfarthing-dist/personas/themes/jazz-legends.yaml +312 -0
  146. package/pennyfarthing-dist/personas/themes/justified.yaml +294 -0
  147. package/pennyfarthing-dist/personas/themes/legion-of-doom.yaml +343 -0
  148. package/pennyfarthing-dist/personas/themes/les-miserables.yaml +293 -0
  149. package/pennyfarthing-dist/personas/themes/lord-of-the-rings.yaml +326 -0
  150. package/pennyfarthing-dist/personas/themes/lovecraft-mythos.yaml +325 -0
  151. package/pennyfarthing-dist/personas/themes/mad-max.yaml +349 -0
  152. package/pennyfarthing-dist/personas/themes/mad-men.yaml +283 -0
  153. package/pennyfarthing-dist/personas/themes/marvel-mcu.yaml +294 -0
  154. package/pennyfarthing-dist/personas/themes/mash.yaml +329 -0
  155. package/pennyfarthing-dist/personas/themes/mass-effect.yaml +283 -0
  156. package/pennyfarthing-dist/personas/themes/military-commanders.yaml +298 -0
  157. package/pennyfarthing-dist/personas/themes/moby-dick.yaml +312 -0
  158. package/pennyfarthing-dist/personas/themes/monty-python.yaml +297 -0
  159. package/pennyfarthing-dist/personas/themes/neuromancer.yaml +294 -0
  160. package/pennyfarthing-dist/personas/themes/norse-mythology.yaml +321 -0
  161. package/pennyfarthing-dist/personas/themes/parks-and-rec.yaml +364 -0
  162. package/pennyfarthing-dist/personas/themes/peaky-blinders.yaml +292 -0
  163. package/pennyfarthing-dist/personas/themes/princess-bride.yaml +344 -0
  164. package/pennyfarthing-dist/personas/themes/renaissance-masters.yaml +312 -0
  165. package/pennyfarthing-dist/personas/themes/rome.yaml +294 -0
  166. package/pennyfarthing-dist/personas/themes/russian-masters.yaml +310 -0
  167. package/pennyfarthing-dist/personas/themes/sandman.yaml +282 -0
  168. package/pennyfarthing-dist/personas/themes/scientific-revolutionaries.yaml +312 -0
  169. package/pennyfarthing-dist/personas/themes/shakespeare.yaml +295 -0
  170. package/pennyfarthing-dist/personas/themes/sherlock-holmes.yaml +283 -0
  171. package/pennyfarthing-dist/personas/themes/snow-crash.yaml +290 -0
  172. package/pennyfarthing-dist/personas/themes/software-pioneers.yaml +294 -0
  173. package/pennyfarthing-dist/personas/themes/star-trek-tng.yaml +358 -0
  174. package/pennyfarthing-dist/personas/themes/star-trek-tos.yaml +327 -0
  175. package/pennyfarthing-dist/personas/themes/star-wars.yaml +297 -0
  176. package/pennyfarthing-dist/personas/themes/succession.yaml +294 -0
  177. package/pennyfarthing-dist/personas/themes/superfriends.yaml +332 -0
  178. package/pennyfarthing-dist/personas/themes/ted-lasso.yaml +359 -0
  179. package/pennyfarthing-dist/personas/themes/the-americans.yaml +294 -0
  180. package/pennyfarthing-dist/personas/themes/the-crown.yaml +294 -0
  181. package/pennyfarthing-dist/personas/themes/the-expanse.yaml +337 -0
  182. package/pennyfarthing-dist/personas/themes/the-good-place.yaml +315 -0
  183. package/pennyfarthing-dist/personas/themes/the-matrix.yaml +342 -0
  184. package/pennyfarthing-dist/personas/themes/the-odyssey.yaml +294 -0
  185. package/pennyfarthing-dist/personas/themes/the-office.yaml +323 -0
  186. package/pennyfarthing-dist/personas/themes/the-simpsons.yaml +300 -0
  187. package/pennyfarthing-dist/personas/themes/the-sopranos.yaml +294 -0
  188. package/pennyfarthing-dist/personas/themes/the-wire.yaml +303 -0
  189. package/pennyfarthing-dist/personas/themes/the-witcher.yaml +294 -0
  190. package/pennyfarthing-dist/personas/themes/twin-peaks.yaml +296 -0
  191. package/pennyfarthing-dist/personas/themes/vorkosigan-saga.yaml +294 -0
  192. package/pennyfarthing-dist/personas/themes/watchmen.yaml +285 -0
  193. package/pennyfarthing-dist/personas/themes/west-wing.yaml +285 -0
  194. package/pennyfarthing-dist/personas/themes/world-explorers.yaml +312 -0
  195. package/pennyfarthing-dist/personas/themes/wwii-leaders.yaml +299 -0
  196. package/pennyfarthing-dist/personas/themes/x-files.yaml +296 -0
  197. package/pennyfarthing-dist/personas/zeitgeist-scores.yaml +1172 -0
  198. package/pennyfarthing-dist/scripts/README.md +87 -0
  199. package/pennyfarthing-dist/scripts/core/README.md +26 -0
  200. package/pennyfarthing-dist/scripts/core/agent-session.sh +383 -0
  201. package/pennyfarthing-dist/scripts/core/check-context.sh +280 -0
  202. package/pennyfarthing-dist/scripts/core/handoff-marker.sh +101 -0
  203. package/pennyfarthing-dist/scripts/core/phase-check-start.sh +95 -0
  204. package/pennyfarthing-dist/scripts/core/prime.sh +30 -0
  205. package/pennyfarthing-dist/scripts/core/run.sh +92 -0
  206. package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +21 -0
  207. package/pennyfarthing-dist/scripts/git/README.md +25 -0
  208. package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +267 -0
  209. package/pennyfarthing-dist/scripts/git/git-status-all.sh +152 -0
  210. package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +91 -0
  211. package/pennyfarthing-dist/scripts/git/release.sh +215 -0
  212. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +494 -0
  213. package/pennyfarthing-dist/scripts/health/drift-detection.sh +162 -0
  214. package/pennyfarthing-dist/scripts/hooks/README.md +32 -0
  215. package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +106 -0
  216. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +60 -0
  217. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +65 -0
  218. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +35 -0
  219. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +166 -0
  220. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +107 -0
  221. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +71 -0
  222. package/pennyfarthing-dist/scripts/hooks/pre-push.sh +54 -0
  223. package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +20 -0
  224. package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +499 -0
  225. package/pennyfarthing-dist/scripts/hooks/session-start.sh +97 -0
  226. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +65 -0
  227. package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +94 -0
  228. package/pennyfarthing-dist/scripts/jira/README.md +36 -0
  229. package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +101 -0
  230. package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +97 -0
  231. package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +22 -0
  232. package/pennyfarthing-dist/scripts/jira/jira-lib.sh +464 -0
  233. package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +266 -0
  234. package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +18 -0
  235. package/pennyfarthing-dist/scripts/jira/jira-sync.sh +16 -0
  236. package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +16 -0
  237. package/pennyfarthing-dist/scripts/jira/sync-epic-to-jira.sh +16 -0
  238. package/pennyfarthing-dist/scripts/lib/README.md +29 -0
  239. package/pennyfarthing-dist/scripts/lib/background-tasks.sh +177 -0
  240. package/pennyfarthing-dist/scripts/lib/checkpoint.sh +136 -0
  241. package/pennyfarthing-dist/scripts/lib/common.sh +212 -0
  242. package/pennyfarthing-dist/scripts/lib/file-lock.sh +269 -0
  243. package/pennyfarthing-dist/scripts/lib/find-root.sh +35 -0
  244. package/pennyfarthing-dist/scripts/lib/logging.sh +186 -0
  245. package/pennyfarthing-dist/scripts/lib/retry.sh +76 -0
  246. package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +102 -0
  247. package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +97 -0
  248. package/pennyfarthing-dist/scripts/misc/README.md +44 -0
  249. package/pennyfarthing-dist/scripts/misc/add-short-names.sh +13 -0
  250. package/pennyfarthing-dist/scripts/misc/add_short_names.py +226 -0
  251. package/pennyfarthing-dist/scripts/misc/backlog.sh +91 -0
  252. package/pennyfarthing-dist/scripts/misc/check-status.sh +247 -0
  253. package/pennyfarthing-dist/scripts/misc/find-related-work.sh +231 -0
  254. package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +122 -0
  255. package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +74 -0
  256. package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +10 -0
  257. package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +319 -0
  258. package/pennyfarthing-dist/scripts/misc/repo-scan.sh +141 -0
  259. package/pennyfarthing-dist/scripts/misc/repo-utils.sh +778 -0
  260. package/pennyfarthing-dist/scripts/misc/run-ci.sh +219 -0
  261. package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +7 -0
  262. package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +319 -0
  263. package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +193 -0
  264. package/pennyfarthing-dist/scripts/misc/statusline.sh +259 -0
  265. package/pennyfarthing-dist/scripts/misc/uninstall.sh +270 -0
  266. package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +160 -0
  267. package/pennyfarthing-dist/scripts/portraits/generate-portraits.py +400 -0
  268. package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +54 -0
  269. package/pennyfarthing-dist/scripts/sprint/README.md +29 -0
  270. package/pennyfarthing-dist/scripts/sprint/archive-story.sh +139 -0
  271. package/pennyfarthing-dist/scripts/sprint/available-stories.sh +97 -0
  272. package/pennyfarthing-dist/scripts/sprint/check-story.sh +164 -0
  273. package/pennyfarthing-dist/scripts/sprint/get-epic-field.sh +58 -0
  274. package/pennyfarthing-dist/scripts/sprint/get-story-field.sh +69 -0
  275. package/pennyfarthing-dist/scripts/sprint/import-epic-to-future.sh +10 -0
  276. package/pennyfarthing-dist/scripts/sprint/import_epic_to_future.py +270 -0
  277. package/pennyfarthing-dist/scripts/sprint/list-future.sh +151 -0
  278. package/pennyfarthing-dist/scripts/sprint/new-sprint.sh +116 -0
  279. package/pennyfarthing-dist/scripts/sprint/promote-epic.sh +154 -0
  280. package/pennyfarthing-dist/scripts/sprint/sprint-common.sh +421 -0
  281. package/pennyfarthing-dist/scripts/sprint/sprint-info.sh +39 -0
  282. package/pennyfarthing-dist/scripts/sprint/sprint-metrics.sh +241 -0
  283. package/pennyfarthing-dist/scripts/sprint/sprint-status.sh +134 -0
  284. package/pennyfarthing-dist/scripts/story/README.md +23 -0
  285. package/pennyfarthing-dist/scripts/story/create-story.sh +19 -0
  286. package/pennyfarthing-dist/scripts/story/size-story.sh +18 -0
  287. package/pennyfarthing-dist/scripts/story/story-template.sh +18 -0
  288. package/pennyfarthing-dist/scripts/test/README.md +23 -0
  289. package/pennyfarthing-dist/scripts/test/ensure-swebench-data.sh +59 -0
  290. package/pennyfarthing-dist/scripts/test/ground-truth-judge.py +220 -0
  291. package/pennyfarthing-dist/scripts/test/swebench-judge.py +374 -0
  292. package/pennyfarthing-dist/scripts/test/test-cache.sh +165 -0
  293. package/pennyfarthing-dist/scripts/test/test-setup.sh +337 -0
  294. package/pennyfarthing-dist/scripts/tests/check.test.sh +582 -0
  295. package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +515 -0
  296. package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +599 -0
  297. package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +332 -0
  298. package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +573 -0
  299. package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +859 -0
  300. package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +662 -0
  301. package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +589 -0
  302. package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +105 -0
  303. package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +597 -0
  304. package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +514 -0
  305. package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +517 -0
  306. package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +331 -0
  307. package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +647 -0
  308. package/pennyfarthing-dist/scripts/theme/README.md +22 -0
  309. package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.sh +13 -0
  310. package/pennyfarthing-dist/scripts/theme/compute_theme_tiers.py +402 -0
  311. package/pennyfarthing-dist/scripts/theme/list-themes.sh +73 -0
  312. package/pennyfarthing-dist/scripts/theme/update-theme-tiers.sh +97 -0
  313. package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +576 -0
  314. package/pennyfarthing-dist/scripts/workflow/README.md +28 -0
  315. package/pennyfarthing-dist/scripts/workflow/check.py +502 -0
  316. package/pennyfarthing-dist/scripts/workflow/check.sh +24 -0
  317. package/pennyfarthing-dist/scripts/workflow/finish-story.sh +159 -0
  318. package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +228 -0
  319. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +61 -0
  320. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +13 -0
  321. package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +130 -0
  322. package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +40 -0
  323. package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +163 -0
  324. package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +138 -0
  325. package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +256 -0
  326. package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +167 -0
  327. package/pennyfarthing-dist/skills/agentic-patterns/SKILL.md +242 -0
  328. package/pennyfarthing-dist/skills/changelog/SKILL.md +367 -0
  329. package/pennyfarthing-dist/skills/code-review/SKILL.md +168 -0
  330. package/pennyfarthing-dist/skills/context-engineering/SKILL.md +274 -0
  331. package/pennyfarthing-dist/skills/cyclist/SKILL.md +88 -0
  332. package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +437 -0
  333. package/pennyfarthing-dist/skills/finalize-run/SKILL.md +258 -0
  334. package/pennyfarthing-dist/skills/jira/SKILL.md +484 -0
  335. package/pennyfarthing-dist/skills/judge/SKILL.md +636 -0
  336. package/pennyfarthing-dist/skills/just/SKILL.md +403 -0
  337. package/pennyfarthing-dist/skills/mermaid/SKILL.md +240 -0
  338. package/pennyfarthing-dist/skills/otel/skill.md +223 -0
  339. package/pennyfarthing-dist/skills/permissions/skill.md +172 -0
  340. package/pennyfarthing-dist/skills/persona-benchmark/SKILL.md +178 -0
  341. package/pennyfarthing-dist/skills/skill-registry.schema.json +107 -0
  342. package/pennyfarthing-dist/skills/skill-registry.yaml +393 -0
  343. package/pennyfarthing-dist/skills/sprint/scripts/archive-story.sh +101 -0
  344. package/pennyfarthing-dist/skills/sprint/scripts/available-stories.sh +97 -0
  345. package/pennyfarthing-dist/skills/sprint/scripts/check-story.sh +164 -0
  346. package/pennyfarthing-dist/skills/sprint/scripts/create-jira-epic.sh +101 -0
  347. package/pennyfarthing-dist/skills/sprint/scripts/new-sprint.sh +116 -0
  348. package/pennyfarthing-dist/skills/sprint/scripts/promote-epic.sh +164 -0
  349. package/pennyfarthing-dist/skills/sprint/scripts/sprint-info.sh +39 -0
  350. package/pennyfarthing-dist/skills/sprint/scripts/sprint-status.sh +147 -0
  351. package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +86 -0
  352. package/pennyfarthing-dist/skills/sprint/skill.md +465 -0
  353. package/pennyfarthing-dist/skills/story/scripts/create-story.sh +159 -0
  354. package/pennyfarthing-dist/skills/story/scripts/size-story.sh +198 -0
  355. package/pennyfarthing-dist/skills/story/scripts/story-template.sh +162 -0
  356. package/pennyfarthing-dist/skills/story/skill.md +219 -0
  357. package/pennyfarthing-dist/skills/systematic-debugging/SKILL.md +390 -0
  358. package/pennyfarthing-dist/skills/testing/SKILL.md +99 -0
  359. package/pennyfarthing-dist/skills/testing/references/troubleshooting.md +124 -0
  360. package/pennyfarthing-dist/skills/theme/skill.md +129 -0
  361. package/pennyfarthing-dist/skills/theme-creation/SKILL.md +174 -0
  362. package/pennyfarthing-dist/skills/workflow/scripts/list-workflows.sh +91 -0
  363. package/pennyfarthing-dist/skills/workflow/scripts/resume-workflow.sh +163 -0
  364. package/pennyfarthing-dist/skills/workflow/scripts/show-workflow.sh +138 -0
  365. package/pennyfarthing-dist/skills/workflow/scripts/start-workflow.sh +273 -0
  366. package/pennyfarthing-dist/skills/workflow/scripts/workflow-status.sh +167 -0
  367. package/pennyfarthing-dist/skills/workflow/skill.md +337 -0
  368. package/pennyfarthing-dist/skills/yq/SKILL.md +264 -0
  369. package/pennyfarthing-dist/templates/LEADERBOARD.schema.yaml +187 -0
  370. package/pennyfarthing-dist/templates/LEADERBOARD.template.md +59 -0
  371. package/pennyfarthing-dist/templates/agent-scopes.yaml.template +276 -0
  372. package/pennyfarthing-dist/templates/pennyfarthing-settings.yaml.template +61 -0
  373. package/pennyfarthing-dist/templates/persona-config.yaml.template +22 -0
  374. package/pennyfarthing-dist/templates/preferences.yaml.template +15 -0
  375. package/pennyfarthing-dist/templates/settings.local.json.template +101 -0
  376. package/pennyfarthing-dist/templates/setup-env.sh.template +18 -0
  377. package/pennyfarthing-dist/templates/shared-context.md.template +70 -0
  378. package/pennyfarthing-dist/templates/sidecar/decisions.md.template +40 -0
  379. package/pennyfarthing-dist/templates/sidecar/gotchas.md.template +37 -0
  380. package/pennyfarthing-dist/templates/sidecar/patterns.md.template +34 -0
  381. package/pennyfarthing-dist/workflows/agent-docs.yaml +70 -0
  382. package/pennyfarthing-dist/workflows/architecture/steps/step-01-initialize.md +101 -0
  383. package/pennyfarthing-dist/workflows/architecture/steps/step-01b-continue.md +93 -0
  384. package/pennyfarthing-dist/workflows/architecture/steps/step-02-context.md +115 -0
  385. package/pennyfarthing-dist/workflows/architecture/steps/step-03-patterns.md +133 -0
  386. package/pennyfarthing-dist/workflows/architecture/steps/step-04-components.md +138 -0
  387. package/pennyfarthing-dist/workflows/architecture/steps/step-05-interfaces.md +133 -0
  388. package/pennyfarthing-dist/workflows/architecture/steps/step-06-risks.md +142 -0
  389. package/pennyfarthing-dist/workflows/architecture/steps/step-07-document.md +160 -0
  390. package/pennyfarthing-dist/workflows/architecture/templates/architecture-decision.md +102 -0
  391. package/pennyfarthing-dist/workflows/architecture.yaml +65 -0
  392. package/pennyfarthing-dist/workflows/bdd.yaml +60 -0
  393. package/pennyfarthing-dist/workflows/brainstorming/brain-methods.csv +62 -0
  394. package/pennyfarthing-dist/workflows/brainstorming/checklist.md +44 -0
  395. package/pennyfarthing-dist/workflows/brainstorming/instructions.md +736 -0
  396. package/pennyfarthing-dist/workflows/brainstorming/workflow.yaml +49 -0
  397. package/pennyfarthing-dist/workflows/code-review/checklist.md +23 -0
  398. package/pennyfarthing-dist/workflows/code-review/instructions.md +234 -0
  399. package/pennyfarthing-dist/workflows/code-review/workflow.yaml +51 -0
  400. package/pennyfarthing-dist/workflows/dev-story/checklist.md +80 -0
  401. package/pennyfarthing-dist/workflows/dev-story/instructions.xml +410 -0
  402. package/pennyfarthing-dist/workflows/dev-story/workflow.yaml +50 -0
  403. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-01-validate-prerequisites.md +256 -0
  404. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-02-design-epics.md +233 -0
  405. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-03-create-stories.md +272 -0
  406. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-04-final-validation.md +153 -0
  407. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +122 -0
  408. package/pennyfarthing-dist/workflows/epics-and-stories/templates/epics-template.md +57 -0
  409. package/pennyfarthing-dist/workflows/epics-and-stories/workflow.yaml +28 -0
  410. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +101 -0
  411. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-02-categorize.md +116 -0
  412. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-03-execute.md +224 -0
  413. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +88 -0
  414. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +79 -0
  415. package/pennyfarthing-dist/workflows/git-cleanup.yaml +59 -0
  416. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-01-document-discovery.md +190 -0
  417. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-02-prd-analysis.md +178 -0
  418. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-03-epic-coverage-validation.md +179 -0
  419. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-04-ux-alignment.md +139 -0
  420. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-05-epic-quality-review.md +252 -0
  421. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-06-final-assessment.md +133 -0
  422. package/pennyfarthing-dist/workflows/implementation-readiness/templates/readiness-report-template.md +4 -0
  423. package/pennyfarthing-dist/workflows/implementation-readiness/workflow.yaml +40 -0
  424. package/pennyfarthing-dist/workflows/prd/data/domain-complexity.csv +13 -0
  425. package/pennyfarthing-dist/workflows/prd/data/prd-purpose.md +197 -0
  426. package/pennyfarthing-dist/workflows/prd/data/project-types.csv +11 -0
  427. package/pennyfarthing-dist/workflows/prd/steps-c/step-01-init.md +191 -0
  428. package/pennyfarthing-dist/workflows/prd/steps-c/step-01b-continue.md +153 -0
  429. package/pennyfarthing-dist/workflows/prd/steps-c/step-02-discovery.md +224 -0
  430. package/pennyfarthing-dist/workflows/prd/steps-c/step-03-success.md +226 -0
  431. package/pennyfarthing-dist/workflows/prd/steps-c/step-04-journeys.md +213 -0
  432. package/pennyfarthing-dist/workflows/prd/steps-c/step-05-domain.md +207 -0
  433. package/pennyfarthing-dist/workflows/prd/steps-c/step-06-innovation.md +226 -0
  434. package/pennyfarthing-dist/workflows/prd/steps-c/step-07-project-type.md +237 -0
  435. package/pennyfarthing-dist/workflows/prd/steps-c/step-08-scoping.md +228 -0
  436. package/pennyfarthing-dist/workflows/prd/steps-c/step-09-functional.md +231 -0
  437. package/pennyfarthing-dist/workflows/prd/steps-c/step-10-nonfunctional.md +242 -0
  438. package/pennyfarthing-dist/workflows/prd/steps-c/step-11-polish.md +217 -0
  439. package/pennyfarthing-dist/workflows/prd/steps-c/step-12-complete.md +180 -0
  440. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-01-discovery.md +247 -0
  441. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-01b-legacy-conversion.md +208 -0
  442. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-02-review.md +249 -0
  443. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-03-edit.md +253 -0
  444. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-04-complete.md +168 -0
  445. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-01-discovery.md +218 -0
  446. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-02-format-detection.md +191 -0
  447. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-02b-parity-check.md +209 -0
  448. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-03-density-validation.md +174 -0
  449. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-04-brief-coverage-validation.md +214 -0
  450. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-05-measurability-validation.md +228 -0
  451. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-06-traceability-validation.md +217 -0
  452. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-07-implementation-leakage-validation.md +205 -0
  453. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-08-domain-compliance-validation.md +243 -0
  454. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-09-project-type-validation.md +263 -0
  455. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-10-smart-validation.md +209 -0
  456. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-11-holistic-quality-validation.md +264 -0
  457. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-12-completeness-validation.md +242 -0
  458. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-13-report-complete.md +232 -0
  459. package/pennyfarthing-dist/workflows/prd/templates/prd-template.md +10 -0
  460. package/pennyfarthing-dist/workflows/prd/workflow.yaml +42 -0
  461. package/pennyfarthing-dist/workflows/product-brief/steps/step-01-init.md +177 -0
  462. package/pennyfarthing-dist/workflows/product-brief/steps/step-01b-continue.md +161 -0
  463. package/pennyfarthing-dist/workflows/product-brief/steps/step-02-vision.md +199 -0
  464. package/pennyfarthing-dist/workflows/product-brief/steps/step-03-users.md +202 -0
  465. package/pennyfarthing-dist/workflows/product-brief/steps/step-04-metrics.md +205 -0
  466. package/pennyfarthing-dist/workflows/product-brief/steps/step-05-scope.md +219 -0
  467. package/pennyfarthing-dist/workflows/product-brief/steps/step-06-complete.md +194 -0
  468. package/pennyfarthing-dist/workflows/product-brief/templates/product-brief.template.md +10 -0
  469. package/pennyfarthing-dist/workflows/product-brief/workflow.yaml +31 -0
  470. package/pennyfarthing-dist/workflows/project-context/project-context-template.md +21 -0
  471. package/pennyfarthing-dist/workflows/project-context/steps/step-01-discover.md +184 -0
  472. package/pennyfarthing-dist/workflows/project-context/steps/step-02-generate.md +318 -0
  473. package/pennyfarthing-dist/workflows/project-context/steps/step-03-complete.md +278 -0
  474. package/pennyfarthing-dist/workflows/project-context/workflow.yaml +27 -0
  475. package/pennyfarthing-dist/workflows/quick-dev/steps/step-01-mode-detection.md +156 -0
  476. package/pennyfarthing-dist/workflows/quick-dev/steps/step-02-context-gathering.md +120 -0
  477. package/pennyfarthing-dist/workflows/quick-dev/steps/step-03-execute.md +113 -0
  478. package/pennyfarthing-dist/workflows/quick-dev/steps/step-04-self-check.md +113 -0
  479. package/pennyfarthing-dist/workflows/quick-dev/steps/step-05-adversarial-review.md +106 -0
  480. package/pennyfarthing-dist/workflows/quick-dev/steps/step-06-resolve-findings.md +140 -0
  481. package/pennyfarthing-dist/workflows/quick-dev/workflow.yaml +27 -0
  482. package/pennyfarthing-dist/workflows/quick-spec/steps/step-01-understand.md +189 -0
  483. package/pennyfarthing-dist/workflows/quick-spec/steps/step-02-investigate.md +144 -0
  484. package/pennyfarthing-dist/workflows/quick-spec/steps/step-03-generate.md +128 -0
  485. package/pennyfarthing-dist/workflows/quick-spec/steps/step-04-review.md +191 -0
  486. package/pennyfarthing-dist/workflows/quick-spec/tech-spec-template.md +74 -0
  487. package/pennyfarthing-dist/workflows/quick-spec/workflow.yaml +27 -0
  488. package/pennyfarthing-dist/workflows/research/steps-domain/step-01-init.md +137 -0
  489. package/pennyfarthing-dist/workflows/research/steps-domain/step-02-domain-analysis.md +229 -0
  490. package/pennyfarthing-dist/workflows/research/steps-domain/step-03-competitive-landscape.md +238 -0
  491. package/pennyfarthing-dist/workflows/research/steps-domain/step-04-regulatory-focus.md +206 -0
  492. package/pennyfarthing-dist/workflows/research/steps-domain/step-05-technical-trends.md +234 -0
  493. package/pennyfarthing-dist/workflows/research/steps-domain/step-06-research-synthesis.md +443 -0
  494. package/pennyfarthing-dist/workflows/research/steps-market/step-01-init.md +182 -0
  495. package/pennyfarthing-dist/workflows/research/steps-market/step-02-customer-behavior.md +237 -0
  496. package/pennyfarthing-dist/workflows/research/steps-market/step-02-customer-insights.md +200 -0
  497. package/pennyfarthing-dist/workflows/research/steps-market/step-03-customer-pain-points.md +249 -0
  498. package/pennyfarthing-dist/workflows/research/steps-market/step-04-customer-decisions.md +259 -0
  499. package/pennyfarthing-dist/workflows/research/steps-market/step-05-competitive-analysis.md +177 -0
  500. package/pennyfarthing-dist/workflows/research/steps-market/step-06-research-completion.md +475 -0
  501. package/pennyfarthing-dist/workflows/research/steps-technical/step-01-init.md +137 -0
  502. package/pennyfarthing-dist/workflows/research/steps-technical/step-02-technical-overview.md +239 -0
  503. package/pennyfarthing-dist/workflows/research/steps-technical/step-03-integration-patterns.md +248 -0
  504. package/pennyfarthing-dist/workflows/research/steps-technical/step-04-architectural-patterns.md +202 -0
  505. package/pennyfarthing-dist/workflows/research/steps-technical/step-05-implementation-research.md +239 -0
  506. package/pennyfarthing-dist/workflows/research/steps-technical/step-06-research-synthesis.md +486 -0
  507. package/pennyfarthing-dist/workflows/research/templates/research.template.md +29 -0
  508. package/pennyfarthing-dist/workflows/research/workflow.yaml +45 -0
  509. package/pennyfarthing-dist/workflows/retrospective/checklist.md +31 -0
  510. package/pennyfarthing-dist/workflows/retrospective/instructions.md +1443 -0
  511. package/pennyfarthing-dist/workflows/retrospective/workflow.yaml +50 -0
  512. package/pennyfarthing-dist/workflows/sprint-planning/checklist.md +33 -0
  513. package/pennyfarthing-dist/workflows/sprint-planning/sprint-status-template.yaml +55 -0
  514. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-01-parse-epic-files.md +54 -0
  515. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-02-build-sprint-status.md +44 -0
  516. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-03-status-detection.md +64 -0
  517. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-04-generate-status-file.md +73 -0
  518. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-05-validate-and-report.md +56 -0
  519. package/pennyfarthing-dist/workflows/sprint-planning/workflow.yaml +34 -0
  520. package/pennyfarthing-dist/workflows/tdd.yaml +50 -0
  521. package/pennyfarthing-dist/workflows/trivial.yaml +40 -0
  522. package/pennyfarthing-dist/workflows/ux-design/steps/step-01-init.md +135 -0
  523. package/pennyfarthing-dist/workflows/ux-design/steps/step-01b-continue.md +127 -0
  524. package/pennyfarthing-dist/workflows/ux-design/steps/step-02-discovery.md +190 -0
  525. package/pennyfarthing-dist/workflows/ux-design/steps/step-03-core-experience.md +216 -0
  526. package/pennyfarthing-dist/workflows/ux-design/steps/step-04-emotional-response.md +219 -0
  527. package/pennyfarthing-dist/workflows/ux-design/steps/step-05-inspiration.md +234 -0
  528. package/pennyfarthing-dist/workflows/ux-design/steps/step-06-design-system.md +252 -0
  529. package/pennyfarthing-dist/workflows/ux-design/steps/step-07-defining-experience.md +254 -0
  530. package/pennyfarthing-dist/workflows/ux-design/steps/step-08-visual-foundation.md +224 -0
  531. package/pennyfarthing-dist/workflows/ux-design/steps/step-09-design-directions.md +224 -0
  532. package/pennyfarthing-dist/workflows/ux-design/steps/step-10-user-journeys.md +241 -0
  533. package/pennyfarthing-dist/workflows/ux-design/steps/step-11-component-strategy.md +248 -0
  534. package/pennyfarthing-dist/workflows/ux-design/steps/step-12-ux-patterns.md +237 -0
  535. package/pennyfarthing-dist/workflows/ux-design/steps/step-13-responsive-accessibility.md +264 -0
  536. package/pennyfarthing-dist/workflows/ux-design/steps/step-14-complete.md +228 -0
  537. package/pennyfarthing-dist/workflows/ux-design/ux-design-template.md +13 -0
  538. package/pennyfarthing-dist/workflows/ux-design/workflow.yaml +41 -0
@@ -0,0 +1,400 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Individual Portrait Generator for Pennyfarthing Themes
4
+
5
+ Generates 10 individual portraits per theme using Stable Diffusion SDXL on M3 Max (MPS).
6
+ Reads visual prompts from theme YAML files in two locations:
7
+ - Built-in: pennyfarthing-dist/personas/themes/
8
+ - Custom: .claude/pennyfarthing/themes/ (takes precedence)
9
+
10
+ Output: pennyfarthing-dist/personas/portraits/{theme}/{slug}-{OCEAN}.png (512x512px each)
11
+
12
+ Usage:
13
+ python3 scripts/generate-portraits.py [--dry-run] [--theme THEME]
14
+ python3 scripts/generate-portraits.py --theme gilligans-island --dry-run
15
+ """
16
+
17
+ import argparse
18
+ import os
19
+ import sys
20
+ import warnings
21
+ from pathlib import Path
22
+ from datetime import datetime
23
+
24
+ # Suppress progress bars before importing torch/diffusers
25
+ os.environ["TQDM_DISABLE"] = "1"
26
+
27
+ # Suppress CUDA warnings on MPS (Apple Silicon)
28
+ warnings.filterwarnings("ignore", message=".*CUDA is not available.*")
29
+
30
+ try:
31
+ import yaml
32
+ except ImportError:
33
+ print("Missing PyYAML: pip install pyyaml")
34
+ sys.exit(1)
35
+
36
+ try:
37
+ import torch
38
+ from diffusers import StableDiffusionXLPipeline, DPMSolverMultistepScheduler
39
+ from diffusers.utils import logging as diffusers_logging
40
+ from PIL import Image
41
+ HAS_TORCH = True
42
+ # Suppress diffusers progress bar
43
+ diffusers_logging.disable_progress_bar()
44
+ except ImportError as e:
45
+ HAS_TORCH = False
46
+ TORCH_ERROR = str(e)
47
+
48
+ # CLIP tokenizer for accurate token counting (optional - falls back to word estimate)
49
+ try:
50
+ from transformers import CLIPTokenizer
51
+ CLIP_TOKENIZER = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14")
52
+ HAS_CLIP_TOKENIZER = True
53
+ except Exception:
54
+ CLIP_TOKENIZER = None
55
+ HAS_CLIP_TOKENIZER = False
56
+
57
+
58
+ # Configuration
59
+ SCRIPT_DIR = Path(__file__).parent
60
+ PROJECT_ROOT = SCRIPT_DIR.parent
61
+ BUILTIN_THEMES_DIR = PROJECT_ROOT / "pennyfarthing-dist" / "personas" / "themes"
62
+ CUSTOM_THEMES_DIR = PROJECT_ROOT / ".claude" / "pennyfarthing" / "themes"
63
+ OUTPUT_DIR = PROJECT_ROOT / "pennyfarthing-dist" / "personas" / "portraits"
64
+ MODEL_ID = "stabilityai/stable-diffusion-xl-base-1.0"
65
+
66
+ # SDXL generates at 1024x1024, we'll resize to 512x512
67
+ GENERATION_SIZE = 1024
68
+ OUTPUT_SIZE = 512
69
+
70
+ # Generation parameters
71
+ NUM_INFERENCE_STEPS = 30
72
+ GUIDANCE_SCALE = 7.5
73
+
74
+ # CLIP token limit - prompts are truncated beyond this
75
+ CLIP_MAX_TOKENS = 77
76
+
77
+ # Role order for the 10 agents
78
+ ROLES = [
79
+ "orchestrator", "sm", "tea", "dev", "reviewer",
80
+ "architect", "pm", "tech-writer", "ux-designer", "devops"
81
+ ]
82
+
83
+ # Default style suffix (visual description comes first for emphasis)
84
+ # Themes can override this by setting 'portrait_style' in their theme metadata
85
+ DEFAULT_STYLE_SUFFIX = ", traditional woodcut portrait bust, black and white, bold linework, crosshatching, medieval style"
86
+
87
+
88
+ def to_slug(name: str) -> str:
89
+ """Convert a name to URL-safe slug (lowercase kebab-case)."""
90
+ import re
91
+ slug = name.lower()
92
+ slug = re.sub(r'[^a-z0-9]+', '-', slug)
93
+ slug = re.sub(r'^-|-$', '', slug)
94
+ return slug
95
+
96
+
97
+ def count_clip_tokens(text: str) -> int:
98
+ """Count CLIP tokens in text. Uses actual tokenizer if available, else estimates."""
99
+ if HAS_CLIP_TOKENIZER and CLIP_TOKENIZER:
100
+ tokens = CLIP_TOKENIZER.encode(text)
101
+ return len(tokens)
102
+ else:
103
+ # Fallback: estimate ~1.3 tokens per word (empirical average for CLIP)
104
+ return int(len(text.split()) * 1.3)
105
+
106
+
107
+ def truncate_prompt_to_clip_limit(visual: str, style_suffix: str, max_tokens: int = CLIP_MAX_TOKENS) -> tuple[str, bool]:
108
+ """Truncate prompt to fit within CLIP token limit.
109
+
110
+ Strategy: Prioritize the visual description over the style suffix.
111
+ If combined prompt exceeds limit, progressively trim the visual description.
112
+
113
+ Returns:
114
+ tuple: (truncated_prompt, was_truncated)
115
+ """
116
+ combined = f"{visual}{style_suffix}"
117
+ token_count = count_clip_tokens(combined)
118
+
119
+ if token_count <= max_tokens:
120
+ return combined, False
121
+
122
+ # Need to truncate - prioritize visual by trimming words from end
123
+ visual_words = visual.split()
124
+ style_tokens = count_clip_tokens(style_suffix)
125
+ available_for_visual = max_tokens - style_tokens - 2 # Buffer for safety
126
+
127
+ # Binary search for optimal truncation point
128
+ while visual_words and count_clip_tokens(" ".join(visual_words)) > available_for_visual:
129
+ visual_words = visual_words[:-1]
130
+
131
+ truncated_visual = " ".join(visual_words)
132
+ if truncated_visual and not truncated_visual.endswith((",", ".", ";")):
133
+ truncated_visual = truncated_visual.rstrip(",. ")
134
+
135
+ return f"{truncated_visual}{style_suffix}", True
136
+
137
+
138
+ def ocean_suffix(ocean: dict) -> str:
139
+ """Generate OCEAN suffix from scores (e.g., '54432' for O=5,C=4,E=4,A=3,N=2)."""
140
+ return f"{ocean['O']}{ocean['C']}{ocean['E']}{ocean['A']}{ocean['N']}"
141
+
142
+
143
+ def generate_portrait_filename(short_name: str, ocean: dict) -> str:
144
+ """Generate portrait filename from shortName and OCEAN scores.
145
+
146
+ Format: {shortName-slug}-{OCEAN}.png (e.g., 'yoda-54242.png')
147
+ """
148
+ slug = to_slug(short_name)
149
+ return f"{slug}-{ocean_suffix(ocean)}.png"
150
+
151
+
152
+ def parse_theme_file(theme_path: Path) -> dict:
153
+ """Parse theme YAML file to extract visual prompts for each agent."""
154
+ with open(theme_path, "r", encoding="utf-8") as f:
155
+ data = yaml.safe_load(f)
156
+
157
+ theme_metadata = data.get("theme", {})
158
+ result = {
159
+ "theme": theme_path.stem,
160
+ "source": theme_metadata.get("source", ""),
161
+ "portrait_style": theme_metadata.get("portrait_style", None),
162
+ "characters": {}
163
+ }
164
+
165
+ agents = data.get("agents", {})
166
+ for role, agent_data in agents.items():
167
+ if isinstance(agent_data, dict) and "visual" in agent_data:
168
+ # Get shortName, fallback to first word of character name
169
+ character = agent_data.get("character", role)
170
+ short_name = agent_data.get("shortName", character.split()[0])
171
+ ocean = agent_data.get("ocean", {})
172
+
173
+ # Generate filename if OCEAN scores are available
174
+ if ocean and all(k in ocean for k in ['O', 'C', 'E', 'A', 'N']):
175
+ filename = generate_portrait_filename(short_name, ocean)
176
+ else:
177
+ # Fallback to role-based name if no OCEAN scores
178
+ filename = f"{role}.png"
179
+
180
+ result["characters"][role] = {
181
+ "name": character,
182
+ "shortName": short_name,
183
+ "visual": agent_data["visual"],
184
+ "ocean": ocean,
185
+ "filename": filename
186
+ }
187
+
188
+ return result
189
+
190
+
191
+ def build_portrait_prompt(visual: str, style_suffix: str = None) -> tuple[str, bool, int]:
192
+ """Build a prompt for portrait generation with CLIP token limit enforcement.
193
+
194
+ Args:
195
+ visual: The character's visual description from theme YAML
196
+ style_suffix: Optional theme-specific style suffix. Falls back to DEFAULT_STYLE_SUFFIX.
197
+
198
+ Returns:
199
+ tuple: (prompt, was_truncated, token_count)
200
+ """
201
+ suffix = style_suffix if style_suffix is not None else DEFAULT_STYLE_SUFFIX
202
+ prompt, was_truncated = truncate_prompt_to_clip_limit(visual, suffix)
203
+ token_count = count_clip_tokens(prompt)
204
+ return prompt, was_truncated, token_count
205
+
206
+
207
+ def load_pipeline():
208
+ """Load SDXL pipeline on MPS."""
209
+ print("\nLoading SDXL model on MPS...")
210
+ print("(First run downloads ~6.5GB model)")
211
+
212
+ # Use float32 on MPS to avoid NaN issues with float16
213
+ pipe = StableDiffusionXLPipeline.from_pretrained(
214
+ MODEL_ID,
215
+ torch_dtype=torch.float32,
216
+ use_safetensors=True,
217
+ )
218
+
219
+ pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
220
+ pipe = pipe.to("mps")
221
+ pipe.enable_attention_slicing()
222
+
223
+ print("Model loaded.\n")
224
+ return pipe
225
+
226
+
227
+ def generate_portrait(pipe, prompt: str, seed: int = 42) -> "Image.Image":
228
+ """Generate a single portrait."""
229
+ # Use CPU generator for MPS compatibility
230
+ generator = torch.Generator().manual_seed(seed)
231
+
232
+ with torch.no_grad():
233
+ result = pipe(
234
+ prompt=prompt,
235
+ negative_prompt="color, grayscale, photorealistic, blurry, deformed",
236
+ width=GENERATION_SIZE,
237
+ height=GENERATION_SIZE,
238
+ num_inference_steps=NUM_INFERENCE_STEPS,
239
+ guidance_scale=GUIDANCE_SCALE,
240
+ generator=generator,
241
+ )
242
+
243
+ image = result.images[0]
244
+ # Resize to output size
245
+ return image.resize((OUTPUT_SIZE, OUTPUT_SIZE), Image.Resampling.LANCZOS)
246
+
247
+
248
+ def main():
249
+ parser = argparse.ArgumentParser(description="Generate individual portraits from theme YAML files")
250
+ parser.add_argument("--dry-run", action="store_true", help="List without generating")
251
+ parser.add_argument("--theme", type=str, help="Generate only this theme")
252
+ parser.add_argument("--role", type=str, help="Generate only this role (with --theme)")
253
+ parser.add_argument("--seed", type=int, default=42, help="Random seed")
254
+ parser.add_argument("--skip-existing", action="store_true", help="Skip existing files")
255
+ parser.add_argument("--output-dir", type=str, help="Output to different directory (default: pennyfarthing-dist/personas/portraits)")
256
+ args = parser.parse_args()
257
+
258
+ # Determine output directory
259
+ output_base = Path(args.output_dir) if args.output_dir else OUTPUT_DIR
260
+
261
+ # Find theme files from both built-in and custom directories
262
+ # Custom themes take precedence over built-in themes with same name
263
+ theme_map = {}
264
+
265
+ # First add built-in themes
266
+ if BUILTIN_THEMES_DIR.exists():
267
+ for tf in BUILTIN_THEMES_DIR.glob("*.yaml"):
268
+ theme_map[tf.stem] = tf
269
+
270
+ # Then add/override with custom themes
271
+ if CUSTOM_THEMES_DIR.exists():
272
+ for tf in CUSTOM_THEMES_DIR.glob("*.yaml"):
273
+ theme_map[tf.stem] = tf
274
+
275
+ theme_files = sorted(theme_map.values(), key=lambda p: p.stem)
276
+
277
+ if args.theme:
278
+ if args.theme in theme_map:
279
+ theme_files = [theme_map[args.theme]]
280
+ else:
281
+ print(f"Theme '{args.theme}' not found")
282
+ print(f" Searched: {BUILTIN_THEMES_DIR}")
283
+ print(f" Searched: {CUSTOM_THEMES_DIR}")
284
+ sys.exit(1)
285
+
286
+ print(f"Theme sources:")
287
+ print(f" Built-in: {BUILTIN_THEMES_DIR}")
288
+ print(f" Custom: {CUSTOM_THEMES_DIR}")
289
+ print(f"Found {len(theme_files)} themes")
290
+ print(f"Output: {output_base}/{{theme}}/{{slug}}-{{OCEAN}}.png")
291
+
292
+ if args.dry_run:
293
+ print(f"\nCLIP token limit: {CLIP_MAX_TOKENS} tokens")
294
+ print(f"Tokenizer: {'CLIP (accurate)' if HAS_CLIP_TOKENIZER else 'word estimate (fallback)'}")
295
+ print("\nDry run - portraits to generate:")
296
+ truncation_warnings = []
297
+ for tf in theme_files:
298
+ parsed = parse_theme_file(tf)
299
+ theme_dir = output_base / parsed["theme"]
300
+ char_count = len(parsed["characters"])
301
+ style_desc = parsed["portrait_style"][:60] + "..." if parsed["portrait_style"] and len(parsed["portrait_style"]) > 60 else parsed["portrait_style"]
302
+ style_display = style_desc if style_desc else "(default woodcut)"
303
+ print(f"\n {parsed['theme']}/ ({char_count} characters with visual)")
304
+ print(f" Style: {style_display}")
305
+ for role in ROLES:
306
+ if role in parsed["characters"]:
307
+ char = parsed["characters"][role]
308
+ out_path = theme_dir / char["filename"]
309
+ status = "EXISTS" if out_path.exists() else "PENDING"
310
+
311
+ # Check token count and truncation
312
+ prompt, was_truncated, token_count = build_portrait_prompt(char["visual"], parsed["portrait_style"])
313
+ token_status = f"{token_count}tok"
314
+ if was_truncated:
315
+ token_status = f"⚠️ {token_count}tok TRUNCATED"
316
+ truncation_warnings.append((parsed["theme"], role, char["filename"]))
317
+
318
+ visual_preview = char["visual"][:40] + "..." if len(char["visual"]) > 40 else char["visual"]
319
+ print(f" [{status}] {char['filename']} ({token_status}): {visual_preview}")
320
+ else:
321
+ print(f" [SKIP] {role}: no visual field")
322
+
323
+ if truncation_warnings:
324
+ print(f"\n{'='*60}")
325
+ print(f"⚠️ WARNING: {len(truncation_warnings)} prompts will be truncated!")
326
+ print(f" CLIP limit is {CLIP_MAX_TOKENS} tokens. Consider shortening:")
327
+ for theme, role, filename in truncation_warnings[:10]:
328
+ print(f" - {theme}/{filename} ({role})")
329
+ if len(truncation_warnings) > 10:
330
+ print(f" ... and {len(truncation_warnings) - 10} more")
331
+ return
332
+
333
+ # Check for torch
334
+ if not HAS_TORCH:
335
+ print(f"Missing required package: {TORCH_ERROR}")
336
+ print("\nInstall: pip install diffusers transformers accelerate torch pillow")
337
+ sys.exit(1)
338
+
339
+ # Load model
340
+ pipe = load_pipeline()
341
+
342
+ # Track results
343
+ successful = 0
344
+ failed = []
345
+ truncated = []
346
+ start_time = datetime.now()
347
+
348
+ total_themes = len(theme_files)
349
+ for theme_idx, tf in enumerate(theme_files, 1):
350
+ parsed = parse_theme_file(tf)
351
+ theme = parsed["theme"]
352
+ theme_dir = output_base / theme
353
+ theme_dir.mkdir(parents=True, exist_ok=True)
354
+
355
+ roles_to_gen = [args.role] if args.role else ROLES
356
+ print(f"\n[{theme_idx}/{total_themes}] Theme: {theme}")
357
+
358
+ for role in roles_to_gen:
359
+ if role not in parsed["characters"]:
360
+ continue
361
+
362
+ char = parsed["characters"][role]
363
+ out_path = theme_dir / char["filename"]
364
+ if args.skip_existing and out_path.exists():
365
+ print(f" SKIP (exists): {char['filename']}")
366
+ continue
367
+
368
+ prompt, was_truncated, token_count = build_portrait_prompt(char["visual"], parsed["portrait_style"])
369
+
370
+ if was_truncated:
371
+ truncated.append((theme, char["filename"], token_count))
372
+ print(f" WARNING: Truncated {char['filename']} to {token_count} tokens")
373
+
374
+ print(f" Generating: {char['filename']} ({char['name']})...")
375
+ print(f" Prompt: {prompt}")
376
+ try:
377
+ # Vary seed per character for diversity (base_seed + role_index)
378
+ role_seed = args.seed + ROLES.index(role)
379
+ image = generate_portrait(pipe, prompt, seed=role_seed)
380
+ image.save(out_path, "PNG")
381
+ successful += 1
382
+ print(f" DONE: {char['filename']}")
383
+ except Exception as e:
384
+ failed.append((theme, char["filename"], str(e)))
385
+ print(f" FAILED: {char['filename']}: {e}")
386
+
387
+ # Summary
388
+ elapsed = datetime.now() - start_time
389
+ print(f"\n{'='*50}")
390
+ print(f"Complete: {successful} portraits in {elapsed}")
391
+ if truncated:
392
+ print(f"Truncated: {len(truncated)} prompts exceeded {CLIP_MAX_TOKENS} token limit")
393
+ if failed:
394
+ print(f"Failed: {len(failed)}")
395
+ for t, r, e in failed:
396
+ print(f" - {t}/{r}: {e}")
397
+
398
+
399
+ if __name__ == "__main__":
400
+ main()
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Portrait Generator Wrapper
4
+ # Activates venv and runs generate-portraits.py with all arguments
5
+ #
6
+ # Usage:
7
+ # ./scripts/generate-portraits.sh --theme arthurian-mythos --dry-run
8
+ # ./scripts/generate-portraits.sh --theme shakespeare
9
+ # ./scripts/generate-portraits.sh --theme star-trek-tos --output-dir /tmp/portraits
10
+ # ./scripts/generate-portraits.sh --help
11
+
12
+ set -euo pipefail
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+
16
+ # Find PROJECT_ROOT by looking for .pennyfarthing or pennyfarthing-dist marker
17
+ _dir="$SCRIPT_DIR"
18
+ while [[ ! -d "$_dir/.pennyfarthing" ]] && [[ ! -d "$_dir/pennyfarthing-dist" ]] && [[ "$_dir" != "/" ]]; do
19
+ _dir="$(dirname "$_dir")"
20
+ done
21
+ PROJECT_ROOT="$_dir"
22
+
23
+ # If we're in the pennyfarthing repo itself, look for .venv there
24
+ # If we're in a user project, .venv should be at project root
25
+ VENV_DIR="$PROJECT_ROOT/.venv"
26
+ PYTHON_SCRIPT="$SCRIPT_DIR/generate-portraits.py"
27
+
28
+ # Check venv exists
29
+ if [[ ! -d "$VENV_DIR" ]]; then
30
+ echo "Error: Virtual environment not found at $VENV_DIR"
31
+ echo "Create it with: python3 -m venv .venv"
32
+ echo "Then install: pip install diffusers transformers accelerate torch pillow pyyaml"
33
+ exit 1
34
+ fi
35
+
36
+ # Check Python script exists
37
+ if [[ ! -f "$PYTHON_SCRIPT" ]]; then
38
+ echo "Error: generate-portraits.py not found at $PYTHON_SCRIPT"
39
+ exit 1
40
+ fi
41
+
42
+ # Activate venv and run
43
+ source "$VENV_DIR/bin/activate"
44
+
45
+ # Verify torch is available
46
+ if ! python -c "import torch" 2>/dev/null; then
47
+ echo "Error: torch not installed in venv"
48
+ echo "Install with: pip install diffusers transformers accelerate torch pillow"
49
+ deactivate
50
+ exit 1
51
+ fi
52
+
53
+ # Run the portrait generator with all passed arguments
54
+ python "$PYTHON_SCRIPT" "$@"
@@ -0,0 +1,29 @@
1
+ # Sprint Scripts
2
+
3
+ Scripts for sprint YAML operations and sprint management.
4
+
5
+ ## Scripts
6
+
7
+ | Script | Purpose |
8
+ |--------|---------|
9
+ | `sprint-status.sh` | Show current sprint status and metrics |
10
+ | `sprint-info.sh` | Display sprint information |
11
+ | `available-stories.sh` | List available stories in backlog |
12
+ | `archive-story.sh` | Archive completed story to sprint archive |
13
+ | `check-story.sh` | Check story details and readiness |
14
+ | `new-sprint.sh` | Create a new sprint |
15
+ | `promote-epic.sh` | Move epic from planning to current sprint |
16
+ | `sprint-common.sh` | Shared sprint utilities (library) |
17
+ | `sprint-metrics.sh` | Calculate sprint metrics |
18
+
19
+ ## Usage
20
+
21
+ ```bash
22
+ .pennyfarthing/scripts/core/run.sh sprint/sprint-status.sh
23
+ .pennyfarthing/scripts/core/run.sh sprint/available-stories.sh
24
+ ```
25
+
26
+ ## Ownership
27
+
28
+ - **Primary users:** SM agent, `/sprint` skill
29
+ - **Maintained by:** Core Pennyfarthing team
@@ -0,0 +1,139 @@
1
+ #!/bin/bash
2
+ # Archive a completed story from current-sprint.yaml to the sprint archive
3
+ # Usage: .pennyfarthing/scripts/core/run.sh sprint/archive-story.sh <story-id> [pr-number] [--apply]
4
+ #
5
+ # Example: .pennyfarthing/scripts/core/run.sh sprint/archive-story.sh MSSCI-11945 368
6
+ # .pennyfarthing/scripts/core/run.sh sprint/archive-story.sh MSSCI-11945 368 --apply
7
+ #
8
+ # Options:
9
+ # --apply Also remove story from current-sprint.yaml (atomic operation)
10
+
11
+ set -euo pipefail
12
+
13
+ STORY_ID="${1:-}"
14
+ PR_NUMBER=""
15
+ APPLY_FLAG=false
16
+
17
+ # Parse positional and flag arguments
18
+ shift || true
19
+ for arg in "$@"; do
20
+ case $arg in
21
+ --apply)
22
+ APPLY_FLAG=true
23
+ ;;
24
+ *)
25
+ # If not a flag, it's the PR number
26
+ if [[ -z "$PR_NUMBER" ]]; then
27
+ PR_NUMBER="$arg"
28
+ fi
29
+ ;;
30
+ esac
31
+ done
32
+
33
+ if [[ -z "$STORY_ID" ]]; then
34
+ echo "Usage: archive-story.sh <story-id> [pr-number] [--apply]"
35
+ echo "Example: archive-story.sh MSSCI-11945 368"
36
+ echo " archive-story.sh MSSCI-11945 368 --apply"
37
+ echo ""
38
+ echo "Options:"
39
+ echo " --apply Also remove story from current-sprint.yaml"
40
+ exit 1
41
+ fi
42
+
43
+ # PROJECT_ROOT should be set by run.sh, but find it if not
44
+ if [[ -z "${PROJECT_ROOT:-}" ]]; then
45
+ d="$PWD"
46
+ while [[ ! -d "$d/.pennyfarthing" ]] && [[ "$d" != "/" ]]; do
47
+ d="$(dirname "$d")"
48
+ done
49
+ PROJECT_ROOT="$d"
50
+ fi
51
+
52
+ SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
53
+
54
+ if [[ ! -f "$SPRINT_FILE" ]]; then
55
+ echo "Error: Sprint file not found at $SPRINT_FILE"
56
+ exit 1
57
+ fi
58
+
59
+ # Extract sprint name to determine archive file
60
+ # Try jira_sprint_name first (newer format), then fall back to name (older format)
61
+ SPRINT_NAME=$(grep -E "^\s+jira_sprint_name:" "$SPRINT_FILE" | head -1 | sed 's/.*TO Sprint \([0-9]*\).*/\1/')
62
+ if [[ -z "$SPRINT_NAME" ]]; then
63
+ SPRINT_NAME=$(grep -E "^\s+name:" "$SPRINT_FILE" | head -1 | sed 's/.*"TO Sprint \([0-9]*\)".*/\1/')
64
+ fi
65
+ if [[ -z "$SPRINT_NAME" ]]; then
66
+ echo "Error: Could not extract sprint name from $SPRINT_FILE"
67
+ exit 1
68
+ fi
69
+
70
+ ARCHIVE_FILE="$PROJECT_ROOT/sprint/archive/sprint-${SPRINT_NAME}-completed.yaml"
71
+
72
+ # Check if archive file exists
73
+ if [[ ! -f "$ARCHIVE_FILE" ]]; then
74
+ echo "Error: Archive file not found at $ARCHIVE_FILE"
75
+ echo "Create it first with new-sprint.sh or manually"
76
+ exit 1
77
+ fi
78
+
79
+ # Use yq to extract story data
80
+ if ! command -v yq &> /dev/null; then
81
+ echo "Error: yq is required but not installed"
82
+ echo "Install with: brew install yq"
83
+ exit 1
84
+ fi
85
+
86
+ # Find the story in current sprint
87
+ STORY_DATA=$(yq eval ".epics[].stories[] | select(.id == \"$STORY_ID\")" "$SPRINT_FILE")
88
+
89
+ if [[ -z "$STORY_DATA" ]]; then
90
+ echo "Error: Story $STORY_ID not found in $SPRINT_FILE"
91
+ exit 1
92
+ fi
93
+
94
+ # Extract story fields
95
+ TITLE=$(echo "$STORY_DATA" | yq eval '.title' -)
96
+ POINTS=$(echo "$STORY_DATA" | yq eval '.points' -)
97
+ EPIC_ID=$(yq eval ".epics[] | select(.stories[].id == \"$STORY_ID\") | .id" "$SPRINT_FILE" | head -1)
98
+
99
+ # Get today's date
100
+ COMPLETED_DATE=$(date +%Y-%m-%d)
101
+
102
+ # Build the archive entry
103
+ echo ""
104
+ echo "Archiving story:"
105
+ echo " ID: $STORY_ID"
106
+ echo " Title: $TITLE"
107
+ echo " Points: $POINTS"
108
+ echo " Epic: $EPIC_ID"
109
+ echo " Completed: $COMPLETED_DATE"
110
+ [[ -n "$PR_NUMBER" ]] && echo " PR: $PR_NUMBER"
111
+ echo ""
112
+
113
+ # Append to archive file
114
+ {
115
+ echo " - id: $STORY_ID"
116
+ echo " epic: $EPIC_ID"
117
+ echo " title: \"$TITLE\""
118
+ echo " points: $POINTS"
119
+ echo " completed: $COMPLETED_DATE"
120
+ [[ -n "$PR_NUMBER" ]] && echo " pr: $PR_NUMBER"
121
+ } >> "$ARCHIVE_FILE"
122
+
123
+ echo "Added to $ARCHIVE_FILE"
124
+
125
+ # Remove from current sprint (if --apply)
126
+ if $APPLY_FLAG; then
127
+ echo ""
128
+ echo "Removing story from current sprint..."
129
+ yq eval -i "del(.epics[].stories[] | select(.id == \"$STORY_ID\"))" "$SPRINT_FILE"
130
+ echo "✓ Story removed from $SPRINT_FILE"
131
+ echo ""
132
+ echo "If the epic has no more stories, you may want to remove the empty epic section."
133
+ else
134
+ echo ""
135
+ echo "To also remove from $SPRINT_FILE, re-run with --apply:"
136
+ echo " .pennyfarthing/scripts/core/run.sh sprint/archive-story.sh $STORY_ID ${PR_NUMBER:-<pr>} --apply"
137
+ echo ""
138
+ echo "Or manually: yq eval -i 'del(.epics[].stories[] | select(.id == \"$STORY_ID\"))' $SPRINT_FILE"
139
+ fi