@camaradesuk/git-worktree-tools 1.10.0 → 1.12.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 (431) hide show
  1. package/README.md +4 -4
  2. package/dist/lib/config.d.ts +2 -1
  3. package/dist/lib/config.d.ts.map +1 -1
  4. package/dist/lib/config.js +11 -0
  5. package/dist/lib/config.js.map +1 -1
  6. package/package.json +12 -3
  7. package/schemas/worktreerc.schema.json +1 -1
  8. package/dist/api/list.test.d.ts +0 -5
  9. package/dist/api/list.test.d.ts.map +0 -1
  10. package/dist/api/list.test.js +0 -390
  11. package/dist/api/list.test.js.map +0 -1
  12. package/dist/cli/cleanpr.test.d.ts +0 -2
  13. package/dist/cli/cleanpr.test.d.ts.map +0 -1
  14. package/dist/cli/cleanpr.test.js +0 -954
  15. package/dist/cli/cleanpr.test.js.map +0 -1
  16. package/dist/cli/lswt.test.d.ts +0 -2
  17. package/dist/cli/lswt.test.d.ts.map +0 -1
  18. package/dist/cli/lswt.test.js +0 -376
  19. package/dist/cli/lswt.test.js.map +0 -1
  20. package/dist/cli/newpr.test.d.ts +0 -2
  21. package/dist/cli/newpr.test.d.ts.map +0 -1
  22. package/dist/cli/newpr.test.js +0 -1182
  23. package/dist/cli/newpr.test.js.map +0 -1
  24. package/dist/cli/prs.test.d.ts +0 -8
  25. package/dist/cli/prs.test.d.ts.map +0 -1
  26. package/dist/cli/prs.test.js +0 -463
  27. package/dist/cli/prs.test.js.map +0 -1
  28. package/dist/cli/wt/clean.test.d.ts +0 -8
  29. package/dist/cli/wt/clean.test.d.ts.map +0 -1
  30. package/dist/cli/wt/clean.test.js +0 -624
  31. package/dist/cli/wt/clean.test.js.map +0 -1
  32. package/dist/cli/wt/completion.test.d.ts +0 -5
  33. package/dist/cli/wt/completion.test.d.ts.map +0 -1
  34. package/dist/cli/wt/completion.test.js +0 -275
  35. package/dist/cli/wt/completion.test.js.map +0 -1
  36. package/dist/cli/wt/config.test.d.ts +0 -7
  37. package/dist/cli/wt/config.test.d.ts.map +0 -1
  38. package/dist/cli/wt/config.test.js +0 -440
  39. package/dist/cli/wt/config.test.js.map +0 -1
  40. package/dist/cli/wt/entry.test.d.ts +0 -8
  41. package/dist/cli/wt/entry.test.d.ts.map +0 -1
  42. package/dist/cli/wt/entry.test.js +0 -201
  43. package/dist/cli/wt/entry.test.js.map +0 -1
  44. package/dist/cli/wt/init.test.d.ts +0 -5
  45. package/dist/cli/wt/init.test.d.ts.map +0 -1
  46. package/dist/cli/wt/init.test.js +0 -165
  47. package/dist/cli/wt/init.test.js.map +0 -1
  48. package/dist/cli/wt/init.unit.test.d.ts +0 -5
  49. package/dist/cli/wt/init.unit.test.d.ts.map +0 -1
  50. package/dist/cli/wt/init.unit.test.js +0 -432
  51. package/dist/cli/wt/init.unit.test.js.map +0 -1
  52. package/dist/cli/wt/interactive-menu.test.d.ts +0 -12
  53. package/dist/cli/wt/interactive-menu.test.d.ts.map +0 -1
  54. package/dist/cli/wt/interactive-menu.test.js +0 -796
  55. package/dist/cli/wt/interactive-menu.test.js.map +0 -1
  56. package/dist/cli/wt/list.test.d.ts +0 -10
  57. package/dist/cli/wt/list.test.d.ts.map +0 -1
  58. package/dist/cli/wt/list.test.js +0 -157
  59. package/dist/cli/wt/list.test.js.map +0 -1
  60. package/dist/cli/wt/prs.test.d.ts +0 -5
  61. package/dist/cli/wt/prs.test.d.ts.map +0 -1
  62. package/dist/cli/wt/prs.test.js +0 -410
  63. package/dist/cli/wt/prs.test.js.map +0 -1
  64. package/dist/cli/wt/run-command.test.d.ts +0 -5
  65. package/dist/cli/wt/run-command.test.d.ts.map +0 -1
  66. package/dist/cli/wt/run-command.test.js +0 -88
  67. package/dist/cli/wt/run-command.test.js.map +0 -1
  68. package/dist/cli/wt/state.test.d.ts +0 -9
  69. package/dist/cli/wt/state.test.d.ts.map +0 -1
  70. package/dist/cli/wt/state.test.js +0 -127
  71. package/dist/cli/wt/state.test.js.map +0 -1
  72. package/dist/cli/wt/wt.test.d.ts +0 -8
  73. package/dist/cli/wt/wt.test.d.ts.map +0 -1
  74. package/dist/cli/wt/wt.test.js +0 -739
  75. package/dist/cli/wt/wt.test.js.map +0 -1
  76. package/dist/cli/wt.unit.test.d.ts +0 -7
  77. package/dist/cli/wt.unit.test.d.ts.map +0 -1
  78. package/dist/cli/wt.unit.test.js +0 -160
  79. package/dist/cli/wt.unit.test.js.map +0 -1
  80. package/dist/cli/wtconfig.test.d.ts +0 -5
  81. package/dist/cli/wtconfig.test.d.ts.map +0 -1
  82. package/dist/cli/wtconfig.test.js +0 -1289
  83. package/dist/cli/wtconfig.test.js.map +0 -1
  84. package/dist/cli/wtlink.test.d.ts +0 -2
  85. package/dist/cli/wtlink.test.d.ts.map +0 -1
  86. package/dist/cli/wtlink.test.js +0 -249
  87. package/dist/cli/wtlink.test.js.map +0 -1
  88. package/dist/cli/wtstate.test.d.ts +0 -5
  89. package/dist/cli/wtstate.test.d.ts.map +0 -1
  90. package/dist/cli/wtstate.test.js +0 -193
  91. package/dist/cli/wtstate.test.js.map +0 -1
  92. package/dist/e2e/cleanpr/cleanpr.e2e.test.d.ts +0 -2
  93. package/dist/e2e/cleanpr/cleanpr.e2e.test.d.ts.map +0 -1
  94. package/dist/e2e/cleanpr/cleanpr.e2e.test.js +0 -326
  95. package/dist/e2e/cleanpr/cleanpr.e2e.test.js.map +0 -1
  96. package/dist/e2e/cli.e2e.test.d.ts +0 -2
  97. package/dist/e2e/cli.e2e.test.d.ts.map +0 -1
  98. package/dist/e2e/cli.e2e.test.js +0 -417
  99. package/dist/e2e/cli.e2e.test.js.map +0 -1
  100. package/dist/e2e/lswt/lswt.e2e.test.d.ts +0 -2
  101. package/dist/e2e/lswt/lswt.e2e.test.d.ts.map +0 -1
  102. package/dist/e2e/lswt/lswt.e2e.test.js +0 -361
  103. package/dist/e2e/lswt/lswt.e2e.test.js.map +0 -1
  104. package/dist/e2e/newpr/newpr.e2e.test.d.ts +0 -2
  105. package/dist/e2e/newpr/newpr.e2e.test.d.ts.map +0 -1
  106. package/dist/e2e/newpr/newpr.e2e.test.js +0 -286
  107. package/dist/e2e/newpr/newpr.e2e.test.js.map +0 -1
  108. package/dist/e2e/newpr/scenarios.e2e.test.d.ts +0 -2
  109. package/dist/e2e/newpr/scenarios.e2e.test.d.ts.map +0 -1
  110. package/dist/e2e/newpr/scenarios.e2e.test.js +0 -426
  111. package/dist/e2e/newpr/scenarios.e2e.test.js.map +0 -1
  112. package/dist/e2e/newpr-full-flow.e2e.test.d.ts +0 -2
  113. package/dist/e2e/newpr-full-flow.e2e.test.d.ts.map +0 -1
  114. package/dist/e2e/newpr-full-flow.e2e.test.js +0 -280
  115. package/dist/e2e/newpr-full-flow.e2e.test.js.map +0 -1
  116. package/dist/e2e/prs/prs.e2e.test.d.ts +0 -7
  117. package/dist/e2e/prs/prs.e2e.test.d.ts.map +0 -1
  118. package/dist/e2e/prs/prs.e2e.test.js +0 -606
  119. package/dist/e2e/prs/prs.e2e.test.js.map +0 -1
  120. package/dist/e2e/workflows/pr-lifecycle.e2e.test.d.ts +0 -2
  121. package/dist/e2e/workflows/pr-lifecycle.e2e.test.d.ts.map +0 -1
  122. package/dist/e2e/workflows/pr-lifecycle.e2e.test.js +0 -298
  123. package/dist/e2e/workflows/pr-lifecycle.e2e.test.js.map +0 -1
  124. package/dist/e2e/wt/interactive-menu.e2e.test.d.ts +0 -8
  125. package/dist/e2e/wt/interactive-menu.e2e.test.d.ts.map +0 -1
  126. package/dist/e2e/wt/interactive-menu.e2e.test.js +0 -583
  127. package/dist/e2e/wt/interactive-menu.e2e.test.js.map +0 -1
  128. package/dist/e2e/wt/wt.e2e.test.d.ts +0 -9
  129. package/dist/e2e/wt/wt.e2e.test.d.ts.map +0 -1
  130. package/dist/e2e/wt/wt.e2e.test.js +0 -597
  131. package/dist/e2e/wt/wt.e2e.test.js.map +0 -1
  132. package/dist/e2e/wtlink/wtlink.e2e.test.d.ts +0 -2
  133. package/dist/e2e/wtlink/wtlink.e2e.test.d.ts.map +0 -1
  134. package/dist/e2e/wtlink/wtlink.e2e.test.js +0 -416
  135. package/dist/e2e/wtlink/wtlink.e2e.test.js.map +0 -1
  136. package/dist/integration/git.integration.test.d.ts +0 -2
  137. package/dist/integration/git.integration.test.d.ts.map +0 -1
  138. package/dist/integration/git.integration.test.js +0 -336
  139. package/dist/integration/git.integration.test.js.map +0 -1
  140. package/dist/integration/lswt-remote-pr.integration.test.d.ts +0 -2
  141. package/dist/integration/lswt-remote-pr.integration.test.d.ts.map +0 -1
  142. package/dist/integration/lswt-remote-pr.integration.test.js +0 -222
  143. package/dist/integration/lswt-remote-pr.integration.test.js.map +0 -1
  144. package/dist/integration/newpr-branchfrom-head.integration.test.d.ts +0 -2
  145. package/dist/integration/newpr-branchfrom-head.integration.test.d.ts.map +0 -1
  146. package/dist/integration/newpr-branchfrom-head.integration.test.js +0 -498
  147. package/dist/integration/newpr-branchfrom-head.integration.test.js.map +0 -1
  148. package/dist/integration/newpr.integration.test.d.ts +0 -2
  149. package/dist/integration/newpr.integration.test.d.ts.map +0 -1
  150. package/dist/integration/newpr.integration.test.js +0 -460
  151. package/dist/integration/newpr.integration.test.js.map +0 -1
  152. package/dist/integration/prs.integration.test.d.ts +0 -8
  153. package/dist/integration/prs.integration.test.d.ts.map +0 -1
  154. package/dist/integration/prs.integration.test.js +0 -478
  155. package/dist/integration/prs.integration.test.js.map +0 -1
  156. package/dist/lib/ai/base-provider.test.d.ts +0 -7
  157. package/dist/lib/ai/base-provider.test.d.ts.map +0 -1
  158. package/dist/lib/ai/base-provider.test.js +0 -319
  159. package/dist/lib/ai/base-provider.test.js.map +0 -1
  160. package/dist/lib/ai/cli-provider.test.d.ts +0 -5
  161. package/dist/lib/ai/cli-provider.test.d.ts.map +0 -1
  162. package/dist/lib/ai/cli-provider.test.js +0 -460
  163. package/dist/lib/ai/cli-provider.test.js.map +0 -1
  164. package/dist/lib/ai/fallback-provider.test.d.ts +0 -7
  165. package/dist/lib/ai/fallback-provider.test.d.ts.map +0 -1
  166. package/dist/lib/ai/fallback-provider.test.js +0 -165
  167. package/dist/lib/ai/fallback-provider.test.js.map +0 -1
  168. package/dist/lib/ai/generation-service.test.d.ts +0 -7
  169. package/dist/lib/ai/generation-service.test.d.ts.map +0 -1
  170. package/dist/lib/ai/generation-service.test.js +0 -213
  171. package/dist/lib/ai/generation-service.test.js.map +0 -1
  172. package/dist/lib/ai/provider-manager.test.d.ts +0 -5
  173. package/dist/lib/ai/provider-manager.test.d.ts.map +0 -1
  174. package/dist/lib/ai/provider-manager.test.js +0 -312
  175. package/dist/lib/ai/provider-manager.test.js.map +0 -1
  176. package/dist/lib/ai/repo-docs.test.d.ts +0 -5
  177. package/dist/lib/ai/repo-docs.test.d.ts.map +0 -1
  178. package/dist/lib/ai/repo-docs.test.js +0 -357
  179. package/dist/lib/ai/repo-docs.test.js.map +0 -1
  180. package/dist/lib/cleanpr/args.test.d.ts +0 -2
  181. package/dist/lib/cleanpr/args.test.d.ts.map +0 -1
  182. package/dist/lib/cleanpr/args.test.js +0 -269
  183. package/dist/lib/cleanpr/args.test.js.map +0 -1
  184. package/dist/lib/cleanpr/cleanup.test.d.ts +0 -2
  185. package/dist/lib/cleanpr/cleanup.test.d.ts.map +0 -1
  186. package/dist/lib/cleanpr/cleanup.test.js +0 -296
  187. package/dist/lib/cleanpr/cleanup.test.js.map +0 -1
  188. package/dist/lib/cleanpr/worktree-info.test.d.ts +0 -2
  189. package/dist/lib/cleanpr/worktree-info.test.d.ts.map +0 -1
  190. package/dist/lib/cleanpr/worktree-info.test.js +0 -228
  191. package/dist/lib/cleanpr/worktree-info.test.js.map +0 -1
  192. package/dist/lib/colors.test.d.ts +0 -2
  193. package/dist/lib/colors.test.d.ts.map +0 -1
  194. package/dist/lib/colors.test.js +0 -142
  195. package/dist/lib/colors.test.js.map +0 -1
  196. package/dist/lib/config-editor.test.d.ts +0 -11
  197. package/dist/lib/config-editor.test.d.ts.map +0 -1
  198. package/dist/lib/config-editor.test.js +0 -526
  199. package/dist/lib/config-editor.test.js.map +0 -1
  200. package/dist/lib/config-migration/detector.test.d.ts +0 -5
  201. package/dist/lib/config-migration/detector.test.d.ts.map +0 -1
  202. package/dist/lib/config-migration/detector.test.js +0 -201
  203. package/dist/lib/config-migration/detector.test.js.map +0 -1
  204. package/dist/lib/config-migration/reporter.test.d.ts +0 -5
  205. package/dist/lib/config-migration/reporter.test.d.ts.map +0 -1
  206. package/dist/lib/config-migration/reporter.test.js +0 -305
  207. package/dist/lib/config-migration/reporter.test.js.map +0 -1
  208. package/dist/lib/config-migration/runner.test.d.ts +0 -5
  209. package/dist/lib/config-migration/runner.test.d.ts.map +0 -1
  210. package/dist/lib/config-migration/runner.test.js +0 -235
  211. package/dist/lib/config-migration/runner.test.js.map +0 -1
  212. package/dist/lib/config-validation.test.d.ts +0 -5
  213. package/dist/lib/config-validation.test.d.ts.map +0 -1
  214. package/dist/lib/config-validation.test.js +0 -423
  215. package/dist/lib/config-validation.test.js.map +0 -1
  216. package/dist/lib/config.test.d.ts +0 -2
  217. package/dist/lib/config.test.d.ts.map +0 -1
  218. package/dist/lib/config.test.js +0 -554
  219. package/dist/lib/config.test.js.map +0 -1
  220. package/dist/lib/constants.test.d.ts +0 -5
  221. package/dist/lib/constants.test.d.ts.map +0 -1
  222. package/dist/lib/constants.test.js +0 -180
  223. package/dist/lib/constants.test.js.map +0 -1
  224. package/dist/lib/deprecation.test.d.ts +0 -2
  225. package/dist/lib/deprecation.test.d.ts.map +0 -1
  226. package/dist/lib/deprecation.test.js +0 -71
  227. package/dist/lib/deprecation.test.js.map +0 -1
  228. package/dist/lib/errors.test.d.ts +0 -2
  229. package/dist/lib/errors.test.d.ts.map +0 -1
  230. package/dist/lib/errors.test.js +0 -117
  231. package/dist/lib/errors.test.js.map +0 -1
  232. package/dist/lib/git.test.d.ts +0 -2
  233. package/dist/lib/git.test.d.ts.map +0 -1
  234. package/dist/lib/git.test.js +0 -608
  235. package/dist/lib/git.test.js.map +0 -1
  236. package/dist/lib/github.test.d.ts +0 -2
  237. package/dist/lib/github.test.d.ts.map +0 -1
  238. package/dist/lib/github.test.js +0 -441
  239. package/dist/lib/github.test.js.map +0 -1
  240. package/dist/lib/global-check.test.d.ts +0 -5
  241. package/dist/lib/global-check.test.d.ts.map +0 -1
  242. package/dist/lib/global-check.test.js +0 -150
  243. package/dist/lib/global-check.test.js.map +0 -1
  244. package/dist/lib/global-config.test.d.ts +0 -5
  245. package/dist/lib/global-config.test.d.ts.map +0 -1
  246. package/dist/lib/global-config.test.js +0 -282
  247. package/dist/lib/global-config.test.js.map +0 -1
  248. package/dist/lib/hooks/confirmation.test.d.ts +0 -7
  249. package/dist/lib/hooks/confirmation.test.d.ts.map +0 -1
  250. package/dist/lib/hooks/confirmation.test.js +0 -300
  251. package/dist/lib/hooks/confirmation.test.js.map +0 -1
  252. package/dist/lib/hooks/executor.test.d.ts +0 -5
  253. package/dist/lib/hooks/executor.test.d.ts.map +0 -1
  254. package/dist/lib/hooks/executor.test.js +0 -648
  255. package/dist/lib/hooks/executor.test.js.map +0 -1
  256. package/dist/lib/hooks/templates.test.d.ts +0 -5
  257. package/dist/lib/hooks/templates.test.d.ts.map +0 -1
  258. package/dist/lib/hooks/templates.test.js +0 -163
  259. package/dist/lib/hooks/templates.test.js.map +0 -1
  260. package/dist/lib/hooks/types.test.d.ts +0 -5
  261. package/dist/lib/hooks/types.test.d.ts.map +0 -1
  262. package/dist/lib/hooks/types.test.js +0 -132
  263. package/dist/lib/hooks/types.test.js.map +0 -1
  264. package/dist/lib/json-output.test.d.ts +0 -5
  265. package/dist/lib/json-output.test.d.ts.map +0 -1
  266. package/dist/lib/json-output.test.js +0 -261
  267. package/dist/lib/json-output.test.js.map +0 -1
  268. package/dist/lib/logger.test.d.ts +0 -14
  269. package/dist/lib/logger.test.d.ts.map +0 -1
  270. package/dist/lib/logger.test.js +0 -692
  271. package/dist/lib/logger.test.js.map +0 -1
  272. package/dist/lib/lswt/action-executors.test.d.ts +0 -2
  273. package/dist/lib/lswt/action-executors.test.d.ts.map +0 -1
  274. package/dist/lib/lswt/action-executors.test.js +0 -1127
  275. package/dist/lib/lswt/action-executors.test.js.map +0 -1
  276. package/dist/lib/lswt/actions.test.d.ts +0 -2
  277. package/dist/lib/lswt/actions.test.d.ts.map +0 -1
  278. package/dist/lib/lswt/actions.test.js +0 -497
  279. package/dist/lib/lswt/actions.test.js.map +0 -1
  280. package/dist/lib/lswt/args.test.d.ts +0 -2
  281. package/dist/lib/lswt/args.test.d.ts.map +0 -1
  282. package/dist/lib/lswt/args.test.js +0 -195
  283. package/dist/lib/lswt/args.test.js.map +0 -1
  284. package/dist/lib/lswt/environment.test.d.ts +0 -2
  285. package/dist/lib/lswt/environment.test.d.ts.map +0 -1
  286. package/dist/lib/lswt/environment.test.js +0 -544
  287. package/dist/lib/lswt/environment.test.js.map +0 -1
  288. package/dist/lib/lswt/formatters.test.d.ts +0 -2
  289. package/dist/lib/lswt/formatters.test.d.ts.map +0 -1
  290. package/dist/lib/lswt/formatters.test.js +0 -323
  291. package/dist/lib/lswt/formatters.test.js.map +0 -1
  292. package/dist/lib/lswt/fuzzy-search.test.d.ts +0 -5
  293. package/dist/lib/lswt/fuzzy-search.test.d.ts.map +0 -1
  294. package/dist/lib/lswt/fuzzy-search.test.js +0 -207
  295. package/dist/lib/lswt/fuzzy-search.test.js.map +0 -1
  296. package/dist/lib/lswt/interactive.test.d.ts +0 -2
  297. package/dist/lib/lswt/interactive.test.d.ts.map +0 -1
  298. package/dist/lib/lswt/interactive.test.js +0 -771
  299. package/dist/lib/lswt/interactive.test.js.map +0 -1
  300. package/dist/lib/lswt/table.test.d.ts +0 -5
  301. package/dist/lib/lswt/table.test.d.ts.map +0 -1
  302. package/dist/lib/lswt/table.test.js +0 -262
  303. package/dist/lib/lswt/table.test.js.map +0 -1
  304. package/dist/lib/lswt/worktree-info.test.d.ts +0 -2
  305. package/dist/lib/lswt/worktree-info.test.d.ts.map +0 -1
  306. package/dist/lib/lswt/worktree-info.test.js +0 -484
  307. package/dist/lib/lswt/worktree-info.test.js.map +0 -1
  308. package/dist/lib/newpr/action-deps.test.d.ts +0 -5
  309. package/dist/lib/newpr/action-deps.test.d.ts.map +0 -1
  310. package/dist/lib/newpr/action-deps.test.js +0 -111
  311. package/dist/lib/newpr/action-deps.test.js.map +0 -1
  312. package/dist/lib/newpr/actions.test.d.ts +0 -2
  313. package/dist/lib/newpr/actions.test.d.ts.map +0 -1
  314. package/dist/lib/newpr/actions.test.js +0 -254
  315. package/dist/lib/newpr/actions.test.js.map +0 -1
  316. package/dist/lib/newpr/args.test.d.ts +0 -2
  317. package/dist/lib/newpr/args.test.d.ts.map +0 -1
  318. package/dist/lib/newpr/args.test.js +0 -479
  319. package/dist/lib/newpr/args.test.js.map +0 -1
  320. package/dist/lib/newpr/hook-runner.test.d.ts +0 -7
  321. package/dist/lib/newpr/hook-runner.test.d.ts.map +0 -1
  322. package/dist/lib/newpr/hook-runner.test.js +0 -422
  323. package/dist/lib/newpr/hook-runner.test.js.map +0 -1
  324. package/dist/lib/newpr/plan-generator.test.d.ts +0 -7
  325. package/dist/lib/newpr/plan-generator.test.d.ts.map +0 -1
  326. package/dist/lib/newpr/plan-generator.test.js +0 -387
  327. package/dist/lib/newpr/plan-generator.test.js.map +0 -1
  328. package/dist/lib/newpr/scenario-handler.test.d.ts +0 -2
  329. package/dist/lib/newpr/scenario-handler.test.d.ts.map +0 -1
  330. package/dist/lib/newpr/scenario-handler.test.js +0 -256
  331. package/dist/lib/newpr/scenario-handler.test.js.map +0 -1
  332. package/dist/lib/prompts.test.d.ts +0 -2
  333. package/dist/lib/prompts.test.d.ts.map +0 -1
  334. package/dist/lib/prompts.test.js +0 -807
  335. package/dist/lib/prompts.test.js.map +0 -1
  336. package/dist/lib/prs/actions.test.d.ts +0 -5
  337. package/dist/lib/prs/actions.test.d.ts.map +0 -1
  338. package/dist/lib/prs/actions.test.js +0 -356
  339. package/dist/lib/prs/actions.test.js.map +0 -1
  340. package/dist/lib/prs/command.test.d.ts +0 -11
  341. package/dist/lib/prs/command.test.d.ts.map +0 -1
  342. package/dist/lib/prs/command.test.js +0 -409
  343. package/dist/lib/prs/command.test.js.map +0 -1
  344. package/dist/lib/prs/data.test.d.ts +0 -5
  345. package/dist/lib/prs/data.test.d.ts.map +0 -1
  346. package/dist/lib/prs/data.test.js +0 -417
  347. package/dist/lib/prs/data.test.js.map +0 -1
  348. package/dist/lib/prs/details.test.d.ts +0 -5
  349. package/dist/lib/prs/details.test.d.ts.map +0 -1
  350. package/dist/lib/prs/details.test.js +0 -325
  351. package/dist/lib/prs/details.test.js.map +0 -1
  352. package/dist/lib/prs/filters.test.d.ts +0 -5
  353. package/dist/lib/prs/filters.test.d.ts.map +0 -1
  354. package/dist/lib/prs/filters.test.js +0 -312
  355. package/dist/lib/prs/filters.test.js.map +0 -1
  356. package/dist/lib/prs/formatters.test.d.ts +0 -2
  357. package/dist/lib/prs/formatters.test.d.ts.map +0 -1
  358. package/dist/lib/prs/formatters.test.js +0 -387
  359. package/dist/lib/prs/formatters.test.js.map +0 -1
  360. package/dist/lib/prs/interactive.test.d.ts +0 -5
  361. package/dist/lib/prs/interactive.test.d.ts.map +0 -1
  362. package/dist/lib/prs/interactive.test.js +0 -517
  363. package/dist/lib/prs/interactive.test.js.map +0 -1
  364. package/dist/lib/schema.test.d.ts +0 -10
  365. package/dist/lib/schema.test.d.ts.map +0 -1
  366. package/dist/lib/schema.test.js +0 -309
  367. package/dist/lib/schema.test.js.map +0 -1
  368. package/dist/lib/state-detection.test.d.ts +0 -2
  369. package/dist/lib/state-detection.test.d.ts.map +0 -1
  370. package/dist/lib/state-detection.test.js +0 -451
  371. package/dist/lib/state-detection.test.js.map +0 -1
  372. package/dist/lib/ui/error.test.d.ts +0 -2
  373. package/dist/lib/ui/error.test.d.ts.map +0 -1
  374. package/dist/lib/ui/error.test.js +0 -143
  375. package/dist/lib/ui/error.test.js.map +0 -1
  376. package/dist/lib/ui/output.test.d.ts +0 -2
  377. package/dist/lib/ui/output.test.d.ts.map +0 -1
  378. package/dist/lib/ui/output.test.js +0 -59
  379. package/dist/lib/ui/output.test.js.map +0 -1
  380. package/dist/lib/ui/status.test.d.ts +0 -2
  381. package/dist/lib/ui/status.test.d.ts.map +0 -1
  382. package/dist/lib/ui/status.test.js +0 -158
  383. package/dist/lib/ui/status.test.js.map +0 -1
  384. package/dist/lib/ui/table.test.d.ts +0 -2
  385. package/dist/lib/ui/table.test.d.ts.map +0 -1
  386. package/dist/lib/ui/table.test.js +0 -115
  387. package/dist/lib/ui/table.test.js.map +0 -1
  388. package/dist/lib/ui/theme.test.d.ts +0 -2
  389. package/dist/lib/ui/theme.test.d.ts.map +0 -1
  390. package/dist/lib/ui/theme.test.js +0 -76
  391. package/dist/lib/ui/theme.test.js.map +0 -1
  392. package/dist/lib/wtconfig/config-manager.test.d.ts +0 -5
  393. package/dist/lib/wtconfig/config-manager.test.d.ts.map +0 -1
  394. package/dist/lib/wtconfig/config-manager.test.js +0 -501
  395. package/dist/lib/wtconfig/config-manager.test.js.map +0 -1
  396. package/dist/lib/wtconfig/environment.test.d.ts +0 -5
  397. package/dist/lib/wtconfig/environment.test.d.ts.map +0 -1
  398. package/dist/lib/wtconfig/environment.test.js +0 -285
  399. package/dist/lib/wtconfig/environment.test.js.map +0 -1
  400. package/dist/lib/wtlink/config-manifest.test.d.ts +0 -2
  401. package/dist/lib/wtlink/config-manifest.test.d.ts.map +0 -1
  402. package/dist/lib/wtlink/config-manifest.test.js +0 -486
  403. package/dist/lib/wtlink/config-manifest.test.js.map +0 -1
  404. package/dist/lib/wtlink/link-configs.test.d.ts +0 -2
  405. package/dist/lib/wtlink/link-configs.test.d.ts.map +0 -1
  406. package/dist/lib/wtlink/link-configs.test.js +0 -612
  407. package/dist/lib/wtlink/link-configs.test.js.map +0 -1
  408. package/dist/lib/wtlink/main-menu.test.d.ts +0 -5
  409. package/dist/lib/wtlink/main-menu.test.d.ts.map +0 -1
  410. package/dist/lib/wtlink/main-menu.test.js +0 -126
  411. package/dist/lib/wtlink/main-menu.test.js.map +0 -1
  412. package/dist/lib/wtlink/manage-manifest.test.d.ts +0 -2
  413. package/dist/lib/wtlink/manage-manifest.test.d.ts.map +0 -1
  414. package/dist/lib/wtlink/manage-manifest.test.js +0 -714
  415. package/dist/lib/wtlink/manage-manifest.test.js.map +0 -1
  416. package/dist/lib/wtlink/validate-manifest.test.d.ts +0 -2
  417. package/dist/lib/wtlink/validate-manifest.test.d.ts.map +0 -1
  418. package/dist/lib/wtlink/validate-manifest.test.js +0 -220
  419. package/dist/lib/wtlink/validate-manifest.test.js.map +0 -1
  420. package/dist/lib/wtstate/analyze.test.d.ts +0 -5
  421. package/dist/lib/wtstate/analyze.test.d.ts.map +0 -1
  422. package/dist/lib/wtstate/analyze.test.js +0 -282
  423. package/dist/lib/wtstate/analyze.test.js.map +0 -1
  424. package/dist/lib/wtstate/args.test.d.ts +0 -5
  425. package/dist/lib/wtstate/args.test.d.ts.map +0 -1
  426. package/dist/lib/wtstate/args.test.js +0 -120
  427. package/dist/lib/wtstate/args.test.js.map +0 -1
  428. package/dist/mcp/server.test.d.ts +0 -9
  429. package/dist/mcp/server.test.d.ts.map +0 -1
  430. package/dist/mcp/server.test.js +0 -550
  431. package/dist/mcp/server.test.js.map +0 -1
@@ -1,796 +0,0 @@
1
- /**
2
- * Integration tests for interactive menu flows
3
- *
4
- * These tests verify that each menu flow:
5
- * 1. Gathers the correct user inputs
6
- * 2. Calls the correct library functions with proper arguments
7
- * 3. Returns to menu after operation execution (not exit)
8
- * 4. Handles cancellation and back navigation correctly
9
- * 5. Uses direct library calls (no subprocess spawning)
10
- */
11
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
12
- // Mock modules before importing the module under test
13
- vi.mock('../../lib/prompts.js', () => {
14
- // Define UserNavigatedBack inside the factory to avoid hoisting issues
15
- class MockUserNavigatedBack extends Error {
16
- constructor() {
17
- super('User navigated back');
18
- this.name = 'UserNavigatedBack';
19
- }
20
- }
21
- return {
22
- promptChoice: vi.fn(),
23
- promptInput: vi.fn(),
24
- promptConfirm: vi.fn(),
25
- UserNavigatedBack: MockUserNavigatedBack,
26
- };
27
- });
28
- vi.mock('../../lib/config.js', () => ({
29
- loadConfig: vi.fn(() => ({
30
- configVersion: 1,
31
- sharedRepos: [],
32
- baseBranch: 'main',
33
- draftPr: true,
34
- worktreePattern: '{repo}.pr{number}',
35
- worktreeParent: '..',
36
- syncPatterns: [],
37
- branchPrefix: 'feat',
38
- previewLabel: 'preview',
39
- preferredEditor: 'vscode',
40
- ai: {
41
- provider: 'auto',
42
- fallback: 'none',
43
- branchName: false,
44
- prTitle: false,
45
- prDescription: false,
46
- commitMessage: false,
47
- planDocument: false,
48
- },
49
- hooks: {},
50
- hookDefaults: { timeout: 30000, maxTimeout: 60000 },
51
- plugins: [],
52
- generators: {},
53
- integrations: {},
54
- logging: { level: 'info', timestamps: true },
55
- global: { warnNotGlobal: true },
56
- wtlink: { enabled: [], disabled: [] },
57
- })),
58
- }));
59
- vi.mock('../../lib/git.js', () => ({
60
- getRepoRoot: vi.fn(() => '/mock/repo'),
61
- listLocalBranches: vi.fn(() => ['feat/existing-branch', 'fix/bug-fix', 'main', 'develop']),
62
- removeWorktree: vi.fn(),
63
- pruneWorktrees: vi.fn(),
64
- }));
65
- vi.mock('../../lib/wtlink/config-manifest.js', () => ({
66
- loadManifestData: vi.fn(() => ({
67
- enabled: ['.env', '.env.local'],
68
- disabled: ['config.json'],
69
- source: 'config',
70
- })),
71
- saveManifestData: vi.fn(),
72
- }));
73
- // Mock direct library imports
74
- vi.mock('../../lib/lswt/index.js', () => ({
75
- gatherWorktreeInfo: vi.fn(async () => []),
76
- createDefaultDeps: vi.fn(() => ({})),
77
- runInteractiveMode: vi.fn(async () => { }),
78
- }));
79
- vi.mock('../../lib/prs/command.js', () => ({
80
- runPrsCommand: vi.fn(async () => { }),
81
- }));
82
- vi.mock('../newpr.js', () => ({
83
- runNewprHandler: vi.fn(async () => { }),
84
- }));
85
- vi.mock('../../lib/cleanpr/index.js', () => ({
86
- gatherPrWorktreeInfo: vi.fn(async () => []),
87
- createDefaultDeps: vi.fn(() => ({})),
88
- getCleanableWorktrees: vi.fn(() => []),
89
- cleanWorktree: vi.fn(() => ({ success: true, message: 'Cleaned', prNumber: 42 })),
90
- findWorktreeByPrNumber: vi.fn(() => null),
91
- summarizeResults: vi.fn(() => ({ cleaned: 0, total: 0 })),
92
- }));
93
- vi.mock('../../lib/wtstate/index.js', () => ({
94
- analyzeState: vi.fn(() => ({
95
- scenario: 'main_clean_same',
96
- scenarioDescription: 'On main, clean, same as origin',
97
- currentBranch: 'main',
98
- baseBranch: 'main',
99
- worktreeType: 'main_worktree',
100
- hasChanges: false,
101
- hasStagedChanges: false,
102
- hasUnstagedChanges: false,
103
- localCommits: 0,
104
- stagedFiles: [],
105
- unstagedFiles: [],
106
- availableActions: [],
107
- recommendedAction: null,
108
- })),
109
- formatText: vi.fn(() => 'State: main_clean_same'),
110
- }));
111
- vi.mock('../../lib/wtlink/link-configs.js', () => ({
112
- run: vi.fn(async () => { }),
113
- }));
114
- vi.mock('../../lib/wtlink/validate-manifest.js', () => ({
115
- run: vi.fn(() => { }),
116
- }));
117
- vi.mock('../../lib/wtconfig/index.js', () => ({
118
- formatConfigDisplay: vi.fn(() => '{ baseBranch: "main" }'),
119
- setConfigValue: vi.fn((config, _key, _value) => config),
120
- loadRepoConfig: vi.fn(() => ({})),
121
- saveRepoConfig: vi.fn(),
122
- validateConfig: vi.fn(() => ({ valid: true, errors: [], warnings: [] })),
123
- }));
124
- vi.mock('../../lib/constants.js', () => ({
125
- DEFAULT_MANIFEST_FILE: '.wtlinkrc',
126
- }));
127
- vi.mock('../../lib/ui/index.js', () => ({
128
- printStatus: vi.fn(),
129
- }));
130
- vi.mock('child_process', () => ({
131
- execSync: vi.fn(),
132
- }));
133
- // Import mocked modules
134
- import { promptChoice, promptInput, promptConfirm } from '../../lib/prompts.js';
135
- import { loadConfig } from '../../lib/config.js';
136
- import * as git from '../../lib/git.js';
137
- import { loadManifestData, saveManifestData } from '../../lib/wtlink/config-manifest.js';
138
- import { gatherWorktreeInfo, runInteractiveMode } from '../../lib/lswt/index.js';
139
- import { runPrsCommand } from '../../lib/prs/command.js';
140
- import { runNewprHandler } from '../newpr.js';
141
- import { gatherPrWorktreeInfo, getCleanableWorktrees, } from '../../lib/cleanpr/index.js';
142
- import { analyzeState, formatText } from '../../lib/wtstate/index.js';
143
- import { run as runWtlinkLink } from '../../lib/wtlink/link-configs.js';
144
- import { run as runWtlinkValidate } from '../../lib/wtlink/validate-manifest.js';
145
- import { formatConfigDisplay, setConfigValue, loadRepoConfig, saveRepoConfig, } from '../../lib/wtconfig/index.js';
146
- // Import flows after mocks are set up
147
- import { flows, showMainMenu } from './interactive-menu.js';
148
- // Mock console.log to keep test output clean
149
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => { });
150
- describe('Interactive Menu Flows', () => {
151
- beforeEach(() => {
152
- vi.clearAllMocks();
153
- });
154
- afterEach(() => {
155
- consoleSpy.mockClear();
156
- });
157
- describe('handleListWorktrees', () => {
158
- it('calls gatherWorktreeInfo and runInteractiveMode and returns to menu', async () => {
159
- const result = await flows.handleListWorktrees();
160
- expect(gatherWorktreeInfo).toHaveBeenCalledWith('/mock/repo', { verbose: false, json: false, showStatus: false }, expect.anything());
161
- expect(runInteractiveMode).toHaveBeenCalled();
162
- expect(result).toEqual({ completed: true, returnToMenu: true });
163
- });
164
- it('returns to menu with error message when library call fails', async () => {
165
- vi.mocked(gatherWorktreeInfo).mockRejectedValueOnce(new Error('git error'));
166
- const result = await flows.handleListWorktrees();
167
- expect(result).toEqual({ completed: true, returnToMenu: true });
168
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('git error'));
169
- });
170
- });
171
- describe('handleBrowsePRs', () => {
172
- it('calls runPrsCommand and returns to menu', async () => {
173
- const result = await flows.handleBrowsePRs();
174
- expect(runPrsCommand).toHaveBeenCalledWith({
175
- state: 'open',
176
- limit: 50,
177
- json: false,
178
- noInteractive: false,
179
- });
180
- expect(result).toEqual({ completed: true, returnToMenu: true });
181
- });
182
- });
183
- describe('handleShowState', () => {
184
- it('calls analyzeState and formatText and returns to menu', async () => {
185
- const result = await flows.handleShowState();
186
- expect(analyzeState).toHaveBeenCalledWith({
187
- verbose: false,
188
- json: false,
189
- baseBranch: 'main',
190
- });
191
- expect(formatText).toHaveBeenCalled();
192
- expect(result).toEqual({ completed: true, returnToMenu: true });
193
- });
194
- });
195
- describe('handleNewPR', () => {
196
- it('returns CANCELLED when user selects back', async () => {
197
- vi.mocked(promptChoice).mockResolvedValueOnce('back');
198
- const result = await flows.handleNewPR();
199
- expect(result).toEqual({ completed: false, returnToMenu: true });
200
- expect(runNewprHandler).not.toHaveBeenCalled();
201
- });
202
- it('handles user cancellation (Ctrl+C)', async () => {
203
- vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
204
- const result = await flows.handleNewPR();
205
- expect(result).toEqual({ completed: false, returnToMenu: true });
206
- });
207
- describe('from-description flow', () => {
208
- it('gathers all inputs and calls runNewprHandler with correct Options', async () => {
209
- vi.mocked(promptChoice)
210
- .mockResolvedValueOnce('from-description') // New PR sub-menu
211
- .mockResolvedValueOnce(true); // Draft PR selection
212
- vi.mocked(promptInput)
213
- .mockResolvedValueOnce('Add dark mode support') // Description
214
- .mockResolvedValueOnce('main'); // Base branch
215
- vi.mocked(promptConfirm)
216
- .mockResolvedValueOnce(false) // Install deps
217
- .mockResolvedValueOnce(false); // Open VS Code
218
- const result = await flows.handleNewPR();
219
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
220
- mode: 'new',
221
- description: 'Add dark mode support',
222
- baseBranch: 'main',
223
- draft: true,
224
- installDeps: false,
225
- openEditor: false,
226
- }));
227
- expect(result).toEqual({ completed: true, returnToMenu: true });
228
- });
229
- it('passes ready flag when not draft', async () => {
230
- vi.mocked(promptChoice)
231
- .mockResolvedValueOnce('from-description')
232
- .mockResolvedValueOnce(false); // Ready for review (not draft)
233
- vi.mocked(promptInput)
234
- .mockResolvedValueOnce('Fix critical bug')
235
- .mockResolvedValueOnce('main');
236
- vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(false);
237
- const result = await flows.handleNewPR();
238
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
239
- mode: 'new',
240
- description: 'Fix critical bug',
241
- draft: false,
242
- }));
243
- expect(result).toEqual({ completed: true, returnToMenu: true });
244
- });
245
- it('passes non-main base branch', async () => {
246
- vi.mocked(promptChoice)
247
- .mockResolvedValueOnce('from-description')
248
- .mockResolvedValueOnce(true);
249
- vi.mocked(promptInput)
250
- .mockResolvedValueOnce('Feature work')
251
- .mockResolvedValueOnce('develop'); // Non-main base branch
252
- vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(false);
253
- const result = await flows.handleNewPR();
254
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
255
- baseBranch: 'develop',
256
- }));
257
- expect(result).toEqual({ completed: true, returnToMenu: true });
258
- });
259
- it('passes install flag when requested', async () => {
260
- vi.mocked(promptChoice)
261
- .mockResolvedValueOnce('from-description')
262
- .mockResolvedValueOnce(true);
263
- vi.mocked(promptInput).mockResolvedValueOnce('Add feature').mockResolvedValueOnce('main');
264
- vi.mocked(promptConfirm)
265
- .mockResolvedValueOnce(true) // Install deps
266
- .mockResolvedValueOnce(false);
267
- const result = await flows.handleNewPR();
268
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
269
- installDeps: true,
270
- }));
271
- expect(result).toEqual({ completed: true, returnToMenu: true });
272
- });
273
- it('passes code flag when requested', async () => {
274
- vi.mocked(promptChoice)
275
- .mockResolvedValueOnce('from-description')
276
- .mockResolvedValueOnce(true);
277
- vi.mocked(promptInput).mockResolvedValueOnce('Add feature').mockResolvedValueOnce('main');
278
- vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(true); // Open VS Code
279
- const result = await flows.handleNewPR();
280
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
281
- openEditor: true,
282
- }));
283
- expect(result).toEqual({ completed: true, returnToMenu: true });
284
- });
285
- it('passes all optional flags together', async () => {
286
- vi.mocked(promptChoice)
287
- .mockResolvedValueOnce('from-description')
288
- .mockResolvedValueOnce(false); // Ready
289
- vi.mocked(promptInput)
290
- .mockResolvedValueOnce('Full feature')
291
- .mockResolvedValueOnce('develop');
292
- vi.mocked(promptConfirm)
293
- .mockResolvedValueOnce(true) // Install
294
- .mockResolvedValueOnce(true); // VS Code
295
- const result = await flows.handleNewPR();
296
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
297
- mode: 'new',
298
- description: 'Full feature',
299
- baseBranch: 'develop',
300
- draft: false,
301
- installDeps: true,
302
- openEditor: true,
303
- }));
304
- expect(result).toEqual({ completed: true, returnToMenu: true });
305
- });
306
- it('returns CANCELLED when description is empty', async () => {
307
- vi.mocked(promptChoice).mockResolvedValueOnce('from-description');
308
- vi.mocked(promptInput).mockResolvedValueOnce(''); // Empty description
309
- const result = await flows.handleNewPR();
310
- expect(result).toEqual({ completed: false, returnToMenu: true });
311
- expect(runNewprHandler).not.toHaveBeenCalled();
312
- });
313
- it('handles user cancellation during input', async () => {
314
- vi.mocked(promptChoice).mockResolvedValueOnce('from-description');
315
- vi.mocked(promptInput).mockRejectedValueOnce(new Error('User cancelled'));
316
- const result = await flows.handleNewPR();
317
- expect(result).toEqual({ completed: false, returnToMenu: true });
318
- });
319
- });
320
- describe('from-pr flow', () => {
321
- it('gathers PR number and calls runNewprHandler with mode pr', async () => {
322
- vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
323
- vi.mocked(promptInput).mockResolvedValueOnce('42');
324
- vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(false);
325
- const result = await flows.handleNewPR();
326
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
327
- mode: 'pr',
328
- prNumber: 42,
329
- }));
330
- expect(result).toEqual({ completed: true, returnToMenu: true });
331
- });
332
- it('passes install and code flags', async () => {
333
- vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
334
- vi.mocked(promptInput).mockResolvedValueOnce('123');
335
- vi.mocked(promptConfirm)
336
- .mockResolvedValueOnce(true) // Install
337
- .mockResolvedValueOnce(true); // VS Code
338
- const result = await flows.handleNewPR();
339
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
340
- mode: 'pr',
341
- prNumber: 123,
342
- installDeps: true,
343
- openEditor: true,
344
- }));
345
- expect(result).toEqual({ completed: true, returnToMenu: true });
346
- });
347
- it('returns CANCELLED when PR number is empty', async () => {
348
- vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
349
- vi.mocked(promptInput).mockResolvedValueOnce('');
350
- const result = await flows.handleNewPR();
351
- expect(result).toEqual({ completed: false, returnToMenu: true });
352
- expect(runNewprHandler).not.toHaveBeenCalled();
353
- });
354
- it('returns CANCELLED when PR number is invalid', async () => {
355
- vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
356
- vi.mocked(promptInput).mockResolvedValueOnce('not-a-number');
357
- const result = await flows.handleNewPR();
358
- expect(result).toEqual({ completed: false, returnToMenu: true });
359
- expect(runNewprHandler).not.toHaveBeenCalled();
360
- });
361
- it('returns CANCELLED when PR number is zero', async () => {
362
- vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
363
- vi.mocked(promptInput).mockResolvedValueOnce('0');
364
- const result = await flows.handleNewPR();
365
- expect(result).toEqual({ completed: false, returnToMenu: true });
366
- expect(runNewprHandler).not.toHaveBeenCalled();
367
- });
368
- it('returns CANCELLED when PR number is negative', async () => {
369
- vi.mocked(promptChoice).mockResolvedValueOnce('from-pr');
370
- vi.mocked(promptInput).mockResolvedValueOnce('-5');
371
- const result = await flows.handleNewPR();
372
- expect(result).toEqual({ completed: false, returnToMenu: true });
373
- expect(runNewprHandler).not.toHaveBeenCalled();
374
- });
375
- });
376
- describe('from-branch flow', () => {
377
- it('allows selecting from existing branches', async () => {
378
- vi.mocked(promptChoice)
379
- .mockResolvedValueOnce('from-branch') // New PR sub-menu
380
- .mockResolvedValueOnce('feat/existing-branch') // Select branch
381
- .mockResolvedValueOnce(true); // Draft PR
382
- vi.mocked(promptInput).mockResolvedValueOnce('main');
383
- const result = await flows.handleNewPR();
384
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
385
- mode: 'branch',
386
- branchName: 'feat/existing-branch',
387
- }));
388
- expect(result).toEqual({ completed: true, returnToMenu: true });
389
- });
390
- it('allows typing custom branch name', async () => {
391
- vi.mocked(promptChoice)
392
- .mockResolvedValueOnce('from-branch')
393
- .mockResolvedValueOnce('__custom__') // Select custom option
394
- .mockResolvedValueOnce(true);
395
- vi.mocked(promptInput)
396
- .mockResolvedValueOnce('feat/my-new-branch') // Custom branch name
397
- .mockResolvedValueOnce('main');
398
- const result = await flows.handleNewPR();
399
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
400
- mode: 'branch',
401
- branchName: 'feat/my-new-branch',
402
- }));
403
- expect(result).toEqual({ completed: true, returnToMenu: true });
404
- });
405
- it('passes non-main base branch and ready flag', async () => {
406
- vi.mocked(promptChoice)
407
- .mockResolvedValueOnce('from-branch')
408
- .mockResolvedValueOnce('fix/bug-fix')
409
- .mockResolvedValueOnce(false); // Ready for review
410
- vi.mocked(promptInput).mockResolvedValueOnce('develop');
411
- const result = await flows.handleNewPR();
412
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
413
- mode: 'branch',
414
- branchName: 'fix/bug-fix',
415
- baseBranch: 'develop',
416
- draft: false,
417
- }));
418
- expect(result).toEqual({ completed: true, returnToMenu: true });
419
- });
420
- it('returns CANCELLED when branch name is empty', async () => {
421
- vi.mocked(promptChoice)
422
- .mockResolvedValueOnce('from-branch')
423
- .mockResolvedValueOnce('__custom__');
424
- vi.mocked(promptInput).mockResolvedValueOnce(''); // Empty branch name
425
- const result = await flows.handleNewPR();
426
- expect(result).toEqual({ completed: false, returnToMenu: true });
427
- expect(runNewprHandler).not.toHaveBeenCalled();
428
- });
429
- it('handles empty branch list gracefully', async () => {
430
- // Mock empty branch list
431
- vi.mocked(git.listLocalBranches).mockReturnValueOnce([]);
432
- vi.mocked(promptChoice).mockResolvedValueOnce('from-branch');
433
- vi.mocked(promptInput)
434
- .mockResolvedValueOnce('feat/new-branch') // Manual branch input
435
- .mockResolvedValueOnce('main');
436
- vi.mocked(promptChoice).mockResolvedValueOnce(true); // Draft
437
- const result = await flows.handleNewPR();
438
- // Should have prompted for branch name directly
439
- expect(promptInput).toHaveBeenCalledWith('Branch name');
440
- expect(result).toEqual({ completed: true, returnToMenu: true });
441
- });
442
- });
443
- });
444
- describe('handleCleanPRs', () => {
445
- it('returns CANCELLED when user selects back', async () => {
446
- vi.mocked(promptChoice).mockResolvedValueOnce('back');
447
- const result = await flows.handleCleanPRs();
448
- expect(result).toEqual({ completed: false, returnToMenu: true });
449
- expect(gatherPrWorktreeInfo).not.toHaveBeenCalled();
450
- });
451
- describe('clean-all', () => {
452
- it('calls cleanpr library after confirmation and returns to menu', async () => {
453
- vi.mocked(promptChoice).mockResolvedValueOnce('clean-all');
454
- vi.mocked(promptConfirm).mockResolvedValueOnce(true);
455
- const result = await flows.handleCleanPRs();
456
- expect(gatherPrWorktreeInfo).toHaveBeenCalled();
457
- expect(result).toEqual({ completed: true, returnToMenu: true });
458
- });
459
- it('returns CANCELLED when not confirmed', async () => {
460
- vi.mocked(promptChoice).mockResolvedValueOnce('clean-all');
461
- vi.mocked(promptConfirm).mockResolvedValueOnce(false);
462
- const result = await flows.handleCleanPRs();
463
- expect(result).toEqual({ completed: false, returnToMenu: true });
464
- expect(gatherPrWorktreeInfo).not.toHaveBeenCalled();
465
- });
466
- });
467
- describe('clean-specific', () => {
468
- it('calls cleanpr with PR number and returns to menu', async () => {
469
- vi.mocked(promptChoice).mockResolvedValueOnce('clean-specific');
470
- vi.mocked(promptInput).mockResolvedValueOnce('42');
471
- const result = await flows.handleCleanPRs();
472
- expect(gatherPrWorktreeInfo).toHaveBeenCalled();
473
- expect(result).toEqual({ completed: true, returnToMenu: true });
474
- });
475
- it('returns CANCELLED when PR number is empty', async () => {
476
- vi.mocked(promptChoice).mockResolvedValueOnce('clean-specific');
477
- vi.mocked(promptInput).mockResolvedValueOnce('');
478
- const result = await flows.handleCleanPRs();
479
- expect(result).toEqual({ completed: false, returnToMenu: true });
480
- });
481
- it('returns CANCELLED when PR number is invalid', async () => {
482
- vi.mocked(promptChoice).mockResolvedValueOnce('clean-specific');
483
- vi.mocked(promptInput).mockResolvedValueOnce('invalid');
484
- const result = await flows.handleCleanPRs();
485
- expect(result).toEqual({ completed: false, returnToMenu: true });
486
- });
487
- });
488
- describe('dry-run', () => {
489
- it('calls cleanpr with dry-run and returns to menu', async () => {
490
- vi.mocked(promptChoice).mockResolvedValueOnce('dry-run');
491
- const result = await flows.handleCleanPRs();
492
- expect(gatherPrWorktreeInfo).toHaveBeenCalled();
493
- expect(getCleanableWorktrees).toHaveBeenCalled();
494
- expect(result).toEqual({ completed: true, returnToMenu: true });
495
- });
496
- });
497
- it('handles user cancellation', async () => {
498
- vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
499
- const result = await flows.handleCleanPRs();
500
- expect(result).toEqual({ completed: false, returnToMenu: true });
501
- });
502
- });
503
- describe('handleLinkConfig', () => {
504
- it('returns CANCELLED when user selects back', async () => {
505
- vi.mocked(promptChoice).mockResolvedValueOnce('back');
506
- const result = await flows.handleLinkConfig();
507
- expect(result).toEqual({ completed: false, returnToMenu: true });
508
- });
509
- describe('view via library', () => {
510
- it('displays manifest contents from loadManifestData', async () => {
511
- vi.mocked(promptChoice).mockResolvedValueOnce('view');
512
- const result = await flows.handleLinkConfig();
513
- expect(loadManifestData).toHaveBeenCalledWith('/mock/repo');
514
- expect(result).toEqual({ completed: true, returnToMenu: true });
515
- });
516
- it('shows empty message when manifest has no files', async () => {
517
- vi.mocked(loadManifestData).mockReturnValueOnce({
518
- enabled: [],
519
- disabled: [],
520
- source: 'empty',
521
- });
522
- vi.mocked(promptChoice).mockResolvedValueOnce('view');
523
- const result = await flows.handleLinkConfig();
524
- expect(result).toEqual({ completed: true, returnToMenu: true });
525
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('No files'));
526
- });
527
- it('displays enabled and disabled files', async () => {
528
- vi.mocked(promptChoice).mockResolvedValueOnce('view');
529
- const result = await flows.handleLinkConfig();
530
- expect(result).toEqual({ completed: true, returnToMenu: true });
531
- // Check enabled files are shown
532
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Enabled'));
533
- expect(consoleSpy).toHaveBeenCalledWith(' .env');
534
- expect(consoleSpy).toHaveBeenCalledWith(' .env.local');
535
- // Check disabled files are shown
536
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Disabled'));
537
- });
538
- });
539
- describe('sync via wtlink link', () => {
540
- it('calls wtlink link library function', async () => {
541
- vi.mocked(promptChoice).mockResolvedValueOnce('sync');
542
- const result = await flows.handleLinkConfig();
543
- expect(runWtlinkLink).toHaveBeenCalledWith(expect.objectContaining({
544
- manifestFile: '.wtlinkrc',
545
- dryRun: false,
546
- type: 'hard',
547
- }));
548
- expect(result).toEqual({ completed: true, returnToMenu: true });
549
- });
550
- it('shows error when sync fails', async () => {
551
- vi.mocked(runWtlinkLink).mockRejectedValueOnce(new Error('Link failed'));
552
- vi.mocked(promptChoice).mockResolvedValueOnce('sync');
553
- const result = await flows.handleLinkConfig();
554
- expect(result).toEqual({ completed: true, returnToMenu: true });
555
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Link failed'));
556
- });
557
- });
558
- describe('add via library', () => {
559
- it('adds file to manifest via saveManifestData', async () => {
560
- vi.mocked(promptChoice).mockResolvedValueOnce('add');
561
- vi.mocked(promptInput).mockResolvedValueOnce('.npmrc');
562
- const result = await flows.handleLinkConfig();
563
- expect(saveManifestData).toHaveBeenCalledWith('/mock/repo', ['.env', '.env.local', '.npmrc'], ['config.json']);
564
- expect(result).toEqual({ completed: true, returnToMenu: true });
565
- });
566
- it('skips duplicate files', async () => {
567
- vi.mocked(promptChoice).mockResolvedValueOnce('add');
568
- vi.mocked(promptInput).mockResolvedValueOnce('.env');
569
- const result = await flows.handleLinkConfig();
570
- expect(saveManifestData).not.toHaveBeenCalled();
571
- expect(result).toEqual({ completed: true, returnToMenu: true });
572
- });
573
- it('returns CANCELLED when file path is empty', async () => {
574
- vi.mocked(promptChoice).mockResolvedValueOnce('add');
575
- vi.mocked(promptInput).mockResolvedValueOnce('');
576
- const result = await flows.handleLinkConfig();
577
- expect(result).toEqual({ completed: false, returnToMenu: true });
578
- expect(saveManifestData).not.toHaveBeenCalled();
579
- });
580
- });
581
- describe('remove via library', () => {
582
- it('removes file from manifest via saveManifestData', async () => {
583
- vi.mocked(promptChoice).mockResolvedValueOnce('remove');
584
- vi.mocked(promptInput).mockResolvedValueOnce('.env');
585
- const result = await flows.handleLinkConfig();
586
- expect(saveManifestData).toHaveBeenCalledWith('/mock/repo', ['.env.local'], ['config.json']);
587
- expect(result).toEqual({ completed: true, returnToMenu: true });
588
- });
589
- it('handles file not in manifest', async () => {
590
- vi.mocked(promptChoice).mockResolvedValueOnce('remove');
591
- vi.mocked(promptInput).mockResolvedValueOnce('nonexistent.txt');
592
- const result = await flows.handleLinkConfig();
593
- expect(saveManifestData).not.toHaveBeenCalled();
594
- expect(result).toEqual({ completed: true, returnToMenu: true });
595
- });
596
- it('returns CANCELLED when file path is empty', async () => {
597
- vi.mocked(promptChoice).mockResolvedValueOnce('remove');
598
- vi.mocked(promptInput).mockResolvedValueOnce('');
599
- const result = await flows.handleLinkConfig();
600
- expect(result).toEqual({ completed: false, returnToMenu: true });
601
- });
602
- });
603
- describe('validate', () => {
604
- it('calls wtlink validate and returns to menu', async () => {
605
- vi.mocked(promptChoice).mockResolvedValueOnce('validate');
606
- const result = await flows.handleLinkConfig();
607
- expect(runWtlinkValidate).toHaveBeenCalledWith(expect.objectContaining({
608
- manifestFile: '.wtlinkrc',
609
- }));
610
- expect(result).toEqual({ completed: true, returnToMenu: true });
611
- });
612
- });
613
- it('handles user cancellation', async () => {
614
- vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
615
- const result = await flows.handleLinkConfig();
616
- expect(result).toEqual({ completed: false, returnToMenu: true });
617
- });
618
- });
619
- describe('handleConfigure', () => {
620
- it('returns CANCELLED when user selects back', async () => {
621
- vi.mocked(promptChoice).mockResolvedValueOnce('back');
622
- const result = await flows.handleConfigure();
623
- expect(result).toEqual({ completed: false, returnToMenu: true });
624
- });
625
- it('view calls formatConfigDisplay and returns to menu', async () => {
626
- vi.mocked(promptChoice).mockResolvedValueOnce('view');
627
- const result = await flows.handleConfigure();
628
- expect(loadRepoConfig).toHaveBeenCalledWith('/mock/repo');
629
- expect(formatConfigDisplay).toHaveBeenCalled();
630
- expect(result).toEqual({ completed: true, returnToMenu: true });
631
- });
632
- it('init shows redirect message after confirmation and returns to menu', async () => {
633
- vi.mocked(promptChoice).mockResolvedValueOnce('init');
634
- vi.mocked(promptConfirm).mockResolvedValueOnce(true);
635
- const result = await flows.handleConfigure();
636
- expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('wt init'));
637
- expect(result).toEqual({ completed: true, returnToMenu: true });
638
- });
639
- it('init returns CANCELLED when not confirmed', async () => {
640
- vi.mocked(promptChoice).mockResolvedValueOnce('init');
641
- vi.mocked(promptConfirm).mockResolvedValueOnce(false);
642
- const result = await flows.handleConfigure();
643
- expect(result).toEqual({ completed: false, returnToMenu: true });
644
- });
645
- it('edit calls setConfigValue and saveRepoConfig with setting and value', async () => {
646
- vi.mocked(promptChoice).mockResolvedValueOnce('edit').mockResolvedValueOnce('baseBranch');
647
- vi.mocked(promptInput).mockResolvedValueOnce('develop');
648
- const result = await flows.handleConfigure();
649
- expect(setConfigValue).toHaveBeenCalledWith({}, 'baseBranch', 'develop');
650
- expect(saveRepoConfig).toHaveBeenCalled();
651
- expect(result).toEqual({ completed: true, returnToMenu: true });
652
- });
653
- it('edit returns CANCELLED when value is empty', async () => {
654
- vi.mocked(promptChoice).mockResolvedValueOnce('edit').mockResolvedValueOnce('branchPrefix');
655
- vi.mocked(promptInput).mockResolvedValueOnce('');
656
- const result = await flows.handleConfigure();
657
- expect(result).toEqual({ completed: false, returnToMenu: true });
658
- expect(saveRepoConfig).not.toHaveBeenCalled();
659
- });
660
- it('handles user cancellation', async () => {
661
- vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
662
- const result = await flows.handleConfigure();
663
- expect(result).toEqual({ completed: false, returnToMenu: true });
664
- });
665
- });
666
- describe('showMainMenu', () => {
667
- it('exits on exit selection', async () => {
668
- vi.mocked(promptChoice).mockResolvedValueOnce('exit');
669
- await showMainMenu();
670
- expect(runNewprHandler).not.toHaveBeenCalled();
671
- });
672
- it('exits on user cancellation', async () => {
673
- vi.mocked(promptChoice).mockRejectedValueOnce(new Error('User cancelled'));
674
- await showMainMenu();
675
- expect(runNewprHandler).not.toHaveBeenCalled();
676
- });
677
- it('re-throws non-cancellation errors', async () => {
678
- vi.mocked(promptChoice).mockRejectedValueOnce(new Error('Some other error'));
679
- await expect(showMainMenu()).rejects.toThrow('Some other error');
680
- });
681
- it('returns to menu when flow returns returnToMenu=true', async () => {
682
- vi.mocked(promptChoice)
683
- .mockResolvedValueOnce('new-pr') // First: select new-pr
684
- .mockResolvedValueOnce('back') // Then: go back from new-pr sub-menu
685
- .mockResolvedValueOnce('exit'); // Finally: exit
686
- await showMainMenu();
687
- // Should have called promptChoice 3 times (menu -> sub-menu -> back to menu -> exit)
688
- expect(promptChoice).toHaveBeenCalledTimes(3);
689
- });
690
- it('handles list worktrees and returns to menu', async () => {
691
- vi.mocked(promptChoice)
692
- .mockResolvedValueOnce('list') // Select list
693
- .mockResolvedValueOnce('exit'); // Then exit
694
- await showMainMenu();
695
- expect(gatherWorktreeInfo).toHaveBeenCalled();
696
- expect(promptChoice).toHaveBeenCalledTimes(2);
697
- });
698
- it('handles browse PRs and returns to menu', async () => {
699
- vi.mocked(promptChoice)
700
- .mockResolvedValueOnce('browse-prs') // Select browse-prs
701
- .mockResolvedValueOnce('exit'); // Then exit
702
- await showMainMenu();
703
- expect(runPrsCommand).toHaveBeenCalled();
704
- expect(promptChoice).toHaveBeenCalledTimes(2);
705
- });
706
- it('handles show state and returns to menu', async () => {
707
- vi.mocked(promptChoice)
708
- .mockResolvedValueOnce('state') // Select state
709
- .mockResolvedValueOnce('exit'); // Then exit
710
- await showMainMenu();
711
- expect(analyzeState).toHaveBeenCalled();
712
- expect(promptChoice).toHaveBeenCalledTimes(2);
713
- });
714
- });
715
- describe('FlowResult types', () => {
716
- it('CANCELLED has correct structure', async () => {
717
- vi.mocked(promptChoice).mockResolvedValueOnce('back');
718
- const result = await flows.handleNewPR();
719
- expect(result.completed).toBe(false);
720
- expect(result.returnToMenu).toBe(true);
721
- });
722
- it('flows that run operations return completed with returnToMenu=true', async () => {
723
- vi.mocked(promptChoice).mockResolvedValueOnce('dry-run');
724
- const result = await flows.handleCleanPRs();
725
- expect(result).toEqual({ completed: true, returnToMenu: true });
726
- });
727
- });
728
- });
729
- describe('Config loading in flows', () => {
730
- beforeEach(() => {
731
- vi.clearAllMocks();
732
- });
733
- it('uses config default for base branch', async () => {
734
- // Set up config mock to return custom baseBranch
735
- vi.mocked(loadConfig).mockReturnValueOnce({
736
- configVersion: 1,
737
- sharedRepos: [],
738
- baseBranch: 'develop',
739
- draftPr: true,
740
- worktreePattern: '{repo}.pr{number}',
741
- worktreeParent: '..',
742
- syncPatterns: [],
743
- branchPrefix: 'feat',
744
- previewLabel: 'preview',
745
- preferredEditor: 'vscode',
746
- ai: {
747
- provider: 'auto',
748
- fallback: 'none',
749
- branchName: false,
750
- prTitle: false,
751
- prDescription: false,
752
- commitMessage: false,
753
- planDocument: false,
754
- },
755
- hooks: {},
756
- hookDefaults: { timeout: 30000, maxTimeout: 60000 },
757
- plugins: [],
758
- generators: {},
759
- integrations: {},
760
- logging: { level: 'info', timestamps: true },
761
- global: { warnNotGlobal: true },
762
- wtlink: { enabled: [], disabled: [] },
763
- linkConfigFiles: undefined,
764
- });
765
- vi.mocked(promptChoice).mockResolvedValueOnce('from-description').mockResolvedValueOnce(true);
766
- vi.mocked(promptInput).mockResolvedValueOnce('Test feature').mockResolvedValueOnce('develop'); // User accepts default
767
- vi.mocked(promptConfirm).mockResolvedValueOnce(false).mockResolvedValueOnce(false);
768
- const result = await flows.handleNewPR();
769
- // Verify loadConfig was called
770
- expect(loadConfig).toHaveBeenCalled();
771
- // Verify runNewprHandler was called with develop base branch
772
- expect(runNewprHandler).toHaveBeenCalledWith(expect.objectContaining({
773
- baseBranch: 'develop',
774
- }));
775
- expect(result).toEqual({ completed: true, returnToMenu: true });
776
- });
777
- });
778
- describe('Git branch listing in flows', () => {
779
- beforeEach(() => {
780
- vi.clearAllMocks();
781
- });
782
- it('filters out main/master/develop from branch selection', async () => {
783
- // The mock already returns ['feat/existing-branch', 'fix/bug-fix', 'main', 'develop']
784
- // The flow should filter out main and develop
785
- vi.mocked(promptChoice)
786
- .mockResolvedValueOnce('from-branch')
787
- .mockResolvedValueOnce('feat/existing-branch')
788
- .mockResolvedValueOnce(true);
789
- vi.mocked(promptInput).mockResolvedValueOnce('main');
790
- const result = await flows.handleNewPR();
791
- // Check that listLocalBranches was called
792
- expect(git.listLocalBranches).toHaveBeenCalled();
793
- expect(result).toEqual({ completed: true, returnToMenu: true });
794
- });
795
- });
796
- //# sourceMappingURL=interactive-menu.test.js.map