@iloom/cli 0.9.2 → 0.10.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 (220) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +159 -40
  3. package/dist/{BranchNamingService-K6XNWQ6C.js → BranchNamingService-ECJHBB67.js} +2 -2
  4. package/dist/ClaudeContextManager-QXX6ZFST.js +14 -0
  5. package/dist/ClaudeService-NJNK2SUH.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-L64HHS3T.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-DULSVRRE.js} +2 -2
  12. package/dist/README.md +159 -40
  13. package/dist/{SettingsManager-AW3JTJHD.js → SettingsManager-BQDQA3FK.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-5GO3XW26.js} +9 -9
  23. package/dist/{chunk-NUACL52E.js → chunk-3D7WQM7I.js} +2 -2
  24. package/dist/chunk-4232AHNQ.js +35 -0
  25. package/dist/chunk-4232AHNQ.js.map +1 -0
  26. package/dist/{chunk-QN47QVBX.js → chunk-4WJNIR5O.js} +1 -1
  27. package/dist/chunk-4WJNIR5O.js.map +1 -0
  28. package/dist/{chunk-A7NJF73J.js → chunk-5MWV33NN.js} +4 -4
  29. package/dist/{chunk-3I4ONZRT.js → chunk-6EU6TCF6.js} +10 -10
  30. package/dist/chunk-6EU6TCF6.js.map +1 -0
  31. package/dist/{chunk-CWRI4JC3.js → chunk-FB47TIJG.js} +29 -11
  32. package/dist/chunk-FB47TIJG.js.map +1 -0
  33. package/dist/chunk-HEXKPKCK.js +1396 -0
  34. package/dist/chunk-HEXKPKCK.js.map +1 -0
  35. package/dist/{chunk-KAYXR544.js → chunk-J5S7DFYC.js} +2 -2
  36. package/dist/{chunk-ULSWCPQG.js → chunk-JO2LZ6EQ.js} +476 -5
  37. package/dist/chunk-JO2LZ6EQ.js.map +1 -0
  38. package/dist/{chunk-KBEIQP4G.js → chunk-KB64WNBZ.js} +43 -3
  39. package/dist/chunk-KB64WNBZ.js.map +1 -0
  40. package/dist/{chunk-OFDN5NKS.js → chunk-KXDRI47U.js} +69 -12
  41. package/dist/chunk-KXDRI47U.js.map +1 -0
  42. package/dist/{chunk-R4YWBGY6.js → chunk-LXLMMXXY.js} +54 -14
  43. package/dist/chunk-LXLMMXXY.js.map +1 -0
  44. package/dist/{chunk-AR5QKYNE.js → chunk-MNHZB4Z2.js} +4 -4
  45. package/dist/{chunk-TL72BGP6.js → chunk-MORRVYPT.js} +2 -2
  46. package/dist/{chunk-KJTVU3HZ.js → chunk-NRSWLOAZ.js} +8 -8
  47. package/dist/chunk-NRSWLOAZ.js.map +1 -0
  48. package/dist/{chunk-FO5GGFOV.js → chunk-ONQYPICO.js} +13 -5
  49. package/dist/chunk-ONQYPICO.js.map +1 -0
  50. package/dist/{chunk-7ZEHSSUP.js → chunk-P4O6EH46.js} +4 -4
  51. package/dist/chunk-QZWEJVWV.js +207 -0
  52. package/dist/chunk-QZWEJVWV.js.map +1 -0
  53. package/dist/chunk-RSYT7MVI.js +202 -0
  54. package/dist/chunk-RSYT7MVI.js.map +1 -0
  55. package/dist/{chunk-Z2TWEXR7.js → chunk-RYWFS37M.js} +6 -6
  56. package/dist/chunk-RYWFS37M.js.map +1 -0
  57. package/dist/{chunk-B7U6OKUR.js → chunk-SF2P22EE.js} +11 -3
  58. package/dist/chunk-SF2P22EE.js.map +1 -0
  59. package/dist/{chunk-6IIL5M2L.js → chunk-SN3SQCFK.js} +10 -8
  60. package/dist/{chunk-6IIL5M2L.js.map → chunk-SN3SQCFK.js.map} +1 -1
  61. package/dist/{chunk-SOSQILHO.js → chunk-UD3WJDIV.js} +92 -82
  62. package/dist/chunk-UD3WJDIV.js.map +1 -0
  63. package/dist/{chunk-KXGQYLFZ.js → chunk-UKBAJ2QQ.js} +61 -7
  64. package/dist/chunk-UKBAJ2QQ.js.map +1 -0
  65. package/dist/{chunk-W6DP5RVR.js → chunk-UVD4CZKS.js} +3 -3
  66. package/dist/chunk-UWGVCXRF.js +207 -0
  67. package/dist/chunk-UWGVCXRF.js.map +1 -0
  68. package/dist/{chunk-NWMORW3U.js → chunk-VECNX6VX.js} +2 -2
  69. package/dist/{chunk-4CO6KG5S.js → chunk-VG45TUYK.js} +53 -7
  70. package/dist/{chunk-4CO6KG5S.js.map → chunk-VG45TUYK.js.map} +1 -1
  71. package/dist/{chunk-TC7APDKU.js → chunk-VGGST52X.js} +2 -2
  72. package/dist/{chunk-4LKGCFGG.js → chunk-WWKOVDWC.js} +2 -2
  73. package/dist/{chunk-YKFCCV6S.js → chunk-WY4QBK43.js} +7 -7
  74. package/dist/chunk-WY4QBK43.js.map +1 -0
  75. package/dist/chunk-Y4YZTHZE.js +73 -0
  76. package/dist/chunk-Y4YZTHZE.js.map +1 -0
  77. package/dist/{chunk-VOGGLPG5.js → chunk-YQ57ORTV.js} +14 -1
  78. package/dist/chunk-YQ57ORTV.js.map +1 -0
  79. package/dist/{chunk-RI2YL6TK.js → chunk-YYAKPQBT.js} +65 -18
  80. package/dist/chunk-YYAKPQBT.js.map +1 -0
  81. package/dist/{chunk-IZIYLYPK.js → chunk-ZEWU5PZK.js} +2 -2
  82. package/dist/{chunk-VPTAX5TR.js → chunk-ZHPNZC75.js} +12 -12
  83. package/dist/chunk-ZHPNZC75.js.map +1 -0
  84. package/dist/{chunk-DGG2VY7B.js → chunk-ZW2LKWWE.js} +9 -9
  85. package/dist/chunk-ZW2LKWWE.js.map +1 -0
  86. package/dist/{claude-TP2QO3BU.js → claude-P3NQR6IJ.js} +2 -2
  87. package/dist/{cleanup-PJRIFFU4.js → cleanup-6UCPVMFG.js} +81 -32
  88. package/dist/cleanup-6UCPVMFG.js.map +1 -0
  89. package/dist/cli.js +638 -349
  90. package/dist/cli.js.map +1 -1
  91. package/dist/{commit-IVP3M4HG.js → commit-L3EPY5QG.js} +21 -20
  92. package/dist/commit-L3EPY5QG.js.map +1 -0
  93. package/dist/{compile-R2J65HBQ.js → compile-ZS4HYRX5.js} +9 -9
  94. package/dist/{contribute-VDZXHK5Y.js → contribute-ORDDQGSL.js} +14 -6
  95. package/dist/contribute-ORDDQGSL.js.map +1 -0
  96. package/dist/{dev-server-7F622OEO.js → dev-server-FYZ2AQIH.js} +29 -15
  97. package/dist/dev-server-FYZ2AQIH.js.map +1 -0
  98. package/dist/{feedback-E7VET7CL.js → feedback-TMBXSCM5.js} +15 -15
  99. package/dist/{git-2QDQ2X2S.js → git-ET64COO3.js} +4 -4
  100. package/dist/hooks/iloom-hook.js +15 -0
  101. package/dist/ignite-CGOV3TD4.js +1393 -0
  102. package/dist/ignite-CGOV3TD4.js.map +1 -0
  103. package/dist/index.d.ts +382 -53
  104. package/dist/index.js +1167 -36
  105. package/dist/index.js.map +1 -1
  106. package/dist/{init-676DHF6R.js → init-GFQ5W7GK.js} +57 -21
  107. package/dist/init-GFQ5W7GK.js.map +1 -0
  108. package/dist/{issues-PJSOLOBJ.js → issues-T4ZZSPEG.js} +61 -20
  109. package/dist/issues-T4ZZSPEG.js.map +1 -0
  110. package/dist/{lint-CJM7BAIM.js → lint-6TQXDZ3T.js} +9 -9
  111. package/dist/mcp/issue-management-server.js +2471 -256
  112. package/dist/mcp/issue-management-server.js.map +1 -1
  113. package/dist/mcp/recap-server.js +144 -21
  114. package/dist/mcp/recap-server.js.map +1 -1
  115. package/dist/{neon-helpers-VVFFTLXE.js → neon-helpers-CQN2PB4S.js} +3 -3
  116. package/dist/neon-helpers-CQN2PB4S.js.map +1 -0
  117. package/dist/{open-544H7JF5.js → open-5QZGXQRF.js} +15 -15
  118. package/dist/open-5QZGXQRF.js.map +1 -0
  119. package/dist/{plan-Q7ELXDLC.js → plan-U7ZQWLFY.js} +41 -25
  120. package/dist/plan-U7ZQWLFY.js.map +1 -0
  121. package/dist/{projects-LH362JZQ.js → projects-2UOXFLNZ.js} +4 -4
  122. package/dist/prompts/CLAUDE.md +62 -0
  123. package/dist/prompts/init-prompt.txt +347 -26
  124. package/dist/prompts/issue-prompt.txt +427 -54
  125. package/dist/prompts/plan-prompt.txt +97 -16
  126. package/dist/prompts/pr-prompt.txt +44 -1
  127. package/dist/prompts/regular-prompt.txt +42 -1
  128. package/dist/prompts/session-summary-prompt.txt +14 -0
  129. package/dist/prompts/swarm-orchestrator-prompt.txt +437 -0
  130. package/dist/{rebase-YND35CIE.js → rebase-DWIB77KV.js} +10 -10
  131. package/dist/{recap-3W7COH7D.js → recap-MX63HAKV.js} +47 -19
  132. package/dist/recap-MX63HAKV.js.map +1 -0
  133. package/dist/{run-QUXJKDQQ.js → run-O3TFNQFC.js} +15 -15
  134. package/dist/run-O3TFNQFC.js.map +1 -0
  135. package/dist/schema/package-iloom.schema.json +58 -0
  136. package/dist/schema/settings.schema.json +115 -15
  137. package/dist/{shell-QGECBLST.js → shell-G6VC2CYR.js} +14 -7
  138. package/dist/shell-G6VC2CYR.js.map +1 -0
  139. package/dist/{summary-G2T4452H.js → summary-FWHAX55O.js} +27 -25
  140. package/dist/summary-FWHAX55O.js.map +1 -0
  141. package/dist/{test-EA5NQFDC.js → test-F7JNJZYP.js} +9 -9
  142. package/dist/{test-git-M7LSLEFL.js → test-git-BTAOIUE2.js} +4 -4
  143. package/dist/test-jira-CHYNV33F.js +96 -0
  144. package/dist/test-jira-CHYNV33F.js.map +1 -0
  145. package/dist/{test-prefix-64NAAUON.js → test-prefix-Q6TFSU6F.js} +4 -4
  146. package/dist/{test-webserver-OK6Z5FJM.js → test-webserver-EONCG7E7.js} +6 -6
  147. package/dist/{vscode-AR5NNXXI.js → vscode-VA5X4P25.js} +7 -7
  148. package/package.json +5 -1
  149. package/dist/ClaudeContextManager-HR5JQKAI.js +0 -14
  150. package/dist/ClaudeService-TK7FMC2X.js +0 -13
  151. package/dist/chunk-3I4ONZRT.js.map +0 -1
  152. package/dist/chunk-B7U6OKUR.js.map +0 -1
  153. package/dist/chunk-CWRI4JC3.js.map +0 -1
  154. package/dist/chunk-DGG2VY7B.js.map +0 -1
  155. package/dist/chunk-FJDRTVJX.js +0 -520
  156. package/dist/chunk-FJDRTVJX.js.map +0 -1
  157. package/dist/chunk-FO5GGFOV.js.map +0 -1
  158. package/dist/chunk-KBEIQP4G.js.map +0 -1
  159. package/dist/chunk-KJTVU3HZ.js.map +0 -1
  160. package/dist/chunk-KXGQYLFZ.js.map +0 -1
  161. package/dist/chunk-OFDN5NKS.js.map +0 -1
  162. package/dist/chunk-QN47QVBX.js.map +0 -1
  163. package/dist/chunk-R4YWBGY6.js.map +0 -1
  164. package/dist/chunk-RI2YL6TK.js.map +0 -1
  165. package/dist/chunk-SOSQILHO.js.map +0 -1
  166. package/dist/chunk-ULSWCPQG.js.map +0 -1
  167. package/dist/chunk-VOGGLPG5.js.map +0 -1
  168. package/dist/chunk-VPTAX5TR.js.map +0 -1
  169. package/dist/chunk-WHI5KEOX.js +0 -121
  170. package/dist/chunk-WHI5KEOX.js.map +0 -1
  171. package/dist/chunk-YKFCCV6S.js.map +0 -1
  172. package/dist/chunk-Z2TWEXR7.js.map +0 -1
  173. package/dist/cleanup-PJRIFFU4.js.map +0 -1
  174. package/dist/commit-IVP3M4HG.js.map +0 -1
  175. package/dist/contribute-VDZXHK5Y.js.map +0 -1
  176. package/dist/dev-server-7F622OEO.js.map +0 -1
  177. package/dist/ignite-IW35CDBD.js +0 -784
  178. package/dist/ignite-IW35CDBD.js.map +0 -1
  179. package/dist/init-676DHF6R.js.map +0 -1
  180. package/dist/issues-PJSOLOBJ.js.map +0 -1
  181. package/dist/open-544H7JF5.js.map +0 -1
  182. package/dist/plan-Q7ELXDLC.js.map +0 -1
  183. package/dist/recap-3W7COH7D.js.map +0 -1
  184. package/dist/run-QUXJKDQQ.js.map +0 -1
  185. package/dist/shell-QGECBLST.js.map +0 -1
  186. package/dist/summary-G2T4452H.js.map +0 -1
  187. /package/dist/{BranchNamingService-K6XNWQ6C.js.map → BranchNamingService-ECJHBB67.js.map} +0 -0
  188. /package/dist/{ClaudeContextManager-HR5JQKAI.js.map → ClaudeContextManager-QXX6ZFST.js.map} +0 -0
  189. /package/dist/{ClaudeService-TK7FMC2X.js.map → ClaudeService-NJNK2SUH.js.map} +0 -0
  190. /package/dist/{GitHubService-TGWJN4V4.js.map → GitHubService-MEHKHUQP.js.map} +0 -0
  191. /package/dist/{MetadataManager-W3C54UYT.js.map → IssueTrackerFactory-NG53YX5S.js.map} +0 -0
  192. /package/dist/{LoomLauncher-73NXL2CL.js.map → LoomLauncher-L64HHS3T.js.map} +0 -0
  193. /package/dist/{ProjectCapabilityDetector-N5L7T4IY.js.map → MetadataManager-5QZSTKNN.js.map} +0 -0
  194. /package/dist/{PromptTemplateManager-36YLQRHP.js.map → ProjectCapabilityDetector-5KSYUTBJ.js.map} +0 -0
  195. /package/dist/{SettingsManager-AW3JTJHD.js.map → PromptTemplateManager-DULSVRRE.js.map} +0 -0
  196. /package/dist/{claude-TP2QO3BU.js.map → SettingsManager-BQDQA3FK.js.map} +0 -0
  197. /package/dist/{build-THZI572G.js.map → build-5GO3XW26.js.map} +0 -0
  198. /package/dist/{chunk-NUACL52E.js.map → chunk-3D7WQM7I.js.map} +0 -0
  199. /package/dist/{chunk-A7NJF73J.js.map → chunk-5MWV33NN.js.map} +0 -0
  200. /package/dist/{chunk-KAYXR544.js.map → chunk-J5S7DFYC.js.map} +0 -0
  201. /package/dist/{chunk-AR5QKYNE.js.map → chunk-MNHZB4Z2.js.map} +0 -0
  202. /package/dist/{chunk-TL72BGP6.js.map → chunk-MORRVYPT.js.map} +0 -0
  203. /package/dist/{chunk-7ZEHSSUP.js.map → chunk-P4O6EH46.js.map} +0 -0
  204. /package/dist/{chunk-W6DP5RVR.js.map → chunk-UVD4CZKS.js.map} +0 -0
  205. /package/dist/{chunk-NWMORW3U.js.map → chunk-VECNX6VX.js.map} +0 -0
  206. /package/dist/{chunk-TC7APDKU.js.map → chunk-VGGST52X.js.map} +0 -0
  207. /package/dist/{chunk-4LKGCFGG.js.map → chunk-WWKOVDWC.js.map} +0 -0
  208. /package/dist/{chunk-IZIYLYPK.js.map → chunk-ZEWU5PZK.js.map} +0 -0
  209. /package/dist/{git-2QDQ2X2S.js.map → claude-P3NQR6IJ.js.map} +0 -0
  210. /package/dist/{compile-R2J65HBQ.js.map → compile-ZS4HYRX5.js.map} +0 -0
  211. /package/dist/{feedback-E7VET7CL.js.map → feedback-TMBXSCM5.js.map} +0 -0
  212. /package/dist/{neon-helpers-VVFFTLXE.js.map → git-ET64COO3.js.map} +0 -0
  213. /package/dist/{lint-CJM7BAIM.js.map → lint-6TQXDZ3T.js.map} +0 -0
  214. /package/dist/{projects-LH362JZQ.js.map → projects-2UOXFLNZ.js.map} +0 -0
  215. /package/dist/{rebase-YND35CIE.js.map → rebase-DWIB77KV.js.map} +0 -0
  216. /package/dist/{test-EA5NQFDC.js.map → test-F7JNJZYP.js.map} +0 -0
  217. /package/dist/{test-git-M7LSLEFL.js.map → test-git-BTAOIUE2.js.map} +0 -0
  218. /package/dist/{test-prefix-64NAAUON.js.map → test-prefix-Q6TFSU6F.js.map} +0 -0
  219. /package/dist/{test-webserver-OK6Z5FJM.js.map → test-webserver-EONCG7E7.js.map} +0 -0
  220. /package/dist/{vscode-AR5NNXXI.js.map → vscode-VA5X4P25.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SessionSummaryService
4
- } from "./chunk-3I4ONZRT.js";
4
+ } from "./chunk-6EU6TCF6.js";
5
5
  import "./chunk-NXMDEL3F.js";
6
6
  import {
7
7
  CLIIsolationManager,
@@ -9,64 +9,74 @@ import {
9
9
  EnvironmentManager,
10
10
  LoomManager,
11
11
  ResourceCleanup
12
- } from "./chunk-SOSQILHO.js";
12
+ } from "./chunk-UD3WJDIV.js";
13
13
  import {
14
14
  PRManager
15
- } from "./chunk-DGG2VY7B.js";
15
+ } from "./chunk-ZW2LKWWE.js";
16
+ import "./chunk-Y4YZTHZE.js";
16
17
  import {
17
18
  launchFirstRunSetup,
18
19
  needsFirstRunSetup
19
- } from "./chunk-W6DP5RVR.js";
20
+ } from "./chunk-UVD4CZKS.js";
21
+ import {
22
+ CommitManager,
23
+ UserAbortedCommitError,
24
+ ValidationRunner
25
+ } from "./chunk-ZHPNZC75.js";
20
26
  import {
21
27
  BuildRunner,
22
28
  MergeManager
23
- } from "./chunk-R4YWBGY6.js";
29
+ } from "./chunk-LXLMMXXY.js";
24
30
  import {
25
- IssueTrackerFactory
26
- } from "./chunk-KXGQYLFZ.js";
31
+ assembleChildrenData,
32
+ buildDependencyMap,
33
+ fetchChildIssueDetails,
34
+ fetchChildIssues
35
+ } from "./chunk-QZWEJVWV.js";
36
+ import {
37
+ IssueManagementProviderFactory
38
+ } from "./chunk-JO2LZ6EQ.js";
39
+ import "./chunk-4232AHNQ.js";
27
40
  import {
28
41
  ProcessManager
29
- } from "./chunk-IZIYLYPK.js";
30
- import "./chunk-NUACL52E.js";
42
+ } from "./chunk-ZEWU5PZK.js";
43
+ import "./chunk-3D7WQM7I.js";
44
+ import {
45
+ installDependencies
46
+ } from "./chunk-WWKOVDWC.js";
31
47
  import {
32
48
  IdentifierParser,
33
49
  matchIssueIdentifier
34
- } from "./chunk-YKFCCV6S.js";
50
+ } from "./chunk-WY4QBK43.js";
35
51
  import {
36
52
  createNeonProviderFromSettings
37
- } from "./chunk-7ZEHSSUP.js";
53
+ } from "./chunk-P4O6EH46.js";
38
54
  import {
39
55
  ShellCompletion
40
- } from "./chunk-NWMORW3U.js";
56
+ } from "./chunk-VECNX6VX.js";
57
+ import {
58
+ TelemetryManager,
59
+ TelemetryService
60
+ } from "./chunk-RSYT7MVI.js";
61
+ import {
62
+ GitWorktreeManager
63
+ } from "./chunk-VGGST52X.js";
41
64
  import "./chunk-Q7POFB5Q.js";
42
65
  import {
43
66
  IssueEnhancementService,
44
67
  capitalizeFirstLetter
45
- } from "./chunk-CWRI4JC3.js";
46
- import "./chunk-WHI5KEOX.js";
68
+ } from "./chunk-FB47TIJG.js";
69
+ import "./chunk-UWGVCXRF.js";
47
70
  import {
48
71
  openBrowser
49
72
  } from "./chunk-YETJNRQM.js";
50
73
  import {
51
- AgentManager
52
- } from "./chunk-B7U6OKUR.js";
53
- import {
54
- CommitManager,
55
- UserAbortedCommitError,
56
- ValidationRunner
57
- } from "./chunk-VPTAX5TR.js";
58
- import {
59
- IssueManagementProviderFactory
60
- } from "./chunk-ULSWCPQG.js";
61
- import {
62
- getLinearChildIssues
63
- } from "./chunk-FJDRTVJX.js";
64
- import {
65
- installDependencies
66
- } from "./chunk-4LKGCFGG.js";
74
+ ProjectCapabilityDetector
75
+ } from "./chunk-MORRVYPT.js";
76
+ import "./chunk-YQ57ORTV.js";
67
77
  import {
68
- GitWorktreeManager
69
- } from "./chunk-TC7APDKU.js";
78
+ AgentManager
79
+ } from "./chunk-SF2P22EE.js";
70
80
  import {
71
81
  getConfiguredRepoFromSettings,
72
82
  hasMultipleRemotes
@@ -78,19 +88,16 @@ import {
78
88
  } from "./chunk-O7VL5N6S.js";
79
89
  import {
80
90
  ClaudeContextManager
81
- } from "./chunk-Z2TWEXR7.js";
82
- import "./chunk-6IIL5M2L.js";
83
- import "./chunk-QN47QVBX.js";
91
+ } from "./chunk-RYWFS37M.js";
92
+ import "./chunk-SN3SQCFK.js";
93
+ import "./chunk-ONQYPICO.js";
94
+ import "./chunk-4WJNIR5O.js";
84
95
  import {
85
96
  extractSettingsOverrides
86
97
  } from "./chunk-GYCR2LOU.js";
87
98
  import {
88
99
  DefaultBranchNamingService
89
- } from "./chunk-KAYXR544.js";
90
- import {
91
- ProjectCapabilityDetector
92
- } from "./chunk-TL72BGP6.js";
93
- import "./chunk-VOGGLPG5.js";
100
+ } from "./chunk-J5S7DFYC.js";
94
101
  import {
95
102
  GitCommandError,
96
103
  executeGitCommand,
@@ -103,29 +110,31 @@ import {
103
110
  pushBranchToRemote,
104
111
  removePlaceholderCommitFromHead,
105
112
  removePlaceholderCommitFromHistory
106
- } from "./chunk-AR5QKYNE.js";
113
+ } from "./chunk-MNHZB4Z2.js";
107
114
  import {
108
115
  SettingsManager
109
- } from "./chunk-RI2YL6TK.js";
116
+ } from "./chunk-YYAKPQBT.js";
110
117
  import {
111
118
  MetadataManager
112
- } from "./chunk-KBEIQP4G.js";
119
+ } from "./chunk-KB64WNBZ.js";
120
+ import {
121
+ IssueTrackerFactory
122
+ } from "./chunk-UKBAJ2QQ.js";
123
+ import "./chunk-HEXKPKCK.js";
113
124
  import {
114
125
  GitHubService
115
- } from "./chunk-OFDN5NKS.js";
126
+ } from "./chunk-KXDRI47U.js";
127
+ import "./chunk-VG45TUYK.js";
116
128
  import {
117
- getSubIssues
118
- } from "./chunk-4CO6KG5S.js";
129
+ getLogger,
130
+ withLogger
131
+ } from "./chunk-6MLEBAYZ.js";
119
132
  import {
133
+ isInteractiveEnvironment,
120
134
  promptConfirmation,
121
135
  waitForKeypress
122
136
  } from "./chunk-7JDMYTFZ.js";
123
137
  import "./chunk-433MOLAU.js";
124
- import "./chunk-FO5GGFOV.js";
125
- import {
126
- getLogger,
127
- withLogger
128
- } from "./chunk-6MLEBAYZ.js";
129
138
  import {
130
139
  createStderrLogger,
131
140
  loadEnvIntoProcess,
@@ -165,7 +174,7 @@ var StartCommand = class {
165
174
  * Uses lazy initialization to ensure we have the correct path
166
175
  */
167
176
  async initializeLoomManager() {
168
- var _a, _b;
177
+ var _a2, _b;
169
178
  if (this.loomManager) {
170
179
  return this.loomManager;
171
180
  }
@@ -177,7 +186,7 @@ var StartCommand = class {
177
186
  const settings = await this.settingsManager.loadSettings();
178
187
  const environmentManager = new EnvironmentManager();
179
188
  const neonProvider = createNeonProviderFromSettings(settings);
180
- const databaseUrlEnvVarName = ((_b = (_a = settings.capabilities) == null ? void 0 : _a.database) == null ? void 0 : _b.databaseUrlEnvVarName) ?? "DATABASE_URL";
189
+ const databaseUrlEnvVarName = ((_b = (_a2 = settings.capabilities) == null ? void 0 : _a2.database) == null ? void 0 : _b.databaseUrlEnvVarName) ?? "DATABASE_URL";
181
190
  const databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName);
182
191
  const branchNaming = new DefaultBranchNamingService({ useClaude: true });
183
192
  this.loomManager = new LoomManager(
@@ -201,14 +210,14 @@ var StartCommand = class {
201
210
  * Main entry point for the start command
202
211
  */
203
212
  async execute(input) {
204
- var _a, _b, _c, _d, _e;
213
+ var _a2, _b, _c, _d, _e;
205
214
  const isJsonMode = input.options.json === true;
206
215
  try {
207
216
  const initialSettings = await this.settingsManager.loadSettings();
208
217
  if (!isJsonMode && (process.env.FORCE_FIRST_TIME_SETUP === "true" || await needsFirstRunSetup())) {
209
218
  await launchFirstRunSetup();
210
219
  const newSettings = await this.settingsManager.loadSettings();
211
- const newProvider = ((_a = newSettings.issueManagement) == null ? void 0 : _a.provider) ?? "github";
220
+ const newProvider = ((_a2 = newSettings.issueManagement) == null ? void 0 : _a2.provider) ?? "github";
212
221
  if (newProvider !== this.issueTracker.providerName) {
213
222
  getLogger().debug(`Reinitializing issue tracker: provider changed to "${newProvider}"`);
214
223
  this.issueTracker = IssueTrackerFactory.create(newSettings);
@@ -224,7 +233,6 @@ var StartCommand = class {
224
233
  const parsed = await this.parseInput(input.identifier, repo);
225
234
  await this.validateInput(parsed, repo);
226
235
  if (parentLoom) {
227
- const { isInteractiveEnvironment, promptConfirmation: promptConfirmation2 } = await import("./prompt-ONNPSNKM.js");
228
236
  const parentDisplay = parentLoom.type === "issue" ? `issue #${parentLoom.identifier}` : parentLoom.type === "pr" ? `PR #${parentLoom.identifier}` : `branch ${parentLoom.identifier}`;
229
237
  if (input.options.childLoom === true) {
230
238
  getLogger().info(`Creating as child loom of ${parentDisplay} (--child-loom flag)`);
@@ -237,14 +245,13 @@ var StartCommand = class {
237
245
  }
238
246
  let createAsChild = true;
239
247
  if (isInteractiveEnvironment()) {
240
- createAsChild = await promptConfirmation2(
248
+ createAsChild = await promptConfirmation(
241
249
  `You are not in your main worktree. Create as a child loom of ${parentDisplay}?`,
242
250
  true
243
251
  // Default yes
244
252
  );
245
253
  } else {
246
- getLogger().error(`Non-interactive environment detected, use either --child-loom or --no-child-loom to specify behavior`);
247
- process.exit(1);
254
+ throw new Error("Non-interactive environment detected, use either --child-loom or --no-child-loom to specify behavior");
248
255
  }
249
256
  if (!createAsChild) {
250
257
  parentLoom = null;
@@ -255,7 +262,7 @@ var StartCommand = class {
255
262
  getLogger().debug("--child-loom flag provided but not running from inside an existing loom (ignored)");
256
263
  }
257
264
  if (parsed.type === "description") {
258
- getLogger().info("Creating GitHub issue from description...");
265
+ getLogger().info("Creating issue from description...");
259
266
  const title = capitalizeFirstLetter(parsed.originalInput);
260
267
  const body = input.options.body ? capitalizeFirstLetter(input.options.body) : "";
261
268
  const result = await this.issueTracker.createIssue(
@@ -268,9 +275,63 @@ var StartCommand = class {
268
275
  parsed.type = "issue";
269
276
  parsed.number = result.number;
270
277
  }
278
+ let childIssueNumbers = [];
279
+ let childIssues = [];
280
+ let dependencyMap = {};
281
+ if (parsed.type === "issue" && parsed.number) {
282
+ const settings2 = await this.settingsManager.loadSettings();
283
+ const epicIssueTracker = IssueTrackerFactory.create(settings2);
284
+ let children = [];
285
+ try {
286
+ children = await fetchChildIssues(String(parsed.number), epicIssueTracker, repo);
287
+ } catch (error) {
288
+ getLogger().warn(`Failed to check for child issues: ${error instanceof Error ? error.message : "Unknown error"}. Proceeding as normal loom.`);
289
+ }
290
+ if (children.length > 0) {
291
+ childIssueNumbers = children.map((c) => c.id);
292
+ let createAsEpic = false;
293
+ if (input.options.epic === true) {
294
+ createAsEpic = true;
295
+ getLogger().info(`Creating as epic loom with ${children.length} child issue(s) (--epic flag)`);
296
+ } else if (input.options.epic === false) {
297
+ createAsEpic = false;
298
+ getLogger().info("Creating as normal loom (--no-epic flag)");
299
+ } else {
300
+ if (isJsonMode) {
301
+ throw new Error("JSON mode requires explicit --epic or --no-epic flag when issue has child issues");
302
+ }
303
+ if (isInteractiveEnvironment()) {
304
+ createAsEpic = await promptConfirmation(
305
+ `This issue has ${children.length} child issue(s). Create as epic loom?`,
306
+ true
307
+ // Default yes
308
+ );
309
+ } else {
310
+ throw new Error("Non-interactive environment detected, use either --epic or --no-epic to specify behavior");
311
+ }
312
+ }
313
+ if (createAsEpic) {
314
+ parsed.type = "epic";
315
+ try {
316
+ const [details, depMap] = await Promise.all([
317
+ fetchChildIssueDetails(String(parsed.number), epicIssueTracker, repo),
318
+ buildDependencyMap(childIssueNumbers, settings2, repo)
319
+ ]);
320
+ childIssues = details ?? [];
321
+ dependencyMap = depMap ?? {};
322
+ getLogger().info(`Fetched ${childIssues.length} child issue details and dependency map`);
323
+ } catch (error) {
324
+ parsed.type = "issue";
325
+ childIssueNumbers = [];
326
+ getLogger().warn(`Failed to fetch epic child data, reverting to normal loom: ${error instanceof Error ? error.message : String(error)}`);
327
+ }
328
+ } else {
329
+ childIssueNumbers = [];
330
+ }
331
+ }
332
+ }
271
333
  if (input.options.oneShot === "bypassPermissions" && input.options.claude !== false && !isJsonMode) {
272
- const { promptConfirmation: promptConfirmation2 } = await import("./prompt-ONNPSNKM.js");
273
- const confirmed = await promptConfirmation2(
334
+ const confirmed = await promptConfirmation(
274
335
  "WARNING: bypassPermissions mode will allow Claude to execute all tool calls without confirmation. This can be dangerous. Do you want to proceed?"
275
336
  );
276
337
  if (!confirmed) {
@@ -280,7 +341,7 @@ var StartCommand = class {
280
341
  }
281
342
  const cliOverrides = extractSettingsOverrides();
282
343
  const settings = await this.settingsManager.loadSettings(void 0, cliOverrides);
283
- const workflowType = parsed.type === "branch" ? "regular" : parsed.type;
344
+ const workflowType = parsed.type === "branch" ? "regular" : parsed.type === "epic" ? "issue" : parsed.type;
284
345
  const workflowConfig = (_b = settings.workflows) == null ? void 0 : _b[workflowType];
285
346
  const { extractRawSetArguments, getExecutablePath } = await import("./cli-overrides-XFZWY7CM.js");
286
347
  const setArguments = extractRawSetArguments();
@@ -309,10 +370,27 @@ var StartCommand = class {
309
370
  enableTerminal,
310
371
  ...input.options.oneShot && { oneShot: input.options.oneShot },
311
372
  ...setArguments.length > 0 && { setArguments },
312
- ...executablePath && { executablePath }
373
+ ...executablePath && { executablePath },
374
+ ...childIssueNumbers.length > 0 && { childIssueNumbers },
375
+ ...childIssues.length > 0 && { childIssues },
376
+ ...Object.keys(dependencyMap).length > 0 && { dependencyMap }
313
377
  }
314
378
  });
315
379
  getLogger().success(`Created loom: ${loom.id} at ${loom.path}`);
380
+ try {
381
+ const oneShotMap = {
382
+ noReview: "skip-reviews",
383
+ bypassPermissions: "yolo"
384
+ };
385
+ TelemetryService.getInstance().track("loom.created", {
386
+ source_type: parsed.type === "epic" ? "issue" : parsed.type,
387
+ tracker: this.issueTracker.providerName,
388
+ is_child_loom: !!parentLoom,
389
+ one_shot_mode: oneShotMap[input.options.oneShot ?? ""] ?? "default"
390
+ });
391
+ } catch (error) {
392
+ getLogger().debug(`Failed to track loom.created telemetry: ${error instanceof Error ? error.message : String(error)}`);
393
+ }
316
394
  getLogger().info(` Branch: ${loom.branch}`);
317
395
  if ((_c = loom.capabilities) == null ? void 0 : _c.includes("web")) {
318
396
  getLogger().info(` Port: ${loom.port}`);
@@ -320,6 +398,9 @@ var StartCommand = class {
320
398
  if ((_d = loom.issueData) == null ? void 0 : _d.title) {
321
399
  getLogger().info(` Title: ${loom.issueData.title}`);
322
400
  }
401
+ if (parsed.type === "epic") {
402
+ getLogger().info(` Epic: yes (${childIssueNumbers.length} child issue(s))`);
403
+ }
323
404
  if (isJsonMode) {
324
405
  return {
325
406
  id: loom.id,
@@ -329,7 +410,8 @@ var StartCommand = class {
329
410
  identifier: loom.identifier,
330
411
  ...loom.port !== void 0 && { port: loom.port },
331
412
  ...((_e = loom.issueData) == null ? void 0 : _e.title) && { title: loom.issueData.title },
332
- ...loom.capabilities && { capabilities: loom.capabilities }
413
+ ...loom.capabilities && { capabilities: loom.capabilities },
414
+ ...childIssueNumbers.length > 0 && { childIssueNumbers }
333
415
  };
334
416
  }
335
417
  } catch (error) {
@@ -367,7 +449,7 @@ var StartCommand = class {
367
449
  };
368
450
  }
369
451
  const identifierMatch = matchIssueIdentifier(trimmedIdentifier);
370
- if (identifierMatch.type === "linear" && identifierMatch.identifier) {
452
+ if (identifierMatch.type === "project-key" && identifierMatch.identifier) {
371
453
  const detection = await this.issueTracker.detectInputType(
372
454
  trimmedIdentifier,
373
455
  repo
@@ -376,12 +458,12 @@ var StartCommand = class {
376
458
  return {
377
459
  type: "issue",
378
460
  number: detection.identifier,
379
- // Keep as string for Linear
461
+ // Keep as string for project key identifiers
380
462
  originalInput: trimmedIdentifier
381
463
  };
382
464
  }
383
465
  throw new Error(
384
- `Could not find Linear issue ${identifierMatch.identifier}`
466
+ `Could not find issue matching identifier ${identifierMatch.identifier}`
385
467
  );
386
468
  }
387
469
  if (identifierMatch.type === "numeric" && identifierMatch.identifier) {
@@ -498,6 +580,8 @@ var StartCommand = class {
498
580
  return `PR #${parsed.number}`;
499
581
  case "issue":
500
582
  return `Issue #${parsed.number}`;
583
+ case "epic":
584
+ return `Epic #${parsed.number}`;
501
585
  case "branch":
502
586
  return `Branch '${parsed.branchName}'`;
503
587
  case "description":
@@ -588,7 +672,10 @@ var AddIssueCommand = class {
588
672
  }
589
673
  throw new Error("Description is required and must be more than 30 characters with at least 3 words");
590
674
  }
591
- const issueBody = body ?? await this.enhancementService.enhanceDescription(description);
675
+ const enhancementInput = body ? `${description}
676
+
677
+ ${body}` : description;
678
+ const issueBody = await this.enhancementService.enhanceDescription(enhancementInput);
592
679
  const result = await this.enhancementService.createEnhancedIssue(
593
680
  description,
594
681
  issueBody,
@@ -747,17 +834,17 @@ var FinishCommand = class {
747
834
  * Lazy initialization of ResourceCleanup with properly configured DatabaseManager
748
835
  */
749
836
  async ensureResourceCleanup() {
750
- var _a, _b;
837
+ var _a2, _b;
751
838
  if (this.resourceCleanup && this.loomManager) {
752
839
  return;
753
840
  }
754
841
  const settings = await this.settingsManager.loadSettings();
755
- const databaseUrlEnvVarName = ((_b = (_a = settings.capabilities) == null ? void 0 : _a.database) == null ? void 0 : _b.databaseUrlEnvVarName) ?? "DATABASE_URL";
842
+ const databaseUrlEnvVarName = ((_b = (_a2 = settings.capabilities) == null ? void 0 : _a2.database) == null ? void 0 : _b.databaseUrlEnvVarName) ?? "DATABASE_URL";
756
843
  const environmentManager = new EnvironmentManager();
757
844
  const neonProvider = createNeonProviderFromSettings(settings);
758
845
  const databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName);
759
846
  const cliIsolationManager = new CLIIsolationManager();
760
- const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-K6XNWQ6C.js");
847
+ const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-ECJHBB67.js");
761
848
  this.loomManager ??= new LoomManager(
762
849
  this.gitWorktreeManager,
763
850
  this.issueTracker,
@@ -815,7 +902,7 @@ var FinishCommand = class {
815
902
  * Main entry point for finish command
816
903
  */
817
904
  async execute(input) {
818
- var _a, _b, _c, _d;
905
+ var _a2, _b, _c, _d, _e;
819
906
  process.env.ILOOM = "1";
820
907
  const isJsonMode = input.options.json === true;
821
908
  const result = {
@@ -827,7 +914,7 @@ var FinishCommand = class {
827
914
  };
828
915
  if (isJsonMode) {
829
916
  const settings2 = await this.settingsManager.loadSettings();
830
- if ((((_a = settings2.mergeBehavior) == null ? void 0 : _a.mode) === "github-pr" || ((_b = settings2.mergeBehavior) == null ? void 0 : _b.mode) === "github-draft-pr") && input.options.cleanup === void 0) {
917
+ if ((((_a2 = settings2.mergeBehavior) == null ? void 0 : _a2.mode) === "github-pr" || ((_b = settings2.mergeBehavior) == null ? void 0 : _b.mode) === "github-draft-pr") && input.options.cleanup === void 0) {
831
918
  throw new Error('JSON mode with "github-pr"/"github-draft-pr" workflow requires --cleanup or --no-cleanup flag. Use: il finish --json --cleanup <identifier>');
832
919
  }
833
920
  }
@@ -848,6 +935,14 @@ var FinishCommand = class {
848
935
  if (!worktree) {
849
936
  throw new Error("No worktree found");
850
937
  }
938
+ let preFinishCreatedAt;
939
+ try {
940
+ const metadataManager = new MetadataManager();
941
+ const metadata = await metadataManager.readMetadata(worktree.path);
942
+ preFinishCreatedAt = (metadata == null ? void 0 : metadata.created_at) ?? void 0;
943
+ } catch (error) {
944
+ getLogger().debug(`Failed to read metadata for telemetry: ${error instanceof Error ? error.message : String(error)}`);
945
+ }
851
946
  if (parsed.type === "pr") {
852
947
  if (!parsed.number) {
853
948
  throw new Error("Invalid PR number");
@@ -861,6 +956,15 @@ var FinishCommand = class {
861
956
  await this.executeIssueWorkflow(parsed, input.options, worktree, result);
862
957
  }
863
958
  result.success = true;
959
+ try {
960
+ const durationMinutes = preFinishCreatedAt ? Math.round((Date.now() - new Date(preFinishCreatedAt).getTime()) / 6e4) : 0;
961
+ TelemetryService.getInstance().track("loom.finished", {
962
+ merge_behavior: ((_e = settings.mergeBehavior) == null ? void 0 : _e.mode) ?? "local",
963
+ duration_minutes: isNaN(durationMinutes) ? 0 : durationMinutes
964
+ });
965
+ } catch (error) {
966
+ getLogger().debug(`Failed to track loom.finished telemetry: ${error instanceof Error ? error.message : String(error)}`);
967
+ }
864
968
  if (isJsonMode) {
865
969
  return result;
866
970
  }
@@ -888,6 +992,7 @@ var FinishCommand = class {
888
992
  * (No GitHub API calls - uses IdentifierParser)
889
993
  */
890
994
  async parseExplicitInput(identifier) {
995
+ var _a2;
891
996
  const prPattern = /^(?:pr|PR)[/-](\d+)$/;
892
997
  const prMatch = identifier.match(prPattern);
893
998
  if (prMatch == null ? void 0 : prMatch[1]) {
@@ -913,6 +1018,18 @@ var FinishCommand = class {
913
1018
  if (parsed.branchName !== void 0) {
914
1019
  result.branchName = parsed.branchName;
915
1020
  }
1021
+ if (result.type === "issue" && result.number !== void 0) {
1022
+ const worktree = await this.gitWorktreeManager.findWorktreeForIssue(result.number);
1023
+ if (worktree) {
1024
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-5QZSTKNN.js");
1025
+ const metadataManager = new MetadataManager2();
1026
+ const metadata = await metadataManager.readMetadata(worktree.path);
1027
+ const canonicalKey = (metadata == null ? void 0 : metadata.issueKey) ?? ((_a2 = metadata == null ? void 0 : metadata.issue_numbers) == null ? void 0 : _a2[0]);
1028
+ if (canonicalKey) {
1029
+ result.number = canonicalKey;
1030
+ }
1031
+ }
1032
+ }
916
1033
  return result;
917
1034
  }
918
1035
  /**
@@ -920,6 +1037,7 @@ var FinishCommand = class {
920
1037
  * Ports logic from merge-current-issue.sh lines 30-52
921
1038
  */
922
1039
  async autoDetectFromCurrentDirectory() {
1040
+ var _a2, _b;
923
1041
  const currentDir = path2.basename(process.cwd());
924
1042
  const prPattern = /_pr_(\d+)$/;
925
1043
  const prMatch = currentDir.match(prPattern);
@@ -933,14 +1051,18 @@ var FinishCommand = class {
933
1051
  autoDetected: true
934
1052
  };
935
1053
  }
1054
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-5QZSTKNN.js");
1055
+ const metadataManager = new MetadataManager2();
1056
+ const metadata = await metadataManager.readMetadata(process.cwd());
936
1057
  const issueNumber = extractIssueNumber(currentDir);
937
1058
  if (issueNumber !== null) {
1059
+ const originalIssueKey = (metadata == null ? void 0 : metadata.issueKey) ?? ((_a2 = metadata == null ? void 0 : metadata.issue_numbers) == null ? void 0 : _a2[0]) ?? issueNumber;
938
1060
  getLogger().debug(
939
- `Auto-detected issue #${issueNumber} from directory: ${currentDir}`
1061
+ `Auto-detected issue #${originalIssueKey} from directory: ${currentDir}`
940
1062
  );
941
1063
  return {
942
1064
  type: "issue",
943
- number: issueNumber,
1065
+ number: originalIssueKey,
944
1066
  originalInput: currentDir,
945
1067
  autoDetected: true
946
1068
  };
@@ -954,12 +1076,13 @@ var FinishCommand = class {
954
1076
  }
955
1077
  const branchIssueNumber = extractIssueNumber(currentBranch);
956
1078
  if (branchIssueNumber !== null) {
1079
+ const originalIssueKey = (metadata == null ? void 0 : metadata.issueKey) ?? ((_b = metadata == null ? void 0 : metadata.issue_numbers) == null ? void 0 : _b[0]) ?? branchIssueNumber;
957
1080
  getLogger().debug(
958
- `Auto-detected issue #${branchIssueNumber} from branch: ${currentBranch}`
1081
+ `Auto-detected issue #${originalIssueKey} from branch: ${currentBranch}`
959
1082
  );
960
1083
  return {
961
1084
  type: "issue",
962
- number: branchIssueNumber,
1085
+ number: originalIssueKey,
963
1086
  originalInput: currentBranch,
964
1087
  autoDetected: true
965
1088
  };
@@ -1098,85 +1221,102 @@ var FinishCommand = class {
1098
1221
  * This is the workflow: rebase → validate → commit → merge → cleanup
1099
1222
  */
1100
1223
  async executeIssueWorkflow(parsed, options, worktree, result) {
1101
- var _a, _b, _c, _d, _e;
1102
- getLogger().info("Rebasing branch on main...");
1224
+ var _a2, _b, _c, _d, _e, _f;
1103
1225
  const mergeOptions = {
1104
1226
  dryRun: options.dryRun ?? false,
1105
1227
  force: options.force ?? false
1106
1228
  };
1107
- await this.mergeManager.rebaseOnMain(worktree.path, mergeOptions);
1108
- getLogger().success("Branch rebased successfully");
1109
- result.operations.push({
1110
- type: "rebase",
1111
- message: "Branch rebased on main",
1112
- success: true
1113
- });
1114
- if (!options.dryRun) {
1115
- getLogger().info("Running pre-merge validations...");
1116
- await this.validationRunner.runValidations(worktree.path, {
1117
- dryRun: options.dryRun ?? false
1118
- });
1119
- getLogger().success("All validations passed");
1120
- result.operations.push({
1121
- type: "validation",
1122
- message: "Pre-merge validations passed",
1123
- success: true
1124
- });
1229
+ if (options.skipToPr) {
1230
+ getLogger().info("Skipping rebase/validation/commit (--skip-to-pr flag)");
1125
1231
  } else {
1126
- getLogger().info("[DRY RUN] Would run pre-merge validations");
1232
+ getLogger().info("Rebasing branch on main...");
1233
+ await this.mergeManager.rebaseOnMain(worktree.path, mergeOptions);
1234
+ getLogger().success("Branch rebased successfully");
1127
1235
  result.operations.push({
1128
- type: "validation",
1129
- message: "Would run pre-merge validations (dry-run)",
1236
+ type: "rebase",
1237
+ message: "Branch rebased on main",
1130
1238
  success: true
1131
1239
  });
1132
- }
1133
- const gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path);
1134
- if (gitStatus.hasUncommittedChanges) {
1135
- if (options.dryRun) {
1136
- getLogger().info("[DRY RUN] Would auto-commit uncommitted changes (validation passed)");
1240
+ if (!options.dryRun) {
1241
+ getLogger().info("Installing dependencies...");
1242
+ try {
1243
+ await installDependencies(worktree.path, true, true);
1244
+ } catch (error) {
1245
+ const message = error instanceof Error ? error.message : "Unknown error";
1246
+ getLogger().warn(`Dependency installation failed: ${message}`);
1247
+ getLogger().warn("Please run your package manager install command manually");
1248
+ }
1249
+ } else {
1250
+ getLogger().info("[DRY RUN] Would install dependencies");
1251
+ }
1252
+ if (!options.dryRun) {
1253
+ getLogger().info("Running pre-merge validations...");
1254
+ await this.validationRunner.runValidations(worktree.path, {
1255
+ dryRun: options.dryRun ?? false
1256
+ });
1257
+ getLogger().success("All validations passed");
1137
1258
  result.operations.push({
1138
- type: "commit",
1139
- message: "Would auto-commit uncommitted changes (dry-run)",
1259
+ type: "validation",
1260
+ message: "Pre-merge validations passed",
1140
1261
  success: true
1141
1262
  });
1142
1263
  } else {
1143
- getLogger().info("Validation passed, auto-committing uncommitted changes...");
1144
- const settings2 = await this.settingsManager.loadSettings(worktree.path);
1145
- const skipVerify = ((_b = (_a = settings2.workflows) == null ? void 0 : _a.issue) == null ? void 0 : _b.noVerify) ?? false;
1146
- const providerType = ((_c = settings2.issueManagement) == null ? void 0 : _c.provider) ?? "github";
1147
- const issuePrefix = IssueManagementProviderFactory.create(providerType).issuePrefix;
1148
- const commitOptions = {
1149
- dryRun: options.dryRun ?? false,
1150
- skipVerify,
1151
- issuePrefix,
1152
- timeout: (_d = settings2.git) == null ? void 0 : _d.commitTimeout
1153
- };
1154
- if (parsed.type === "issue" && parsed.number) {
1155
- commitOptions.issueNumber = parsed.number;
1156
- }
1157
- try {
1158
- await this.commitManager.commitChanges(worktree.path, commitOptions);
1159
- getLogger().success("Changes committed successfully");
1264
+ getLogger().info("[DRY RUN] Would run pre-merge validations");
1265
+ result.operations.push({
1266
+ type: "validation",
1267
+ message: "Would run pre-merge validations (dry-run)",
1268
+ success: true
1269
+ });
1270
+ }
1271
+ const gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path);
1272
+ if (gitStatus.hasUncommittedChanges) {
1273
+ if (options.dryRun) {
1274
+ getLogger().info("[DRY RUN] Would auto-commit uncommitted changes (validation passed)");
1160
1275
  result.operations.push({
1161
1276
  type: "commit",
1162
- message: "Changes committed successfully",
1277
+ message: "Would auto-commit uncommitted changes (dry-run)",
1163
1278
  success: true
1164
1279
  });
1165
- } catch (error) {
1166
- if (error instanceof UserAbortedCommitError) {
1167
- getLogger().info("Commit aborted by user");
1280
+ } else {
1281
+ getLogger().info("Validation passed, auto-committing uncommitted changes...");
1282
+ const settings2 = await this.settingsManager.loadSettings(worktree.path);
1283
+ const skipVerify = ((_b = (_a2 = settings2.workflows) == null ? void 0 : _a2.issue) == null ? void 0 : _b.noVerify) ?? false;
1284
+ const providerType = ((_c = settings2.issueManagement) == null ? void 0 : _c.provider) ?? "github";
1285
+ const issuePrefix = IssueManagementProviderFactory.create(providerType, settings2).issuePrefix;
1286
+ const commitOptions = {
1287
+ dryRun: options.dryRun ?? false,
1288
+ skipVerify,
1289
+ issuePrefix,
1290
+ timeout: (_d = settings2.git) == null ? void 0 : _d.commitTimeout,
1291
+ noReview: options.review !== true || options.json === true
1292
+ };
1293
+ if (parsed.type === "issue" && parsed.number) {
1294
+ commitOptions.issueNumber = parsed.number;
1295
+ }
1296
+ try {
1297
+ await this.commitManager.commitChanges(worktree.path, commitOptions);
1298
+ getLogger().success("Changes committed successfully");
1168
1299
  result.operations.push({
1169
1300
  type: "commit",
1170
- message: "Commit aborted by user",
1171
- success: false
1301
+ message: "Changes committed successfully",
1302
+ success: true
1172
1303
  });
1304
+ } catch (error) {
1305
+ if (error instanceof UserAbortedCommitError) {
1306
+ getLogger().info("Commit aborted by user");
1307
+ result.operations.push({
1308
+ type: "commit",
1309
+ message: "Commit aborted by user",
1310
+ success: false
1311
+ });
1312
+ throw error;
1313
+ }
1173
1314
  throw error;
1174
1315
  }
1175
- throw error;
1176
1316
  }
1317
+ } else {
1318
+ getLogger().debug("No uncommitted changes found");
1177
1319
  }
1178
- } else {
1179
- getLogger().debug("No uncommitted changes found");
1180
1320
  }
1181
1321
  const settings = await this.settingsManager.loadSettings(worktree.path);
1182
1322
  const mergeBehavior = settings.mergeBehavior ?? { mode: "local" };
@@ -1185,7 +1325,7 @@ var FinishCommand = class {
1185
1325
  return;
1186
1326
  }
1187
1327
  if (mergeBehavior.mode === "github-draft-pr") {
1188
- const { MetadataManager: MetadataManager3 } = await import("./MetadataManager-W3C54UYT.js");
1328
+ const { MetadataManager: MetadataManager3 } = await import("./MetadataManager-5QZSTKNN.js");
1189
1329
  const metadataManager2 = new MetadataManager3();
1190
1330
  const metadata = await metadataManager2.readMetadata(worktree.path);
1191
1331
  getLogger().debug(`Draft PR mode: worktree=${worktree.path}, draftPrNumber=${(metadata == null ? void 0 : metadata.draftPrNumber) ?? "none"}`);
@@ -1247,6 +1387,10 @@ var FinishCommand = class {
1247
1387
  if (prUrl) {
1248
1388
  result.prUrl = prUrl;
1249
1389
  }
1390
+ const shouldOpenBrowser = !options.dryRun && !options.noBrowser && !options.json && ((_f = settings.mergeBehavior) == null ? void 0 : _f.openBrowserOnFinish) !== false;
1391
+ if (shouldOpenBrowser && prUrl) {
1392
+ await prManager.openPRInBrowser(prUrl);
1393
+ }
1250
1394
  result.operations.push({
1251
1395
  type: "pr-ready",
1252
1396
  message: `PR #${metadata.draftPrNumber} marked as ready for review`,
@@ -1277,7 +1421,7 @@ var FinishCommand = class {
1277
1421
  getLogger().debug("Skipping build verification (--skip-build flag provided)");
1278
1422
  }
1279
1423
  await this.generateSessionSummaryIfConfigured(parsed, worktree, options);
1280
- const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-W3C54UYT.js");
1424
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-5QZSTKNN.js");
1281
1425
  const metadataManager = new MetadataManager2();
1282
1426
  if (!options.dryRun) {
1283
1427
  await metadataManager.archiveMetadata(worktree.path);
@@ -1296,7 +1440,7 @@ var FinishCommand = class {
1296
1440
  * - CLOSED/MERGED: Skip to cleanup
1297
1441
  */
1298
1442
  async executePRWorkflow(parsed, options, worktree, pr, result) {
1299
- var _a, _b, _c, _d;
1443
+ var _a2, _b, _c, _d;
1300
1444
  if (pr.state === "closed" || pr.state === "merged") {
1301
1445
  getLogger().info(`PR #${parsed.number} is ${pr.state.toUpperCase()} - skipping to cleanup`);
1302
1446
  const gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path);
@@ -1306,7 +1450,7 @@ var FinishCommand = class {
1306
1450
  "Cannot cleanup PR with uncommitted changes. Commit or stash changes, then run again with --force to cleanup anyway."
1307
1451
  );
1308
1452
  }
1309
- const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-W3C54UYT.js");
1453
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-5QZSTKNN.js");
1310
1454
  const metadataManager = new MetadataManager2();
1311
1455
  if (!options.dryRun) {
1312
1456
  await metadataManager.archiveMetadata(worktree.path);
@@ -1332,15 +1476,16 @@ var FinishCommand = class {
1332
1476
  } else {
1333
1477
  getLogger().info("Committing uncommitted changes...");
1334
1478
  const settings = await this.settingsManager.loadSettings(worktree.path);
1335
- const skipVerify = ((_b = (_a = settings.workflows) == null ? void 0 : _a.pr) == null ? void 0 : _b.noVerify) ?? false;
1479
+ const skipVerify = ((_b = (_a2 = settings.workflows) == null ? void 0 : _a2.pr) == null ? void 0 : _b.noVerify) ?? false;
1336
1480
  const providerType = ((_c = settings.issueManagement) == null ? void 0 : _c.provider) ?? "github";
1337
- const issuePrefix = IssueManagementProviderFactory.create(providerType).issuePrefix;
1481
+ const issuePrefix = IssueManagementProviderFactory.create(providerType, settings).issuePrefix;
1338
1482
  try {
1339
1483
  await this.commitManager.commitChanges(worktree.path, {
1340
1484
  dryRun: false,
1341
1485
  skipVerify,
1342
1486
  issuePrefix,
1343
- timeout: (_d = settings.git) == null ? void 0 : _d.commitTimeout
1487
+ timeout: (_d = settings.git) == null ? void 0 : _d.commitTimeout,
1488
+ noReview: options.review !== true || options.json === true
1344
1489
  // Do NOT pass issueNumber for PRs - no "Fixes #" trailer needed
1345
1490
  });
1346
1491
  getLogger().success("Changes committed");
@@ -1385,6 +1530,7 @@ var FinishCommand = class {
1385
1530
  * Validates → Commits → Pushes → Creates PR → Prompts for cleanup
1386
1531
  */
1387
1532
  async executeGitHubPRWorkflow(parsed, options, worktree, settings, finishResult) {
1533
+ var _a2;
1388
1534
  if (options.dryRun) {
1389
1535
  getLogger().info("[DRY RUN] Would push branch to origin");
1390
1536
  } else {
@@ -1413,7 +1559,7 @@ var FinishCommand = class {
1413
1559
  success: true
1414
1560
  });
1415
1561
  } else {
1416
- const openInBrowser = options.noBrowser !== true;
1562
+ const openInBrowser = !options.noBrowser && !options.json && ((_a2 = settings.mergeBehavior) == null ? void 0 : _a2.openBrowserOnFinish) !== false;
1417
1563
  const prResult = await prManager.createOrOpenPR(
1418
1564
  worktree.branch,
1419
1565
  prTitle,
@@ -1436,10 +1582,23 @@ var FinishCommand = class {
1436
1582
  message: `Pull request created`,
1437
1583
  success: true
1438
1584
  });
1585
+ if (parsed.type === "issue" && parsed.number) {
1586
+ try {
1587
+ if (this.issueTracker.moveIssueToReadyForReview) {
1588
+ await this.issueTracker.moveIssueToReadyForReview(parsed.number);
1589
+ getLogger().info("Issue moved to Ready for Review");
1590
+ }
1591
+ } catch (error) {
1592
+ getLogger().warn(
1593
+ `Failed to move issue to Ready for Review: ${error instanceof Error ? error.message : "Unknown error"}`,
1594
+ error
1595
+ );
1596
+ }
1597
+ }
1439
1598
  }
1440
1599
  finishResult.prUrl = prResult.url;
1441
1600
  await this.generateSessionSummaryIfConfigured(parsed, worktree, options, prResult.number);
1442
- const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-W3C54UYT.js");
1601
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-5QZSTKNN.js");
1443
1602
  const metadataManager = new MetadataManager2();
1444
1603
  if (!options.dryRun) {
1445
1604
  await metadataManager.archiveMetadata(worktree.path);
@@ -1493,7 +1652,8 @@ var FinishCommand = class {
1493
1652
  // Don't delete branch - PR still needs it
1494
1653
  keepDatabase: false,
1495
1654
  // Clean up database
1496
- force: options.force ?? false
1655
+ force: options.force ?? false,
1656
+ worktree: { path: worktree.path, branch: worktree.branch }
1497
1657
  };
1498
1658
  try {
1499
1659
  getLogger().info("Starting worktree cleanup...");
@@ -1576,7 +1736,8 @@ var FinishCommand = class {
1576
1736
  // For CLOSED PRs, we rely on checkMergeSafety to verify no unpushed commits
1577
1737
  // rather than checkRemoteBranch, since the remote branch may still exist
1578
1738
  // but local may have additional commits
1579
- checkRemoteBranch: false
1739
+ checkRemoteBranch: false,
1740
+ worktree: { path: worktree.path, branch: worktree.branch }
1580
1741
  };
1581
1742
  try {
1582
1743
  await this.ensureResourceCleanup();
@@ -1707,7 +1868,8 @@ var FinishCommand = class {
1707
1868
  // Delete branch after successful merge
1708
1869
  keepDatabase: false,
1709
1870
  // Clean up database after merge
1710
- force: options.force ?? false
1871
+ force: options.force ?? false,
1872
+ worktree: { path: worktree.path, branch: worktree.branch }
1711
1873
  };
1712
1874
  try {
1713
1875
  getLogger().info("Starting post-merge cleanup...");
@@ -1822,9 +1984,17 @@ function getPackageInfo(scriptPath) {
1822
1984
 
1823
1985
  // src/cli.ts
1824
1986
  import { fileURLToPath as fileURLToPath2 } from "url";
1825
- import { realpathSync } from "fs";
1987
+ import { realpathSync as realpathSync2 } from "fs";
1826
1988
 
1827
1989
  // src/utils/loom-formatter.ts
1990
+ import { realpathSync } from "fs";
1991
+ function resolvePathSafe(p) {
1992
+ try {
1993
+ return realpathSync(p);
1994
+ } catch {
1995
+ return p;
1996
+ }
1997
+ }
1828
1998
  function determineLoomType(worktree) {
1829
1999
  const prPathPattern = /_pr_\d+$/;
1830
2000
  if (prPathPattern.test(worktree.path)) {
@@ -1857,7 +2027,37 @@ function extractIssueNumbers(branch) {
1857
2027
  }
1858
2028
  return [issueNumber];
1859
2029
  }
1860
- function formatLoomForJson(worktree, mainWorktreePath, metadata) {
2030
+ function enrichSwarmIssues(childIssues, allMetadata, finishedMetadata, projectPath) {
2031
+ const resolvedProjectPath = projectPath ? resolvePathSafe(projectPath) : null;
2032
+ const scopedActive = resolvedProjectPath ? allMetadata.filter((m) => m.projectPath && resolvePathSafe(m.projectPath) === resolvedProjectPath) : allMetadata;
2033
+ const scopedFinished = resolvedProjectPath && finishedMetadata ? finishedMetadata.filter((m) => m.projectPath && resolvePathSafe(m.projectPath) === resolvedProjectPath) : finishedMetadata;
2034
+ const issueNumberToMetadata = /* @__PURE__ */ new Map();
2035
+ for (const meta of scopedActive) {
2036
+ for (const issueNum of meta.issue_numbers) {
2037
+ issueNumberToMetadata.set(issueNum, meta);
2038
+ }
2039
+ }
2040
+ const finishedIssueNumberToMetadata = /* @__PURE__ */ new Map();
2041
+ if (scopedFinished) {
2042
+ for (const meta of scopedFinished) {
2043
+ for (const issueNum of meta.issue_numbers) {
2044
+ finishedIssueNumberToMetadata.set(issueNum, meta);
2045
+ }
2046
+ }
2047
+ }
2048
+ return childIssues.map((child) => {
2049
+ const lookupNumber = child.number.startsWith("#") ? child.number.slice(1) : child.number;
2050
+ const childMeta = issueNumberToMetadata.get(lookupNumber) ?? finishedIssueNumberToMetadata.get(lookupNumber);
2051
+ return {
2052
+ number: child.number,
2053
+ title: child.title,
2054
+ url: child.url,
2055
+ state: (childMeta == null ? void 0 : childMeta.state) ?? null,
2056
+ worktreePath: (childMeta == null ? void 0 : childMeta.worktreePath) ?? null
2057
+ };
2058
+ });
2059
+ }
2060
+ function formatLoomForJson(worktree, mainWorktreePath, metadata, allMetadata, finishedMetadata) {
1861
2061
  const loomType = (metadata == null ? void 0 : metadata.issueType) ?? determineLoomType(worktree);
1862
2062
  let issueNumbers;
1863
2063
  let prNumbers;
@@ -1874,6 +2074,9 @@ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
1874
2074
  }
1875
2075
  }
1876
2076
  const isMainWorktree = mainWorktreePath ? worktree.path === mainWorktreePath : false;
2077
+ const isEpic = loomType === "epic";
2078
+ const swarmIssues = isEpic && (metadata == null ? void 0 : metadata.childIssues) && metadata.childIssues.length > 0 ? enrichSwarmIssues(metadata.childIssues, allMetadata ?? [], finishedMetadata, metadata == null ? void 0 : metadata.projectPath) : isEpic ? [] : void 0;
2079
+ const dependencyMap = isEpic ? (metadata == null ? void 0 : metadata.dependencyMap) && Object.keys(metadata.dependencyMap).length > 0 ? metadata.dependencyMap : {} : void 0;
1877
2080
  return {
1878
2081
  name: worktree.branch || worktree.path,
1879
2082
  worktreePath: worktree.bare ? null : worktree.path,
@@ -1890,15 +2093,22 @@ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
1890
2093
  issueUrls: (metadata == null ? void 0 : metadata.issueUrls) ?? {},
1891
2094
  prUrls: (metadata == null ? void 0 : metadata.prUrls) ?? {},
1892
2095
  capabilities: (metadata == null ? void 0 : metadata.capabilities) ?? [],
2096
+ state: (metadata == null ? void 0 : metadata.state) ?? null,
1893
2097
  isChildLoom: (metadata == null ? void 0 : metadata.parentLoom) != null,
1894
- parentLoom: (metadata == null ? void 0 : metadata.parentLoom) ?? null
2098
+ parentLoom: (metadata == null ? void 0 : metadata.parentLoom) ?? null,
2099
+ ...swarmIssues !== void 0 && { swarmIssues },
2100
+ ...dependencyMap !== void 0 && { dependencyMap }
1895
2101
  };
1896
2102
  }
1897
- function formatLoomsForJson(worktrees, mainWorktreePath, metadata) {
1898
- return worktrees.map((wt) => formatLoomForJson(wt, mainWorktreePath, metadata == null ? void 0 : metadata.get(wt.path)));
2103
+ function formatLoomsForJson(worktrees, mainWorktreePath, metadata, allMetadata, finishedMetadata) {
2104
+ const resolvedAllMetadata = allMetadata ?? (metadata ? Array.from(metadata.values()).filter((m) => m != null) : []);
2105
+ return worktrees.map((wt) => formatLoomForJson(wt, mainWorktreePath, metadata == null ? void 0 : metadata.get(wt.path), resolvedAllMetadata, finishedMetadata));
1899
2106
  }
1900
- function formatFinishedLoomForJson(metadata) {
2107
+ function formatFinishedLoomForJson(metadata, allMetadata, finishedMetadata) {
1901
2108
  const loomType = metadata.issueType ?? "branch";
2109
+ const isEpic = loomType === "epic";
2110
+ const swarmIssues = isEpic && metadata.childIssues && metadata.childIssues.length > 0 ? enrichSwarmIssues(metadata.childIssues, allMetadata ?? [], finishedMetadata, metadata.projectPath) : isEpic ? [] : void 0;
2111
+ const dependencyMap = isEpic ? metadata.dependencyMap && Object.keys(metadata.dependencyMap).length > 0 ? metadata.dependencyMap : {} : void 0;
1902
2112
  return {
1903
2113
  name: metadata.branchName ?? metadata.worktreePath ?? "unknown",
1904
2114
  worktreePath: null,
@@ -1919,116 +2129,16 @@ function formatFinishedLoomForJson(metadata) {
1919
2129
  capabilities: metadata.capabilities ?? [],
1920
2130
  status: metadata.status ?? "finished",
1921
2131
  finishedAt: metadata.finishedAt ?? null,
2132
+ state: metadata.state ?? null,
1922
2133
  isChildLoom: metadata.parentLoom != null,
1923
- parentLoom: metadata.parentLoom ?? null
2134
+ parentLoom: metadata.parentLoom ?? null,
2135
+ ...swarmIssues !== void 0 && { swarmIssues },
2136
+ ...dependencyMap !== void 0 && { dependencyMap }
1924
2137
  };
1925
2138
  }
1926
2139
 
1927
- // src/utils/list-children.ts
1928
- async function fetchChildIssues(parentIssueNumber, settings, repo) {
1929
- const providerName = IssueTrackerFactory.getProviderName(settings);
1930
- logger.debug("Fetching child issues", { parentIssueNumber, provider: providerName, repo });
1931
- const results = await Promise.allSettled([
1932
- (async () => {
1933
- var _a, _b;
1934
- if (providerName === "github") {
1935
- const issueNum = parseInt(parentIssueNumber, 10);
1936
- if (isNaN(issueNum)) {
1937
- logger.warn(`Invalid GitHub issue number: ${parentIssueNumber}`);
1938
- return [];
1939
- }
1940
- return getSubIssues(issueNum, repo);
1941
- } else if (providerName === "linear") {
1942
- const apiToken = (_b = (_a = settings.issueManagement) == null ? void 0 : _a.linear) == null ? void 0 : _b.apiToken;
1943
- return getLinearChildIssues(parentIssueNumber, apiToken ? { apiToken } : void 0);
1944
- } else {
1945
- logger.warn(`Unsupported issue tracker provider: ${providerName}`);
1946
- return [];
1947
- }
1948
- })()
1949
- ]);
1950
- const result = results[0];
1951
- if (result.status === "fulfilled") {
1952
- return result.value;
1953
- } else {
1954
- logger.warn(`Failed to fetch child issues for ${parentIssueNumber}`, { error: result.reason });
1955
- return [];
1956
- }
1957
- }
1958
- async function findChildLooms(parentBranchName, metadataManager) {
1959
- logger.debug("Finding child looms", { parentBranchName });
1960
- const allMetadata = await metadataManager.listAllMetadata();
1961
- const childLooms = allMetadata.filter((metadata) => {
1962
- if (!metadata.parentLoom) {
1963
- return false;
1964
- }
1965
- return metadata.parentLoom.branchName === parentBranchName;
1966
- });
1967
- logger.debug(`Found ${childLooms.length} child looms for parent: ${parentBranchName}`);
1968
- return childLooms;
1969
- }
1970
- function matchChildrenData(childIssues, childLooms) {
1971
- const issueToLoomMap = /* @__PURE__ */ new Map();
1972
- for (const loom of childLooms) {
1973
- for (const issueNum of loom.issue_numbers) {
1974
- issueToLoomMap.set(issueNum, loom);
1975
- }
1976
- }
1977
- const childIssueIds = new Set(childIssues.map((issue) => issue.id));
1978
- const matchedIssues = childIssues.map((issue) => {
1979
- const matchingLoom = issueToLoomMap.get(issue.id);
1980
- return {
1981
- id: issue.id,
1982
- title: issue.title,
1983
- url: issue.url,
1984
- state: issue.state,
1985
- hasActiveLoom: matchingLoom != null,
1986
- loomBranch: (matchingLoom == null ? void 0 : matchingLoom.branchName) ?? null
1987
- };
1988
- });
1989
- const matchedLooms = childLooms.map((loom) => {
1990
- const hasMatchingIssue = loom.issue_numbers.some((issueNum) => childIssueIds.has(issueNum));
1991
- return {
1992
- branch: loom.branchName ?? "",
1993
- issueNumbers: loom.issue_numbers,
1994
- hasMatchingIssue
1995
- };
1996
- });
1997
- const summary = {
1998
- totalIssues: matchedIssues.length,
1999
- issuesWithLooms: matchedIssues.filter((issue) => issue.hasActiveLoom).length,
2000
- totalLooms: matchedLooms.length,
2001
- orphanLooms: matchedLooms.filter((loom) => !loom.hasMatchingIssue).length
2002
- };
2003
- return {
2004
- issues: matchedIssues,
2005
- looms: matchedLooms,
2006
- summary
2007
- };
2008
- }
2009
- async function assembleChildrenData(parentLoom, metadataManager, settings, repo) {
2010
- if (!parentLoom.issue_numbers || parentLoom.issue_numbers.length === 0) {
2011
- logger.debug("No issue_numbers on loom, skipping children fetch", {
2012
- branch: parentLoom.branchName
2013
- });
2014
- return null;
2015
- }
2016
- if (!parentLoom.branchName) {
2017
- logger.debug("No branchName on loom, skipping children fetch");
2018
- return null;
2019
- }
2020
- const parentIssueNumber = parentLoom.issue_numbers[0];
2021
- if (parentIssueNumber === void 0) {
2022
- return null;
2023
- }
2024
- const [childIssues, childLooms] = await Promise.all([
2025
- fetchChildIssues(parentIssueNumber, settings, repo),
2026
- findChildLooms(parentLoom.branchName, metadataManager)
2027
- ]);
2028
- return matchChildrenData(childIssues, childLooms);
2029
- }
2030
-
2031
2140
  // src/cli.ts
2141
+ import chalk from "chalk";
2032
2142
  import fs3 from "fs-extra";
2033
2143
 
2034
2144
  // src/lib/VersionMigrationManager.ts
@@ -2081,6 +2191,28 @@ var migrations = [
2081
2191
  const newContent = content + separator + "\n# Added by iloom CLI\n" + pattern + "\n";
2082
2192
  await fs.writeFile(globalIgnorePath, newContent, "utf-8");
2083
2193
  }
2194
+ },
2195
+ {
2196
+ version: "0.9.3",
2197
+ description: "Add global gitignore for swarm mode agent and skill files",
2198
+ migrate: async () => {
2199
+ const globalIgnorePath = path3.join(os.homedir(), ".config", "git", "ignore");
2200
+ const agentPattern = "**/.claude/agents/iloom-*";
2201
+ const skillPattern = "**/.claude/skills/iloom-*";
2202
+ const mcpConfigPathPattern = "**/.claude/iloom-swarm-mcp-config-path";
2203
+ await fs.ensureDir(path3.dirname(globalIgnorePath));
2204
+ let content = "";
2205
+ try {
2206
+ content = await fs.readFile(globalIgnorePath, "utf-8");
2207
+ } catch {
2208
+ }
2209
+ if (content.includes(agentPattern)) {
2210
+ return;
2211
+ }
2212
+ const separator = content.endsWith("\n") || content === "" ? "" : "\n";
2213
+ const newContent = content + separator + "\n# Added by iloom CLI\n" + agentPattern + "\n" + skillPattern + "\n" + mcpConfigPathPattern + "\n";
2214
+ await fs.writeFile(globalIgnorePath, newContent, "utf-8");
2215
+ }
2084
2216
  }
2085
2217
  ];
2086
2218
 
@@ -2213,6 +2345,35 @@ var VersionMigrationManager = class {
2213
2345
  // src/cli.ts
2214
2346
  var __filename = fileURLToPath2(import.meta.url);
2215
2347
  var packageJson = getPackageInfo(__filename);
2348
+ function handleTelemetryLifecycle(currentVersion, jsonMode) {
2349
+ const service = TelemetryService.getInstance();
2350
+ const telemetryManager = service.getManager();
2351
+ if (!telemetryManager.hasBeenDisclosed()) {
2352
+ if (!jsonMode) {
2353
+ logger.info("");
2354
+ logger.info("iloom collects anonymous usage data to improve the product.");
2355
+ logger.info("No personal information, repo names, or code is collected.");
2356
+ logger.info('Run "il telemetry off" to disable CLI telemetry at any time.');
2357
+ logger.info("If you also use the iloom VS Code extension, its telemetry is managed separately in VS Code settings.");
2358
+ logger.info("");
2359
+ }
2360
+ telemetryManager.markDisclosed();
2361
+ service.track("cli.installed", {
2362
+ version: currentVersion,
2363
+ os: process.platform,
2364
+ node_version: process.version
2365
+ });
2366
+ }
2367
+ const lastVersion = telemetryManager.getLastVersion();
2368
+ if (lastVersion && lastVersion !== currentVersion) {
2369
+ service.track("cli.upgraded", {
2370
+ version: currentVersion,
2371
+ previous_version: lastVersion,
2372
+ os: process.platform
2373
+ });
2374
+ }
2375
+ telemetryManager.setLastVersion(currentVersion);
2376
+ }
2216
2377
  function parseIssueIdentifier(value) {
2217
2378
  const parsed = parseInt(value, 10);
2218
2379
  return !isNaN(parsed) && String(parsed) === value ? parsed : value;
@@ -2248,6 +2409,12 @@ program.name("iloom").description(packageJson.description).version(packageJson.v
2248
2409
  } catch (error) {
2249
2410
  logger.warn(`Version migration failed: ${error instanceof Error ? error.message : "Unknown"}`);
2250
2411
  }
2412
+ try {
2413
+ const jsonMode = actionCommand.opts().json === true;
2414
+ handleTelemetryLifecycle(packageJson.version, jsonMode);
2415
+ } catch (error) {
2416
+ logger.debug(`Telemetry: ${error instanceof Error ? error.message : String(error)}`);
2417
+ }
2251
2418
  await validateSettingsForCommand(actionCommand);
2252
2419
  await validateGhCliForCommand(actionCommand);
2253
2420
  await validateIdeForStartCommand(actionCommand);
@@ -2262,9 +2429,9 @@ program.name("iloom").description(packageJson.description).version(packageJson.v
2262
2429
  }
2263
2430
  });
2264
2431
  async function validateSettingsForCommand(command) {
2265
- var _a, _b;
2432
+ var _a2, _b;
2266
2433
  const commandName = command.name();
2267
- const bypassCommands = ["help", "init", "update", "contribute"];
2434
+ const bypassCommands = ["help", "init", "update", "contribute", "telemetry"];
2268
2435
  if (bypassCommands.includes(commandName)) {
2269
2436
  return;
2270
2437
  }
@@ -2273,7 +2440,7 @@ async function validateSettingsForCommand(command) {
2273
2440
  const settingsManager = new SettingsManager();
2274
2441
  const settings = await settingsManager.loadSettings();
2275
2442
  const multipleRemotes = await hasMultipleRemotes();
2276
- if (multipleRemotes && !((_b = (_a = settings.issueManagement) == null ? void 0 : _a.github) == null ? void 0 : _b.remote)) {
2443
+ if (multipleRemotes && !((_b = (_a2 = settings.issueManagement) == null ? void 0 : _a2.github) == null ? void 0 : _b.remote)) {
2277
2444
  await autoLaunchInitForMultipleRemotes();
2278
2445
  return;
2279
2446
  }
@@ -2288,7 +2455,7 @@ async function validateSettingsForCommand(command) {
2288
2455
  }
2289
2456
  }
2290
2457
  async function validateGhCliForCommand(command) {
2291
- var _a, _b;
2458
+ var _a2, _b;
2292
2459
  const commandName = command.name();
2293
2460
  const alwaysRequireGh = ["feedback", "contribute"];
2294
2461
  const conditionallyRequireGh = ["start", "finish", "enhance", "add-issue", "ignite", "spin"];
@@ -2303,7 +2470,7 @@ async function validateGhCliForCommand(command) {
2303
2470
  const settingsManager = new SettingsManager();
2304
2471
  const settings = await settingsManager.loadSettings();
2305
2472
  const provider = IssueTrackerFactory.getProviderName(settings);
2306
- const mergeBehaviorMode = (_a = settings.mergeBehavior) == null ? void 0 : _a.mode;
2473
+ const mergeBehaviorMode = (_a2 = settings.mergeBehavior) == null ? void 0 : _a2.mode;
2307
2474
  needsGhCli = provider === "github" || mergeBehaviorMode === "github-pr" || mergeBehaviorMode === "github-draft-pr";
2308
2475
  } catch {
2309
2476
  needsGhCli = true;
@@ -2341,7 +2508,7 @@ async function validateGhCliForCommand(command) {
2341
2508
  }
2342
2509
  }
2343
2510
  async function validateIdeForStartCommand(command) {
2344
- var _a, _b;
2511
+ var _a2, _b;
2345
2512
  const commandName = command.name();
2346
2513
  if (commandName !== "start") {
2347
2514
  return;
@@ -2357,7 +2524,7 @@ async function validateIdeForStartCommand(command) {
2357
2524
  } catch {
2358
2525
  return;
2359
2526
  }
2360
- const workflowConfig = (_a = settings.workflows) == null ? void 0 : _a.issue;
2527
+ const workflowConfig = (_a2 = settings.workflows) == null ? void 0 : _a2.issue;
2361
2528
  if ((workflowConfig == null ? void 0 : workflowConfig.startIde) === false && codeOption !== true) {
2362
2529
  return;
2363
2530
  }
@@ -2376,7 +2543,7 @@ async function validateIdeForStartCommand(command) {
2376
2543
  }
2377
2544
  }
2378
2545
  async function autoLaunchInitForMultipleRemotes() {
2379
- var _a, _b;
2546
+ var _a2, _b;
2380
2547
  logger.info("Multiple git remotes detected, but no GitHub remote is configured.");
2381
2548
  logger.info("");
2382
2549
  logger.info("iloom will now launch an interactive configuration session with Claude");
@@ -2386,19 +2553,19 @@ async function autoLaunchInitForMultipleRemotes() {
2386
2553
  await waitForKeypress2("Press any key to start configuration...");
2387
2554
  logger.info("");
2388
2555
  try {
2389
- const { InitCommand } = await import("./init-676DHF6R.js");
2556
+ const { InitCommand } = await import("./init-GFQ5W7GK.js");
2390
2557
  const initCommand = new InitCommand();
2391
2558
  const customInitialMessage = "Help me configure which git remote iloom should use for GitHub operations. I have multiple remotes and need to select the correct one.";
2392
2559
  await initCommand.execute(customInitialMessage);
2393
2560
  logger.info("");
2394
2561
  logger.info("Configuration complete! Continuing with your original command...");
2395
2562
  logger.info("");
2396
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-AW3JTJHD.js");
2563
+ const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-BQDQA3FK.js");
2397
2564
  const settingsManager = new SettingsManager2();
2398
2565
  const settings = await settingsManager.loadSettings();
2399
2566
  const { hasMultipleRemotes: hasMultipleRemotes2 } = await import("./remote-IJAMOEAP.js");
2400
2567
  const multipleRemotes = await hasMultipleRemotes2();
2401
- if (multipleRemotes && !((_b = (_a = settings.issueManagement) == null ? void 0 : _a.github) == null ? void 0 : _b.remote)) {
2568
+ if (multipleRemotes && !((_b = (_a2 = settings.issueManagement) == null ? void 0 : _a2.github) == null ? void 0 : _b.remote)) {
2402
2569
  logger.error("Configuration incomplete: GitHub remote is still not configured.");
2403
2570
  logger.info('Please run "iloom init" again and configure the GitHub remote setting.');
2404
2571
  process.exit(1);
@@ -2412,7 +2579,7 @@ async function autoLaunchInitForMultipleRemotes() {
2412
2579
  }
2413
2580
  var shellCompletion = new ShellCompletion();
2414
2581
  shellCompletion.init();
2415
- program.command("start").alias("new").alias("create").alias("up").description("Create isolated workspace for an issue/PR").argument("[identifier]", "Issue number, PR number, or branch name (optional - will prompt if not provided)").option("--claude", "Enable Claude integration (default: true)").option("--no-claude", "Disable Claude integration").option("--code", "Enable VSCode (default: true)").option("--no-code", "Disable VSCode").option("--dev-server", "Enable dev server in terminal (default: true)").option("--no-dev-server", "Disable dev server").option("--terminal", "Enable terminal without dev server (default: false)").option("--no-terminal", "Disable terminal").option("--child-loom", "Force create as child loom (skip prompt)").option("--no-child-loom", "Force create as independent loom (skip prompt)").option("--body <text>", "Body text for issue (skips AI enhancement)").option("--json", "Output result as JSON").addOption(
2582
+ program.command("start").alias("new").alias("create").alias("up").description("Create isolated workspace for an issue/PR").argument("[identifier]", "Issue number, PR number, or branch name (optional - will prompt if not provided)").option("--claude", "Enable Claude integration (default: true)").option("--no-claude", "Disable Claude integration").option("--code", "Enable VSCode (default: true)").option("--no-code", "Disable VSCode").option("--dev-server", "Enable dev server in terminal (default: true)").option("--no-dev-server", "Disable dev server").option("--terminal", "Enable terminal without dev server (default: false)").option("--no-terminal", "Disable terminal").option("--child-loom", "Force create as child loom (skip prompt)").option("--no-child-loom", "Force create as independent loom (skip prompt)").option("--epic", "Create as epic loom with child issues (skip prompt; ignored if no children)").option("--no-epic", "Skip epic loom creation even if issue has children (ignored if no children)").option("--body <text>", "Body text for issue (skips AI enhancement)").option("--json", "Output result as JSON").addOption(
2416
2583
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
2417
2584
  ).option("--yolo", "Enable autonomous mode (shorthand for --one-shot=bypassPermissions)").action(async (identifier, options) => {
2418
2585
  if (options.yolo) {
@@ -2490,7 +2657,7 @@ program.command("add-issue").alias("a").description("Create and enhance GitHub i
2490
2657
  });
2491
2658
  program.command("feedback").alias("f").description("Submit feedback/bug report to iloom-cli repository").argument("<description>", "Feedback title (>30 chars, >2 spaces; or any non-empty text when --body provided)").option("--body <text>", "Body text for feedback (added after diagnostics)").action(async (description, options) => {
2492
2659
  try {
2493
- const { FeedbackCommand } = await import("./feedback-E7VET7CL.js");
2660
+ const { FeedbackCommand } = await import("./feedback-TMBXSCM5.js");
2494
2661
  const command = new FeedbackCommand();
2495
2662
  const feedbackOptions = {};
2496
2663
  if (options.body !== void 0) {
@@ -2541,7 +2708,10 @@ program.command("enhance").description("Apply enhancement agent to existing GitH
2541
2708
  await executeAction();
2542
2709
  }
2543
2710
  });
2544
- program.command("finish").alias("dn").description("Merge work and cleanup workspace").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("-f, --force", "Skip confirmation prompts").option("-n, --dry-run", "Preview actions without executing").option("--pr <number>", "Treat input as PR number", parseFloat).option("--skip-build", "Skip post-merge build verification").option("--no-browser", "Skip opening PR in browser (github-pr mode only)").option("--cleanup", "Clean up worktree after finishing (default in local mode)").option("--no-cleanup", "Keep worktree after finishing").option("--json", "Output result as JSON").action(async (identifier, options) => {
2711
+ program.command("finish").alias("dn").description("Merge work and cleanup workspace").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("-f, --force", "Skip confirmation prompts").option("-n, --dry-run", "Preview actions without executing").option("--pr <number>", "Treat input as PR number", parseFloat).option("--skip-build", "Skip post-merge build verification").option("--no-browser", "Skip opening PR in browser (github-pr and github-draft-pr modes)").option("--cleanup", "Clean up worktree after finishing (default in local mode)").option("--no-cleanup", "Keep worktree after finishing").option("--review", "Review commit message before committing (default: auto-commit without review)").option("--json", "Output result as JSON").action(async (identifier, options) => {
2712
+ if (options.browser === false) {
2713
+ options.noBrowser = true;
2714
+ }
2545
2715
  const executeAction = async () => {
2546
2716
  try {
2547
2717
  const settingsManager = new SettingsManager();
@@ -2575,7 +2745,7 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
2575
2745
  program.command("commit").alias("c").description("Commit all uncommitted files with issue reference").option("-m, --message <text>", "Custom commit message (skip Claude generation)").option("--fixes", 'Use "Fixes #N" trailer instead of "Refs #N" (closes issue)').option("--no-review", "Skip commit message review prompt").option("--json", "Output result as JSON (implies --no-review)").option("--wip-commit", "Quick WIP commit: skip validations and pre-commit hooks").action(async (options) => {
2576
2746
  const executeAction = async () => {
2577
2747
  try {
2578
- const { CommitCommand } = await import("./commit-IVP3M4HG.js");
2748
+ const { CommitCommand } = await import("./commit-L3EPY5QG.js");
2579
2749
  const command = new CommitCommand();
2580
2750
  const noReview = options.review === false || options.json === true;
2581
2751
  const result = await command.execute({
@@ -2610,7 +2780,7 @@ program.command("commit").alias("c").description("Commit all uncommitted files w
2610
2780
  });
2611
2781
  program.command("rebase").description("Rebase current branch on main with Claude-assisted conflict resolution").option("-f, --force", "Skip confirmation prompts").option("-n, --dry-run", "Preview actions without executing").action(async (options) => {
2612
2782
  try {
2613
- const { RebaseCommand } = await import("./rebase-YND35CIE.js");
2783
+ const { RebaseCommand } = await import("./rebase-DWIB77KV.js");
2614
2784
  const command = new RebaseCommand();
2615
2785
  await command.execute(options);
2616
2786
  } catch (error) {
@@ -2622,12 +2792,12 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2622
2792
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"])
2623
2793
  ).option("--yolo", "Enable autonomous mode (shorthand for --one-shot=bypassPermissions)").option("-p, --print", "Enable print/headless mode for CI/CD (uses bypassPermissions)").addOption(
2624
2794
  new Option("--output-format <format>", "Output format for Claude CLI (requires --print)").choices(["json", "stream-json", "text"])
2625
- ).option("--verbose", "Enable verbose output (requires --print)").option("--json", "Output final result as JSON object (requires --print)").option("--json-stream", "Stream JSONL output to stdout in real-time (requires --print)").action(async (options) => {
2795
+ ).option("--verbose", "Enable verbose output (requires --print)").option("--json", "Output final result as JSON object (requires --print)").option("--json-stream", "Stream JSONL output to stdout in real-time (requires --print)").option("--set <key=value>", "Override settings (repeatable, e.g., --set workflows.issue.permissionMode=bypassPermissions)").option("--skip-cleanup", "Skip automatic cleanup of child worktrees after they complete in swarm mode").action(async (options) => {
2626
2796
  if (options.yolo) {
2627
2797
  options.oneShot = "bypassPermissions";
2628
2798
  }
2629
2799
  try {
2630
- const { IgniteCommand } = await import("./ignite-IW35CDBD.js");
2800
+ const { IgniteCommand } = await import("./ignite-CGOV3TD4.js");
2631
2801
  const command = new IgniteCommand();
2632
2802
  if (options.json && options.jsonStream) {
2633
2803
  logger.error("--json and --json-stream are mutually exclusive");
@@ -2646,7 +2816,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2646
2816
  ...options.json && { json: true },
2647
2817
  ...options.jsonStream && { jsonStream: true }
2648
2818
  } : void 0;
2649
- await command.execute(options.oneShot, printOptions);
2819
+ await command.execute(options.oneShot, printOptions, options.skipCleanup);
2650
2820
  } catch (error) {
2651
2821
  logger.error(`Failed to spin up loom: ${error instanceof Error ? error.message : "Unknown error"}`);
2652
2822
  process.exit(1);
@@ -2655,7 +2825,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2655
2825
  program.command("open").description("Open workspace in browser or run CLI tool").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").allowUnknownOption().action(async (identifier, _options, command) => {
2656
2826
  try {
2657
2827
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2658
- const { OpenCommand } = await import("./open-544H7JF5.js");
2828
+ const { OpenCommand } = await import("./open-5QZGXQRF.js");
2659
2829
  const cmd = new OpenCommand();
2660
2830
  const input = identifier ? { identifier, args } : { args };
2661
2831
  await cmd.execute(input);
@@ -2667,7 +2837,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
2667
2837
  program.command("run").description("Run CLI tool or open workspace in browser").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").allowUnknownOption().action(async (identifier, _options, command) => {
2668
2838
  try {
2669
2839
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2670
- const { RunCommand } = await import("./run-QUXJKDQQ.js");
2840
+ const { RunCommand } = await import("./run-O3TFNQFC.js");
2671
2841
  const cmd = new RunCommand();
2672
2842
  const input = identifier ? { identifier, args } : { args };
2673
2843
  await cmd.execute(input);
@@ -2678,7 +2848,7 @@ program.command("run").description("Run CLI tool or open workspace in browser").
2678
2848
  });
2679
2849
  program.command("vscode").description("Install iloom VS Code extension and open workspace in VS Code").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("--no-wait", "Skip keypress prompt and open immediately").action(async (identifier, options) => {
2680
2850
  try {
2681
- const { VSCodeCommand } = await import("./vscode-AR5NNXXI.js");
2851
+ const { VSCodeCommand } = await import("./vscode-VA5X4P25.js");
2682
2852
  const cmd = new VSCodeCommand();
2683
2853
  await cmd.execute({ identifier, wait: options == null ? void 0 : options.wait });
2684
2854
  } catch (error) {
@@ -2687,7 +2857,7 @@ program.command("vscode").description("Install iloom VS Code extension and open
2687
2857
  });
2688
2858
  program.command("dev-server").alias("dev").description("Start dev server for workspace (foreground)").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("--json", "Output as JSON").action(async (identifier, options) => {
2689
2859
  try {
2690
- const { DevServerCommand } = await import("./dev-server-7F622OEO.js");
2860
+ const { DevServerCommand } = await import("./dev-server-FYZ2AQIH.js");
2691
2861
  const cmd = new DevServerCommand();
2692
2862
  await cmd.execute({ identifier, json: options == null ? void 0 : options.json });
2693
2863
  } catch (error) {
@@ -2697,7 +2867,7 @@ program.command("dev-server").alias("dev").description("Start dev server for wor
2697
2867
  });
2698
2868
  program.command("shell").alias("terminal").description("Open interactive shell with workspace environment").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
2699
2869
  try {
2700
- const { ShellCommand } = await import("./shell-QGECBLST.js");
2870
+ const { ShellCommand } = await import("./shell-G6VC2CYR.js");
2701
2871
  const cmd = new ShellCommand();
2702
2872
  await cmd.execute({ identifier });
2703
2873
  } catch (error) {
@@ -2707,7 +2877,7 @@ program.command("shell").alias("terminal").description("Open interactive shell w
2707
2877
  });
2708
2878
  program.command("build").description("Run the build script").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
2709
2879
  try {
2710
- const { BuildCommand } = await import("./build-THZI572G.js");
2880
+ const { BuildCommand } = await import("./build-5GO3XW26.js");
2711
2881
  const cmd = new BuildCommand();
2712
2882
  await cmd.execute(identifier ? { identifier } : {});
2713
2883
  } catch (error) {
@@ -2717,7 +2887,7 @@ program.command("build").description("Run the build script").argument("[identifi
2717
2887
  });
2718
2888
  program.command("lint").description("Run the lint script").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
2719
2889
  try {
2720
- const { LintCommand } = await import("./lint-CJM7BAIM.js");
2890
+ const { LintCommand } = await import("./lint-6TQXDZ3T.js");
2721
2891
  const cmd = new LintCommand();
2722
2892
  await cmd.execute(identifier ? { identifier } : {});
2723
2893
  } catch (error) {
@@ -2727,7 +2897,7 @@ program.command("lint").description("Run the lint script").argument("[identifier
2727
2897
  });
2728
2898
  program.command("test").description("Run the test script").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
2729
2899
  try {
2730
- const { TestCommand } = await import("./test-EA5NQFDC.js");
2900
+ const { TestCommand } = await import("./test-F7JNJZYP.js");
2731
2901
  const cmd = new TestCommand();
2732
2902
  await cmd.execute(identifier ? { identifier } : {});
2733
2903
  } catch (error) {
@@ -2737,7 +2907,7 @@ program.command("test").description("Run the test script").argument("[identifier
2737
2907
  });
2738
2908
  program.command("compile").alias("typecheck").description("Run the compile or typecheck script (prefers compile if both exist)").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
2739
2909
  try {
2740
- const { CompileCommand } = await import("./compile-R2J65HBQ.js");
2910
+ const { CompileCommand } = await import("./compile-ZS4HYRX5.js");
2741
2911
  const cmd = new CompileCommand();
2742
2912
  await cmd.execute(identifier ? { identifier } : {});
2743
2913
  } catch (error) {
@@ -2745,10 +2915,10 @@ program.command("compile").alias("typecheck").description("Run the compile or ty
2745
2915
  process.exit(1);
2746
2916
  }
2747
2917
  });
2748
- program.command("cleanup").alias("remove").alias("clean").description("Remove workspaces").argument("[identifier]", "Branch name or issue number to cleanup (auto-detected)").option("-l, --list", "List all worktrees").option("-a, --all", "Remove all worktrees (interactive confirmation)").option("-i, --issue <number>", "Cleanup by issue number", parseInt).option("-f, --force", "Skip confirmations and force removal").option("--dry-run", "Show what would be done without doing it").option("--json", "Output result as JSON").option("--defer <ms>", "Wait specified milliseconds before cleanup", parseInt).action(async (identifier, options) => {
2918
+ program.command("cleanup").alias("remove").alias("clean").description("Remove workspaces").argument("[identifier]", "Branch name or issue number to cleanup (auto-detected)").option("-l, --list", "List all worktrees").option("-a, --all", "Remove all worktrees (interactive confirmation)").option("-i, --issue <number>", "Cleanup by issue number", parseInt).option("-f, --force", "Skip confirmations and force removal").option("--dry-run", "Show what would be done without doing it").option("--json", "Output result as JSON").option("--archive", "Archive metadata instead of deleting (preserves loom in il list --finished)").option("--defer <ms>", "Wait specified milliseconds before cleanup", parseInt).action(async (identifier, options) => {
2749
2919
  const executeAction = async () => {
2750
2920
  try {
2751
- const { CleanupCommand } = await import("./cleanup-PJRIFFU4.js");
2921
+ const { CleanupCommand } = await import("./cleanup-6UCPVMFG.js");
2752
2922
  const command = new CleanupCommand();
2753
2923
  const input = {
2754
2924
  options: options ?? {}
@@ -2777,6 +2947,22 @@ program.command("cleanup").alias("remove").alias("clean").description("Remove wo
2777
2947
  await executeAction();
2778
2948
  }
2779
2949
  });
2950
+ function colorizeState(state) {
2951
+ switch (state) {
2952
+ case "pending":
2953
+ return chalk.gray(state);
2954
+ case "in_progress":
2955
+ return chalk.yellow(state);
2956
+ case "code_review":
2957
+ return chalk.blue(state);
2958
+ case "done":
2959
+ return chalk.green(state);
2960
+ case "failed":
2961
+ return chalk.red(state);
2962
+ default:
2963
+ return chalk.gray(state);
2964
+ }
2965
+ }
2780
2966
  program.command("list").description("Show active workspaces").option("--json", "Output as JSON").option("--finished", "Show only finished looms (sorted by finish time, latest first)").option("--all", "Show both active and finished looms").option("--global", "Show looms from all projects (default: current project only)").option("--children", "Fetch and display child issues and child looms for each parent loom").action(async (options) => {
2781
2967
  try {
2782
2968
  const manager = new GitWorktreeManager();
@@ -2834,10 +3020,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2834
3020
  }
2835
3021
  }
2836
3022
  }
2837
- let finishedLooms = [];
2838
- if (showFinished) {
2839
- finishedLooms = await metadataManager.listFinishedMetadata();
2840
- }
3023
+ const finishedLooms = await metadataManager.listFinishedMetadata();
2841
3024
  let filteredWorktrees = worktrees;
2842
3025
  let filteredGlobalActiveLooms = globalActiveLooms;
2843
3026
  let filteredFinishedLooms = finishedLooms;
@@ -2856,32 +3039,41 @@ program.command("list").description("Show active workspaces").option("--json", "
2856
3039
  mainWorktreePath = await findMainWorktreePathWithSettings();
2857
3040
  } catch {
2858
3041
  }
3042
+ const allActiveMetadata = options.global ? globalActiveLooms : Array.from(metadata.values()).filter((m) => m != null);
2859
3043
  let activeJson = [];
2860
3044
  if (showActive) {
2861
3045
  if (options.global) {
2862
- activeJson = globalActiveLooms.map((loom) => ({
2863
- name: loom.branchName ?? loom.worktreePath ?? "unknown",
2864
- worktreePath: loom.worktreePath,
2865
- branch: loom.branchName,
2866
- type: loom.issueType ?? "branch",
2867
- issue_numbers: loom.issue_numbers,
2868
- pr_numbers: loom.pr_numbers,
2869
- isMainWorktree: false,
2870
- // Global looms from other projects are never the main worktree
2871
- description: loom.description ?? null,
2872
- created_at: loom.created_at ?? null,
2873
- issueTracker: loom.issueTracker ?? null,
2874
- colorHex: loom.colorHex ?? null,
2875
- projectPath: loom.projectPath ?? null,
2876
- issueUrls: loom.issueUrls ?? {},
2877
- prUrls: loom.prUrls ?? {},
2878
- status: "active",
2879
- finishedAt: null,
2880
- isChildLoom: loom.parentLoom != null,
2881
- parentLoom: loom.parentLoom ?? null
2882
- }));
3046
+ activeJson = globalActiveLooms.map((loom) => {
3047
+ const isEpic = (loom.issueType ?? "branch") === "epic";
3048
+ const swarmIssues = isEpic && loom.childIssues && loom.childIssues.length > 0 ? enrichSwarmIssues(loom.childIssues, globalActiveLooms, finishedLooms, loom.projectPath) : isEpic ? [] : void 0;
3049
+ const depMap = isEpic ? loom.dependencyMap && Object.keys(loom.dependencyMap).length > 0 ? loom.dependencyMap : {} : void 0;
3050
+ return {
3051
+ name: loom.branchName ?? loom.worktreePath ?? "unknown",
3052
+ worktreePath: loom.worktreePath,
3053
+ branch: loom.branchName,
3054
+ type: loom.issueType ?? "branch",
3055
+ issue_numbers: loom.issue_numbers,
3056
+ pr_numbers: loom.pr_numbers,
3057
+ isMainWorktree: false,
3058
+ // Global looms from other projects are never the main worktree
3059
+ description: loom.description ?? null,
3060
+ created_at: loom.created_at ?? null,
3061
+ issueTracker: loom.issueTracker ?? null,
3062
+ colorHex: loom.colorHex ?? null,
3063
+ projectPath: loom.projectPath ?? null,
3064
+ issueUrls: loom.issueUrls ?? {},
3065
+ prUrls: loom.prUrls ?? {},
3066
+ status: "active",
3067
+ finishedAt: null,
3068
+ state: loom.state ?? null,
3069
+ isChildLoom: loom.parentLoom != null,
3070
+ parentLoom: loom.parentLoom ?? null,
3071
+ ...swarmIssues !== void 0 && { swarmIssues },
3072
+ ...depMap !== void 0 && { dependencyMap: depMap }
3073
+ };
3074
+ });
2883
3075
  } else {
2884
- activeJson = formatLoomsForJson(worktrees, mainWorktreePath, metadata).map((loom) => ({
3076
+ activeJson = formatLoomsForJson(worktrees, mainWorktreePath, metadata, allActiveMetadata, finishedLooms).map((loom) => ({
2885
3077
  ...loom,
2886
3078
  status: "active",
2887
3079
  finishedAt: null
@@ -2893,7 +3085,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2893
3085
  (loom) => loom.projectPath == null || loom.projectPath === currentProjectPath
2894
3086
  );
2895
3087
  }
2896
- let finishedJson = finishedLooms.map(formatFinishedLoomForJson);
3088
+ let finishedJson = showFinished ? finishedLooms.map((loom) => formatFinishedLoomForJson(loom, allActiveMetadata, finishedLooms)) : [];
2897
3089
  if (currentProjectPath) {
2898
3090
  finishedJson = finishedJson.filter(
2899
3091
  (loom) => loom.projectPath == null || loom.projectPath === currentProjectPath
@@ -2902,6 +3094,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2902
3094
  if (options.children) {
2903
3095
  const settingsManager = new SettingsManager();
2904
3096
  const settings = await settingsManager.loadSettings();
3097
+ const issueTracker = IssueTrackerFactory.create(settings);
2905
3098
  const activeChildrenResults = await Promise.allSettled(
2906
3099
  activeJson.map(async (loom) => {
2907
3100
  const index = activeJson.indexOf(loom);
@@ -2909,7 +3102,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2909
3102
  if (!loomMetadata) {
2910
3103
  return { index, children: null };
2911
3104
  }
2912
- const children = await assembleChildrenData(loomMetadata, metadataManager, settings);
3105
+ const children = await assembleChildrenData(loomMetadata, metadataManager, issueTracker);
2913
3106
  return { index, children };
2914
3107
  })
2915
3108
  );
@@ -2927,7 +3120,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2927
3120
  if (!loomMetadata) {
2928
3121
  return { index, children: null };
2929
3122
  }
2930
- const children = await assembleChildrenData(loomMetadata, metadataManager, settings);
3123
+ const children = await assembleChildrenData(loomMetadata, metadataManager, issueTracker);
2931
3124
  return { index, children };
2932
3125
  })
2933
3126
  );
@@ -2956,10 +3149,11 @@ program.command("list").description("Show active workspaces").option("--json", "
2956
3149
  }
2957
3150
  return;
2958
3151
  }
2959
- let textSettings = null;
3152
+ let textIssueTracker = null;
2960
3153
  if (options.children) {
2961
3154
  const settingsManager = new SettingsManager();
2962
- textSettings = await settingsManager.loadSettings();
3155
+ const textSettings = await settingsManager.loadSettings();
3156
+ textIssueTracker = IssueTrackerFactory.create(textSettings);
2963
3157
  }
2964
3158
  if (showActive && hasActive) {
2965
3159
  logger.info("Active workspaces:");
@@ -2973,14 +3167,17 @@ program.command("list").description("Show active workspaces").option("--json", "
2973
3167
  if (loom.description) {
2974
3168
  logger.info(` Description: ${loom.description}`);
2975
3169
  }
3170
+ if (loom.state) {
3171
+ logger.info(` State: ${colorizeState(loom.state)}`);
3172
+ }
2976
3173
  if (loom.worktreePath) {
2977
3174
  logger.info(` Path: ${loom.worktreePath}`);
2978
3175
  }
2979
3176
  if (loom.projectPath) {
2980
3177
  logger.info(` Project: ${loom.projectPath}`);
2981
3178
  }
2982
- if (options.children && textSettings) {
2983
- const childrenData = await assembleChildrenData(loom, metadataManager, textSettings);
3179
+ if (options.children && textIssueTracker) {
3180
+ const childrenData = await assembleChildrenData(loom, metadataManager, textIssueTracker);
2984
3181
  if (childrenData && (childrenData.summary.totalIssues > 0 || childrenData.summary.totalLooms > 0)) {
2985
3182
  logger.info(` Child Issues: ${childrenData.summary.totalIssues} (${childrenData.summary.issuesWithLooms} with active looms)`);
2986
3183
  for (const issue of childrenData.issues) {
@@ -3003,10 +3200,13 @@ program.command("list").description("Show active workspaces").option("--json", "
3003
3200
  if (loomMetadata == null ? void 0 : loomMetadata.description) {
3004
3201
  logger.info(` Description: ${loomMetadata.description}`);
3005
3202
  }
3203
+ if (loomMetadata == null ? void 0 : loomMetadata.state) {
3204
+ logger.info(` State: ${colorizeState(loomMetadata.state)}`);
3205
+ }
3006
3206
  logger.info(` Path: ${formatted.path}`);
3007
3207
  logger.info(` Commit: ${formatted.commit}`);
3008
- if (options.children && textSettings && loomMetadata) {
3009
- const childrenData = await assembleChildrenData(loomMetadata, metadataManager, textSettings);
3208
+ if (options.children && textIssueTracker && loomMetadata) {
3209
+ const childrenData = await assembleChildrenData(loomMetadata, metadataManager, textIssueTracker);
3010
3210
  if (childrenData && (childrenData.summary.totalIssues > 0 || childrenData.summary.totalLooms > 0)) {
3011
3211
  logger.info(` Child Issues: ${childrenData.summary.totalIssues} (${childrenData.summary.issuesWithLooms} with active looms)`);
3012
3212
  for (const issue of childrenData.issues) {
@@ -3033,11 +3233,14 @@ program.command("list").description("Show active workspaces").option("--json", "
3033
3233
  if (loom.description) {
3034
3234
  logger.info(` Description: ${loom.description}`);
3035
3235
  }
3236
+ if (loom.state) {
3237
+ logger.info(` State: ${colorizeState(loom.state)}`);
3238
+ }
3036
3239
  if (loom.finishedAt) {
3037
3240
  logger.info(` Finished: ${new Date(loom.finishedAt).toLocaleString()}`);
3038
3241
  }
3039
- if (options.children && textSettings) {
3040
- const childrenData = await assembleChildrenData(loom, metadataManager, textSettings);
3242
+ if (options.children && textIssueTracker) {
3243
+ const childrenData = await assembleChildrenData(loom, metadataManager, textIssueTracker);
3041
3244
  if (childrenData && (childrenData.summary.totalIssues > 0 || childrenData.summary.totalLooms > 0)) {
3042
3245
  logger.info(` Child Issues: ${childrenData.summary.totalIssues} (${childrenData.summary.issuesWithLooms} with active looms)`);
3043
3246
  for (const issue of childrenData.issues) {
@@ -3064,7 +3267,7 @@ program.command("list").description("Show active workspaces").option("--json", "
3064
3267
  });
3065
3268
  program.command("projects").description("List configured iloom projects").option("--json", "Output as JSON (default behavior)").action(async (options) => {
3066
3269
  try {
3067
- const { ProjectsCommand } = await import("./projects-LH362JZQ.js");
3270
+ const { ProjectsCommand } = await import("./projects-2UOXFLNZ.js");
3068
3271
  const command = new ProjectsCommand();
3069
3272
  const result = await command.execute(options);
3070
3273
  console.log(JSON.stringify(result, null, 2));
@@ -3073,15 +3276,17 @@ program.command("projects").description("List configured iloom projects").option
3073
3276
  process.exit(1);
3074
3277
  }
3075
3278
  });
3076
- program.command("issues").description("List project issues from configured issue tracker").argument("[project-path]", "Path to project root (auto-detected if omitted)").option("--json", "Output as JSON (default behavior)").option("--limit <n>", "Max issues to return", "100").action(async (projectPath, options) => {
3279
+ program.command("issues").description("List project issues from configured issue tracker").argument("[project-path]", "Path to project root (auto-detected if omitted)").option("--json", "Output as JSON (default behavior)").option("--limit <n>", "Max issues to return", "100").option("--sprint <name>", 'Jira only: filter by sprint name (e.g., "Sprint 17") or "current" for active sprint').option("--mine", "Show only issues and PRs assigned to me").action(async (projectPath, options) => {
3077
3280
  try {
3078
- const { IssuesCommand } = await import("./issues-PJSOLOBJ.js");
3281
+ const { IssuesCommand } = await import("./issues-T4ZZSPEG.js");
3079
3282
  const command = new IssuesCommand();
3080
3283
  const parsedLimit = parseInt((options == null ? void 0 : options.limit) ?? "100", 10);
3081
3284
  const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? 100 : parsedLimit;
3082
3285
  const result = await command.execute({
3083
3286
  ...projectPath ? { projectPath } : {},
3084
- limit
3287
+ limit,
3288
+ sprint: options == null ? void 0 : options.sprint,
3289
+ mine: options == null ? void 0 : options.mine
3085
3290
  });
3086
3291
  console.log(JSON.stringify(result, null, 2));
3087
3292
  } catch (error) {
@@ -3089,13 +3294,13 @@ program.command("issues").description("List project issues from configured issue
3089
3294
  process.exit(1);
3090
3295
  }
3091
3296
  });
3092
- program.command("init").alias("config").description("Initialize iloom configuration").argument("[prompt]", 'Custom initial message to send to Claude (defaults to "Help me configure iloom settings.")').action(async (prompt) => {
3297
+ program.command("init").alias("config").description("Initialize iloom configuration").argument("[prompt]", 'Custom initial message to send to Claude (defaults to "Help me configure iloom settings.")').addOption(new Option("--accept-defaults").hideHelp()).action(async (prompt, options) => {
3093
3298
  try {
3094
- const { InitCommand } = await import("./init-676DHF6R.js");
3299
+ const { InitCommand } = await import("./init-GFQ5W7GK.js");
3095
3300
  const command = new InitCommand();
3096
3301
  const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
3097
3302
  const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
3098
- await command.execute(customPrompt);
3303
+ await command.execute(customPrompt, options == null ? void 0 : options.acceptDefaults);
3099
3304
  } catch (error) {
3100
3305
  logger.error(`Failed to initialize: ${error instanceof Error ? error.message : "Unknown error"}`);
3101
3306
  process.exit(1);
@@ -3105,7 +3310,7 @@ program.command("plan").description("Launch interactive planning session with Ar
3105
3310
  new Option("--output-format <format>", "Output format for Claude CLI (requires --print)").choices(["json", "stream-json", "text"])
3106
3311
  ).option("--verbose", "Enable verbose output (requires --print)").option("--json", "Output final result as JSON object (requires --print)").option("--json-stream", "Stream JSONL output to stdout in real-time (requires --print)").action(async (prompt, options) => {
3107
3312
  try {
3108
- const { PlanCommand } = await import("./plan-Q7ELXDLC.js");
3313
+ const { PlanCommand } = await import("./plan-U7ZQWLFY.js");
3109
3314
  const command = new PlanCommand();
3110
3315
  if ((options == null ? void 0 : options.json) && (options == null ? void 0 : options.jsonStream)) {
3111
3316
  logger.error("--json and --json-stream are mutually exclusive");
@@ -3132,7 +3337,7 @@ program.command("plan").description("Launch interactive planning session with Ar
3132
3337
  });
3133
3338
  program.command("contribute").description("Set up local development environment for contributing to a GitHub project").argument("[repository]", "GitHub repository (owner/repo, github.com/owner/repo, or full URL). Defaults to iloom-ai/iloom-cli").action(async (repository) => {
3134
3339
  try {
3135
- const { ContributeCommand } = await import("./contribute-VDZXHK5Y.js");
3340
+ const { ContributeCommand } = await import("./contribute-ORDDQGSL.js");
3136
3341
  const command = new ContributeCommand();
3137
3342
  await command.execute(repository);
3138
3343
  } catch (error) {
@@ -3152,8 +3357,8 @@ program.command("update").description("Update iloom-cli to the latest version").
3152
3357
  });
3153
3358
  program.command("test-github").description("Test GitHub integration (Issue #3)").argument("<identifier>", "Issue number or PR number").option("--no-claude", "Skip Claude for branch name generation").action(async (identifier, options) => {
3154
3359
  try {
3155
- const { GitHubService: GitHubService2 } = await import("./GitHubService-TGWJN4V4.js");
3156
- const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-K6XNWQ6C.js");
3360
+ const { GitHubService: GitHubService2 } = await import("./GitHubService-MEHKHUQP.js");
3361
+ const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-ECJHBB67.js");
3157
3362
  logger.info("Testing GitHub Integration\n");
3158
3363
  const service = new GitHubService2();
3159
3364
  const branchNaming = new DefaultBranchNamingService2({ useClaude: options.claude !== false });
@@ -3211,10 +3416,10 @@ program.command("test-github").description("Test GitHub integration (Issue #3)")
3211
3416
  });
3212
3417
  program.command("test-claude").description("Test Claude integration (Issue #10)").option("--detect", "Test Claude CLI detection").option("--version", "Get Claude CLI version").option("--branch <title>", "Test branch name generation with given title").option("--issue <number>", "Issue number for branch generation", "123").option("--launch <prompt>", "Launch Claude with a prompt (headless)").option("--interactive", "Launch Claude interactively (requires --launch)").option("--template <name>", "Test template loading").action(async (options) => {
3213
3418
  try {
3214
- const { detectClaudeCli, getClaudeVersion, generateBranchName, launchClaude } = await import("./claude-TP2QO3BU.js");
3215
- const { PromptTemplateManager } = await import("./PromptTemplateManager-36YLQRHP.js");
3216
- const { ClaudeService } = await import("./ClaudeService-TK7FMC2X.js");
3217
- const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-HR5JQKAI.js");
3419
+ const { detectClaudeCli, getClaudeVersion, generateBranchName, launchClaude } = await import("./claude-P3NQR6IJ.js");
3420
+ const { PromptTemplateManager } = await import("./PromptTemplateManager-DULSVRRE.js");
3421
+ const { ClaudeService } = await import("./ClaudeService-NJNK2SUH.js");
3422
+ const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-QXX6ZFST.js");
3218
3423
  logger.info("Testing Claude Integration\n");
3219
3424
  if (options.detect) {
3220
3425
  logger.info("Detecting Claude CLI...");
@@ -3349,7 +3554,7 @@ program.command("test-claude").description("Test Claude integration (Issue #10)"
3349
3554
  });
3350
3555
  program.command("test-webserver").description("Test if a web server is running on a workspace port").argument("<issue-number>", "Issue number (port will be calculated as 3000 + issue number)", parseInt).option("--kill", "Kill the web server if detected").action(async (issueNumber, options) => {
3351
3556
  try {
3352
- const { TestWebserverCommand } = await import("./test-webserver-OK6Z5FJM.js");
3557
+ const { TestWebserverCommand } = await import("./test-webserver-EONCG7E7.js");
3353
3558
  const command = new TestWebserverCommand();
3354
3559
  await command.execute({ issueNumber, options });
3355
3560
  } catch (error) {
@@ -3362,7 +3567,7 @@ program.command("test-webserver").description("Test if a web server is running o
3362
3567
  });
3363
3568
  program.command("test-git").description("Test Git integration - findMainWorktreePath() function (reads .iloom/settings.json)").action(async () => {
3364
3569
  try {
3365
- const { TestGitCommand } = await import("./test-git-M7LSLEFL.js");
3570
+ const { TestGitCommand } = await import("./test-git-BTAOIUE2.js");
3366
3571
  const command = new TestGitCommand();
3367
3572
  await command.execute();
3368
3573
  } catch (error) {
@@ -3388,7 +3593,7 @@ program.command("test-tabs").description("Test iTerm2 dual tab functionality - o
3388
3593
  });
3389
3594
  program.command("test-prefix").description("Test worktree prefix configuration - preview worktree paths (reads .iloom/settings.json)").action(async () => {
3390
3595
  try {
3391
- const { TestPrefixCommand } = await import("./test-prefix-64NAAUON.js");
3596
+ const { TestPrefixCommand } = await import("./test-prefix-Q6TFSU6F.js");
3392
3597
  const command = new TestPrefixCommand();
3393
3598
  await command.execute();
3394
3599
  } catch (error) {
@@ -3402,7 +3607,7 @@ program.command("test-prefix").description("Test worktree prefix configuration -
3402
3607
  program.command("summary").description("Generate Claude session summary for a loom").argument("[identifier]", "Issue number, PR number (pr/123), or branch name (auto-detected if omitted)").option("--with-comment", "Post summary as a comment to the issue/PR").option("--json", "Output result as JSON").action(async (identifier, options) => {
3403
3608
  const executeAction = async () => {
3404
3609
  try {
3405
- const { SummaryCommand } = await import("./summary-G2T4452H.js");
3610
+ const { SummaryCommand } = await import("./summary-FWHAX55O.js");
3406
3611
  const command = new SummaryCommand();
3407
3612
  const result = await command.execute({ identifier, options });
3408
3613
  if (options.json && result) {
@@ -3431,7 +3636,7 @@ program.command("summary").description("Generate Claude session summary for a lo
3431
3636
  program.command("recap").description("Get recap for a loom (defaults to current directory)").argument("[identifier]", "Issue number, PR number (pr/123), or branch name (auto-detected if omitted)").option("--json", "Output as JSON with filePath for file watching").action(async (identifier, options) => {
3432
3637
  const executeAction = async () => {
3433
3638
  try {
3434
- const { RecapCommand } = await import("./recap-3W7COH7D.js");
3639
+ const { RecapCommand } = await import("./recap-MX63HAKV.js");
3435
3640
  const command = new RecapCommand();
3436
3641
  const result = await command.execute({ identifier, json: options.json });
3437
3642
  if (options.json && result) {
@@ -3457,16 +3662,62 @@ program.command("recap").description("Get recap for a loom (defaults to current
3457
3662
  await executeAction();
3458
3663
  }
3459
3664
  });
3665
+ var testJiraCommand = program.command("test-jira").description("Test Jira integration methods against a real Jira instance");
3666
+ testJiraCommand.command("child-issue").description("Create a test child issue under a parent").argument("<parentKey>", "Parent issue key (e.g., PROJ-123)").action(async (parentKey) => {
3667
+ try {
3668
+ const { TestJiraCommand } = await import("./test-jira-CHYNV33F.js");
3669
+ await new TestJiraCommand().createChildIssue(parentKey);
3670
+ } catch (error) {
3671
+ logger.error(`Failed: ${error instanceof Error ? error.message : "Unknown error"}`);
3672
+ process.exit(1);
3673
+ }
3674
+ });
3675
+ testJiraCommand.command("create-dep").description('Create a "Blocks" dependency between two issues').argument("<blockingKey>", "Issue key that blocks (e.g., PROJ-100)").argument("<blockedKey>", "Issue key being blocked (e.g., PROJ-200)").action(async (blockingKey, blockedKey) => {
3676
+ try {
3677
+ const { TestJiraCommand } = await import("./test-jira-CHYNV33F.js");
3678
+ await new TestJiraCommand().createDependency(blockingKey, blockedKey);
3679
+ } catch (error) {
3680
+ logger.error(`Failed: ${error instanceof Error ? error.message : "Unknown error"}`);
3681
+ process.exit(1);
3682
+ }
3683
+ });
3684
+ testJiraCommand.command("get-deps").description("Fetch and print dependencies for an issue").argument("<issueKey>", "Issue key (e.g., PROJ-123)").action(async (issueKey) => {
3685
+ try {
3686
+ const { TestJiraCommand } = await import("./test-jira-CHYNV33F.js");
3687
+ await new TestJiraCommand().getDependencies(issueKey);
3688
+ } catch (error) {
3689
+ logger.error(`Failed: ${error instanceof Error ? error.message : "Unknown error"}`);
3690
+ process.exit(1);
3691
+ }
3692
+ });
3693
+ testJiraCommand.command("remove-dep").description('Remove a "Blocks" dependency between two issues').argument("<blockingKey>", "Issue key that blocks (e.g., PROJ-100)").argument("<blockedKey>", "Issue key being blocked (e.g., PROJ-200)").action(async (blockingKey, blockedKey) => {
3694
+ try {
3695
+ const { TestJiraCommand } = await import("./test-jira-CHYNV33F.js");
3696
+ await new TestJiraCommand().removeDependency(blockingKey, blockedKey);
3697
+ } catch (error) {
3698
+ logger.error(`Failed: ${error instanceof Error ? error.message : "Unknown error"}`);
3699
+ process.exit(1);
3700
+ }
3701
+ });
3702
+ testJiraCommand.command("get-children").description("List child issues of a parent").argument("<issueKey>", "Parent issue key (e.g., PROJ-123)").action(async (issueKey) => {
3703
+ try {
3704
+ const { TestJiraCommand } = await import("./test-jira-CHYNV33F.js");
3705
+ await new TestJiraCommand().getChildIssues(issueKey);
3706
+ } catch (error) {
3707
+ logger.error(`Failed: ${error instanceof Error ? error.message : "Unknown error"}`);
3708
+ process.exit(1);
3709
+ }
3710
+ });
3460
3711
  program.command("test-neon").description("Test Neon integration and debug configuration").action(async () => {
3461
- var _a;
3712
+ var _a2;
3462
3713
  try {
3463
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-AW3JTJHD.js");
3464
- const { createNeonProviderFromSettings: createNeonProviderFromSettings2 } = await import("./neon-helpers-VVFFTLXE.js");
3714
+ const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-BQDQA3FK.js");
3715
+ const { createNeonProviderFromSettings: createNeonProviderFromSettings2 } = await import("./neon-helpers-CQN2PB4S.js");
3465
3716
  logger.info("Testing Neon Integration\n");
3466
3717
  logger.info("1. Settings Configuration:");
3467
3718
  const settingsManager = new SettingsManager2();
3468
3719
  const settings = await settingsManager.loadSettings();
3469
- const neonConfig = (_a = settings.databaseProviders) == null ? void 0 : _a.neon;
3720
+ const neonConfig = (_a2 = settings.databaseProviders) == null ? void 0 : _a2.neon;
3470
3721
  logger.info(` projectId: ${(neonConfig == null ? void 0 : neonConfig.projectId) ?? "(not configured)"}`);
3471
3722
  logger.info(` parentBranch: ${(neonConfig == null ? void 0 : neonConfig.parentBranch) ?? "(not configured)"}`);
3472
3723
  logger.info("\n2. Creating NeonProvider...");
@@ -3525,6 +3776,23 @@ program.command("test-neon").description("Test Neon integration and debug config
3525
3776
  process.exit(1);
3526
3777
  }
3527
3778
  });
3779
+ var telemetryCmd = program.command("telemetry").description("Manage anonymous usage telemetry");
3780
+ telemetryCmd.command("off").description("Disable anonymous usage telemetry").action(async () => {
3781
+ const manager = new TelemetryManager();
3782
+ manager.disable();
3783
+ logger.info("Telemetry disabled. No usage data will be collected.");
3784
+ });
3785
+ telemetryCmd.command("on").description("Enable anonymous usage telemetry").action(async () => {
3786
+ const manager = new TelemetryManager();
3787
+ manager.enable();
3788
+ logger.info("Telemetry enabled. Anonymous usage data will be collected to improve iloom.");
3789
+ });
3790
+ telemetryCmd.command("status").description("Show current telemetry status").action(async () => {
3791
+ const manager = new TelemetryManager();
3792
+ const status = manager.getStatus();
3793
+ logger.info(`Telemetry: ${status.enabled ? "enabled" : "disabled"}`);
3794
+ logger.info(`Anonymous ID: ${status.distinctId}`);
3795
+ });
3528
3796
  program.command("help").description("Display help information").argument("[command]", "Show help for specific command").action(async (command) => {
3529
3797
  if (command) {
3530
3798
  const subCommand = program.commands.find((cmd) => cmd.name() === command);
@@ -3541,24 +3809,45 @@ program.command("help").description("Display help information").argument("[comma
3541
3809
  });
3542
3810
  var isRunDirectly = process.argv[1] && (() => {
3543
3811
  try {
3544
- const scriptPath = realpathSync(process.argv[1]);
3812
+ const scriptPath = realpathSync2(process.argv[1]);
3545
3813
  const modulePath = fileURLToPath2(import.meta.url);
3546
3814
  return scriptPath === modulePath;
3547
3815
  } catch {
3548
3816
  return true;
3549
3817
  }
3550
3818
  })();
3819
+ var _a;
3551
3820
  if (isRunDirectly) {
3552
3821
  try {
3553
3822
  await program.parseAsync();
3823
+ try {
3824
+ await TelemetryService.getInstance().shutdown();
3825
+ } catch (shutdownError) {
3826
+ logger.debug(`Telemetry shutdown: ${shutdownError instanceof Error ? shutdownError.message : String(shutdownError)}`);
3827
+ }
3554
3828
  } catch (error) {
3829
+ try {
3830
+ const commandName = ((_a = program.args) == null ? void 0 : _a[0]) ?? "unknown";
3831
+ TelemetryService.getInstance().track("error.occurred", {
3832
+ error_type: error instanceof Error ? error.constructor.name : "Unknown",
3833
+ command: commandName,
3834
+ phase: "execution"
3835
+ });
3836
+ await TelemetryService.getInstance().shutdown();
3837
+ } catch (telemetryError) {
3838
+ logger.debug(`Telemetry error tracking: ${telemetryError instanceof Error ? telemetryError.message : String(telemetryError)}`);
3839
+ }
3555
3840
  if (error instanceof Error) {
3556
3841
  logger.error(`Error: ${error.message}`);
3557
3842
  process.exit(1);
3843
+ } else {
3844
+ logger.error(`Error: ${String(error)}`);
3845
+ process.exit(1);
3558
3846
  }
3559
3847
  }
3560
3848
  }
3561
3849
  export {
3850
+ handleTelemetryLifecycle,
3562
3851
  validateGhCliForCommand,
3563
3852
  validateIdeForStartCommand
3564
3853
  };