@camaradesuk/git-worktree-tools 1.10.0 → 1.11.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 (426) hide show
  1. package/README.md +4 -4
  2. package/package.json +12 -3
  3. package/dist/api/list.test.d.ts +0 -5
  4. package/dist/api/list.test.d.ts.map +0 -1
  5. package/dist/api/list.test.js +0 -390
  6. package/dist/api/list.test.js.map +0 -1
  7. package/dist/cli/cleanpr.test.d.ts +0 -2
  8. package/dist/cli/cleanpr.test.d.ts.map +0 -1
  9. package/dist/cli/cleanpr.test.js +0 -954
  10. package/dist/cli/cleanpr.test.js.map +0 -1
  11. package/dist/cli/lswt.test.d.ts +0 -2
  12. package/dist/cli/lswt.test.d.ts.map +0 -1
  13. package/dist/cli/lswt.test.js +0 -376
  14. package/dist/cli/lswt.test.js.map +0 -1
  15. package/dist/cli/newpr.test.d.ts +0 -2
  16. package/dist/cli/newpr.test.d.ts.map +0 -1
  17. package/dist/cli/newpr.test.js +0 -1182
  18. package/dist/cli/newpr.test.js.map +0 -1
  19. package/dist/cli/prs.test.d.ts +0 -8
  20. package/dist/cli/prs.test.d.ts.map +0 -1
  21. package/dist/cli/prs.test.js +0 -463
  22. package/dist/cli/prs.test.js.map +0 -1
  23. package/dist/cli/wt/clean.test.d.ts +0 -8
  24. package/dist/cli/wt/clean.test.d.ts.map +0 -1
  25. package/dist/cli/wt/clean.test.js +0 -624
  26. package/dist/cli/wt/clean.test.js.map +0 -1
  27. package/dist/cli/wt/completion.test.d.ts +0 -5
  28. package/dist/cli/wt/completion.test.d.ts.map +0 -1
  29. package/dist/cli/wt/completion.test.js +0 -275
  30. package/dist/cli/wt/completion.test.js.map +0 -1
  31. package/dist/cli/wt/config.test.d.ts +0 -7
  32. package/dist/cli/wt/config.test.d.ts.map +0 -1
  33. package/dist/cli/wt/config.test.js +0 -440
  34. package/dist/cli/wt/config.test.js.map +0 -1
  35. package/dist/cli/wt/entry.test.d.ts +0 -8
  36. package/dist/cli/wt/entry.test.d.ts.map +0 -1
  37. package/dist/cli/wt/entry.test.js +0 -201
  38. package/dist/cli/wt/entry.test.js.map +0 -1
  39. package/dist/cli/wt/init.test.d.ts +0 -5
  40. package/dist/cli/wt/init.test.d.ts.map +0 -1
  41. package/dist/cli/wt/init.test.js +0 -165
  42. package/dist/cli/wt/init.test.js.map +0 -1
  43. package/dist/cli/wt/init.unit.test.d.ts +0 -5
  44. package/dist/cli/wt/init.unit.test.d.ts.map +0 -1
  45. package/dist/cli/wt/init.unit.test.js +0 -432
  46. package/dist/cli/wt/init.unit.test.js.map +0 -1
  47. package/dist/cli/wt/interactive-menu.test.d.ts +0 -12
  48. package/dist/cli/wt/interactive-menu.test.d.ts.map +0 -1
  49. package/dist/cli/wt/interactive-menu.test.js +0 -796
  50. package/dist/cli/wt/interactive-menu.test.js.map +0 -1
  51. package/dist/cli/wt/list.test.d.ts +0 -10
  52. package/dist/cli/wt/list.test.d.ts.map +0 -1
  53. package/dist/cli/wt/list.test.js +0 -157
  54. package/dist/cli/wt/list.test.js.map +0 -1
  55. package/dist/cli/wt/prs.test.d.ts +0 -5
  56. package/dist/cli/wt/prs.test.d.ts.map +0 -1
  57. package/dist/cli/wt/prs.test.js +0 -410
  58. package/dist/cli/wt/prs.test.js.map +0 -1
  59. package/dist/cli/wt/run-command.test.d.ts +0 -5
  60. package/dist/cli/wt/run-command.test.d.ts.map +0 -1
  61. package/dist/cli/wt/run-command.test.js +0 -88
  62. package/dist/cli/wt/run-command.test.js.map +0 -1
  63. package/dist/cli/wt/state.test.d.ts +0 -9
  64. package/dist/cli/wt/state.test.d.ts.map +0 -1
  65. package/dist/cli/wt/state.test.js +0 -127
  66. package/dist/cli/wt/state.test.js.map +0 -1
  67. package/dist/cli/wt/wt.test.d.ts +0 -8
  68. package/dist/cli/wt/wt.test.d.ts.map +0 -1
  69. package/dist/cli/wt/wt.test.js +0 -739
  70. package/dist/cli/wt/wt.test.js.map +0 -1
  71. package/dist/cli/wt.unit.test.d.ts +0 -7
  72. package/dist/cli/wt.unit.test.d.ts.map +0 -1
  73. package/dist/cli/wt.unit.test.js +0 -160
  74. package/dist/cli/wt.unit.test.js.map +0 -1
  75. package/dist/cli/wtconfig.test.d.ts +0 -5
  76. package/dist/cli/wtconfig.test.d.ts.map +0 -1
  77. package/dist/cli/wtconfig.test.js +0 -1289
  78. package/dist/cli/wtconfig.test.js.map +0 -1
  79. package/dist/cli/wtlink.test.d.ts +0 -2
  80. package/dist/cli/wtlink.test.d.ts.map +0 -1
  81. package/dist/cli/wtlink.test.js +0 -249
  82. package/dist/cli/wtlink.test.js.map +0 -1
  83. package/dist/cli/wtstate.test.d.ts +0 -5
  84. package/dist/cli/wtstate.test.d.ts.map +0 -1
  85. package/dist/cli/wtstate.test.js +0 -193
  86. package/dist/cli/wtstate.test.js.map +0 -1
  87. package/dist/e2e/cleanpr/cleanpr.e2e.test.d.ts +0 -2
  88. package/dist/e2e/cleanpr/cleanpr.e2e.test.d.ts.map +0 -1
  89. package/dist/e2e/cleanpr/cleanpr.e2e.test.js +0 -326
  90. package/dist/e2e/cleanpr/cleanpr.e2e.test.js.map +0 -1
  91. package/dist/e2e/cli.e2e.test.d.ts +0 -2
  92. package/dist/e2e/cli.e2e.test.d.ts.map +0 -1
  93. package/dist/e2e/cli.e2e.test.js +0 -417
  94. package/dist/e2e/cli.e2e.test.js.map +0 -1
  95. package/dist/e2e/lswt/lswt.e2e.test.d.ts +0 -2
  96. package/dist/e2e/lswt/lswt.e2e.test.d.ts.map +0 -1
  97. package/dist/e2e/lswt/lswt.e2e.test.js +0 -361
  98. package/dist/e2e/lswt/lswt.e2e.test.js.map +0 -1
  99. package/dist/e2e/newpr/newpr.e2e.test.d.ts +0 -2
  100. package/dist/e2e/newpr/newpr.e2e.test.d.ts.map +0 -1
  101. package/dist/e2e/newpr/newpr.e2e.test.js +0 -286
  102. package/dist/e2e/newpr/newpr.e2e.test.js.map +0 -1
  103. package/dist/e2e/newpr/scenarios.e2e.test.d.ts +0 -2
  104. package/dist/e2e/newpr/scenarios.e2e.test.d.ts.map +0 -1
  105. package/dist/e2e/newpr/scenarios.e2e.test.js +0 -426
  106. package/dist/e2e/newpr/scenarios.e2e.test.js.map +0 -1
  107. package/dist/e2e/newpr-full-flow.e2e.test.d.ts +0 -2
  108. package/dist/e2e/newpr-full-flow.e2e.test.d.ts.map +0 -1
  109. package/dist/e2e/newpr-full-flow.e2e.test.js +0 -280
  110. package/dist/e2e/newpr-full-flow.e2e.test.js.map +0 -1
  111. package/dist/e2e/prs/prs.e2e.test.d.ts +0 -7
  112. package/dist/e2e/prs/prs.e2e.test.d.ts.map +0 -1
  113. package/dist/e2e/prs/prs.e2e.test.js +0 -606
  114. package/dist/e2e/prs/prs.e2e.test.js.map +0 -1
  115. package/dist/e2e/workflows/pr-lifecycle.e2e.test.d.ts +0 -2
  116. package/dist/e2e/workflows/pr-lifecycle.e2e.test.d.ts.map +0 -1
  117. package/dist/e2e/workflows/pr-lifecycle.e2e.test.js +0 -298
  118. package/dist/e2e/workflows/pr-lifecycle.e2e.test.js.map +0 -1
  119. package/dist/e2e/wt/interactive-menu.e2e.test.d.ts +0 -8
  120. package/dist/e2e/wt/interactive-menu.e2e.test.d.ts.map +0 -1
  121. package/dist/e2e/wt/interactive-menu.e2e.test.js +0 -583
  122. package/dist/e2e/wt/interactive-menu.e2e.test.js.map +0 -1
  123. package/dist/e2e/wt/wt.e2e.test.d.ts +0 -9
  124. package/dist/e2e/wt/wt.e2e.test.d.ts.map +0 -1
  125. package/dist/e2e/wt/wt.e2e.test.js +0 -597
  126. package/dist/e2e/wt/wt.e2e.test.js.map +0 -1
  127. package/dist/e2e/wtlink/wtlink.e2e.test.d.ts +0 -2
  128. package/dist/e2e/wtlink/wtlink.e2e.test.d.ts.map +0 -1
  129. package/dist/e2e/wtlink/wtlink.e2e.test.js +0 -416
  130. package/dist/e2e/wtlink/wtlink.e2e.test.js.map +0 -1
  131. package/dist/integration/git.integration.test.d.ts +0 -2
  132. package/dist/integration/git.integration.test.d.ts.map +0 -1
  133. package/dist/integration/git.integration.test.js +0 -336
  134. package/dist/integration/git.integration.test.js.map +0 -1
  135. package/dist/integration/lswt-remote-pr.integration.test.d.ts +0 -2
  136. package/dist/integration/lswt-remote-pr.integration.test.d.ts.map +0 -1
  137. package/dist/integration/lswt-remote-pr.integration.test.js +0 -222
  138. package/dist/integration/lswt-remote-pr.integration.test.js.map +0 -1
  139. package/dist/integration/newpr-branchfrom-head.integration.test.d.ts +0 -2
  140. package/dist/integration/newpr-branchfrom-head.integration.test.d.ts.map +0 -1
  141. package/dist/integration/newpr-branchfrom-head.integration.test.js +0 -498
  142. package/dist/integration/newpr-branchfrom-head.integration.test.js.map +0 -1
  143. package/dist/integration/newpr.integration.test.d.ts +0 -2
  144. package/dist/integration/newpr.integration.test.d.ts.map +0 -1
  145. package/dist/integration/newpr.integration.test.js +0 -460
  146. package/dist/integration/newpr.integration.test.js.map +0 -1
  147. package/dist/integration/prs.integration.test.d.ts +0 -8
  148. package/dist/integration/prs.integration.test.d.ts.map +0 -1
  149. package/dist/integration/prs.integration.test.js +0 -478
  150. package/dist/integration/prs.integration.test.js.map +0 -1
  151. package/dist/lib/ai/base-provider.test.d.ts +0 -7
  152. package/dist/lib/ai/base-provider.test.d.ts.map +0 -1
  153. package/dist/lib/ai/base-provider.test.js +0 -319
  154. package/dist/lib/ai/base-provider.test.js.map +0 -1
  155. package/dist/lib/ai/cli-provider.test.d.ts +0 -5
  156. package/dist/lib/ai/cli-provider.test.d.ts.map +0 -1
  157. package/dist/lib/ai/cli-provider.test.js +0 -460
  158. package/dist/lib/ai/cli-provider.test.js.map +0 -1
  159. package/dist/lib/ai/fallback-provider.test.d.ts +0 -7
  160. package/dist/lib/ai/fallback-provider.test.d.ts.map +0 -1
  161. package/dist/lib/ai/fallback-provider.test.js +0 -165
  162. package/dist/lib/ai/fallback-provider.test.js.map +0 -1
  163. package/dist/lib/ai/generation-service.test.d.ts +0 -7
  164. package/dist/lib/ai/generation-service.test.d.ts.map +0 -1
  165. package/dist/lib/ai/generation-service.test.js +0 -213
  166. package/dist/lib/ai/generation-service.test.js.map +0 -1
  167. package/dist/lib/ai/provider-manager.test.d.ts +0 -5
  168. package/dist/lib/ai/provider-manager.test.d.ts.map +0 -1
  169. package/dist/lib/ai/provider-manager.test.js +0 -312
  170. package/dist/lib/ai/provider-manager.test.js.map +0 -1
  171. package/dist/lib/ai/repo-docs.test.d.ts +0 -5
  172. package/dist/lib/ai/repo-docs.test.d.ts.map +0 -1
  173. package/dist/lib/ai/repo-docs.test.js +0 -357
  174. package/dist/lib/ai/repo-docs.test.js.map +0 -1
  175. package/dist/lib/cleanpr/args.test.d.ts +0 -2
  176. package/dist/lib/cleanpr/args.test.d.ts.map +0 -1
  177. package/dist/lib/cleanpr/args.test.js +0 -269
  178. package/dist/lib/cleanpr/args.test.js.map +0 -1
  179. package/dist/lib/cleanpr/cleanup.test.d.ts +0 -2
  180. package/dist/lib/cleanpr/cleanup.test.d.ts.map +0 -1
  181. package/dist/lib/cleanpr/cleanup.test.js +0 -296
  182. package/dist/lib/cleanpr/cleanup.test.js.map +0 -1
  183. package/dist/lib/cleanpr/worktree-info.test.d.ts +0 -2
  184. package/dist/lib/cleanpr/worktree-info.test.d.ts.map +0 -1
  185. package/dist/lib/cleanpr/worktree-info.test.js +0 -228
  186. package/dist/lib/cleanpr/worktree-info.test.js.map +0 -1
  187. package/dist/lib/colors.test.d.ts +0 -2
  188. package/dist/lib/colors.test.d.ts.map +0 -1
  189. package/dist/lib/colors.test.js +0 -142
  190. package/dist/lib/colors.test.js.map +0 -1
  191. package/dist/lib/config-editor.test.d.ts +0 -11
  192. package/dist/lib/config-editor.test.d.ts.map +0 -1
  193. package/dist/lib/config-editor.test.js +0 -526
  194. package/dist/lib/config-editor.test.js.map +0 -1
  195. package/dist/lib/config-migration/detector.test.d.ts +0 -5
  196. package/dist/lib/config-migration/detector.test.d.ts.map +0 -1
  197. package/dist/lib/config-migration/detector.test.js +0 -201
  198. package/dist/lib/config-migration/detector.test.js.map +0 -1
  199. package/dist/lib/config-migration/reporter.test.d.ts +0 -5
  200. package/dist/lib/config-migration/reporter.test.d.ts.map +0 -1
  201. package/dist/lib/config-migration/reporter.test.js +0 -305
  202. package/dist/lib/config-migration/reporter.test.js.map +0 -1
  203. package/dist/lib/config-migration/runner.test.d.ts +0 -5
  204. package/dist/lib/config-migration/runner.test.d.ts.map +0 -1
  205. package/dist/lib/config-migration/runner.test.js +0 -235
  206. package/dist/lib/config-migration/runner.test.js.map +0 -1
  207. package/dist/lib/config-validation.test.d.ts +0 -5
  208. package/dist/lib/config-validation.test.d.ts.map +0 -1
  209. package/dist/lib/config-validation.test.js +0 -423
  210. package/dist/lib/config-validation.test.js.map +0 -1
  211. package/dist/lib/config.test.d.ts +0 -2
  212. package/dist/lib/config.test.d.ts.map +0 -1
  213. package/dist/lib/config.test.js +0 -554
  214. package/dist/lib/config.test.js.map +0 -1
  215. package/dist/lib/constants.test.d.ts +0 -5
  216. package/dist/lib/constants.test.d.ts.map +0 -1
  217. package/dist/lib/constants.test.js +0 -180
  218. package/dist/lib/constants.test.js.map +0 -1
  219. package/dist/lib/deprecation.test.d.ts +0 -2
  220. package/dist/lib/deprecation.test.d.ts.map +0 -1
  221. package/dist/lib/deprecation.test.js +0 -71
  222. package/dist/lib/deprecation.test.js.map +0 -1
  223. package/dist/lib/errors.test.d.ts +0 -2
  224. package/dist/lib/errors.test.d.ts.map +0 -1
  225. package/dist/lib/errors.test.js +0 -117
  226. package/dist/lib/errors.test.js.map +0 -1
  227. package/dist/lib/git.test.d.ts +0 -2
  228. package/dist/lib/git.test.d.ts.map +0 -1
  229. package/dist/lib/git.test.js +0 -608
  230. package/dist/lib/git.test.js.map +0 -1
  231. package/dist/lib/github.test.d.ts +0 -2
  232. package/dist/lib/github.test.d.ts.map +0 -1
  233. package/dist/lib/github.test.js +0 -441
  234. package/dist/lib/github.test.js.map +0 -1
  235. package/dist/lib/global-check.test.d.ts +0 -5
  236. package/dist/lib/global-check.test.d.ts.map +0 -1
  237. package/dist/lib/global-check.test.js +0 -150
  238. package/dist/lib/global-check.test.js.map +0 -1
  239. package/dist/lib/global-config.test.d.ts +0 -5
  240. package/dist/lib/global-config.test.d.ts.map +0 -1
  241. package/dist/lib/global-config.test.js +0 -282
  242. package/dist/lib/global-config.test.js.map +0 -1
  243. package/dist/lib/hooks/confirmation.test.d.ts +0 -7
  244. package/dist/lib/hooks/confirmation.test.d.ts.map +0 -1
  245. package/dist/lib/hooks/confirmation.test.js +0 -300
  246. package/dist/lib/hooks/confirmation.test.js.map +0 -1
  247. package/dist/lib/hooks/executor.test.d.ts +0 -5
  248. package/dist/lib/hooks/executor.test.d.ts.map +0 -1
  249. package/dist/lib/hooks/executor.test.js +0 -648
  250. package/dist/lib/hooks/executor.test.js.map +0 -1
  251. package/dist/lib/hooks/templates.test.d.ts +0 -5
  252. package/dist/lib/hooks/templates.test.d.ts.map +0 -1
  253. package/dist/lib/hooks/templates.test.js +0 -163
  254. package/dist/lib/hooks/templates.test.js.map +0 -1
  255. package/dist/lib/hooks/types.test.d.ts +0 -5
  256. package/dist/lib/hooks/types.test.d.ts.map +0 -1
  257. package/dist/lib/hooks/types.test.js +0 -132
  258. package/dist/lib/hooks/types.test.js.map +0 -1
  259. package/dist/lib/json-output.test.d.ts +0 -5
  260. package/dist/lib/json-output.test.d.ts.map +0 -1
  261. package/dist/lib/json-output.test.js +0 -261
  262. package/dist/lib/json-output.test.js.map +0 -1
  263. package/dist/lib/logger.test.d.ts +0 -14
  264. package/dist/lib/logger.test.d.ts.map +0 -1
  265. package/dist/lib/logger.test.js +0 -692
  266. package/dist/lib/logger.test.js.map +0 -1
  267. package/dist/lib/lswt/action-executors.test.d.ts +0 -2
  268. package/dist/lib/lswt/action-executors.test.d.ts.map +0 -1
  269. package/dist/lib/lswt/action-executors.test.js +0 -1127
  270. package/dist/lib/lswt/action-executors.test.js.map +0 -1
  271. package/dist/lib/lswt/actions.test.d.ts +0 -2
  272. package/dist/lib/lswt/actions.test.d.ts.map +0 -1
  273. package/dist/lib/lswt/actions.test.js +0 -497
  274. package/dist/lib/lswt/actions.test.js.map +0 -1
  275. package/dist/lib/lswt/args.test.d.ts +0 -2
  276. package/dist/lib/lswt/args.test.d.ts.map +0 -1
  277. package/dist/lib/lswt/args.test.js +0 -195
  278. package/dist/lib/lswt/args.test.js.map +0 -1
  279. package/dist/lib/lswt/environment.test.d.ts +0 -2
  280. package/dist/lib/lswt/environment.test.d.ts.map +0 -1
  281. package/dist/lib/lswt/environment.test.js +0 -544
  282. package/dist/lib/lswt/environment.test.js.map +0 -1
  283. package/dist/lib/lswt/formatters.test.d.ts +0 -2
  284. package/dist/lib/lswt/formatters.test.d.ts.map +0 -1
  285. package/dist/lib/lswt/formatters.test.js +0 -323
  286. package/dist/lib/lswt/formatters.test.js.map +0 -1
  287. package/dist/lib/lswt/fuzzy-search.test.d.ts +0 -5
  288. package/dist/lib/lswt/fuzzy-search.test.d.ts.map +0 -1
  289. package/dist/lib/lswt/fuzzy-search.test.js +0 -207
  290. package/dist/lib/lswt/fuzzy-search.test.js.map +0 -1
  291. package/dist/lib/lswt/interactive.test.d.ts +0 -2
  292. package/dist/lib/lswt/interactive.test.d.ts.map +0 -1
  293. package/dist/lib/lswt/interactive.test.js +0 -771
  294. package/dist/lib/lswt/interactive.test.js.map +0 -1
  295. package/dist/lib/lswt/table.test.d.ts +0 -5
  296. package/dist/lib/lswt/table.test.d.ts.map +0 -1
  297. package/dist/lib/lswt/table.test.js +0 -262
  298. package/dist/lib/lswt/table.test.js.map +0 -1
  299. package/dist/lib/lswt/worktree-info.test.d.ts +0 -2
  300. package/dist/lib/lswt/worktree-info.test.d.ts.map +0 -1
  301. package/dist/lib/lswt/worktree-info.test.js +0 -484
  302. package/dist/lib/lswt/worktree-info.test.js.map +0 -1
  303. package/dist/lib/newpr/action-deps.test.d.ts +0 -5
  304. package/dist/lib/newpr/action-deps.test.d.ts.map +0 -1
  305. package/dist/lib/newpr/action-deps.test.js +0 -111
  306. package/dist/lib/newpr/action-deps.test.js.map +0 -1
  307. package/dist/lib/newpr/actions.test.d.ts +0 -2
  308. package/dist/lib/newpr/actions.test.d.ts.map +0 -1
  309. package/dist/lib/newpr/actions.test.js +0 -254
  310. package/dist/lib/newpr/actions.test.js.map +0 -1
  311. package/dist/lib/newpr/args.test.d.ts +0 -2
  312. package/dist/lib/newpr/args.test.d.ts.map +0 -1
  313. package/dist/lib/newpr/args.test.js +0 -479
  314. package/dist/lib/newpr/args.test.js.map +0 -1
  315. package/dist/lib/newpr/hook-runner.test.d.ts +0 -7
  316. package/dist/lib/newpr/hook-runner.test.d.ts.map +0 -1
  317. package/dist/lib/newpr/hook-runner.test.js +0 -422
  318. package/dist/lib/newpr/hook-runner.test.js.map +0 -1
  319. package/dist/lib/newpr/plan-generator.test.d.ts +0 -7
  320. package/dist/lib/newpr/plan-generator.test.d.ts.map +0 -1
  321. package/dist/lib/newpr/plan-generator.test.js +0 -387
  322. package/dist/lib/newpr/plan-generator.test.js.map +0 -1
  323. package/dist/lib/newpr/scenario-handler.test.d.ts +0 -2
  324. package/dist/lib/newpr/scenario-handler.test.d.ts.map +0 -1
  325. package/dist/lib/newpr/scenario-handler.test.js +0 -256
  326. package/dist/lib/newpr/scenario-handler.test.js.map +0 -1
  327. package/dist/lib/prompts.test.d.ts +0 -2
  328. package/dist/lib/prompts.test.d.ts.map +0 -1
  329. package/dist/lib/prompts.test.js +0 -807
  330. package/dist/lib/prompts.test.js.map +0 -1
  331. package/dist/lib/prs/actions.test.d.ts +0 -5
  332. package/dist/lib/prs/actions.test.d.ts.map +0 -1
  333. package/dist/lib/prs/actions.test.js +0 -356
  334. package/dist/lib/prs/actions.test.js.map +0 -1
  335. package/dist/lib/prs/command.test.d.ts +0 -11
  336. package/dist/lib/prs/command.test.d.ts.map +0 -1
  337. package/dist/lib/prs/command.test.js +0 -409
  338. package/dist/lib/prs/command.test.js.map +0 -1
  339. package/dist/lib/prs/data.test.d.ts +0 -5
  340. package/dist/lib/prs/data.test.d.ts.map +0 -1
  341. package/dist/lib/prs/data.test.js +0 -417
  342. package/dist/lib/prs/data.test.js.map +0 -1
  343. package/dist/lib/prs/details.test.d.ts +0 -5
  344. package/dist/lib/prs/details.test.d.ts.map +0 -1
  345. package/dist/lib/prs/details.test.js +0 -325
  346. package/dist/lib/prs/details.test.js.map +0 -1
  347. package/dist/lib/prs/filters.test.d.ts +0 -5
  348. package/dist/lib/prs/filters.test.d.ts.map +0 -1
  349. package/dist/lib/prs/filters.test.js +0 -312
  350. package/dist/lib/prs/filters.test.js.map +0 -1
  351. package/dist/lib/prs/formatters.test.d.ts +0 -2
  352. package/dist/lib/prs/formatters.test.d.ts.map +0 -1
  353. package/dist/lib/prs/formatters.test.js +0 -387
  354. package/dist/lib/prs/formatters.test.js.map +0 -1
  355. package/dist/lib/prs/interactive.test.d.ts +0 -5
  356. package/dist/lib/prs/interactive.test.d.ts.map +0 -1
  357. package/dist/lib/prs/interactive.test.js +0 -517
  358. package/dist/lib/prs/interactive.test.js.map +0 -1
  359. package/dist/lib/schema.test.d.ts +0 -10
  360. package/dist/lib/schema.test.d.ts.map +0 -1
  361. package/dist/lib/schema.test.js +0 -309
  362. package/dist/lib/schema.test.js.map +0 -1
  363. package/dist/lib/state-detection.test.d.ts +0 -2
  364. package/dist/lib/state-detection.test.d.ts.map +0 -1
  365. package/dist/lib/state-detection.test.js +0 -451
  366. package/dist/lib/state-detection.test.js.map +0 -1
  367. package/dist/lib/ui/error.test.d.ts +0 -2
  368. package/dist/lib/ui/error.test.d.ts.map +0 -1
  369. package/dist/lib/ui/error.test.js +0 -143
  370. package/dist/lib/ui/error.test.js.map +0 -1
  371. package/dist/lib/ui/output.test.d.ts +0 -2
  372. package/dist/lib/ui/output.test.d.ts.map +0 -1
  373. package/dist/lib/ui/output.test.js +0 -59
  374. package/dist/lib/ui/output.test.js.map +0 -1
  375. package/dist/lib/ui/status.test.d.ts +0 -2
  376. package/dist/lib/ui/status.test.d.ts.map +0 -1
  377. package/dist/lib/ui/status.test.js +0 -158
  378. package/dist/lib/ui/status.test.js.map +0 -1
  379. package/dist/lib/ui/table.test.d.ts +0 -2
  380. package/dist/lib/ui/table.test.d.ts.map +0 -1
  381. package/dist/lib/ui/table.test.js +0 -115
  382. package/dist/lib/ui/table.test.js.map +0 -1
  383. package/dist/lib/ui/theme.test.d.ts +0 -2
  384. package/dist/lib/ui/theme.test.d.ts.map +0 -1
  385. package/dist/lib/ui/theme.test.js +0 -76
  386. package/dist/lib/ui/theme.test.js.map +0 -1
  387. package/dist/lib/wtconfig/config-manager.test.d.ts +0 -5
  388. package/dist/lib/wtconfig/config-manager.test.d.ts.map +0 -1
  389. package/dist/lib/wtconfig/config-manager.test.js +0 -501
  390. package/dist/lib/wtconfig/config-manager.test.js.map +0 -1
  391. package/dist/lib/wtconfig/environment.test.d.ts +0 -5
  392. package/dist/lib/wtconfig/environment.test.d.ts.map +0 -1
  393. package/dist/lib/wtconfig/environment.test.js +0 -285
  394. package/dist/lib/wtconfig/environment.test.js.map +0 -1
  395. package/dist/lib/wtlink/config-manifest.test.d.ts +0 -2
  396. package/dist/lib/wtlink/config-manifest.test.d.ts.map +0 -1
  397. package/dist/lib/wtlink/config-manifest.test.js +0 -486
  398. package/dist/lib/wtlink/config-manifest.test.js.map +0 -1
  399. package/dist/lib/wtlink/link-configs.test.d.ts +0 -2
  400. package/dist/lib/wtlink/link-configs.test.d.ts.map +0 -1
  401. package/dist/lib/wtlink/link-configs.test.js +0 -612
  402. package/dist/lib/wtlink/link-configs.test.js.map +0 -1
  403. package/dist/lib/wtlink/main-menu.test.d.ts +0 -5
  404. package/dist/lib/wtlink/main-menu.test.d.ts.map +0 -1
  405. package/dist/lib/wtlink/main-menu.test.js +0 -126
  406. package/dist/lib/wtlink/main-menu.test.js.map +0 -1
  407. package/dist/lib/wtlink/manage-manifest.test.d.ts +0 -2
  408. package/dist/lib/wtlink/manage-manifest.test.d.ts.map +0 -1
  409. package/dist/lib/wtlink/manage-manifest.test.js +0 -714
  410. package/dist/lib/wtlink/manage-manifest.test.js.map +0 -1
  411. package/dist/lib/wtlink/validate-manifest.test.d.ts +0 -2
  412. package/dist/lib/wtlink/validate-manifest.test.d.ts.map +0 -1
  413. package/dist/lib/wtlink/validate-manifest.test.js +0 -220
  414. package/dist/lib/wtlink/validate-manifest.test.js.map +0 -1
  415. package/dist/lib/wtstate/analyze.test.d.ts +0 -5
  416. package/dist/lib/wtstate/analyze.test.d.ts.map +0 -1
  417. package/dist/lib/wtstate/analyze.test.js +0 -282
  418. package/dist/lib/wtstate/analyze.test.js.map +0 -1
  419. package/dist/lib/wtstate/args.test.d.ts +0 -5
  420. package/dist/lib/wtstate/args.test.d.ts.map +0 -1
  421. package/dist/lib/wtstate/args.test.js +0 -120
  422. package/dist/lib/wtstate/args.test.js.map +0 -1
  423. package/dist/mcp/server.test.d.ts +0 -9
  424. package/dist/mcp/server.test.d.ts.map +0 -1
  425. package/dist/mcp/server.test.js +0 -550
  426. 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