@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,608 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { spawnSync, execSync, spawn, } from 'child_process';
3
- import * as path from 'path';
4
- import { EventEmitter } from 'stream';
5
- import * as git from './git.js';
6
- // Mock child_process
7
- vi.mock('child_process', () => ({
8
- spawnSync: vi.fn(),
9
- execSync: vi.fn(),
10
- spawn: vi.fn(),
11
- }));
12
- const mockSpawnSync = vi.mocked(spawnSync);
13
- const mockExecSync = vi.mocked(execSync);
14
- const mockSpawn = vi.mocked(spawn);
15
- /**
16
- * Helper to create a successful spawnSync result
17
- */
18
- function mockSpawnSuccess(stdout) {
19
- return {
20
- status: 0,
21
- signal: null,
22
- output: ['', stdout, ''],
23
- pid: 123,
24
- stdout,
25
- stderr: '',
26
- error: undefined,
27
- };
28
- }
29
- /**
30
- * Helper to create a failed spawnSync result
31
- */
32
- function mockSpawnFailure(stderr) {
33
- return {
34
- status: 1,
35
- signal: null,
36
- output: ['', '', stderr],
37
- pid: 123,
38
- stdout: '',
39
- stderr,
40
- error: undefined,
41
- };
42
- }
43
- describe('git', () => {
44
- beforeEach(() => {
45
- vi.clearAllMocks();
46
- });
47
- describe('exec', () => {
48
- it('executes git command and returns output with trailing whitespace trimmed', () => {
49
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('output with trailing whitespace \n'));
50
- const result = git.exec(['status']);
51
- // Leading whitespace is preserved (important for git status), trailing is trimmed
52
- expect(result).toBe('output with trailing whitespace');
53
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['status'], expect.any(Object));
54
- });
55
- it('preserves leading whitespace in output', () => {
56
- // Leading spaces are significant in git status --porcelain output
57
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(' M file.txt\n'));
58
- const result = git.exec(['status', '--porcelain']);
59
- expect(result).toBe(' M file.txt');
60
- });
61
- it('passes cwd option correctly', () => {
62
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('output'));
63
- git.exec(['status'], { cwd: '/some/path' });
64
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['status'], expect.objectContaining({ cwd: '/some/path' }));
65
- });
66
- it('throws error with stderr message on failure', () => {
67
- mockSpawnSync.mockReturnValue(mockSpawnFailure('fatal: not a git repository'));
68
- expect(() => git.exec(['status'])).toThrow('Git command failed');
69
- });
70
- });
71
- describe('execSafe', () => {
72
- it('returns output on success', () => {
73
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('output'));
74
- const result = git.execSafe(['status']);
75
- expect(result).toBe('output');
76
- });
77
- it('returns null on failure', () => {
78
- mockSpawnSync.mockReturnValue(mockSpawnFailure('Command failed'));
79
- const result = git.execSafe(['status']);
80
- expect(result).toBeNull();
81
- });
82
- });
83
- describe('getRepoRoot', () => {
84
- it('returns normalized path from git rev-parse', () => {
85
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('/home/user/repo\n'));
86
- const result = git.getRepoRoot();
87
- expect(result).toContain('repo');
88
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['rev-parse', '--show-toplevel'], expect.any(Object));
89
- });
90
- });
91
- describe('getRepoName', () => {
92
- it('extracts name from SSH remote URL', () => {
93
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('git@github.com:org/my-repo.git'));
94
- const result = git.getRepoName('/repo');
95
- expect(result).toBe('my-repo');
96
- });
97
- it('extracts name from HTTPS remote URL', () => {
98
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('https://github.com/org/my-repo.git'));
99
- const result = git.getRepoName('/repo');
100
- expect(result).toBe('my-repo');
101
- });
102
- it('extracts name from URL without .git suffix', () => {
103
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('https://github.com/org/my-repo'));
104
- const result = git.getRepoName('/repo');
105
- expect(result).toBe('my-repo');
106
- });
107
- it('falls back to directory name when no remote', () => {
108
- mockSpawnSync.mockReturnValue(mockSpawnFailure('No remote'));
109
- const result = git.getRepoName('/home/user/my-project');
110
- expect(result).toBe('my-project');
111
- });
112
- it('extracts name from Unix local path with .git suffix', () => {
113
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('/path/to/my-repo.git'));
114
- const result = git.getRepoName('/repo');
115
- expect(result).toBe('my-repo');
116
- });
117
- it('extracts name from Windows local path with .git suffix', () => {
118
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('C:\\Users\\test\\repos\\my-repo.git'));
119
- const result = git.getRepoName('/repo');
120
- expect(result).toBe('my-repo');
121
- });
122
- it('extracts name from Windows local path without .git suffix', () => {
123
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('C:\\Users\\test\\repos\\my-repo'));
124
- const result = git.getRepoName('/repo');
125
- expect(result).toBe('my-repo');
126
- });
127
- it('extracts name from Windows short path format', () => {
128
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('C:\\Users\\RUNNER~1\\AppData\\Local\\Temp\\main-repo.git'));
129
- const result = git.getRepoName('/repo');
130
- expect(result).toBe('main-repo');
131
- });
132
- });
133
- describe('getCurrentBranch', () => {
134
- it('returns branch name', () => {
135
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('feature/my-branch'));
136
- const result = git.getCurrentBranch();
137
- expect(result).toBe('feature/my-branch');
138
- });
139
- it('returns null for detached HEAD', () => {
140
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('HEAD'));
141
- const result = git.getCurrentBranch();
142
- expect(result).toBeNull();
143
- });
144
- });
145
- describe('isDetachedHead', () => {
146
- it('returns true when in detached HEAD state', () => {
147
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('HEAD'));
148
- expect(git.isDetachedHead()).toBe(true);
149
- });
150
- it('returns false when on a branch', () => {
151
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('main'));
152
- expect(git.isDetachedHead()).toBe(false);
153
- });
154
- });
155
- describe('getWorkingTreeStatus', () => {
156
- it('returns clean for empty status', () => {
157
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
158
- expect(git.getWorkingTreeStatus()).toBe('clean');
159
- });
160
- it('returns staged_only for staged changes', () => {
161
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('M file.txt'));
162
- expect(git.getWorkingTreeStatus()).toBe('staged_only');
163
- });
164
- it('returns unstaged_only for unstaged changes', () => {
165
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(' M file.txt'));
166
- expect(git.getWorkingTreeStatus()).toBe('unstaged_only');
167
- });
168
- it('returns unstaged_only for untracked files', () => {
169
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('?? newfile.txt'));
170
- expect(git.getWorkingTreeStatus()).toBe('unstaged_only');
171
- });
172
- it('returns both for staged and unstaged changes', () => {
173
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('MM file.txt'));
174
- expect(git.getWorkingTreeStatus()).toBe('both');
175
- });
176
- it('returns both for staged changes and untracked files', () => {
177
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('M staged.txt\n?? untracked.txt'));
178
- expect(git.getWorkingTreeStatus()).toBe('both');
179
- });
180
- });
181
- describe('getStagedFiles', () => {
182
- it('returns list of staged files', () => {
183
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('file1.txt\nfile2.txt\n'));
184
- const result = git.getStagedFiles();
185
- expect(result).toEqual(['file1.txt', 'file2.txt']);
186
- });
187
- it('returns empty array when nothing staged', () => {
188
- mockSpawnSync.mockReturnValue(mockSpawnFailure('No staged files'));
189
- const result = git.getStagedFiles();
190
- expect(result).toEqual([]);
191
- });
192
- });
193
- describe('getUnstagedFiles', () => {
194
- it('returns list of unstaged and untracked files', () => {
195
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(' M modified.txt\n?? untracked.txt'));
196
- const result = git.getUnstagedFiles();
197
- expect(result).toEqual(['modified.txt', 'untracked.txt']);
198
- });
199
- it('excludes staged-only files', () => {
200
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('M staged.txt\n M both.txt'));
201
- const result = git.getUnstagedFiles();
202
- expect(result).toEqual(['both.txt']);
203
- });
204
- it('returns empty array when working tree is clean', () => {
205
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
206
- const result = git.getUnstagedFiles();
207
- expect(result).toEqual([]);
208
- });
209
- });
210
- describe('listWorktrees', () => {
211
- it('parses worktree list porcelain output', () => {
212
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('worktree /home/user/repo\n' +
213
- 'HEAD abc123def456\n' +
214
- 'branch refs/heads/main\n' +
215
- '\n' +
216
- 'worktree /home/user/repo.pr42\n' +
217
- 'HEAD def456abc123\n' +
218
- 'branch refs/heads/feature/test\n' +
219
- '\n'));
220
- const result = git.listWorktrees();
221
- expect(result).toHaveLength(2);
222
- expect(result[0]).toEqual({
223
- path: '/home/user/repo',
224
- commit: 'abc123def456',
225
- branch: 'main',
226
- isMain: true,
227
- isBare: false,
228
- isLocked: false,
229
- isPrunable: false,
230
- });
231
- expect(result[1]).toEqual({
232
- path: '/home/user/repo.pr42',
233
- commit: 'def456abc123',
234
- branch: 'feature/test',
235
- isMain: false,
236
- isBare: false,
237
- isLocked: false,
238
- isPrunable: false,
239
- });
240
- });
241
- it('handles bare repository', () => {
242
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('worktree /home/user/repo.git\n' + 'bare\n' + '\n'));
243
- const result = git.listWorktrees();
244
- expect(result[0].isBare).toBe(true);
245
- expect(result[0].isMain).toBe(true);
246
- });
247
- it('handles locked and prunable worktrees', () => {
248
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('worktree /home/user/repo.pr1\n' +
249
- 'HEAD abc123\n' +
250
- 'branch refs/heads/test\n' +
251
- 'locked\n' +
252
- 'prunable\n' +
253
- '\n'));
254
- const result = git.listWorktrees();
255
- expect(result[0].isLocked).toBe(true);
256
- expect(result[0].isPrunable).toBe(true);
257
- });
258
- it('handles detached HEAD in worktree', () => {
259
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('worktree /home/user/repo\n' + 'HEAD abc123\n' + 'detached\n' + '\n'));
260
- const result = git.listWorktrees();
261
- expect(result[0].branch).toBeNull();
262
- });
263
- });
264
- describe('getCommitRelationship', () => {
265
- it('returns same when HEAD equals base', () => {
266
- mockSpawnSync
267
- .mockReturnValueOnce(mockSpawnSuccess('abc123')) // getHeadCommit
268
- .mockReturnValueOnce(mockSpawnSuccess('abc123')); // getRefCommit
269
- const result = git.getCommitRelationship('main');
270
- expect(result).toBe('same');
271
- });
272
- it('returns divergent when base branch does not exist', () => {
273
- mockSpawnSync
274
- .mockReturnValueOnce(mockSpawnSuccess('abc123')) // getHeadCommit
275
- .mockReturnValueOnce(mockSpawnFailure('unknown revision')); // getRefCommit fails
276
- const result = git.getCommitRelationship('main');
277
- expect(result).toBe('divergent');
278
- });
279
- });
280
- describe('getCommitsAhead', () => {
281
- it('returns list of commits ahead of base', () => {
282
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('abc123 First commit\ndef456 Second commit'));
283
- const result = git.getCommitsAhead('main');
284
- expect(result).toEqual(['abc123 First commit', 'def456 Second commit']);
285
- });
286
- it('returns empty array when not ahead', () => {
287
- mockSpawnSync.mockReturnValue(mockSpawnFailure('No commits'));
288
- const result = git.getCommitsAhead('main');
289
- expect(result).toEqual([]);
290
- });
291
- });
292
- describe('addWorktree', () => {
293
- it('creates worktree with existing branch', () => {
294
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
295
- git.addWorktree('/path/to/worktree', 'feature-branch');
296
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['worktree', 'add', '/path/to/worktree', 'feature-branch'], expect.any(Object));
297
- });
298
- it('creates worktree with new branch', () => {
299
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
300
- git.addWorktree('/path/to/worktree', 'new-branch', { createBranch: true });
301
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['worktree', 'add', '-b', 'new-branch', '/path/to/worktree'], expect.any(Object));
302
- });
303
- it('creates worktree with new branch from start point', () => {
304
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
305
- git.addWorktree('/path/to/worktree', 'new-branch', {
306
- createBranch: true,
307
- startPoint: 'origin/main',
308
- });
309
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['worktree', 'add', '-b', 'new-branch', '/path/to/worktree', 'origin/main'], expect.any(Object));
310
- });
311
- });
312
- describe('removeWorktree', () => {
313
- it('removes worktree', () => {
314
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
315
- git.removeWorktree('/path/to/worktree');
316
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['worktree', 'remove', '/path/to/worktree'], expect.any(Object));
317
- });
318
- it('force removes worktree', () => {
319
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
320
- git.removeWorktree('/path/to/worktree', { force: true });
321
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['worktree', 'remove', '--force', '/path/to/worktree'], expect.any(Object));
322
- });
323
- });
324
- describe('createBranch', () => {
325
- it('creates branch from HEAD', () => {
326
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
327
- git.createBranch('new-branch');
328
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['branch', 'new-branch'], expect.any(Object));
329
- });
330
- it('creates branch from start point', () => {
331
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
332
- git.createBranch('new-branch', 'origin/main');
333
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['branch', 'new-branch', 'origin/main'], expect.any(Object));
334
- });
335
- });
336
- describe('deleteBranch', () => {
337
- it('deletes branch with -d flag', () => {
338
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
339
- git.deleteBranch('old-branch');
340
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['branch', '-d', 'old-branch'], expect.any(Object));
341
- });
342
- it('force deletes branch with -D flag', () => {
343
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
344
- git.deleteBranch('old-branch', { force: true });
345
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['branch', '-D', 'old-branch'], expect.any(Object));
346
- });
347
- });
348
- describe('commit', () => {
349
- it('creates commit with message', () => {
350
- mockSpawnSync
351
- .mockReturnValueOnce(mockSpawnSuccess('')) // commit
352
- .mockReturnValueOnce(mockSpawnSuccess('abc123')); // getHeadCommit
353
- const result = git.commit({ message: 'Test commit' });
354
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['commit', '-m', 'Test commit'], expect.any(Object));
355
- expect(result).toBe('abc123');
356
- });
357
- it('creates commit with all flag', () => {
358
- mockSpawnSync
359
- .mockReturnValueOnce(mockSpawnSuccess(''))
360
- .mockReturnValueOnce(mockSpawnSuccess('abc123'));
361
- git.commit({ message: 'Test commit', all: true });
362
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['commit', '-a', '-m', 'Test commit'], expect.any(Object));
363
- });
364
- it('creates empty commit when allowed', () => {
365
- mockSpawnSync
366
- .mockReturnValueOnce(mockSpawnSuccess(''))
367
- .mockReturnValueOnce(mockSpawnSuccess('abc123'));
368
- git.commit({ message: 'Empty commit', allowEmpty: true });
369
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['commit', '--allow-empty', '-m', 'Empty commit'], expect.any(Object));
370
- });
371
- });
372
- describe('push', () => {
373
- it('pushes to remote', () => {
374
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
375
- git.push();
376
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['push'], expect.any(Object));
377
- });
378
- it('pushes with upstream flag', () => {
379
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
380
- git.push({ setUpstream: true, remote: 'origin', branch: 'feature' });
381
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['push', '-u', 'origin', 'feature'], expect.any(Object));
382
- });
383
- it('force pushes', () => {
384
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
385
- git.push({ force: true });
386
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['push', '--force'], expect.any(Object));
387
- });
388
- });
389
- describe('stash', () => {
390
- it('creates stash and returns reference', () => {
391
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('Saved working directory'));
392
- const result = git.stash();
393
- expect(result).toBe('stash@{0}');
394
- });
395
- it('returns null when nothing to stash', () => {
396
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('No local changes to save'));
397
- const result = git.stash();
398
- expect(result).toBeNull();
399
- });
400
- it('stashes with keep-index flag', () => {
401
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('Saved'));
402
- git.stash({ keepIndex: true });
403
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['stash', 'push', '--keep-index'], expect.any(Object));
404
- });
405
- it('stashes with message', () => {
406
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('Saved'));
407
- git.stash({ message: 'WIP: feature' });
408
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['stash', 'push', '-m', 'WIP: feature'], expect.any(Object));
409
- });
410
- it('stashes untracked files', () => {
411
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('Saved'));
412
- git.stash({ includeUntracked: true });
413
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['stash', 'push', '--include-untracked'], expect.any(Object));
414
- });
415
- });
416
- describe('branchExists', () => {
417
- it('returns true when branch exists', () => {
418
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('abc123'));
419
- expect(git.branchExists('main')).toBe(true);
420
- });
421
- it('returns false when branch does not exist', () => {
422
- mockSpawnSync.mockReturnValue(mockSpawnFailure('unknown revision'));
423
- expect(git.branchExists('nonexistent')).toBe(false);
424
- });
425
- });
426
- describe('remoteBranchExists', () => {
427
- it('returns true when remote branch exists', () => {
428
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('abc123'));
429
- expect(git.remoteBranchExists('main')).toBe(true);
430
- });
431
- it('returns false when remote branch does not exist', () => {
432
- mockSpawnSync.mockReturnValue(mockSpawnFailure('unknown revision'));
433
- expect(git.remoteBranchExists('nonexistent')).toBe(false);
434
- });
435
- it('checks specific remote', () => {
436
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('abc123'));
437
- git.remoteBranchExists('main', 'upstream');
438
- expect(mockSpawnSync).toHaveBeenCalledWith('git', ['rev-parse', '--verify', 'refs/remotes/upstream/main'], expect.any(Object));
439
- });
440
- });
441
- describe('getMainWorktreeRoot', () => {
442
- it('returns repo root when in main worktree', () => {
443
- // Use path.join to create platform-appropriate paths
444
- const repoPath = path.join('/home', 'user', 'repo');
445
- const gitDir = path.join(repoPath, '.git');
446
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(gitDir));
447
- const result = git.getMainWorktreeRoot(repoPath);
448
- expect(result).toBe(path.resolve(repoPath));
449
- });
450
- it('returns main worktree root when in linked worktree', () => {
451
- const mainRepo = path.join('/home', 'user', 'main-repo');
452
- const worktreeGitDir = path.join(mainRepo, '.git', 'worktrees', 'feature-branch');
453
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(worktreeGitDir));
454
- const result = git.getMainWorktreeRoot(path.join('/home', 'user', 'main-repo.pr42'));
455
- expect(result).toBe(path.resolve(mainRepo));
456
- });
457
- it('falls back to getRepoRoot when commonDir is null', () => {
458
- const fallbackPath = path.join('/fallback', 'root');
459
- // First call (git-common-dir) fails, second call (show-toplevel) succeeds
460
- mockSpawnSync
461
- .mockReturnValueOnce(mockSpawnFailure('failed'))
462
- .mockReturnValueOnce(mockSpawnSuccess(fallbackPath));
463
- const result = git.getMainWorktreeRoot();
464
- expect(result).toContain('fallback');
465
- });
466
- });
467
- describe('isGitIgnored', () => {
468
- it('returns true when file is ignored', () => {
469
- mockSpawnSync.mockReturnValue(mockSpawnSuccess('node_modules/'));
470
- expect(git.isGitIgnored('node_modules/')).toBe(true);
471
- });
472
- it('returns false when file is not ignored', () => {
473
- mockSpawnSync.mockReturnValue(mockSpawnFailure('no output for unignored files'));
474
- expect(git.isGitIgnored('src/index.ts')).toBe(false);
475
- });
476
- it('returns false when check-ignore returns empty', () => {
477
- mockSpawnSync.mockReturnValue(mockSpawnSuccess(''));
478
- expect(git.isGitIgnored('src/index.ts')).toBe(false);
479
- });
480
- });
481
- describe('checkGitInstalled', () => {
482
- it('returns true when git is installed', () => {
483
- mockExecSync.mockReturnValue('git version 2.39.0');
484
- expect(git.checkGitInstalled()).toBe(true);
485
- });
486
- it('returns false when git is not installed', () => {
487
- mockExecSync.mockImplementation(() => {
488
- throw new Error('command not found: git');
489
- });
490
- expect(git.checkGitInstalled()).toBe(false);
491
- });
492
- });
493
- // ============================================================================
494
- // Async function tests
495
- // ============================================================================
496
- /**
497
- * Helper to create a mock child process for async spawn
498
- */
499
- function createMockChildProcess(stdout, stderr, exitCode) {
500
- const child = new EventEmitter();
501
- // Create mock readable streams
502
- const mockStdout = new EventEmitter();
503
- const mockStderr = new EventEmitter();
504
- child.stdout = mockStdout;
505
- child.stderr = mockStderr;
506
- // Emit data and close event on next tick
507
- process.nextTick(() => {
508
- if (stdout) {
509
- child.stdout?.emit('data', Buffer.from(stdout));
510
- }
511
- if (stderr) {
512
- child.stderr?.emit('data', Buffer.from(stderr));
513
- }
514
- child.emit('close', exitCode);
515
- });
516
- return child;
517
- }
518
- describe('execAsync', () => {
519
- it('executes git command and returns output', async () => {
520
- mockSpawn.mockReturnValue(createMockChildProcess('output\n', '', 0));
521
- const result = await git.execAsync(['status']);
522
- expect(result).toBe('output');
523
- expect(mockSpawn).toHaveBeenCalledWith('git', ['status'], expect.any(Object));
524
- });
525
- it('rejects on non-zero exit code', async () => {
526
- mockSpawn.mockReturnValue(createMockChildProcess('', 'fatal: error', 1));
527
- await expect(git.execAsync(['invalid'])).rejects.toThrow('Git command failed');
528
- });
529
- it('rejects on spawn error', async () => {
530
- const child = new EventEmitter();
531
- child.stdout = new EventEmitter();
532
- child.stderr = new EventEmitter();
533
- mockSpawn.mockReturnValue(child);
534
- const promise = git.execAsync(['status']);
535
- process.nextTick(() => {
536
- child.emit('error', new Error('spawn failed'));
537
- });
538
- await expect(promise).rejects.toThrow('spawn failed');
539
- });
540
- it('passes cwd option correctly', async () => {
541
- mockSpawn.mockReturnValue(createMockChildProcess('output', '', 0));
542
- await git.execAsync(['status'], { cwd: '/some/path' });
543
- expect(mockSpawn).toHaveBeenCalledWith('git', ['status'], expect.objectContaining({ cwd: '/some/path' }));
544
- });
545
- });
546
- describe('fetchAsync', () => {
547
- it('fetches from remote', async () => {
548
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
549
- await git.fetchAsync('origin');
550
- expect(mockSpawn).toHaveBeenCalledWith('git', ['fetch', 'origin'], expect.any(Object));
551
- });
552
- it('uses default remote', async () => {
553
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
554
- await git.fetchAsync();
555
- expect(mockSpawn).toHaveBeenCalledWith('git', ['fetch', 'origin'], expect.any(Object));
556
- });
557
- });
558
- describe('addWorktreeAsync', () => {
559
- it('creates worktree with existing branch', async () => {
560
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
561
- await git.addWorktreeAsync('/path/to/worktree', 'feature-branch');
562
- expect(mockSpawn).toHaveBeenCalledWith('git', ['worktree', 'add', '/path/to/worktree', 'feature-branch'], expect.any(Object));
563
- });
564
- it('creates worktree with new branch', async () => {
565
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
566
- await git.addWorktreeAsync('/path/to/worktree', 'new-branch', { createBranch: true });
567
- expect(mockSpawn).toHaveBeenCalledWith('git', ['worktree', 'add', '-b', 'new-branch', '/path/to/worktree'], expect.any(Object));
568
- });
569
- it('creates worktree with new branch from start point', async () => {
570
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
571
- await git.addWorktreeAsync('/path/to/worktree', 'new-branch', {
572
- createBranch: true,
573
- startPoint: 'origin/main',
574
- });
575
- expect(mockSpawn).toHaveBeenCalledWith('git', ['worktree', 'add', '-b', 'new-branch', '/path/to/worktree', 'origin/main'], expect.any(Object));
576
- });
577
- });
578
- describe('removeWorktreeAsync', () => {
579
- it('removes worktree', async () => {
580
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
581
- await git.removeWorktreeAsync('/path/to/worktree');
582
- expect(mockSpawn).toHaveBeenCalledWith('git', ['worktree', 'remove', '/path/to/worktree'], expect.any(Object));
583
- });
584
- it('force removes worktree', async () => {
585
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
586
- await git.removeWorktreeAsync('/path/to/worktree', { force: true });
587
- expect(mockSpawn).toHaveBeenCalledWith('git', ['worktree', 'remove', '--force', '/path/to/worktree'], expect.any(Object));
588
- });
589
- });
590
- describe('pushAsync', () => {
591
- it('pushes to remote', async () => {
592
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
593
- await git.pushAsync();
594
- expect(mockSpawn).toHaveBeenCalledWith('git', ['push'], expect.any(Object));
595
- });
596
- it('pushes with upstream flag', async () => {
597
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
598
- await git.pushAsync({ setUpstream: true, remote: 'origin', branch: 'feature' });
599
- expect(mockSpawn).toHaveBeenCalledWith('git', ['push', '-u', 'origin', 'feature'], expect.any(Object));
600
- });
601
- it('force pushes', async () => {
602
- mockSpawn.mockReturnValue(createMockChildProcess('', '', 0));
603
- await git.pushAsync({ force: true });
604
- expect(mockSpawn).toHaveBeenCalledWith('git', ['push', '--force'], expect.any(Object));
605
- });
606
- });
607
- });
608
- //# sourceMappingURL=git.test.js.map