@iloom/cli 0.9.2 → 0.10.1

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 (231) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +160 -41
  3. package/dist/{BranchNamingService-K6XNWQ6C.js → BranchNamingService-25KSZAEM.js} +2 -2
  4. package/dist/ClaudeContextManager-66GR4BGM.js +14 -0
  5. package/dist/ClaudeService-7KM5NA5Z.js +13 -0
  6. package/dist/{GitHubService-TGWJN4V4.js → GitHubService-MEHKHUQP.js} +4 -4
  7. package/dist/IssueTrackerFactory-NG53YX5S.js +14 -0
  8. package/dist/{LoomLauncher-73NXL2CL.js → LoomLauncher-TDLZSYG2.js} +9 -9
  9. package/dist/{MetadataManager-W3C54UYT.js → MetadataManager-5QZSTKNN.js} +2 -2
  10. package/dist/{ProjectCapabilityDetector-N5L7T4IY.js → ProjectCapabilityDetector-5KSYUTBJ.js} +3 -3
  11. package/dist/{PromptTemplateManager-36YLQRHP.js → PromptTemplateManager-YOE2SIPG.js} +2 -2
  12. package/dist/README.md +160 -41
  13. package/dist/{SettingsManager-AW3JTJHD.js → SettingsManager-FNKCOZMQ.js} +4 -2
  14. package/dist/agents/iloom-artifact-reviewer.md +11 -0
  15. package/dist/agents/iloom-code-reviewer.md +14 -0
  16. package/dist/agents/iloom-issue-analyze-and-plan.md +55 -12
  17. package/dist/agents/iloom-issue-analyzer.md +49 -6
  18. package/dist/agents/iloom-issue-complexity-evaluator.md +47 -6
  19. package/dist/agents/iloom-issue-enhancer.md +86 -7
  20. package/dist/agents/iloom-issue-implementer.md +48 -7
  21. package/dist/agents/iloom-issue-planner.md +115 -62
  22. package/dist/{build-THZI572G.js → build-VHGEMXBA.js} +9 -9
  23. package/dist/chunk-4232AHNQ.js +35 -0
  24. package/dist/chunk-4232AHNQ.js.map +1 -0
  25. package/dist/chunk-4E7LCFUG.js +24 -0
  26. package/dist/chunk-4E7LCFUG.js.map +1 -0
  27. package/dist/{chunk-AR5QKYNE.js → chunk-4FGEGQW4.js} +4 -4
  28. package/dist/{chunk-R4YWBGY6.js → chunk-5FJWO4IT.js} +67 -22
  29. package/dist/chunk-5FJWO4IT.js.map +1 -0
  30. package/dist/{chunk-VPTAX5TR.js → chunk-5RPBYK5Q.js} +35 -30
  31. package/dist/chunk-5RPBYK5Q.js.map +1 -0
  32. package/dist/{chunk-YKFCCV6S.js → chunk-63QWFWH3.js} +7 -7
  33. package/dist/chunk-63QWFWH3.js.map +1 -0
  34. package/dist/{chunk-RI2YL6TK.js → chunk-7VHJNVLF.js} +80 -23
  35. package/dist/chunk-7VHJNVLF.js.map +1 -0
  36. package/dist/{chunk-B7U6OKUR.js → chunk-C6HNNJIV.js} +11 -3
  37. package/dist/chunk-C6HNNJIV.js.map +1 -0
  38. package/dist/{chunk-A7NJF73J.js → chunk-CVCTIDDK.js} +4 -4
  39. package/dist/{chunk-Z2TWEXR7.js → chunk-E6KOWMKA.js} +6 -6
  40. package/dist/chunk-E6KOWMKA.js.map +1 -0
  41. package/dist/{chunk-3I4ONZRT.js → chunk-EVPZFV3K.js} +10 -10
  42. package/dist/chunk-EVPZFV3K.js.map +1 -0
  43. package/dist/{chunk-IZIYLYPK.js → chunk-G5V75JD5.js} +2 -2
  44. package/dist/chunk-GRISNU6G.js +651 -0
  45. package/dist/chunk-GRISNU6G.js.map +1 -0
  46. package/dist/chunk-HEXKPKCK.js +1396 -0
  47. package/dist/chunk-HEXKPKCK.js.map +1 -0
  48. package/dist/{chunk-TC7APDKU.js → chunk-I5T677EA.js} +2 -2
  49. package/dist/{chunk-KBEIQP4G.js → chunk-KB64WNBZ.js} +43 -3
  50. package/dist/chunk-KB64WNBZ.js.map +1 -0
  51. package/dist/{chunk-NWMORW3U.js → chunk-KIK2ZFAL.js} +2 -2
  52. package/dist/{chunk-CWRI4JC3.js → chunk-KKV5WH5M.js} +30 -31
  53. package/dist/chunk-KKV5WH5M.js.map +1 -0
  54. package/dist/{chunk-DGG2VY7B.js → chunk-KVHIAWVT.js} +9 -9
  55. package/dist/chunk-KVHIAWVT.js.map +1 -0
  56. package/dist/{chunk-OFDN5NKS.js → chunk-KXDRI47U.js} +69 -12
  57. package/dist/chunk-KXDRI47U.js.map +1 -0
  58. package/dist/{chunk-NUACL52E.js → chunk-LLHXQS3C.js} +2 -2
  59. package/dist/chunk-LUKXJSRI.js +73 -0
  60. package/dist/chunk-LUKXJSRI.js.map +1 -0
  61. package/dist/{chunk-TL72BGP6.js → chunk-MORRVYPT.js} +2 -2
  62. package/dist/chunk-OTGH2HRS.js +1427 -0
  63. package/dist/chunk-OTGH2HRS.js.map +1 -0
  64. package/dist/{chunk-7ZEHSSUP.js → chunk-P4O6EH46.js} +4 -4
  65. package/dist/{chunk-KAYXR544.js → chunk-QVLPWNE3.js} +2 -2
  66. package/dist/chunk-QZWEJVWV.js +207 -0
  67. package/dist/chunk-QZWEJVWV.js.map +1 -0
  68. package/dist/chunk-RJ3VBUFK.js +781 -0
  69. package/dist/chunk-RJ3VBUFK.js.map +1 -0
  70. package/dist/chunk-RSYT7MVI.js +202 -0
  71. package/dist/chunk-RSYT7MVI.js.map +1 -0
  72. package/dist/{chunk-6IIL5M2L.js → chunk-S7PZA6IV.js} +10 -8
  73. package/dist/{chunk-6IIL5M2L.js.map → chunk-S7PZA6IV.js.map} +1 -1
  74. package/dist/chunk-SKSYYBCU.js +229 -0
  75. package/dist/chunk-SKSYYBCU.js.map +1 -0
  76. package/dist/{chunk-ULSWCPQG.js → chunk-SWSJWA2S.js} +476 -5
  77. package/dist/chunk-SWSJWA2S.js.map +1 -0
  78. package/dist/{chunk-KXGQYLFZ.js → chunk-UKBAJ2QQ.js} +61 -7
  79. package/dist/chunk-UKBAJ2QQ.js.map +1 -0
  80. package/dist/{chunk-FO5GGFOV.js → chunk-UR5DGNUO.js} +71 -9
  81. package/dist/chunk-UR5DGNUO.js.map +1 -0
  82. package/dist/{chunk-QN47QVBX.js → chunk-UUEW5KWB.js} +1 -1
  83. package/dist/chunk-UUEW5KWB.js.map +1 -0
  84. package/dist/{chunk-4CO6KG5S.js → chunk-VG45TUYK.js} +53 -7
  85. package/dist/{chunk-4CO6KG5S.js.map → chunk-VG45TUYK.js.map} +1 -1
  86. package/dist/{chunk-4LKGCFGG.js → chunk-WWKOVDWC.js} +2 -2
  87. package/dist/{chunk-KJTVU3HZ.js → chunk-WXIM2WS7.js} +8 -8
  88. package/dist/chunk-WXIM2WS7.js.map +1 -0
  89. package/dist/{chunk-VOGGLPG5.js → chunk-YQ57ORTV.js} +14 -1
  90. package/dist/chunk-YQ57ORTV.js.map +1 -0
  91. package/dist/{chunk-SOSQILHO.js → chunk-ZNMPGMHY.js} +44 -797
  92. package/dist/chunk-ZNMPGMHY.js.map +1 -0
  93. package/dist/{claude-TP2QO3BU.js → claude-7GGEWVEM.js} +2 -2
  94. package/dist/{cleanup-PJRIFFU4.js → cleanup-6PVAC4NI.js} +85 -34
  95. package/dist/cleanup-6PVAC4NI.js.map +1 -0
  96. package/dist/cli.js +630 -801
  97. package/dist/cli.js.map +1 -1
  98. package/dist/{commit-IVP3M4HG.js → commit-FZR5XDQG.js} +26 -23
  99. package/dist/commit-FZR5XDQG.js.map +1 -0
  100. package/dist/{compile-R2J65HBQ.js → compile-7ALJHZ4N.js} +9 -9
  101. package/dist/{contribute-VDZXHK5Y.js → contribute-5GKLK3BQ.js} +14 -6
  102. package/dist/contribute-5GKLK3BQ.js.map +1 -0
  103. package/dist/{dev-server-7F622OEO.js → dev-server-7SMIB7OF.js} +29 -15
  104. package/dist/dev-server-7SMIB7OF.js.map +1 -0
  105. package/dist/{feedback-E7VET7CL.js → feedback-G2GJFN2F.js} +18 -16
  106. package/dist/{feedback-E7VET7CL.js.map → feedback-G2GJFN2F.js.map} +1 -1
  107. package/dist/{git-2QDQ2X2S.js → git-GTLKAZRJ.js} +4 -4
  108. package/dist/hooks/iloom-hook.js +15 -0
  109. package/dist/ignite-H2O5Y5A2.js +34 -0
  110. package/dist/ignite-H2O5Y5A2.js.map +1 -0
  111. package/dist/index.d.ts +482 -58
  112. package/dist/index.js +1340 -44
  113. package/dist/index.js.map +1 -1
  114. package/dist/{init-676DHF6R.js → init-32YOKXRL.js} +57 -21
  115. package/dist/init-32YOKXRL.js.map +1 -0
  116. package/dist/{issues-PJSOLOBJ.js → issues-4UUAQ5K6.js} +61 -20
  117. package/dist/issues-4UUAQ5K6.js.map +1 -0
  118. package/dist/{lint-CJM7BAIM.js → lint-AAN2NZWG.js} +9 -9
  119. package/dist/mcp/harness-server.js +140 -0
  120. package/dist/mcp/harness-server.js.map +1 -0
  121. package/dist/mcp/issue-management-server.js +2599 -262
  122. package/dist/mcp/issue-management-server.js.map +1 -1
  123. package/dist/mcp/recap-server.js +144 -21
  124. package/dist/mcp/recap-server.js.map +1 -1
  125. package/dist/{neon-helpers-VVFFTLXE.js → neon-helpers-CQN2PB4S.js} +3 -3
  126. package/dist/neon-helpers-CQN2PB4S.js.map +1 -0
  127. package/dist/{open-544H7JF5.js → open-FXWW3VI4.js} +15 -15
  128. package/dist/open-FXWW3VI4.js.map +1 -0
  129. package/dist/{plan-Q7ELXDLC.js → plan-RQ5FPIGF.js} +358 -40
  130. package/dist/plan-RQ5FPIGF.js.map +1 -0
  131. package/dist/{projects-LH362JZQ.js → projects-2UOXFLNZ.js} +4 -4
  132. package/dist/prompts/CLAUDE.md +62 -0
  133. package/dist/prompts/init-prompt.txt +430 -34
  134. package/dist/prompts/issue-prompt.txt +473 -54
  135. package/dist/prompts/plan-prompt.txt +140 -19
  136. package/dist/prompts/pr-prompt.txt +44 -1
  137. package/dist/prompts/regular-prompt.txt +42 -1
  138. package/dist/prompts/session-summary-prompt.txt +14 -0
  139. package/dist/prompts/swarm-orchestrator-prompt.txt +464 -0
  140. package/dist/{rebase-YND35CIE.js → rebase-6NVLX5V7.js} +21 -12
  141. package/dist/rebase-6NVLX5V7.js.map +1 -0
  142. package/dist/{recap-3W7COH7D.js → recap-OMBOKJST.js} +47 -19
  143. package/dist/recap-OMBOKJST.js.map +1 -0
  144. package/dist/{run-QUXJKDQQ.js → run-BBXLRIZB.js} +15 -15
  145. package/dist/run-BBXLRIZB.js.map +1 -0
  146. package/dist/schema/package-iloom.schema.json +58 -0
  147. package/dist/schema/settings.schema.json +149 -15
  148. package/dist/{shell-QGECBLST.js → shell-RF7LTND5.js} +14 -7
  149. package/dist/shell-RF7LTND5.js.map +1 -0
  150. package/dist/{summary-G2T4452H.js → summary-WTQZ7XG2.js} +27 -25
  151. package/dist/summary-WTQZ7XG2.js.map +1 -0
  152. package/dist/{test-EA5NQFDC.js → test-SGO6I5Z7.js} +9 -9
  153. package/dist/{test-git-M7LSLEFL.js → test-git-XM4TM65W.js} +4 -4
  154. package/dist/test-jira-LDTOYFSD.js +96 -0
  155. package/dist/test-jira-LDTOYFSD.js.map +1 -0
  156. package/dist/{test-prefix-64NAAUON.js → test-prefix-GBO37XCN.js} +4 -4
  157. package/dist/{test-webserver-OK6Z5FJM.js → test-webserver-NZ3JTVLL.js} +6 -6
  158. package/dist/{vscode-AR5NNXXI.js → vscode-6XUGHJKL.js} +7 -7
  159. package/package.json +5 -1
  160. package/dist/ClaudeContextManager-HR5JQKAI.js +0 -14
  161. package/dist/ClaudeService-TK7FMC2X.js +0 -13
  162. package/dist/chunk-3I4ONZRT.js.map +0 -1
  163. package/dist/chunk-B7U6OKUR.js.map +0 -1
  164. package/dist/chunk-CWRI4JC3.js.map +0 -1
  165. package/dist/chunk-DGG2VY7B.js.map +0 -1
  166. package/dist/chunk-FJDRTVJX.js +0 -520
  167. package/dist/chunk-FJDRTVJX.js.map +0 -1
  168. package/dist/chunk-FO5GGFOV.js.map +0 -1
  169. package/dist/chunk-KBEIQP4G.js.map +0 -1
  170. package/dist/chunk-KJTVU3HZ.js.map +0 -1
  171. package/dist/chunk-KXGQYLFZ.js.map +0 -1
  172. package/dist/chunk-OFDN5NKS.js.map +0 -1
  173. package/dist/chunk-QN47QVBX.js.map +0 -1
  174. package/dist/chunk-R4YWBGY6.js.map +0 -1
  175. package/dist/chunk-RI2YL6TK.js.map +0 -1
  176. package/dist/chunk-SOSQILHO.js.map +0 -1
  177. package/dist/chunk-ULSWCPQG.js.map +0 -1
  178. package/dist/chunk-VOGGLPG5.js.map +0 -1
  179. package/dist/chunk-VPTAX5TR.js.map +0 -1
  180. package/dist/chunk-W6DP5RVR.js +0 -101
  181. package/dist/chunk-W6DP5RVR.js.map +0 -1
  182. package/dist/chunk-WHI5KEOX.js +0 -121
  183. package/dist/chunk-WHI5KEOX.js.map +0 -1
  184. package/dist/chunk-YKFCCV6S.js.map +0 -1
  185. package/dist/chunk-Z2TWEXR7.js.map +0 -1
  186. package/dist/cleanup-PJRIFFU4.js.map +0 -1
  187. package/dist/commit-IVP3M4HG.js.map +0 -1
  188. package/dist/contribute-VDZXHK5Y.js.map +0 -1
  189. package/dist/dev-server-7F622OEO.js.map +0 -1
  190. package/dist/ignite-IW35CDBD.js +0 -784
  191. package/dist/ignite-IW35CDBD.js.map +0 -1
  192. package/dist/init-676DHF6R.js.map +0 -1
  193. package/dist/issues-PJSOLOBJ.js.map +0 -1
  194. package/dist/open-544H7JF5.js.map +0 -1
  195. package/dist/plan-Q7ELXDLC.js.map +0 -1
  196. package/dist/rebase-YND35CIE.js.map +0 -1
  197. package/dist/recap-3W7COH7D.js.map +0 -1
  198. package/dist/run-QUXJKDQQ.js.map +0 -1
  199. package/dist/shell-QGECBLST.js.map +0 -1
  200. package/dist/summary-G2T4452H.js.map +0 -1
  201. /package/dist/{BranchNamingService-K6XNWQ6C.js.map → BranchNamingService-25KSZAEM.js.map} +0 -0
  202. /package/dist/{ClaudeContextManager-HR5JQKAI.js.map → ClaudeContextManager-66GR4BGM.js.map} +0 -0
  203. /package/dist/{ClaudeService-TK7FMC2X.js.map → ClaudeService-7KM5NA5Z.js.map} +0 -0
  204. /package/dist/{GitHubService-TGWJN4V4.js.map → GitHubService-MEHKHUQP.js.map} +0 -0
  205. /package/dist/{MetadataManager-W3C54UYT.js.map → IssueTrackerFactory-NG53YX5S.js.map} +0 -0
  206. /package/dist/{LoomLauncher-73NXL2CL.js.map → LoomLauncher-TDLZSYG2.js.map} +0 -0
  207. /package/dist/{ProjectCapabilityDetector-N5L7T4IY.js.map → MetadataManager-5QZSTKNN.js.map} +0 -0
  208. /package/dist/{PromptTemplateManager-36YLQRHP.js.map → ProjectCapabilityDetector-5KSYUTBJ.js.map} +0 -0
  209. /package/dist/{SettingsManager-AW3JTJHD.js.map → PromptTemplateManager-YOE2SIPG.js.map} +0 -0
  210. /package/dist/{claude-TP2QO3BU.js.map → SettingsManager-FNKCOZMQ.js.map} +0 -0
  211. /package/dist/{build-THZI572G.js.map → build-VHGEMXBA.js.map} +0 -0
  212. /package/dist/{chunk-AR5QKYNE.js.map → chunk-4FGEGQW4.js.map} +0 -0
  213. /package/dist/{chunk-A7NJF73J.js.map → chunk-CVCTIDDK.js.map} +0 -0
  214. /package/dist/{chunk-IZIYLYPK.js.map → chunk-G5V75JD5.js.map} +0 -0
  215. /package/dist/{chunk-TC7APDKU.js.map → chunk-I5T677EA.js.map} +0 -0
  216. /package/dist/{chunk-NWMORW3U.js.map → chunk-KIK2ZFAL.js.map} +0 -0
  217. /package/dist/{chunk-NUACL52E.js.map → chunk-LLHXQS3C.js.map} +0 -0
  218. /package/dist/{chunk-TL72BGP6.js.map → chunk-MORRVYPT.js.map} +0 -0
  219. /package/dist/{chunk-7ZEHSSUP.js.map → chunk-P4O6EH46.js.map} +0 -0
  220. /package/dist/{chunk-KAYXR544.js.map → chunk-QVLPWNE3.js.map} +0 -0
  221. /package/dist/{chunk-4LKGCFGG.js.map → chunk-WWKOVDWC.js.map} +0 -0
  222. /package/dist/{git-2QDQ2X2S.js.map → claude-7GGEWVEM.js.map} +0 -0
  223. /package/dist/{compile-R2J65HBQ.js.map → compile-7ALJHZ4N.js.map} +0 -0
  224. /package/dist/{neon-helpers-VVFFTLXE.js.map → git-GTLKAZRJ.js.map} +0 -0
  225. /package/dist/{lint-CJM7BAIM.js.map → lint-AAN2NZWG.js.map} +0 -0
  226. /package/dist/{projects-LH362JZQ.js.map → projects-2UOXFLNZ.js.map} +0 -0
  227. /package/dist/{test-EA5NQFDC.js.map → test-SGO6I5Z7.js.map} +0 -0
  228. /package/dist/{test-git-M7LSLEFL.js.map → test-git-XM4TM65W.js.map} +0 -0
  229. /package/dist/{test-prefix-64NAAUON.js.map → test-prefix-GBO37XCN.js.map} +0 -0
  230. /package/dist/{test-webserver-OK6Z5FJM.js.map → test-webserver-NZ3JTVLL.js.map} +0 -0
  231. /package/dist/{vscode-AR5NNXXI.js.map → vscode-6XUGHJKL.js.map} +0 -0
@@ -1,46 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  PRManager
4
- } from "./chunk-DGG2VY7B.js";
4
+ } from "./chunk-KVHIAWVT.js";
5
5
  import {
6
6
  calculatePortForBranch,
7
7
  calculatePortFromIdentifier
8
- } from "./chunk-NUACL52E.js";
8
+ } from "./chunk-LLHXQS3C.js";
9
9
  import {
10
10
  installDependencies,
11
11
  runScript
12
- } from "./chunk-4LKGCFGG.js";
12
+ } from "./chunk-WWKOVDWC.js";
13
13
  import {
14
14
  getPackageConfig,
15
15
  hasScript
16
- } from "./chunk-VOGGLPG5.js";
16
+ } from "./chunk-YQ57ORTV.js";
17
+ import {
18
+ generateRandomSessionId
19
+ } from "./chunk-UR5DGNUO.js";
17
20
  import {
18
21
  GitCommandError,
19
22
  PLACEHOLDER_COMMIT_PREFIX,
20
23
  branchExists,
21
- checkRemoteBranchStatus,
22
24
  ensureRepositoryHasCommits,
23
25
  executeGitCommand,
24
26
  extractIssueNumber,
25
27
  extractPRNumber,
26
28
  fetchOrigin,
27
- findMainWorktreePathWithSettings,
28
- findWorktreeForBranch,
29
- getMergeTargetBranch,
30
- hasUncommittedChanges,
31
- isBranchMergedIntoMain,
32
29
  isFileTrackedByGit,
33
30
  pushBranchToRemote
34
- } from "./chunk-AR5QKYNE.js";
35
- import {
36
- SettingsManager
37
- } from "./chunk-RI2YL6TK.js";
31
+ } from "./chunk-4FGEGQW4.js";
38
32
  import {
39
33
  MetadataManager
40
- } from "./chunk-KBEIQP4G.js";
34
+ } from "./chunk-KB64WNBZ.js";
41
35
  import {
42
36
  GitHubService
43
- } from "./chunk-OFDN5NKS.js";
37
+ } from "./chunk-KXDRI47U.js";
38
+ import {
39
+ getLogger
40
+ } from "./chunk-6MLEBAYZ.js";
44
41
  import {
45
42
  calculateForegroundColor,
46
43
  generateColorFromBranchName,
@@ -49,12 +46,6 @@ import {
49
46
  rgbToHex,
50
47
  selectDistinctColor
51
48
  } from "./chunk-433MOLAU.js";
52
- import {
53
- generateRandomSessionId
54
- } from "./chunk-FO5GGFOV.js";
55
- import {
56
- getLogger
57
- } from "./chunk-6MLEBAYZ.js";
58
49
  import {
59
50
  detectDarkMode,
60
51
  findEnvFileForDatabaseUrl,
@@ -244,10 +235,10 @@ var LoomManager = class {
244
235
  * NEW: Checks for existing worktrees and reuses them if found
245
236
  */
246
237
  async createIloom(input) {
247
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
238
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
248
239
  getLogger().info("Fetching issue data...");
249
240
  const issueData = await this.fetchIssueData(input);
250
- if (input.type === "issue" || input.type === "pr" || input.type === "branch") {
241
+ if (input.type === "issue" || input.type === "epic" || input.type === "pr" || input.type === "branch") {
251
242
  getLogger().info("Checking for existing worktree...");
252
243
  const existing = await this.findExistingIloom(input, issueData);
253
244
  if (existing) {
@@ -332,7 +323,7 @@ var LoomManager = class {
332
323
  let draftPrNumber = void 0;
333
324
  let draftPrUrl = void 0;
334
325
  const mergeBehavior = settingsData.mergeBehavior ?? { mode: "local" };
335
- if (mergeBehavior.mode === "github-draft-pr" && (input.type === "issue" || input.type === "branch")) {
326
+ if (mergeBehavior.mode === "github-draft-pr" && (input.type === "issue" || input.type === "epic" || input.type === "branch")) {
336
327
  const prManager = new PRManager(settingsData);
337
328
  getLogger().info("Fetching from origin...");
338
329
  await executeGitCommand(["fetch", "origin"], { cwd: worktreePath });
@@ -367,6 +358,8 @@ var LoomManager = class {
367
358
  getLogger().debug("Placeholder commit created");
368
359
  getLogger().info("Pushing branch to remote for draft PR...");
369
360
  await pushBranchToRemote(branchName, worktreePath, { dryRun: false });
361
+ await executeGitCommand(["reset", "--soft", "HEAD~1"], { cwd: worktreePath });
362
+ getLogger().debug("Placeholder commit removed from local branch (still on remote)");
370
363
  }
371
364
  const existingPR = await prManager.checkForExistingPR(branchName, worktreePath);
372
365
  if (existingPR) {
@@ -376,7 +369,7 @@ var LoomManager = class {
376
369
  } else {
377
370
  const prTitle = (issueData == null ? void 0 : issueData.title) ?? `Work on ${branchName}`;
378
371
  let prBody;
379
- if (input.type === "issue") {
372
+ if (input.type === "issue" || input.type === "epic") {
380
373
  const issueBody = (issueData == null ? void 0 : issueData.body) ? `
381
374
 
382
375
  ## ${issueData.title}
@@ -419,7 +412,7 @@ ${issueData.body}` : "";
419
412
  error
420
413
  );
421
414
  }
422
- if (input.type === "issue") {
415
+ if (input.type === "issue" || input.type === "epic") {
423
416
  try {
424
417
  getLogger().info("Moving issue to In Progress...");
425
418
  if (this.issueTracker.moveIssueToInProgress) {
@@ -440,8 +433,8 @@ ${issueData.body}` : "";
440
433
  const setArguments = (_k = input.options) == null ? void 0 : _k.setArguments;
441
434
  const executablePath = (_l = input.options) == null ? void 0 : _l.executablePath;
442
435
  if (enableClaude || enableCode || enableDevServer || enableTerminal) {
443
- const { LoomLauncher } = await import("./LoomLauncher-73NXL2CL.js");
444
- const { ClaudeContextManager } = await import("./ClaudeContextManager-HR5JQKAI.js");
436
+ const { LoomLauncher } = await import("./LoomLauncher-TDLZSYG2.js");
437
+ const { ClaudeContextManager } = await import("./ClaudeContextManager-66GR4BGM.js");
445
438
  const claudeContext = new ClaudeContextManager(void 0, void 0, this.settings);
446
439
  const launcher = new LoomLauncher(claudeContext, this.settings);
447
440
  await launcher.launchLoom({
@@ -453,7 +446,7 @@ ${issueData.body}` : "";
453
446
  branchName,
454
447
  port,
455
448
  capabilities,
456
- workflowType: input.type === "branch" ? "regular" : input.type,
449
+ workflowType: input.type === "branch" ? "regular" : input.type === "epic" ? "issue" : input.type,
457
450
  identifier: input.identifier,
458
451
  ...(issueData == null ? void 0 : issueData.title) && { title: issueData.title },
459
452
  oneShot,
@@ -467,7 +460,7 @@ ${issueData.body}` : "";
467
460
  const description = (issueData == null ? void 0 : issueData.title) ?? branchName;
468
461
  let issue_numbers = [];
469
462
  let extractedIssueNum = null;
470
- if (input.type === "issue") {
463
+ if (input.type === "issue" || input.type === "epic") {
471
464
  issue_numbers = [String(input.identifier)];
472
465
  } else if (input.type === "pr") {
473
466
  extractedIssueNum = extractIssueNumber(branchName);
@@ -481,7 +474,7 @@ ${issueData.body}` : "";
481
474
  }
482
475
  const sessionId = generateRandomSessionId();
483
476
  let issueUrls = {};
484
- if (input.type === "issue" && (issueData == null ? void 0 : issueData.url)) {
477
+ if ((input.type === "issue" || input.type === "epic") && (issueData == null ? void 0 : issueData.url)) {
485
478
  issueUrls = { [String(input.identifier)]: issueData.url };
486
479
  } else if (input.type === "pr" && extractedIssueNum && (issueData == null ? void 0 : issueData.url)) {
487
480
  const issueUrl = issueData.url.replace(`/pull/${input.identifier}`, `/issues/${extractedIssueNum}`);
@@ -493,6 +486,7 @@ ${issueData.body}` : "";
493
486
  branchName,
494
487
  worktreePath,
495
488
  issueType: input.type,
489
+ ...(input.type === "issue" || input.type === "epic") && { issueKey: this.issueTracker.normalizeIdentifier(input.identifier) },
496
490
  issue_numbers,
497
491
  pr_numbers,
498
492
  issueTracker: this.issueTracker.providerName,
@@ -504,6 +498,9 @@ ${issueData.body}` : "";
504
498
  capabilities,
505
499
  ...draftPrNumber && { draftPrNumber },
506
500
  ...((_o = input.options) == null ? void 0 : _o.oneShot) && { oneShot: input.options.oneShot },
501
+ ...((_p = input.options) == null ? void 0 : _p.childIssueNumbers) && input.options.childIssueNumbers.length > 0 && { childIssueNumbers: input.options.childIssueNumbers },
502
+ ...((_q = input.options) == null ? void 0 : _q.childIssues) && input.options.childIssues.length > 0 && { childIssues: input.options.childIssues },
503
+ ...((_r = input.options) == null ? void 0 : _r.dependencyMap) && Object.keys(input.options.dependencyMap).length > 0 && { dependencyMap: input.options.dependencyMap },
507
504
  ...input.parentLoom && { parentLoom: input.parentLoom }
508
505
  };
509
506
  await this.metadataManager.writeMetadata(worktreePath, metadataInput);
@@ -592,7 +589,7 @@ ${issueData.body}` : "";
592
589
  async checkAndWarnChildLooms(branchName) {
593
590
  let targetBranch = branchName;
594
591
  if (!targetBranch) {
595
- const { getCurrentBranch } = await import("./git-2QDQ2X2S.js");
592
+ const { getCurrentBranch } = await import("./git-GTLKAZRJ.js");
596
593
  targetBranch = await getCurrentBranch();
597
594
  }
598
595
  if (!targetBranch) {
@@ -621,7 +618,7 @@ ${issueData.body}` : "";
621
618
  * Fetch issue/PR data based on input type
622
619
  */
623
620
  async fetchIssueData(input) {
624
- if (input.type === "issue") {
621
+ if (input.type === "issue" || input.type === "epic") {
625
622
  return await this.issueTracker.fetchIssue(input.identifier);
626
623
  } else if (input.type === "pr") {
627
624
  if (this.issueTracker.supportsPullRequests && this.issueTracker.fetchPR) {
@@ -645,7 +642,7 @@ ${issueData.body}` : "";
645
642
  if (input.type === "pr" && issueData && "branch" in issueData) {
646
643
  return issueData.branch;
647
644
  }
648
- if (input.type === "issue" && issueData) {
645
+ if ((input.type === "issue" || input.type === "epic") && issueData) {
649
646
  const branchName = await this.branchNaming.generateBranchName({
650
647
  issueNumber: input.identifier,
651
648
  title: issueData.title
@@ -918,7 +915,7 @@ ${issueData.body}` : "";
918
915
  async setupPortForWeb(worktreePath, input, basePort) {
919
916
  const envFilePath = path2.join(worktreePath, ".env.local");
920
917
  const options = { basePort };
921
- if (input.type === "issue") {
918
+ if (input.type === "issue" || input.type === "epic") {
922
919
  options.issueNumber = input.identifier;
923
920
  } else if (input.type === "pr") {
924
921
  options.prNumber = input.identifier;
@@ -963,7 +960,7 @@ ${issueData.body}` : "";
963
960
  var _a, _b;
964
961
  const settingsData = await this.settings.loadSettings();
965
962
  const basePort = ((_b = (_a = settingsData.capabilities) == null ? void 0 : _a.web) == null ? void 0 : _b.basePort) ?? 3e3;
966
- if (input.type === "issue") {
963
+ if (input.type === "issue" || input.type === "epic") {
967
964
  if (typeof input.identifier === "number") {
968
965
  return this.environment.calculatePort({ basePort, issueNumber: input.identifier });
969
966
  } else if (typeof input.identifier === "string") {
@@ -1017,8 +1014,8 @@ ${issueData.body}` : "";
1017
1014
  let identifier = wt.branch;
1018
1015
  if (loomMetadata == null ? void 0 : loomMetadata.issueType) {
1019
1016
  type = loomMetadata.issueType;
1020
- if (type === "issue" && ((_a = loomMetadata.issue_numbers) == null ? void 0 : _a[0])) {
1021
- const issueId = loomMetadata.issue_numbers[0];
1017
+ if (type === "issue" && (loomMetadata.issueKey || ((_a = loomMetadata.issue_numbers) == null ? void 0 : _a[0]))) {
1018
+ const issueId = loomMetadata.issueKey ?? loomMetadata.issue_numbers[0] ?? "";
1022
1019
  const numericId = parseInt(issueId, 10);
1023
1020
  identifier = isNaN(numericId) ? issueId : numericId;
1024
1021
  } else if (type === "pr" && ((_b = loomMetadata.pr_numbers) == null ? void 0 : _b[0])) {
@@ -1080,7 +1077,7 @@ ${issueData.body}` : "";
1080
1077
  * Ports: handle_existing_worktree() from bash script lines 168-215
1081
1078
  */
1082
1079
  async reuseIloom(worktree, input, issueData) {
1083
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1080
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1084
1081
  const worktreePath = worktree.path;
1085
1082
  const branchName = worktree.branch;
1086
1083
  this.loadMainEnvFile();
@@ -1140,8 +1137,8 @@ ${issueData.body}` : "";
1140
1137
  const executablePath = (_i = input.options) == null ? void 0 : _i.executablePath;
1141
1138
  if (enableClaude || enableCode || enableDevServer || enableTerminal) {
1142
1139
  getLogger().info("Launching workspace components...");
1143
- const { LoomLauncher } = await import("./LoomLauncher-73NXL2CL.js");
1144
- const { ClaudeContextManager } = await import("./ClaudeContextManager-HR5JQKAI.js");
1140
+ const { LoomLauncher } = await import("./LoomLauncher-TDLZSYG2.js");
1141
+ const { ClaudeContextManager } = await import("./ClaudeContextManager-66GR4BGM.js");
1145
1142
  const claudeContext = new ClaudeContextManager(void 0, void 0, this.settings);
1146
1143
  const launcher = new LoomLauncher(claudeContext, this.settings);
1147
1144
  await launcher.launchLoom({
@@ -1153,7 +1150,7 @@ ${issueData.body}` : "";
1153
1150
  branchName,
1154
1151
  port,
1155
1152
  capabilities,
1156
- workflowType: input.type === "branch" ? "regular" : input.type,
1153
+ workflowType: input.type === "branch" ? "regular" : input.type === "epic" ? "issue" : input.type,
1157
1154
  identifier: input.identifier,
1158
1155
  ...(issueData == null ? void 0 : issueData.title) && { title: issueData.title },
1159
1156
  oneShot,
@@ -1191,6 +1188,7 @@ ${issueData.body}` : "";
1191
1188
  branchName,
1192
1189
  worktreePath,
1193
1190
  issueType: input.type,
1191
+ ...input.type === "issue" && { issueKey: this.issueTracker.normalizeIdentifier(input.identifier) },
1194
1192
  issue_numbers,
1195
1193
  pr_numbers,
1196
1194
  issueTracker: this.issueTracker.providerName,
@@ -1201,6 +1199,7 @@ ${issueData.body}` : "";
1201
1199
  prUrls,
1202
1200
  capabilities,
1203
1201
  ...((_l = input.options) == null ? void 0 : _l.oneShot) && { oneShot: input.options.oneShot },
1202
+ ...((_m = input.options) == null ? void 0 : _m.childIssueNumbers) && input.options.childIssueNumbers.length > 0 && { childIssueNumbers: input.options.childIssueNumbers },
1204
1203
  ...input.parentLoom && { parentLoom: input.parentLoom }
1205
1204
  };
1206
1205
  await this.metadataManager.writeMetadata(worktreePath, metadataInput);
@@ -1875,762 +1874,10 @@ var DatabaseManager = class {
1875
1874
  }
1876
1875
  };
1877
1876
 
1878
- // src/lib/ResourceCleanup.ts
1879
- import path5 from "path";
1880
-
1881
- // src/utils/recap-archiver.ts
1882
- import path4 from "path";
1883
- import os2 from "os";
1884
- import fs6 from "fs-extra";
1885
- var RECAPS_DIR = path4.join(os2.homedir(), ".config", "iloom-ai", "recaps");
1886
- var ARCHIVED_DIR = path4.join(RECAPS_DIR, "archived");
1887
- function slugifyPath(loomPath) {
1888
- let slug = loomPath.replace(/[/\\]+$/, "");
1889
- slug = slug.replace(/[/\\]/g, "___");
1890
- slug = slug.replace(/[^a-zA-Z0-9_-]/g, "-");
1891
- return `${slug}.json`;
1892
- }
1893
- async function archiveRecap(worktreePath) {
1894
- const filename = slugifyPath(worktreePath);
1895
- const sourcePath = path4.join(RECAPS_DIR, filename);
1896
- if (!await fs6.pathExists(sourcePath)) {
1897
- getLogger().debug(`No recap file to archive for worktree: ${worktreePath}`);
1898
- return;
1899
- }
1900
- const content = await fs6.readFile(sourcePath, "utf8");
1901
- const data = JSON.parse(content);
1902
- const archivedData = {
1903
- ...data,
1904
- archivedAt: (/* @__PURE__ */ new Date()).toISOString()
1905
- };
1906
- await fs6.ensureDir(ARCHIVED_DIR, { mode: 493 });
1907
- const destPath = path4.join(ARCHIVED_DIR, filename);
1908
- await fs6.writeFile(destPath, JSON.stringify(archivedData, null, 2), { mode: 420 });
1909
- await fs6.unlink(sourcePath);
1910
- getLogger().debug(`Recap archived for worktree: ${worktreePath}`);
1911
- }
1912
-
1913
- // src/lib/ResourceCleanup.ts
1914
- var ResourceCleanup = class {
1915
- constructor(gitWorktree, processManager, database, cliIsolation, settingsManager) {
1916
- this.gitWorktree = gitWorktree;
1917
- this.processManager = processManager;
1918
- this.database = database;
1919
- this.cliIsolation = cliIsolation;
1920
- this.settingsManager = settingsManager ?? new SettingsManager();
1921
- this.metadataManager = new MetadataManager();
1922
- }
1923
- /**
1924
- * Cleanup a worktree and associated resources
1925
- * Main orchestration method
1926
- *
1927
- * @param parsed - ParsedInput from IdentifierParser with type information
1928
- * @param options - Cleanup options
1929
- */
1930
- async cleanupWorktree(parsed, options = {}) {
1931
- var _a, _b, _c;
1932
- const operations = [];
1933
- const errors = [];
1934
- const displayIdentifier = parsed.branchName ?? ((_a = parsed.number) == null ? void 0 : _a.toString()) ?? parsed.originalInput;
1935
- getLogger().info(`Starting cleanup for: ${displayIdentifier}`);
1936
- const number = parsed.number;
1937
- if (number !== void 0) {
1938
- const settings = await this.settingsManager.loadSettings();
1939
- const basePort = ((_c = (_b = settings == null ? void 0 : settings.capabilities) == null ? void 0 : _b.web) == null ? void 0 : _c.basePort) ?? 3e3;
1940
- const port = calculatePortFromIdentifier(number, basePort);
1941
- if (options.dryRun) {
1942
- operations.push({
1943
- type: "dev-server",
1944
- success: true,
1945
- message: `[DRY RUN] Would check for dev server on port ${port}`
1946
- });
1947
- } else {
1948
- try {
1949
- const terminated = await this.terminateDevServer(port);
1950
- operations.push({
1951
- type: "dev-server",
1952
- success: true,
1953
- message: terminated ? `Dev server on port ${port} terminated` : `No dev server running on port ${port}`
1954
- });
1955
- } catch (error) {
1956
- const err = error instanceof Error ? error : new Error("Unknown error");
1957
- errors.push(err);
1958
- operations.push({
1959
- type: "dev-server",
1960
- success: false,
1961
- message: `Failed to terminate dev server`,
1962
- error: err.message
1963
- });
1964
- }
1965
- }
1966
- }
1967
- let worktree = null;
1968
- try {
1969
- if (parsed.type === "pr" && parsed.number !== void 0) {
1970
- const prNumber = typeof parsed.number === "number" ? parsed.number : Number(parsed.number);
1971
- if (isNaN(prNumber) || !isFinite(prNumber)) {
1972
- throw new Error(`Invalid PR number: ${parsed.number}. PR numbers must be numeric.`);
1973
- }
1974
- worktree = await this.gitWorktree.findWorktreeForPR(prNumber, "");
1975
- } else if (parsed.type === "issue" && parsed.number !== void 0) {
1976
- worktree = await this.gitWorktree.findWorktreeForIssue(parsed.number);
1977
- } else if (parsed.type === "branch" && parsed.branchName) {
1978
- worktree = await this.gitWorktree.findWorktreeForBranch(parsed.branchName);
1979
- }
1980
- if (!worktree) {
1981
- throw new Error(`No worktree found for identifier: ${displayIdentifier}`);
1982
- }
1983
- getLogger().debug(`Found worktree: path="${worktree.path}", branch="${worktree.branch}"`);
1984
- } catch (error) {
1985
- const err = error instanceof Error ? error : new Error("Unknown error");
1986
- errors.push(err);
1987
- return {
1988
- identifier: displayIdentifier,
1989
- success: false,
1990
- operations,
1991
- errors,
1992
- rollbackRequired: false
1993
- };
1994
- }
1995
- let safetyCheckPassed = false;
1996
- if (!options.force) {
1997
- const shouldCheckMergeSafety = options.checkMergeSafety ?? options.deleteBranch === true;
1998
- const shouldCheckRemoteBranch = options.checkRemoteBranch ?? false;
1999
- const safety = await this.validateWorktreeSafety(worktree, parsed.originalInput, shouldCheckMergeSafety, shouldCheckRemoteBranch);
2000
- if (!safety.isSafe) {
2001
- const blockerMessage = safety.blockers.join("\n\n");
2002
- throw new Error(`Cannot cleanup:
2003
-
2004
- ${blockerMessage}`);
2005
- }
2006
- safetyCheckPassed = true;
2007
- if (safety.warnings.length > 0) {
2008
- safety.warnings.forEach((warning) => {
2009
- getLogger().warn(warning);
2010
- });
2011
- }
2012
- }
2013
- let databaseConfig = null;
2014
- if (!options.keepDatabase && worktree) {
2015
- const envFilePath = path5.join(worktree.path, ".env");
2016
- try {
2017
- const shouldCleanup = this.database ? await this.database.shouldUseDatabaseBranching(envFilePath) : false;
2018
- databaseConfig = { shouldCleanup, envFilePath };
2019
- } catch (error) {
2020
- getLogger().warn(
2021
- `Failed to read database config from ${envFilePath}, skipping database cleanup: ${error instanceof Error ? error.message : String(error)}`
2022
- );
2023
- databaseConfig = { shouldCleanup: false, envFilePath };
2024
- }
2025
- }
2026
- let mainWorktreePath = null;
2027
- if (!options.dryRun) {
2028
- try {
2029
- mainWorktreePath = await findMainWorktreePathWithSettings(worktree.path, this.settingsManager);
2030
- } catch (error) {
2031
- getLogger().warn(
2032
- `Failed to find main worktree path: ${error instanceof Error ? error.message : String(error)}`
2033
- );
2034
- }
2035
- }
2036
- let mergeTargetBranch = null;
2037
- if (options.deleteBranch && worktree && !options.dryRun) {
2038
- try {
2039
- mergeTargetBranch = await getMergeTargetBranch(worktree.path, {
2040
- settingsManager: this.settingsManager,
2041
- metadataManager: this.metadataManager
2042
- });
2043
- getLogger().debug(`Pre-fetched merge target branch: ${mergeTargetBranch}`);
2044
- } catch (error) {
2045
- getLogger().warn(
2046
- `Failed to pre-fetch merge target branch: ${error instanceof Error ? error.message : String(error)}`
2047
- );
2048
- }
2049
- }
2050
- if (options.dryRun) {
2051
- operations.push({
2052
- type: "worktree",
2053
- success: true,
2054
- message: `[DRY RUN] Would remove worktree: ${worktree.path}`
2055
- });
2056
- } else {
2057
- try {
2058
- const worktreeOptions = {
2059
- removeDirectory: true,
2060
- removeBranch: false
2061
- // Handle branch separately
2062
- };
2063
- if (options.force !== void 0) {
2064
- worktreeOptions.force = options.force;
2065
- }
2066
- await this.gitWorktree.removeWorktree(worktree.path, worktreeOptions);
2067
- operations.push({
2068
- type: "worktree",
2069
- success: true,
2070
- message: `Worktree removed: ${worktree.path}`
2071
- });
2072
- } catch (error) {
2073
- const err = error instanceof Error ? error : new Error("Unknown error");
2074
- errors.push(err);
2075
- operations.push({
2076
- type: "worktree",
2077
- success: false,
2078
- message: `Failed to remove worktree`,
2079
- error: err.message
2080
- });
2081
- }
2082
- }
2083
- if (worktree) {
2084
- if (options.dryRun) {
2085
- operations.push({
2086
- type: "recap",
2087
- success: true,
2088
- message: `[DRY RUN] Would archive recap file for: ${worktree.path}`
2089
- });
2090
- } else {
2091
- try {
2092
- await archiveRecap(worktree.path);
2093
- operations.push({
2094
- type: "recap",
2095
- success: true,
2096
- message: `Recap file archived`
2097
- });
2098
- } catch (error) {
2099
- const err = error instanceof Error ? error : new Error("Unknown error");
2100
- getLogger().warn(`Recap archival failed: ${err.message}`);
2101
- operations.push({
2102
- type: "recap",
2103
- success: false,
2104
- message: "Recap archival failed (non-fatal)",
2105
- error: err.message
2106
- });
2107
- }
2108
- }
2109
- }
2110
- if (options.deleteBranch && worktree) {
2111
- if (options.dryRun) {
2112
- operations.push({
2113
- type: "branch",
2114
- success: true,
2115
- message: `[DRY RUN] Would delete branch: ${worktree.branch}`
2116
- });
2117
- } else {
2118
- try {
2119
- const branchOptions = {
2120
- dryRun: false,
2121
- safetyVerified: safetyCheckPassed
2122
- };
2123
- if (mergeTargetBranch !== null) {
2124
- branchOptions.mergeTargetBranch = mergeTargetBranch;
2125
- }
2126
- if (options.force !== void 0) {
2127
- branchOptions.force = options.force;
2128
- }
2129
- await this.deleteBranch(worktree.branch, branchOptions, mainWorktreePath ?? void 0);
2130
- operations.push({
2131
- type: "branch",
2132
- success: true,
2133
- message: `Branch deleted: ${worktree.branch}`
2134
- });
2135
- } catch (error) {
2136
- const err = error instanceof Error ? error : new Error("Unknown error");
2137
- errors.push(err);
2138
- operations.push({
2139
- type: "branch",
2140
- success: false,
2141
- message: `Failed to delete branch`,
2142
- error: err.message
2143
- });
2144
- }
2145
- }
2146
- }
2147
- const cliIdentifier = parsed.number ?? parsed.branchName;
2148
- if (this.cliIsolation && cliIdentifier !== void 0) {
2149
- if (options.dryRun) {
2150
- operations.push({
2151
- type: "cli-symlinks",
2152
- success: true,
2153
- message: `[DRY RUN] Would cleanup CLI symlinks for: ${cliIdentifier}`
2154
- });
2155
- } else {
2156
- try {
2157
- const removed = await this.cliIsolation.cleanupVersionedExecutables(cliIdentifier);
2158
- operations.push({
2159
- type: "cli-symlinks",
2160
- success: true,
2161
- message: removed.length > 0 ? `CLI symlinks removed: ${removed.length}` : "No CLI symlinks to cleanup"
2162
- });
2163
- } catch (error) {
2164
- const err = error instanceof Error ? error : new Error("Unknown error");
2165
- errors.push(err);
2166
- getLogger().warn(
2167
- `CLI symlink cleanup failed: ${err.message}`
2168
- );
2169
- operations.push({
2170
- type: "cli-symlinks",
2171
- success: false,
2172
- message: "CLI symlink cleanup failed (non-fatal)"
2173
- });
2174
- }
2175
- }
2176
- }
2177
- if (databaseConfig && worktree) {
2178
- if (options.dryRun) {
2179
- operations.push({
2180
- type: "database",
2181
- success: true,
2182
- message: `[DRY RUN] Would cleanup database branch for: ${worktree.branch}`
2183
- });
2184
- } else {
2185
- try {
2186
- if (databaseConfig.shouldCleanup && this.database) {
2187
- try {
2188
- const deletionResult = await this.database.deleteBranchIfConfigured(
2189
- worktree.branch,
2190
- databaseConfig.shouldCleanup,
2191
- false,
2192
- // isPreview
2193
- mainWorktreePath ?? void 0
2194
- );
2195
- if (deletionResult.deleted) {
2196
- getLogger().info(`Database branch deleted: ${worktree.branch}`);
2197
- operations.push({
2198
- type: "database",
2199
- success: true,
2200
- message: `Database branch deleted`,
2201
- deleted: true
2202
- });
2203
- } else if (deletionResult.notFound) {
2204
- getLogger().debug(`No database branch found for: ${worktree.branch}`);
2205
- operations.push({
2206
- type: "database",
2207
- success: true,
2208
- message: `No database branch found (skipped)`,
2209
- deleted: false
2210
- });
2211
- } else if (deletionResult.userDeclined) {
2212
- getLogger().info("Preview database deletion declined by user");
2213
- operations.push({
2214
- type: "database",
2215
- success: true,
2216
- message: `Database cleanup skipped (user declined)`,
2217
- deleted: false
2218
- });
2219
- } else if (!deletionResult.success) {
2220
- const errorMsg = deletionResult.error ?? "Unknown error";
2221
- errors.push(new Error(errorMsg));
2222
- getLogger().warn(`Database cleanup failed: ${errorMsg}`);
2223
- operations.push({
2224
- type: "database",
2225
- success: false,
2226
- // Non-fatal, but report error
2227
- message: `Database cleanup failed`,
2228
- error: errorMsg,
2229
- deleted: false
2230
- });
2231
- } else {
2232
- errors.push(new Error("Database cleanup in an unknown state"));
2233
- getLogger().warn("Database deletion returned unexpected result state");
2234
- operations.push({
2235
- type: "database",
2236
- success: false,
2237
- message: `Database cleanup in an unknown state`,
2238
- deleted: false
2239
- });
2240
- }
2241
- } catch (error) {
2242
- errors.push(error instanceof Error ? error : new Error(String(error)));
2243
- getLogger().warn(
2244
- `Unexpected database cleanup exception: ${error instanceof Error ? error.message : String(error)}`
2245
- );
2246
- operations.push({
2247
- type: "database",
2248
- success: false,
2249
- message: `Database cleanup failed`,
2250
- error: error instanceof Error ? error.message : String(error),
2251
- deleted: false
2252
- });
2253
- }
2254
- } else {
2255
- operations.push({
2256
- type: "database",
2257
- success: true,
2258
- message: `Database cleanup skipped (not available)`,
2259
- deleted: false
2260
- });
2261
- }
2262
- } catch (error) {
2263
- const err = error instanceof Error ? error : new Error("Unknown error");
2264
- errors.push(err);
2265
- operations.push({
2266
- type: "database",
2267
- success: false,
2268
- message: `Database cleanup failed`,
2269
- error: err.message,
2270
- deleted: false
2271
- });
2272
- }
2273
- }
2274
- }
2275
- if (worktree) {
2276
- if (options.dryRun) {
2277
- operations.push({
2278
- type: "metadata",
2279
- success: true,
2280
- message: `[DRY RUN] Would delete metadata for worktree: ${worktree.path}`
2281
- });
2282
- } else {
2283
- try {
2284
- await this.metadataManager.deleteMetadata(worktree.path);
2285
- getLogger().info(`Metadata deleted for worktree: ${worktree.path}`);
2286
- operations.push({
2287
- type: "metadata",
2288
- success: true,
2289
- message: "Metadata deleted"
2290
- });
2291
- } catch (error) {
2292
- const err = error instanceof Error ? error : new Error(String(error));
2293
- errors.push(err);
2294
- getLogger().warn(`Metadata deletion failed: ${err.message}`);
2295
- operations.push({
2296
- type: "metadata",
2297
- success: false,
2298
- message: "Metadata deletion failed (non-fatal)",
2299
- error: err.message
2300
- });
2301
- }
2302
- }
2303
- }
2304
- const success = errors.length === 0;
2305
- return {
2306
- identifier: displayIdentifier,
2307
- branchName: worktree == null ? void 0 : worktree.branch,
2308
- success,
2309
- operations,
2310
- errors,
2311
- rollbackRequired: false
2312
- // Cleanup operations are generally not reversible
2313
- };
2314
- }
2315
- /**
2316
- * Terminate dev server on specified port
2317
- */
2318
- async terminateDevServer(port) {
2319
- getLogger().debug(`Checking for dev server on port ${port}`);
2320
- const processInfo = await this.processManager.detectDevServer(port);
2321
- if (!processInfo) {
2322
- getLogger().debug(`No process found on port ${port}`);
2323
- return false;
2324
- }
2325
- if (!processInfo.isDevServer) {
2326
- getLogger().warn(
2327
- `Process on port ${port} (${processInfo.name}) doesn't appear to be a dev server, skipping`
2328
- );
2329
- return false;
2330
- }
2331
- getLogger().info(`Terminating dev server: ${processInfo.name} (PID: ${processInfo.pid})`);
2332
- await this.processManager.terminateProcess(processInfo.pid);
2333
- const isFree = await this.processManager.verifyPortFree(port);
2334
- if (!isFree) {
2335
- throw new Error(`Dev server may still be running on port ${port}`);
2336
- }
2337
- return true;
2338
- }
2339
- /**
2340
- * Delete a Git branch with safety checks
2341
- *
2342
- * @param branchName - Name of the branch to delete
2343
- * @param options - Delete options (force, dryRun)
2344
- * @param cwd - Working directory to execute git command from (defaults to finding main worktree)
2345
- */
2346
- async deleteBranch(branchName, options = {}, cwd) {
2347
- const protectedBranches = await this.settingsManager.getProtectedBranches(cwd);
2348
- if (protectedBranches.includes(branchName)) {
2349
- throw new Error(`Cannot delete protected branch: ${branchName}`);
2350
- }
2351
- const workingDir = cwd ?? await findMainWorktreePathWithSettings(void 0, this.settingsManager);
2352
- try {
2353
- await executeGitCommand(["rev-parse", "--verify", `refs/heads/${branchName}`], {
2354
- cwd: workingDir
2355
- });
2356
- } catch {
2357
- getLogger().debug(`Branch ${branchName} does not exist, skipping deletion`);
2358
- return true;
2359
- }
2360
- if (options.dryRun) {
2361
- getLogger().info(`[DRY RUN] Would delete branch: ${branchName}`);
2362
- return true;
2363
- }
2364
- let deleteCwd = workingDir;
2365
- try {
2366
- let deleteFlag = "-d";
2367
- if (options.force) {
2368
- deleteFlag = "-D";
2369
- } else if (options.mergeTargetBranch) {
2370
- const mergeTarget = options.mergeTargetBranch;
2371
- try {
2372
- const targetWorktreePath = await findWorktreeForBranch(mergeTarget, workingDir);
2373
- getLogger().debug(`Running branch delete from worktree where '${mergeTarget}' is checked out: ${targetWorktreePath}`);
2374
- deleteCwd = targetWorktreePath;
2375
- } catch {
2376
- getLogger().debug(`Could not find worktree for branch '${mergeTarget}', falling back to merge check`);
2377
- const isMerged = await isBranchMergedIntoMain(branchName, mergeTarget, workingDir);
2378
- if (isMerged) {
2379
- getLogger().debug(`Branch '${branchName}' verified merged into '${mergeTarget}', using force delete`);
2380
- deleteFlag = "-D";
2381
- }
2382
- }
2383
- } else if (options.worktreePath) {
2384
- getLogger().warn("deleteBranch called with worktreePath but no mergeTargetBranch - this may fail if worktree was deleted");
2385
- try {
2386
- const mergeTarget = await getMergeTargetBranch(options.worktreePath, {
2387
- settingsManager: this.settingsManager,
2388
- metadataManager: this.metadataManager
2389
- });
2390
- try {
2391
- const targetWorktreePath = await findWorktreeForBranch(mergeTarget, workingDir);
2392
- getLogger().debug(`Running branch delete from worktree where '${mergeTarget}' is checked out: ${targetWorktreePath}`);
2393
- deleteCwd = targetWorktreePath;
2394
- } catch {
2395
- getLogger().debug(`Could not find worktree for branch '${mergeTarget}', falling back to merge check`);
2396
- const isMerged = await isBranchMergedIntoMain(branchName, mergeTarget, workingDir);
2397
- if (isMerged) {
2398
- getLogger().debug(`Branch '${branchName}' verified merged into '${mergeTarget}', using force delete`);
2399
- deleteFlag = "-D";
2400
- }
2401
- }
2402
- } catch (error) {
2403
- getLogger().debug(`Could not read merge target from worktreePath: ${error instanceof Error ? error.message : String(error)}`);
2404
- }
2405
- }
2406
- await executeGitCommand(["branch", deleteFlag, branchName], {
2407
- cwd: deleteCwd
2408
- });
2409
- getLogger().info(`Branch deleted: ${branchName}`);
2410
- return true;
2411
- } catch (error) {
2412
- const errorMessage = error instanceof Error ? error.message : String(error);
2413
- if (errorMessage.includes("not found") || errorMessage.includes("does not exist")) {
2414
- getLogger().debug(`Branch ${branchName} already deleted`);
2415
- return true;
2416
- }
2417
- if (options.force) {
2418
- throw error;
2419
- }
2420
- if (errorMessage.includes("not fully merged")) {
2421
- if (options.safetyVerified) {
2422
- getLogger().info(`Branch '${branchName}' not merged into HEAD but safety verified - using force delete`);
2423
- await executeGitCommand(["branch", "-D", branchName], { cwd: deleteCwd });
2424
- getLogger().info(`Branch deleted: ${branchName}`);
2425
- return true;
2426
- }
2427
- throw new Error(
2428
- `Cannot delete unmerged branch '${branchName}'. Use --force to delete anyway.`
2429
- );
2430
- }
2431
- throw error;
2432
- }
2433
- }
2434
- /**
2435
- * Cleanup database branch
2436
- * Gracefully handles missing DatabaseManager
2437
- *
2438
- * @deprecated This method is deprecated and should not be used for post-deletion cleanup.
2439
- * Use the pre-fetch mechanism in cleanupWorktree() instead.
2440
- * This method will fail if called after worktree deletion because
2441
- * it attempts to read the .env file which has been deleted.
2442
- *
2443
- * @param branchName - Name of the branch to delete
2444
- * @param worktreePath - Path to worktree (must still exist with .env file)
2445
- */
2446
- async cleanupDatabase(branchName, worktreePath) {
2447
- if (!this.database) {
2448
- getLogger().debug("Database manager not available, skipping database cleanup");
2449
- return false;
2450
- }
2451
- try {
2452
- const envFilePath = path5.join(worktreePath, ".env");
2453
- const shouldCleanup = await this.database.shouldUseDatabaseBranching(envFilePath);
2454
- let cwd;
2455
- try {
2456
- cwd = await findMainWorktreePathWithSettings(worktreePath, this.settingsManager);
2457
- } catch (error) {
2458
- getLogger().debug(
2459
- `Could not find main worktree path, using current directory: ${error instanceof Error ? error.message : String(error)}`
2460
- );
2461
- }
2462
- const result = await this.database.deleteBranchIfConfigured(
2463
- branchName,
2464
- shouldCleanup,
2465
- false,
2466
- // isPreview
2467
- cwd
2468
- );
2469
- if (result.deleted) {
2470
- getLogger().info(`Database branch deleted: ${branchName}`);
2471
- return true;
2472
- } else if (result.notFound) {
2473
- getLogger().debug(`No database branch found for: ${branchName}`);
2474
- return false;
2475
- } else if (result.userDeclined) {
2476
- getLogger().info("Preview database deletion declined by user");
2477
- return false;
2478
- } else if (!result.success) {
2479
- getLogger().warn(`Database cleanup failed: ${result.error ?? "Unknown error"}`);
2480
- return false;
2481
- } else {
2482
- getLogger().debug("Database deletion returned unexpected result");
2483
- return false;
2484
- }
2485
- } catch (error) {
2486
- getLogger().warn(
2487
- `Unexpected database cleanup error: ${error instanceof Error ? error.message : String(error)}`
2488
- );
2489
- return false;
2490
- }
2491
- }
2492
- /**
2493
- * Cleanup multiple worktrees
2494
- */
2495
- async cleanupMultipleWorktrees(identifiers, options = {}) {
2496
- const results = [];
2497
- for (const identifier of identifiers) {
2498
- const parsed = this.parseIdentifier(identifier);
2499
- const result = await this.cleanupWorktree(parsed, options);
2500
- results.push(result);
2501
- }
2502
- return results;
2503
- }
2504
- /**
2505
- * Validate worktree safety given a worktree object
2506
- * Private method used internally when worktree is already known
2507
- *
2508
- * @param worktree - The worktree to validate
2509
- * @param identifier - The original identifier used (for error messages)
2510
- * @param checkBranchMerge - Whether to check if branch is merged into main (for branch deletion)
2511
- * @param checkRemoteBranch - Whether to check if branch exists on remote (for GitHub-PR mode)
2512
- */
2513
- async validateWorktreeSafety(worktree, identifier, checkBranchMerge = false, checkRemoteBranch = false) {
2514
- const warnings = [];
2515
- const blockers = [];
2516
- const isMain = await this.gitWorktree.isMainWorktree(worktree, this.settingsManager);
2517
- if (isMain) {
2518
- blockers.push(`Cannot cleanup main worktree: "${worktree.branch}" @ "${worktree.path}"`);
2519
- }
2520
- const hasChanges = await hasUncommittedChanges(worktree.path);
2521
- if (hasChanges) {
2522
- const blockerMessage = `Worktree has uncommitted changes.
2523
-
2524
- Please resolve before cleanup - you have some options:
2525
- \u2022 Commit changes: cd ${worktree.path} && git commit -am "message"
2526
- \u2022 Stash changes: cd ${worktree.path} && git stash
2527
- \u2022 Force cleanup: il cleanup ${identifier} --force (WARNING: will discard changes)`;
2528
- blockers.push(blockerMessage);
2529
- }
2530
- if ((checkBranchMerge || checkRemoteBranch) && worktree.branch) {
2531
- const mainBranch = await getMergeTargetBranch(worktree.path, {
2532
- settingsManager: this.settingsManager,
2533
- metadataManager: this.metadataManager
2534
- });
2535
- const remoteStatus = await checkRemoteBranchStatus(worktree.branch, worktree.path);
2536
- if (remoteStatus.networkError) {
2537
- const blockerMessage = `Cannot verify remote branch status due to network error.
2538
-
2539
- Error: ${remoteStatus.errorMessage ?? "Unknown network error"}
2540
-
2541
- Unable to determine if branch '${worktree.branch}' is safely backed up.
2542
- Use --force to proceed without verification.`;
2543
- blockers.push(blockerMessage);
2544
- } else if (remoteStatus.exists && remoteStatus.localAhead) {
2545
- const blockerMessage = `Branch '${worktree.branch}' has unpushed commits that would be lost.
2546
- The remote branch exists but your local branch is ahead.
2547
-
2548
- Please resolve before cleanup:
2549
- \u2022 Push your commits: git push origin ${worktree.branch}
2550
- \u2022 Force cleanup: il cleanup ${identifier} --force (WARNING: will lose commits)`;
2551
- blockers.push(blockerMessage);
2552
- } else if (remoteStatus.exists && !remoteStatus.localAhead) {
2553
- } else if (!remoteStatus.exists) {
2554
- const isMerged = await isBranchMergedIntoMain(worktree.branch, mainBranch, worktree.path);
2555
- if (isMerged) {
2556
- } else {
2557
- const blockerMessage = `Branch '${worktree.branch}' has not been pushed to remote and is not merged into '${mainBranch}'.
2558
- Deleting this branch would result in data loss.
2559
-
2560
- Please resolve before cleanup - you have some options:
2561
- \u2022 Push to remote: git push -u origin ${worktree.branch}
2562
- \u2022 Merge to ${mainBranch}: git checkout ${mainBranch} && git merge ${worktree.branch}
2563
- \u2022 Force cleanup: il cleanup ${identifier} --force (WARNING: will lose commits)`;
2564
- blockers.push(blockerMessage);
2565
- }
2566
- }
2567
- }
2568
- return {
2569
- isSafe: blockers.length === 0,
2570
- warnings,
2571
- blockers
2572
- };
2573
- }
2574
- /**
2575
- * Validate cleanup safety
2576
- */
2577
- async validateCleanupSafety(identifier) {
2578
- const warnings = [];
2579
- const blockers = [];
2580
- const worktrees = await this.gitWorktree.findWorktreesByIdentifier(identifier);
2581
- if (worktrees.length === 0) {
2582
- blockers.push(`No worktree found for: ${identifier}`);
2583
- return { isSafe: false, warnings, blockers };
2584
- }
2585
- const worktree = worktrees[0];
2586
- if (!worktree) {
2587
- blockers.push(`No worktree found for: ${identifier}`);
2588
- return { isSafe: false, warnings, blockers };
2589
- }
2590
- return await this.validateWorktreeSafety(worktree, identifier);
2591
- }
2592
- /**
2593
- * Parse identifier to determine type and extract number
2594
- * Helper method for port calculation
2595
- */
2596
- parseIdentifier(identifier) {
2597
- const issueId = extractIssueNumber(identifier);
2598
- if (issueId !== null) {
2599
- return {
2600
- type: "issue",
2601
- number: issueId,
2602
- originalInput: identifier
2603
- };
2604
- }
2605
- const prMatch = identifier.match(/(?:pr|PR)[/-](\d+)/);
2606
- if (prMatch == null ? void 0 : prMatch[1]) {
2607
- return {
2608
- type: "pr",
2609
- number: parseInt(prMatch[1], 10),
2610
- originalInput: identifier
2611
- };
2612
- }
2613
- const numericMatch = identifier.match(/^#?(\d+)$/);
2614
- if (numericMatch == null ? void 0 : numericMatch[1]) {
2615
- return {
2616
- type: "issue",
2617
- number: parseInt(numericMatch[1], 10),
2618
- originalInput: identifier
2619
- };
2620
- }
2621
- return {
2622
- type: "branch",
2623
- branchName: identifier,
2624
- originalInput: identifier
2625
- };
2626
- }
2627
- };
2628
-
2629
1877
  export {
2630
1878
  LoomManager,
2631
1879
  EnvironmentManager,
2632
1880
  CLIIsolationManager,
2633
- DatabaseManager,
2634
- ResourceCleanup
1881
+ DatabaseManager
2635
1882
  };
2636
- //# sourceMappingURL=chunk-SOSQILHO.js.map
1883
+ //# sourceMappingURL=chunk-ZNMPGMHY.js.map