@pennyfarthing/core 7.0.2 → 7.4.0

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 (692) hide show
  1. package/{packages/core/dist → dist}/cli/commands/cyclist.d.ts +2 -2
  2. package/{packages/core/dist → dist}/cli/commands/cyclist.d.ts.map +1 -1
  3. package/{packages/core/dist → dist}/cli/commands/cyclist.js +8 -9
  4. package/dist/cli/commands/cyclist.js.map +1 -0
  5. package/{packages/core/dist → dist}/cli/commands/cyclist.test.js +6 -4
  6. package/dist/cli/commands/cyclist.test.js.map +1 -0
  7. package/{packages/core/dist → dist}/cli/commands/update.d.ts.map +1 -1
  8. package/{packages/core/dist → dist}/cli/commands/update.js +9 -136
  9. package/dist/cli/commands/update.js.map +1 -0
  10. package/{packages/core/dist → dist}/cli/cyclist-migration.test.js +4 -3
  11. package/{packages/core/dist → dist}/cli/cyclist-migration.test.js.map +1 -1
  12. package/{packages/core/dist → dist}/cli/utils/constants.d.ts +7 -1
  13. package/dist/cli/utils/constants.d.ts.map +1 -0
  14. package/{packages/core/dist → dist}/cli/utils/constants.js +4 -2
  15. package/{packages/core/dist → dist}/cli/utils/constants.js.map +1 -1
  16. package/{packages/core/dist → dist}/cli/utils/themes.d.ts +1 -4
  17. package/{packages/core/dist → dist}/cli/utils/themes.d.ts.map +1 -1
  18. package/{packages/core/dist → dist}/cli/utils/themes.js +2 -22
  19. package/dist/cli/utils/themes.js.map +1 -0
  20. package/dist/cli/utils/themes.test.d.ts +12 -0
  21. package/{packages/core/dist → dist}/cli/utils/themes.test.js +16 -13
  22. package/dist/cli/utils/themes.test.js.map +1 -0
  23. package/{packages/core/dist → dist}/cli/workspace.test.js +5 -8
  24. package/{packages/core/dist → dist}/cli/workspace.test.js.map +1 -1
  25. package/{packages/core/dist → dist}/index.d.ts +1 -0
  26. package/{packages/core/dist → dist}/index.d.ts.map +1 -1
  27. package/{packages/core/dist → dist}/index.js +10 -0
  28. package/{packages/core/dist → dist}/index.js.map +1 -1
  29. package/dist/jira/jira-epic-creation.d.ts +109 -0
  30. package/dist/jira/jira-epic-creation.d.ts.map +1 -0
  31. package/dist/jira/jira-epic-creation.js +253 -0
  32. package/dist/jira/jira-epic-creation.js.map +1 -0
  33. package/dist/jira/jira-epic-creation.test.d.ts +16 -0
  34. package/dist/jira/jira-epic-creation.test.d.ts.map +1 -0
  35. package/dist/jira/jira-epic-creation.test.js +387 -0
  36. package/dist/jira/jira-epic-creation.test.js.map +1 -0
  37. package/dist/jira/jira-sprint-sync.d.ts +247 -0
  38. package/dist/jira/jira-sprint-sync.d.ts.map +1 -0
  39. package/dist/jira/jira-sprint-sync.js +670 -0
  40. package/dist/jira/jira-sprint-sync.js.map +1 -0
  41. package/dist/jira/jira-sprint-sync.test.d.ts +16 -0
  42. package/dist/jira/jira-sprint-sync.test.d.ts.map +1 -0
  43. package/dist/jira/jira-sprint-sync.test.js +845 -0
  44. package/dist/jira/jira-sprint-sync.test.js.map +1 -0
  45. package/{packages/core/dist → dist}/scripts/generate-spider.d.ts +11 -1
  46. package/{packages/core/dist → dist}/scripts/generate-spider.d.ts.map +1 -1
  47. package/{packages/core/dist → dist}/scripts/generate-spider.js +24 -1
  48. package/dist/scripts/generate-spider.js.map +1 -0
  49. package/{packages/core/dist → dist}/scripts/generate-spider.test.js +6 -4
  50. package/dist/scripts/generate-spider.test.js.map +1 -0
  51. package/dist/workflow/gate-handler.d.ts +94 -0
  52. package/dist/workflow/gate-handler.d.ts.map +1 -0
  53. package/dist/workflow/gate-handler.js +189 -0
  54. package/dist/workflow/gate-handler.js.map +1 -0
  55. package/dist/workflow/gate-handler.test.d.ts +14 -0
  56. package/dist/workflow/gate-handler.test.d.ts.map +1 -0
  57. package/dist/workflow/gate-handler.test.js +543 -0
  58. package/dist/workflow/gate-handler.test.js.map +1 -0
  59. package/{packages/core/dist → dist}/workflow/generic-handoff.d.ts +46 -0
  60. package/{packages/core/dist → dist}/workflow/generic-handoff.d.ts.map +1 -1
  61. package/{packages/core/dist → dist}/workflow/generic-handoff.js +53 -0
  62. package/{packages/core/dist → dist}/workflow/generic-handoff.js.map +1 -1
  63. package/{packages/core/dist → dist}/workflow/generic-handoff.test.js +2 -2
  64. package/{packages/core/dist → dist}/workflow/generic-handoff.test.js.map +1 -1
  65. package/dist/workflow/index.d.ts +16 -0
  66. package/dist/workflow/index.d.ts.map +1 -0
  67. package/dist/workflow/index.js +24 -0
  68. package/dist/workflow/index.js.map +1 -0
  69. package/dist/workflow/session-state.d.ts +92 -0
  70. package/dist/workflow/session-state.d.ts.map +1 -0
  71. package/dist/workflow/session-state.js +198 -0
  72. package/dist/workflow/session-state.js.map +1 -0
  73. package/dist/workflow/session-state.test.d.ts +8 -0
  74. package/dist/workflow/session-state.test.d.ts.map +1 -0
  75. package/dist/workflow/session-state.test.js +551 -0
  76. package/dist/workflow/session-state.test.js.map +1 -0
  77. package/dist/workflow/step-parser.d.ts +45 -0
  78. package/dist/workflow/step-parser.d.ts.map +1 -0
  79. package/dist/workflow/step-parser.js +147 -0
  80. package/dist/workflow/step-parser.js.map +1 -0
  81. package/dist/workflow/step-parser.test.d.ts +14 -0
  82. package/dist/workflow/step-parser.test.d.ts.map +1 -0
  83. package/dist/workflow/step-parser.test.js +470 -0
  84. package/dist/workflow/step-parser.test.js.map +1 -0
  85. package/dist/workflow/trimodal.d.ts +86 -0
  86. package/dist/workflow/trimodal.d.ts.map +1 -0
  87. package/dist/workflow/trimodal.js +118 -0
  88. package/dist/workflow/trimodal.js.map +1 -0
  89. package/dist/workflow/trimodal.test.d.ts +11 -0
  90. package/dist/workflow/trimodal.test.d.ts.map +1 -0
  91. package/dist/workflow/trimodal.test.js +395 -0
  92. package/dist/workflow/trimodal.test.js.map +1 -0
  93. package/dist/workflow/variable-resolver.d.ts +67 -0
  94. package/dist/workflow/variable-resolver.d.ts.map +1 -0
  95. package/dist/workflow/variable-resolver.js +156 -0
  96. package/dist/workflow/variable-resolver.js.map +1 -0
  97. package/dist/workflow/variable-resolver.test.d.ts +14 -0
  98. package/dist/workflow/variable-resolver.test.d.ts.map +1 -0
  99. package/dist/workflow/variable-resolver.test.js +400 -0
  100. package/dist/workflow/variable-resolver.test.js.map +1 -0
  101. package/dist/workflow/workflow-executor.d.ts +163 -0
  102. package/dist/workflow/workflow-executor.d.ts.map +1 -0
  103. package/dist/workflow/workflow-executor.js +197 -0
  104. package/dist/workflow/workflow-executor.js.map +1 -0
  105. package/dist/workflow/workflow-executor.test.d.ts +8 -0
  106. package/dist/workflow/workflow-executor.test.d.ts.map +1 -0
  107. package/dist/workflow/workflow-executor.test.js +444 -0
  108. package/dist/workflow/workflow-executor.test.js.map +1 -0
  109. package/{packages/core/dist → dist}/workflow/workflow-loader.test.js +5 -5
  110. package/dist/workflow/workflow-loader.test.js.map +1 -0
  111. package/{packages/core/dist → dist}/workflow/workflow-migration.test.js +8 -9
  112. package/{packages/core/dist → dist}/workflow/workflow-migration.test.js.map +1 -1
  113. package/dist/workflow/workflow-permissions.d.ts +55 -0
  114. package/dist/workflow/workflow-permissions.d.ts.map +1 -0
  115. package/dist/workflow/workflow-permissions.js +64 -0
  116. package/dist/workflow/workflow-permissions.js.map +1 -0
  117. package/dist/workflow/workflow-permissions.test.d.ts +15 -0
  118. package/dist/workflow/workflow-permissions.test.d.ts.map +1 -0
  119. package/dist/workflow/workflow-permissions.test.js +301 -0
  120. package/dist/workflow/workflow-permissions.test.js.map +1 -0
  121. package/{packages/core/dist → dist}/workflow/workflow-schema.d.ts +61 -2
  122. package/dist/workflow/workflow-schema.d.ts.map +1 -0
  123. package/dist/workflow/workflow-schema.js +454 -0
  124. package/dist/workflow/workflow-schema.js.map +1 -0
  125. package/{packages/core/dist → dist}/workflow/workflow-schema.test.js +6 -6
  126. package/{packages/core/dist → dist}/workflow/workflow-schema.test.js.map +1 -1
  127. package/dist/workflow/workflow-stepped-schema.test.d.ts +18 -0
  128. package/dist/workflow/workflow-stepped-schema.test.d.ts.map +1 -0
  129. package/dist/workflow/workflow-stepped-schema.test.js +608 -0
  130. package/dist/workflow/workflow-stepped-schema.test.js.map +1 -0
  131. package/package.json +38 -32
  132. package/README.md +0 -301
  133. package/packages/core/dist/cli/commands/cyclist.js.map +0 -1
  134. package/packages/core/dist/cli/commands/cyclist.test.js.map +0 -1
  135. package/packages/core/dist/cli/commands/update.js.map +0 -1
  136. package/packages/core/dist/cli/utils/constants.d.ts.map +0 -1
  137. package/packages/core/dist/cli/utils/themes.js.map +0 -1
  138. package/packages/core/dist/cli/utils/themes.test.d.ts +0 -12
  139. package/packages/core/dist/cli/utils/themes.test.js.map +0 -1
  140. package/packages/core/dist/scripts/generate-all-faces.d.ts +0 -10
  141. package/packages/core/dist/scripts/generate-all-faces.d.ts.map +0 -1
  142. package/packages/core/dist/scripts/generate-all-faces.js +0 -256
  143. package/packages/core/dist/scripts/generate-all-faces.js.map +0 -1
  144. package/packages/core/dist/scripts/generate-all-faces.test.d.ts +0 -17
  145. package/packages/core/dist/scripts/generate-all-faces.test.d.ts.map +0 -1
  146. package/packages/core/dist/scripts/generate-all-faces.test.js +0 -372
  147. package/packages/core/dist/scripts/generate-all-faces.test.js.map +0 -1
  148. package/packages/core/dist/scripts/generate-ascii-face.d.ts +0 -52
  149. package/packages/core/dist/scripts/generate-ascii-face.d.ts.map +0 -1
  150. package/packages/core/dist/scripts/generate-ascii-face.js +0 -155
  151. package/packages/core/dist/scripts/generate-ascii-face.js.map +0 -1
  152. package/packages/core/dist/scripts/generate-face.d.ts +0 -52
  153. package/packages/core/dist/scripts/generate-face.d.ts.map +0 -1
  154. package/packages/core/dist/scripts/generate-face.js +0 -199
  155. package/packages/core/dist/scripts/generate-face.js.map +0 -1
  156. package/packages/core/dist/scripts/generate-face.test.d.ts +0 -13
  157. package/packages/core/dist/scripts/generate-face.test.d.ts.map +0 -1
  158. package/packages/core/dist/scripts/generate-face.test.js +0 -301
  159. package/packages/core/dist/scripts/generate-face.test.js.map +0 -1
  160. package/packages/core/dist/scripts/generate-spider.js.map +0 -1
  161. package/packages/core/dist/scripts/generate-spider.test.js.map +0 -1
  162. package/packages/core/dist/workflow/workflow-loader.test.js.map +0 -1
  163. package/packages/core/dist/workflow/workflow-schema.d.ts.map +0 -1
  164. package/packages/core/dist/workflow/workflow-schema.js +0 -230
  165. package/packages/core/dist/workflow/workflow-schema.js.map +0 -1
  166. package/pennyfarthing-dist/agents/README.md +0 -411
  167. package/pennyfarthing-dist/agents/architect.md +0 -185
  168. package/pennyfarthing-dist/agents/dev.md +0 -239
  169. package/pennyfarthing-dist/agents/devops.md +0 -197
  170. package/pennyfarthing-dist/agents/generic-handoff.md +0 -454
  171. package/pennyfarthing-dist/agents/generic-sm-finish.md +0 -261
  172. package/pennyfarthing-dist/agents/generic-sm-setup.md +0 -214
  173. package/pennyfarthing-dist/agents/orchestrator.md +0 -333
  174. package/pennyfarthing-dist/agents/pm.md +0 -164
  175. package/pennyfarthing-dist/agents/reviewer-preflight.md +0 -182
  176. package/pennyfarthing-dist/agents/reviewer.md +0 -335
  177. package/pennyfarthing-dist/agents/sm-file-summary.md +0 -109
  178. package/pennyfarthing-dist/agents/sm-handoff.md +0 -97
  179. package/pennyfarthing-dist/agents/sm.md +0 -509
  180. package/pennyfarthing-dist/agents/tea.md +0 -205
  181. package/pennyfarthing-dist/agents/tech-writer.md +0 -148
  182. package/pennyfarthing-dist/agents/testing-runner.md +0 -423
  183. package/pennyfarthing-dist/agents/ux-designer.md +0 -158
  184. package/pennyfarthing-dist/agents/workflow-status-check.md +0 -332
  185. package/pennyfarthing-dist/commands/architect.md +0 -62
  186. package/pennyfarthing-dist/commands/benchmark-control.md +0 -69
  187. package/pennyfarthing-dist/commands/benchmark.md +0 -467
  188. package/pennyfarthing-dist/commands/brainstorm.md +0 -91
  189. package/pennyfarthing-dist/commands/check.md +0 -156
  190. package/pennyfarthing-dist/commands/chore.md +0 -178
  191. package/pennyfarthing-dist/commands/close-epic.md +0 -136
  192. package/pennyfarthing-dist/commands/continue-session.md +0 -184
  193. package/pennyfarthing-dist/commands/create-branches-from-story.md +0 -374
  194. package/pennyfarthing-dist/commands/create-theme.md +0 -29
  195. package/pennyfarthing-dist/commands/dev.md +0 -60
  196. package/pennyfarthing-dist/commands/devops.md +0 -59
  197. package/pennyfarthing-dist/commands/git-cleanup.md +0 -340
  198. package/pennyfarthing-dist/commands/health-check.md +0 -108
  199. package/pennyfarthing-dist/commands/help.md +0 -264
  200. package/pennyfarthing-dist/commands/job-fair.md +0 -102
  201. package/pennyfarthing-dist/commands/list-themes.md +0 -17
  202. package/pennyfarthing-dist/commands/new-work.md +0 -127
  203. package/pennyfarthing-dist/commands/orchestrator.md +0 -56
  204. package/pennyfarthing-dist/commands/parallel-work.md +0 -71
  205. package/pennyfarthing-dist/commands/party-mode.md +0 -67
  206. package/pennyfarthing-dist/commands/permissions.md +0 -193
  207. package/pennyfarthing-dist/commands/pm.md +0 -60
  208. package/pennyfarthing-dist/commands/prime.md +0 -140
  209. package/pennyfarthing-dist/commands/release.md +0 -58
  210. package/pennyfarthing-dist/commands/repo-status.md +0 -49
  211. package/pennyfarthing-dist/commands/retro.md +0 -200
  212. package/pennyfarthing-dist/commands/reviewer.md +0 -64
  213. package/pennyfarthing-dist/commands/run-ci.md +0 -116
  214. package/pennyfarthing-dist/commands/set-theme.md +0 -52
  215. package/pennyfarthing-dist/commands/show-theme.md +0 -21
  216. package/pennyfarthing-dist/commands/sm.md +0 -70
  217. package/pennyfarthing-dist/commands/solo.md +0 -411
  218. package/pennyfarthing-dist/commands/sprint-planning.md +0 -109
  219. package/pennyfarthing-dist/commands/start-epic.md +0 -156
  220. package/pennyfarthing-dist/commands/sync-epic-to-jira.md +0 -184
  221. package/pennyfarthing-dist/commands/sync-work-with-sprint.md +0 -376
  222. package/pennyfarthing-dist/commands/tea.md +0 -63
  223. package/pennyfarthing-dist/commands/tech-writer.md +0 -53
  224. package/pennyfarthing-dist/commands/theme-maker.md +0 -671
  225. package/pennyfarthing-dist/commands/update-domain-docs.md +0 -83
  226. package/pennyfarthing-dist/commands/ux-designer.md +0 -62
  227. package/pennyfarthing-dist/commands/work.md +0 -111
  228. package/pennyfarthing-dist/guides/AGENT-COORDINATION.md +0 -480
  229. package/pennyfarthing-dist/guides/AGENT-SCOPES.md +0 -201
  230. package/pennyfarthing-dist/guides/HOOKS.md +0 -230
  231. package/pennyfarthing-dist/guides/PROMPT-PATTERNS.md +0 -338
  232. package/pennyfarthing-dist/guides/SESSION-ARTIFACTS.md +0 -193
  233. package/pennyfarthing-dist/guides/agent-template-strategic.md +0 -148
  234. package/pennyfarthing-dist/guides/agent-template-tactical.md +0 -162
  235. package/pennyfarthing-dist/guides/patterns/approval-gates-pattern.md +0 -746
  236. package/pennyfarthing-dist/guides/patterns/fan-out-fan-in-pattern.md +0 -574
  237. package/pennyfarthing-dist/guides/patterns/helper-delegation-pattern.md +0 -488
  238. package/pennyfarthing-dist/guides/patterns/tdd-flow-pattern.md +0 -402
  239. package/pennyfarthing-dist/guides/permission-protocol.md +0 -188
  240. package/pennyfarthing-dist/guides/persona-loading.md +0 -46
  241. package/pennyfarthing-dist/guides/persona-system.md +0 -294
  242. package/pennyfarthing-dist/guides/shared-agent-behavior.md +0 -388
  243. package/pennyfarthing-dist/guides/shared-context.md +0 -147
  244. package/pennyfarthing-dist/guides/strategic-agent-behavior.md +0 -348
  245. package/pennyfarthing-dist/guides/tactical-agent-behavior.md +0 -1041
  246. package/pennyfarthing-dist/guides/workflow-schema.md +0 -195
  247. package/pennyfarthing-dist/guides/worktree-mode.md +0 -113
  248. package/pennyfarthing-dist/output-styles/teaching.md +0 -33
  249. package/pennyfarthing-dist/output-styles/terse.md +0 -20
  250. package/pennyfarthing-dist/output-styles/verbose.md +0 -28
  251. package/pennyfarthing-dist/personas/themes/1984.yaml +0 -312
  252. package/pennyfarthing-dist/personas/themes/a-team.yaml +0 -207
  253. package/pennyfarthing-dist/personas/themes/agatha-christie.yaml +0 -300
  254. package/pennyfarthing-dist/personas/themes/alice-in-wonderland.yaml +0 -330
  255. package/pennyfarthing-dist/personas/themes/all-stars.yaml +0 -332
  256. package/pennyfarthing-dist/personas/themes/ancient-philosophers.yaml +0 -320
  257. package/pennyfarthing-dist/personas/themes/ancient-strategists.yaml +0 -306
  258. package/pennyfarthing-dist/personas/themes/arcane.yaml +0 -288
  259. package/pennyfarthing-dist/personas/themes/arthurian-mythos.yaml +0 -331
  260. package/pennyfarthing-dist/personas/themes/avatar-the-last-airbender.yaml +0 -288
  261. package/pennyfarthing-dist/personas/themes/babylon-5.yaml +0 -288
  262. package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +0 -288
  263. package/pennyfarthing-dist/personas/themes/better-call-saul.yaml +0 -288
  264. package/pennyfarthing-dist/personas/themes/big-lebowski.yaml +0 -300
  265. package/pennyfarthing-dist/personas/themes/black-sails.yaml +0 -300
  266. package/pennyfarthing-dist/personas/themes/blade-runner.yaml +0 -295
  267. package/pennyfarthing-dist/personas/themes/bobiverse.yaml +0 -288
  268. package/pennyfarthing-dist/personas/themes/breaking-bad.yaml +0 -327
  269. package/pennyfarthing-dist/personas/themes/catch-22.yaml +0 -316
  270. package/pennyfarthing-dist/personas/themes/classical-composers.yaml +0 -310
  271. package/pennyfarthing-dist/personas/themes/control.yaml +0 -197
  272. package/pennyfarthing-dist/personas/themes/count-of-monte-cristo.yaml +0 -320
  273. package/pennyfarthing-dist/personas/themes/cowboy-bebop.yaml +0 -323
  274. package/pennyfarthing-dist/personas/themes/deadwood.yaml +0 -300
  275. package/pennyfarthing-dist/personas/themes/dickens.yaml +0 -320
  276. package/pennyfarthing-dist/personas/themes/discworld.yaml +0 -332
  277. package/pennyfarthing-dist/personas/themes/doctor-who.yaml +0 -290
  278. package/pennyfarthing-dist/personas/themes/don-quixote.yaml +0 -320
  279. package/pennyfarthing-dist/personas/themes/dune.yaml +0 -307
  280. package/pennyfarthing-dist/personas/themes/enlightenment-thinkers.yaml +0 -320
  281. package/pennyfarthing-dist/personas/themes/expeditionary-force.yaml +0 -288
  282. package/pennyfarthing-dist/personas/themes/fargo.yaml +0 -330
  283. package/pennyfarthing-dist/personas/themes/film-auteurs.yaml +0 -312
  284. package/pennyfarthing-dist/personas/themes/firefly.yaml +0 -328
  285. package/pennyfarthing-dist/personas/themes/foundation.yaml +0 -290
  286. package/pennyfarthing-dist/personas/themes/futurama.yaml +0 -321
  287. package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +0 -290
  288. package/pennyfarthing-dist/personas/themes/gilligans-island.yaml +0 -243
  289. package/pennyfarthing-dist/personas/themes/gothic-literature.yaml +0 -308
  290. package/pennyfarthing-dist/personas/themes/great-gatsby.yaml +0 -308
  291. package/pennyfarthing-dist/personas/themes/greek-mythology.yaml +0 -330
  292. package/pennyfarthing-dist/personas/themes/hannibal.yaml +0 -300
  293. package/pennyfarthing-dist/personas/themes/harry-potter.yaml +0 -324
  294. package/pennyfarthing-dist/personas/themes/his-dark-materials.yaml +0 -291
  295. package/pennyfarthing-dist/personas/themes/historical-figures.yaml +0 -288
  296. package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +0 -331
  297. package/pennyfarthing-dist/personas/themes/house-md.yaml +0 -321
  298. package/pennyfarthing-dist/personas/themes/imperial-radch.yaml +0 -289
  299. package/pennyfarthing-dist/personas/themes/inspector-morse.yaml +0 -300
  300. package/pennyfarthing-dist/personas/themes/jane-austen.yaml +0 -287
  301. package/pennyfarthing-dist/personas/themes/jazz-legends.yaml +0 -320
  302. package/pennyfarthing-dist/personas/themes/justified.yaml +0 -300
  303. package/pennyfarthing-dist/personas/themes/legion-of-doom.yaml +0 -219
  304. package/pennyfarthing-dist/personas/themes/les-miserables.yaml +0 -299
  305. package/pennyfarthing-dist/personas/themes/lord-of-the-rings.yaml +0 -334
  306. package/pennyfarthing-dist/personas/themes/lovecraft-mythos.yaml +0 -334
  307. package/pennyfarthing-dist/personas/themes/mad-max.yaml +0 -355
  308. package/pennyfarthing-dist/personas/themes/mad-men.yaml +0 -289
  309. package/pennyfarthing-dist/personas/themes/marvel-mcu.yaml +0 -300
  310. package/pennyfarthing-dist/personas/themes/mash.yaml +0 -334
  311. package/pennyfarthing-dist/personas/themes/mass-effect.yaml +0 -289
  312. package/pennyfarthing-dist/personas/themes/military-commanders.yaml +0 -306
  313. package/pennyfarthing-dist/personas/themes/moby-dick.yaml +0 -320
  314. package/pennyfarthing-dist/personas/themes/monty-python.yaml +0 -303
  315. package/pennyfarthing-dist/personas/themes/neuromancer.yaml +0 -300
  316. package/pennyfarthing-dist/personas/themes/norse-mythology.yaml +0 -329
  317. package/pennyfarthing-dist/personas/themes/parks-and-rec.yaml +0 -242
  318. package/pennyfarthing-dist/personas/themes/peaky-blinders.yaml +0 -298
  319. package/pennyfarthing-dist/personas/themes/princess-bride.yaml +0 -220
  320. package/pennyfarthing-dist/personas/themes/renaissance-masters.yaml +0 -320
  321. package/pennyfarthing-dist/personas/themes/rome.yaml +0 -300
  322. package/pennyfarthing-dist/personas/themes/russian-masters.yaml +0 -318
  323. package/pennyfarthing-dist/personas/themes/sandman.yaml +0 -288
  324. package/pennyfarthing-dist/personas/themes/scientific-revolutionaries.yaml +0 -320
  325. package/pennyfarthing-dist/personas/themes/shakespeare.yaml +0 -301
  326. package/pennyfarthing-dist/personas/themes/sherlock-holmes.yaml +0 -289
  327. package/pennyfarthing-dist/personas/themes/snow-crash.yaml +0 -288
  328. package/pennyfarthing-dist/personas/themes/software-pioneers.yaml +0 -300
  329. package/pennyfarthing-dist/personas/themes/star-trek-tng.yaml +0 -230
  330. package/pennyfarthing-dist/personas/themes/star-trek-tos.yaml +0 -210
  331. package/pennyfarthing-dist/personas/themes/star-wars.yaml +0 -303
  332. package/pennyfarthing-dist/personas/themes/succession.yaml +0 -300
  333. package/pennyfarthing-dist/personas/themes/superfriends.yaml +0 -208
  334. package/pennyfarthing-dist/personas/themes/ted-lasso.yaml +0 -236
  335. package/pennyfarthing-dist/personas/themes/the-americans.yaml +0 -300
  336. package/pennyfarthing-dist/personas/themes/the-crown.yaml +0 -300
  337. package/pennyfarthing-dist/personas/themes/the-expanse.yaml +0 -213
  338. package/pennyfarthing-dist/personas/themes/the-good-place.yaml +0 -322
  339. package/pennyfarthing-dist/personas/themes/the-matrix.yaml +0 -353
  340. package/pennyfarthing-dist/personas/themes/the-odyssey.yaml +0 -300
  341. package/pennyfarthing-dist/personas/themes/the-office.yaml +0 -330
  342. package/pennyfarthing-dist/personas/themes/the-simpsons.yaml +0 -308
  343. package/pennyfarthing-dist/personas/themes/the-sopranos.yaml +0 -300
  344. package/pennyfarthing-dist/personas/themes/the-wire.yaml +0 -311
  345. package/pennyfarthing-dist/personas/themes/the-witcher.yaml +0 -300
  346. package/pennyfarthing-dist/personas/themes/twin-peaks.yaml +0 -302
  347. package/pennyfarthing-dist/personas/themes/vorkosigan-saga.yaml +0 -300
  348. package/pennyfarthing-dist/personas/themes/watchmen.yaml +0 -291
  349. package/pennyfarthing-dist/personas/themes/west-wing.yaml +0 -291
  350. package/pennyfarthing-dist/personas/themes/world-explorers.yaml +0 -320
  351. package/pennyfarthing-dist/personas/themes/wwii-leaders.yaml +0 -307
  352. package/pennyfarthing-dist/personas/themes/x-files.yaml +0 -302
  353. package/pennyfarthing-dist/scripts/add-short-names.mjs +0 -264
  354. package/pennyfarthing-dist/scripts/agent-session.sh +0 -367
  355. package/pennyfarthing-dist/scripts/check-context.sh +0 -187
  356. package/pennyfarthing-dist/scripts/check.sh +0 -497
  357. package/pennyfarthing-dist/scripts/deploy.sh +0 -284
  358. package/pennyfarthing-dist/scripts/doctor-dogfood.sh +0 -395
  359. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -61
  360. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -66
  361. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +0 -35
  362. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +0 -166
  363. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +0 -50
  364. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -71
  365. package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -54
  366. package/pennyfarthing-dist/scripts/hooks/session-start.sh +0 -98
  367. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -59
  368. package/pennyfarthing-dist/scripts/install-git-hooks.sh +0 -91
  369. package/pennyfarthing-dist/scripts/prime.sh +0 -161
  370. package/pennyfarthing-dist/scripts/release.sh +0 -198
  371. package/pennyfarthing-dist/scripts/repo-utils.sh +0 -778
  372. package/pennyfarthing-dist/scripts/run-ci.sh +0 -219
  373. package/pennyfarthing-dist/scripts/run.sh +0 -65
  374. package/pennyfarthing-dist/scripts/statusline.sh +0 -264
  375. package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -582
  376. package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -107
  377. package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +0 -597
  378. package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -514
  379. package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -517
  380. package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -331
  381. package/pennyfarthing-dist/scripts/uninstall.sh +0 -271
  382. package/pennyfarthing-dist/scripts/utils/background-tasks.sh +0 -177
  383. package/pennyfarthing-dist/scripts/utils/check-status.sh +0 -251
  384. package/pennyfarthing-dist/scripts/utils/checkpoint.sh +0 -136
  385. package/pennyfarthing-dist/scripts/utils/common.sh +0 -157
  386. package/pennyfarthing-dist/scripts/utils/create-feature-branches.sh +0 -230
  387. package/pennyfarthing-dist/scripts/utils/file-lock.sh +0 -269
  388. package/pennyfarthing-dist/scripts/utils/find-related-work.sh +0 -231
  389. package/pennyfarthing-dist/scripts/utils/find-root.sh +0 -33
  390. package/pennyfarthing-dist/scripts/utils/generate-skill-docs.sh +0 -110
  391. package/pennyfarthing-dist/scripts/utils/git-status-all.sh +0 -127
  392. package/pennyfarthing-dist/scripts/utils/ground-truth-judge.py +0 -289
  393. package/pennyfarthing-dist/scripts/utils/jira/jira-lib.mjs +0 -443
  394. package/pennyfarthing-dist/scripts/utils/jira/jira-sync-story.mjs +0 -208
  395. package/pennyfarthing-dist/scripts/utils/jira/jira-sync.mjs +0 -198
  396. package/pennyfarthing-dist/scripts/utils/jira-claim-story.sh +0 -162
  397. package/pennyfarthing-dist/scripts/utils/jira-lib.sh +0 -463
  398. package/pennyfarthing-dist/scripts/utils/jira-sync-story.sh +0 -8
  399. package/pennyfarthing-dist/scripts/utils/jira-sync.sh +0 -8
  400. package/pennyfarthing-dist/scripts/utils/log-skill-usage.sh +0 -74
  401. package/pennyfarthing-dist/scripts/utils/logging.sh +0 -186
  402. package/pennyfarthing-dist/scripts/utils/repo-scan.sh +0 -141
  403. package/pennyfarthing-dist/scripts/utils/retry.sh +0 -76
  404. package/pennyfarthing-dist/scripts/utils/run-timestamp.sh +0 -7
  405. package/pennyfarthing-dist/scripts/utils/session-cleanup.sh +0 -319
  406. package/pennyfarthing-dist/scripts/utils/skill-usage-report.sh +0 -193
  407. package/pennyfarthing-dist/scripts/utils/sprint-common.sh +0 -286
  408. package/pennyfarthing-dist/scripts/utils/sprint-metrics.sh +0 -241
  409. package/pennyfarthing-dist/scripts/utils/swebench-judge.py +0 -400
  410. package/pennyfarthing-dist/scripts/utils/sync-epic-to-jira.sh +0 -16
  411. package/pennyfarthing-dist/scripts/utils/test-setup.sh +0 -337
  412. package/pennyfarthing-dist/scripts/utils/validate-subagent-frontmatter.sh +0 -160
  413. package/pennyfarthing-dist/scripts/worktree-manager.sh +0 -498
  414. package/pennyfarthing-dist/skills/agentic-patterns/SKILL.md +0 -236
  415. package/pennyfarthing-dist/skills/changelog/SKILL.md +0 -367
  416. package/pennyfarthing-dist/skills/code-review/SKILL.md +0 -168
  417. package/pennyfarthing-dist/skills/context-engineering/SKILL.md +0 -268
  418. package/pennyfarthing-dist/skills/cyclist/SKILL.md +0 -171
  419. package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +0 -421
  420. package/pennyfarthing-dist/skills/finalize-run/SKILL.md +0 -258
  421. package/pennyfarthing-dist/skills/jira/SKILL.md +0 -281
  422. package/pennyfarthing-dist/skills/judge/SKILL.md +0 -524
  423. package/pennyfarthing-dist/skills/just/SKILL.md +0 -160
  424. package/pennyfarthing-dist/skills/mermaid/SKILL.md +0 -240
  425. package/pennyfarthing-dist/skills/otel/skill.md +0 -222
  426. package/pennyfarthing-dist/skills/permissions/skill.md +0 -172
  427. package/pennyfarthing-dist/skills/persona-benchmark/SKILL.md +0 -173
  428. package/pennyfarthing-dist/skills/skill-registry.schema.json +0 -102
  429. package/pennyfarthing-dist/skills/skill-registry.yaml +0 -335
  430. package/pennyfarthing-dist/skills/sprint-context/SKILL.md +0 -120
  431. package/pennyfarthing-dist/skills/story-management/SKILL.md +0 -208
  432. package/pennyfarthing-dist/skills/testing/SKILL.md +0 -99
  433. package/pennyfarthing-dist/skills/testing/references/troubleshooting.md +0 -124
  434. package/pennyfarthing-dist/skills/theme/skill.md +0 -129
  435. package/pennyfarthing-dist/skills/theme-creation/SKILL.md +0 -169
  436. package/pennyfarthing-dist/skills/workflow/SKILL.md +0 -160
  437. package/pennyfarthing-dist/skills/yq/SKILL.md +0 -264
  438. package/pennyfarthing-dist/templates/LEADERBOARD.schema.yaml +0 -187
  439. package/pennyfarthing-dist/templates/LEADERBOARD.template.md +0 -59
  440. package/pennyfarthing-dist/templates/agent-scopes.yaml.template +0 -276
  441. package/pennyfarthing-dist/templates/pennyfarthing-settings.yaml.template +0 -61
  442. package/pennyfarthing-dist/templates/persona-config.yaml.template +0 -22
  443. package/pennyfarthing-dist/templates/preferences.yaml.template +0 -15
  444. package/pennyfarthing-dist/templates/settings.local.json.template +0 -90
  445. package/pennyfarthing-dist/templates/setup-env.sh.template +0 -18
  446. package/pennyfarthing-dist/templates/shared-context.md.template +0 -70
  447. package/pennyfarthing-dist/templates/sidecar/decisions.md.template +0 -40
  448. package/pennyfarthing-dist/templates/sidecar/gotchas.md.template +0 -37
  449. package/pennyfarthing-dist/templates/sidecar/patterns.md.template +0 -34
  450. package/pennyfarthing-dist/workflows/agent-docs.yaml +0 -70
  451. package/pennyfarthing-dist/workflows/bdd.yaml +0 -58
  452. package/pennyfarthing-dist/workflows/tdd.yaml +0 -50
  453. package/pennyfarthing-dist/workflows/trivial.yaml +0 -40
  454. /package/{packages/core/bin → bin}/pennyfarthing.js +0 -0
  455. /package/{packages/core/dist → dist}/bmad/context-reader.d.ts +0 -0
  456. /package/{packages/core/dist → dist}/bmad/context-reader.d.ts.map +0 -0
  457. /package/{packages/core/dist → dist}/bmad/context-reader.js +0 -0
  458. /package/{packages/core/dist → dist}/bmad/context-reader.js.map +0 -0
  459. /package/{packages/core/dist → dist}/bmad/context-reader.test.d.ts +0 -0
  460. /package/{packages/core/dist → dist}/bmad/context-reader.test.d.ts.map +0 -0
  461. /package/{packages/core/dist → dist}/bmad/context-reader.test.js +0 -0
  462. /package/{packages/core/dist → dist}/bmad/context-reader.test.js.map +0 -0
  463. /package/{packages/core/dist → dist}/bmad/epics-parser.d.ts +0 -0
  464. /package/{packages/core/dist → dist}/bmad/epics-parser.d.ts.map +0 -0
  465. /package/{packages/core/dist → dist}/bmad/epics-parser.js +0 -0
  466. /package/{packages/core/dist → dist}/bmad/epics-parser.js.map +0 -0
  467. /package/{packages/core/dist → dist}/bmad/epics-parser.test.d.ts +0 -0
  468. /package/{packages/core/dist → dist}/bmad/epics-parser.test.d.ts.map +0 -0
  469. /package/{packages/core/dist → dist}/bmad/epics-parser.test.js +0 -0
  470. /package/{packages/core/dist → dist}/bmad/epics-parser.test.js.map +0 -0
  471. /package/{packages/core/dist → dist}/bmad/index.d.ts +0 -0
  472. /package/{packages/core/dist → dist}/bmad/index.d.ts.map +0 -0
  473. /package/{packages/core/dist → dist}/bmad/index.js +0 -0
  474. /package/{packages/core/dist → dist}/bmad/index.js.map +0 -0
  475. /package/{packages/core/dist → dist}/bmad/status-sync.d.ts +0 -0
  476. /package/{packages/core/dist → dist}/bmad/status-sync.d.ts.map +0 -0
  477. /package/{packages/core/dist → dist}/bmad/status-sync.js +0 -0
  478. /package/{packages/core/dist → dist}/bmad/status-sync.js.map +0 -0
  479. /package/{packages/core/dist → dist}/bmad/status-sync.test.d.ts +0 -0
  480. /package/{packages/core/dist → dist}/bmad/status-sync.test.d.ts.map +0 -0
  481. /package/{packages/core/dist → dist}/bmad/status-sync.test.js +0 -0
  482. /package/{packages/core/dist → dist}/bmad/status-sync.test.js.map +0 -0
  483. /package/{packages/core/dist → dist}/bmad/story-exporter.d.ts +0 -0
  484. /package/{packages/core/dist → dist}/bmad/story-exporter.d.ts.map +0 -0
  485. /package/{packages/core/dist → dist}/bmad/story-exporter.js +0 -0
  486. /package/{packages/core/dist → dist}/bmad/story-exporter.js.map +0 -0
  487. /package/{packages/core/dist → dist}/bmad/story-exporter.test.d.ts +0 -0
  488. /package/{packages/core/dist → dist}/bmad/story-exporter.test.d.ts.map +0 -0
  489. /package/{packages/core/dist → dist}/bmad/story-exporter.test.js +0 -0
  490. /package/{packages/core/dist → dist}/bmad/story-exporter.test.js.map +0 -0
  491. /package/{packages/core/dist → dist}/bmad/story-parser.d.ts +0 -0
  492. /package/{packages/core/dist → dist}/bmad/story-parser.d.ts.map +0 -0
  493. /package/{packages/core/dist → dist}/bmad/story-parser.js +0 -0
  494. /package/{packages/core/dist → dist}/bmad/story-parser.js.map +0 -0
  495. /package/{packages/core/dist → dist}/bmad/story-parser.test.d.ts +0 -0
  496. /package/{packages/core/dist → dist}/bmad/story-parser.test.d.ts.map +0 -0
  497. /package/{packages/core/dist → dist}/bmad/story-parser.test.js +0 -0
  498. /package/{packages/core/dist → dist}/bmad/story-parser.test.js.map +0 -0
  499. /package/{packages/core/dist → dist}/cli/commands/command.d.ts +0 -0
  500. /package/{packages/core/dist → dist}/cli/commands/command.d.ts.map +0 -0
  501. /package/{packages/core/dist → dist}/cli/commands/command.js +0 -0
  502. /package/{packages/core/dist → dist}/cli/commands/command.js.map +0 -0
  503. /package/{packages/core/dist → dist}/cli/commands/cyclist.test.d.ts +0 -0
  504. /package/{packages/core/dist → dist}/cli/commands/cyclist.test.d.ts.map +0 -0
  505. /package/{packages/core/dist → dist}/cli/commands/doctor.d.ts +0 -0
  506. /package/{packages/core/dist → dist}/cli/commands/doctor.d.ts.map +0 -0
  507. /package/{packages/core/dist → dist}/cli/commands/doctor.js +0 -0
  508. /package/{packages/core/dist → dist}/cli/commands/doctor.js.map +0 -0
  509. /package/{packages/core/dist → dist}/cli/commands/init.d.ts +0 -0
  510. /package/{packages/core/dist → dist}/cli/commands/init.d.ts.map +0 -0
  511. /package/{packages/core/dist → dist}/cli/commands/init.js +0 -0
  512. /package/{packages/core/dist → dist}/cli/commands/init.js.map +0 -0
  513. /package/{packages/core/dist → dist}/cli/commands/skill.d.ts +0 -0
  514. /package/{packages/core/dist → dist}/cli/commands/skill.d.ts.map +0 -0
  515. /package/{packages/core/dist → dist}/cli/commands/skill.js +0 -0
  516. /package/{packages/core/dist → dist}/cli/commands/skill.js.map +0 -0
  517. /package/{packages/core/dist → dist}/cli/commands/theme.d.ts +0 -0
  518. /package/{packages/core/dist → dist}/cli/commands/theme.d.ts.map +0 -0
  519. /package/{packages/core/dist → dist}/cli/commands/theme.js +0 -0
  520. /package/{packages/core/dist → dist}/cli/commands/theme.js.map +0 -0
  521. /package/{packages/core/dist → dist}/cli/commands/uninstall.d.ts +0 -0
  522. /package/{packages/core/dist → dist}/cli/commands/uninstall.d.ts.map +0 -0
  523. /package/{packages/core/dist → dist}/cli/commands/uninstall.js +0 -0
  524. /package/{packages/core/dist → dist}/cli/commands/uninstall.js.map +0 -0
  525. /package/{packages/core/dist → dist}/cli/commands/update.d.ts +0 -0
  526. /package/{packages/core/dist → dist}/cli/commands/version.d.ts +0 -0
  527. /package/{packages/core/dist → dist}/cli/commands/version.d.ts.map +0 -0
  528. /package/{packages/core/dist → dist}/cli/commands/version.js +0 -0
  529. /package/{packages/core/dist → dist}/cli/commands/version.js.map +0 -0
  530. /package/{packages/core/dist → dist}/cli/customization.test.d.ts +0 -0
  531. /package/{packages/core/dist → dist}/cli/customization.test.d.ts.map +0 -0
  532. /package/{packages/core/dist → dist}/cli/customization.test.js +0 -0
  533. /package/{packages/core/dist → dist}/cli/customization.test.js.map +0 -0
  534. /package/{packages/core/dist → dist}/cli/cyclist-migration.test.d.ts +0 -0
  535. /package/{packages/core/dist → dist}/cli/cyclist-migration.test.d.ts.map +0 -0
  536. /package/{packages/core/dist → dist}/cli/index.d.ts +0 -0
  537. /package/{packages/core/dist → dist}/cli/index.d.ts.map +0 -0
  538. /package/{packages/core/dist → dist}/cli/index.js +0 -0
  539. /package/{packages/core/dist → dist}/cli/index.js.map +0 -0
  540. /package/{packages/core/dist → dist}/cli/ocean-profiles.test.d.ts +0 -0
  541. /package/{packages/core/dist → dist}/cli/ocean-profiles.test.d.ts.map +0 -0
  542. /package/{packages/core/dist → dist}/cli/ocean-profiles.test.js +0 -0
  543. /package/{packages/core/dist → dist}/cli/ocean-profiles.test.js.map +0 -0
  544. /package/{packages/core/dist → dist}/cli/theme-maker.test.d.ts +0 -0
  545. /package/{packages/core/dist → dist}/cli/theme-maker.test.d.ts.map +0 -0
  546. /package/{packages/core/dist → dist}/cli/theme-maker.test.js +0 -0
  547. /package/{packages/core/dist → dist}/cli/theme-maker.test.js.map +0 -0
  548. /package/{packages/core/dist → dist}/cli/utils/files.d.ts +0 -0
  549. /package/{packages/core/dist → dist}/cli/utils/files.d.ts.map +0 -0
  550. /package/{packages/core/dist → dist}/cli/utils/files.js +0 -0
  551. /package/{packages/core/dist → dist}/cli/utils/files.js.map +0 -0
  552. /package/{packages/core/dist → dist}/cli/utils/logger.d.ts +0 -0
  553. /package/{packages/core/dist → dist}/cli/utils/logger.d.ts.map +0 -0
  554. /package/{packages/core/dist → dist}/cli/utils/logger.js +0 -0
  555. /package/{packages/core/dist → dist}/cli/utils/logger.js.map +0 -0
  556. /package/{packages/core/dist → dist}/cli/utils/manifest.d.ts +0 -0
  557. /package/{packages/core/dist → dist}/cli/utils/manifest.d.ts.map +0 -0
  558. /package/{packages/core/dist → dist}/cli/utils/manifest.js +0 -0
  559. /package/{packages/core/dist → dist}/cli/utils/manifest.js.map +0 -0
  560. /package/{packages/core/dist → dist}/cli/utils/node-modules.d.ts +0 -0
  561. /package/{packages/core/dist → dist}/cli/utils/node-modules.d.ts.map +0 -0
  562. /package/{packages/core/dist → dist}/cli/utils/node-modules.js +0 -0
  563. /package/{packages/core/dist → dist}/cli/utils/node-modules.js.map +0 -0
  564. /package/{packages/core/dist → dist}/cli/utils/prompts.d.ts +0 -0
  565. /package/{packages/core/dist → dist}/cli/utils/prompts.d.ts.map +0 -0
  566. /package/{packages/core/dist → dist}/cli/utils/prompts.js +0 -0
  567. /package/{packages/core/dist → dist}/cli/utils/prompts.js.map +0 -0
  568. /package/{packages/core/dist → dist}/cli/utils/symlinks.d.ts +0 -0
  569. /package/{packages/core/dist → dist}/cli/utils/symlinks.d.ts.map +0 -0
  570. /package/{packages/core/dist → dist}/cli/utils/symlinks.js +0 -0
  571. /package/{packages/core/dist → dist}/cli/utils/symlinks.js.map +0 -0
  572. /package/{packages/core/dist → dist}/cli/utils/themes.test.d.ts.map +0 -0
  573. /package/{packages/core/dist → dist}/cli/utils/version.d.ts +0 -0
  574. /package/{packages/core/dist → dist}/cli/utils/version.d.ts.map +0 -0
  575. /package/{packages/core/dist → dist}/cli/utils/version.js +0 -0
  576. /package/{packages/core/dist → dist}/cli/utils/version.js.map +0 -0
  577. /package/{packages/core/dist → dist}/cli/workspace.test.d.ts +0 -0
  578. /package/{packages/core/dist → dist}/cli/workspace.test.d.ts.map +0 -0
  579. /package/{packages/core/dist → dist}/permissions/index.d.ts +0 -0
  580. /package/{packages/core/dist → dist}/permissions/index.d.ts.map +0 -0
  581. /package/{packages/core/dist → dist}/permissions/index.js +0 -0
  582. /package/{packages/core/dist → dist}/permissions/index.js.map +0 -0
  583. /package/{packages/core/dist → dist}/permissions/permission-schema.d.ts +0 -0
  584. /package/{packages/core/dist → dist}/permissions/permission-schema.d.ts.map +0 -0
  585. /package/{packages/core/dist → dist}/permissions/permission-schema.js +0 -0
  586. /package/{packages/core/dist → dist}/permissions/permission-schema.js.map +0 -0
  587. /package/{packages/core/dist → dist}/permissions/permission-schema.test.d.ts +0 -0
  588. /package/{packages/core/dist → dist}/permissions/permission-schema.test.d.ts.map +0 -0
  589. /package/{packages/core/dist → dist}/permissions/permission-schema.test.js +0 -0
  590. /package/{packages/core/dist → dist}/permissions/permission-schema.test.js.map +0 -0
  591. /package/{packages/core/dist → dist}/scripts/add-ocean-profiles.d.ts +0 -0
  592. /package/{packages/core/dist → dist}/scripts/add-ocean-profiles.d.ts.map +0 -0
  593. /package/{packages/core/dist → dist}/scripts/add-ocean-profiles.js +0 -0
  594. /package/{packages/core/dist → dist}/scripts/add-ocean-profiles.js.map +0 -0
  595. /package/{packages/core/dist → dist}/scripts/benchmark-integration.d.ts +0 -0
  596. /package/{packages/core/dist → dist}/scripts/benchmark-integration.d.ts.map +0 -0
  597. /package/{packages/core/dist → dist}/scripts/benchmark-integration.js +0 -0
  598. /package/{packages/core/dist → dist}/scripts/benchmark-integration.js.map +0 -0
  599. /package/{packages/core/dist → dist}/scripts/benchmark-integration.test.d.ts +0 -0
  600. /package/{packages/core/dist → dist}/scripts/benchmark-integration.test.d.ts.map +0 -0
  601. /package/{packages/core/dist → dist}/scripts/benchmark-integration.test.js +0 -0
  602. /package/{packages/core/dist → dist}/scripts/benchmark-integration.test.js.map +0 -0
  603. /package/{packages/core/dist → dist}/scripts/debugging-scenarios.test.d.ts +0 -0
  604. /package/{packages/core/dist → dist}/scripts/debugging-scenarios.test.d.ts.map +0 -0
  605. /package/{packages/core/dist → dist}/scripts/debugging-scenarios.test.js +0 -0
  606. /package/{packages/core/dist → dist}/scripts/debugging-scenarios.test.js.map +0 -0
  607. /package/{packages/core/dist → dist}/scripts/generate-all-spiders.d.ts +0 -0
  608. /package/{packages/core/dist → dist}/scripts/generate-all-spiders.d.ts.map +0 -0
  609. /package/{packages/core/dist → dist}/scripts/generate-all-spiders.js +0 -0
  610. /package/{packages/core/dist → dist}/scripts/generate-all-spiders.js.map +0 -0
  611. /package/{packages/core/dist → dist}/scripts/generate-report.d.ts +0 -0
  612. /package/{packages/core/dist → dist}/scripts/generate-report.d.ts.map +0 -0
  613. /package/{packages/core/dist → dist}/scripts/generate-report.js +0 -0
  614. /package/{packages/core/dist → dist}/scripts/generate-report.js.map +0 -0
  615. /package/{packages/core/dist → dist}/scripts/generate-report.test.d.ts +0 -0
  616. /package/{packages/core/dist → dist}/scripts/generate-report.test.d.ts.map +0 -0
  617. /package/{packages/core/dist → dist}/scripts/generate-report.test.js +0 -0
  618. /package/{packages/core/dist → dist}/scripts/generate-report.test.js.map +0 -0
  619. /package/{packages/core/dist → dist}/scripts/generate-spider-report.d.ts +0 -0
  620. /package/{packages/core/dist → dist}/scripts/generate-spider-report.d.ts.map +0 -0
  621. /package/{packages/core/dist → dist}/scripts/generate-spider-report.js +0 -0
  622. /package/{packages/core/dist → dist}/scripts/generate-spider-report.js.map +0 -0
  623. /package/{packages/core/dist → dist}/scripts/generate-spider-report.test.d.ts +0 -0
  624. /package/{packages/core/dist → dist}/scripts/generate-spider-report.test.d.ts.map +0 -0
  625. /package/{packages/core/dist → dist}/scripts/generate-spider-report.test.js +0 -0
  626. /package/{packages/core/dist → dist}/scripts/generate-spider-report.test.js.map +0 -0
  627. /package/{packages/core/dist → dist}/scripts/generate-spider.test.d.ts +0 -0
  628. /package/{packages/core/dist → dist}/scripts/generate-spider.test.d.ts.map +0 -0
  629. /package/{packages/core/dist → dist}/scripts/job-fair-aggregator.d.ts +0 -0
  630. /package/{packages/core/dist → dist}/scripts/job-fair-aggregator.d.ts.map +0 -0
  631. /package/{packages/core/dist → dist}/scripts/job-fair-aggregator.js +0 -0
  632. /package/{packages/core/dist → dist}/scripts/job-fair-aggregator.js.map +0 -0
  633. /package/{packages/core/dist → dist}/scripts/job-fair-aggregator.test.d.ts +0 -0
  634. /package/{packages/core/dist → dist}/scripts/job-fair-aggregator.test.d.ts.map +0 -0
  635. /package/{packages/core/dist → dist}/scripts/job-fair-aggregator.test.js +0 -0
  636. /package/{packages/core/dist → dist}/scripts/job-fair-aggregator.test.js.map +0 -0
  637. /package/{packages/core/dist → dist}/scripts/run-ci.test.d.ts +0 -0
  638. /package/{packages/core/dist → dist}/scripts/run-ci.test.d.ts.map +0 -0
  639. /package/{packages/core/dist → dist}/scripts/run-ci.test.js +0 -0
  640. /package/{packages/core/dist → dist}/scripts/run-ci.test.js.map +0 -0
  641. /package/{packages/core/dist → dist}/scripts/theme-detail.test.d.ts +0 -0
  642. /package/{packages/core/dist → dist}/scripts/theme-detail.test.d.ts.map +0 -0
  643. /package/{packages/core/dist → dist}/scripts/theme-detail.test.js +0 -0
  644. /package/{packages/core/dist → dist}/scripts/theme-detail.test.js.map +0 -0
  645. /package/{packages/core/dist → dist}/scripts/validate-ocean-profiles.d.ts +0 -0
  646. /package/{packages/core/dist → dist}/scripts/validate-ocean-profiles.d.ts.map +0 -0
  647. /package/{packages/core/dist → dist}/scripts/validate-ocean-profiles.js +0 -0
  648. /package/{packages/core/dist → dist}/scripts/validate-ocean-profiles.js.map +0 -0
  649. /package/{packages/core/dist → dist}/workflow/generic-handoff.test.d.ts +0 -0
  650. /package/{packages/core/dist → dist}/workflow/generic-handoff.test.d.ts.map +0 -0
  651. /package/{packages/core/dist → dist}/workflow/generic-sm-finish.d.ts +0 -0
  652. /package/{packages/core/dist → dist}/workflow/generic-sm-finish.d.ts.map +0 -0
  653. /package/{packages/core/dist → dist}/workflow/generic-sm-finish.js +0 -0
  654. /package/{packages/core/dist → dist}/workflow/generic-sm-finish.js.map +0 -0
  655. /package/{packages/core/dist → dist}/workflow/generic-sm-setup.d.ts +0 -0
  656. /package/{packages/core/dist → dist}/workflow/generic-sm-setup.d.ts.map +0 -0
  657. /package/{packages/core/dist → dist}/workflow/generic-sm-setup.js +0 -0
  658. /package/{packages/core/dist → dist}/workflow/generic-sm-setup.js.map +0 -0
  659. /package/{packages/core/dist → dist}/workflow/sm-subagents.test.d.ts +0 -0
  660. /package/{packages/core/dist → dist}/workflow/sm-subagents.test.d.ts.map +0 -0
  661. /package/{packages/core/dist → dist}/workflow/sm-subagents.test.js +0 -0
  662. /package/{packages/core/dist → dist}/workflow/sm-subagents.test.js.map +0 -0
  663. /package/{packages/core/dist → dist}/workflow/story-workflow-routing.test.d.ts +0 -0
  664. /package/{packages/core/dist → dist}/workflow/story-workflow-routing.test.d.ts.map +0 -0
  665. /package/{packages/core/dist → dist}/workflow/story-workflow-routing.test.js +0 -0
  666. /package/{packages/core/dist → dist}/workflow/story-workflow-routing.test.js.map +0 -0
  667. /package/{packages/core/dist → dist}/workflow/test-cache.d.ts +0 -0
  668. /package/{packages/core/dist → dist}/workflow/test-cache.d.ts.map +0 -0
  669. /package/{packages/core/dist → dist}/workflow/test-cache.js +0 -0
  670. /package/{packages/core/dist → dist}/workflow/test-cache.js.map +0 -0
  671. /package/{packages/core/dist → dist}/workflow/test-cache.test.d.ts +0 -0
  672. /package/{packages/core/dist → dist}/workflow/test-cache.test.d.ts.map +0 -0
  673. /package/{packages/core/dist → dist}/workflow/test-cache.test.js +0 -0
  674. /package/{packages/core/dist → dist}/workflow/test-cache.test.js.map +0 -0
  675. /package/{packages/core/dist → dist}/workflow/workflow-loader.d.ts +0 -0
  676. /package/{packages/core/dist → dist}/workflow/workflow-loader.d.ts.map +0 -0
  677. /package/{packages/core/dist → dist}/workflow/workflow-loader.js +0 -0
  678. /package/{packages/core/dist → dist}/workflow/workflow-loader.js.map +0 -0
  679. /package/{packages/core/dist → dist}/workflow/workflow-loader.test.d.ts +0 -0
  680. /package/{packages/core/dist → dist}/workflow/workflow-loader.test.d.ts.map +0 -0
  681. /package/{packages/core/dist → dist}/workflow/workflow-migration.test.d.ts +0 -0
  682. /package/{packages/core/dist → dist}/workflow/workflow-migration.test.d.ts.map +0 -0
  683. /package/{packages/core/dist → dist}/workflow/workflow-router.d.ts +0 -0
  684. /package/{packages/core/dist → dist}/workflow/workflow-router.d.ts.map +0 -0
  685. /package/{packages/core/dist → dist}/workflow/workflow-router.js +0 -0
  686. /package/{packages/core/dist → dist}/workflow/workflow-router.js.map +0 -0
  687. /package/{packages/core/dist → dist}/workflow/workflow-router.test.d.ts +0 -0
  688. /package/{packages/core/dist → dist}/workflow/workflow-router.test.d.ts.map +0 -0
  689. /package/{packages/core/dist → dist}/workflow/workflow-router.test.js +0 -0
  690. /package/{packages/core/dist → dist}/workflow/workflow-router.test.js.map +0 -0
  691. /package/{packages/core/dist → dist}/workflow/workflow-schema.test.d.ts +0 -0
  692. /package/{packages/core/dist → dist}/workflow/workflow-schema.test.d.ts.map +0 -0
@@ -0,0 +1,845 @@
1
+ /**
2
+ * Tests for Story 47-2: Sync sprint numbers with Jira sprint IDs
3
+ *
4
+ * These tests define the contract for syncing Pennyfarthing sprint numbers
5
+ * with Jira sprint IDs, enabling bidirectional sprint tracking.
6
+ *
7
+ * Acceptance Criteria:
8
+ * 1. Sprint YAML references Jira sprint ID (e.g., 275)
9
+ * 2. Status check queries Jira sprint for membership
10
+ * 3. Sprint velocity pulls from Jira sprint metrics
11
+ * 4. Local sprint number matches Jira sprint
12
+ *
13
+ * Run with: npm test
14
+ */
15
+ import { describe, it, beforeEach, afterEach } from 'node:test';
16
+ import assert from 'node:assert';
17
+ import { mkdirSync, rmSync, existsSync, writeFileSync, readFileSync } from 'node:fs';
18
+ import { join, dirname } from 'node:path';
19
+ import { fileURLToPath } from 'node:url';
20
+ // Get directory for test fixtures
21
+ const __dirname = dirname(fileURLToPath(import.meta.url));
22
+ const TEST_DIR = join(__dirname, '__test_jira_sprint_sync__');
23
+ // Import the sprint sync functions (to be implemented)
24
+ import { getJiraSprintInfo, getSprintIssues, isStoryInJiraSprint, getSprintVelocityFromJira, validateSprintAlignment, addJiraSprintIdToYaml,
25
+ // Story 47-3 imports
26
+ getYamlStoryIds, findJiraOnlyStories, formatMissingStoriesReport, importMissingStoriesToYaml } from './jira-sprint-sync.js';
27
+ describe('Jira Sprint Sync (47-2)', () => {
28
+ beforeEach(() => {
29
+ if (existsSync(TEST_DIR)) {
30
+ rmSync(TEST_DIR, { recursive: true });
31
+ }
32
+ mkdirSync(TEST_DIR, { recursive: true });
33
+ });
34
+ afterEach(() => {
35
+ if (existsSync(TEST_DIR)) {
36
+ rmSync(TEST_DIR, { recursive: true });
37
+ }
38
+ });
39
+ // ============================================
40
+ // AC1: Sprint YAML references Jira sprint ID
41
+ // ============================================
42
+ describe('addJiraSprintIdToYaml() - AC1: Sprint YAML references Jira sprint ID', () => {
43
+ it('should add jira_sprint_id field to sprint section', async () => {
44
+ const sprintYaml = `sprint:
45
+ number: 11
46
+ goal: Complete Epic 31 workflow engine
47
+ planned_start: 2026-01-15
48
+ status: active
49
+ velocity_target: 22
50
+ `;
51
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
52
+ writeFileSync(sprintPath, sprintYaml);
53
+ const result = await addJiraSprintIdToYaml({
54
+ sprintPath,
55
+ jiraSprintId: 275
56
+ });
57
+ assert.strictEqual(result.success, true, 'Update should succeed');
58
+ const updatedContent = readFileSync(sprintPath, 'utf-8');
59
+ assert.ok(updatedContent.includes('jira_sprint_id: 275'), 'YAML should contain jira_sprint_id field');
60
+ });
61
+ it('should preserve existing sprint fields when adding jira_sprint_id', async () => {
62
+ const sprintYaml = `sprint:
63
+ number: 11
64
+ goal: Complete Epic 31 workflow engine
65
+ planned_start: 2026-01-15
66
+ status: active
67
+ velocity_target: 22
68
+ `;
69
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
70
+ writeFileSync(sprintPath, sprintYaml);
71
+ await addJiraSprintIdToYaml({
72
+ sprintPath,
73
+ jiraSprintId: 275
74
+ });
75
+ const updatedContent = readFileSync(sprintPath, 'utf-8');
76
+ assert.ok(updatedContent.includes('number: 11'), 'Number should be preserved');
77
+ assert.ok(updatedContent.includes('goal: Complete Epic 31'), 'Goal should be preserved');
78
+ assert.ok(updatedContent.includes('velocity_target: 22'), 'Velocity target should be preserved');
79
+ });
80
+ it('should update existing jira_sprint_id if already present', async () => {
81
+ const sprintYaml = `sprint:
82
+ number: 11
83
+ jira_sprint_id: 274
84
+ goal: Old sprint
85
+ status: active
86
+ `;
87
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
88
+ writeFileSync(sprintPath, sprintYaml);
89
+ const result = await addJiraSprintIdToYaml({
90
+ sprintPath,
91
+ jiraSprintId: 275,
92
+ force: true
93
+ });
94
+ assert.strictEqual(result.success, true);
95
+ const updatedContent = readFileSync(sprintPath, 'utf-8');
96
+ assert.ok(updatedContent.includes('jira_sprint_id: 275'), 'Should have updated jira_sprint_id');
97
+ assert.ok(!updatedContent.includes('jira_sprint_id: 274'), 'Should not have old jira_sprint_id');
98
+ });
99
+ it('should fail if jira_sprint_id exists and force is false', async () => {
100
+ const sprintYaml = `sprint:
101
+ number: 11
102
+ jira_sprint_id: 274
103
+ status: active
104
+ `;
105
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
106
+ writeFileSync(sprintPath, sprintYaml);
107
+ const result = await addJiraSprintIdToYaml({
108
+ sprintPath,
109
+ jiraSprintId: 275,
110
+ force: false
111
+ });
112
+ assert.strictEqual(result.success, false);
113
+ assert.ok(result.error?.includes('already has'), 'Should mention existing ID');
114
+ });
115
+ it('should handle file not found gracefully', async () => {
116
+ const result = await addJiraSprintIdToYaml({
117
+ sprintPath: join(TEST_DIR, 'nonexistent.yaml'),
118
+ jiraSprintId: 275
119
+ });
120
+ assert.strictEqual(result.success, false);
121
+ assert.ok(result.error?.includes('not found') || result.error?.includes('ENOENT'), 'Should report file not found');
122
+ });
123
+ });
124
+ // ============================================
125
+ // AC2: Status check queries Jira sprint for membership
126
+ // ============================================
127
+ describe('getJiraSprintInfo() - AC2: Query Jira sprint for membership', () => {
128
+ it('should return sprint details from Jira', async () => {
129
+ const result = await getJiraSprintInfo({
130
+ sprintId: 275,
131
+ _mockResponse: {
132
+ id: 275,
133
+ name: 'Sprint 11',
134
+ state: 'active',
135
+ startDate: '2026-01-15',
136
+ endDate: '2026-01-29'
137
+ }
138
+ });
139
+ assert.strictEqual(result.success, true);
140
+ assert.strictEqual(result.sprint?.id, 275);
141
+ assert.strictEqual(result.sprint?.name, 'Sprint 11');
142
+ assert.strictEqual(result.sprint?.state, 'active');
143
+ });
144
+ it('should return null for non-existent sprint', async () => {
145
+ const result = await getJiraSprintInfo({
146
+ sprintId: 99999,
147
+ _mockResponse: null
148
+ });
149
+ assert.strictEqual(result.success, false);
150
+ assert.ok(result.error?.includes('not found'), 'Should indicate sprint not found');
151
+ });
152
+ it('should handle Jira API errors', async () => {
153
+ const result = await getJiraSprintInfo({
154
+ sprintId: 275,
155
+ _mockError: 'Connection refused'
156
+ });
157
+ assert.strictEqual(result.success, false);
158
+ assert.ok(result.error, 'Should have error message');
159
+ });
160
+ });
161
+ describe('getSprintIssues() - AC2: List issues in Jira sprint', () => {
162
+ it('should return issues in the sprint', async () => {
163
+ const result = await getSprintIssues({
164
+ sprintId: 275,
165
+ _mockResponse: [
166
+ { key: 'MSSCI-11798', summary: 'Sprint sync story', status: 'In Progress' },
167
+ { key: 'MSSCI-11750', summary: 'Another story', status: 'Done' }
168
+ ]
169
+ });
170
+ assert.strictEqual(result.success, true);
171
+ assert.strictEqual(result.issues?.length, 2);
172
+ assert.strictEqual(result.issues?.[0].key, 'MSSCI-11798');
173
+ });
174
+ it('should filter by label when provided', async () => {
175
+ const result = await getSprintIssues({
176
+ sprintId: 275,
177
+ label: 'pennyfarthing',
178
+ _mockResponse: [
179
+ { key: 'MSSCI-11798', summary: 'Pennyfarthing story', status: 'In Progress', labels: ['pennyfarthing'] }
180
+ ]
181
+ });
182
+ assert.strictEqual(result.success, true);
183
+ assert.strictEqual(result.issues?.length, 1);
184
+ });
185
+ it('should return empty array for sprint with no issues', async () => {
186
+ const result = await getSprintIssues({
187
+ sprintId: 275,
188
+ _mockResponse: []
189
+ });
190
+ assert.strictEqual(result.success, true);
191
+ assert.strictEqual(result.issues?.length, 0);
192
+ });
193
+ });
194
+ describe('isStoryInJiraSprint() - AC2: Check sprint membership', () => {
195
+ it('should return true if story is in the sprint', async () => {
196
+ const result = await isStoryInJiraSprint({
197
+ jiraKey: 'MSSCI-11798',
198
+ sprintId: 275,
199
+ _mockResponse: true
200
+ });
201
+ assert.strictEqual(result.success, true);
202
+ assert.strictEqual(result.inSprint, true);
203
+ });
204
+ it('should return false if story is not in the sprint', async () => {
205
+ const result = await isStoryInJiraSprint({
206
+ jiraKey: 'MSSCI-11798',
207
+ sprintId: 274, // Different sprint
208
+ _mockResponse: false
209
+ });
210
+ assert.strictEqual(result.success, true);
211
+ assert.strictEqual(result.inSprint, false);
212
+ });
213
+ it('should handle story not found in Jira', async () => {
214
+ const result = await isStoryInJiraSprint({
215
+ jiraKey: 'MSSCI-99999',
216
+ sprintId: 275,
217
+ _mockError: 'Issue not found'
218
+ });
219
+ assert.strictEqual(result.success, false);
220
+ assert.ok(result.error?.includes('not found'));
221
+ });
222
+ });
223
+ // ============================================
224
+ // AC3: Sprint velocity pulls from Jira sprint metrics
225
+ // ============================================
226
+ describe('getSprintVelocityFromJira() - AC3: Sprint velocity from Jira', () => {
227
+ it('should return velocity metrics from Jira sprint', async () => {
228
+ const result = await getSprintVelocityFromJira({
229
+ sprintId: 275,
230
+ _mockResponse: {
231
+ totalPoints: 22,
232
+ completedPoints: 15,
233
+ remainingPoints: 7,
234
+ issueCount: 8,
235
+ completedCount: 5
236
+ }
237
+ });
238
+ assert.strictEqual(result.success, true);
239
+ assert.strictEqual(result.metrics?.totalPoints, 22);
240
+ assert.strictEqual(result.metrics?.completedPoints, 15);
241
+ assert.strictEqual(result.metrics?.remainingPoints, 7);
242
+ });
243
+ it('should calculate velocity percentage', async () => {
244
+ const result = await getSprintVelocityFromJira({
245
+ sprintId: 275,
246
+ _mockResponse: {
247
+ totalPoints: 20,
248
+ completedPoints: 10,
249
+ remainingPoints: 10
250
+ }
251
+ });
252
+ assert.strictEqual(result.success, true);
253
+ assert.strictEqual(result.metrics?.velocityPercentage, 50);
254
+ });
255
+ it('should handle sprint with no points', async () => {
256
+ const result = await getSprintVelocityFromJira({
257
+ sprintId: 275,
258
+ _mockResponse: {
259
+ totalPoints: 0,
260
+ completedPoints: 0,
261
+ remainingPoints: 0
262
+ }
263
+ });
264
+ assert.strictEqual(result.success, true);
265
+ assert.strictEqual(result.metrics?.totalPoints, 0);
266
+ // Should not divide by zero
267
+ assert.ok(result.metrics?.velocityPercentage === 0 || result.metrics?.velocityPercentage === null, 'Should handle zero total gracefully');
268
+ });
269
+ it('should return issue breakdown by status', async () => {
270
+ const result = await getSprintVelocityFromJira({
271
+ sprintId: 275,
272
+ _mockResponse: {
273
+ totalPoints: 22,
274
+ completedPoints: 15,
275
+ remainingPoints: 7,
276
+ byStatus: {
277
+ 'To Do': { count: 2, points: 3 },
278
+ 'In Progress': { count: 1, points: 4 },
279
+ 'Done': { count: 5, points: 15 }
280
+ }
281
+ }
282
+ });
283
+ assert.strictEqual(result.success, true);
284
+ assert.ok(result.metrics?.byStatus, 'Should have status breakdown');
285
+ assert.strictEqual(result.metrics?.byStatus?.Done?.points, 15);
286
+ });
287
+ });
288
+ // ============================================
289
+ // AC4: Local sprint name matches Jira sprint
290
+ // ============================================
291
+ describe('validateSprintAlignment() - AC4: Local sprint matches Jira', () => {
292
+ it('should return aligned when sprint names match', async () => {
293
+ const sprintYaml = `sprint:
294
+ name: "TO Sprint 2604"
295
+ jira_sprint_id: 275
296
+ jira_sprint_name: "TO Sprint 2604"
297
+ status: active
298
+ `;
299
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
300
+ writeFileSync(sprintPath, sprintYaml);
301
+ const result = await validateSprintAlignment({
302
+ sprintPath,
303
+ _mockJiraSprint: {
304
+ id: 275,
305
+ name: 'TO Sprint 2604',
306
+ state: 'active'
307
+ }
308
+ });
309
+ assert.strictEqual(result.success, true);
310
+ assert.strictEqual(result.aligned, true);
311
+ assert.strictEqual(result.localSprintName, 'TO Sprint 2604');
312
+ assert.strictEqual(result.jiraSprintId, 275);
313
+ });
314
+ it('should detect misalignment when sprint names differ', async () => {
315
+ const sprintYaml = `sprint:
316
+ name: "TO Sprint 2604"
317
+ jira_sprint_id: 275
318
+ jira_sprint_name: "TO Sprint 2604"
319
+ status: active
320
+ `;
321
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
322
+ writeFileSync(sprintPath, sprintYaml);
323
+ const result = await validateSprintAlignment({
324
+ sprintPath,
325
+ _mockJiraSprint: {
326
+ id: 275,
327
+ name: 'TO Sprint 2605', // Mismatch!
328
+ state: 'active'
329
+ }
330
+ });
331
+ assert.strictEqual(result.success, true);
332
+ assert.strictEqual(result.aligned, false);
333
+ assert.ok(result.warning?.includes('mismatch'), 'Should warn about mismatch');
334
+ });
335
+ it('should detect when Jira sprint is closed but local is active', async () => {
336
+ const sprintYaml = `sprint:
337
+ name: "TO Sprint 2604"
338
+ jira_sprint_id: 275
339
+ jira_sprint_name: "TO Sprint 2604"
340
+ status: active
341
+ `;
342
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
343
+ writeFileSync(sprintPath, sprintYaml);
344
+ const result = await validateSprintAlignment({
345
+ sprintPath,
346
+ _mockJiraSprint: {
347
+ id: 275,
348
+ name: 'TO Sprint 2604',
349
+ state: 'closed' // Jira sprint closed!
350
+ }
351
+ });
352
+ assert.strictEqual(result.success, true);
353
+ assert.strictEqual(result.aligned, false);
354
+ assert.ok(result.warning?.includes('closed'), 'Should warn about closed sprint');
355
+ });
356
+ it('should handle missing jira_sprint_id in YAML', async () => {
357
+ const sprintYaml = `sprint:
358
+ name: "TO Sprint 2604"
359
+ status: active
360
+ `;
361
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
362
+ writeFileSync(sprintPath, sprintYaml);
363
+ const result = await validateSprintAlignment({
364
+ sprintPath,
365
+ _mockJiraSprint: null
366
+ });
367
+ assert.strictEqual(result.success, false);
368
+ assert.ok(result.error?.includes('jira_sprint_id') || result.error?.includes('not configured'), 'Should report missing jira_sprint_id');
369
+ });
370
+ it('should use jira_sprint_name for comparison if present', async () => {
371
+ const sprintYaml = `sprint:
372
+ name: "My Local Name"
373
+ jira_sprint_id: 275
374
+ jira_sprint_name: "TO Sprint 2604"
375
+ status: active
376
+ `;
377
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
378
+ writeFileSync(sprintPath, sprintYaml);
379
+ const result = await validateSprintAlignment({
380
+ sprintPath,
381
+ _mockJiraSprint: {
382
+ id: 275,
383
+ name: 'TO Sprint 2604',
384
+ state: 'active'
385
+ }
386
+ });
387
+ assert.strictEqual(result.success, true);
388
+ assert.strictEqual(result.aligned, true);
389
+ assert.strictEqual(result.jiraSprintName, 'TO Sprint 2604');
390
+ });
391
+ });
392
+ // ============================================
393
+ // Integration tests
394
+ // ============================================
395
+ describe('Integration: Full sprint sync workflow', () => {
396
+ it('should sync sprint with Jira and update YAML', async () => {
397
+ // Start with no jira_sprint_id
398
+ const sprintYaml = `sprint:
399
+ name: "TO Sprint 2604"
400
+ goal: Test sprint
401
+ status: active
402
+ `;
403
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
404
+ writeFileSync(sprintPath, sprintYaml);
405
+ // Step 1: Add jira_sprint_id
406
+ const addResult = await addJiraSprintIdToYaml({
407
+ sprintPath,
408
+ jiraSprintId: 275
409
+ });
410
+ assert.strictEqual(addResult.success, true);
411
+ // Step 2: Validate alignment
412
+ const validateResult = await validateSprintAlignment({
413
+ sprintPath,
414
+ _mockJiraSprint: {
415
+ id: 275,
416
+ name: 'TO Sprint 2604',
417
+ state: 'active'
418
+ }
419
+ });
420
+ assert.strictEqual(validateResult.success, true);
421
+ assert.strictEqual(validateResult.aligned, true);
422
+ // Step 3: Get velocity
423
+ const velocityResult = await getSprintVelocityFromJira({
424
+ sprintId: 275,
425
+ _mockResponse: {
426
+ totalPoints: 22,
427
+ completedPoints: 10,
428
+ remainingPoints: 12
429
+ }
430
+ });
431
+ assert.strictEqual(velocityResult.success, true);
432
+ assert.strictEqual(velocityResult.metrics?.totalPoints, 22);
433
+ });
434
+ it('should warn when story is not in Jira sprint', async () => {
435
+ // This tests the SM setup flow integration
436
+ const membershipResult = await isStoryInJiraSprint({
437
+ jiraKey: 'MSSCI-11798',
438
+ sprintId: 275,
439
+ _mockResponse: false
440
+ });
441
+ assert.strictEqual(membershipResult.success, true);
442
+ assert.strictEqual(membershipResult.inSprint, false);
443
+ // In real implementation, this would trigger a warning in SM setup
444
+ });
445
+ });
446
+ });
447
+ // ============================================
448
+ // Story 47-3: Detect Jira-only stories missing from sprint YAML
449
+ // ============================================
450
+ //
451
+ // Acceptance Criteria:
452
+ // 1. Sync script queries Jira sprint for all pennyfarthing stories
453
+ // 2. Compares against sprint YAML story list
454
+ // 3. Reports stories in Jira but not in YAML
455
+ // 4. Optionally imports missing stories to YAML
456
+ describe('Jira-Only Story Detection (47-3)', () => {
457
+ beforeEach(() => {
458
+ if (existsSync(TEST_DIR)) {
459
+ rmSync(TEST_DIR, { recursive: true });
460
+ }
461
+ mkdirSync(TEST_DIR, { recursive: true });
462
+ });
463
+ afterEach(() => {
464
+ if (existsSync(TEST_DIR)) {
465
+ rmSync(TEST_DIR, { recursive: true });
466
+ }
467
+ });
468
+ // ============================================
469
+ // AC1 + AC2: Query Jira and compare against YAML
470
+ // ============================================
471
+ describe('getYamlStoryIds() - Extract story IDs from sprint YAML', () => {
472
+ it('should extract all story IDs from sprint YAML', async () => {
473
+ const sprintYaml = `sprint:
474
+ number: 11
475
+ status: active
476
+ epics:
477
+ - id: epic-47
478
+ title: Jira Sync
479
+ stories:
480
+ - id: "47-1"
481
+ title: Auto-create Jira epic
482
+ status: done
483
+ - id: "47-2"
484
+ title: Sync sprint numbers
485
+ status: done
486
+ - id: "47-3"
487
+ title: Detect Jira-only stories
488
+ status: in_progress
489
+ `;
490
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
491
+ writeFileSync(sprintPath, sprintYaml);
492
+ const result = await getYamlStoryIds({ sprintPath });
493
+ assert.strictEqual(result.success, true);
494
+ assert.ok(result.storyIds, 'Should return storyIds array');
495
+ assert.strictEqual(result.storyIds?.length, 3);
496
+ assert.ok(result.storyIds?.includes('47-1'));
497
+ assert.ok(result.storyIds?.includes('47-2'));
498
+ assert.ok(result.storyIds?.includes('47-3'));
499
+ });
500
+ it('should extract stories from multiple epics', async () => {
501
+ const sprintYaml = `sprint:
502
+ number: 11
503
+ status: active
504
+ epics:
505
+ - id: epic-31
506
+ title: Workflow Engine
507
+ stories:
508
+ - id: "31-1"
509
+ status: done
510
+ - id: "31-2"
511
+ status: done
512
+ - id: epic-47
513
+ title: Jira Sync
514
+ stories:
515
+ - id: "47-1"
516
+ status: done
517
+ `;
518
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
519
+ writeFileSync(sprintPath, sprintYaml);
520
+ const result = await getYamlStoryIds({ sprintPath });
521
+ assert.strictEqual(result.success, true);
522
+ assert.strictEqual(result.storyIds?.length, 3);
523
+ assert.ok(result.storyIds?.includes('31-1'));
524
+ assert.ok(result.storyIds?.includes('31-2'));
525
+ assert.ok(result.storyIds?.includes('47-1'));
526
+ });
527
+ it('should return empty array for YAML with no stories', async () => {
528
+ const sprintYaml = `sprint:
529
+ number: 11
530
+ status: active
531
+ epics: []
532
+ `;
533
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
534
+ writeFileSync(sprintPath, sprintYaml);
535
+ const result = await getYamlStoryIds({ sprintPath });
536
+ assert.strictEqual(result.success, true);
537
+ assert.strictEqual(result.storyIds?.length, 0);
538
+ });
539
+ it('should handle missing file gracefully', async () => {
540
+ const result = await getYamlStoryIds({
541
+ sprintPath: join(TEST_DIR, 'nonexistent.yaml')
542
+ });
543
+ assert.strictEqual(result.success, false);
544
+ assert.ok(result.error?.includes('not found') || result.error?.includes('ENOENT'));
545
+ });
546
+ });
547
+ describe('findJiraOnlyStories() - Compare Jira issues with YAML stories', () => {
548
+ it('should find stories in Jira but not in YAML', async () => {
549
+ const jiraIssues = [
550
+ { key: 'MSSCI-11797', summary: '47-1: Auto-create Jira epic', status: 'Done' },
551
+ { key: 'MSSCI-11798', summary: '47-2: Sync sprint numbers', status: 'Done' },
552
+ { key: 'MSSCI-11800', summary: '47-4: Bidirectional sync', status: 'To Do' } // Not in YAML!
553
+ ];
554
+ const yamlStoryIds = ['47-1', '47-2', '47-3'];
555
+ const result = await findJiraOnlyStories({
556
+ jiraIssues,
557
+ yamlStoryIds
558
+ });
559
+ assert.strictEqual(result.success, true);
560
+ assert.strictEqual(result.missingStories?.length, 1);
561
+ assert.strictEqual(result.missingStories?.[0].key, 'MSSCI-11800');
562
+ assert.strictEqual(result.missingStories?.[0].storyId, '47-4');
563
+ });
564
+ it('should return empty when all Jira stories are in YAML', async () => {
565
+ const jiraIssues = [
566
+ { key: 'MSSCI-11797', summary: '47-1: Auto-create Jira epic', status: 'Done' },
567
+ { key: 'MSSCI-11798', summary: '47-2: Sync sprint numbers', status: 'Done' }
568
+ ];
569
+ const yamlStoryIds = ['47-1', '47-2', '47-3'];
570
+ const result = await findJiraOnlyStories({
571
+ jiraIssues,
572
+ yamlStoryIds
573
+ });
574
+ assert.strictEqual(result.success, true);
575
+ assert.strictEqual(result.missingStories?.length, 0);
576
+ });
577
+ it('should extract story ID from Jira summary format', async () => {
578
+ // Jira summaries often have format "47-1: Title" or "Story 47-1: Title"
579
+ const jiraIssues = [
580
+ { key: 'MSSCI-100', summary: 'Story 31-5: New feature', status: 'In Progress' },
581
+ { key: 'MSSCI-101', summary: '31-6: Another feature', status: 'To Do' }
582
+ ];
583
+ const yamlStoryIds = ['31-1', '31-2'];
584
+ const result = await findJiraOnlyStories({
585
+ jiraIssues,
586
+ yamlStoryIds
587
+ });
588
+ assert.strictEqual(result.success, true);
589
+ assert.strictEqual(result.missingStories?.length, 2);
590
+ assert.strictEqual(result.missingStories?.[0].storyId, '31-5');
591
+ assert.strictEqual(result.missingStories?.[1].storyId, '31-6');
592
+ });
593
+ it('should filter by pennyfarthing label when provided', async () => {
594
+ const jiraIssues = [
595
+ { key: 'MSSCI-100', summary: '47-4: PF story', status: 'To Do', labels: ['pennyfarthing'] },
596
+ { key: 'MSSCI-101', summary: 'OTHER-1: Not PF', status: 'To Do', labels: ['other-project'] }
597
+ ];
598
+ const yamlStoryIds = ['47-1'];
599
+ const result = await findJiraOnlyStories({
600
+ jiraIssues,
601
+ yamlStoryIds,
602
+ filterLabel: 'pennyfarthing'
603
+ });
604
+ assert.strictEqual(result.success, true);
605
+ assert.strictEqual(result.missingStories?.length, 1);
606
+ assert.strictEqual(result.missingStories?.[0].key, 'MSSCI-100');
607
+ });
608
+ });
609
+ // ============================================
610
+ // AC3: Report stories in Jira but not in YAML
611
+ // ============================================
612
+ describe('formatMissingStoriesReport() - Human-readable report', () => {
613
+ it('should format missing stories as readable report', async () => {
614
+ const missingStories = [
615
+ { key: 'MSSCI-11800', summary: '47-4: Bidirectional sync', status: 'To Do', storyId: '47-4' },
616
+ { key: 'MSSCI-11801', summary: '47-5: Retrofit epics', status: 'To Do', storyId: '47-5' }
617
+ ];
618
+ const result = await formatMissingStoriesReport({ missingStories });
619
+ assert.strictEqual(result.success, true);
620
+ assert.ok(result.report, 'Should have report string');
621
+ assert.ok(result.report?.includes('MSSCI-11800'));
622
+ assert.ok(result.report?.includes('47-4'));
623
+ assert.ok(result.report?.includes('Bidirectional sync'));
624
+ assert.ok(result.report?.includes('2 stories')); // Count in header
625
+ });
626
+ it('should return "no missing stories" message when empty', async () => {
627
+ const result = await formatMissingStoriesReport({ missingStories: [] });
628
+ assert.strictEqual(result.success, true);
629
+ assert.ok(result.report?.toLowerCase().includes('no missing') ||
630
+ result.report?.toLowerCase().includes('all synced') ||
631
+ result.report?.includes('0 stories'));
632
+ });
633
+ it('should include Jira URL in report', async () => {
634
+ const missingStories = [
635
+ { key: 'MSSCI-11800', summary: '47-4: Test', status: 'To Do', storyId: '47-4' }
636
+ ];
637
+ const result = await formatMissingStoriesReport({
638
+ missingStories,
639
+ jiraBaseUrl: 'https://1898andco.atlassian.net'
640
+ });
641
+ assert.strictEqual(result.success, true);
642
+ assert.ok(result.report?.includes('https://1898andco.atlassian.net/browse/MSSCI-11800'));
643
+ });
644
+ });
645
+ // ============================================
646
+ // AC4: Optionally import missing stories to YAML
647
+ // ============================================
648
+ describe('importMissingStoriesToYaml() - Add missing stories to sprint YAML', () => {
649
+ it('should add missing story to existing epic in YAML', async () => {
650
+ const sprintYaml = `sprint:
651
+ number: 11
652
+ status: active
653
+ epics:
654
+ - id: epic-47
655
+ title: Jira Sync
656
+ stories:
657
+ - id: "47-1"
658
+ title: Auto-create Jira epic
659
+ status: done
660
+ `;
661
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
662
+ writeFileSync(sprintPath, sprintYaml);
663
+ const missingStories = [
664
+ { key: 'MSSCI-11800', summary: '47-4: Bidirectional sync', status: 'To Do', storyId: '47-4', points: 4 }
665
+ ];
666
+ const result = await importMissingStoriesToYaml({
667
+ sprintPath,
668
+ missingStories,
669
+ targetEpicId: 'epic-47'
670
+ });
671
+ assert.strictEqual(result.success, true);
672
+ assert.strictEqual(result.importedCount, 1);
673
+ // Verify the YAML was updated
674
+ const updatedContent = readFileSync(sprintPath, 'utf-8');
675
+ assert.ok(updatedContent.includes('47-4'));
676
+ assert.ok(updatedContent.includes('Bidirectional sync'));
677
+ });
678
+ it('should preserve existing story order and add new at end', async () => {
679
+ const sprintYaml = `sprint:
680
+ number: 11
681
+ epics:
682
+ - id: epic-47
683
+ stories:
684
+ - id: "47-1"
685
+ status: done
686
+ - id: "47-2"
687
+ status: done
688
+ `;
689
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
690
+ writeFileSync(sprintPath, sprintYaml);
691
+ const missingStories = [
692
+ { key: 'MSSCI-11800', summary: '47-4: New story', status: 'To Do', storyId: '47-4' }
693
+ ];
694
+ const result = await importMissingStoriesToYaml({
695
+ sprintPath,
696
+ missingStories,
697
+ targetEpicId: 'epic-47'
698
+ });
699
+ assert.strictEqual(result.success, true);
700
+ const updatedContent = readFileSync(sprintPath, 'utf-8');
701
+ const idx47_1 = updatedContent.indexOf('47-1');
702
+ const idx47_2 = updatedContent.indexOf('47-2');
703
+ const idx47_4 = updatedContent.indexOf('47-4');
704
+ assert.ok(idx47_1 < idx47_2, '47-1 should come before 47-2');
705
+ assert.ok(idx47_2 < idx47_4, '47-4 should come after 47-2');
706
+ });
707
+ it('should support dry-run mode that does not modify file', async () => {
708
+ const sprintYaml = `sprint:
709
+ number: 11
710
+ epics:
711
+ - id: epic-47
712
+ stories:
713
+ - id: "47-1"
714
+ status: done
715
+ `;
716
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
717
+ writeFileSync(sprintPath, sprintYaml);
718
+ const missingStories = [
719
+ { key: 'MSSCI-11800', summary: '47-4: New story', status: 'To Do', storyId: '47-4' }
720
+ ];
721
+ const result = await importMissingStoriesToYaml({
722
+ sprintPath,
723
+ missingStories,
724
+ targetEpicId: 'epic-47',
725
+ dryRun: true
726
+ });
727
+ assert.strictEqual(result.success, true);
728
+ assert.strictEqual(result.importedCount, 1);
729
+ assert.ok(result.wouldImport, 'Should indicate what would be imported');
730
+ // File should NOT be modified
731
+ const content = readFileSync(sprintPath, 'utf-8');
732
+ assert.ok(!content.includes('47-4'), 'File should not contain 47-4 in dry-run');
733
+ });
734
+ it('should fail if target epic does not exist', async () => {
735
+ const sprintYaml = `sprint:
736
+ number: 11
737
+ epics:
738
+ - id: epic-31
739
+ stories:
740
+ - id: "31-1"
741
+ status: done
742
+ `;
743
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
744
+ writeFileSync(sprintPath, sprintYaml);
745
+ const missingStories = [
746
+ { key: 'MSSCI-11800', summary: '47-4: New story', status: 'To Do', storyId: '47-4' }
747
+ ];
748
+ const result = await importMissingStoriesToYaml({
749
+ sprintPath,
750
+ missingStories,
751
+ targetEpicId: 'epic-47' // Does not exist!
752
+ });
753
+ assert.strictEqual(result.success, false);
754
+ assert.ok(result.error?.includes('epic-47') || result.error?.includes('not found'));
755
+ });
756
+ it('should map Jira status to YAML status', async () => {
757
+ const sprintYaml = `sprint:
758
+ number: 11
759
+ epics:
760
+ - id: epic-47
761
+ stories:
762
+ - id: "47-1"
763
+ status: done
764
+ `;
765
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
766
+ writeFileSync(sprintPath, sprintYaml);
767
+ const missingStories = [
768
+ { key: 'MSSCI-100', summary: '47-2: Story', status: 'In Progress', storyId: '47-2' },
769
+ { key: 'MSSCI-101', summary: '47-3: Story', status: 'Done', storyId: '47-3' },
770
+ { key: 'MSSCI-102', summary: '47-4: Story', status: 'To Do', storyId: '47-4' }
771
+ ];
772
+ const result = await importMissingStoriesToYaml({
773
+ sprintPath,
774
+ missingStories,
775
+ targetEpicId: 'epic-47'
776
+ });
777
+ assert.strictEqual(result.success, true);
778
+ const content = readFileSync(sprintPath, 'utf-8');
779
+ assert.ok(content.includes('status: in_progress') || content.includes('status: in-progress'));
780
+ assert.ok(content.includes('status: done'));
781
+ assert.ok(content.includes('status: backlog') || content.includes('status: todo'));
782
+ });
783
+ });
784
+ // ============================================
785
+ // Integration: Full detection flow
786
+ // ============================================
787
+ describe('Integration: Detect and report Jira-only stories', () => {
788
+ it('should detect stories in Jira sprint but missing from YAML', async () => {
789
+ // Setup: YAML with stories 47-1, 47-2, 47-3
790
+ const sprintYaml = `sprint:
791
+ number: 11
792
+ jira_sprint_id: 275
793
+ status: active
794
+ epics:
795
+ - id: epic-47
796
+ title: Jira Sync
797
+ stories:
798
+ - id: "47-1"
799
+ title: Auto-create Jira epic
800
+ jira: MSSCI-11797
801
+ status: done
802
+ - id: "47-2"
803
+ title: Sync sprint numbers
804
+ jira: MSSCI-11798
805
+ status: done
806
+ - id: "47-3"
807
+ title: Detect Jira-only stories
808
+ jira: MSSCI-11799
809
+ status: in_progress
810
+ `;
811
+ const sprintPath = join(TEST_DIR, 'current-sprint.yaml');
812
+ writeFileSync(sprintPath, sprintYaml);
813
+ // Step 1: Get YAML story IDs
814
+ const yamlResult = await getYamlStoryIds({ sprintPath });
815
+ assert.strictEqual(yamlResult.success, true);
816
+ assert.strictEqual(yamlResult.storyIds?.length, 3);
817
+ // Step 2: Mock Jira sprint issues (includes 47-4 and 47-5 not in YAML)
818
+ const jiraIssues = [
819
+ { key: 'MSSCI-11797', summary: '47-1: Auto-create Jira epic', status: 'Done', labels: ['pennyfarthing'] },
820
+ { key: 'MSSCI-11798', summary: '47-2: Sync sprint numbers', status: 'Done', labels: ['pennyfarthing'] },
821
+ { key: 'MSSCI-11799', summary: '47-3: Detect Jira-only stories', status: 'In Progress', labels: ['pennyfarthing'] },
822
+ { key: 'MSSCI-11800', summary: '47-4: Bidirectional sync', status: 'To Do', labels: ['pennyfarthing'] },
823
+ { key: 'MSSCI-11801', summary: '47-5: Retrofit epics', status: 'To Do', labels: ['pennyfarthing'] }
824
+ ];
825
+ // Step 3: Find Jira-only stories
826
+ const compareResult = await findJiraOnlyStories({
827
+ jiraIssues,
828
+ yamlStoryIds: yamlResult.storyIds,
829
+ filterLabel: 'pennyfarthing'
830
+ });
831
+ assert.strictEqual(compareResult.success, true);
832
+ assert.strictEqual(compareResult.missingStories?.length, 2);
833
+ // Step 4: Generate report
834
+ const reportResult = await formatMissingStoriesReport({
835
+ missingStories: compareResult.missingStories,
836
+ jiraBaseUrl: 'https://1898andco.atlassian.net'
837
+ });
838
+ assert.strictEqual(reportResult.success, true);
839
+ assert.ok(reportResult.report?.includes('47-4'));
840
+ assert.ok(reportResult.report?.includes('47-5'));
841
+ assert.ok(reportResult.report?.includes('2 stories'));
842
+ });
843
+ });
844
+ });
845
+ //# sourceMappingURL=jira-sprint-sync.test.js.map