@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,1289 +0,0 @@
1
- /**
2
- * wtconfig CLI Tests
3
- */
4
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
5
- // Mock modules before importing
6
- vi.mock('inquirer');
7
- vi.mock('child_process');
8
- vi.mock('../lib/git.js');
9
- vi.mock('../lib/config.js');
10
- vi.mock('../lib/wtconfig/index.js');
11
- import inquirer from 'inquirer';
12
- import { execSync } from 'child_process';
13
- import * as git from '../lib/git.js';
14
- import { getDefaultConfig } from '../lib/config.js';
15
- import * as wtconfig from '../lib/wtconfig/index.js';
16
- describe('cli/wtconfig', () => {
17
- let mockConsoleLog;
18
- let mockConsoleError;
19
- let mockConsoleWarn;
20
- let mockProcessExit;
21
- let originalArgv;
22
- const mockConfig = {
23
- configVersion: 1,
24
- baseBranch: 'main',
25
- draftPr: false,
26
- branchPrefix: 'feat',
27
- worktreePattern: '{repo}.pr{number}',
28
- worktreeParent: '..',
29
- wtlink: { enabled: [], disabled: [] },
30
- };
31
- const mockDefaultConfig = {
32
- configVersion: 1,
33
- baseBranch: 'main',
34
- draftPr: false,
35
- branchPrefix: 'feat',
36
- worktreePattern: '{repo}.pr{number}',
37
- worktreeParent: '..',
38
- sharedRepos: [],
39
- syncPatterns: [],
40
- preferredEditor: 'auto',
41
- previewLabel: 'preview',
42
- plugins: [],
43
- generators: {},
44
- integrations: {},
45
- ai: {
46
- provider: 'none',
47
- branchName: false,
48
- prTitle: false,
49
- prDescription: false,
50
- },
51
- hooks: {},
52
- hookDefaults: { timeout: 30000, maxTimeout: 60000 },
53
- logging: { level: 'info', timestamps: true },
54
- global: { warnNotGlobal: true },
55
- wtlink: { enabled: [], disabled: [] },
56
- linkConfigFiles: undefined,
57
- };
58
- beforeEach(() => {
59
- vi.resetAllMocks();
60
- vi.resetModules();
61
- mockConsoleLog = vi.spyOn(console, 'log').mockImplementation(() => { });
62
- mockConsoleError = vi.spyOn(console, 'error').mockImplementation(() => { });
63
- mockConsoleWarn = vi.spyOn(console, 'warn').mockImplementation(() => { });
64
- // @ts-expect-error - process.exit mock type is complex
65
- mockProcessExit = vi.spyOn(process, 'exit').mockImplementation((() => { }));
66
- originalArgv = process.argv;
67
- // Setup default mocks
68
- vi.mocked(git.getRepoRoot).mockReturnValue('/repo');
69
- vi.mocked(getDefaultConfig).mockReturnValue(mockDefaultConfig);
70
- vi.mocked(wtconfig.loadMergedConfig).mockReturnValue(mockConfig);
71
- vi.mocked(wtconfig.getConfigSource).mockReturnValue({
72
- type: 'repository',
73
- path: '/repo/.worktreerc',
74
- });
75
- vi.mocked(wtconfig.formatConfigDisplay).mockReturnValue('formatted config');
76
- vi.mocked(wtconfig.validateConfig).mockReturnValue({ valid: true, errors: [], warnings: [] });
77
- });
78
- afterEach(() => {
79
- mockConsoleLog.mockRestore();
80
- mockConsoleError.mockRestore();
81
- mockConsoleWarn.mockRestore();
82
- mockProcessExit.mockRestore();
83
- process.argv = originalArgv;
84
- });
85
- async function runCli(args = []) {
86
- process.argv = ['node', 'wtconfig', ...args];
87
- // Re-import to trigger CLI execution
88
- await import('./wtconfig.js');
89
- // Wait for async operations
90
- await new Promise((resolve) => setTimeout(resolve, 50));
91
- }
92
- describe('show command', () => {
93
- it('shows current configuration with source', async () => {
94
- await runCli(['show']);
95
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Current Configuration'));
96
- });
97
- it('shows default message when no config exists', async () => {
98
- vi.mocked(wtconfig.getConfigSource).mockReturnValue({ type: 'none', path: null });
99
- await runCli(['show']);
100
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('No configuration file found'));
101
- });
102
- it('shows config source path when config exists', async () => {
103
- await runCli(['show']);
104
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Source:'));
105
- });
106
- });
107
- describe('get command', () => {
108
- it('displays error when no key provided', async () => {
109
- await runCli(['get']);
110
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Usage: wtconfig get <key>'));
111
- expect(mockProcessExit).toHaveBeenCalledWith(1);
112
- });
113
- it('returns value for valid key', async () => {
114
- vi.mocked(wtconfig.getConfigValue).mockReturnValueOnce('develop');
115
- await runCli(['get', 'baseBranch']);
116
- expect(mockConsoleLog).toHaveBeenCalledWith('develop');
117
- });
118
- it('returns default value when key not in user config', async () => {
119
- vi.mocked(wtconfig.getConfigValue).mockReturnValueOnce(undefined).mockReturnValueOnce('feat');
120
- await runCli(['get', 'branchPrefix']);
121
- expect(mockConsoleLog).toHaveBeenCalledWith('feat');
122
- });
123
- it('displays error for unknown key', async () => {
124
- vi.mocked(wtconfig.getConfigValue).mockReturnValue(undefined);
125
- await runCli(['get', 'unknownKey']);
126
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Unknown configuration key'));
127
- expect(mockProcessExit).toHaveBeenCalledWith(1);
128
- });
129
- it('outputs JSON for object values', async () => {
130
- vi.mocked(wtconfig.getConfigValue).mockReturnValueOnce({
131
- provider: 'claude',
132
- branchName: true,
133
- });
134
- await runCli(['get', 'ai']);
135
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('"provider"'));
136
- });
137
- });
138
- describe('set command', () => {
139
- beforeEach(() => {
140
- vi.mocked(inquirer.prompt).mockResolvedValue({ saveLocation: 'repo' });
141
- vi.mocked(wtconfig.loadRepoConfig).mockReturnValue({});
142
- vi.mocked(wtconfig.setConfigValue).mockReturnValue({ baseBranch: 'develop' });
143
- });
144
- it('displays error when no key provided', async () => {
145
- await runCli(['set']);
146
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Usage: wtconfig set <key> <value>'));
147
- expect(mockProcessExit).toHaveBeenCalledWith(1);
148
- });
149
- it('displays error when no value provided', async () => {
150
- await runCli(['set', 'baseBranch']);
151
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Missing value for key'));
152
- expect(mockProcessExit).toHaveBeenCalledWith(1);
153
- });
154
- it('prompts for save location and saves to repo', async () => {
155
- await runCli(['set', 'baseBranch', 'develop']);
156
- expect(inquirer.prompt).toHaveBeenCalled();
157
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.any(Object));
158
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Set baseBranch = develop'));
159
- });
160
- it('saves to global config when selected', async () => {
161
- vi.mocked(inquirer.prompt).mockResolvedValue({ saveLocation: 'global' });
162
- vi.mocked(wtconfig.loadGlobalConfig).mockReturnValue({});
163
- await runCli(['set', 'baseBranch', 'develop']);
164
- expect(wtconfig.saveGlobalConfig).toHaveBeenCalled();
165
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('~/.worktreerc'));
166
- });
167
- it('shows validation errors and exits', async () => {
168
- vi.mocked(wtconfig.validateConfig).mockReturnValue({
169
- valid: false,
170
- errors: [{ path: 'baseBranch', message: 'Invalid value' }],
171
- warnings: [],
172
- });
173
- await runCli(['set', 'baseBranch', 'invalid']);
174
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('validation failed'));
175
- expect(mockProcessExit).toHaveBeenCalledWith(1);
176
- });
177
- it('shows validation warnings', async () => {
178
- vi.mocked(wtconfig.validateConfig).mockReturnValue({
179
- valid: true,
180
- errors: [],
181
- warnings: [{ path: 'ai.provider', message: 'Experimental feature' }],
182
- });
183
- await runCli(['set', 'ai.provider', 'claude']);
184
- expect(mockConsoleWarn).toHaveBeenCalledWith(expect.stringContaining('Warning'));
185
- });
186
- });
187
- describe('validate command', () => {
188
- it('shows success when no config exists', async () => {
189
- vi.mocked(wtconfig.getConfigSource).mockReturnValue({ type: 'none', path: null });
190
- await runCli(['validate']);
191
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('No configuration file found'));
192
- });
193
- it('shows success for valid config', async () => {
194
- await runCli(['validate']);
195
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Configuration is valid'));
196
- });
197
- it('shows validation source path', async () => {
198
- await runCli(['validate']);
199
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Validating:'));
200
- });
201
- it('shows errors and exits for invalid config', async () => {
202
- vi.mocked(wtconfig.validateConfig).mockReturnValue({
203
- valid: false,
204
- errors: [
205
- { path: 'baseBranch', message: 'Invalid branch name' },
206
- { path: 'ai.provider', message: 'Unknown provider' },
207
- ],
208
- warnings: [],
209
- });
210
- await runCli(['validate']);
211
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Errors:'));
212
- expect(mockProcessExit).toHaveBeenCalledWith(1);
213
- });
214
- it('shows warnings for valid config with warnings', async () => {
215
- vi.mocked(wtconfig.validateConfig).mockReturnValue({
216
- valid: true,
217
- errors: [],
218
- warnings: [{ path: 'sharedRepos', message: 'Repo not found' }],
219
- });
220
- await runCli(['validate']);
221
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Warnings:'));
222
- });
223
- it('shows both errors and warnings', async () => {
224
- vi.mocked(wtconfig.validateConfig).mockReturnValue({
225
- valid: false,
226
- errors: [{ path: 'baseBranch', message: 'Invalid' }],
227
- warnings: [{ path: 'ai.provider', message: 'Deprecated' }],
228
- });
229
- await runCli(['validate']);
230
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Errors:'));
231
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Warnings:'));
232
- expect(mockProcessExit).toHaveBeenCalledWith(1);
233
- });
234
- });
235
- describe('help command', () => {
236
- it('shows help text for help command', async () => {
237
- await runCli(['help']);
238
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('wtconfig'));
239
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Usage:'));
240
- });
241
- it('shows help text for --help flag', async () => {
242
- await runCli(['--help']);
243
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Usage:'));
244
- });
245
- it('shows help text for -h flag', async () => {
246
- await runCli(['-h']);
247
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Usage:'));
248
- });
249
- });
250
- describe('unknown command', () => {
251
- it('shows error and help for unknown command', async () => {
252
- await runCli(['unknown']);
253
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Unknown command'));
254
- expect(mockProcessExit).toHaveBeenCalledWith(1);
255
- });
256
- });
257
- describe('error handling', () => {
258
- it('handles git repo not found gracefully', async () => {
259
- vi.mocked(git.getRepoRoot).mockImplementation(() => {
260
- throw new Error('Not a git repository');
261
- });
262
- vi.mocked(wtconfig.getConfigSource).mockReturnValue({
263
- type: 'global',
264
- path: '/home/user/.worktreerc',
265
- });
266
- await runCli(['show']);
267
- // Should still show config (from global)
268
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Current Configuration'));
269
- });
270
- });
271
- describe('edit command', () => {
272
- beforeEach(() => {
273
- vi.mocked(inquirer.prompt).mockResolvedValue({ editLocation: 'repo' });
274
- vi.mocked(wtconfig.getDefaultRepoConfigPath).mockReturnValue('/repo/.worktreerc');
275
- vi.mocked(wtconfig.getGlobalConfigPath).mockReturnValue('/home/user/.worktreerc');
276
- });
277
- it('prompts for location when editing', async () => {
278
- // Mock fs.existsSync for the dynamic import
279
- vi.doMock('fs', () => ({
280
- existsSync: vi.fn().mockReturnValue(true),
281
- }));
282
- vi.mocked(execSync).mockImplementation(() => Buffer.from(''));
283
- await runCli(['edit']);
284
- expect(inquirer.prompt).toHaveBeenCalled();
285
- });
286
- });
287
- describe('init/wizard command', () => {
288
- const mockEnv = {
289
- os: 'linux',
290
- git: { version: '2.30.0', configured: true, user: 'testuser', email: 'test@example.com' },
291
- github: { installed: true, authenticated: true, user: 'testuser' },
292
- ai: { claudeCode: false, geminiCLI: false, ollama: false, codexCLI: false },
293
- packageManager: 'npm',
294
- ide: { vscode: true, cursor: false },
295
- };
296
- beforeEach(() => {
297
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue(mockEnv);
298
- vi.mocked(wtconfig.detectDefaultBranch).mockReturnValue('main');
299
- vi.mocked(wtconfig.getDefaultRepoConfigPath).mockReturnValue('/repo/.worktreerc');
300
- vi.mocked(wtconfig.getGlobalConfigPath).mockReturnValue('/home/user/.worktreerc');
301
- vi.mocked(wtconfig.getInstallCommand).mockReturnValue('npm install');
302
- vi.mocked(wtconfig.getEditorCommand).mockReturnValue('code');
303
- });
304
- it('displays wizard header and detects environment', async () => {
305
- // Mock all wizard prompts in sequence (Step 1 has 3 questions in one call)
306
- vi.mocked(inquirer.prompt)
307
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
308
- .mockResolvedValueOnce({
309
- worktreeLocation: 'sibling',
310
- worktreePattern: '{repo}.pr{number}',
311
- })
312
- .mockResolvedValueOnce({ hooks: ['autoDeps'] })
313
- .mockResolvedValueOnce({ saveChoice: 'repo' });
314
- await runCli(['init']);
315
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Setup Wizard'));
316
- expect(wtconfig.detectEnvironment).toHaveBeenCalled();
317
- });
318
- it('runs wizard command alias', async () => {
319
- vi.mocked(inquirer.prompt)
320
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
321
- .mockResolvedValueOnce({
322
- worktreeLocation: 'sibling',
323
- worktreePattern: '{repo}.pr{number}',
324
- })
325
- .mockResolvedValueOnce({ hooks: [] })
326
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
327
- await runCli(['wizard']);
328
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Setup Wizard'));
329
- });
330
- it('displays environment detection message', async () => {
331
- vi.mocked(inquirer.prompt)
332
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
333
- .mockResolvedValueOnce({
334
- worktreeLocation: 'sibling',
335
- worktreePattern: '{repo}.pr{number}',
336
- })
337
- .mockResolvedValueOnce({ hooks: [] })
338
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
339
- await runCli(['init']);
340
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Detecting'));
341
- });
342
- });
343
- describe('show command with config values', () => {
344
- it('shows AI config when present', async () => {
345
- vi.mocked(wtconfig.loadMergedConfig).mockReturnValue({
346
- ...mockConfig,
347
- ai: { provider: 'claude', branchName: true, prTitle: false, prDescription: false },
348
- });
349
- await runCli(['show']);
350
- expect(mockConsoleLog).toHaveBeenCalled();
351
- });
352
- it('shows hooks config when present', async () => {
353
- vi.mocked(wtconfig.loadMergedConfig).mockReturnValue({
354
- ...mockConfig,
355
- hooks: { 'post-worktree': 'npm install' },
356
- });
357
- await runCli(['show']);
358
- expect(mockConsoleLog).toHaveBeenCalled();
359
- });
360
- it('shows plugins when present', async () => {
361
- vi.mocked(wtconfig.loadMergedConfig).mockReturnValue({
362
- ...mockConfig,
363
- plugins: ['@worktree/plugin-linear'],
364
- });
365
- await runCli(['show']);
366
- expect(mockConsoleLog).toHaveBeenCalled();
367
- });
368
- it('shows generators when present', async () => {
369
- vi.mocked(wtconfig.loadMergedConfig).mockReturnValue({
370
- ...mockConfig,
371
- generators: { branchName: './scripts/gen.js' },
372
- });
373
- await runCli(['show']);
374
- expect(mockConsoleLog).toHaveBeenCalled();
375
- });
376
- it('shows integrations when present', async () => {
377
- vi.mocked(wtconfig.loadMergedConfig).mockReturnValue({
378
- ...mockConfig,
379
- integrations: { linear: { teamId: 'ENG' } },
380
- });
381
- await runCli(['show']);
382
- expect(mockConsoleLog).toHaveBeenCalled();
383
- });
384
- it('shows sharedRepos when present', async () => {
385
- vi.mocked(wtconfig.loadMergedConfig).mockReturnValue({
386
- ...mockConfig,
387
- sharedRepos: ['other-repo'],
388
- });
389
- await runCli(['show']);
390
- expect(mockConsoleLog).toHaveBeenCalled();
391
- });
392
- it('shows syncPatterns when present', async () => {
393
- vi.mocked(wtconfig.loadMergedConfig).mockReturnValue({
394
- ...mockConfig,
395
- syncPatterns: ['*.env'],
396
- });
397
- await runCli(['show']);
398
- expect(mockConsoleLog).toHaveBeenCalled();
399
- });
400
- });
401
- describe('displayEnvironment scenarios', () => {
402
- const mockEnvBase = {
403
- os: 'linux',
404
- git: { version: '2.30.0', configured: true, user: 'testuser', email: 'test@example.com' },
405
- github: { installed: true, authenticated: true, user: 'testuser' },
406
- ai: { claudeCode: false, geminiCLI: false, ollama: false, codexCLI: false },
407
- packageManager: 'npm',
408
- ide: { vscode: true, cursor: false },
409
- };
410
- beforeEach(() => {
411
- vi.mocked(wtconfig.detectDefaultBranch).mockReturnValue('main');
412
- vi.mocked(wtconfig.getDefaultRepoConfigPath).mockReturnValue('/repo/.worktreerc');
413
- vi.mocked(wtconfig.getGlobalConfigPath).mockReturnValue('/home/user/.worktreerc');
414
- vi.mocked(wtconfig.getInstallCommand).mockReturnValue('npm install');
415
- vi.mocked(wtconfig.getEditorCommand).mockReturnValue('code');
416
- });
417
- it('displays git not found message', async () => {
418
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
419
- ...mockEnvBase,
420
- git: { version: null, configured: false, user: null, email: null },
421
- });
422
- vi.mocked(inquirer.prompt)
423
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
424
- .mockResolvedValueOnce({
425
- worktreeLocation: 'sibling',
426
- worktreePattern: '{repo}.pr{number}',
427
- })
428
- .mockResolvedValueOnce({ hooks: [] })
429
- .mockResolvedValueOnce({ configureAdvanced: false })
430
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
431
- await runCli(['init']);
432
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Git not found'));
433
- });
434
- it('displays git not configured warning', async () => {
435
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
436
- ...mockEnvBase,
437
- git: { version: '2.30.0', configured: false, user: null, email: null },
438
- });
439
- vi.mocked(inquirer.prompt)
440
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
441
- .mockResolvedValueOnce({
442
- worktreeLocation: 'sibling',
443
- worktreePattern: '{repo}.pr{number}',
444
- })
445
- .mockResolvedValueOnce({ hooks: [] })
446
- .mockResolvedValueOnce({ configureAdvanced: false })
447
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
448
- await runCli(['init']);
449
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('not configured'));
450
- });
451
- it('displays GitHub CLI not installed', async () => {
452
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
453
- ...mockEnvBase,
454
- github: { installed: false, authenticated: false, user: null },
455
- });
456
- vi.mocked(inquirer.prompt)
457
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
458
- .mockResolvedValueOnce({
459
- worktreeLocation: 'sibling',
460
- worktreePattern: '{repo}.pr{number}',
461
- })
462
- .mockResolvedValueOnce({ hooks: [] })
463
- .mockResolvedValueOnce({ configureAdvanced: false })
464
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
465
- await runCli(['init']);
466
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('GitHub CLI not installed'));
467
- });
468
- it('displays GitHub CLI not authenticated', async () => {
469
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
470
- ...mockEnvBase,
471
- github: { installed: true, authenticated: false, user: null },
472
- });
473
- vi.mocked(inquirer.prompt)
474
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
475
- .mockResolvedValueOnce({
476
- worktreeLocation: 'sibling',
477
- worktreePattern: '{repo}.pr{number}',
478
- })
479
- .mockResolvedValueOnce({ hooks: [] })
480
- .mockResolvedValueOnce({ configureAdvanced: false })
481
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
482
- await runCli(['init']);
483
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('not authenticated'));
484
- });
485
- it('displays detected AI tools', async () => {
486
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
487
- ...mockEnvBase,
488
- ai: { claudeCode: true, geminiCLI: true, ollama: false, codexCLI: false },
489
- });
490
- vi.mocked(inquirer.prompt)
491
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
492
- .mockResolvedValueOnce({
493
- worktreeLocation: 'sibling',
494
- worktreePattern: '{repo}.pr{number}',
495
- })
496
- .mockResolvedValueOnce({ aiChoice: 'no' })
497
- .mockResolvedValueOnce({ hooks: [] })
498
- .mockResolvedValueOnce({ configureAdvanced: false })
499
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
500
- await runCli(['init']);
501
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('AI tools'));
502
- });
503
- it('displays no AI tools message', async () => {
504
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
505
- ...mockEnvBase,
506
- ai: { claudeCode: false, geminiCLI: false, ollama: false, codexCLI: false },
507
- });
508
- vi.mocked(inquirer.prompt)
509
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
510
- .mockResolvedValueOnce({
511
- worktreeLocation: 'sibling',
512
- worktreePattern: '{repo}.pr{number}',
513
- })
514
- .mockResolvedValueOnce({ hooks: [] })
515
- .mockResolvedValueOnce({ configureAdvanced: false })
516
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
517
- await runCli(['init']);
518
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('No AI tools detected'));
519
- });
520
- it('displays no package manager', async () => {
521
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
522
- ...mockEnvBase,
523
- packageManager: null,
524
- });
525
- vi.mocked(wtconfig.getEditorCommand).mockReturnValue(null);
526
- vi.mocked(inquirer.prompt)
527
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
528
- .mockResolvedValueOnce({
529
- worktreeLocation: 'sibling',
530
- worktreePattern: '{repo}.pr{number}',
531
- })
532
- .mockResolvedValueOnce({ configureAdvanced: false })
533
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
534
- await runCli(['init']);
535
- // No package manager means no autoDeps hook available
536
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Detecting'));
537
- });
538
- it('displays both IDEs when present', async () => {
539
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
540
- ...mockEnvBase,
541
- ide: { vscode: true, cursor: true },
542
- });
543
- vi.mocked(inquirer.prompt)
544
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
545
- .mockResolvedValueOnce({
546
- worktreeLocation: 'sibling',
547
- worktreePattern: '{repo}.pr{number}',
548
- })
549
- .mockResolvedValueOnce({ hooks: [] })
550
- .mockResolvedValueOnce({ configureAdvanced: false })
551
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
552
- await runCli(['init']);
553
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('IDE'));
554
- });
555
- it('displays no IDEs message when none present', async () => {
556
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
557
- ...mockEnvBase,
558
- ide: { vscode: false, cursor: false },
559
- });
560
- vi.mocked(wtconfig.getEditorCommand).mockReturnValue(null);
561
- vi.mocked(inquirer.prompt)
562
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
563
- .mockResolvedValueOnce({
564
- worktreeLocation: 'sibling',
565
- worktreePattern: '{repo}.pr{number}',
566
- })
567
- .mockResolvedValueOnce({ hooks: [] })
568
- .mockResolvedValueOnce({ configureAdvanced: false })
569
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
570
- await runCli(['init']);
571
- expect(mockConsoleLog).toHaveBeenCalled();
572
- });
573
- });
574
- describe('wizard step paths', () => {
575
- const mockEnvBase = {
576
- os: 'linux',
577
- git: { version: '2.30.0', configured: true, user: 'testuser', email: 'test@example.com' },
578
- github: { installed: true, authenticated: true, user: 'testuser' },
579
- ai: { claudeCode: false, geminiCLI: false, ollama: false, codexCLI: false },
580
- packageManager: 'npm',
581
- ide: { vscode: true, cursor: false },
582
- };
583
- beforeEach(() => {
584
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue(mockEnvBase);
585
- vi.mocked(wtconfig.detectDefaultBranch).mockReturnValue('main');
586
- vi.mocked(wtconfig.getDefaultRepoConfigPath).mockReturnValue('/repo/.worktreerc');
587
- vi.mocked(wtconfig.getGlobalConfigPath).mockReturnValue('/home/user/.worktreerc');
588
- vi.mocked(wtconfig.getInstallCommand).mockReturnValue('npm install');
589
- vi.mocked(wtconfig.getEditorCommand).mockReturnValue('code');
590
- });
591
- it('handles custom base branch input', async () => {
592
- vi.mocked(inquirer.prompt)
593
- .mockResolvedValueOnce({ baseBranch: '__other__', draftPr: false, branchPrefix: 'feat' })
594
- .mockResolvedValueOnce({ customBranch: 'my-branch' })
595
- .mockResolvedValueOnce({
596
- worktreeLocation: 'sibling',
597
- worktreePattern: '{repo}.pr{number}',
598
- })
599
- .mockResolvedValueOnce({ hooks: [] })
600
- .mockResolvedValueOnce({ configureAdvanced: false })
601
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
602
- await runCli(['init']);
603
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('cancelled'));
604
- });
605
- it('handles inside worktree location', async () => {
606
- vi.mocked(inquirer.prompt)
607
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
608
- .mockResolvedValueOnce({ worktreeLocation: 'inside', worktreePattern: '{repo}.pr{number}' })
609
- .mockResolvedValueOnce({ hooks: [] })
610
- .mockResolvedValueOnce({ configureAdvanced: false })
611
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
612
- await runCli(['init']);
613
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('cancelled'));
614
- });
615
- it('handles custom worktree location', async () => {
616
- vi.mocked(inquirer.prompt)
617
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
618
- .mockResolvedValueOnce({ worktreeLocation: 'custom', worktreePattern: '{repo}.pr{number}' })
619
- .mockResolvedValueOnce({ customParent: '/custom/path' })
620
- .mockResolvedValueOnce({ hooks: [] })
621
- .mockResolvedValueOnce({ configureAdvanced: false })
622
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
623
- await runCli(['init']);
624
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('cancelled'));
625
- });
626
- it('handles AI configuration with detected Claude', async () => {
627
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
628
- ...mockEnvBase,
629
- ai: { claudeCode: true, geminiCLI: false, ollama: false, codexCLI: false },
630
- });
631
- vi.mocked(inquirer.prompt)
632
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
633
- .mockResolvedValueOnce({
634
- worktreeLocation: 'sibling',
635
- worktreePattern: '{repo}.pr{number}',
636
- })
637
- .mockResolvedValueOnce({ aiChoice: 'yes' })
638
- .mockResolvedValueOnce({ aiFeatures: ['branchName', 'prDescription'] })
639
- .mockResolvedValueOnce({ hooks: [] })
640
- .mockResolvedValueOnce({ configureAdvanced: false })
641
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
642
- await runCli(['init']);
643
- // Claude Code is shown in environment display as "AI tools: Claude Code"
644
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Claude Code'));
645
- });
646
- it('handles AI configuration with detected Gemini', async () => {
647
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
648
- ...mockEnvBase,
649
- ai: { claudeCode: false, geminiCLI: true, ollama: false, codexCLI: false },
650
- });
651
- vi.mocked(inquirer.prompt)
652
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
653
- .mockResolvedValueOnce({
654
- worktreeLocation: 'sibling',
655
- worktreePattern: '{repo}.pr{number}',
656
- })
657
- .mockResolvedValueOnce({ aiChoice: 'yes' })
658
- .mockResolvedValueOnce({ aiFeatures: [] })
659
- .mockResolvedValueOnce({ hooks: [] })
660
- .mockResolvedValueOnce({ configureAdvanced: false })
661
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
662
- await runCli(['init']);
663
- // Gemini CLI is shown in environment display as "AI tools: Gemini CLI"
664
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Gemini CLI'));
665
- });
666
- it('handles AI configuration with detected Ollama', async () => {
667
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
668
- ...mockEnvBase,
669
- ai: { claudeCode: false, geminiCLI: false, ollama: true, codexCLI: false },
670
- });
671
- vi.mocked(inquirer.prompt)
672
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
673
- .mockResolvedValueOnce({
674
- worktreeLocation: 'sibling',
675
- worktreePattern: '{repo}.pr{number}',
676
- })
677
- .mockResolvedValueOnce({ aiChoice: 'yes' })
678
- .mockResolvedValueOnce({ aiFeatures: [] })
679
- .mockResolvedValueOnce({ hooks: [] })
680
- .mockResolvedValueOnce({ configureAdvanced: false })
681
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
682
- await runCli(['init']);
683
- // Ollama is shown in environment display as "AI tools: Ollama"
684
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Ollama'));
685
- });
686
- it('handles AI configuration with detected OpenAI', async () => {
687
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
688
- ...mockEnvBase,
689
- ai: { claudeCode: false, geminiCLI: false, ollama: false, codexCLI: true },
690
- });
691
- vi.mocked(inquirer.prompt)
692
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
693
- .mockResolvedValueOnce({
694
- worktreeLocation: 'sibling',
695
- worktreePattern: '{repo}.pr{number}',
696
- })
697
- .mockResolvedValueOnce({ aiChoice: 'yes' })
698
- .mockResolvedValueOnce({ aiFeatures: [] })
699
- .mockResolvedValueOnce({ hooks: [] })
700
- .mockResolvedValueOnce({ configureAdvanced: false })
701
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
702
- await runCli(['init']);
703
- // Codex CLI is shown in environment display as "AI tools: Codex CLI"
704
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Codex CLI'));
705
- });
706
- it('handles manual AI provider configuration', async () => {
707
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
708
- ...mockEnvBase,
709
- ai: { claudeCode: true, geminiCLI: false, ollama: false, codexCLI: false },
710
- });
711
- vi.mocked(inquirer.prompt)
712
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
713
- .mockResolvedValueOnce({
714
- worktreeLocation: 'sibling',
715
- worktreePattern: '{repo}.pr{number}',
716
- })
717
- .mockResolvedValueOnce({ aiChoice: 'configure' })
718
- .mockResolvedValueOnce({ manualProvider: 'gemini' })
719
- .mockResolvedValueOnce({ aiFeatures: ['branchName'] })
720
- .mockResolvedValueOnce({ hooks: [] })
721
- .mockResolvedValueOnce({ configureAdvanced: false })
722
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
723
- await runCli(['init']);
724
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('cancelled'));
725
- });
726
- it('handles hooks with both IDEs detected and editor preference', async () => {
727
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
728
- ...mockEnvBase,
729
- ide: { vscode: true, cursor: true },
730
- });
731
- vi.mocked(inquirer.prompt)
732
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
733
- .mockResolvedValueOnce({
734
- worktreeLocation: 'sibling',
735
- worktreePattern: '{repo}.pr{number}',
736
- })
737
- .mockResolvedValueOnce({ hooks: ['autoDeps', 'openEditor'] })
738
- .mockResolvedValueOnce({ editorChoice: 'cursor' })
739
- .mockResolvedValueOnce({ configureAdvanced: false })
740
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
741
- await runCli(['init']);
742
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('cancelled'));
743
- });
744
- it('handles hooks with cursor only', async () => {
745
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
746
- ...mockEnvBase,
747
- ide: { vscode: false, cursor: true },
748
- });
749
- vi.mocked(wtconfig.getEditorCommand).mockReturnValue('cursor');
750
- vi.mocked(inquirer.prompt)
751
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
752
- .mockResolvedValueOnce({
753
- worktreeLocation: 'sibling',
754
- worktreePattern: '{repo}.pr{number}',
755
- })
756
- .mockResolvedValueOnce({ hooks: ['openEditor'] })
757
- .mockResolvedValueOnce({ configureAdvanced: false })
758
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
759
- await runCli(['init']);
760
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('cancelled'));
761
- });
762
- it('saves configuration to repository', async () => {
763
- vi.mocked(inquirer.prompt)
764
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: true, branchPrefix: 'fix' })
765
- .mockResolvedValueOnce({
766
- worktreeLocation: 'sibling',
767
- worktreePattern: '{repo}.pr{number}',
768
- })
769
- .mockResolvedValueOnce({ hooks: [] })
770
- .mockResolvedValueOnce({ configureAdvanced: false })
771
- .mockResolvedValueOnce({ saveChoice: 'repo' });
772
- await runCli(['init']);
773
- expect(wtconfig.saveRepoConfig).toHaveBeenCalled();
774
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Configuration saved'));
775
- });
776
- it('saves configuration globally', async () => {
777
- vi.mocked(inquirer.prompt)
778
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
779
- .mockResolvedValueOnce({
780
- worktreeLocation: 'sibling',
781
- worktreePattern: '{repo}.pr{number}',
782
- })
783
- .mockResolvedValueOnce({ hooks: [] })
784
- .mockResolvedValueOnce({ configureAdvanced: false })
785
- .mockResolvedValueOnce({ saveChoice: 'global' });
786
- await runCli(['init']);
787
- expect(wtconfig.saveGlobalConfig).toHaveBeenCalled();
788
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Configuration saved'));
789
- });
790
- it('displays quick start after saving', async () => {
791
- vi.mocked(inquirer.prompt)
792
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
793
- .mockResolvedValueOnce({
794
- worktreeLocation: 'sibling',
795
- worktreePattern: '{repo}.pr{number}',
796
- })
797
- .mockResolvedValueOnce({ hooks: [] })
798
- .mockResolvedValueOnce({ configureAdvanced: false })
799
- .mockResolvedValueOnce({ saveChoice: 'repo' });
800
- await runCli(['init']);
801
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Quick Start'));
802
- });
803
- });
804
- describe('advanced configuration', () => {
805
- const mockEnvBase = {
806
- os: 'linux',
807
- git: { version: '2.30.0', configured: true, user: 'testuser', email: 'test@example.com' },
808
- github: { installed: true, authenticated: true, user: 'testuser' },
809
- ai: { claudeCode: false, geminiCLI: false, ollama: false, codexCLI: false },
810
- packageManager: 'npm',
811
- ide: { vscode: true, cursor: false },
812
- };
813
- beforeEach(() => {
814
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue(mockEnvBase);
815
- vi.mocked(wtconfig.detectDefaultBranch).mockReturnValue('main');
816
- vi.mocked(wtconfig.getDefaultRepoConfigPath).mockReturnValue('/repo/.worktreerc');
817
- vi.mocked(wtconfig.getGlobalConfigPath).mockReturnValue('/home/user/.worktreerc');
818
- vi.mocked(wtconfig.getInstallCommand).mockReturnValue('npm install');
819
- vi.mocked(wtconfig.getEditorCommand).mockReturnValue('code');
820
- });
821
- it('configures plugins', async () => {
822
- vi.mocked(inquirer.prompt)
823
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
824
- .mockResolvedValueOnce({
825
- worktreeLocation: 'sibling',
826
- worktreePattern: '{repo}.pr{number}',
827
- })
828
- .mockResolvedValueOnce({ hooks: [] })
829
- .mockResolvedValueOnce({ configureAdvanced: true })
830
- .mockResolvedValueOnce({ addPlugins: true })
831
- .mockResolvedValueOnce({ pluginList: 'plugin1, plugin2' })
832
- .mockResolvedValueOnce({ useGenerators: false })
833
- .mockResolvedValueOnce({ integrationsToAdd: [] })
834
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
835
- await runCli(['init']);
836
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Advanced Configuration'));
837
- });
838
- it('configures custom generators', async () => {
839
- vi.mocked(inquirer.prompt)
840
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
841
- .mockResolvedValueOnce({
842
- worktreeLocation: 'sibling',
843
- worktreePattern: '{repo}.pr{number}',
844
- })
845
- .mockResolvedValueOnce({ hooks: [] })
846
- .mockResolvedValueOnce({ configureAdvanced: true })
847
- .mockResolvedValueOnce({ addPlugins: false })
848
- .mockResolvedValueOnce({ useGenerators: true })
849
- .mockResolvedValueOnce({
850
- branchNameGen: './scripts/branch.js',
851
- prTitleGen: './scripts/title.js',
852
- prDescGen: '',
853
- commitMsgGen: './scripts/commit.js',
854
- })
855
- .mockResolvedValueOnce({ integrationsToAdd: [] })
856
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
857
- await runCli(['init']);
858
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Advanced Configuration'));
859
- });
860
- it('configures Linear integration', async () => {
861
- vi.mocked(inquirer.prompt)
862
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
863
- .mockResolvedValueOnce({
864
- worktreeLocation: 'sibling',
865
- worktreePattern: '{repo}.pr{number}',
866
- })
867
- .mockResolvedValueOnce({ hooks: [] })
868
- .mockResolvedValueOnce({ configureAdvanced: true })
869
- .mockResolvedValueOnce({ addPlugins: false })
870
- .mockResolvedValueOnce({ useGenerators: false })
871
- .mockResolvedValueOnce({ integrationsToAdd: ['linear'] })
872
- .mockResolvedValueOnce({ teamId: 'ENG', apiKeyEnv: 'LINEAR_API_KEY' })
873
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
874
- await runCli(['init']);
875
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Advanced Configuration'));
876
- });
877
- it('configures Jira integration', async () => {
878
- vi.mocked(inquirer.prompt)
879
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
880
- .mockResolvedValueOnce({
881
- worktreeLocation: 'sibling',
882
- worktreePattern: '{repo}.pr{number}',
883
- })
884
- .mockResolvedValueOnce({ hooks: [] })
885
- .mockResolvedValueOnce({ configureAdvanced: true })
886
- .mockResolvedValueOnce({ addPlugins: false })
887
- .mockResolvedValueOnce({ useGenerators: false })
888
- .mockResolvedValueOnce({ integrationsToAdd: ['jira'] })
889
- .mockResolvedValueOnce({
890
- projectKey: 'PROJ',
891
- baseUrl: 'https://jira.example.com',
892
- apiTokenEnv: 'JIRA_TOKEN',
893
- })
894
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
895
- await runCli(['init']);
896
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Advanced Configuration'));
897
- });
898
- it('configures Slack integration', async () => {
899
- vi.mocked(inquirer.prompt)
900
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
901
- .mockResolvedValueOnce({
902
- worktreeLocation: 'sibling',
903
- worktreePattern: '{repo}.pr{number}',
904
- })
905
- .mockResolvedValueOnce({ hooks: [] })
906
- .mockResolvedValueOnce({ configureAdvanced: true })
907
- .mockResolvedValueOnce({ addPlugins: false })
908
- .mockResolvedValueOnce({ useGenerators: false })
909
- .mockResolvedValueOnce({ integrationsToAdd: ['slack'] })
910
- .mockResolvedValueOnce({ webhookUrl: 'SLACK_WEBHOOK_URL', channel: '#releases' })
911
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
912
- await runCli(['init']);
913
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Advanced Configuration'));
914
- });
915
- it('configures all integrations', async () => {
916
- vi.mocked(inquirer.prompt)
917
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
918
- .mockResolvedValueOnce({
919
- worktreeLocation: 'sibling',
920
- worktreePattern: '{repo}.pr{number}',
921
- })
922
- .mockResolvedValueOnce({ hooks: [] })
923
- .mockResolvedValueOnce({ configureAdvanced: true })
924
- .mockResolvedValueOnce({ addPlugins: false })
925
- .mockResolvedValueOnce({ useGenerators: false })
926
- .mockResolvedValueOnce({ integrationsToAdd: ['linear', 'jira', 'slack'] })
927
- .mockResolvedValueOnce({ teamId: '', apiKeyEnv: '' })
928
- .mockResolvedValueOnce({ projectKey: '', baseUrl: '', apiTokenEnv: '' })
929
- .mockResolvedValueOnce({ webhookUrl: '', channel: '' })
930
- .mockResolvedValueOnce({ saveChoice: 'cancel' });
931
- await runCli(['init']);
932
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Advanced Configuration'));
933
- });
934
- });
935
- describe('edit command edge cases', () => {
936
- beforeEach(() => {
937
- vi.mocked(wtconfig.getDefaultRepoConfigPath).mockReturnValue('/repo/.worktreerc');
938
- vi.mocked(wtconfig.getGlobalConfigPath).mockReturnValue('/home/user/.worktreerc');
939
- });
940
- it('edits global config when not in repo', async () => {
941
- vi.mocked(git.getRepoRoot).mockImplementation(() => {
942
- throw new Error('Not a git repository');
943
- });
944
- vi.mocked(inquirer.prompt).mockResolvedValueOnce({ editLocation: 'global' });
945
- // Mock fs for the dynamic import
946
- vi.doMock('fs', () => ({
947
- existsSync: vi.fn().mockReturnValue(true),
948
- writeFileSync: vi.fn(),
949
- }));
950
- vi.mocked(execSync).mockImplementation(() => Buffer.from(''));
951
- await runCli(['edit']);
952
- expect(inquirer.prompt).toHaveBeenCalled();
953
- });
954
- it('cancels file creation when user declines', async () => {
955
- vi.mocked(inquirer.prompt)
956
- .mockResolvedValueOnce({ editLocation: 'repo' })
957
- .mockResolvedValueOnce({ create: false });
958
- vi.doMock('fs', () => ({
959
- existsSync: vi.fn().mockReturnValue(false),
960
- writeFileSync: vi.fn(),
961
- }));
962
- await runCli(['edit']);
963
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Cancelled'));
964
- });
965
- it('creates new config file when user confirms', async () => {
966
- vi.mocked(inquirer.prompt)
967
- .mockResolvedValueOnce({ editLocation: 'repo' })
968
- .mockResolvedValueOnce({ create: true });
969
- const mockWriteFileSync = vi.fn();
970
- vi.doMock('fs', () => ({
971
- existsSync: vi.fn().mockReturnValue(false),
972
- writeFileSync: mockWriteFileSync,
973
- }));
974
- vi.mocked(execSync).mockImplementation(() => Buffer.from(''));
975
- await runCli(['edit']);
976
- // Config file should be created
977
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Opening'));
978
- });
979
- it('handles editor failure gracefully', async () => {
980
- vi.mocked(inquirer.prompt).mockResolvedValueOnce({ editLocation: 'repo' });
981
- vi.doMock('fs', () => ({
982
- existsSync: vi.fn().mockReturnValue(true),
983
- writeFileSync: vi.fn(),
984
- }));
985
- vi.mocked(execSync).mockImplementation(() => {
986
- throw new Error('Editor failed');
987
- });
988
- await runCli(['edit']);
989
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Failed to open editor'));
990
- expect(mockProcessExit).toHaveBeenCalledWith(1);
991
- });
992
- });
993
- describe('set command edge cases', () => {
994
- beforeEach(() => {
995
- vi.mocked(inquirer.prompt).mockResolvedValue({ saveLocation: 'repo' });
996
- vi.mocked(wtconfig.loadRepoConfig).mockReturnValue({});
997
- });
998
- it('handles setConfigValue error', async () => {
999
- vi.mocked(wtconfig.setConfigValue).mockImplementation(() => {
1000
- throw new Error('Invalid key format');
1001
- });
1002
- await runCli(['set', 'invalid..key', 'value']);
1003
- expect(mockConsoleError).toHaveBeenCalledWith(expect.stringContaining('Failed to set value'));
1004
- expect(mockProcessExit).toHaveBeenCalledWith(1);
1005
- });
1006
- it('uses global config when not in repo', async () => {
1007
- vi.mocked(git.getRepoRoot).mockImplementation(() => {
1008
- throw new Error('Not a git repository');
1009
- });
1010
- vi.mocked(inquirer.prompt).mockResolvedValue({ saveLocation: 'global' });
1011
- vi.mocked(wtconfig.loadGlobalConfig).mockReturnValue({});
1012
- vi.mocked(wtconfig.setConfigValue).mockReturnValue({ baseBranch: 'develop' });
1013
- await runCli(['set', 'baseBranch', 'develop']);
1014
- expect(wtconfig.saveGlobalConfig).toHaveBeenCalled();
1015
- });
1016
- });
1017
- describe('wizard outside repository', () => {
1018
- beforeEach(() => {
1019
- vi.mocked(git.getRepoRoot).mockImplementation(() => {
1020
- throw new Error('Not a git repository');
1021
- });
1022
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
1023
- os: 'linux',
1024
- git: { version: '2.30.0', configured: true, user: 'testuser', email: 'test@example.com' },
1025
- github: { installed: true, authenticated: true, user: 'testuser' },
1026
- ai: { claudeCode: false, geminiCLI: false, ollama: false, codexCLI: false },
1027
- packageManager: 'npm',
1028
- ide: { vscode: true, cursor: false },
1029
- });
1030
- vi.mocked(wtconfig.getDefaultRepoConfigPath).mockReturnValue('/repo/.worktreerc');
1031
- vi.mocked(wtconfig.getGlobalConfigPath).mockReturnValue('/home/user/.worktreerc');
1032
- vi.mocked(wtconfig.getInstallCommand).mockReturnValue('npm install');
1033
- vi.mocked(wtconfig.getEditorCommand).mockReturnValue('code');
1034
- });
1035
- it('runs wizard without repo context and uses default branch', async () => {
1036
- vi.mocked(inquirer.prompt)
1037
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1038
- .mockResolvedValueOnce({
1039
- worktreeLocation: 'sibling',
1040
- worktreePattern: '{repo}.pr{number}',
1041
- })
1042
- .mockResolvedValueOnce({ hooks: [] })
1043
- .mockResolvedValueOnce({ configureAdvanced: false })
1044
- .mockResolvedValueOnce({ saveChoice: 'global' });
1045
- await runCli(['init']);
1046
- // Should not call detectDefaultBranch with null
1047
- expect(wtconfig.detectDefaultBranch).not.toHaveBeenCalled();
1048
- expect(wtconfig.saveGlobalConfig).toHaveBeenCalled();
1049
- });
1050
- });
1051
- describe('buildConfigFromState paths', () => {
1052
- const mockEnvBase = {
1053
- os: 'linux',
1054
- git: { version: '2.30.0', configured: true, user: 'testuser', email: 'test@example.com' },
1055
- github: { installed: true, authenticated: true, user: 'testuser' },
1056
- ai: { claudeCode: false, geminiCLI: false, ollama: false, codexCLI: false },
1057
- packageManager: 'npm',
1058
- ide: { vscode: true, cursor: false },
1059
- };
1060
- beforeEach(() => {
1061
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue(mockEnvBase);
1062
- vi.mocked(wtconfig.detectDefaultBranch).mockReturnValue('main');
1063
- vi.mocked(wtconfig.getDefaultRepoConfigPath).mockReturnValue('/repo/.worktreerc');
1064
- vi.mocked(wtconfig.getGlobalConfigPath).mockReturnValue('/home/user/.worktreerc');
1065
- vi.mocked(wtconfig.getInstallCommand).mockReturnValue('npm install');
1066
- vi.mocked(wtconfig.getEditorCommand).mockReturnValue('code');
1067
- });
1068
- it('builds config with non-default baseBranch', async () => {
1069
- vi.mocked(inquirer.prompt)
1070
- .mockResolvedValueOnce({ baseBranch: 'develop', draftPr: false, branchPrefix: 'feat' })
1071
- .mockResolvedValueOnce({
1072
- worktreeLocation: 'sibling',
1073
- worktreePattern: '{repo}.pr{number}',
1074
- })
1075
- .mockResolvedValueOnce({ hooks: [] })
1076
- .mockResolvedValueOnce({ configureAdvanced: false })
1077
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1078
- await runCli(['init']);
1079
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({ baseBranch: 'develop' }));
1080
- });
1081
- it('builds config with draftPr enabled', async () => {
1082
- vi.mocked(inquirer.prompt)
1083
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: true, branchPrefix: 'feat' })
1084
- .mockResolvedValueOnce({
1085
- worktreeLocation: 'sibling',
1086
- worktreePattern: '{repo}.pr{number}',
1087
- })
1088
- .mockResolvedValueOnce({ hooks: [] })
1089
- .mockResolvedValueOnce({ configureAdvanced: false })
1090
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1091
- await runCli(['init']);
1092
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({ draftPr: true }));
1093
- });
1094
- it('builds config with non-default branchPrefix', async () => {
1095
- vi.mocked(inquirer.prompt)
1096
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'fix' })
1097
- .mockResolvedValueOnce({
1098
- worktreeLocation: 'sibling',
1099
- worktreePattern: '{repo}.pr{number}',
1100
- })
1101
- .mockResolvedValueOnce({ hooks: [] })
1102
- .mockResolvedValueOnce({ configureAdvanced: false })
1103
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1104
- await runCli(['init']);
1105
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({ branchPrefix: 'fix' }));
1106
- });
1107
- it('builds config with non-default worktreePattern', async () => {
1108
- vi.mocked(inquirer.prompt)
1109
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1110
- .mockResolvedValueOnce({ worktreeLocation: 'sibling', worktreePattern: 'pr-{number}' })
1111
- .mockResolvedValueOnce({ hooks: [] })
1112
- .mockResolvedValueOnce({ configureAdvanced: false })
1113
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1114
- await runCli(['init']);
1115
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({ worktreePattern: 'pr-{number}' }));
1116
- });
1117
- it('builds config with non-default worktreeParent', async () => {
1118
- vi.mocked(inquirer.prompt)
1119
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1120
- .mockResolvedValueOnce({ worktreeLocation: 'inside', worktreePattern: '{repo}.pr{number}' })
1121
- .mockResolvedValueOnce({ hooks: [] })
1122
- .mockResolvedValueOnce({ configureAdvanced: false })
1123
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1124
- await runCli(['init']);
1125
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({ worktreeParent: '.worktrees' }));
1126
- });
1127
- it('builds config with AI enabled', async () => {
1128
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
1129
- ...mockEnvBase,
1130
- ai: { claudeCode: true, geminiCLI: false, ollama: false, codexCLI: false },
1131
- });
1132
- vi.mocked(inquirer.prompt)
1133
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1134
- .mockResolvedValueOnce({
1135
- worktreeLocation: 'sibling',
1136
- worktreePattern: '{repo}.pr{number}',
1137
- })
1138
- .mockResolvedValueOnce({ aiChoice: 'yes' })
1139
- .mockResolvedValueOnce({ aiFeatures: ['branchName', 'prDescription'] })
1140
- .mockResolvedValueOnce({ hooks: [] })
1141
- .mockResolvedValueOnce({ configureAdvanced: false })
1142
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1143
- await runCli(['init']);
1144
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({
1145
- ai: expect.objectContaining({
1146
- provider: 'auto',
1147
- branchName: true,
1148
- prDescription: true,
1149
- }),
1150
- }));
1151
- });
1152
- it('builds config with hooks (autoDeps)', async () => {
1153
- vi.mocked(inquirer.prompt)
1154
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1155
- .mockResolvedValueOnce({
1156
- worktreeLocation: 'sibling',
1157
- worktreePattern: '{repo}.pr{number}',
1158
- })
1159
- .mockResolvedValueOnce({ hooks: ['autoDeps'] })
1160
- .mockResolvedValueOnce({ configureAdvanced: false })
1161
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1162
- await runCli(['init']);
1163
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({
1164
- hooks: expect.objectContaining({
1165
- 'post-worktree': 'npm install',
1166
- }),
1167
- }));
1168
- });
1169
- it('builds config with hooks (openEditor)', async () => {
1170
- vi.mocked(inquirer.prompt)
1171
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1172
- .mockResolvedValueOnce({
1173
- worktreeLocation: 'sibling',
1174
- worktreePattern: '{repo}.pr{number}',
1175
- })
1176
- .mockResolvedValueOnce({ hooks: ['openEditor'] })
1177
- .mockResolvedValueOnce({ configureAdvanced: false })
1178
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1179
- await runCli(['init']);
1180
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({
1181
- hooks: expect.objectContaining({
1182
- 'post-worktree': 'code',
1183
- }),
1184
- }));
1185
- });
1186
- it('builds config with multiple hooks', async () => {
1187
- vi.mocked(inquirer.prompt)
1188
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1189
- .mockResolvedValueOnce({
1190
- worktreeLocation: 'sibling',
1191
- worktreePattern: '{repo}.pr{number}',
1192
- })
1193
- .mockResolvedValueOnce({ hooks: ['autoDeps', 'openEditor'] })
1194
- .mockResolvedValueOnce({ configureAdvanced: false })
1195
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1196
- await runCli(['init']);
1197
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({
1198
- hooks: expect.objectContaining({
1199
- 'post-worktree': expect.arrayContaining(['npm install', 'code']),
1200
- }),
1201
- }));
1202
- });
1203
- it('builds config with preferredEditor set', async () => {
1204
- vi.mocked(wtconfig.detectEnvironment).mockReturnValue({
1205
- ...mockEnvBase,
1206
- ide: { vscode: true, cursor: true },
1207
- });
1208
- vi.mocked(inquirer.prompt)
1209
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1210
- .mockResolvedValueOnce({
1211
- worktreeLocation: 'sibling',
1212
- worktreePattern: '{repo}.pr{number}',
1213
- })
1214
- .mockResolvedValueOnce({ hooks: ['openEditor'] })
1215
- .mockResolvedValueOnce({ editorChoice: 'cursor' })
1216
- .mockResolvedValueOnce({ configureAdvanced: false })
1217
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1218
- await runCli(['init']);
1219
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({ preferredEditor: 'cursor' }));
1220
- });
1221
- it('builds config with plugins', async () => {
1222
- vi.mocked(inquirer.prompt)
1223
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1224
- .mockResolvedValueOnce({
1225
- worktreeLocation: 'sibling',
1226
- worktreePattern: '{repo}.pr{number}',
1227
- })
1228
- .mockResolvedValueOnce({ hooks: [] })
1229
- .mockResolvedValueOnce({ configureAdvanced: true })
1230
- .mockResolvedValueOnce({ addPlugins: true })
1231
- .mockResolvedValueOnce({ pluginList: 'plugin-a, plugin-b' })
1232
- .mockResolvedValueOnce({ useGenerators: false })
1233
- .mockResolvedValueOnce({ integrationsToAdd: [] })
1234
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1235
- await runCli(['init']);
1236
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({ plugins: ['plugin-a', 'plugin-b'] }));
1237
- });
1238
- it('builds config with generators', async () => {
1239
- vi.mocked(inquirer.prompt)
1240
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1241
- .mockResolvedValueOnce({
1242
- worktreeLocation: 'sibling',
1243
- worktreePattern: '{repo}.pr{number}',
1244
- })
1245
- .mockResolvedValueOnce({ hooks: [] })
1246
- .mockResolvedValueOnce({ configureAdvanced: true })
1247
- .mockResolvedValueOnce({ addPlugins: false })
1248
- .mockResolvedValueOnce({ useGenerators: true })
1249
- .mockResolvedValueOnce({
1250
- branchNameGen: './branch.sh',
1251
- prTitleGen: '',
1252
- prDescGen: './pr-desc.sh',
1253
- commitMsgGen: '',
1254
- })
1255
- .mockResolvedValueOnce({ integrationsToAdd: [] })
1256
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1257
- await runCli(['init']);
1258
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({
1259
- generators: { branchName: './branch.sh', prDescription: './pr-desc.sh' },
1260
- }));
1261
- });
1262
- it('builds config with integrations', async () => {
1263
- vi.mocked(inquirer.prompt)
1264
- .mockResolvedValueOnce({ baseBranch: 'main', draftPr: false, branchPrefix: 'feat' })
1265
- .mockResolvedValueOnce({
1266
- worktreeLocation: 'sibling',
1267
- worktreePattern: '{repo}.pr{number}',
1268
- })
1269
- .mockResolvedValueOnce({ hooks: [] })
1270
- .mockResolvedValueOnce({ configureAdvanced: true })
1271
- .mockResolvedValueOnce({ addPlugins: false })
1272
- .mockResolvedValueOnce({ useGenerators: false })
1273
- .mockResolvedValueOnce({ integrationsToAdd: ['linear'] })
1274
- .mockResolvedValueOnce({ teamId: 'TEAM', apiKeyEnv: 'MY_KEY' })
1275
- .mockResolvedValueOnce({ saveChoice: 'repo' });
1276
- await runCli(['init']);
1277
- expect(wtconfig.saveRepoConfig).toHaveBeenCalledWith('/repo', expect.objectContaining({
1278
- integrations: { linear: { teamId: 'TEAM', apiKeyEnv: 'MY_KEY' } },
1279
- }));
1280
- });
1281
- });
1282
- describe('default command behavior', () => {
1283
- it('defaults to show command when no command provided', async () => {
1284
- await runCli([]);
1285
- expect(mockConsoleLog).toHaveBeenCalledWith(expect.stringContaining('Current Configuration'));
1286
- });
1287
- });
1288
- });
1289
- //# sourceMappingURL=wtconfig.test.js.map