@pennyfarthing/core 7.0.2 → 7.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (628) hide show
  1. package/LICENSE +14 -0
  2. package/README.md +2 -2
  3. package/package.json +11 -10
  4. package/packages/core/dist/cli/commands/cyclist.d.ts +2 -2
  5. package/packages/core/dist/cli/commands/cyclist.d.ts.map +1 -1
  6. package/packages/core/dist/cli/commands/cyclist.js +8 -9
  7. package/packages/core/dist/cli/commands/cyclist.js.map +1 -1
  8. package/packages/core/dist/cli/commands/cyclist.test.js +6 -4
  9. package/packages/core/dist/cli/commands/cyclist.test.js.map +1 -1
  10. package/packages/core/dist/cli/commands/init.js +4 -3
  11. package/packages/core/dist/cli/commands/init.js.map +1 -1
  12. package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
  13. package/packages/core/dist/cli/commands/update.js +15 -139
  14. package/packages/core/dist/cli/commands/update.js.map +1 -1
  15. package/packages/core/dist/cli/cyclist-migration.test.js +4 -3
  16. package/packages/core/dist/cli/cyclist-migration.test.js.map +1 -1
  17. package/packages/core/dist/cli/utils/constants.d.ts +7 -1
  18. package/packages/core/dist/cli/utils/constants.d.ts.map +1 -1
  19. package/packages/core/dist/cli/utils/constants.js +4 -2
  20. package/packages/core/dist/cli/utils/constants.js.map +1 -1
  21. package/packages/core/dist/cli/utils/node-modules.d.ts.map +1 -1
  22. package/packages/core/dist/cli/utils/node-modules.js +2 -1
  23. package/packages/core/dist/cli/utils/node-modules.js.map +1 -1
  24. package/packages/core/dist/cli/utils/themes.d.ts +1 -4
  25. package/packages/core/dist/cli/utils/themes.d.ts.map +1 -1
  26. package/packages/core/dist/cli/utils/themes.js +2 -22
  27. package/packages/core/dist/cli/utils/themes.js.map +1 -1
  28. package/packages/core/dist/cli/utils/themes.test.d.ts +3 -3
  29. package/packages/core/dist/cli/utils/themes.test.js +16 -13
  30. package/packages/core/dist/cli/utils/themes.test.js.map +1 -1
  31. package/packages/core/dist/cli/workspace.test.js +11 -9
  32. package/packages/core/dist/cli/workspace.test.js.map +1 -1
  33. package/packages/core/dist/index.d.ts +1 -0
  34. package/packages/core/dist/index.d.ts.map +1 -1
  35. package/packages/core/dist/index.js +10 -0
  36. package/packages/core/dist/index.js.map +1 -1
  37. package/packages/core/dist/jira/jira-epic-creation.d.ts +109 -0
  38. package/packages/core/dist/jira/jira-epic-creation.d.ts.map +1 -0
  39. package/packages/core/dist/jira/jira-epic-creation.js +253 -0
  40. package/packages/core/dist/jira/jira-epic-creation.js.map +1 -0
  41. package/packages/core/dist/jira/jira-epic-creation.test.d.ts +16 -0
  42. package/packages/core/dist/jira/jira-epic-creation.test.d.ts.map +1 -0
  43. package/packages/core/dist/jira/jira-epic-creation.test.js +387 -0
  44. package/packages/core/dist/jira/jira-epic-creation.test.js.map +1 -0
  45. package/packages/core/dist/jira/jira-sprint-sync.d.ts +247 -0
  46. package/packages/core/dist/jira/jira-sprint-sync.d.ts.map +1 -0
  47. package/packages/core/dist/jira/jira-sprint-sync.js +670 -0
  48. package/packages/core/dist/jira/jira-sprint-sync.js.map +1 -0
  49. package/packages/core/dist/jira/jira-sprint-sync.test.d.ts +16 -0
  50. package/packages/core/dist/jira/jira-sprint-sync.test.d.ts.map +1 -0
  51. package/packages/core/dist/jira/jira-sprint-sync.test.js +845 -0
  52. package/packages/core/dist/jira/jira-sprint-sync.test.js.map +1 -0
  53. package/packages/core/dist/scripts/generate-spider.d.ts +11 -1
  54. package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -1
  55. package/packages/core/dist/scripts/generate-spider.js +24 -1
  56. package/packages/core/dist/scripts/generate-spider.js.map +1 -1
  57. package/packages/core/dist/scripts/generate-spider.test.js +6 -4
  58. package/packages/core/dist/scripts/generate-spider.test.js.map +1 -1
  59. package/packages/core/dist/workflow/gate-handler.d.ts +94 -0
  60. package/packages/core/dist/workflow/gate-handler.d.ts.map +1 -0
  61. package/packages/core/dist/workflow/gate-handler.js +189 -0
  62. package/packages/core/dist/workflow/gate-handler.js.map +1 -0
  63. package/packages/core/dist/workflow/gate-handler.test.d.ts +14 -0
  64. package/packages/core/dist/workflow/gate-handler.test.d.ts.map +1 -0
  65. package/packages/core/dist/workflow/gate-handler.test.js +543 -0
  66. package/packages/core/dist/workflow/gate-handler.test.js.map +1 -0
  67. package/packages/core/dist/workflow/generic-handoff.d.ts +46 -0
  68. package/packages/core/dist/workflow/generic-handoff.d.ts.map +1 -1
  69. package/packages/core/dist/workflow/generic-handoff.js +53 -0
  70. package/packages/core/dist/workflow/generic-handoff.js.map +1 -1
  71. package/packages/core/dist/workflow/generic-handoff.test.js +2 -2
  72. package/packages/core/dist/workflow/generic-handoff.test.js.map +1 -1
  73. package/packages/core/dist/workflow/handoff.d.ts +281 -0
  74. package/packages/core/dist/workflow/handoff.d.ts.map +1 -0
  75. package/packages/core/dist/workflow/handoff.js +411 -0
  76. package/packages/core/dist/workflow/handoff.js.map +1 -0
  77. package/packages/core/dist/workflow/handoff.test.d.ts +21 -0
  78. package/packages/core/dist/workflow/handoff.test.d.ts.map +1 -0
  79. package/packages/core/dist/workflow/handoff.test.js +499 -0
  80. package/packages/core/dist/workflow/handoff.test.js.map +1 -0
  81. package/packages/core/dist/workflow/index.d.ts +16 -0
  82. package/packages/core/dist/workflow/index.d.ts.map +1 -0
  83. package/packages/core/dist/workflow/index.js +24 -0
  84. package/packages/core/dist/workflow/index.js.map +1 -0
  85. package/packages/core/dist/workflow/session-state.d.ts +92 -0
  86. package/packages/core/dist/workflow/session-state.d.ts.map +1 -0
  87. package/packages/core/dist/workflow/session-state.js +198 -0
  88. package/packages/core/dist/workflow/session-state.js.map +1 -0
  89. package/packages/core/dist/workflow/session-state.test.d.ts +8 -0
  90. package/packages/core/dist/workflow/session-state.test.d.ts.map +1 -0
  91. package/packages/core/dist/workflow/session-state.test.js +551 -0
  92. package/packages/core/dist/workflow/session-state.test.js.map +1 -0
  93. package/packages/core/dist/workflow/sm-subagents.test.d.ts +2 -2
  94. package/packages/core/dist/workflow/sm-subagents.test.js +6 -6
  95. package/packages/core/dist/workflow/sm-subagents.test.js.map +1 -1
  96. package/packages/core/dist/workflow/step-parser.d.ts +45 -0
  97. package/packages/core/dist/workflow/step-parser.d.ts.map +1 -0
  98. package/packages/core/dist/workflow/step-parser.js +147 -0
  99. package/packages/core/dist/workflow/step-parser.js.map +1 -0
  100. package/packages/core/dist/workflow/step-parser.test.d.ts +14 -0
  101. package/packages/core/dist/workflow/step-parser.test.d.ts.map +1 -0
  102. package/packages/core/dist/workflow/step-parser.test.js +470 -0
  103. package/packages/core/dist/workflow/step-parser.test.js.map +1 -0
  104. package/packages/core/dist/workflow/trimodal.d.ts +86 -0
  105. package/packages/core/dist/workflow/trimodal.d.ts.map +1 -0
  106. package/packages/core/dist/workflow/trimodal.js +118 -0
  107. package/packages/core/dist/workflow/trimodal.js.map +1 -0
  108. package/packages/core/dist/workflow/trimodal.test.d.ts +11 -0
  109. package/packages/core/dist/workflow/trimodal.test.d.ts.map +1 -0
  110. package/packages/core/dist/workflow/trimodal.test.js +395 -0
  111. package/packages/core/dist/workflow/trimodal.test.js.map +1 -0
  112. package/packages/core/dist/workflow/variable-resolver.d.ts +67 -0
  113. package/packages/core/dist/workflow/variable-resolver.d.ts.map +1 -0
  114. package/packages/core/dist/workflow/variable-resolver.js +156 -0
  115. package/packages/core/dist/workflow/variable-resolver.js.map +1 -0
  116. package/packages/core/dist/workflow/variable-resolver.test.d.ts +14 -0
  117. package/packages/core/dist/workflow/variable-resolver.test.d.ts.map +1 -0
  118. package/packages/core/dist/workflow/variable-resolver.test.js +400 -0
  119. package/packages/core/dist/workflow/variable-resolver.test.js.map +1 -0
  120. package/packages/core/dist/workflow/workflow-executor.d.ts +163 -0
  121. package/packages/core/dist/workflow/workflow-executor.d.ts.map +1 -0
  122. package/packages/core/dist/workflow/workflow-executor.js +197 -0
  123. package/packages/core/dist/workflow/workflow-executor.js.map +1 -0
  124. package/packages/core/dist/workflow/workflow-executor.test.d.ts +8 -0
  125. package/packages/core/dist/workflow/workflow-executor.test.d.ts.map +1 -0
  126. package/packages/core/dist/workflow/workflow-executor.test.js +444 -0
  127. package/packages/core/dist/workflow/workflow-executor.test.js.map +1 -0
  128. package/packages/core/dist/workflow/workflow-loader.test.js +5 -5
  129. package/packages/core/dist/workflow/workflow-loader.test.js.map +1 -1
  130. package/packages/core/dist/workflow/workflow-migration.test.js +8 -9
  131. package/packages/core/dist/workflow/workflow-migration.test.js.map +1 -1
  132. package/packages/core/dist/workflow/workflow-permissions.d.ts +55 -0
  133. package/packages/core/dist/workflow/workflow-permissions.d.ts.map +1 -0
  134. package/packages/core/dist/workflow/workflow-permissions.js +64 -0
  135. package/packages/core/dist/workflow/workflow-permissions.js.map +1 -0
  136. package/packages/core/dist/workflow/workflow-permissions.test.d.ts +15 -0
  137. package/packages/core/dist/workflow/workflow-permissions.test.d.ts.map +1 -0
  138. package/packages/core/dist/workflow/workflow-permissions.test.js +301 -0
  139. package/packages/core/dist/workflow/workflow-permissions.test.js.map +1 -0
  140. package/packages/core/dist/workflow/workflow-schema.d.ts +61 -2
  141. package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -1
  142. package/packages/core/dist/workflow/workflow-schema.js +293 -69
  143. package/packages/core/dist/workflow/workflow-schema.js.map +1 -1
  144. package/packages/core/dist/workflow/workflow-schema.test.js +6 -6
  145. package/packages/core/dist/workflow/workflow-schema.test.js.map +1 -1
  146. package/packages/core/dist/workflow/workflow-stepped-schema.test.d.ts +18 -0
  147. package/packages/core/dist/workflow/workflow-stepped-schema.test.d.ts.map +1 -0
  148. package/packages/core/dist/workflow/workflow-stepped-schema.test.js +608 -0
  149. package/packages/core/dist/workflow/workflow-stepped-schema.test.js.map +1 -0
  150. package/pennyfarthing-dist/agents/README.md +63 -134
  151. package/pennyfarthing-dist/agents/architect.md +18 -10
  152. package/pennyfarthing-dist/agents/dev.md +47 -32
  153. package/pennyfarthing-dist/agents/devops.md +18 -9
  154. package/pennyfarthing-dist/agents/handoff.md +289 -0
  155. package/pennyfarthing-dist/agents/orchestrator.md +44 -22
  156. package/pennyfarthing-dist/agents/pm.md +13 -8
  157. package/pennyfarthing-dist/agents/reviewer-preflight.md +42 -128
  158. package/pennyfarthing-dist/agents/reviewer.md +104 -57
  159. package/pennyfarthing-dist/agents/sm-file-summary.md +24 -75
  160. package/pennyfarthing-dist/agents/sm-finish.md +61 -0
  161. package/pennyfarthing-dist/agents/sm-handoff.md +102 -54
  162. package/pennyfarthing-dist/agents/sm-setup.md +174 -0
  163. package/pennyfarthing-dist/agents/sm.md +223 -100
  164. package/pennyfarthing-dist/agents/tea.md +42 -34
  165. package/pennyfarthing-dist/agents/tech-writer.md +74 -6
  166. package/pennyfarthing-dist/agents/testing-runner.md +78 -360
  167. package/pennyfarthing-dist/agents/ux-designer.md +80 -7
  168. package/pennyfarthing-dist/agents/workflow-status-check.md +35 -299
  169. package/pennyfarthing-dist/commands/architect.md +2 -2
  170. package/pennyfarthing-dist/commands/close-epic.md +5 -2
  171. package/pennyfarthing-dist/commands/create-branches-from-story.md +7 -23
  172. package/pennyfarthing-dist/commands/dev.md +2 -2
  173. package/pennyfarthing-dist/commands/devops.md +3 -3
  174. package/pennyfarthing-dist/commands/git-cleanup.md +5 -5
  175. package/pennyfarthing-dist/commands/health-check.md +1 -1
  176. package/pennyfarthing-dist/commands/list-themes.md +7 -3
  177. package/pennyfarthing-dist/commands/orchestrator.md +2 -2
  178. package/pennyfarthing-dist/commands/parallel-work.md +4 -4
  179. package/pennyfarthing-dist/commands/pm.md +2 -2
  180. package/pennyfarthing-dist/commands/prime.md +7 -7
  181. package/pennyfarthing-dist/commands/release.md +1 -1
  182. package/pennyfarthing-dist/commands/repo-status.md +2 -2
  183. package/pennyfarthing-dist/commands/retro.md +2 -2
  184. package/pennyfarthing-dist/commands/reviewer.md +2 -2
  185. package/pennyfarthing-dist/commands/set-theme.md +5 -1
  186. package/pennyfarthing-dist/commands/sm.md +2 -2
  187. package/pennyfarthing-dist/commands/start-epic.md +26 -14
  188. package/pennyfarthing-dist/commands/sync-epic-to-jira.md +8 -8
  189. package/pennyfarthing-dist/commands/sync-work-with-sprint.md +1 -4
  190. package/pennyfarthing-dist/commands/tea.md +2 -2
  191. package/pennyfarthing-dist/commands/tech-writer.md +2 -2
  192. package/pennyfarthing-dist/commands/ux-designer.md +3 -3
  193. package/pennyfarthing-dist/commands/work.md +15 -4
  194. package/pennyfarthing-dist/commands/workflow.md +21 -0
  195. package/pennyfarthing-dist/guides/AGENT-COORDINATION.md +15 -15
  196. package/pennyfarthing-dist/guides/PROMPT-PATTERNS.md +1 -1
  197. package/pennyfarthing-dist/guides/SESSION-ARTIFACTS.md +4 -4
  198. package/pennyfarthing-dist/guides/agent-behavior.md +238 -0
  199. package/pennyfarthing-dist/guides/agent-template-strategic.md +2 -2
  200. package/pennyfarthing-dist/guides/agent-template-tactical.md +4 -4
  201. package/pennyfarthing-dist/guides/patterns/approval-gates-pattern.md +1 -1
  202. package/pennyfarthing-dist/guides/patterns/helper-delegation-pattern.md +17 -17
  203. package/pennyfarthing-dist/guides/patterns/tdd-flow-pattern.md +8 -8
  204. package/pennyfarthing-dist/guides/workflow-schema.md +62 -0
  205. package/pennyfarthing-dist/guides/worktree-mode.md +5 -5
  206. package/pennyfarthing-dist/personas/themes/1984.yaml +1 -1
  207. package/pennyfarthing-dist/personas/themes/a-team.yaml +1 -1
  208. package/pennyfarthing-dist/personas/themes/agatha-christie.yaml +1 -1
  209. package/pennyfarthing-dist/personas/themes/alice-in-wonderland.yaml +1 -1
  210. package/pennyfarthing-dist/personas/themes/all-stars.yaml +1 -1
  211. package/pennyfarthing-dist/personas/themes/ancient-philosophers.yaml +1 -1
  212. package/pennyfarthing-dist/personas/themes/ancient-strategists.yaml +1 -1
  213. package/pennyfarthing-dist/personas/themes/arcane.yaml +1 -1
  214. package/pennyfarthing-dist/personas/themes/arthurian-mythos.yaml +1 -1
  215. package/pennyfarthing-dist/personas/themes/avatar-the-last-airbender.yaml +1 -1
  216. package/pennyfarthing-dist/personas/themes/babylon-5.yaml +1 -1
  217. package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +1 -1
  218. package/pennyfarthing-dist/personas/themes/better-call-saul.yaml +1 -1
  219. package/pennyfarthing-dist/personas/themes/big-lebowski.yaml +2 -2
  220. package/pennyfarthing-dist/personas/themes/black-sails.yaml +1 -1
  221. package/pennyfarthing-dist/personas/themes/blade-runner.yaml +1 -1
  222. package/pennyfarthing-dist/personas/themes/bobiverse.yaml +1 -1
  223. package/pennyfarthing-dist/personas/themes/breaking-bad.yaml +1 -1
  224. package/pennyfarthing-dist/personas/themes/catch-22.yaml +1 -1
  225. package/pennyfarthing-dist/personas/themes/classical-composers.yaml +1 -1
  226. package/pennyfarthing-dist/personas/themes/control.yaml +1 -1
  227. package/pennyfarthing-dist/personas/themes/count-of-monte-cristo.yaml +1 -1
  228. package/pennyfarthing-dist/personas/themes/cowboy-bebop.yaml +1 -1
  229. package/pennyfarthing-dist/personas/themes/deadwood.yaml +2 -2
  230. package/pennyfarthing-dist/personas/themes/discworld.yaml +2 -2
  231. package/pennyfarthing-dist/personas/themes/doctor-who.yaml +1 -1
  232. package/pennyfarthing-dist/personas/themes/enlightenment-thinkers.yaml +1 -1
  233. package/pennyfarthing-dist/personas/themes/expeditionary-force.yaml +1 -1
  234. package/pennyfarthing-dist/personas/themes/firefly.yaml +1 -1
  235. package/pennyfarthing-dist/personas/themes/foundation.yaml +1 -1
  236. package/pennyfarthing-dist/personas/themes/futurama.yaml +1 -1
  237. package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +2 -2
  238. package/pennyfarthing-dist/personas/themes/gilligans-island.yaml +1 -1
  239. package/pennyfarthing-dist/personas/themes/gothic-literature.yaml +1 -1
  240. package/pennyfarthing-dist/personas/themes/great-gatsby.yaml +1 -1
  241. package/pennyfarthing-dist/personas/themes/greek-mythology.yaml +1 -1
  242. package/pennyfarthing-dist/personas/themes/harry-potter.yaml +2 -2
  243. package/pennyfarthing-dist/personas/themes/his-dark-materials.yaml +1 -1
  244. package/pennyfarthing-dist/personas/themes/historical-figures.yaml +1 -1
  245. package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +1 -1
  246. package/pennyfarthing-dist/personas/themes/house-md.yaml +1 -1
  247. package/pennyfarthing-dist/personas/themes/imperial-radch.yaml +1 -1
  248. package/pennyfarthing-dist/personas/themes/jane-austen.yaml +1 -1
  249. package/pennyfarthing-dist/personas/themes/jazz-legends.yaml +1 -1
  250. package/pennyfarthing-dist/personas/themes/justified.yaml +1 -1
  251. package/pennyfarthing-dist/personas/themes/legion-of-doom.yaml +1 -1
  252. package/pennyfarthing-dist/personas/themes/les-miserables.yaml +1 -1
  253. package/pennyfarthing-dist/personas/themes/lord-of-the-rings.yaml +1 -1
  254. package/pennyfarthing-dist/personas/themes/lovecraft-mythos.yaml +1 -1
  255. package/pennyfarthing-dist/personas/themes/mad-men.yaml +1 -1
  256. package/pennyfarthing-dist/personas/themes/marvel-mcu.yaml +1 -1
  257. package/pennyfarthing-dist/personas/themes/mash.yaml +69 -66
  258. package/pennyfarthing-dist/personas/themes/mass-effect.yaml +1 -1
  259. package/pennyfarthing-dist/personas/themes/military-commanders.yaml +1 -1
  260. package/pennyfarthing-dist/personas/themes/moby-dick.yaml +1 -1
  261. package/pennyfarthing-dist/personas/themes/monty-python.yaml +1 -1
  262. package/pennyfarthing-dist/personas/themes/neuromancer.yaml +1 -1
  263. package/pennyfarthing-dist/personas/themes/norse-mythology.yaml +1 -1
  264. package/pennyfarthing-dist/personas/themes/peaky-blinders.yaml +1 -1
  265. package/pennyfarthing-dist/personas/themes/princess-bride.yaml +1 -1
  266. package/pennyfarthing-dist/personas/themes/rome.yaml +1 -1
  267. package/pennyfarthing-dist/personas/themes/russian-masters.yaml +1 -1
  268. package/pennyfarthing-dist/personas/themes/sandman.yaml +1 -1
  269. package/pennyfarthing-dist/personas/themes/shakespeare.yaml +1 -1
  270. package/pennyfarthing-dist/personas/themes/sherlock-holmes.yaml +1 -1
  271. package/pennyfarthing-dist/personas/themes/snow-crash.yaml +1 -1
  272. package/pennyfarthing-dist/personas/themes/software-pioneers.yaml +1 -1
  273. package/pennyfarthing-dist/personas/themes/star-trek-tng.yaml +1 -1
  274. package/pennyfarthing-dist/personas/themes/star-trek-tos.yaml +1 -1
  275. package/pennyfarthing-dist/personas/themes/star-wars.yaml +1 -1
  276. package/pennyfarthing-dist/personas/themes/superfriends.yaml +1 -1
  277. package/pennyfarthing-dist/personas/themes/the-americans.yaml +1 -1
  278. package/pennyfarthing-dist/personas/themes/the-crown.yaml +1 -1
  279. package/pennyfarthing-dist/personas/themes/the-expanse.yaml +1 -1
  280. package/pennyfarthing-dist/personas/themes/the-good-place.yaml +1 -1
  281. package/pennyfarthing-dist/personas/themes/the-office.yaml +1 -1
  282. package/pennyfarthing-dist/personas/themes/the-simpsons.yaml +1 -1
  283. package/pennyfarthing-dist/personas/themes/the-sopranos.yaml +1 -1
  284. package/pennyfarthing-dist/personas/themes/the-wire.yaml +1 -1
  285. package/pennyfarthing-dist/personas/themes/the-witcher.yaml +1 -1
  286. package/pennyfarthing-dist/personas/themes/vorkosigan-saga.yaml +1 -1
  287. package/pennyfarthing-dist/personas/themes/west-wing.yaml +1 -1
  288. package/pennyfarthing-dist/personas/themes/wwii-leaders.yaml +1 -1
  289. package/pennyfarthing-dist/scripts/README.md +68 -0
  290. package/pennyfarthing-dist/scripts/core/README.md +26 -0
  291. package/pennyfarthing-dist/scripts/{agent-session.sh → core/agent-session.sh} +34 -23
  292. package/pennyfarthing-dist/scripts/{check-context.sh → core/check-context.sh} +93 -37
  293. package/pennyfarthing-dist/scripts/core/handoff-marker.sh +90 -0
  294. package/pennyfarthing-dist/scripts/core/prime.sh +136 -0
  295. package/pennyfarthing-dist/scripts/core/run.sh +75 -0
  296. package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +21 -0
  297. package/pennyfarthing-dist/scripts/git/README.md +25 -0
  298. package/pennyfarthing-dist/scripts/{utils → git}/create-feature-branches.sh +11 -15
  299. package/pennyfarthing-dist/scripts/{utils → git}/git-status-all.sh +1 -1
  300. package/pennyfarthing-dist/scripts/{install-git-hooks.sh → git/install-git-hooks.sh} +0 -0
  301. package/pennyfarthing-dist/scripts/{release.sh → git/release.sh} +0 -0
  302. package/pennyfarthing-dist/scripts/{worktree-manager.sh → git/worktree-manager.sh} +0 -4
  303. package/pennyfarthing-dist/scripts/hooks/README.md +32 -0
  304. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +3 -4
  305. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +1 -2
  306. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +0 -0
  307. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +1 -1
  308. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +0 -0
  309. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
  310. package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -0
  311. package/pennyfarthing-dist/scripts/hooks/session-start.sh +2 -3
  312. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +2 -3
  313. package/pennyfarthing-dist/scripts/jira/README.md +33 -0
  314. package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +101 -0
  315. package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +97 -0
  316. package/pennyfarthing-dist/scripts/jira/jira-bidirectional-sync.mjs +327 -0
  317. package/pennyfarthing-dist/scripts/jira/jira-bidirectional-sync.test.mjs +503 -0
  318. package/pennyfarthing-dist/scripts/{utils → jira}/jira-claim-story.sh +8 -6
  319. package/pennyfarthing-dist/scripts/{utils/jira → jira}/jira-lib.mjs +10 -10
  320. package/pennyfarthing-dist/scripts/{utils → jira}/jira-lib.sh +18 -17
  321. package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +266 -0
  322. package/pennyfarthing-dist/scripts/{utils/jira → jira}/jira-sync-story.mjs +14 -14
  323. package/pennyfarthing-dist/scripts/{utils → jira}/jira-sync-story.sh +0 -0
  324. package/pennyfarthing-dist/scripts/{utils/jira → jira}/jira-sync.mjs +4 -4
  325. package/pennyfarthing-dist/scripts/{utils → jira}/jira-sync.sh +0 -0
  326. package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +104 -0
  327. package/pennyfarthing-dist/scripts/{utils → jira}/sync-epic-to-jira.sh +1 -1
  328. package/pennyfarthing-dist/scripts/lib/README.md +29 -0
  329. package/pennyfarthing-dist/scripts/{utils → lib}/background-tasks.sh +1 -1
  330. package/pennyfarthing-dist/scripts/{utils → lib}/checkpoint.sh +0 -0
  331. package/pennyfarthing-dist/scripts/{utils → lib}/common.sh +1 -1
  332. package/pennyfarthing-dist/scripts/{utils → lib}/file-lock.sh +0 -0
  333. package/pennyfarthing-dist/scripts/{utils → lib}/find-root.sh +7 -5
  334. package/pennyfarthing-dist/scripts/{utils → lib}/logging.sh +0 -0
  335. package/pennyfarthing-dist/scripts/{utils → lib}/retry.sh +0 -0
  336. package/pennyfarthing-dist/scripts/misc/README.md +44 -0
  337. package/pennyfarthing-dist/scripts/{add-short-names.mjs → misc/add-short-names.mjs} +0 -0
  338. package/pennyfarthing-dist/scripts/misc/backlog.sh +91 -0
  339. package/pennyfarthing-dist/scripts/{utils → misc}/check-status.sh +4 -8
  340. package/pennyfarthing-dist/scripts/{deploy.sh → misc/deploy.sh} +0 -0
  341. package/pennyfarthing-dist/scripts/{doctor-dogfood.sh → misc/doctor-dogfood.sh} +2 -5
  342. package/pennyfarthing-dist/scripts/{utils → misc}/find-related-work.sh +0 -0
  343. package/pennyfarthing-dist/scripts/{utils → misc}/generate-skill-docs.sh +0 -0
  344. package/pennyfarthing-dist/scripts/{utils → misc}/log-skill-usage.sh +0 -0
  345. package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.mjs +474 -0
  346. package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +9 -0
  347. package/pennyfarthing-dist/scripts/{utils → misc}/repo-scan.sh +0 -0
  348. package/pennyfarthing-dist/scripts/{repo-utils.sh → misc/repo-utils.sh} +2 -2
  349. package/pennyfarthing-dist/scripts/{run-ci.sh → misc/run-ci.sh} +0 -0
  350. package/pennyfarthing-dist/scripts/{utils → misc}/run-timestamp.sh +0 -0
  351. package/pennyfarthing-dist/scripts/{utils → misc}/session-cleanup.sh +0 -0
  352. package/pennyfarthing-dist/scripts/{utils → misc}/skill-usage-report.sh +0 -0
  353. package/pennyfarthing-dist/scripts/{statusline.sh → misc/statusline.sh} +2 -7
  354. package/pennyfarthing-dist/scripts/{uninstall.sh → misc/uninstall.sh} +4 -5
  355. package/pennyfarthing-dist/scripts/{utils → misc}/validate-subagent-frontmatter.sh +3 -3
  356. package/pennyfarthing-dist/scripts/sprint/README.md +29 -0
  357. package/pennyfarthing-dist/scripts/sprint/archive-story.sh +135 -0
  358. package/pennyfarthing-dist/scripts/sprint/available-stories.sh +97 -0
  359. package/pennyfarthing-dist/scripts/sprint/check-story.sh +164 -0
  360. package/pennyfarthing-dist/scripts/sprint/get-epic-field.sh +58 -0
  361. package/pennyfarthing-dist/scripts/sprint/get-story-field.sh +69 -0
  362. package/pennyfarthing-dist/scripts/sprint/list-future.sh +151 -0
  363. package/pennyfarthing-dist/scripts/sprint/new-sprint.sh +116 -0
  364. package/pennyfarthing-dist/scripts/sprint/promote-epic.sh +164 -0
  365. package/pennyfarthing-dist/scripts/{utils → sprint}/sprint-common.sh +135 -0
  366. package/pennyfarthing-dist/scripts/sprint/sprint-info.sh +39 -0
  367. package/pennyfarthing-dist/scripts/{utils → sprint}/sprint-metrics.sh +0 -0
  368. package/pennyfarthing-dist/scripts/sprint/sprint-status.sh +134 -0
  369. package/pennyfarthing-dist/scripts/story/README.md +23 -0
  370. package/pennyfarthing-dist/scripts/story/create-story.sh +159 -0
  371. package/pennyfarthing-dist/scripts/story/size-story.sh +198 -0
  372. package/pennyfarthing-dist/scripts/story/story-template.sh +162 -0
  373. package/pennyfarthing-dist/scripts/test/README.md +23 -0
  374. package/pennyfarthing-dist/scripts/{utils → test}/swebench-judge.py +0 -0
  375. package/pennyfarthing-dist/scripts/test/test-cache.sh +165 -0
  376. package/pennyfarthing-dist/scripts/{utils → test}/test-setup.sh +5 -5
  377. package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
  378. package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +515 -0
  379. package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +599 -0
  380. package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +332 -0
  381. package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +573 -0
  382. package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +859 -0
  383. package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +662 -0
  384. package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +589 -0
  385. package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +7 -9
  386. package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +18 -18
  387. package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +10 -10
  388. package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +1 -1
  389. package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
  390. package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +647 -0
  391. package/pennyfarthing-dist/scripts/theme/README.md +22 -0
  392. package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.sh +203 -0
  393. package/pennyfarthing-dist/scripts/theme/list-themes.sh +73 -0
  394. package/pennyfarthing-dist/scripts/theme/update-theme-tiers.sh +97 -0
  395. package/pennyfarthing-dist/scripts/workflow/README.md +28 -0
  396. package/pennyfarthing-dist/scripts/{check.sh → workflow/check.sh} +0 -0
  397. package/pennyfarthing-dist/scripts/workflow/finish-story.sh +159 -0
  398. package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +228 -0
  399. package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +91 -0
  400. package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +163 -0
  401. package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +138 -0
  402. package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +256 -0
  403. package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +167 -0
  404. package/pennyfarthing-dist/skills/agentic-patterns/SKILL.md +6 -0
  405. package/pennyfarthing-dist/skills/changelog/SKILL.md +2 -2
  406. package/pennyfarthing-dist/skills/code-review/SKILL.md +3 -3
  407. package/pennyfarthing-dist/skills/context-engineering/SKILL.md +6 -0
  408. package/pennyfarthing-dist/skills/cyclist/SKILL.md +56 -139
  409. package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +21 -5
  410. package/pennyfarthing-dist/skills/finalize-run/SKILL.md +1 -1
  411. package/pennyfarthing-dist/skills/jira/SKILL.md +381 -178
  412. package/pennyfarthing-dist/skills/judge/SKILL.md +76 -21
  413. package/pennyfarthing-dist/skills/just/SKILL.md +345 -102
  414. package/pennyfarthing-dist/skills/otel/skill.md +1 -0
  415. package/pennyfarthing-dist/skills/permissions/skill.md +1 -1
  416. package/pennyfarthing-dist/skills/persona-benchmark/SKILL.md +5 -0
  417. package/pennyfarthing-dist/skills/skill-registry.schema.json +5 -0
  418. package/pennyfarthing-dist/skills/skill-registry.yaml +22 -0
  419. package/pennyfarthing-dist/skills/sprint/scripts/archive-story.sh +101 -0
  420. package/pennyfarthing-dist/skills/sprint/scripts/available-stories.sh +97 -0
  421. package/pennyfarthing-dist/skills/sprint/scripts/check-story.sh +164 -0
  422. package/pennyfarthing-dist/skills/sprint/scripts/create-jira-epic.sh +101 -0
  423. package/pennyfarthing-dist/skills/sprint/scripts/new-sprint.sh +116 -0
  424. package/pennyfarthing-dist/skills/sprint/scripts/promote-epic.sh +164 -0
  425. package/pennyfarthing-dist/skills/sprint/scripts/sprint-info.sh +39 -0
  426. package/pennyfarthing-dist/skills/sprint/scripts/sprint-status.sh +147 -0
  427. package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +104 -0
  428. package/pennyfarthing-dist/skills/sprint/skill.md +465 -0
  429. package/pennyfarthing-dist/skills/story/scripts/create-story.sh +159 -0
  430. package/pennyfarthing-dist/skills/story/scripts/size-story.sh +198 -0
  431. package/pennyfarthing-dist/skills/story/scripts/story-template.sh +162 -0
  432. package/pennyfarthing-dist/skills/story/skill.md +219 -0
  433. package/pennyfarthing-dist/skills/systematic-debugging/SKILL.md +390 -0
  434. package/pennyfarthing-dist/skills/theme/skill.md +1 -1
  435. package/pennyfarthing-dist/skills/workflow/scripts/list-workflows.sh +91 -0
  436. package/pennyfarthing-dist/skills/workflow/scripts/resume-workflow.sh +163 -0
  437. package/pennyfarthing-dist/skills/workflow/scripts/show-workflow.sh +138 -0
  438. package/pennyfarthing-dist/skills/workflow/scripts/start-workflow.sh +273 -0
  439. package/pennyfarthing-dist/skills/workflow/scripts/workflow-status.sh +167 -0
  440. package/pennyfarthing-dist/skills/workflow/skill.md +337 -0
  441. package/pennyfarthing-dist/templates/settings.local.json.template +1 -1
  442. package/pennyfarthing-dist/workflows/agent-docs.yaml +1 -1
  443. package/pennyfarthing-dist/workflows/architecture/steps/step-01-initialize.md +101 -0
  444. package/pennyfarthing-dist/workflows/architecture/steps/step-01b-continue.md +93 -0
  445. package/pennyfarthing-dist/workflows/architecture/steps/step-02-context.md +115 -0
  446. package/pennyfarthing-dist/workflows/architecture/steps/step-03-patterns.md +133 -0
  447. package/pennyfarthing-dist/workflows/architecture/steps/step-04-components.md +138 -0
  448. package/pennyfarthing-dist/workflows/architecture/steps/step-05-interfaces.md +133 -0
  449. package/pennyfarthing-dist/workflows/architecture/steps/step-06-risks.md +142 -0
  450. package/pennyfarthing-dist/workflows/architecture/steps/step-07-document.md +160 -0
  451. package/pennyfarthing-dist/workflows/architecture/templates/architecture-decision.md +102 -0
  452. package/pennyfarthing-dist/workflows/architecture.yaml +65 -0
  453. package/pennyfarthing-dist/workflows/bdd.yaml +3 -1
  454. package/pennyfarthing-dist/workflows/brainstorming/brain-methods.csv +62 -0
  455. package/pennyfarthing-dist/workflows/brainstorming/checklist.md +44 -0
  456. package/pennyfarthing-dist/workflows/brainstorming/instructions.md +736 -0
  457. package/pennyfarthing-dist/workflows/brainstorming/workflow.yaml +49 -0
  458. package/pennyfarthing-dist/workflows/code-review/checklist.md +23 -0
  459. package/pennyfarthing-dist/workflows/code-review/instructions.md +234 -0
  460. package/pennyfarthing-dist/workflows/code-review/workflow.yaml +51 -0
  461. package/pennyfarthing-dist/workflows/dev-story/checklist.md +80 -0
  462. package/pennyfarthing-dist/workflows/dev-story/instructions.xml +410 -0
  463. package/pennyfarthing-dist/workflows/dev-story/workflow.yaml +50 -0
  464. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-01-validate-prerequisites.md +256 -0
  465. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-02-design-epics.md +233 -0
  466. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-03-create-stories.md +272 -0
  467. package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-04-final-validation.md +145 -0
  468. package/pennyfarthing-dist/workflows/epics-and-stories/templates/epics-template.md +57 -0
  469. package/pennyfarthing-dist/workflows/epics-and-stories/workflow.yaml +27 -0
  470. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-01-document-discovery.md +190 -0
  471. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-02-prd-analysis.md +178 -0
  472. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-03-epic-coverage-validation.md +179 -0
  473. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-04-ux-alignment.md +139 -0
  474. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-05-epic-quality-review.md +252 -0
  475. package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-06-final-assessment.md +133 -0
  476. package/pennyfarthing-dist/workflows/implementation-readiness/templates/readiness-report-template.md +4 -0
  477. package/pennyfarthing-dist/workflows/implementation-readiness/workflow.yaml +40 -0
  478. package/pennyfarthing-dist/workflows/prd/data/domain-complexity.csv +13 -0
  479. package/pennyfarthing-dist/workflows/prd/data/prd-purpose.md +197 -0
  480. package/pennyfarthing-dist/workflows/prd/data/project-types.csv +11 -0
  481. package/pennyfarthing-dist/workflows/prd/steps-c/step-01-init.md +191 -0
  482. package/pennyfarthing-dist/workflows/prd/steps-c/step-01b-continue.md +153 -0
  483. package/pennyfarthing-dist/workflows/prd/steps-c/step-02-discovery.md +224 -0
  484. package/pennyfarthing-dist/workflows/prd/steps-c/step-03-success.md +226 -0
  485. package/pennyfarthing-dist/workflows/prd/steps-c/step-04-journeys.md +213 -0
  486. package/pennyfarthing-dist/workflows/prd/steps-c/step-05-domain.md +207 -0
  487. package/pennyfarthing-dist/workflows/prd/steps-c/step-06-innovation.md +226 -0
  488. package/pennyfarthing-dist/workflows/prd/steps-c/step-07-project-type.md +237 -0
  489. package/pennyfarthing-dist/workflows/prd/steps-c/step-08-scoping.md +228 -0
  490. package/pennyfarthing-dist/workflows/prd/steps-c/step-09-functional.md +231 -0
  491. package/pennyfarthing-dist/workflows/prd/steps-c/step-10-nonfunctional.md +242 -0
  492. package/pennyfarthing-dist/workflows/prd/steps-c/step-11-polish.md +217 -0
  493. package/pennyfarthing-dist/workflows/prd/steps-c/step-12-complete.md +180 -0
  494. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-01-discovery.md +247 -0
  495. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-01b-legacy-conversion.md +208 -0
  496. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-02-review.md +249 -0
  497. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-03-edit.md +253 -0
  498. package/pennyfarthing-dist/workflows/prd/steps-e/step-e-04-complete.md +168 -0
  499. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-01-discovery.md +218 -0
  500. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-02-format-detection.md +191 -0
  501. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-02b-parity-check.md +209 -0
  502. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-03-density-validation.md +174 -0
  503. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-04-brief-coverage-validation.md +214 -0
  504. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-05-measurability-validation.md +228 -0
  505. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-06-traceability-validation.md +217 -0
  506. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-07-implementation-leakage-validation.md +205 -0
  507. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-08-domain-compliance-validation.md +243 -0
  508. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-09-project-type-validation.md +263 -0
  509. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-10-smart-validation.md +209 -0
  510. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-11-holistic-quality-validation.md +264 -0
  511. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-12-completeness-validation.md +242 -0
  512. package/pennyfarthing-dist/workflows/prd/steps-v/step-v-13-report-complete.md +232 -0
  513. package/pennyfarthing-dist/workflows/prd/templates/prd-template.md +10 -0
  514. package/pennyfarthing-dist/workflows/prd/workflow.yaml +42 -0
  515. package/pennyfarthing-dist/workflows/product-brief/steps/step-01-init.md +177 -0
  516. package/pennyfarthing-dist/workflows/product-brief/steps/step-01b-continue.md +161 -0
  517. package/pennyfarthing-dist/workflows/product-brief/steps/step-02-vision.md +199 -0
  518. package/pennyfarthing-dist/workflows/product-brief/steps/step-03-users.md +202 -0
  519. package/pennyfarthing-dist/workflows/product-brief/steps/step-04-metrics.md +205 -0
  520. package/pennyfarthing-dist/workflows/product-brief/steps/step-05-scope.md +219 -0
  521. package/pennyfarthing-dist/workflows/product-brief/steps/step-06-complete.md +194 -0
  522. package/pennyfarthing-dist/workflows/product-brief/templates/product-brief.template.md +10 -0
  523. package/pennyfarthing-dist/workflows/product-brief/workflow.yaml +31 -0
  524. package/pennyfarthing-dist/workflows/project-context/project-context-template.md +21 -0
  525. package/pennyfarthing-dist/workflows/project-context/steps/step-01-discover.md +184 -0
  526. package/pennyfarthing-dist/workflows/project-context/steps/step-02-generate.md +318 -0
  527. package/pennyfarthing-dist/workflows/project-context/steps/step-03-complete.md +278 -0
  528. package/pennyfarthing-dist/workflows/project-context/workflow.yaml +27 -0
  529. package/pennyfarthing-dist/workflows/quick-dev/steps/step-01-mode-detection.md +156 -0
  530. package/pennyfarthing-dist/workflows/quick-dev/steps/step-02-context-gathering.md +120 -0
  531. package/pennyfarthing-dist/workflows/quick-dev/steps/step-03-execute.md +113 -0
  532. package/pennyfarthing-dist/workflows/quick-dev/steps/step-04-self-check.md +113 -0
  533. package/pennyfarthing-dist/workflows/quick-dev/steps/step-05-adversarial-review.md +106 -0
  534. package/pennyfarthing-dist/workflows/quick-dev/steps/step-06-resolve-findings.md +140 -0
  535. package/pennyfarthing-dist/workflows/quick-dev/workflow.yaml +27 -0
  536. package/pennyfarthing-dist/workflows/quick-spec/steps/step-01-understand.md +189 -0
  537. package/pennyfarthing-dist/workflows/quick-spec/steps/step-02-investigate.md +144 -0
  538. package/pennyfarthing-dist/workflows/quick-spec/steps/step-03-generate.md +128 -0
  539. package/pennyfarthing-dist/workflows/quick-spec/steps/step-04-review.md +191 -0
  540. package/pennyfarthing-dist/workflows/quick-spec/tech-spec-template.md +74 -0
  541. package/pennyfarthing-dist/workflows/quick-spec/workflow.yaml +27 -0
  542. package/pennyfarthing-dist/workflows/research/steps-domain/step-01-init.md +137 -0
  543. package/pennyfarthing-dist/workflows/research/steps-domain/step-02-domain-analysis.md +229 -0
  544. package/pennyfarthing-dist/workflows/research/steps-domain/step-03-competitive-landscape.md +238 -0
  545. package/pennyfarthing-dist/workflows/research/steps-domain/step-04-regulatory-focus.md +206 -0
  546. package/pennyfarthing-dist/workflows/research/steps-domain/step-05-technical-trends.md +234 -0
  547. package/pennyfarthing-dist/workflows/research/steps-domain/step-06-research-synthesis.md +443 -0
  548. package/pennyfarthing-dist/workflows/research/steps-market/step-01-init.md +182 -0
  549. package/pennyfarthing-dist/workflows/research/steps-market/step-02-customer-behavior.md +237 -0
  550. package/pennyfarthing-dist/workflows/research/steps-market/step-02-customer-insights.md +200 -0
  551. package/pennyfarthing-dist/workflows/research/steps-market/step-03-customer-pain-points.md +249 -0
  552. package/pennyfarthing-dist/workflows/research/steps-market/step-04-customer-decisions.md +259 -0
  553. package/pennyfarthing-dist/workflows/research/steps-market/step-05-competitive-analysis.md +177 -0
  554. package/pennyfarthing-dist/workflows/research/steps-market/step-06-research-completion.md +475 -0
  555. package/pennyfarthing-dist/workflows/research/steps-technical/step-01-init.md +137 -0
  556. package/pennyfarthing-dist/workflows/research/steps-technical/step-02-technical-overview.md +239 -0
  557. package/pennyfarthing-dist/workflows/research/steps-technical/step-03-integration-patterns.md +248 -0
  558. package/pennyfarthing-dist/workflows/research/steps-technical/step-04-architectural-patterns.md +202 -0
  559. package/pennyfarthing-dist/workflows/research/steps-technical/step-05-implementation-research.md +239 -0
  560. package/pennyfarthing-dist/workflows/research/steps-technical/step-06-research-synthesis.md +486 -0
  561. package/pennyfarthing-dist/workflows/research/templates/research.template.md +29 -0
  562. package/pennyfarthing-dist/workflows/research/workflow.yaml +45 -0
  563. package/pennyfarthing-dist/workflows/retrospective/checklist.md +31 -0
  564. package/pennyfarthing-dist/workflows/retrospective/instructions.md +1443 -0
  565. package/pennyfarthing-dist/workflows/retrospective/workflow.yaml +50 -0
  566. package/pennyfarthing-dist/workflows/sprint-planning/checklist.md +33 -0
  567. package/pennyfarthing-dist/workflows/sprint-planning/sprint-status-template.yaml +55 -0
  568. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-01-parse-epic-files.md +54 -0
  569. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-02-build-sprint-status.md +44 -0
  570. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-03-status-detection.md +64 -0
  571. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-04-generate-status-file.md +73 -0
  572. package/pennyfarthing-dist/workflows/sprint-planning/steps/step-05-validate-and-report.md +56 -0
  573. package/pennyfarthing-dist/workflows/sprint-planning/workflow.yaml +34 -0
  574. package/pennyfarthing-dist/workflows/trivial.yaml +1 -1
  575. package/pennyfarthing-dist/workflows/ux-design/steps/step-01-init.md +135 -0
  576. package/pennyfarthing-dist/workflows/ux-design/steps/step-01b-continue.md +127 -0
  577. package/pennyfarthing-dist/workflows/ux-design/steps/step-02-discovery.md +190 -0
  578. package/pennyfarthing-dist/workflows/ux-design/steps/step-03-core-experience.md +216 -0
  579. package/pennyfarthing-dist/workflows/ux-design/steps/step-04-emotional-response.md +219 -0
  580. package/pennyfarthing-dist/workflows/ux-design/steps/step-05-inspiration.md +234 -0
  581. package/pennyfarthing-dist/workflows/ux-design/steps/step-06-design-system.md +252 -0
  582. package/pennyfarthing-dist/workflows/ux-design/steps/step-07-defining-experience.md +254 -0
  583. package/pennyfarthing-dist/workflows/ux-design/steps/step-08-visual-foundation.md +224 -0
  584. package/pennyfarthing-dist/workflows/ux-design/steps/step-09-design-directions.md +224 -0
  585. package/pennyfarthing-dist/workflows/ux-design/steps/step-10-user-journeys.md +241 -0
  586. package/pennyfarthing-dist/workflows/ux-design/steps/step-11-component-strategy.md +248 -0
  587. package/pennyfarthing-dist/workflows/ux-design/steps/step-12-ux-patterns.md +237 -0
  588. package/pennyfarthing-dist/workflows/ux-design/steps/step-13-responsive-accessibility.md +264 -0
  589. package/pennyfarthing-dist/workflows/ux-design/steps/step-14-complete.md +228 -0
  590. package/pennyfarthing-dist/workflows/ux-design/ux-design-template.md +13 -0
  591. package/pennyfarthing-dist/workflows/ux-design/workflow.yaml +41 -0
  592. package/packages/core/dist/scripts/generate-all-faces.d.ts +0 -10
  593. package/packages/core/dist/scripts/generate-all-faces.d.ts.map +0 -1
  594. package/packages/core/dist/scripts/generate-all-faces.js +0 -256
  595. package/packages/core/dist/scripts/generate-all-faces.js.map +0 -1
  596. package/packages/core/dist/scripts/generate-all-faces.test.d.ts +0 -17
  597. package/packages/core/dist/scripts/generate-all-faces.test.d.ts.map +0 -1
  598. package/packages/core/dist/scripts/generate-all-faces.test.js +0 -372
  599. package/packages/core/dist/scripts/generate-all-faces.test.js.map +0 -1
  600. package/packages/core/dist/scripts/generate-ascii-face.d.ts +0 -52
  601. package/packages/core/dist/scripts/generate-ascii-face.d.ts.map +0 -1
  602. package/packages/core/dist/scripts/generate-ascii-face.js +0 -155
  603. package/packages/core/dist/scripts/generate-ascii-face.js.map +0 -1
  604. package/packages/core/dist/scripts/generate-face.d.ts +0 -52
  605. package/packages/core/dist/scripts/generate-face.d.ts.map +0 -1
  606. package/packages/core/dist/scripts/generate-face.js +0 -199
  607. package/packages/core/dist/scripts/generate-face.js.map +0 -1
  608. package/packages/core/dist/scripts/generate-face.test.d.ts +0 -13
  609. package/packages/core/dist/scripts/generate-face.test.d.ts.map +0 -1
  610. package/packages/core/dist/scripts/generate-face.test.js +0 -301
  611. package/packages/core/dist/scripts/generate-face.test.js.map +0 -1
  612. package/pennyfarthing-dist/agents/generic-handoff.md +0 -454
  613. package/pennyfarthing-dist/agents/generic-sm-finish.md +0 -261
  614. package/pennyfarthing-dist/agents/generic-sm-setup.md +0 -214
  615. package/pennyfarthing-dist/commands/new-work.md +0 -127
  616. package/pennyfarthing-dist/guides/AGENT-SCOPES.md +0 -201
  617. package/pennyfarthing-dist/guides/persona-system.md +0 -294
  618. package/pennyfarthing-dist/guides/shared-agent-behavior.md +0 -388
  619. package/pennyfarthing-dist/guides/shared-context.md +0 -147
  620. package/pennyfarthing-dist/guides/strategic-agent-behavior.md +0 -348
  621. package/pennyfarthing-dist/guides/tactical-agent-behavior.md +0 -1041
  622. package/pennyfarthing-dist/scripts/prime.sh +0 -161
  623. package/pennyfarthing-dist/scripts/run.sh +0 -65
  624. package/pennyfarthing-dist/skills/sprint-context/SKILL.md +0 -120
  625. package/pennyfarthing-dist/skills/story-management/SKILL.md +0 -208
  626. package/pennyfarthing-dist/skills/workflow/SKILL.md +0 -160
  627. /package/pennyfarthing-dist/commands/{brainstorm.md → brainstorming.md} +0 -0
  628. /package/pennyfarthing-dist/scripts/{utils → test}/ground-truth-judge.py +0 -0
@@ -0,0 +1,503 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * jira-bidirectional-sync.test.mjs - Tests for bidirectional Jira sync
4
+ *
5
+ * Story: MSSCI-11842
6
+ * TDD Phase: RED
7
+ *
8
+ * Run with: node --test pennyfarthing-dist/scripts/utils/jira/jira-bidirectional-sync.test.mjs
9
+ */
10
+
11
+ import { describe, it, beforeEach, afterEach, mock } from 'node:test';
12
+ import assert from 'node:assert';
13
+
14
+ // The module under test (will be created by Dev)
15
+ // import { ... } from './jira-bidirectional-sync.mjs';
16
+
17
+ // For now, import from jira-lib.mjs to test helper functions
18
+ import {
19
+ mapStatusToJira,
20
+ mapJiraToStatus,
21
+ extractJiraKey
22
+ } from './jira-lib.mjs';
23
+
24
+ // =============================================================================
25
+ // Test Fixtures
26
+ // =============================================================================
27
+
28
+ /**
29
+ * Sample YAML story data (as parsed from sprint YAML)
30
+ */
31
+ const sampleYamlStories = [
32
+ {
33
+ id: 'MSSCI-11842',
34
+ title: 'Bidirectional sync script',
35
+ status: 'in_progress',
36
+ points: 4,
37
+ priority: 'P2'
38
+ },
39
+ {
40
+ id: 'MSSCI-11843',
41
+ title: 'Document Jira auto-creation',
42
+ status: 'backlog',
43
+ points: 2,
44
+ priority: 'P2'
45
+ },
46
+ {
47
+ id: 'MSSCI-11844',
48
+ title: 'YAML-only story',
49
+ status: 'backlog',
50
+ points: 3,
51
+ priority: 'P3'
52
+ }
53
+ ];
54
+
55
+ /**
56
+ * Sample Jira story data (as returned from Jira API)
57
+ */
58
+ const sampleJiraStories = [
59
+ {
60
+ key: 'MSSCI-11842',
61
+ fields: {
62
+ summary: 'Bidirectional sync script',
63
+ status: { name: 'In Progress' },
64
+ customfield_10031: 4, // Story points
65
+ priority: { name: 'Medium' }
66
+ }
67
+ },
68
+ {
69
+ key: 'MSSCI-11843',
70
+ fields: {
71
+ summary: 'Document Jira auto-creation',
72
+ status: { name: 'Done' }, // Different from YAML!
73
+ customfield_10031: 2,
74
+ priority: { name: 'Medium' }
75
+ }
76
+ },
77
+ {
78
+ key: 'MSSCI-11850',
79
+ fields: {
80
+ summary: 'Jira-only story',
81
+ status: { name: 'To Do' },
82
+ customfield_10031: 5,
83
+ priority: { name: 'High' }
84
+ }
85
+ }
86
+ ];
87
+
88
+ // =============================================================================
89
+ // AC1: Script syncs status changes both directions
90
+ // =============================================================================
91
+
92
+ describe('AC1: Bidirectional status sync', () => {
93
+
94
+ describe('YAML → Jira direction', () => {
95
+
96
+ it('should detect when YAML status differs from Jira status', async () => {
97
+ // Import the function that will be implemented
98
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
99
+
100
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {
101
+ syncStatus: true
102
+ });
103
+
104
+ // MSSCI-11843: YAML=backlog, Jira=Done
105
+ const story11843 = plan.changes.find(c => c.key === 'MSSCI-11843');
106
+ assert.ok(story11843, 'Should detect status difference for MSSCI-11843');
107
+ assert.strictEqual(story11843.yamlStatus, 'backlog');
108
+ assert.strictEqual(story11843.jiraStatus, 'Done');
109
+ });
110
+
111
+ it('should generate Jira update action when YAML is source of truth', async () => {
112
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
113
+
114
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {
115
+ syncStatus: true,
116
+ direction: 'yaml-to-jira'
117
+ });
118
+
119
+ const story11843 = plan.changes.find(c => c.key === 'MSSCI-11843');
120
+ assert.ok(story11843);
121
+ assert.strictEqual(story11843.action, 'update-jira');
122
+ assert.strictEqual(story11843.targetStatus, 'To Do'); // backlog maps to To Do
123
+ });
124
+
125
+ });
126
+
127
+ describe('Jira → YAML direction', () => {
128
+
129
+ it('should generate YAML update action when Jira is source of truth', async () => {
130
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
131
+
132
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {
133
+ syncStatus: true,
134
+ direction: 'jira-to-yaml'
135
+ });
136
+
137
+ const story11843 = plan.changes.find(c => c.key === 'MSSCI-11843');
138
+ assert.ok(story11843);
139
+ assert.strictEqual(story11843.action, 'update-yaml');
140
+ assert.strictEqual(story11843.targetStatus, 'done'); // Done maps to done
141
+ });
142
+
143
+ it('should correctly map Jira status to YAML status', () => {
144
+ // Test existing helper function
145
+ assert.strictEqual(mapJiraToStatus('To Do'), 'backlog');
146
+ assert.strictEqual(mapJiraToStatus('In Progress'), 'in-progress');
147
+ assert.strictEqual(mapJiraToStatus('Done'), 'done');
148
+ assert.strictEqual(mapJiraToStatus('In Review'), 'review');
149
+ });
150
+
151
+ });
152
+
153
+ describe('Bidirectional conflict detection', () => {
154
+
155
+ it('should detect conflicts when both systems changed', async () => {
156
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
157
+
158
+ // Simulate scenario where timestamps indicate both changed
159
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {
160
+ syncStatus: true,
161
+ direction: 'bidirectional',
162
+ lastSyncTime: new Date('2026-01-17T00:00:00Z')
163
+ });
164
+
165
+ const conflicts = plan.conflicts || [];
166
+ // Should identify potential conflicts for manual resolution
167
+ assert.ok(Array.isArray(conflicts));
168
+ });
169
+
170
+ it('should use Jira as default winner on conflict', async () => {
171
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
172
+
173
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {
174
+ syncStatus: true,
175
+ direction: 'bidirectional'
176
+ // No yamlWins flag, so Jira should win
177
+ });
178
+
179
+ // Default: Jira wins conflicts
180
+ const story11843 = plan.changes.find(c => c.key === 'MSSCI-11843');
181
+ if (story11843) {
182
+ assert.strictEqual(story11843.action, 'update-yaml');
183
+ }
184
+ });
185
+
186
+ it('should use YAML as winner when --yaml-wins flag is set', async () => {
187
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
188
+
189
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {
190
+ syncStatus: true,
191
+ direction: 'bidirectional',
192
+ yamlWins: true
193
+ });
194
+
195
+ const story11843 = plan.changes.find(c => c.key === 'MSSCI-11843');
196
+ if (story11843) {
197
+ assert.strictEqual(story11843.action, 'update-jira');
198
+ }
199
+ });
200
+
201
+ });
202
+
203
+ });
204
+
205
+ // =============================================================================
206
+ // AC2: Points updated in Jira match sprint YAML
207
+ // =============================================================================
208
+
209
+ describe('AC2: Story points sync', () => {
210
+
211
+ it('should detect when YAML points differ from Jira points', async () => {
212
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
213
+
214
+ // Create test data with mismatched points
215
+ const yamlWithDifferentPoints = [
216
+ { id: 'MSSCI-11842', status: 'in_progress', points: 5 } // YAML says 5
217
+ ];
218
+ const jiraWithDifferentPoints = [
219
+ { key: 'MSSCI-11842', fields: { status: { name: 'In Progress' }, customfield_10031: 4 } } // Jira says 4
220
+ ];
221
+
222
+ const plan = generateSyncPlan(yamlWithDifferentPoints, jiraWithDifferentPoints, {
223
+ syncPoints: true
224
+ });
225
+
226
+ const pointsChange = plan.changes.find(c => c.key === 'MSSCI-11842' && c.field === 'points');
227
+ assert.ok(pointsChange, 'Should detect points difference');
228
+ assert.strictEqual(pointsChange.yamlPoints, 5);
229
+ assert.strictEqual(pointsChange.jiraPoints, 4);
230
+ });
231
+
232
+ it('should sync points from YAML to Jira', async () => {
233
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
234
+
235
+ const yamlStories = [{ id: 'MSSCI-11842', status: 'backlog', points: 8 }];
236
+ const jiraStories = [{ key: 'MSSCI-11842', fields: { status: { name: 'To Do' }, customfield_10031: 5 } }];
237
+
238
+ const plan = generateSyncPlan(yamlStories, jiraStories, {
239
+ syncPoints: true,
240
+ direction: 'yaml-to-jira'
241
+ });
242
+
243
+ const change = plan.changes.find(c => c.field === 'points');
244
+ assert.ok(change);
245
+ assert.strictEqual(change.action, 'update-jira');
246
+ assert.strictEqual(change.targetPoints, 8);
247
+ });
248
+
249
+ it('should sync points from Jira to YAML', async () => {
250
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
251
+
252
+ const yamlStories = [{ id: 'MSSCI-11842', status: 'backlog', points: 3 }];
253
+ const jiraStories = [{ key: 'MSSCI-11842', fields: { status: { name: 'To Do' }, customfield_10031: 5 } }];
254
+
255
+ const plan = generateSyncPlan(yamlStories, jiraStories, {
256
+ syncPoints: true,
257
+ direction: 'jira-to-yaml'
258
+ });
259
+
260
+ const change = plan.changes.find(c => c.field === 'points');
261
+ assert.ok(change);
262
+ assert.strictEqual(change.action, 'update-yaml');
263
+ assert.strictEqual(change.targetPoints, 5);
264
+ });
265
+
266
+ it('should not generate change when points match', async () => {
267
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
268
+
269
+ const yamlStories = [{ id: 'MSSCI-11842', status: 'backlog', points: 4 }];
270
+ const jiraStories = [{ key: 'MSSCI-11842', fields: { status: { name: 'To Do' }, customfield_10031: 4 } }];
271
+
272
+ const plan = generateSyncPlan(yamlStories, jiraStories, {
273
+ syncPoints: true
274
+ });
275
+
276
+ const pointsChange = plan.changes.find(c => c.key === 'MSSCI-11842' && c.field === 'points');
277
+ assert.ok(!pointsChange, 'Should not generate change when points match');
278
+ });
279
+
280
+ });
281
+
282
+ // =============================================================================
283
+ // AC3: New stories in either system detected
284
+ // =============================================================================
285
+
286
+ describe('AC3: Detect new stories in either system', () => {
287
+
288
+ describe('YAML-only stories', () => {
289
+
290
+ it('should detect stories in YAML but not in Jira', async () => {
291
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
292
+
293
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {});
294
+
295
+ // MSSCI-11844 is in YAML but not in Jira fixtures
296
+ assert.ok(plan.yamlOnly, 'Plan should have yamlOnly array');
297
+ assert.ok(plan.yamlOnly.includes('MSSCI-11844'), 'Should detect MSSCI-11844 as YAML-only');
298
+ });
299
+
300
+ it('should report YAML-only stories for potential Jira creation', async () => {
301
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
302
+
303
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {
304
+ reportMissing: true
305
+ });
306
+
307
+ const yamlOnlyReport = plan.reports?.yamlOnly || [];
308
+ assert.ok(yamlOnlyReport.length > 0, 'Should report YAML-only stories');
309
+ });
310
+
311
+ });
312
+
313
+ describe('Jira-only stories', () => {
314
+
315
+ it('should detect stories in Jira but not in YAML', async () => {
316
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
317
+
318
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {});
319
+
320
+ // MSSCI-11850 is in Jira but not in YAML fixtures
321
+ assert.ok(plan.jiraOnly, 'Plan should have jiraOnly array');
322
+ assert.ok(plan.jiraOnly.includes('MSSCI-11850'), 'Should detect MSSCI-11850 as Jira-only');
323
+ });
324
+
325
+ it('should report Jira-only stories for potential YAML import', async () => {
326
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
327
+
328
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {
329
+ reportMissing: true
330
+ });
331
+
332
+ const jiraOnlyReport = plan.reports?.jiraOnly || [];
333
+ assert.ok(jiraOnlyReport.length > 0, 'Should report Jira-only stories');
334
+ });
335
+
336
+ });
337
+
338
+ describe('Stories in both systems', () => {
339
+
340
+ it('should identify stories present in both systems', async () => {
341
+ const { generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
342
+
343
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {});
344
+
345
+ assert.ok(plan.both, 'Plan should have both array');
346
+ // MSSCI-11842 and MSSCI-11843 are in both
347
+ assert.ok(plan.both.includes('MSSCI-11842'));
348
+ assert.ok(plan.both.includes('MSSCI-11843'));
349
+ });
350
+
351
+ });
352
+
353
+ });
354
+
355
+ // =============================================================================
356
+ // AC4: Dry-run mode shows changes before applying
357
+ // =============================================================================
358
+
359
+ describe('AC4: Dry-run mode', () => {
360
+
361
+ it('should generate plan without executing changes in dry-run mode', async () => {
362
+ const { executeSyncPlan, generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
363
+
364
+ const plan = generateSyncPlan(sampleYamlStories, sampleJiraStories, {
365
+ syncStatus: true,
366
+ syncPoints: true
367
+ });
368
+
369
+ // Execute with dry-run
370
+ const result = await executeSyncPlan(plan, { dryRun: true });
371
+
372
+ assert.ok(result.dryRun, 'Result should indicate dry-run mode');
373
+ assert.ok(result.wouldApply, 'Result should list what would be applied');
374
+ assert.strictEqual(result.applied, 0, 'Should not apply any changes');
375
+ });
376
+
377
+ it('should display planned changes in human-readable format', async () => {
378
+ const { formatSyncPlan } = await import('./jira-bidirectional-sync.mjs');
379
+
380
+ const plan = {
381
+ changes: [
382
+ { key: 'MSSCI-11843', field: 'status', action: 'update-yaml', targetStatus: 'done' }
383
+ ],
384
+ yamlOnly: ['MSSCI-11844'],
385
+ jiraOnly: ['MSSCI-11850'],
386
+ both: ['MSSCI-11842', 'MSSCI-11843']
387
+ };
388
+
389
+ const output = formatSyncPlan(plan);
390
+
391
+ assert.ok(typeof output === 'string', 'Should return string output');
392
+ assert.ok(output.includes('MSSCI-11843'), 'Should include story keys');
393
+ assert.ok(output.includes('status'), 'Should include field names');
394
+ });
395
+
396
+ it('should not modify YAML file in dry-run mode', async () => {
397
+ const { executeSyncPlan, generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
398
+
399
+ // This test verifies no file writes happen
400
+ const plan = generateSyncPlan(
401
+ [{ id: 'MSSCI-11842', status: 'backlog', points: 4 }],
402
+ [{ key: 'MSSCI-11842', fields: { status: { name: 'Done' }, customfield_10031: 4 } }],
403
+ { syncStatus: true, direction: 'jira-to-yaml' }
404
+ );
405
+
406
+ const result = await executeSyncPlan(plan, { dryRun: true });
407
+
408
+ assert.ok(result.dryRun);
409
+ assert.strictEqual(result.yamlModified, false, 'YAML should not be modified');
410
+ });
411
+
412
+ it('should not call Jira API in dry-run mode', async () => {
413
+ const { executeSyncPlan, generateSyncPlan } = await import('./jira-bidirectional-sync.mjs');
414
+
415
+ const plan = generateSyncPlan(
416
+ [{ id: 'MSSCI-11842', status: 'done', points: 4 }],
417
+ [{ key: 'MSSCI-11842', fields: { status: { name: 'To Do' }, customfield_10031: 4 } }],
418
+ { syncStatus: true, direction: 'yaml-to-jira' }
419
+ );
420
+
421
+ const result = await executeSyncPlan(plan, { dryRun: true });
422
+
423
+ assert.ok(result.dryRun);
424
+ assert.strictEqual(result.jiraApiCalls, 0, 'Should not make Jira API calls');
425
+ });
426
+
427
+ });
428
+
429
+ // =============================================================================
430
+ // Integration: CLI argument parsing
431
+ // =============================================================================
432
+
433
+ describe('CLI argument parsing', () => {
434
+
435
+ it('should parse --dry-run flag', async () => {
436
+ const { parseCliArgs } = await import('./jira-bidirectional-sync.mjs');
437
+
438
+ const args = parseCliArgs(['--dry-run']);
439
+ assert.strictEqual(args.dryRun, true);
440
+ });
441
+
442
+ it('should parse --yaml-wins flag', async () => {
443
+ const { parseCliArgs } = await import('./jira-bidirectional-sync.mjs');
444
+
445
+ const args = parseCliArgs(['--yaml-wins']);
446
+ assert.strictEqual(args.yamlWins, true);
447
+ });
448
+
449
+ it('should parse --status and --points flags', async () => {
450
+ const { parseCliArgs } = await import('./jira-bidirectional-sync.mjs');
451
+
452
+ const args = parseCliArgs(['--status', '--points']);
453
+ assert.strictEqual(args.syncStatus, true);
454
+ assert.strictEqual(args.syncPoints, true);
455
+ });
456
+
457
+ it('should parse --all flag as status + points', async () => {
458
+ const { parseCliArgs } = await import('./jira-bidirectional-sync.mjs');
459
+
460
+ const args = parseCliArgs(['--all']);
461
+ assert.strictEqual(args.syncStatus, true);
462
+ assert.strictEqual(args.syncPoints, true);
463
+ });
464
+
465
+ it('should parse --sprint <id> option', async () => {
466
+ const { parseCliArgs } = await import('./jira-bidirectional-sync.mjs');
467
+
468
+ const args = parseCliArgs(['--sprint', '275']);
469
+ assert.strictEqual(args.sprintId, '275');
470
+ });
471
+
472
+ });
473
+
474
+ // =============================================================================
475
+ // Helper function tests (using existing jira-lib.mjs)
476
+ // =============================================================================
477
+
478
+ describe('Helper functions from jira-lib.mjs', () => {
479
+
480
+ it('mapStatusToJira converts Pennyfarthing status to Jira', () => {
481
+ assert.strictEqual(mapStatusToJira('backlog'), 'To Do');
482
+ assert.strictEqual(mapStatusToJira('in_progress'), 'In Progress');
483
+ assert.strictEqual(mapStatusToJira('in-progress'), 'In Progress');
484
+ assert.strictEqual(mapStatusToJira('done'), 'Done');
485
+ assert.strictEqual(mapStatusToJira('review'), 'In Review');
486
+ });
487
+
488
+ it('mapJiraToStatus converts Jira status to Pennyfarthing', () => {
489
+ assert.strictEqual(mapJiraToStatus('To Do'), 'backlog');
490
+ assert.strictEqual(mapJiraToStatus('In Progress'), 'in-progress');
491
+ assert.strictEqual(mapJiraToStatus('Done'), 'done');
492
+ assert.strictEqual(mapJiraToStatus('In Review'), 'review');
493
+ });
494
+
495
+ it('extractJiraKey extracts key from URL or returns as-is', () => {
496
+ assert.strictEqual(extractJiraKey('MSSCI-11842'), 'MSSCI-11842');
497
+ assert.strictEqual(
498
+ extractJiraKey('https://1898andco.atlassian.net/browse/MSSCI-11842'),
499
+ 'MSSCI-11842'
500
+ );
501
+ });
502
+
503
+ });
@@ -23,7 +23,9 @@ set -e
23
23
 
24
24
  # Source common functions
25
25
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
26
- source "${SCRIPT_DIR}/sprint-common.sh"
26
+ PARENT_DIR="$(dirname "$SCRIPT_DIR")"
27
+ source "${PARENT_DIR}/lib/common.sh"
28
+ source "${PARENT_DIR}/sprint/sprint-common.sh"
27
29
  source "${SCRIPT_DIR}/jira-lib.sh"
28
30
 
29
31
  # Check dependencies (using jira-lib's robust check)
@@ -103,11 +105,11 @@ if [ "$ISSUE_JSON" = "{}" ]; then
103
105
  exit 3
104
106
  fi
105
107
 
106
- # Parse assignee
107
- ASSIGNEE=$(echo "$ISSUE_JSON" | jq -r '.fields.assignee.displayName // "Unassigned"')
108
- ASSIGNEE_EMAIL=$(echo "$ISSUE_JSON" | jq -r '.fields.assignee.emailAddress // ""')
109
- STATUS=$(echo "$ISSUE_JSON" | jq -r '.fields.status.name // "Unknown"')
110
- SUMMARY=$(echo "$ISSUE_JSON" | jq -r '.fields.summary // "No summary"')
108
+ # Parse assignee (use printf to avoid zsh echo interpreting \n in JSON)
109
+ ASSIGNEE=$(printf '%s' "$ISSUE_JSON" | jq -r '.fields.assignee.displayName // "Unassigned"')
110
+ ASSIGNEE_EMAIL=$(printf '%s' "$ISSUE_JSON" | jq -r '.fields.assignee.emailAddress // ""')
111
+ STATUS=$(printf '%s' "$ISSUE_JSON" | jq -r '.fields.status.name // "Unknown"')
112
+ SUMMARY=$(printf '%s' "$ISSUE_JSON" | jq -r '.fields.summary // "No summary"')
111
113
 
112
114
  echo ""
113
115
  echo "📋 Issue: ${JIRA_ISSUE_KEY}"
@@ -170,9 +170,9 @@ export function getJiraField(issueJson, fieldPath, defaultValue = null) {
170
170
  }
171
171
 
172
172
  /**
173
- * Status mapping: Conductor -> Jira
173
+ * Status mapping: Pennyfarthing -> Jira
174
174
  */
175
- export function mapStatusToJira(conductorStatus) {
175
+ export function mapStatusToJira(PennyfarthingStatus) {
176
176
  const mapping = {
177
177
  'backlog': 'To Do',
178
178
  'todo': 'To Do',
@@ -188,11 +188,11 @@ export function mapStatusToJira(conductorStatus) {
188
188
  'blocked': 'Blocked'
189
189
  };
190
190
 
191
- return mapping[conductorStatus?.toLowerCase()] || 'To Do';
191
+ return mapping[PennyfarthingStatus?.toLowerCase()] || 'To Do';
192
192
  }
193
193
 
194
194
  /**
195
- * Status mapping: Jira -> Conductor
195
+ * Status mapping: Jira -> Pennyfarthing
196
196
  */
197
197
  export function mapJiraToStatus(jiraStatus) {
198
198
  const mapping = {
@@ -328,23 +328,23 @@ export function getStoryPoints(issueKey, issueJson = null) {
328
328
  /**
329
329
  * Sync story points via REST API (jira CLI doesn't handle custom fields well)
330
330
  */
331
- export async function syncStoryPoints(issueKey, conductorPoints, options = {}) {
331
+ export async function syncStoryPoints(issueKey, PennyfarthingPoints, options = {}) {
332
332
  const { dryRun = false, currentJiraPoints = null } = options;
333
333
 
334
- if (!conductorPoints || conductorPoints === 'null') {
335
- return { success: false, reason: 'No points in Conductor' };
334
+ if (!PennyfarthingPoints || PennyfarthingPoints === 'null') {
335
+ return { success: false, reason: 'No points in Pennyfarthing' };
336
336
  }
337
337
 
338
338
  // Compare current points
339
339
  const jiraPoints = currentJiraPoints ?? getStoryPoints(issueKey);
340
340
  const jiraPointsInt = jiraPoints ? Math.floor(Number(jiraPoints)) : null;
341
341
 
342
- if (jiraPointsInt === Number(conductorPoints)) {
342
+ if (jiraPointsInt === Number(PennyfarthingPoints)) {
343
343
  return { success: true, alreadySynced: true };
344
344
  }
345
345
 
346
346
  if (dryRun) {
347
- warn(`[DRY-RUN] Would sync points for ${issueKey}: ${jiraPoints} -> ${conductorPoints}`);
347
+ warn(`[DRY-RUN] Would sync points for ${issueKey}: ${jiraPoints} -> ${PennyfarthingPoints}`);
348
348
  return { success: true, dryRun: true };
349
349
  }
350
350
 
@@ -361,7 +361,7 @@ export async function syncStoryPoints(issueKey, conductorPoints, options = {}) {
361
361
  },
362
362
  body: JSON.stringify({
363
363
  fields: {
364
- customfield_10031: Number(conductorPoints)
364
+ customfield_10031: Number(PennyfarthingPoints)
365
365
  }
366
366
  })
367
367
  });
@@ -5,7 +5,8 @@
5
5
 
6
6
  # Source common utilities (for dry_run_check, escape_for_jql, get_issue_json, etc.)
7
7
  _JIRA_LIB_DIR="$(cd "$(dirname "${0:-$BASH_SOURCE[0]}")" && pwd)"
8
- source "${_JIRA_LIB_DIR}/common.sh"
8
+ _SCRIPTS_DIR="$(dirname "$_JIRA_LIB_DIR")"
9
+ source "${_SCRIPTS_DIR}/lib/common.sh"
9
10
 
10
11
  #############################################
11
12
  # Dependency Checks
@@ -287,21 +288,21 @@ get_story_points() {
287
288
  echo "$points"
288
289
  }
289
290
 
290
- # Sync story points from Conductor to Jira
291
- # Usage: sync_story_points <issue_key> <conductor_points> [jira_points]
291
+ # Sync story points from Pennyfarthing to Jira
292
+ # Usage: sync_story_points <issue_key> <Pennyfarthing_points> [jira_points]
292
293
  # Returns: 0 if synced, 1 if already correct, 2 if failed
293
294
  sync_story_points() {
294
295
  local key="$1"
295
- local conductor_points="$2"
296
+ local Pennyfarthing_points="$2"
296
297
  local jira_points="${3:-}"
297
298
 
298
- if dry_run_check "sync story points for $key: ${conductor_points}"; then
299
+ if dry_run_check "sync story points for $key: ${Pennyfarthing_points}"; then
299
300
  return 0
300
301
  fi
301
302
 
302
- # Skip if no points defined in Conductor
303
- if [ -z "$conductor_points" ] || [ "$conductor_points" = "null" ]; then
304
- warn " ⚠️ No story points defined in Conductor"
303
+ # Skip if no points defined in Pennyfarthing
304
+ if [ -z "$Pennyfarthing_points" ] || [ "$Pennyfarthing_points" = "null" ]; then
305
+ warn " ⚠️ No story points defined in Pennyfarthing"
305
306
  return 1
306
307
  fi
307
308
 
@@ -312,7 +313,7 @@ sync_story_points() {
312
313
 
313
314
  # Compare as integers (Jira might return float like "5.0")
314
315
  local jira_points_int=$(echo "$jira_points" | cut -d'.' -f1)
315
- if [ "$jira_points_int" = "$conductor_points" ]; then
316
+ if [ "$jira_points_int" = "$Pennyfarthing_points" ]; then
316
317
  return 1 # Already correct
317
318
  fi
318
319
 
@@ -326,7 +327,7 @@ sync_story_points() {
326
327
  http_code=$(curl -s -o /dev/null -w "%{http_code}" -X PUT \
327
328
  -u "${jira_user}:${JIRA_API_TOKEN}" \
328
329
  -H "Content-Type: application/json" \
329
- -d "{\"fields\": {\"customfield_10031\": ${conductor_points}}}" \
330
+ -d "{\"fields\": {\"customfield_10031\": ${Pennyfarthing_points}}}" \
330
331
  "${api_url}" 2>&1)
331
332
 
332
333
  if [ "$http_code" = "204" ] || [ "$http_code" = "200" ]; then
@@ -341,13 +342,13 @@ sync_story_points() {
341
342
  # Status Mapping
342
343
  #############################################
343
344
 
344
- # map_status_to_jira CONDUCTOR_STATUS
345
- # Map Conductor status to Jira status name
345
+ # map_status_to_jira Pennyfarthing_STATUS
346
+ # Map Pennyfarthing status to Jira status name
346
347
  # Returns: Jira status string
347
348
  map_status_to_jira() {
348
- local conductor_status="$1"
349
+ local Pennyfarthing_status="$1"
349
350
 
350
- case "$conductor_status" in
351
+ case "$Pennyfarthing_status" in
351
352
  backlog|todo)
352
353
  echo "To Do"
353
354
  ;;
@@ -371,8 +372,8 @@ map_status_to_jira() {
371
372
  }
372
373
 
373
374
  # map_jira_to_status JIRA_STATUS
374
- # Map Jira status to Conductor status name
375
- # Returns: Conductor status string
375
+ # Map Jira status to Pennyfarthing status name
376
+ # Returns: Pennyfarthing status string
376
377
  map_jira_to_status() {
377
378
  local jira_status="$1"
378
379
 
@@ -412,7 +413,7 @@ get_pr_author() {
412
413
  fi
413
414
 
414
415
  # Extract org/repo/number from URL
415
- # Example: https://github.com/1898andCo/conductor-ui/pull/42
416
+ # Example: https://github.com/1898andCo/Pennyfarthing-ui/pull/42
416
417
  if [[ "$pr_url" =~ github\.com/([^/]+)/([^/]+)/pull/([0-9]+) ]]; then
417
418
  local org="${BASH_REMATCH[1]}"
418
419
  local repo="${BASH_REMATCH[2]}"