@iloom/cli 0.9.1 → 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 (222) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +179 -41
  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-O7T6CFAJ.js → GitHubService-MEHKHUQP.js} +4 -4
  7. package/dist/IssueTrackerFactory-NG53YX5S.js +14 -0
  8. package/dist/{LoomLauncher-3I47SUPV.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 +179 -41
  13. package/dist/{SettingsManager-QR7V2IW2.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-IC4CJRMP.js → build-5GO3XW26.js} +9 -9
  23. package/dist/{chunk-USSL2X4A.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-2JPXGGP4.js → chunk-5MWV33NN.js} +4 -4
  29. package/dist/{chunk-POU2UMWN.js → chunk-6EU6TCF6.js} +10 -10
  30. package/dist/chunk-6EU6TCF6.js.map +1 -0
  31. package/dist/{chunk-Y5O2ALDZ.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-OK7LUTRW.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-Y5HSSIK2.js → chunk-KXDRI47U.js} +71 -13
  41. package/dist/chunk-KXDRI47U.js.map +1 -0
  42. package/dist/{chunk-HZXBHMVM.js → chunk-LXLMMXXY.js} +54 -14
  43. package/dist/chunk-LXLMMXXY.js.map +1 -0
  44. package/dist/{chunk-H6ST2TGP.js → chunk-MNHZB4Z2.js} +4 -4
  45. package/dist/{chunk-TL72BGP6.js → chunk-MORRVYPT.js} +2 -2
  46. package/dist/{chunk-TGRK3CHF.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-OAVJR4PM.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-MZPRBNYC.js → chunk-SN3SQCFK.js} +10 -8
  60. package/dist/{chunk-MZPRBNYC.js.map → chunk-SN3SQCFK.js.map} +1 -1
  61. package/dist/{chunk-4ZIHFUPN.js → chunk-UD3WJDIV.js} +145 -107
  62. package/dist/chunk-UD3WJDIV.js.map +1 -0
  63. package/dist/{chunk-3P6J4IZZ.js → chunk-UKBAJ2QQ.js} +61 -7
  64. package/dist/chunk-UKBAJ2QQ.js.map +1 -0
  65. package/dist/{chunk-RD7OPXZK.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-JT5LZRMI.js → chunk-VECNX6VX.js} +2 -2
  69. package/dist/{chunk-TRUMP4DA.js → chunk-VG45TUYK.js} +75 -6
  70. package/dist/chunk-VG45TUYK.js.map +1 -0
  71. package/dist/{chunk-4GAJJUYS.js → chunk-VGGST52X.js} +2 -2
  72. package/dist/{chunk-4LKGCFGG.js → chunk-WWKOVDWC.js} +2 -2
  73. package/dist/{chunk-2HZX6AMR.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-XFEK2X2D.js → chunk-YYAKPQBT.js} +73 -20
  80. package/dist/chunk-YYAKPQBT.js.map +1 -0
  81. package/dist/{chunk-NTTSUAVM.js → chunk-ZEWU5PZK.js} +2 -2
  82. package/dist/{chunk-5LVVQGB3.js → chunk-ZHPNZC75.js} +17 -17
  83. package/dist/chunk-ZHPNZC75.js.map +1 -0
  84. package/dist/{chunk-I3HMNWQQ.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-D3CSRBBZ.js → cleanup-6UCPVMFG.js} +81 -32
  88. package/dist/cleanup-6UCPVMFG.js.map +1 -0
  89. package/dist/cli.js +640 -350
  90. package/dist/cli.js.map +1 -1
  91. package/dist/{commit-IWGT42XN.js → commit-L3EPY5QG.js} +23 -21
  92. package/dist/commit-L3EPY5QG.js.map +1 -0
  93. package/dist/{compile-EOWJORKO.js → compile-ZS4HYRX5.js} +9 -9
  94. package/dist/{contribute-WSJTV2RX.js → contribute-ORDDQGSL.js} +14 -6
  95. package/dist/contribute-ORDDQGSL.js.map +1 -0
  96. package/dist/{dev-server-Q6M62ATG.js → dev-server-FYZ2AQIH.js} +29 -15
  97. package/dist/dev-server-FYZ2AQIH.js.map +1 -0
  98. package/dist/{feedback-QPNDZQRV.js → feedback-TMBXSCM5.js} +15 -15
  99. package/dist/{git-W3XUIFTR.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 +397 -53
  104. package/dist/index.js +1178 -40
  105. package/dist/index.js.map +1 -1
  106. package/dist/{init-ALYWKNWG.js → init-GFQ5W7GK.js} +57 -21
  107. package/dist/init-GFQ5W7GK.js.map +1 -0
  108. package/dist/issues-T4ZZSPEG.js +179 -0
  109. package/dist/issues-T4ZZSPEG.js.map +1 -0
  110. package/dist/{lint-IHUH45OC.js → lint-6TQXDZ3T.js} +9 -9
  111. package/dist/mcp/issue-management-server.js +2472 -257
  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-KWOV2OFO.js → open-5QZGXQRF.js} +15 -15
  118. package/dist/open-5QZGXQRF.js.map +1 -0
  119. package/dist/{plan-BRJBFJHF.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 +386 -47
  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-AJOJOZUG.js → rebase-DWIB77KV.js} +10 -10
  131. package/dist/{recap-GKJXMDXW.js → recap-MX63HAKV.js} +47 -19
  132. package/dist/recap-MX63HAKV.js.map +1 -0
  133. package/dist/{run-QEUVZF7J.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 +130 -15
  137. package/dist/{shell-DAAVG4YN.js → shell-G6VC2CYR.js} +14 -7
  138. package/dist/shell-G6VC2CYR.js.map +1 -0
  139. package/dist/{summary-ZKOA35PT.js → summary-FWHAX55O.js} +27 -25
  140. package/dist/summary-FWHAX55O.js.map +1 -0
  141. package/dist/{test-5GPWWO3P.js → test-F7JNJZYP.js} +9 -9
  142. package/dist/{test-git-EJUKDB7F.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-23TOBUXY.js → test-prefix-Q6TFSU6F.js} +4 -4
  146. package/dist/{test-webserver-CKROHFBQ.js → test-webserver-EONCG7E7.js} +6 -6
  147. package/dist/{vscode-6TOLFCI2.js → vscode-VA5X4P25.js} +7 -7
  148. package/package.json +5 -1
  149. package/dist/ClaudeContextManager-X2Y72GRL.js +0 -14
  150. package/dist/ClaudeService-7P32TTES.js +0 -13
  151. package/dist/chunk-2HZX6AMR.js.map +0 -1
  152. package/dist/chunk-3P6J4IZZ.js.map +0 -1
  153. package/dist/chunk-4ZIHFUPN.js.map +0 -1
  154. package/dist/chunk-5LVVQGB3.js.map +0 -1
  155. package/dist/chunk-B7U6OKUR.js.map +0 -1
  156. package/dist/chunk-ENGCJIYQ.js +0 -520
  157. package/dist/chunk-ENGCJIYQ.js.map +0 -1
  158. package/dist/chunk-FO5GGFOV.js.map +0 -1
  159. package/dist/chunk-HZXBHMVM.js.map +0 -1
  160. package/dist/chunk-I3HMNWQQ.js.map +0 -1
  161. package/dist/chunk-J7FJ6PUT.js +0 -121
  162. package/dist/chunk-J7FJ6PUT.js.map +0 -1
  163. package/dist/chunk-KBEIQP4G.js.map +0 -1
  164. package/dist/chunk-OAVJR4PM.js.map +0 -1
  165. package/dist/chunk-OK7LUTRW.js.map +0 -1
  166. package/dist/chunk-POU2UMWN.js.map +0 -1
  167. package/dist/chunk-QN47QVBX.js.map +0 -1
  168. package/dist/chunk-TGRK3CHF.js.map +0 -1
  169. package/dist/chunk-TRUMP4DA.js.map +0 -1
  170. package/dist/chunk-VOGGLPG5.js.map +0 -1
  171. package/dist/chunk-XFEK2X2D.js.map +0 -1
  172. package/dist/chunk-Y5HSSIK2.js.map +0 -1
  173. package/dist/chunk-Y5O2ALDZ.js.map +0 -1
  174. package/dist/cleanup-D3CSRBBZ.js.map +0 -1
  175. package/dist/commit-IWGT42XN.js.map +0 -1
  176. package/dist/contribute-WSJTV2RX.js.map +0 -1
  177. package/dist/dev-server-Q6M62ATG.js.map +0 -1
  178. package/dist/ignite-OPO6EDYT.js +0 -784
  179. package/dist/ignite-OPO6EDYT.js.map +0 -1
  180. package/dist/init-ALYWKNWG.js.map +0 -1
  181. package/dist/issues-L7TBUPXT.js +0 -116
  182. package/dist/issues-L7TBUPXT.js.map +0 -1
  183. package/dist/open-KWOV2OFO.js.map +0 -1
  184. package/dist/plan-BRJBFJHF.js.map +0 -1
  185. package/dist/recap-GKJXMDXW.js.map +0 -1
  186. package/dist/run-QEUVZF7J.js.map +0 -1
  187. package/dist/shell-DAAVG4YN.js.map +0 -1
  188. package/dist/summary-ZKOA35PT.js.map +0 -1
  189. /package/dist/{BranchNamingService-K6XNWQ6C.js.map → BranchNamingService-ECJHBB67.js.map} +0 -0
  190. /package/dist/{ClaudeContextManager-X2Y72GRL.js.map → ClaudeContextManager-QXX6ZFST.js.map} +0 -0
  191. /package/dist/{ClaudeService-7P32TTES.js.map → ClaudeService-NJNK2SUH.js.map} +0 -0
  192. /package/dist/{GitHubService-O7T6CFAJ.js.map → GitHubService-MEHKHUQP.js.map} +0 -0
  193. /package/dist/{MetadataManager-W3C54UYT.js.map → IssueTrackerFactory-NG53YX5S.js.map} +0 -0
  194. /package/dist/{LoomLauncher-3I47SUPV.js.map → LoomLauncher-L64HHS3T.js.map} +0 -0
  195. /package/dist/{ProjectCapabilityDetector-N5L7T4IY.js.map → MetadataManager-5QZSTKNN.js.map} +0 -0
  196. /package/dist/{PromptTemplateManager-36YLQRHP.js.map → ProjectCapabilityDetector-5KSYUTBJ.js.map} +0 -0
  197. /package/dist/{SettingsManager-QR7V2IW2.js.map → PromptTemplateManager-DULSVRRE.js.map} +0 -0
  198. /package/dist/{claude-TP2QO3BU.js.map → SettingsManager-BQDQA3FK.js.map} +0 -0
  199. /package/dist/{build-IC4CJRMP.js.map → build-5GO3XW26.js.map} +0 -0
  200. /package/dist/{chunk-USSL2X4A.js.map → chunk-3D7WQM7I.js.map} +0 -0
  201. /package/dist/{chunk-2JPXGGP4.js.map → chunk-5MWV33NN.js.map} +0 -0
  202. /package/dist/{chunk-KAYXR544.js.map → chunk-J5S7DFYC.js.map} +0 -0
  203. /package/dist/{chunk-H6ST2TGP.js.map → chunk-MNHZB4Z2.js.map} +0 -0
  204. /package/dist/{chunk-TL72BGP6.js.map → chunk-MORRVYPT.js.map} +0 -0
  205. /package/dist/{chunk-7ZEHSSUP.js.map → chunk-P4O6EH46.js.map} +0 -0
  206. /package/dist/{chunk-RD7OPXZK.js.map → chunk-UVD4CZKS.js.map} +0 -0
  207. /package/dist/{chunk-JT5LZRMI.js.map → chunk-VECNX6VX.js.map} +0 -0
  208. /package/dist/{chunk-4GAJJUYS.js.map → chunk-VGGST52X.js.map} +0 -0
  209. /package/dist/{chunk-4LKGCFGG.js.map → chunk-WWKOVDWC.js.map} +0 -0
  210. /package/dist/{chunk-NTTSUAVM.js.map → chunk-ZEWU5PZK.js.map} +0 -0
  211. /package/dist/{git-W3XUIFTR.js.map → claude-P3NQR6IJ.js.map} +0 -0
  212. /package/dist/{compile-EOWJORKO.js.map → compile-ZS4HYRX5.js.map} +0 -0
  213. /package/dist/{feedback-QPNDZQRV.js.map → feedback-TMBXSCM5.js.map} +0 -0
  214. /package/dist/{neon-helpers-VVFFTLXE.js.map → git-ET64COO3.js.map} +0 -0
  215. /package/dist/{lint-IHUH45OC.js.map → lint-6TQXDZ3T.js.map} +0 -0
  216. /package/dist/{projects-LH362JZQ.js.map → projects-2UOXFLNZ.js.map} +0 -0
  217. /package/dist/{rebase-AJOJOZUG.js.map → rebase-DWIB77KV.js.map} +0 -0
  218. /package/dist/{test-5GPWWO3P.js.map → test-F7JNJZYP.js.map} +0 -0
  219. /package/dist/{test-git-EJUKDB7F.js.map → test-git-BTAOIUE2.js.map} +0 -0
  220. /package/dist/{test-prefix-23TOBUXY.js.map → test-prefix-Q6TFSU6F.js.map} +0 -0
  221. /package/dist/{test-webserver-CKROHFBQ.js.map → test-webserver-EONCG7E7.js.map} +0 -0
  222. /package/dist/{vscode-6TOLFCI2.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-POU2UMWN.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-4ZIHFUPN.js";
12
+ } from "./chunk-UD3WJDIV.js";
13
13
  import {
14
14
  PRManager
15
- } from "./chunk-I3HMNWQQ.js";
15
+ } from "./chunk-ZW2LKWWE.js";
16
+ import "./chunk-Y4YZTHZE.js";
16
17
  import {
17
18
  launchFirstRunSetup,
18
19
  needsFirstRunSetup
19
- } from "./chunk-RD7OPXZK.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-HZXBHMVM.js";
29
+ } from "./chunk-LXLMMXXY.js";
24
30
  import {
25
- IssueTrackerFactory
26
- } from "./chunk-3P6J4IZZ.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-NTTSUAVM.js";
30
- import "./chunk-USSL2X4A.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-2HZX6AMR.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-JT5LZRMI.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-Y5O2ALDZ.js";
46
- import "./chunk-J7FJ6PUT.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-5LVVQGB3.js";
58
- import {
59
- IssueManagementProviderFactory
60
- } from "./chunk-OK7LUTRW.js";
61
- import {
62
- getLinearChildIssues
63
- } from "./chunk-ENGCJIYQ.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-4GAJJUYS.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-OAVJR4PM.js";
82
- import "./chunk-MZPRBNYC.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-H6ST2TGP.js";
113
+ } from "./chunk-MNHZB4Z2.js";
107
114
  import {
108
115
  SettingsManager
109
- } from "./chunk-XFEK2X2D.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-Y5HSSIK2.js";
126
+ } from "./chunk-KXDRI47U.js";
127
+ import "./chunk-VG45TUYK.js";
116
128
  import {
117
- getSubIssues
118
- } from "./chunk-TRUMP4DA.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,12 +275,63 @@ var StartCommand = class {
268
275
  parsed.type = "issue";
269
276
  parsed.number = result.number;
270
277
  }
271
- if (input.options.oneShot === "bypassPermissions") {
272
- if (isJsonMode) {
273
- throw new Error("JSON mode does not support bypassPermissions confirmation prompt");
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
+ }
274
331
  }
275
- const { promptConfirmation: promptConfirmation2 } = await import("./prompt-ONNPSNKM.js");
276
- const confirmed = await promptConfirmation2(
332
+ }
333
+ if (input.options.oneShot === "bypassPermissions" && input.options.claude !== false && !isJsonMode) {
334
+ const confirmed = await promptConfirmation(
277
335
  "WARNING: bypassPermissions mode will allow Claude to execute all tool calls without confirmation. This can be dangerous. Do you want to proceed?"
278
336
  );
279
337
  if (!confirmed) {
@@ -283,7 +341,7 @@ var StartCommand = class {
283
341
  }
284
342
  const cliOverrides = extractSettingsOverrides();
285
343
  const settings = await this.settingsManager.loadSettings(void 0, cliOverrides);
286
- const workflowType = parsed.type === "branch" ? "regular" : parsed.type;
344
+ const workflowType = parsed.type === "branch" ? "regular" : parsed.type === "epic" ? "issue" : parsed.type;
287
345
  const workflowConfig = (_b = settings.workflows) == null ? void 0 : _b[workflowType];
288
346
  const { extractRawSetArguments, getExecutablePath } = await import("./cli-overrides-XFZWY7CM.js");
289
347
  const setArguments = extractRawSetArguments();
@@ -312,10 +370,27 @@ var StartCommand = class {
312
370
  enableTerminal,
313
371
  ...input.options.oneShot && { oneShot: input.options.oneShot },
314
372
  ...setArguments.length > 0 && { setArguments },
315
- ...executablePath && { executablePath }
373
+ ...executablePath && { executablePath },
374
+ ...childIssueNumbers.length > 0 && { childIssueNumbers },
375
+ ...childIssues.length > 0 && { childIssues },
376
+ ...Object.keys(dependencyMap).length > 0 && { dependencyMap }
316
377
  }
317
378
  });
318
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
+ }
319
394
  getLogger().info(` Branch: ${loom.branch}`);
320
395
  if ((_c = loom.capabilities) == null ? void 0 : _c.includes("web")) {
321
396
  getLogger().info(` Port: ${loom.port}`);
@@ -323,6 +398,9 @@ var StartCommand = class {
323
398
  if ((_d = loom.issueData) == null ? void 0 : _d.title) {
324
399
  getLogger().info(` Title: ${loom.issueData.title}`);
325
400
  }
401
+ if (parsed.type === "epic") {
402
+ getLogger().info(` Epic: yes (${childIssueNumbers.length} child issue(s))`);
403
+ }
326
404
  if (isJsonMode) {
327
405
  return {
328
406
  id: loom.id,
@@ -332,7 +410,8 @@ var StartCommand = class {
332
410
  identifier: loom.identifier,
333
411
  ...loom.port !== void 0 && { port: loom.port },
334
412
  ...((_e = loom.issueData) == null ? void 0 : _e.title) && { title: loom.issueData.title },
335
- ...loom.capabilities && { capabilities: loom.capabilities }
413
+ ...loom.capabilities && { capabilities: loom.capabilities },
414
+ ...childIssueNumbers.length > 0 && { childIssueNumbers }
336
415
  };
337
416
  }
338
417
  } catch (error) {
@@ -370,7 +449,7 @@ var StartCommand = class {
370
449
  };
371
450
  }
372
451
  const identifierMatch = matchIssueIdentifier(trimmedIdentifier);
373
- if (identifierMatch.type === "linear" && identifierMatch.identifier) {
452
+ if (identifierMatch.type === "project-key" && identifierMatch.identifier) {
374
453
  const detection = await this.issueTracker.detectInputType(
375
454
  trimmedIdentifier,
376
455
  repo
@@ -379,12 +458,12 @@ var StartCommand = class {
379
458
  return {
380
459
  type: "issue",
381
460
  number: detection.identifier,
382
- // Keep as string for Linear
461
+ // Keep as string for project key identifiers
383
462
  originalInput: trimmedIdentifier
384
463
  };
385
464
  }
386
465
  throw new Error(
387
- `Could not find Linear issue ${identifierMatch.identifier}`
466
+ `Could not find issue matching identifier ${identifierMatch.identifier}`
388
467
  );
389
468
  }
390
469
  if (identifierMatch.type === "numeric" && identifierMatch.identifier) {
@@ -501,6 +580,8 @@ var StartCommand = class {
501
580
  return `PR #${parsed.number}`;
502
581
  case "issue":
503
582
  return `Issue #${parsed.number}`;
583
+ case "epic":
584
+ return `Epic #${parsed.number}`;
504
585
  case "branch":
505
586
  return `Branch '${parsed.branchName}'`;
506
587
  case "description":
@@ -591,7 +672,10 @@ var AddIssueCommand = class {
591
672
  }
592
673
  throw new Error("Description is required and must be more than 30 characters with at least 3 words");
593
674
  }
594
- 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);
595
679
  const result = await this.enhancementService.createEnhancedIssue(
596
680
  description,
597
681
  issueBody,
@@ -750,17 +834,17 @@ var FinishCommand = class {
750
834
  * Lazy initialization of ResourceCleanup with properly configured DatabaseManager
751
835
  */
752
836
  async ensureResourceCleanup() {
753
- var _a, _b;
837
+ var _a2, _b;
754
838
  if (this.resourceCleanup && this.loomManager) {
755
839
  return;
756
840
  }
757
841
  const settings = await this.settingsManager.loadSettings();
758
- 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";
759
843
  const environmentManager = new EnvironmentManager();
760
844
  const neonProvider = createNeonProviderFromSettings(settings);
761
845
  const databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName);
762
846
  const cliIsolationManager = new CLIIsolationManager();
763
- const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-K6XNWQ6C.js");
847
+ const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-ECJHBB67.js");
764
848
  this.loomManager ??= new LoomManager(
765
849
  this.gitWorktreeManager,
766
850
  this.issueTracker,
@@ -818,7 +902,7 @@ var FinishCommand = class {
818
902
  * Main entry point for finish command
819
903
  */
820
904
  async execute(input) {
821
- var _a, _b, _c, _d;
905
+ var _a2, _b, _c, _d, _e;
822
906
  process.env.ILOOM = "1";
823
907
  const isJsonMode = input.options.json === true;
824
908
  const result = {
@@ -830,7 +914,7 @@ var FinishCommand = class {
830
914
  };
831
915
  if (isJsonMode) {
832
916
  const settings2 = await this.settingsManager.loadSettings();
833
- 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) {
834
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>');
835
919
  }
836
920
  }
@@ -851,6 +935,14 @@ var FinishCommand = class {
851
935
  if (!worktree) {
852
936
  throw new Error("No worktree found");
853
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
+ }
854
946
  if (parsed.type === "pr") {
855
947
  if (!parsed.number) {
856
948
  throw new Error("Invalid PR number");
@@ -864,6 +956,15 @@ var FinishCommand = class {
864
956
  await this.executeIssueWorkflow(parsed, input.options, worktree, result);
865
957
  }
866
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
+ }
867
968
  if (isJsonMode) {
868
969
  return result;
869
970
  }
@@ -891,6 +992,7 @@ var FinishCommand = class {
891
992
  * (No GitHub API calls - uses IdentifierParser)
892
993
  */
893
994
  async parseExplicitInput(identifier) {
995
+ var _a2;
894
996
  const prPattern = /^(?:pr|PR)[/-](\d+)$/;
895
997
  const prMatch = identifier.match(prPattern);
896
998
  if (prMatch == null ? void 0 : prMatch[1]) {
@@ -916,6 +1018,18 @@ var FinishCommand = class {
916
1018
  if (parsed.branchName !== void 0) {
917
1019
  result.branchName = parsed.branchName;
918
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
+ }
919
1033
  return result;
920
1034
  }
921
1035
  /**
@@ -923,6 +1037,7 @@ var FinishCommand = class {
923
1037
  * Ports logic from merge-current-issue.sh lines 30-52
924
1038
  */
925
1039
  async autoDetectFromCurrentDirectory() {
1040
+ var _a2, _b;
926
1041
  const currentDir = path2.basename(process.cwd());
927
1042
  const prPattern = /_pr_(\d+)$/;
928
1043
  const prMatch = currentDir.match(prPattern);
@@ -936,14 +1051,18 @@ var FinishCommand = class {
936
1051
  autoDetected: true
937
1052
  };
938
1053
  }
1054
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-5QZSTKNN.js");
1055
+ const metadataManager = new MetadataManager2();
1056
+ const metadata = await metadataManager.readMetadata(process.cwd());
939
1057
  const issueNumber = extractIssueNumber(currentDir);
940
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;
941
1060
  getLogger().debug(
942
- `Auto-detected issue #${issueNumber} from directory: ${currentDir}`
1061
+ `Auto-detected issue #${originalIssueKey} from directory: ${currentDir}`
943
1062
  );
944
1063
  return {
945
1064
  type: "issue",
946
- number: issueNumber,
1065
+ number: originalIssueKey,
947
1066
  originalInput: currentDir,
948
1067
  autoDetected: true
949
1068
  };
@@ -957,12 +1076,13 @@ var FinishCommand = class {
957
1076
  }
958
1077
  const branchIssueNumber = extractIssueNumber(currentBranch);
959
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;
960
1080
  getLogger().debug(
961
- `Auto-detected issue #${branchIssueNumber} from branch: ${currentBranch}`
1081
+ `Auto-detected issue #${originalIssueKey} from branch: ${currentBranch}`
962
1082
  );
963
1083
  return {
964
1084
  type: "issue",
965
- number: branchIssueNumber,
1085
+ number: originalIssueKey,
966
1086
  originalInput: currentBranch,
967
1087
  autoDetected: true
968
1088
  };
@@ -1101,84 +1221,102 @@ var FinishCommand = class {
1101
1221
  * This is the workflow: rebase → validate → commit → merge → cleanup
1102
1222
  */
1103
1223
  async executeIssueWorkflow(parsed, options, worktree, result) {
1104
- var _a, _b, _c, _d;
1105
- getLogger().info("Rebasing branch on main...");
1224
+ var _a2, _b, _c, _d, _e, _f;
1106
1225
  const mergeOptions = {
1107
1226
  dryRun: options.dryRun ?? false,
1108
1227
  force: options.force ?? false
1109
1228
  };
1110
- await this.mergeManager.rebaseOnMain(worktree.path, mergeOptions);
1111
- getLogger().success("Branch rebased successfully");
1112
- result.operations.push({
1113
- type: "rebase",
1114
- message: "Branch rebased on main",
1115
- success: true
1116
- });
1117
- if (!options.dryRun) {
1118
- getLogger().info("Running pre-merge validations...");
1119
- await this.validationRunner.runValidations(worktree.path, {
1120
- dryRun: options.dryRun ?? false
1121
- });
1122
- getLogger().success("All validations passed");
1123
- result.operations.push({
1124
- type: "validation",
1125
- message: "Pre-merge validations passed",
1126
- success: true
1127
- });
1229
+ if (options.skipToPr) {
1230
+ getLogger().info("Skipping rebase/validation/commit (--skip-to-pr flag)");
1128
1231
  } else {
1129
- 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");
1130
1235
  result.operations.push({
1131
- type: "validation",
1132
- message: "Would run pre-merge validations (dry-run)",
1236
+ type: "rebase",
1237
+ message: "Branch rebased on main",
1133
1238
  success: true
1134
1239
  });
1135
- }
1136
- const gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path);
1137
- if (gitStatus.hasUncommittedChanges) {
1138
- if (options.dryRun) {
1139
- 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");
1140
1258
  result.operations.push({
1141
- type: "commit",
1142
- message: "Would auto-commit uncommitted changes (dry-run)",
1259
+ type: "validation",
1260
+ message: "Pre-merge validations passed",
1143
1261
  success: true
1144
1262
  });
1145
1263
  } else {
1146
- getLogger().info("Validation passed, auto-committing uncommitted changes...");
1147
- const settings2 = await this.settingsManager.loadSettings(worktree.path);
1148
- const skipVerify = ((_b = (_a = settings2.workflows) == null ? void 0 : _a.issue) == null ? void 0 : _b.noVerify) ?? false;
1149
- const providerType = ((_c = settings2.issueManagement) == null ? void 0 : _c.provider) ?? "github";
1150
- const issuePrefix = IssueManagementProviderFactory.create(providerType).issuePrefix;
1151
- const commitOptions = {
1152
- dryRun: options.dryRun ?? false,
1153
- skipVerify,
1154
- issuePrefix
1155
- };
1156
- if (parsed.type === "issue" && parsed.number) {
1157
- commitOptions.issueNumber = parsed.number;
1158
- }
1159
- try {
1160
- await this.commitManager.commitChanges(worktree.path, commitOptions);
1161
- 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)");
1162
1275
  result.operations.push({
1163
1276
  type: "commit",
1164
- message: "Changes committed successfully",
1277
+ message: "Would auto-commit uncommitted changes (dry-run)",
1165
1278
  success: true
1166
1279
  });
1167
- } catch (error) {
1168
- if (error instanceof UserAbortedCommitError) {
1169
- 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");
1170
1299
  result.operations.push({
1171
1300
  type: "commit",
1172
- message: "Commit aborted by user",
1173
- success: false
1301
+ message: "Changes committed successfully",
1302
+ success: true
1174
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
+ }
1175
1314
  throw error;
1176
1315
  }
1177
- throw error;
1178
1316
  }
1317
+ } else {
1318
+ getLogger().debug("No uncommitted changes found");
1179
1319
  }
1180
- } else {
1181
- getLogger().debug("No uncommitted changes found");
1182
1320
  }
1183
1321
  const settings = await this.settingsManager.loadSettings(worktree.path);
1184
1322
  const mergeBehavior = settings.mergeBehavior ?? { mode: "local" };
@@ -1187,7 +1325,7 @@ var FinishCommand = class {
1187
1325
  return;
1188
1326
  }
1189
1327
  if (mergeBehavior.mode === "github-draft-pr") {
1190
- const { MetadataManager: MetadataManager3 } = await import("./MetadataManager-W3C54UYT.js");
1328
+ const { MetadataManager: MetadataManager3 } = await import("./MetadataManager-5QZSTKNN.js");
1191
1329
  const metadataManager2 = new MetadataManager3();
1192
1330
  const metadata = await metadataManager2.readMetadata(worktree.path);
1193
1331
  getLogger().debug(`Draft PR mode: worktree=${worktree.path}, draftPrNumber=${(metadata == null ? void 0 : metadata.draftPrNumber) ?? "none"}`);
@@ -1245,10 +1383,14 @@ var FinishCommand = class {
1245
1383
  } else {
1246
1384
  getLogger().info(`[DRY RUN] Would mark PR #${metadata.draftPrNumber} as ready for review`);
1247
1385
  }
1248
- const prUrl = (_d = metadata.prUrls) == null ? void 0 : _d[String(metadata.draftPrNumber)];
1386
+ const prUrl = (_e = metadata.prUrls) == null ? void 0 : _e[String(metadata.draftPrNumber)];
1249
1387
  if (prUrl) {
1250
1388
  result.prUrl = prUrl;
1251
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
+ }
1252
1394
  result.operations.push({
1253
1395
  type: "pr-ready",
1254
1396
  message: `PR #${metadata.draftPrNumber} marked as ready for review`,
@@ -1279,7 +1421,7 @@ var FinishCommand = class {
1279
1421
  getLogger().debug("Skipping build verification (--skip-build flag provided)");
1280
1422
  }
1281
1423
  await this.generateSessionSummaryIfConfigured(parsed, worktree, options);
1282
- const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-W3C54UYT.js");
1424
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-5QZSTKNN.js");
1283
1425
  const metadataManager = new MetadataManager2();
1284
1426
  if (!options.dryRun) {
1285
1427
  await metadataManager.archiveMetadata(worktree.path);
@@ -1298,7 +1440,7 @@ var FinishCommand = class {
1298
1440
  * - CLOSED/MERGED: Skip to cleanup
1299
1441
  */
1300
1442
  async executePRWorkflow(parsed, options, worktree, pr, result) {
1301
- var _a, _b, _c;
1443
+ var _a2, _b, _c, _d;
1302
1444
  if (pr.state === "closed" || pr.state === "merged") {
1303
1445
  getLogger().info(`PR #${parsed.number} is ${pr.state.toUpperCase()} - skipping to cleanup`);
1304
1446
  const gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path);
@@ -1308,7 +1450,7 @@ var FinishCommand = class {
1308
1450
  "Cannot cleanup PR with uncommitted changes. Commit or stash changes, then run again with --force to cleanup anyway."
1309
1451
  );
1310
1452
  }
1311
- const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-W3C54UYT.js");
1453
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-5QZSTKNN.js");
1312
1454
  const metadataManager = new MetadataManager2();
1313
1455
  if (!options.dryRun) {
1314
1456
  await metadataManager.archiveMetadata(worktree.path);
@@ -1334,14 +1476,16 @@ var FinishCommand = class {
1334
1476
  } else {
1335
1477
  getLogger().info("Committing uncommitted changes...");
1336
1478
  const settings = await this.settingsManager.loadSettings(worktree.path);
1337
- 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;
1338
1480
  const providerType = ((_c = settings.issueManagement) == null ? void 0 : _c.provider) ?? "github";
1339
- const issuePrefix = IssueManagementProviderFactory.create(providerType).issuePrefix;
1481
+ const issuePrefix = IssueManagementProviderFactory.create(providerType, settings).issuePrefix;
1340
1482
  try {
1341
1483
  await this.commitManager.commitChanges(worktree.path, {
1342
1484
  dryRun: false,
1343
1485
  skipVerify,
1344
- issuePrefix
1486
+ issuePrefix,
1487
+ timeout: (_d = settings.git) == null ? void 0 : _d.commitTimeout,
1488
+ noReview: options.review !== true || options.json === true
1345
1489
  // Do NOT pass issueNumber for PRs - no "Fixes #" trailer needed
1346
1490
  });
1347
1491
  getLogger().success("Changes committed");
@@ -1386,6 +1530,7 @@ var FinishCommand = class {
1386
1530
  * Validates → Commits → Pushes → Creates PR → Prompts for cleanup
1387
1531
  */
1388
1532
  async executeGitHubPRWorkflow(parsed, options, worktree, settings, finishResult) {
1533
+ var _a2;
1389
1534
  if (options.dryRun) {
1390
1535
  getLogger().info("[DRY RUN] Would push branch to origin");
1391
1536
  } else {
@@ -1414,7 +1559,7 @@ var FinishCommand = class {
1414
1559
  success: true
1415
1560
  });
1416
1561
  } else {
1417
- const openInBrowser = options.noBrowser !== true;
1562
+ const openInBrowser = !options.noBrowser && !options.json && ((_a2 = settings.mergeBehavior) == null ? void 0 : _a2.openBrowserOnFinish) !== false;
1418
1563
  const prResult = await prManager.createOrOpenPR(
1419
1564
  worktree.branch,
1420
1565
  prTitle,
@@ -1437,10 +1582,23 @@ var FinishCommand = class {
1437
1582
  message: `Pull request created`,
1438
1583
  success: true
1439
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
+ }
1440
1598
  }
1441
1599
  finishResult.prUrl = prResult.url;
1442
1600
  await this.generateSessionSummaryIfConfigured(parsed, worktree, options, prResult.number);
1443
- const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-W3C54UYT.js");
1601
+ const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-5QZSTKNN.js");
1444
1602
  const metadataManager = new MetadataManager2();
1445
1603
  if (!options.dryRun) {
1446
1604
  await metadataManager.archiveMetadata(worktree.path);
@@ -1494,7 +1652,8 @@ var FinishCommand = class {
1494
1652
  // Don't delete branch - PR still needs it
1495
1653
  keepDatabase: false,
1496
1654
  // Clean up database
1497
- force: options.force ?? false
1655
+ force: options.force ?? false,
1656
+ worktree: { path: worktree.path, branch: worktree.branch }
1498
1657
  };
1499
1658
  try {
1500
1659
  getLogger().info("Starting worktree cleanup...");
@@ -1577,7 +1736,8 @@ var FinishCommand = class {
1577
1736
  // For CLOSED PRs, we rely on checkMergeSafety to verify no unpushed commits
1578
1737
  // rather than checkRemoteBranch, since the remote branch may still exist
1579
1738
  // but local may have additional commits
1580
- checkRemoteBranch: false
1739
+ checkRemoteBranch: false,
1740
+ worktree: { path: worktree.path, branch: worktree.branch }
1581
1741
  };
1582
1742
  try {
1583
1743
  await this.ensureResourceCleanup();
@@ -1708,7 +1868,8 @@ var FinishCommand = class {
1708
1868
  // Delete branch after successful merge
1709
1869
  keepDatabase: false,
1710
1870
  // Clean up database after merge
1711
- force: options.force ?? false
1871
+ force: options.force ?? false,
1872
+ worktree: { path: worktree.path, branch: worktree.branch }
1712
1873
  };
1713
1874
  try {
1714
1875
  getLogger().info("Starting post-merge cleanup...");
@@ -1823,9 +1984,17 @@ function getPackageInfo(scriptPath) {
1823
1984
 
1824
1985
  // src/cli.ts
1825
1986
  import { fileURLToPath as fileURLToPath2 } from "url";
1826
- import { realpathSync } from "fs";
1987
+ import { realpathSync as realpathSync2 } from "fs";
1827
1988
 
1828
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
+ }
1829
1998
  function determineLoomType(worktree) {
1830
1999
  const prPathPattern = /_pr_\d+$/;
1831
2000
  if (prPathPattern.test(worktree.path)) {
@@ -1858,7 +2027,37 @@ function extractIssueNumbers(branch) {
1858
2027
  }
1859
2028
  return [issueNumber];
1860
2029
  }
1861
- 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) {
1862
2061
  const loomType = (metadata == null ? void 0 : metadata.issueType) ?? determineLoomType(worktree);
1863
2062
  let issueNumbers;
1864
2063
  let prNumbers;
@@ -1875,6 +2074,9 @@ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
1875
2074
  }
1876
2075
  }
1877
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;
1878
2080
  return {
1879
2081
  name: worktree.branch || worktree.path,
1880
2082
  worktreePath: worktree.bare ? null : worktree.path,
@@ -1891,15 +2093,22 @@ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
1891
2093
  issueUrls: (metadata == null ? void 0 : metadata.issueUrls) ?? {},
1892
2094
  prUrls: (metadata == null ? void 0 : metadata.prUrls) ?? {},
1893
2095
  capabilities: (metadata == null ? void 0 : metadata.capabilities) ?? [],
2096
+ state: (metadata == null ? void 0 : metadata.state) ?? null,
1894
2097
  isChildLoom: (metadata == null ? void 0 : metadata.parentLoom) != null,
1895
- 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 }
1896
2101
  };
1897
2102
  }
1898
- function formatLoomsForJson(worktrees, mainWorktreePath, metadata) {
1899
- 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));
1900
2106
  }
1901
- function formatFinishedLoomForJson(metadata) {
2107
+ function formatFinishedLoomForJson(metadata, allMetadata, finishedMetadata) {
1902
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;
1903
2112
  return {
1904
2113
  name: metadata.branchName ?? metadata.worktreePath ?? "unknown",
1905
2114
  worktreePath: null,
@@ -1920,114 +2129,16 @@ function formatFinishedLoomForJson(metadata) {
1920
2129
  capabilities: metadata.capabilities ?? [],
1921
2130
  status: metadata.status ?? "finished",
1922
2131
  finishedAt: metadata.finishedAt ?? null,
2132
+ state: metadata.state ?? null,
1923
2133
  isChildLoom: metadata.parentLoom != null,
1924
- parentLoom: metadata.parentLoom ?? null
1925
- };
1926
- }
1927
-
1928
- // src/utils/list-children.ts
1929
- async function fetchChildIssues(parentIssueNumber, settings, repo) {
1930
- const providerName = IssueTrackerFactory.getProviderName(settings);
1931
- logger.debug("Fetching child issues", { parentIssueNumber, provider: providerName, repo });
1932
- const results = await Promise.allSettled([
1933
- (async () => {
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
- return getLinearChildIssues(parentIssueNumber);
1943
- } else {
1944
- logger.warn(`Unsupported issue tracker provider: ${providerName}`);
1945
- return [];
1946
- }
1947
- })()
1948
- ]);
1949
- const result = results[0];
1950
- if (result.status === "fulfilled") {
1951
- return result.value;
1952
- } else {
1953
- logger.warn(`Failed to fetch child issues for ${parentIssueNumber}`, { error: result.reason });
1954
- return [];
1955
- }
1956
- }
1957
- async function findChildLooms(parentBranchName, metadataManager) {
1958
- logger.debug("Finding child looms", { parentBranchName });
1959
- const allMetadata = await metadataManager.listAllMetadata();
1960
- const childLooms = allMetadata.filter((metadata) => {
1961
- if (!metadata.parentLoom) {
1962
- return false;
1963
- }
1964
- return metadata.parentLoom.branchName === parentBranchName;
1965
- });
1966
- logger.debug(`Found ${childLooms.length} child looms for parent: ${parentBranchName}`);
1967
- return childLooms;
1968
- }
1969
- function matchChildrenData(childIssues, childLooms) {
1970
- const issueToLoomMap = /* @__PURE__ */ new Map();
1971
- for (const loom of childLooms) {
1972
- for (const issueNum of loom.issue_numbers) {
1973
- issueToLoomMap.set(issueNum, loom);
1974
- }
1975
- }
1976
- const childIssueIds = new Set(childIssues.map((issue) => issue.id));
1977
- const matchedIssues = childIssues.map((issue) => {
1978
- const matchingLoom = issueToLoomMap.get(issue.id);
1979
- return {
1980
- id: issue.id,
1981
- title: issue.title,
1982
- url: issue.url,
1983
- state: issue.state,
1984
- hasActiveLoom: matchingLoom != null,
1985
- loomBranch: (matchingLoom == null ? void 0 : matchingLoom.branchName) ?? null
1986
- };
1987
- });
1988
- const matchedLooms = childLooms.map((loom) => {
1989
- const hasMatchingIssue = loom.issue_numbers.some((issueNum) => childIssueIds.has(issueNum));
1990
- return {
1991
- branch: loom.branchName ?? "",
1992
- issueNumbers: loom.issue_numbers,
1993
- hasMatchingIssue
1994
- };
1995
- });
1996
- const summary = {
1997
- totalIssues: matchedIssues.length,
1998
- issuesWithLooms: matchedIssues.filter((issue) => issue.hasActiveLoom).length,
1999
- totalLooms: matchedLooms.length,
2000
- orphanLooms: matchedLooms.filter((loom) => !loom.hasMatchingIssue).length
2001
- };
2002
- return {
2003
- issues: matchedIssues,
2004
- looms: matchedLooms,
2005
- summary
2134
+ parentLoom: metadata.parentLoom ?? null,
2135
+ ...swarmIssues !== void 0 && { swarmIssues },
2136
+ ...dependencyMap !== void 0 && { dependencyMap }
2006
2137
  };
2007
2138
  }
2008
- async function assembleChildrenData(parentLoom, metadataManager, settings, repo) {
2009
- if (!parentLoom.issue_numbers || parentLoom.issue_numbers.length === 0) {
2010
- logger.debug("No issue_numbers on loom, skipping children fetch", {
2011
- branch: parentLoom.branchName
2012
- });
2013
- return null;
2014
- }
2015
- if (!parentLoom.branchName) {
2016
- logger.debug("No branchName on loom, skipping children fetch");
2017
- return null;
2018
- }
2019
- const parentIssueNumber = parentLoom.issue_numbers[0];
2020
- if (parentIssueNumber === void 0) {
2021
- return null;
2022
- }
2023
- const [childIssues, childLooms] = await Promise.all([
2024
- fetchChildIssues(parentIssueNumber, settings, repo),
2025
- findChildLooms(parentLoom.branchName, metadataManager)
2026
- ]);
2027
- return matchChildrenData(childIssues, childLooms);
2028
- }
2029
2139
 
2030
2140
  // src/cli.ts
2141
+ import chalk from "chalk";
2031
2142
  import fs3 from "fs-extra";
2032
2143
 
2033
2144
  // src/lib/VersionMigrationManager.ts
@@ -2080,6 +2191,28 @@ var migrations = [
2080
2191
  const newContent = content + separator + "\n# Added by iloom CLI\n" + pattern + "\n";
2081
2192
  await fs.writeFile(globalIgnorePath, newContent, "utf-8");
2082
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
+ }
2083
2216
  }
2084
2217
  ];
2085
2218
 
@@ -2212,6 +2345,35 @@ var VersionMigrationManager = class {
2212
2345
  // src/cli.ts
2213
2346
  var __filename = fileURLToPath2(import.meta.url);
2214
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
+ }
2215
2377
  function parseIssueIdentifier(value) {
2216
2378
  const parsed = parseInt(value, 10);
2217
2379
  return !isNaN(parsed) && String(parsed) === value ? parsed : value;
@@ -2247,6 +2409,12 @@ program.name("iloom").description(packageJson.description).version(packageJson.v
2247
2409
  } catch (error) {
2248
2410
  logger.warn(`Version migration failed: ${error instanceof Error ? error.message : "Unknown"}`);
2249
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
+ }
2250
2418
  await validateSettingsForCommand(actionCommand);
2251
2419
  await validateGhCliForCommand(actionCommand);
2252
2420
  await validateIdeForStartCommand(actionCommand);
@@ -2261,9 +2429,9 @@ program.name("iloom").description(packageJson.description).version(packageJson.v
2261
2429
  }
2262
2430
  });
2263
2431
  async function validateSettingsForCommand(command) {
2264
- var _a, _b;
2432
+ var _a2, _b;
2265
2433
  const commandName = command.name();
2266
- const bypassCommands = ["help", "init", "update", "contribute"];
2434
+ const bypassCommands = ["help", "init", "update", "contribute", "telemetry"];
2267
2435
  if (bypassCommands.includes(commandName)) {
2268
2436
  return;
2269
2437
  }
@@ -2272,7 +2440,7 @@ async function validateSettingsForCommand(command) {
2272
2440
  const settingsManager = new SettingsManager();
2273
2441
  const settings = await settingsManager.loadSettings();
2274
2442
  const multipleRemotes = await hasMultipleRemotes();
2275
- 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)) {
2276
2444
  await autoLaunchInitForMultipleRemotes();
2277
2445
  return;
2278
2446
  }
@@ -2287,7 +2455,7 @@ async function validateSettingsForCommand(command) {
2287
2455
  }
2288
2456
  }
2289
2457
  async function validateGhCliForCommand(command) {
2290
- var _a, _b;
2458
+ var _a2, _b;
2291
2459
  const commandName = command.name();
2292
2460
  const alwaysRequireGh = ["feedback", "contribute"];
2293
2461
  const conditionallyRequireGh = ["start", "finish", "enhance", "add-issue", "ignite", "spin"];
@@ -2302,7 +2470,7 @@ async function validateGhCliForCommand(command) {
2302
2470
  const settingsManager = new SettingsManager();
2303
2471
  const settings = await settingsManager.loadSettings();
2304
2472
  const provider = IssueTrackerFactory.getProviderName(settings);
2305
- const mergeBehaviorMode = (_a = settings.mergeBehavior) == null ? void 0 : _a.mode;
2473
+ const mergeBehaviorMode = (_a2 = settings.mergeBehavior) == null ? void 0 : _a2.mode;
2306
2474
  needsGhCli = provider === "github" || mergeBehaviorMode === "github-pr" || mergeBehaviorMode === "github-draft-pr";
2307
2475
  } catch {
2308
2476
  needsGhCli = true;
@@ -2340,7 +2508,7 @@ async function validateGhCliForCommand(command) {
2340
2508
  }
2341
2509
  }
2342
2510
  async function validateIdeForStartCommand(command) {
2343
- var _a, _b;
2511
+ var _a2, _b;
2344
2512
  const commandName = command.name();
2345
2513
  if (commandName !== "start") {
2346
2514
  return;
@@ -2356,7 +2524,7 @@ async function validateIdeForStartCommand(command) {
2356
2524
  } catch {
2357
2525
  return;
2358
2526
  }
2359
- const workflowConfig = (_a = settings.workflows) == null ? void 0 : _a.issue;
2527
+ const workflowConfig = (_a2 = settings.workflows) == null ? void 0 : _a2.issue;
2360
2528
  if ((workflowConfig == null ? void 0 : workflowConfig.startIde) === false && codeOption !== true) {
2361
2529
  return;
2362
2530
  }
@@ -2375,7 +2543,7 @@ async function validateIdeForStartCommand(command) {
2375
2543
  }
2376
2544
  }
2377
2545
  async function autoLaunchInitForMultipleRemotes() {
2378
- var _a, _b;
2546
+ var _a2, _b;
2379
2547
  logger.info("Multiple git remotes detected, but no GitHub remote is configured.");
2380
2548
  logger.info("");
2381
2549
  logger.info("iloom will now launch an interactive configuration session with Claude");
@@ -2385,19 +2553,19 @@ async function autoLaunchInitForMultipleRemotes() {
2385
2553
  await waitForKeypress2("Press any key to start configuration...");
2386
2554
  logger.info("");
2387
2555
  try {
2388
- const { InitCommand } = await import("./init-ALYWKNWG.js");
2556
+ const { InitCommand } = await import("./init-GFQ5W7GK.js");
2389
2557
  const initCommand = new InitCommand();
2390
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.";
2391
2559
  await initCommand.execute(customInitialMessage);
2392
2560
  logger.info("");
2393
2561
  logger.info("Configuration complete! Continuing with your original command...");
2394
2562
  logger.info("");
2395
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-QR7V2IW2.js");
2563
+ const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-BQDQA3FK.js");
2396
2564
  const settingsManager = new SettingsManager2();
2397
2565
  const settings = await settingsManager.loadSettings();
2398
2566
  const { hasMultipleRemotes: hasMultipleRemotes2 } = await import("./remote-IJAMOEAP.js");
2399
2567
  const multipleRemotes = await hasMultipleRemotes2();
2400
- 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)) {
2401
2569
  logger.error("Configuration incomplete: GitHub remote is still not configured.");
2402
2570
  logger.info('Please run "iloom init" again and configure the GitHub remote setting.');
2403
2571
  process.exit(1);
@@ -2411,7 +2579,7 @@ async function autoLaunchInitForMultipleRemotes() {
2411
2579
  }
2412
2580
  var shellCompletion = new ShellCompletion();
2413
2581
  shellCompletion.init();
2414
- 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(
2415
2583
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
2416
2584
  ).option("--yolo", "Enable autonomous mode (shorthand for --one-shot=bypassPermissions)").action(async (identifier, options) => {
2417
2585
  if (options.yolo) {
@@ -2489,7 +2657,7 @@ program.command("add-issue").alias("a").description("Create and enhance GitHub i
2489
2657
  });
2490
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) => {
2491
2659
  try {
2492
- const { FeedbackCommand } = await import("./feedback-QPNDZQRV.js");
2660
+ const { FeedbackCommand } = await import("./feedback-TMBXSCM5.js");
2493
2661
  const command = new FeedbackCommand();
2494
2662
  const feedbackOptions = {};
2495
2663
  if (options.body !== void 0) {
@@ -2540,7 +2708,10 @@ program.command("enhance").description("Apply enhancement agent to existing GitH
2540
2708
  await executeAction();
2541
2709
  }
2542
2710
  });
2543
- 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
+ }
2544
2715
  const executeAction = async () => {
2545
2716
  try {
2546
2717
  const settingsManager = new SettingsManager();
@@ -2574,7 +2745,7 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
2574
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) => {
2575
2746
  const executeAction = async () => {
2576
2747
  try {
2577
- const { CommitCommand } = await import("./commit-IWGT42XN.js");
2748
+ const { CommitCommand } = await import("./commit-L3EPY5QG.js");
2578
2749
  const command = new CommitCommand();
2579
2750
  const noReview = options.review === false || options.json === true;
2580
2751
  const result = await command.execute({
@@ -2609,7 +2780,7 @@ program.command("commit").alias("c").description("Commit all uncommitted files w
2609
2780
  });
2610
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) => {
2611
2782
  try {
2612
- const { RebaseCommand } = await import("./rebase-AJOJOZUG.js");
2783
+ const { RebaseCommand } = await import("./rebase-DWIB77KV.js");
2613
2784
  const command = new RebaseCommand();
2614
2785
  await command.execute(options);
2615
2786
  } catch (error) {
@@ -2621,12 +2792,12 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2621
2792
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"])
2622
2793
  ).option("--yolo", "Enable autonomous mode (shorthand for --one-shot=bypassPermissions)").option("-p, --print", "Enable print/headless mode for CI/CD (uses bypassPermissions)").addOption(
2623
2794
  new Option("--output-format <format>", "Output format for Claude CLI (requires --print)").choices(["json", "stream-json", "text"])
2624
- ).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) => {
2625
2796
  if (options.yolo) {
2626
2797
  options.oneShot = "bypassPermissions";
2627
2798
  }
2628
2799
  try {
2629
- const { IgniteCommand } = await import("./ignite-OPO6EDYT.js");
2800
+ const { IgniteCommand } = await import("./ignite-CGOV3TD4.js");
2630
2801
  const command = new IgniteCommand();
2631
2802
  if (options.json && options.jsonStream) {
2632
2803
  logger.error("--json and --json-stream are mutually exclusive");
@@ -2645,7 +2816,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2645
2816
  ...options.json && { json: true },
2646
2817
  ...options.jsonStream && { jsonStream: true }
2647
2818
  } : void 0;
2648
- await command.execute(options.oneShot, printOptions);
2819
+ await command.execute(options.oneShot, printOptions, options.skipCleanup);
2649
2820
  } catch (error) {
2650
2821
  logger.error(`Failed to spin up loom: ${error instanceof Error ? error.message : "Unknown error"}`);
2651
2822
  process.exit(1);
@@ -2654,7 +2825,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2654
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) => {
2655
2826
  try {
2656
2827
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2657
- const { OpenCommand } = await import("./open-KWOV2OFO.js");
2828
+ const { OpenCommand } = await import("./open-5QZGXQRF.js");
2658
2829
  const cmd = new OpenCommand();
2659
2830
  const input = identifier ? { identifier, args } : { args };
2660
2831
  await cmd.execute(input);
@@ -2666,7 +2837,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
2666
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) => {
2667
2838
  try {
2668
2839
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2669
- const { RunCommand } = await import("./run-QEUVZF7J.js");
2840
+ const { RunCommand } = await import("./run-O3TFNQFC.js");
2670
2841
  const cmd = new RunCommand();
2671
2842
  const input = identifier ? { identifier, args } : { args };
2672
2843
  await cmd.execute(input);
@@ -2677,7 +2848,7 @@ program.command("run").description("Run CLI tool or open workspace in browser").
2677
2848
  });
2678
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) => {
2679
2850
  try {
2680
- const { VSCodeCommand } = await import("./vscode-6TOLFCI2.js");
2851
+ const { VSCodeCommand } = await import("./vscode-VA5X4P25.js");
2681
2852
  const cmd = new VSCodeCommand();
2682
2853
  await cmd.execute({ identifier, wait: options == null ? void 0 : options.wait });
2683
2854
  } catch (error) {
@@ -2686,7 +2857,7 @@ program.command("vscode").description("Install iloom VS Code extension and open
2686
2857
  });
2687
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) => {
2688
2859
  try {
2689
- const { DevServerCommand } = await import("./dev-server-Q6M62ATG.js");
2860
+ const { DevServerCommand } = await import("./dev-server-FYZ2AQIH.js");
2690
2861
  const cmd = new DevServerCommand();
2691
2862
  await cmd.execute({ identifier, json: options == null ? void 0 : options.json });
2692
2863
  } catch (error) {
@@ -2696,7 +2867,7 @@ program.command("dev-server").alias("dev").description("Start dev server for wor
2696
2867
  });
2697
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) => {
2698
2869
  try {
2699
- const { ShellCommand } = await import("./shell-DAAVG4YN.js");
2870
+ const { ShellCommand } = await import("./shell-G6VC2CYR.js");
2700
2871
  const cmd = new ShellCommand();
2701
2872
  await cmd.execute({ identifier });
2702
2873
  } catch (error) {
@@ -2706,7 +2877,7 @@ program.command("shell").alias("terminal").description("Open interactive shell w
2706
2877
  });
2707
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) => {
2708
2879
  try {
2709
- const { BuildCommand } = await import("./build-IC4CJRMP.js");
2880
+ const { BuildCommand } = await import("./build-5GO3XW26.js");
2710
2881
  const cmd = new BuildCommand();
2711
2882
  await cmd.execute(identifier ? { identifier } : {});
2712
2883
  } catch (error) {
@@ -2716,7 +2887,7 @@ program.command("build").description("Run the build script").argument("[identifi
2716
2887
  });
2717
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) => {
2718
2889
  try {
2719
- const { LintCommand } = await import("./lint-IHUH45OC.js");
2890
+ const { LintCommand } = await import("./lint-6TQXDZ3T.js");
2720
2891
  const cmd = new LintCommand();
2721
2892
  await cmd.execute(identifier ? { identifier } : {});
2722
2893
  } catch (error) {
@@ -2726,7 +2897,7 @@ program.command("lint").description("Run the lint script").argument("[identifier
2726
2897
  });
2727
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) => {
2728
2899
  try {
2729
- const { TestCommand } = await import("./test-5GPWWO3P.js");
2900
+ const { TestCommand } = await import("./test-F7JNJZYP.js");
2730
2901
  const cmd = new TestCommand();
2731
2902
  await cmd.execute(identifier ? { identifier } : {});
2732
2903
  } catch (error) {
@@ -2736,7 +2907,7 @@ program.command("test").description("Run the test script").argument("[identifier
2736
2907
  });
2737
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) => {
2738
2909
  try {
2739
- const { CompileCommand } = await import("./compile-EOWJORKO.js");
2910
+ const { CompileCommand } = await import("./compile-ZS4HYRX5.js");
2740
2911
  const cmd = new CompileCommand();
2741
2912
  await cmd.execute(identifier ? { identifier } : {});
2742
2913
  } catch (error) {
@@ -2744,10 +2915,10 @@ program.command("compile").alias("typecheck").description("Run the compile or ty
2744
2915
  process.exit(1);
2745
2916
  }
2746
2917
  });
2747
- 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) => {
2748
2919
  const executeAction = async () => {
2749
2920
  try {
2750
- const { CleanupCommand } = await import("./cleanup-D3CSRBBZ.js");
2921
+ const { CleanupCommand } = await import("./cleanup-6UCPVMFG.js");
2751
2922
  const command = new CleanupCommand();
2752
2923
  const input = {
2753
2924
  options: options ?? {}
@@ -2776,6 +2947,22 @@ program.command("cleanup").alias("remove").alias("clean").description("Remove wo
2776
2947
  await executeAction();
2777
2948
  }
2778
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
+ }
2779
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) => {
2780
2967
  try {
2781
2968
  const manager = new GitWorktreeManager();
@@ -2833,10 +3020,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2833
3020
  }
2834
3021
  }
2835
3022
  }
2836
- let finishedLooms = [];
2837
- if (showFinished) {
2838
- finishedLooms = await metadataManager.listFinishedMetadata();
2839
- }
3023
+ const finishedLooms = await metadataManager.listFinishedMetadata();
2840
3024
  let filteredWorktrees = worktrees;
2841
3025
  let filteredGlobalActiveLooms = globalActiveLooms;
2842
3026
  let filteredFinishedLooms = finishedLooms;
@@ -2855,32 +3039,41 @@ program.command("list").description("Show active workspaces").option("--json", "
2855
3039
  mainWorktreePath = await findMainWorktreePathWithSettings();
2856
3040
  } catch {
2857
3041
  }
3042
+ const allActiveMetadata = options.global ? globalActiveLooms : Array.from(metadata.values()).filter((m) => m != null);
2858
3043
  let activeJson = [];
2859
3044
  if (showActive) {
2860
3045
  if (options.global) {
2861
- activeJson = globalActiveLooms.map((loom) => ({
2862
- name: loom.branchName ?? loom.worktreePath ?? "unknown",
2863
- worktreePath: loom.worktreePath,
2864
- branch: loom.branchName,
2865
- type: loom.issueType ?? "branch",
2866
- issue_numbers: loom.issue_numbers,
2867
- pr_numbers: loom.pr_numbers,
2868
- isMainWorktree: false,
2869
- // Global looms from other projects are never the main worktree
2870
- description: loom.description ?? null,
2871
- created_at: loom.created_at ?? null,
2872
- issueTracker: loom.issueTracker ?? null,
2873
- colorHex: loom.colorHex ?? null,
2874
- projectPath: loom.projectPath ?? null,
2875
- issueUrls: loom.issueUrls ?? {},
2876
- prUrls: loom.prUrls ?? {},
2877
- status: "active",
2878
- finishedAt: null,
2879
- isChildLoom: loom.parentLoom != null,
2880
- parentLoom: loom.parentLoom ?? null
2881
- }));
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
+ });
2882
3075
  } else {
2883
- activeJson = formatLoomsForJson(worktrees, mainWorktreePath, metadata).map((loom) => ({
3076
+ activeJson = formatLoomsForJson(worktrees, mainWorktreePath, metadata, allActiveMetadata, finishedLooms).map((loom) => ({
2884
3077
  ...loom,
2885
3078
  status: "active",
2886
3079
  finishedAt: null
@@ -2892,7 +3085,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2892
3085
  (loom) => loom.projectPath == null || loom.projectPath === currentProjectPath
2893
3086
  );
2894
3087
  }
2895
- let finishedJson = finishedLooms.map(formatFinishedLoomForJson);
3088
+ let finishedJson = showFinished ? finishedLooms.map((loom) => formatFinishedLoomForJson(loom, allActiveMetadata, finishedLooms)) : [];
2896
3089
  if (currentProjectPath) {
2897
3090
  finishedJson = finishedJson.filter(
2898
3091
  (loom) => loom.projectPath == null || loom.projectPath === currentProjectPath
@@ -2901,6 +3094,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2901
3094
  if (options.children) {
2902
3095
  const settingsManager = new SettingsManager();
2903
3096
  const settings = await settingsManager.loadSettings();
3097
+ const issueTracker = IssueTrackerFactory.create(settings);
2904
3098
  const activeChildrenResults = await Promise.allSettled(
2905
3099
  activeJson.map(async (loom) => {
2906
3100
  const index = activeJson.indexOf(loom);
@@ -2908,7 +3102,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2908
3102
  if (!loomMetadata) {
2909
3103
  return { index, children: null };
2910
3104
  }
2911
- const children = await assembleChildrenData(loomMetadata, metadataManager, settings);
3105
+ const children = await assembleChildrenData(loomMetadata, metadataManager, issueTracker);
2912
3106
  return { index, children };
2913
3107
  })
2914
3108
  );
@@ -2926,7 +3120,7 @@ program.command("list").description("Show active workspaces").option("--json", "
2926
3120
  if (!loomMetadata) {
2927
3121
  return { index, children: null };
2928
3122
  }
2929
- const children = await assembleChildrenData(loomMetadata, metadataManager, settings);
3123
+ const children = await assembleChildrenData(loomMetadata, metadataManager, issueTracker);
2930
3124
  return { index, children };
2931
3125
  })
2932
3126
  );
@@ -2955,10 +3149,11 @@ program.command("list").description("Show active workspaces").option("--json", "
2955
3149
  }
2956
3150
  return;
2957
3151
  }
2958
- let textSettings = null;
3152
+ let textIssueTracker = null;
2959
3153
  if (options.children) {
2960
3154
  const settingsManager = new SettingsManager();
2961
- textSettings = await settingsManager.loadSettings();
3155
+ const textSettings = await settingsManager.loadSettings();
3156
+ textIssueTracker = IssueTrackerFactory.create(textSettings);
2962
3157
  }
2963
3158
  if (showActive && hasActive) {
2964
3159
  logger.info("Active workspaces:");
@@ -2972,14 +3167,17 @@ program.command("list").description("Show active workspaces").option("--json", "
2972
3167
  if (loom.description) {
2973
3168
  logger.info(` Description: ${loom.description}`);
2974
3169
  }
3170
+ if (loom.state) {
3171
+ logger.info(` State: ${colorizeState(loom.state)}`);
3172
+ }
2975
3173
  if (loom.worktreePath) {
2976
3174
  logger.info(` Path: ${loom.worktreePath}`);
2977
3175
  }
2978
3176
  if (loom.projectPath) {
2979
3177
  logger.info(` Project: ${loom.projectPath}`);
2980
3178
  }
2981
- if (options.children && textSettings) {
2982
- const childrenData = await assembleChildrenData(loom, metadataManager, textSettings);
3179
+ if (options.children && textIssueTracker) {
3180
+ const childrenData = await assembleChildrenData(loom, metadataManager, textIssueTracker);
2983
3181
  if (childrenData && (childrenData.summary.totalIssues > 0 || childrenData.summary.totalLooms > 0)) {
2984
3182
  logger.info(` Child Issues: ${childrenData.summary.totalIssues} (${childrenData.summary.issuesWithLooms} with active looms)`);
2985
3183
  for (const issue of childrenData.issues) {
@@ -3002,10 +3200,13 @@ program.command("list").description("Show active workspaces").option("--json", "
3002
3200
  if (loomMetadata == null ? void 0 : loomMetadata.description) {
3003
3201
  logger.info(` Description: ${loomMetadata.description}`);
3004
3202
  }
3203
+ if (loomMetadata == null ? void 0 : loomMetadata.state) {
3204
+ logger.info(` State: ${colorizeState(loomMetadata.state)}`);
3205
+ }
3005
3206
  logger.info(` Path: ${formatted.path}`);
3006
3207
  logger.info(` Commit: ${formatted.commit}`);
3007
- if (options.children && textSettings && loomMetadata) {
3008
- const childrenData = await assembleChildrenData(loomMetadata, metadataManager, textSettings);
3208
+ if (options.children && textIssueTracker && loomMetadata) {
3209
+ const childrenData = await assembleChildrenData(loomMetadata, metadataManager, textIssueTracker);
3009
3210
  if (childrenData && (childrenData.summary.totalIssues > 0 || childrenData.summary.totalLooms > 0)) {
3010
3211
  logger.info(` Child Issues: ${childrenData.summary.totalIssues} (${childrenData.summary.issuesWithLooms} with active looms)`);
3011
3212
  for (const issue of childrenData.issues) {
@@ -3032,11 +3233,14 @@ program.command("list").description("Show active workspaces").option("--json", "
3032
3233
  if (loom.description) {
3033
3234
  logger.info(` Description: ${loom.description}`);
3034
3235
  }
3236
+ if (loom.state) {
3237
+ logger.info(` State: ${colorizeState(loom.state)}`);
3238
+ }
3035
3239
  if (loom.finishedAt) {
3036
3240
  logger.info(` Finished: ${new Date(loom.finishedAt).toLocaleString()}`);
3037
3241
  }
3038
- if (options.children && textSettings) {
3039
- const childrenData = await assembleChildrenData(loom, metadataManager, textSettings);
3242
+ if (options.children && textIssueTracker) {
3243
+ const childrenData = await assembleChildrenData(loom, metadataManager, textIssueTracker);
3040
3244
  if (childrenData && (childrenData.summary.totalIssues > 0 || childrenData.summary.totalLooms > 0)) {
3041
3245
  logger.info(` Child Issues: ${childrenData.summary.totalIssues} (${childrenData.summary.issuesWithLooms} with active looms)`);
3042
3246
  for (const issue of childrenData.issues) {
@@ -3063,7 +3267,7 @@ program.command("list").description("Show active workspaces").option("--json", "
3063
3267
  });
3064
3268
  program.command("projects").description("List configured iloom projects").option("--json", "Output as JSON (default behavior)").action(async (options) => {
3065
3269
  try {
3066
- const { ProjectsCommand } = await import("./projects-LH362JZQ.js");
3270
+ const { ProjectsCommand } = await import("./projects-2UOXFLNZ.js");
3067
3271
  const command = new ProjectsCommand();
3068
3272
  const result = await command.execute(options);
3069
3273
  console.log(JSON.stringify(result, null, 2));
@@ -3072,15 +3276,17 @@ program.command("projects").description("List configured iloom projects").option
3072
3276
  process.exit(1);
3073
3277
  }
3074
3278
  });
3075
- 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) => {
3076
3280
  try {
3077
- const { IssuesCommand } = await import("./issues-L7TBUPXT.js");
3281
+ const { IssuesCommand } = await import("./issues-T4ZZSPEG.js");
3078
3282
  const command = new IssuesCommand();
3079
3283
  const parsedLimit = parseInt((options == null ? void 0 : options.limit) ?? "100", 10);
3080
3284
  const limit = Number.isNaN(parsedLimit) || parsedLimit <= 0 ? 100 : parsedLimit;
3081
3285
  const result = await command.execute({
3082
3286
  ...projectPath ? { projectPath } : {},
3083
- limit
3287
+ limit,
3288
+ sprint: options == null ? void 0 : options.sprint,
3289
+ mine: options == null ? void 0 : options.mine
3084
3290
  });
3085
3291
  console.log(JSON.stringify(result, null, 2));
3086
3292
  } catch (error) {
@@ -3088,13 +3294,13 @@ program.command("issues").description("List project issues from configured issue
3088
3294
  process.exit(1);
3089
3295
  }
3090
3296
  });
3091
- 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) => {
3092
3298
  try {
3093
- const { InitCommand } = await import("./init-ALYWKNWG.js");
3299
+ const { InitCommand } = await import("./init-GFQ5W7GK.js");
3094
3300
  const command = new InitCommand();
3095
3301
  const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
3096
3302
  const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
3097
- await command.execute(customPrompt);
3303
+ await command.execute(customPrompt, options == null ? void 0 : options.acceptDefaults);
3098
3304
  } catch (error) {
3099
3305
  logger.error(`Failed to initialize: ${error instanceof Error ? error.message : "Unknown error"}`);
3100
3306
  process.exit(1);
@@ -3104,7 +3310,7 @@ program.command("plan").description("Launch interactive planning session with Ar
3104
3310
  new Option("--output-format <format>", "Output format for Claude CLI (requires --print)").choices(["json", "stream-json", "text"])
3105
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) => {
3106
3312
  try {
3107
- const { PlanCommand } = await import("./plan-BRJBFJHF.js");
3313
+ const { PlanCommand } = await import("./plan-U7ZQWLFY.js");
3108
3314
  const command = new PlanCommand();
3109
3315
  if ((options == null ? void 0 : options.json) && (options == null ? void 0 : options.jsonStream)) {
3110
3316
  logger.error("--json and --json-stream are mutually exclusive");
@@ -3131,7 +3337,7 @@ program.command("plan").description("Launch interactive planning session with Ar
3131
3337
  });
3132
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) => {
3133
3339
  try {
3134
- const { ContributeCommand } = await import("./contribute-WSJTV2RX.js");
3340
+ const { ContributeCommand } = await import("./contribute-ORDDQGSL.js");
3135
3341
  const command = new ContributeCommand();
3136
3342
  await command.execute(repository);
3137
3343
  } catch (error) {
@@ -3151,8 +3357,8 @@ program.command("update").description("Update iloom-cli to the latest version").
3151
3357
  });
3152
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) => {
3153
3359
  try {
3154
- const { GitHubService: GitHubService2 } = await import("./GitHubService-O7T6CFAJ.js");
3155
- 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");
3156
3362
  logger.info("Testing GitHub Integration\n");
3157
3363
  const service = new GitHubService2();
3158
3364
  const branchNaming = new DefaultBranchNamingService2({ useClaude: options.claude !== false });
@@ -3210,10 +3416,10 @@ program.command("test-github").description("Test GitHub integration (Issue #3)")
3210
3416
  });
3211
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) => {
3212
3418
  try {
3213
- const { detectClaudeCli, getClaudeVersion, generateBranchName, launchClaude } = await import("./claude-TP2QO3BU.js");
3214
- const { PromptTemplateManager } = await import("./PromptTemplateManager-36YLQRHP.js");
3215
- const { ClaudeService } = await import("./ClaudeService-7P32TTES.js");
3216
- const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-X2Y72GRL.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");
3217
3423
  logger.info("Testing Claude Integration\n");
3218
3424
  if (options.detect) {
3219
3425
  logger.info("Detecting Claude CLI...");
@@ -3348,7 +3554,7 @@ program.command("test-claude").description("Test Claude integration (Issue #10)"
3348
3554
  });
3349
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) => {
3350
3556
  try {
3351
- const { TestWebserverCommand } = await import("./test-webserver-CKROHFBQ.js");
3557
+ const { TestWebserverCommand } = await import("./test-webserver-EONCG7E7.js");
3352
3558
  const command = new TestWebserverCommand();
3353
3559
  await command.execute({ issueNumber, options });
3354
3560
  } catch (error) {
@@ -3361,7 +3567,7 @@ program.command("test-webserver").description("Test if a web server is running o
3361
3567
  });
3362
3568
  program.command("test-git").description("Test Git integration - findMainWorktreePath() function (reads .iloom/settings.json)").action(async () => {
3363
3569
  try {
3364
- const { TestGitCommand } = await import("./test-git-EJUKDB7F.js");
3570
+ const { TestGitCommand } = await import("./test-git-BTAOIUE2.js");
3365
3571
  const command = new TestGitCommand();
3366
3572
  await command.execute();
3367
3573
  } catch (error) {
@@ -3387,7 +3593,7 @@ program.command("test-tabs").description("Test iTerm2 dual tab functionality - o
3387
3593
  });
3388
3594
  program.command("test-prefix").description("Test worktree prefix configuration - preview worktree paths (reads .iloom/settings.json)").action(async () => {
3389
3595
  try {
3390
- const { TestPrefixCommand } = await import("./test-prefix-23TOBUXY.js");
3596
+ const { TestPrefixCommand } = await import("./test-prefix-Q6TFSU6F.js");
3391
3597
  const command = new TestPrefixCommand();
3392
3598
  await command.execute();
3393
3599
  } catch (error) {
@@ -3401,7 +3607,7 @@ program.command("test-prefix").description("Test worktree prefix configuration -
3401
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) => {
3402
3608
  const executeAction = async () => {
3403
3609
  try {
3404
- const { SummaryCommand } = await import("./summary-ZKOA35PT.js");
3610
+ const { SummaryCommand } = await import("./summary-FWHAX55O.js");
3405
3611
  const command = new SummaryCommand();
3406
3612
  const result = await command.execute({ identifier, options });
3407
3613
  if (options.json && result) {
@@ -3430,7 +3636,7 @@ program.command("summary").description("Generate Claude session summary for a lo
3430
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) => {
3431
3637
  const executeAction = async () => {
3432
3638
  try {
3433
- const { RecapCommand } = await import("./recap-GKJXMDXW.js");
3639
+ const { RecapCommand } = await import("./recap-MX63HAKV.js");
3434
3640
  const command = new RecapCommand();
3435
3641
  const result = await command.execute({ identifier, json: options.json });
3436
3642
  if (options.json && result) {
@@ -3456,16 +3662,62 @@ program.command("recap").description("Get recap for a loom (defaults to current
3456
3662
  await executeAction();
3457
3663
  }
3458
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
+ });
3459
3711
  program.command("test-neon").description("Test Neon integration and debug configuration").action(async () => {
3460
- var _a;
3712
+ var _a2;
3461
3713
  try {
3462
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-QR7V2IW2.js");
3463
- 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");
3464
3716
  logger.info("Testing Neon Integration\n");
3465
3717
  logger.info("1. Settings Configuration:");
3466
3718
  const settingsManager = new SettingsManager2();
3467
3719
  const settings = await settingsManager.loadSettings();
3468
- const neonConfig = (_a = settings.databaseProviders) == null ? void 0 : _a.neon;
3720
+ const neonConfig = (_a2 = settings.databaseProviders) == null ? void 0 : _a2.neon;
3469
3721
  logger.info(` projectId: ${(neonConfig == null ? void 0 : neonConfig.projectId) ?? "(not configured)"}`);
3470
3722
  logger.info(` parentBranch: ${(neonConfig == null ? void 0 : neonConfig.parentBranch) ?? "(not configured)"}`);
3471
3723
  logger.info("\n2. Creating NeonProvider...");
@@ -3524,6 +3776,23 @@ program.command("test-neon").description("Test Neon integration and debug config
3524
3776
  process.exit(1);
3525
3777
  }
3526
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
+ });
3527
3796
  program.command("help").description("Display help information").argument("[command]", "Show help for specific command").action(async (command) => {
3528
3797
  if (command) {
3529
3798
  const subCommand = program.commands.find((cmd) => cmd.name() === command);
@@ -3540,24 +3809,45 @@ program.command("help").description("Display help information").argument("[comma
3540
3809
  });
3541
3810
  var isRunDirectly = process.argv[1] && (() => {
3542
3811
  try {
3543
- const scriptPath = realpathSync(process.argv[1]);
3812
+ const scriptPath = realpathSync2(process.argv[1]);
3544
3813
  const modulePath = fileURLToPath2(import.meta.url);
3545
3814
  return scriptPath === modulePath;
3546
3815
  } catch {
3547
3816
  return true;
3548
3817
  }
3549
3818
  })();
3819
+ var _a;
3550
3820
  if (isRunDirectly) {
3551
3821
  try {
3552
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
+ }
3553
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
+ }
3554
3840
  if (error instanceof Error) {
3555
3841
  logger.error(`Error: ${error.message}`);
3556
3842
  process.exit(1);
3843
+ } else {
3844
+ logger.error(`Error: ${String(error)}`);
3845
+ process.exit(1);
3557
3846
  }
3558
3847
  }
3559
3848
  }
3560
3849
  export {
3850
+ handleTelemetryLifecycle,
3561
3851
  validateGhCliForCommand,
3562
3852
  validateIdeForStartCommand
3563
3853
  };