@iloom/cli 0.3.3 → 0.4.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 (178) hide show
  1. package/README.md +13 -3
  2. package/dist/{BranchNamingService-A77VI6AI.js → BranchNamingService-TOM2KAUT.js} +4 -3
  3. package/dist/ClaudeContextManager-VEGJTS5E.js +16 -0
  4. package/dist/ClaudeService-ICSHJMQ5.js +15 -0
  5. package/dist/GitHubService-RPM27GWD.js +12 -0
  6. package/dist/{LoomLauncher-ZV3ZZIBA.js → LoomLauncher-SJBZFZXE.js} +25 -22
  7. package/dist/LoomLauncher-SJBZFZXE.js.map +1 -0
  8. package/dist/PromptTemplateManager-2TDZAUC6.js +9 -0
  9. package/dist/README.md +13 -3
  10. package/dist/{SettingsManager-I2LRCW2A.js → SettingsManager-FJFU6JJD.js} +7 -3
  11. package/dist/SettingsMigrationManager-EH3J2TCN.js +10 -0
  12. package/dist/{chunk-UJL4HI2R.js → chunk-3NFBZRPR.js} +2 -2
  13. package/dist/chunk-6UIGZD2N.js +20 -0
  14. package/dist/chunk-6UIGZD2N.js.map +1 -0
  15. package/dist/{chunk-RIEO2WML.js → chunk-74VMN2KC.js} +26 -2
  16. package/dist/chunk-74VMN2KC.js.map +1 -0
  17. package/dist/{chunk-OYF4VIFI.js → chunk-75B2HZZ5.js} +147 -22
  18. package/dist/chunk-75B2HZZ5.js.map +1 -0
  19. package/dist/{chunk-PGPI5LR4.js → chunk-ADDNFQJ4.js} +7 -21
  20. package/dist/chunk-ADDNFQJ4.js.map +1 -0
  21. package/dist/{chunk-AKUJXDNW.js → chunk-F4J6KEL6.js} +3 -3
  22. package/dist/{chunk-DLHA5VQ3.js → chunk-HD5SUKI2.js} +36 -179
  23. package/dist/chunk-HD5SUKI2.js.map +1 -0
  24. package/dist/chunk-HHDSIE72.js +667 -0
  25. package/dist/chunk-HHDSIE72.js.map +1 -0
  26. package/dist/{chunk-OXAM2WVC.js → chunk-HVGQP44L.js} +21 -1
  27. package/dist/chunk-HVGQP44L.js.map +1 -0
  28. package/dist/{chunk-RW54ZMBM.js → chunk-JJUPY5MM.js} +2 -2
  29. package/dist/{chunk-UAN4A3YU.js → chunk-KM3W7YQX.js} +11 -11
  30. package/dist/{chunk-3RUPPQRG.js → chunk-KO2FOMHL.js} +43 -2
  31. package/dist/{chunk-3RUPPQRG.js.map → chunk-KO2FOMHL.js.map} +1 -1
  32. package/dist/{chunk-2MAIX45J.js → chunk-LTNDJMTH.js} +104 -43
  33. package/dist/chunk-LTNDJMTH.js.map +1 -0
  34. package/dist/{chunk-2CXREBLZ.js → chunk-M5XUCTTJ.js} +8 -6
  35. package/dist/chunk-M5XUCTTJ.js.map +1 -0
  36. package/dist/{chunk-4XIDC3NF.js → chunk-MD6HA5IK.js} +2 -2
  37. package/dist/chunk-MLS5FAV7.js +189 -0
  38. package/dist/chunk-MLS5FAV7.js.map +1 -0
  39. package/dist/{chunk-2IJEMXOB.js → chunk-NFVFVYAP.js} +419 -427
  40. package/dist/chunk-NFVFVYAP.js.map +1 -0
  41. package/dist/{chunk-OC4H6HJD.js → chunk-O7WHXLCB.js} +2 -2
  42. package/dist/{chunk-M7JJCX53.js → chunk-OEGECBFS.js} +20 -20
  43. package/dist/chunk-OEGECBFS.js.map +1 -0
  44. package/dist/{chunk-MKWYLDFK.js → chunk-OF7BNW4D.js} +43 -3
  45. package/dist/chunk-OF7BNW4D.js.map +1 -0
  46. package/dist/{chunk-SUOXY5WJ.js → chunk-P2WZIDF3.js} +5 -5
  47. package/dist/chunk-P2WZIDF3.js.map +1 -0
  48. package/dist/{chunk-PA6Q6AWM.js → chunk-PSFVTBM7.js} +2 -2
  49. package/dist/chunk-QHA67Q7A.js +281 -0
  50. package/dist/chunk-QHA67Q7A.js.map +1 -0
  51. package/dist/{chunk-ZM3CFL5L.js → chunk-QRBOPFAA.js} +3 -3
  52. package/dist/{chunk-IFB4Z76W.js → chunk-S44CHE3G.js} +13 -12
  53. package/dist/chunk-S44CHE3G.js.map +1 -0
  54. package/dist/{chunk-CE26YH2U.js → chunk-SJ2GZ6RF.js} +48 -50
  55. package/dist/chunk-SJ2GZ6RF.js.map +1 -0
  56. package/dist/{chunk-SSCQCCJ7.js → chunk-THF25ICZ.js} +2 -2
  57. package/dist/{chunk-5Q3NDNNV.js → chunk-TR5MC2U6.js} +153 -6
  58. package/dist/chunk-TR5MC2U6.js.map +1 -0
  59. package/dist/{chunk-5VK4NRSF.js → chunk-UNXRACJ7.js} +35 -36
  60. package/dist/chunk-UNXRACJ7.js.map +1 -0
  61. package/dist/{chunk-GEHQXLEI.js → chunk-UYVWLISQ.js} +18 -35
  62. package/dist/chunk-UYVWLISQ.js.map +1 -0
  63. package/dist/{chunk-OSCLCMDG.js → chunk-UYWAESOT.js} +3 -3
  64. package/dist/{chunk-ZT3YZB4K.js → chunk-VBFDVGAE.js} +12 -12
  65. package/dist/chunk-VBFDVGAE.js.map +1 -0
  66. package/dist/{chunk-CDZERT7Z.js → chunk-VWNS6DH5.js} +48 -4
  67. package/dist/chunk-VWNS6DH5.js.map +1 -0
  68. package/dist/{chunk-CFFQ2Z7A.js → chunk-WUQQNE63.js} +2 -2
  69. package/dist/{claude-W52VKI6L.js → claude-X7EBJRB2.js} +8 -5
  70. package/dist/{cleanup-H4VXU3C3.js → cleanup-7QVPYBJJ.js} +133 -122
  71. package/dist/cleanup-7QVPYBJJ.js.map +1 -0
  72. package/dist/cli.js +901 -425
  73. package/dist/cli.js.map +1 -1
  74. package/dist/{color-F7RU6B6Z.js → color-ZPIIUADB.js} +3 -3
  75. package/dist/{contribute-Y7IQV5QY.js → contribute-RZYCYUDX.js} +8 -6
  76. package/dist/{contribute-Y7IQV5QY.js.map → contribute-RZYCYUDX.js.map} +1 -1
  77. package/dist/dev-server-LOY7YWCP.js +298 -0
  78. package/dist/dev-server-LOY7YWCP.js.map +1 -0
  79. package/dist/{feedback-XTUCKJNT.js → feedback-562KPG5U.js} +13 -12
  80. package/dist/{feedback-XTUCKJNT.js.map → feedback-562KPG5U.js.map} +1 -1
  81. package/dist/{git-IYA53VIC.js → git-OXJACVAU.js} +16 -4
  82. package/dist/hooks/iloom-hook.js +258 -0
  83. package/dist/{ignite-T74RYXCA.js → ignite-VSIPGKKG.js} +245 -39
  84. package/dist/ignite-VSIPGKKG.js.map +1 -0
  85. package/dist/index.d.ts +459 -124
  86. package/dist/index.js +740 -210
  87. package/dist/index.js.map +1 -1
  88. package/dist/init-SCR2LQ4A.js +21 -0
  89. package/dist/{installation-detector-VARGFFRZ.js → installation-detector-6R6YOFVZ.js} +3 -3
  90. package/dist/mcp/issue-management-server.js +2 -1
  91. package/dist/mcp/issue-management-server.js.map +1 -1
  92. package/dist/neon-helpers-L5CXQ5CT.js +11 -0
  93. package/dist/{open-UMXANW5S.js → open-CX7HUE26.js} +12 -10
  94. package/dist/{open-UMXANW5S.js.map → open-CX7HUE26.js.map} +1 -1
  95. package/dist/projects-6DTNDVLH.js +73 -0
  96. package/dist/projects-6DTNDVLH.js.map +1 -0
  97. package/dist/{prompt-QALMYTVC.js → prompt-A7GGRHSY.js} +3 -3
  98. package/dist/prompts/init-prompt.txt +49 -0
  99. package/dist/prompts/issue-prompt.txt +110 -8
  100. package/dist/prompts/regular-prompt.txt +463 -14
  101. package/dist/prompts/session-summary-prompt.txt +82 -0
  102. package/dist/{rebase-VJ2VKR6R.js → rebase-55URTXZC.js} +11 -9
  103. package/dist/{rebase-VJ2VKR6R.js.map → rebase-55URTXZC.js.map} +1 -1
  104. package/dist/{remote-VUNCQZ6J.js → remote-73TZ2ADI.js} +3 -3
  105. package/dist/{run-MJYY4PUT.js → run-DP2U2CA2.js} +12 -10
  106. package/dist/{run-MJYY4PUT.js.map → run-DP2U2CA2.js.map} +1 -1
  107. package/dist/schema/settings.schema.json +49 -0
  108. package/dist/summary-J3CJSM7L.js +244 -0
  109. package/dist/summary-J3CJSM7L.js.map +1 -0
  110. package/dist/{test-git-IT5EWQ5C.js → test-git-QLAIBJLX.js} +6 -4
  111. package/dist/{test-git-IT5EWQ5C.js.map → test-git-QLAIBJLX.js.map} +1 -1
  112. package/dist/{test-prefix-NPWDPUUH.js → test-prefix-6YM2ZOON.js} +6 -4
  113. package/dist/{test-prefix-NPWDPUUH.js.map → test-prefix-6YM2ZOON.js.map} +1 -1
  114. package/dist/{test-tabs-PRMRSHKI.js → test-tabs-JGO3VOXJ.js} +4 -4
  115. package/dist/{test-webserver-DAHONWCS.js → test-webserver-VPNLAFZ3.js} +2 -2
  116. package/dist/{update-4TDDUR5K.js → update-LETF5ASC.js} +4 -4
  117. package/dist/{update-notifier-QEX3CJHA.js → update-notifier-H55ZK7NU.js} +3 -3
  118. package/package.json +6 -6
  119. package/dist/ClaudeContextManager-BN7RE5ZQ.js +0 -15
  120. package/dist/ClaudeService-DLYLJUPA.js +0 -14
  121. package/dist/GitHubService-FZHHBOFG.js +0 -11
  122. package/dist/LoomLauncher-ZV3ZZIBA.js.map +0 -1
  123. package/dist/PromptTemplateManager-6HH3PVXV.js +0 -9
  124. package/dist/SettingsMigrationManager-TJ7UWZG5.js +0 -10
  125. package/dist/chunk-2CXREBLZ.js.map +0 -1
  126. package/dist/chunk-2IJEMXOB.js.map +0 -1
  127. package/dist/chunk-2MAIX45J.js.map +0 -1
  128. package/dist/chunk-5Q3NDNNV.js.map +0 -1
  129. package/dist/chunk-5VK4NRSF.js.map +0 -1
  130. package/dist/chunk-CDZERT7Z.js.map +0 -1
  131. package/dist/chunk-CE26YH2U.js.map +0 -1
  132. package/dist/chunk-DLHA5VQ3.js.map +0 -1
  133. package/dist/chunk-GEHQXLEI.js.map +0 -1
  134. package/dist/chunk-IFB4Z76W.js.map +0 -1
  135. package/dist/chunk-M7JJCX53.js.map +0 -1
  136. package/dist/chunk-MKWYLDFK.js.map +0 -1
  137. package/dist/chunk-OXAM2WVC.js.map +0 -1
  138. package/dist/chunk-OYF4VIFI.js.map +0 -1
  139. package/dist/chunk-PGPI5LR4.js.map +0 -1
  140. package/dist/chunk-RIEO2WML.js.map +0 -1
  141. package/dist/chunk-SUOXY5WJ.js.map +0 -1
  142. package/dist/chunk-ZT3YZB4K.js.map +0 -1
  143. package/dist/cleanup-H4VXU3C3.js.map +0 -1
  144. package/dist/ignite-T74RYXCA.js.map +0 -1
  145. package/dist/init-4FHTAM3F.js +0 -19
  146. package/dist/logger-MKYH4UDV.js +0 -12
  147. package/dist/neon-helpers-77PBPGJ5.js +0 -10
  148. package/dist/update-notifier-QEX3CJHA.js.map +0 -1
  149. /package/dist/{BranchNamingService-A77VI6AI.js.map → BranchNamingService-TOM2KAUT.js.map} +0 -0
  150. /package/dist/{ClaudeContextManager-BN7RE5ZQ.js.map → ClaudeContextManager-VEGJTS5E.js.map} +0 -0
  151. /package/dist/{ClaudeService-DLYLJUPA.js.map → ClaudeService-ICSHJMQ5.js.map} +0 -0
  152. /package/dist/{GitHubService-FZHHBOFG.js.map → GitHubService-RPM27GWD.js.map} +0 -0
  153. /package/dist/{PromptTemplateManager-6HH3PVXV.js.map → PromptTemplateManager-2TDZAUC6.js.map} +0 -0
  154. /package/dist/{SettingsManager-I2LRCW2A.js.map → SettingsManager-FJFU6JJD.js.map} +0 -0
  155. /package/dist/{SettingsMigrationManager-TJ7UWZG5.js.map → SettingsMigrationManager-EH3J2TCN.js.map} +0 -0
  156. /package/dist/{chunk-UJL4HI2R.js.map → chunk-3NFBZRPR.js.map} +0 -0
  157. /package/dist/{chunk-AKUJXDNW.js.map → chunk-F4J6KEL6.js.map} +0 -0
  158. /package/dist/{chunk-RW54ZMBM.js.map → chunk-JJUPY5MM.js.map} +0 -0
  159. /package/dist/{chunk-UAN4A3YU.js.map → chunk-KM3W7YQX.js.map} +0 -0
  160. /package/dist/{chunk-4XIDC3NF.js.map → chunk-MD6HA5IK.js.map} +0 -0
  161. /package/dist/{chunk-OC4H6HJD.js.map → chunk-O7WHXLCB.js.map} +0 -0
  162. /package/dist/{chunk-PA6Q6AWM.js.map → chunk-PSFVTBM7.js.map} +0 -0
  163. /package/dist/{chunk-ZM3CFL5L.js.map → chunk-QRBOPFAA.js.map} +0 -0
  164. /package/dist/{chunk-SSCQCCJ7.js.map → chunk-THF25ICZ.js.map} +0 -0
  165. /package/dist/{chunk-OSCLCMDG.js.map → chunk-UYWAESOT.js.map} +0 -0
  166. /package/dist/{chunk-CFFQ2Z7A.js.map → chunk-WUQQNE63.js.map} +0 -0
  167. /package/dist/{claude-W52VKI6L.js.map → claude-X7EBJRB2.js.map} +0 -0
  168. /package/dist/{color-F7RU6B6Z.js.map → color-ZPIIUADB.js.map} +0 -0
  169. /package/dist/{git-IYA53VIC.js.map → git-OXJACVAU.js.map} +0 -0
  170. /package/dist/{init-4FHTAM3F.js.map → init-SCR2LQ4A.js.map} +0 -0
  171. /package/dist/{installation-detector-VARGFFRZ.js.map → installation-detector-6R6YOFVZ.js.map} +0 -0
  172. /package/dist/{logger-MKYH4UDV.js.map → neon-helpers-L5CXQ5CT.js.map} +0 -0
  173. /package/dist/{neon-helpers-77PBPGJ5.js.map → prompt-A7GGRHSY.js.map} +0 -0
  174. /package/dist/{prompt-QALMYTVC.js.map → remote-73TZ2ADI.js.map} +0 -0
  175. /package/dist/{test-tabs-PRMRSHKI.js.map → test-tabs-JGO3VOXJ.js.map} +0 -0
  176. /package/dist/{test-webserver-DAHONWCS.js.map → test-webserver-VPNLAFZ3.js.map} +0 -0
  177. /package/dist/{update-4TDDUR5K.js.map → update-LETF5ASC.js.map} +0 -0
  178. /package/dist/{remote-VUNCQZ6J.js.map → update-notifier-H55ZK7NU.js.map} +0 -0
package/dist/cli.js CHANGED
@@ -1,63 +1,59 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ SessionSummaryService
4
+ } from "./chunk-HHDSIE72.js";
2
5
  import {
3
6
  CLIIsolationManager,
4
7
  DatabaseManager,
5
8
  EnvironmentManager,
6
9
  LoomManager,
7
- MetadataManager,
8
10
  ResourceCleanup
9
- } from "./chunk-2IJEMXOB.js";
10
- import {
11
- IdentifierParser
12
- } from "./chunk-OXAM2WVC.js";
13
- import {
14
- ProcessManager
15
- } from "./chunk-VU3QMIP2.js";
11
+ } from "./chunk-NFVFVYAP.js";
16
12
  import {
17
13
  InitCommand,
18
14
  ShellCompletion
19
- } from "./chunk-UAN4A3YU.js";
20
- import {
21
- getConfiguredRepoFromSettings,
22
- getEffectivePRTargetRemote,
23
- hasMultipleRemotes,
24
- parseGitRemotes
25
- } from "./chunk-PA6Q6AWM.js";
26
- import "./chunk-OSCLCMDG.js";
15
+ } from "./chunk-KM3W7YQX.js";
16
+ import "./chunk-UYWAESOT.js";
27
17
  import {
28
18
  IssueEnhancementService,
29
19
  capitalizeFirstLetter
30
- } from "./chunk-IFB4Z76W.js";
31
- import {
32
- openBrowser
33
- } from "./chunk-YETJNRQM.js";
20
+ } from "./chunk-S44CHE3G.js";
34
21
  import {
35
22
  MergeManager
36
- } from "./chunk-2MAIX45J.js";
23
+ } from "./chunk-LTNDJMTH.js";
37
24
  import {
38
25
  FirstRunManager,
39
26
  IssueTrackerFactory,
40
27
  generateIssueManagementMcpConfig
41
- } from "./chunk-DLHA5VQ3.js";
28
+ } from "./chunk-HD5SUKI2.js";
29
+ import "./chunk-QHA67Q7A.js";
42
30
  import {
43
31
  AgentManager
44
- } from "./chunk-OC4H6HJD.js";
32
+ } from "./chunk-O7WHXLCB.js";
33
+ import {
34
+ IdentifierParser
35
+ } from "./chunk-HVGQP44L.js";
36
+ import {
37
+ ProcessManager
38
+ } from "./chunk-VU3QMIP2.js";
39
+ import {
40
+ openBrowser
41
+ } from "./chunk-YETJNRQM.js";
45
42
  import {
46
43
  GitWorktreeManager
47
- } from "./chunk-2CXREBLZ.js";
44
+ } from "./chunk-M5XUCTTJ.js";
48
45
  import {
49
46
  detectPackageManager,
50
47
  installDependencies,
51
48
  runScript
52
- } from "./chunk-ZT3YZB4K.js";
49
+ } from "./chunk-VBFDVGAE.js";
53
50
  import {
54
51
  ClaudeContextManager
55
- } from "./chunk-AKUJXDNW.js";
56
- import "./chunk-PGPI5LR4.js";
57
- import "./chunk-RIEO2WML.js";
52
+ } from "./chunk-F4J6KEL6.js";
53
+ import "./chunk-ADDNFQJ4.js";
58
54
  import {
59
55
  DefaultBranchNamingService
60
- } from "./chunk-SUOXY5WJ.js";
56
+ } from "./chunk-P2WZIDF3.js";
61
57
  import {
62
58
  ProjectCapabilityDetector
63
59
  } from "./chunk-EBISESAP.js";
@@ -70,40 +66,55 @@ import {
70
66
  } from "./chunk-GYCR2LOU.js";
71
67
  import {
72
68
  createNeonProviderFromSettings
73
- } from "./chunk-5VK4NRSF.js";
69
+ } from "./chunk-UNXRACJ7.js";
70
+ import {
71
+ getConfiguredRepoFromSettings,
72
+ getEffectivePRTargetRemote,
73
+ hasMultipleRemotes,
74
+ parseGitRemotes
75
+ } from "./chunk-PSFVTBM7.js";
74
76
  import {
75
77
  executeGitCommand,
76
78
  extractIssueNumber,
77
79
  findMainWorktreePathWithSettings,
78
80
  getRepoRoot,
79
81
  pushBranchToRemote
80
- } from "./chunk-5Q3NDNNV.js";
82
+ } from "./chunk-TR5MC2U6.js";
83
+ import {
84
+ MetadataManager
85
+ } from "./chunk-MLS5FAV7.js";
81
86
  import {
82
87
  SettingsManager
83
- } from "./chunk-CDZERT7Z.js";
88
+ } from "./chunk-VWNS6DH5.js";
84
89
  import {
85
90
  GitHubService
86
- } from "./chunk-M7JJCX53.js";
91
+ } from "./chunk-OEGECBFS.js";
87
92
  import {
88
93
  executeGhCommand
89
- } from "./chunk-3RUPPQRG.js";
94
+ } from "./chunk-KO2FOMHL.js";
90
95
  import {
91
96
  promptCommitAction,
92
97
  promptConfirmation,
93
98
  waitForKeypress
94
- } from "./chunk-CE26YH2U.js";
95
- import "./chunk-CFFQ2Z7A.js";
99
+ } from "./chunk-SJ2GZ6RF.js";
100
+ import "./chunk-WUQQNE63.js";
96
101
  import {
97
102
  detectClaudeCli,
98
103
  launchClaude
99
- } from "./chunk-OYF4VIFI.js";
100
- import "./chunk-RW54ZMBM.js";
104
+ } from "./chunk-75B2HZZ5.js";
105
+ import "./chunk-JJUPY5MM.js";
101
106
  import {
102
107
  loadEnvIntoProcess
103
- } from "./chunk-UJL4HI2R.js";
108
+ } from "./chunk-3NFBZRPR.js";
104
109
  import {
110
+ getLogger,
111
+ withLogger
112
+ } from "./chunk-6UIGZD2N.js";
113
+ import "./chunk-74VMN2KC.js";
114
+ import {
115
+ createStderrLogger,
105
116
  logger
106
- } from "./chunk-GEHQXLEI.js";
117
+ } from "./chunk-UYVWLISQ.js";
107
118
 
108
119
  // src/cli.ts
109
120
  import { program, Option } from "commander";
@@ -158,7 +169,7 @@ async function launchFirstRunSetup() {
158
169
  logger.info(
159
170
  "iloom will now launch an interactive configuration session with Claude."
160
171
  );
161
- const { waitForKeypress: waitForKeypress2 } = await import("./prompt-QALMYTVC.js");
172
+ const { waitForKeypress: waitForKeypress2 } = await import("./prompt-A7GGRHSY.js");
162
173
  await waitForKeypress2("Press any key to start configuration...");
163
174
  const initCommand = new InitCommand();
164
175
  await initCommand.execute(
@@ -181,10 +192,10 @@ var StartCommand = class {
181
192
  this.providedLoomManager = loomManager;
182
193
  const envResult = loadEnvIntoProcess();
183
194
  if (envResult.error) {
184
- logger.debug(`Environment loading warning: ${envResult.error.message}`);
195
+ getLogger().debug(`Environment loading warning: ${envResult.error.message}`);
185
196
  }
186
197
  if (envResult.parsed) {
187
- logger.debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`);
198
+ getLogger().debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`);
188
199
  }
189
200
  }
190
201
  /**
@@ -228,36 +239,40 @@ var StartCommand = class {
228
239
  * Main entry point for the start command
229
240
  */
230
241
  async execute(input) {
231
- var _a, _b, _c, _d;
242
+ var _a, _b, _c, _d, _e;
243
+ const isJsonMode = input.options.json === true;
232
244
  try {
233
245
  const initialSettings = await this.settingsManager.loadSettings();
234
- if (process.env.FORCE_FIRST_TIME_SETUP === "true" || await needsFirstRunSetup()) {
246
+ if (!isJsonMode && (process.env.FORCE_FIRST_TIME_SETUP === "true" || await needsFirstRunSetup())) {
235
247
  await launchFirstRunSetup();
236
248
  const newSettings = await this.settingsManager.loadSettings();
237
249
  const newProvider = ((_a = newSettings.issueManagement) == null ? void 0 : _a.provider) ?? "github";
238
250
  if (newProvider !== this.issueTracker.providerName) {
239
- logger.debug(`Reinitializing issue tracker: provider changed to "${newProvider}"`);
251
+ getLogger().debug(`Reinitializing issue tracker: provider changed to "${newProvider}"`);
240
252
  this.issueTracker = IssueTrackerFactory.create(newSettings);
241
253
  }
242
254
  }
243
255
  let repo;
244
256
  if (this.issueTracker.providerName === "github" && await hasMultipleRemotes()) {
245
257
  repo = await getConfiguredRepoFromSettings(initialSettings);
246
- logger.info(`Using GitHub repository: ${repo}`);
258
+ getLogger().info(`Using GitHub repository: ${repo}`);
247
259
  }
248
260
  const loomManager = await this.initializeLoomManager();
249
261
  let parentLoom = await this.detectParentLoom(loomManager);
250
262
  const parsed = await this.parseInput(input.identifier, repo);
251
263
  await this.validateInput(parsed, repo);
252
264
  if (parentLoom) {
253
- const { isInteractiveEnvironment, promptConfirmation: promptConfirmation2 } = await import("./prompt-QALMYTVC.js");
265
+ const { isInteractiveEnvironment, promptConfirmation: promptConfirmation2 } = await import("./prompt-A7GGRHSY.js");
254
266
  const parentDisplay = parentLoom.type === "issue" ? `issue #${parentLoom.identifier}` : parentLoom.type === "pr" ? `PR #${parentLoom.identifier}` : `branch ${parentLoom.identifier}`;
255
267
  if (input.options.childLoom === true) {
256
- logger.info(`Creating as child loom of ${parentDisplay} (--child-loom flag)`);
268
+ getLogger().info(`Creating as child loom of ${parentDisplay} (--child-loom flag)`);
257
269
  } else if (input.options.childLoom === false) {
258
270
  parentLoom = null;
259
- logger.info("Creating as independent loom (--no-child-loom flag)");
271
+ getLogger().info("Creating as independent loom (--no-child-loom flag)");
260
272
  } else {
273
+ if (isJsonMode) {
274
+ throw new Error("JSON mode requires explicit --child-loom or --no-child-loom flag when running from inside a loom");
275
+ }
261
276
  let createAsChild = true;
262
277
  if (isInteractiveEnvironment()) {
263
278
  createAsChild = await promptConfirmation2(
@@ -266,19 +281,19 @@ var StartCommand = class {
266
281
  // Default yes
267
282
  );
268
283
  } else {
269
- logger.error(`Non-interactive environment detected, use either --child-loom or --no-child-loom to specify behavior`);
284
+ getLogger().error(`Non-interactive environment detected, use either --child-loom or --no-child-loom to specify behavior`);
270
285
  process.exit(1);
271
286
  }
272
287
  if (!createAsChild) {
273
288
  parentLoom = null;
274
- logger.info("Creating as independent loom");
289
+ getLogger().info("Creating as independent loom");
275
290
  }
276
291
  }
277
292
  } else if (input.options.childLoom === true) {
278
- logger.debug("--child-loom flag provided but not running from inside an existing loom (ignored)");
293
+ getLogger().debug("--child-loom flag provided but not running from inside an existing loom (ignored)");
279
294
  }
280
295
  if (parsed.type === "description") {
281
- logger.info("Creating GitHub issue from description...");
296
+ getLogger().info("Creating GitHub issue from description...");
282
297
  const title = capitalizeFirstLetter(parsed.originalInput);
283
298
  const body = input.options.body ? capitalizeFirstLetter(input.options.body) : "";
284
299
  const result = await this.issueTracker.createIssue(
@@ -287,17 +302,20 @@ var StartCommand = class {
287
302
  body
288
303
  // Use capitalized body or empty
289
304
  );
290
- logger.success(`Created issue #${result.number}: ${result.url}`);
305
+ getLogger().success(`Created issue #${result.number}: ${result.url}`);
291
306
  parsed.type = "issue";
292
307
  parsed.number = result.number;
293
308
  }
294
309
  if (input.options.oneShot === "bypassPermissions") {
295
- const { promptConfirmation: promptConfirmation2 } = await import("./prompt-QALMYTVC.js");
310
+ if (isJsonMode) {
311
+ throw new Error("JSON mode does not support bypassPermissions confirmation prompt");
312
+ }
313
+ const { promptConfirmation: promptConfirmation2 } = await import("./prompt-A7GGRHSY.js");
296
314
  const confirmed = await promptConfirmation2(
297
- "\u26A0\uFE0F WARNING: bypassPermissions mode will allow Claude to execute all tool calls without confirmation. This can be dangerous. Do you want to proceed?"
315
+ "WARNING: bypassPermissions mode will allow Claude to execute all tool calls without confirmation. This can be dangerous. Do you want to proceed?"
298
316
  );
299
317
  if (!confirmed) {
300
- logger.info("Operation cancelled by user");
318
+ getLogger().info("Operation cancelled by user");
301
319
  process.exit(0);
302
320
  }
303
321
  }
@@ -308,13 +326,13 @@ var StartCommand = class {
308
326
  const { extractRawSetArguments, getExecutablePath } = await import("./cli-overrides-XFZWY7CM.js");
309
327
  const setArguments = extractRawSetArguments();
310
328
  const executablePath = getExecutablePath();
311
- logger.info(`\u2705 Validated input: ${this.formatParsedInput(parsed)}`);
329
+ getLogger().info(`Validated input: ${this.formatParsedInput(parsed)}`);
312
330
  const identifier = parsed.type === "branch" ? parsed.branchName ?? "" : parsed.number ?? 0;
313
331
  const enableClaude = input.options.claude ?? (workflowConfig == null ? void 0 : workflowConfig.startAiAgent) ?? true;
314
332
  const enableCode = input.options.code ?? (workflowConfig == null ? void 0 : workflowConfig.startIde) ?? true;
315
333
  const enableDevServer = input.options.devServer ?? (workflowConfig == null ? void 0 : workflowConfig.startDevServer) ?? true;
316
334
  const enableTerminal = input.options.terminal ?? (workflowConfig == null ? void 0 : workflowConfig.startTerminal) ?? false;
317
- logger.debug("Final workflow config values:", {
335
+ getLogger().debug("Final workflow config values:", {
318
336
  enableClaude,
319
337
  enableCode,
320
338
  enableDevServer,
@@ -335,19 +353,31 @@ var StartCommand = class {
335
353
  ...executablePath && { executablePath }
336
354
  }
337
355
  });
338
- logger.success(`\u2705 Created loom: ${loom.id} at ${loom.path}`);
339
- logger.info(` Branch: ${loom.branch}`);
356
+ getLogger().success(`Created loom: ${loom.id} at ${loom.path}`);
357
+ getLogger().info(` Branch: ${loom.branch}`);
340
358
  if ((_c = loom.capabilities) == null ? void 0 : _c.includes("web")) {
341
- logger.info(` Port: ${loom.port}`);
359
+ getLogger().info(` Port: ${loom.port}`);
342
360
  }
343
361
  if ((_d = loom.issueData) == null ? void 0 : _d.title) {
344
- logger.info(` Title: ${loom.issueData.title}`);
362
+ getLogger().info(` Title: ${loom.issueData.title}`);
363
+ }
364
+ if (isJsonMode) {
365
+ return {
366
+ id: loom.id,
367
+ path: loom.path,
368
+ branch: loom.branch,
369
+ type: parsed.type,
370
+ identifier: loom.identifier,
371
+ ...loom.port !== void 0 && { port: loom.port },
372
+ ...((_e = loom.issueData) == null ? void 0 : _e.title) && { title: loom.issueData.title },
373
+ ...loom.capabilities && { capabilities: loom.capabilities }
374
+ };
345
375
  }
346
376
  } catch (error) {
347
377
  if (error instanceof Error) {
348
- logger.error(`\u274C ${error.message}`);
378
+ getLogger().error(`${error.message}`);
349
379
  } else {
350
- logger.error("\u274C An unknown error occurred");
380
+ getLogger().error("An unknown error occurred");
351
381
  }
352
382
  throw error;
353
383
  }
@@ -440,7 +470,7 @@ var StartCommand = class {
440
470
  }
441
471
  const pr = await this.issueTracker.fetchPR(parsed.number, repo);
442
472
  await this.issueTracker.validatePRState(pr);
443
- logger.debug(`Validated PR #${parsed.number}`);
473
+ getLogger().debug(`Validated PR #${parsed.number}`);
444
474
  break;
445
475
  }
446
476
  case "issue": {
@@ -449,7 +479,7 @@ var StartCommand = class {
449
479
  }
450
480
  const issue = await this.issueTracker.fetchIssue(parsed.number, repo);
451
481
  await this.issueTracker.validateIssueState(issue);
452
- logger.debug(`Validated issue #${parsed.number}`);
482
+ getLogger().debug(`Validated issue #${parsed.number}`);
453
483
  break;
454
484
  }
455
485
  case "branch": {
@@ -461,11 +491,11 @@ var StartCommand = class {
461
491
  "Invalid branch name. Use only letters, numbers, hyphens, underscores, and slashes"
462
492
  );
463
493
  }
464
- logger.debug(`Validated branch name: ${parsed.branchName}`);
494
+ getLogger().debug(`Validated branch name: ${parsed.branchName}`);
465
495
  break;
466
496
  }
467
497
  case "description": {
468
- logger.debug("Detected description input", {
498
+ getLogger().debug("Detected description input", {
469
499
  length: parsed.originalInput.length
470
500
  });
471
501
  break;
@@ -520,7 +550,7 @@ var StartCommand = class {
520
550
  if (!parentLoom) {
521
551
  return null;
522
552
  }
523
- logger.debug(`Detected parent loom: ${parentLoom.type} ${parentLoom.identifier} at ${parentLoom.path}`);
553
+ getLogger().debug(`Detected parent loom: ${parentLoom.type} ${parentLoom.identifier} at ${parentLoom.path}`);
524
554
  const result = {
525
555
  type: parentLoom.type,
526
556
  identifier: parentLoom.identifier,
@@ -534,12 +564,12 @@ var StartCommand = class {
534
564
  const databaseBranch = await loomManager.getDatabaseBranchForLoom(parentLoom.path);
535
565
  if (databaseBranch) {
536
566
  result.databaseBranch = databaseBranch;
537
- logger.debug(`Detected parent database branch: ${databaseBranch}`);
567
+ getLogger().debug(`Detected parent database branch: ${databaseBranch}`);
538
568
  }
539
569
  }
540
570
  return result;
541
571
  } catch (error) {
542
- logger.debug(`Failed to detect parent loom: ${error instanceof Error ? error.message : "Unknown error"}`);
572
+ getLogger().debug(`Failed to detect parent loom: ${error instanceof Error ? error.message : "Unknown error"}`);
543
573
  return null;
544
574
  }
545
575
  }
@@ -556,20 +586,23 @@ var AddIssueCommand = class {
556
586
  * 1. Validate description format
557
587
  * 2. Skip enhancement if body provided, otherwise enhance description with Claude Code
558
588
  * 3. Create GitHub issue
559
- * 4. Wait for keypress and open browser for review
560
- * 5. Return issue number
589
+ * 4. Wait for keypress and open browser for review (unless --json mode)
590
+ * 5. Return issue number or full result object (when --json)
561
591
  */
562
592
  async execute(input) {
563
593
  const description = capitalizeFirstLetter(input.description);
564
594
  const body = input.options.body ? capitalizeFirstLetter(input.options.body) : void 0;
565
- if (process.env.FORCE_FIRST_TIME_SETUP === "true" || await needsFirstRunSetup()) {
595
+ const isJsonMode = input.options.json === true;
596
+ if (!isJsonMode && (process.env.FORCE_FIRST_TIME_SETUP === "true" || await needsFirstRunSetup())) {
566
597
  await launchFirstRunSetup();
567
598
  }
568
599
  const settings = await this.settingsManager.loadSettings();
569
600
  let repo;
570
601
  if (this.enhancementService.issueTracker.providerName === "github" && await hasMultipleRemotes()) {
571
602
  repo = await getConfiguredRepoFromSettings(settings);
572
- logger.info(`Using GitHub repository: ${repo}`);
603
+ if (!isJsonMode) {
604
+ getLogger().info(`Using GitHub repository: ${repo}`);
605
+ }
573
606
  }
574
607
  if (!description || !this.enhancementService.validateDescription(description)) {
575
608
  throw new Error("Description is required and must be more than 30 characters with at least 3 words");
@@ -580,6 +613,15 @@ var AddIssueCommand = class {
580
613
  issueBody,
581
614
  repo
582
615
  );
616
+ if (isJsonMode) {
617
+ const resultData = {
618
+ url: result.url,
619
+ id: typeof result.number === "string" ? parseInt(result.number, 10) : result.number,
620
+ title: description,
621
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
622
+ };
623
+ return resultData;
624
+ }
583
625
  await this.enhancementService.waitForReviewAndOpen(result.number);
584
626
  return result.number;
585
627
  }
@@ -599,25 +641,31 @@ var EnhanceCommand = class {
599
641
  * 3. Load agent configurations
600
642
  * 4. Invoke Claude CLI with enhancer agent
601
643
  * 5. Parse response to determine outcome
602
- * 6. Handle browser interaction based on outcome
644
+ * 6. Handle browser interaction based on outcome (unless --json mode)
645
+ * 7. Return result object when --json mode
603
646
  */
604
647
  async execute(input) {
605
648
  const { issueNumber, options } = input;
606
649
  const { author } = options;
607
- if (process.env.FORCE_FIRST_TIME_SETUP === "true" || await needsFirstRunSetup()) {
650
+ const isJsonMode = options.json === true;
651
+ if (!isJsonMode && (process.env.FORCE_FIRST_TIME_SETUP === "true" || await needsFirstRunSetup())) {
608
652
  await launchFirstRunSetup();
609
653
  }
610
654
  const settings = await this.settingsManager.loadSettings();
611
655
  let repo;
612
656
  if (this.issueTracker.providerName === "github" && await hasMultipleRemotes()) {
613
657
  repo = await getConfiguredRepoFromSettings(settings);
614
- logger.info(`Using GitHub repository: ${repo}`);
658
+ if (!isJsonMode) {
659
+ getLogger().info(`Using GitHub repository: ${repo}`);
660
+ }
615
661
  }
616
662
  this.validateIssueNumber(issueNumber);
617
- logger.info(`Fetching issue #${issueNumber}...`);
663
+ if (!isJsonMode) {
664
+ getLogger().info(`Fetching issue #${issueNumber}...`);
665
+ }
618
666
  const issue = await this.issueTracker.fetchIssue(issueNumber, repo);
619
- logger.debug("Issue fetched successfully", { number: issue.number, title: issue.title });
620
- logger.debug("Loading agent configurations...");
667
+ getLogger().debug("Issue fetched successfully", { number: issue.number, title: issue.title });
668
+ getLogger().debug("Loading agent configurations...");
621
669
  const loadedAgents = await this.agentManager.loadAgents(settings);
622
670
  const agents = this.agentManager.formatForCli(loadedAgents);
623
671
  let mcpConfig;
@@ -626,7 +674,7 @@ var EnhanceCommand = class {
626
674
  try {
627
675
  const provider = this.issueTracker.providerName;
628
676
  mcpConfig = await generateIssueManagementMcpConfig("issue", repo, provider, settings);
629
- logger.debug("Generated MCP configuration for issue management:", { mcpConfig });
677
+ getLogger().debug("Generated MCP configuration for issue management:", { mcpConfig });
630
678
  allowedTools = [
631
679
  "mcp__issue_management__get_issue",
632
680
  "mcp__issue_management__get_comment",
@@ -634,11 +682,13 @@ var EnhanceCommand = class {
634
682
  "mcp__issue_management__update_comment"
635
683
  ];
636
684
  disallowedTools = ["Bash(gh api:*)"];
637
- logger.debug("Configured tool filtering for issue workflow", { allowedTools, disallowedTools });
685
+ getLogger().debug("Configured tool filtering for issue workflow", { allowedTools, disallowedTools });
638
686
  } catch (error) {
639
- logger.warn(`Failed to generate MCP config: ${error instanceof Error ? error.message : "Unknown error"}`);
687
+ getLogger().warn(`Failed to generate MCP config: ${error instanceof Error ? error.message : "Unknown error"}`);
688
+ }
689
+ if (!isJsonMode) {
690
+ getLogger().info("Invoking enhancer agent. This may take a moment...");
640
691
  }
641
- logger.info("Invoking enhancer agent. This may take a moment...");
642
692
  const prompt = this.constructPrompt(issueNumber, author);
643
693
  const response = await launchClaude(prompt, {
644
694
  headless: true,
@@ -649,16 +699,36 @@ var EnhanceCommand = class {
649
699
  ...disallowedTools && { disallowedTools }
650
700
  });
651
701
  const result = this.parseEnhancerResponse(response);
702
+ if (isJsonMode) {
703
+ const commentId = result.url ? this.extractCommentId(result.url) : 0;
704
+ const resultData = {
705
+ url: result.url ?? issue.url,
706
+ id: commentId,
707
+ title: issue.title,
708
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
709
+ enhanced: result.enhanced
710
+ };
711
+ return resultData;
712
+ }
652
713
  if (!result.enhanced) {
653
- logger.success("Issue already has thorough description. No enhancement needed.");
714
+ getLogger().success("Issue already has thorough description. No enhancement needed.");
654
715
  return;
655
716
  }
656
- logger.success(`Issue #${issueNumber} enhanced successfully!`);
657
- logger.info(`Enhanced specification available at: ${result.url}`);
717
+ getLogger().success(`Issue #${issueNumber} enhanced successfully!`);
718
+ getLogger().info(`Enhanced specification available at: ${result.url}`);
658
719
  if (!options.noBrowser && result.url) {
659
720
  await this.promptAndOpenBrowser(result.url);
660
721
  }
661
722
  }
723
+ /**
724
+ * Extract comment ID from GitHub comment URL
725
+ * @param url - GitHub comment URL (e.g., https://github.com/owner/repo/issues/123#issuecomment-456789)
726
+ * @returns Comment ID as number, or 0 if not found
727
+ */
728
+ extractCommentId(url) {
729
+ const match = url.match(/issuecomment-(\d+)/);
730
+ return (match == null ? void 0 : match[1]) ? parseInt(match[1], 10) : 0;
731
+ }
662
732
  /**
663
733
  * Validate that issue number is a valid positive integer
664
734
  */
@@ -702,7 +772,7 @@ IMPORTANT: When you create your analysis comment, tag @${author} in the "Questio
702
772
  throw new Error("No response from enhancer agent");
703
773
  }
704
774
  const trimmed = response.trim();
705
- logger.debug(`RESPONSE FROM ENHANCER AGENT: '${trimmed}'`);
775
+ getLogger().debug(`RESPONSE FROM ENHANCER AGENT: '${trimmed}'`);
706
776
  if (trimmed.toLowerCase().startsWith("permission denied:")) {
707
777
  const errorMessage = trimmed.substring("permission denied:".length).trim();
708
778
  throw new Error(`Permission denied: ${errorMessage}`);
@@ -727,18 +797,20 @@ IMPORTANT: When you create your analysis comment, tag @${author} in the "Questio
727
797
  "Press q to quit or any other key to view the enhanced issue in a web browser..."
728
798
  );
729
799
  if (key.toLowerCase() === "q") {
730
- logger.info("Skipping browser opening");
800
+ getLogger().info("Skipping browser opening");
731
801
  return;
732
802
  }
733
803
  await openBrowser(commentUrl);
734
804
  } catch (error) {
735
- logger.warn(`Failed to open browser: ${error instanceof Error ? error.message : "Unknown error"}`);
805
+ getLogger().warn(`Failed to open browser: ${error instanceof Error ? error.message : "Unknown error"}`);
736
806
  }
737
807
  }
738
808
  };
739
809
 
740
810
  // src/lib/ValidationRunner.ts
741
811
  var ValidationRunner = class {
812
+ constructor() {
813
+ }
742
814
  /**
743
815
  * Run all validations in sequence: typecheck → lint → test
744
816
  * Fails fast on first error
@@ -781,14 +853,22 @@ var ValidationRunner = class {
781
853
  }
782
854
  /**
783
855
  * Run typecheck validation
856
+ * Prefers 'compile' script over 'typecheck' if both exist
784
857
  */
785
858
  async runTypecheck(worktreePath, dryRun) {
786
859
  const stepStartTime = Date.now();
860
+ let scriptToRun = null;
787
861
  try {
788
862
  const pkgJson = await readPackageJson(worktreePath);
863
+ const hasCompileScript = hasScript(pkgJson, "compile");
789
864
  const hasTypecheckScript = hasScript(pkgJson, "typecheck");
790
- if (!hasTypecheckScript) {
791
- logger.debug("Skipping typecheck - no typecheck script found");
865
+ if (hasCompileScript) {
866
+ scriptToRun = "compile";
867
+ } else if (hasTypecheckScript) {
868
+ scriptToRun = "typecheck";
869
+ }
870
+ if (!scriptToRun) {
871
+ getLogger().debug("Skipping typecheck - no compile or typecheck script found");
792
872
  return {
793
873
  step: "typecheck",
794
874
  passed: true,
@@ -798,7 +878,7 @@ var ValidationRunner = class {
798
878
  }
799
879
  } catch (error) {
800
880
  if (error instanceof Error && error.message.includes("package.json not found")) {
801
- logger.debug("Skipping typecheck - no package.json found (non-Node.js project)");
881
+ getLogger().debug("Skipping typecheck - no package.json found (non-Node.js project)");
802
882
  return {
803
883
  step: "typecheck",
804
884
  passed: true,
@@ -810,42 +890,43 @@ var ValidationRunner = class {
810
890
  }
811
891
  const packageManager = await detectPackageManager(worktreePath);
812
892
  if (dryRun) {
813
- const command = packageManager === "npm" ? "npm run typecheck" : `${packageManager} typecheck`;
814
- logger.info(`[DRY RUN] Would run: ${command}`);
893
+ const command = packageManager === "npm" ? `npm run ${scriptToRun}` : `${packageManager} ${scriptToRun}`;
894
+ getLogger().info(`[DRY RUN] Would run: ${command}`);
815
895
  return {
816
- step: "typecheck",
896
+ step: scriptToRun,
817
897
  passed: true,
818
898
  skipped: false,
819
899
  duration: Date.now() - stepStartTime
820
900
  };
821
901
  }
822
- logger.info("Running typecheck...");
902
+ getLogger().info(`Running ${scriptToRun}...`);
823
903
  try {
824
- await runScript("typecheck", worktreePath, [], { quiet: true });
825
- logger.success("Typecheck passed");
904
+ await runScript(scriptToRun, worktreePath, [], { quiet: true });
905
+ getLogger().success(`${scriptToRun.charAt(0).toUpperCase() + scriptToRun.slice(1)} passed`);
826
906
  return {
827
- step: "typecheck",
907
+ step: scriptToRun,
828
908
  passed: true,
829
909
  skipped: false,
830
910
  duration: Date.now() - stepStartTime
831
911
  };
832
912
  } catch {
833
913
  const fixed = await this.attemptClaudeFix(
834
- "typecheck",
914
+ scriptToRun,
835
915
  worktreePath,
836
916
  packageManager
837
917
  );
838
918
  if (fixed) {
839
919
  return {
840
- step: "typecheck",
920
+ step: scriptToRun,
841
921
  passed: true,
842
922
  skipped: false,
843
923
  duration: Date.now() - stepStartTime
844
924
  };
845
925
  }
846
- const runCommand = packageManager === "npm" ? "npm run typecheck" : `${packageManager} typecheck`;
926
+ const runCommand = packageManager === "npm" ? `npm run ${scriptToRun}` : `${packageManager} ${scriptToRun}`;
927
+ const stepLabel = scriptToRun.charAt(0).toUpperCase() + scriptToRun.slice(1);
847
928
  throw new Error(
848
- `Error: Typecheck failed.
929
+ `Error: ${stepLabel} failed.
849
930
  Fix type errors before merging.
850
931
 
851
932
  Run '${runCommand}' to see detailed errors.`
@@ -861,7 +942,7 @@ Run '${runCommand}' to see detailed errors.`
861
942
  const pkgJson = await readPackageJson(worktreePath);
862
943
  const hasLintScript = hasScript(pkgJson, "lint");
863
944
  if (!hasLintScript) {
864
- logger.debug("Skipping lint - no lint script found");
945
+ getLogger().debug("Skipping lint - no lint script found");
865
946
  return {
866
947
  step: "lint",
867
948
  passed: true,
@@ -871,7 +952,7 @@ Run '${runCommand}' to see detailed errors.`
871
952
  }
872
953
  } catch (error) {
873
954
  if (error instanceof Error && error.message.includes("package.json not found")) {
874
- logger.debug("Skipping lint - no package.json found (non-Node.js project)");
955
+ getLogger().debug("Skipping lint - no package.json found (non-Node.js project)");
875
956
  return {
876
957
  step: "lint",
877
958
  passed: true,
@@ -884,7 +965,7 @@ Run '${runCommand}' to see detailed errors.`
884
965
  const packageManager = await detectPackageManager(worktreePath);
885
966
  if (dryRun) {
886
967
  const command = packageManager === "npm" ? "npm run lint" : `${packageManager} lint`;
887
- logger.info(`[DRY RUN] Would run: ${command}`);
968
+ getLogger().info(`[DRY RUN] Would run: ${command}`);
888
969
  return {
889
970
  step: "lint",
890
971
  passed: true,
@@ -892,10 +973,10 @@ Run '${runCommand}' to see detailed errors.`
892
973
  duration: Date.now() - stepStartTime
893
974
  };
894
975
  }
895
- logger.info("Running lint...");
976
+ getLogger().info("Running lint...");
896
977
  try {
897
978
  await runScript("lint", worktreePath, [], { quiet: true });
898
- logger.success("Linting passed");
979
+ getLogger().success("Linting passed");
899
980
  return {
900
981
  step: "lint",
901
982
  passed: true,
@@ -934,7 +1015,7 @@ Run '${runCommand}' to see detailed errors.`
934
1015
  const pkgJson = await readPackageJson(worktreePath);
935
1016
  const hasTestScript = hasScript(pkgJson, "test");
936
1017
  if (!hasTestScript) {
937
- logger.debug("Skipping tests - no test script found");
1018
+ getLogger().debug("Skipping tests - no test script found");
938
1019
  return {
939
1020
  step: "test",
940
1021
  passed: true,
@@ -944,7 +1025,7 @@ Run '${runCommand}' to see detailed errors.`
944
1025
  }
945
1026
  } catch (error) {
946
1027
  if (error instanceof Error && error.message.includes("package.json not found")) {
947
- logger.debug("Skipping tests - no package.json found (non-Node.js project)");
1028
+ getLogger().debug("Skipping tests - no package.json found (non-Node.js project)");
948
1029
  return {
949
1030
  step: "test",
950
1031
  passed: true,
@@ -957,7 +1038,7 @@ Run '${runCommand}' to see detailed errors.`
957
1038
  const packageManager = await detectPackageManager(worktreePath);
958
1039
  if (dryRun) {
959
1040
  const command = packageManager === "npm" ? "npm run test" : `${packageManager} test`;
960
- logger.info(`[DRY RUN] Would run: ${command}`);
1041
+ getLogger().info(`[DRY RUN] Would run: ${command}`);
961
1042
  return {
962
1043
  step: "test",
963
1044
  passed: true,
@@ -965,10 +1046,10 @@ Run '${runCommand}' to see detailed errors.`
965
1046
  duration: Date.now() - stepStartTime
966
1047
  };
967
1048
  }
968
- logger.info("Running tests...");
1049
+ getLogger().info("Running tests...");
969
1050
  try {
970
1051
  await runScript("test", worktreePath, [], { quiet: true });
971
- logger.success("Tests passed");
1052
+ getLogger().success("Tests passed");
972
1053
  return {
973
1054
  step: "test",
974
1055
  passed: true,
@@ -1002,7 +1083,7 @@ Run '${runCommand}' to see detailed errors.`
1002
1083
  * Attempt to fix validation errors using Claude
1003
1084
  * Pattern based on MergeManager.attemptClaudeConflictResolution
1004
1085
  *
1005
- * @param validationType - Type of validation that failed ('typecheck' | 'lint' | 'test')
1086
+ * @param validationType - Type of validation that failed ('compile' | 'typecheck' | 'lint' | 'test')
1006
1087
  * @param worktreePath - Path to the worktree
1007
1088
  * @param packageManager - Detected package manager
1008
1089
  * @returns true if Claude fixed the issue, false otherwise
@@ -1010,13 +1091,13 @@ Run '${runCommand}' to see detailed errors.`
1010
1091
  async attemptClaudeFix(validationType, worktreePath, packageManager) {
1011
1092
  const isClaudeAvailable = await detectClaudeCli();
1012
1093
  if (!isClaudeAvailable) {
1013
- logger.debug("Claude CLI not available, skipping auto-fix");
1094
+ getLogger().debug("Claude CLI not available, skipping auto-fix");
1014
1095
  return false;
1015
1096
  }
1016
1097
  const validationCommand = this.getValidationCommand(validationType, packageManager);
1017
1098
  const prompt = this.getClaudePrompt(validationType, validationCommand);
1018
1099
  const validationTypeCapitalized = validationType.charAt(0).toUpperCase() + validationType.slice(1);
1019
- logger.info(`Launching Claude to help fix ${validationTypeCapitalized} errors...`);
1100
+ getLogger().info(`Launching Claude to help fix ${validationTypeCapitalized} errors...`);
1020
1101
  try {
1021
1102
  await launchClaude(prompt, {
1022
1103
  addDir: worktreePath,
@@ -1027,17 +1108,17 @@ Run '${runCommand}' to see detailed errors.`
1027
1108
  model: "sonnet"
1028
1109
  // Use Sonnet model
1029
1110
  });
1030
- logger.info(`Re-running ${validationTypeCapitalized} after Claude's fixes...`);
1111
+ getLogger().info(`Re-running ${validationTypeCapitalized} after Claude's fixes...`);
1031
1112
  try {
1032
1113
  await runScript(validationType, worktreePath, [], { quiet: true });
1033
- logger.success(`${validationTypeCapitalized} passed after Claude auto-fix`);
1114
+ getLogger().success(`${validationTypeCapitalized} passed after Claude auto-fix`);
1034
1115
  return true;
1035
1116
  } catch {
1036
- logger.warn(`${validationTypeCapitalized} still failing after Claude's help`);
1117
+ getLogger().warn(`${validationTypeCapitalized} still failing after Claude's help`);
1037
1118
  return false;
1038
1119
  }
1039
1120
  } catch (error) {
1040
- logger.warn("Claude auto-fix failed", {
1121
+ getLogger().warn("Claude auto-fix failed", {
1041
1122
  error: error instanceof Error ? error.message : String(error)
1042
1123
  });
1043
1124
  return false;
@@ -1058,8 +1139,9 @@ Run '${runCommand}' to see detailed errors.`
1058
1139
  */
1059
1140
  getClaudePrompt(validationType, validationCommand) {
1060
1141
  switch (validationType) {
1142
+ case "compile":
1061
1143
  case "typecheck":
1062
- return `There are TypeScript errors in this codebase. Please analyze the typecheck output, identify all type errors, and fix them. Run '${validationCommand}' to see the errors, then make the necessary code changes to resolve all type issues. When you are done, tell the user to quit using /exit to continue the validation process.`;
1144
+ return `There are TypeScript errors in this codebase. Please analyze the ${validationType} output, identify all type errors, and fix them. Run '${validationCommand}' to see the errors, then make the necessary code changes to resolve all type issues. When you are done, tell the user to quit using /exit to continue the validation process.`;
1063
1145
  case "lint":
1064
1146
  return `There are ESLint errors in this codebase. Please analyze the linting output, identify all linting issues, and fix them. Run '${validationCommand}' to see the errors, then make the necessary code changes to resolve all linting issues. Focus on code quality, consistency, and following the project's linting rules. When you are done, tell the user to quit using /exit to continue the validation process.`;
1065
1147
  case "test":
@@ -1068,6 +1150,24 @@ Run '${runCommand}' to see detailed errors.`
1068
1150
  }
1069
1151
  };
1070
1152
 
1153
+ // src/utils/vscode.ts
1154
+ import { execa } from "execa";
1155
+ function isRunningInVSCode() {
1156
+ return process.env.TERM_PROGRAM === "vscode";
1157
+ }
1158
+ async function isVSCodeAvailable() {
1159
+ try {
1160
+ await execa("command", ["-v", "code"], {
1161
+ shell: true,
1162
+ timeout: 5e3
1163
+ });
1164
+ return true;
1165
+ } catch (error) {
1166
+ logger.debug("VSCode CLI not available", { error });
1167
+ return false;
1168
+ }
1169
+ }
1170
+
1071
1171
  // src/types/index.ts
1072
1172
  var UserAbortedCommitError = class extends Error {
1073
1173
  constructor(message = "User aborted the commit") {
@@ -1077,7 +1177,12 @@ var UserAbortedCommitError = class extends Error {
1077
1177
  };
1078
1178
 
1079
1179
  // src/lib/CommitManager.ts
1180
+ import { writeFile, readFile as readFile2, unlink } from "fs/promises";
1181
+ import { join } from "path";
1182
+ import { execa as execa2 } from "execa";
1080
1183
  var CommitManager = class {
1184
+ constructor() {
1185
+ }
1081
1186
  /**
1082
1187
  * Detect uncommitted changes in a worktree
1083
1188
  * Parses git status --porcelain output into structured GitStatus
@@ -1106,11 +1211,11 @@ var CommitManager = class {
1106
1211
  */
1107
1212
  async commitChanges(worktreePath, options) {
1108
1213
  if (options.dryRun) {
1109
- logger.info("[DRY RUN] Would run: git add -A");
1110
- logger.info("[DRY RUN] Would generate commit message with Claude (if available)");
1214
+ getLogger().info("[DRY RUN] Would run: git add -A");
1215
+ getLogger().info("[DRY RUN] Would generate commit message with Claude (if available)");
1111
1216
  const fallbackMessage = this.generateFallbackMessage(options);
1112
1217
  const verifyFlag = options.skipVerify ? " --no-verify" : "";
1113
- logger.info(`[DRY RUN] Would commit with message${verifyFlag}: ${fallbackMessage}`);
1218
+ getLogger().info(`[DRY RUN] Would commit with message${verifyFlag}: ${fallbackMessage}`);
1114
1219
  return;
1115
1220
  }
1116
1221
  await executeGitCommand(["add", "-A"], { cwd: worktreePath });
@@ -1119,12 +1224,12 @@ var CommitManager = class {
1119
1224
  try {
1120
1225
  message = await this.generateClaudeCommitMessage(worktreePath, options.issueNumber);
1121
1226
  } catch (error) {
1122
- logger.debug("Claude commit message generation failed, using fallback", { error });
1227
+ getLogger().debug("Claude commit message generation failed, using fallback", { error });
1123
1228
  }
1124
1229
  }
1125
1230
  message ??= this.generateFallbackMessage(options);
1126
1231
  if (options.skipVerify) {
1127
- logger.warn("\u26A0\uFE0F Skipping pre-commit hooks (--no-verify configured in settings)");
1232
+ getLogger().warn("Skipping pre-commit hooks (--no-verify configured in settings)");
1128
1233
  }
1129
1234
  try {
1130
1235
  if (options.noReview || options.message) {
@@ -1145,17 +1250,21 @@ var CommitManager = class {
1145
1250
  }
1146
1251
  await executeGitCommand(commitArgs, { cwd: worktreePath });
1147
1252
  } else {
1148
- logger.info("Opening git editor for commit message review...");
1149
- const commitArgs = ["commit", "-e", "-m", message];
1150
- if (options.skipVerify) {
1151
- commitArgs.push("--no-verify");
1253
+ getLogger().info("Opening editor for commit message review...");
1254
+ if (isRunningInVSCode() && await isVSCodeAvailable()) {
1255
+ await this.commitWithVSCodeEditor(worktreePath, message, options);
1256
+ } else {
1257
+ const commitArgs = ["commit", "-e", "-m", message];
1258
+ if (options.skipVerify) {
1259
+ commitArgs.push("--no-verify");
1260
+ }
1261
+ await executeGitCommand(commitArgs, {
1262
+ cwd: worktreePath,
1263
+ stdio: "inherit",
1264
+ timeout: 3e5
1265
+ // 5 minutes for interactive editing
1266
+ });
1152
1267
  }
1153
- await executeGitCommand(commitArgs, {
1154
- cwd: worktreePath,
1155
- stdio: "inherit",
1156
- timeout: 3e5
1157
- // 5 minutes for interactive editing
1158
- });
1159
1268
  }
1160
1269
  }
1161
1270
  } catch (error) {
@@ -1163,12 +1272,50 @@ var CommitManager = class {
1163
1272
  throw error;
1164
1273
  }
1165
1274
  if (error instanceof Error && error.message.includes("nothing to commit")) {
1166
- logger.info("No changes to commit");
1275
+ getLogger().info("No changes to commit");
1167
1276
  return;
1168
1277
  }
1169
1278
  throw error;
1170
1279
  }
1171
1280
  }
1281
+ /**
1282
+ * Commit with VSCode editor - handles file creation, editing, and commit ourselves
1283
+ * to ensure the file opens in the current VSCode window (preserves IPC context)
1284
+ */
1285
+ async commitWithVSCodeEditor(worktreePath, message, options) {
1286
+ const commitMsgPath = join(worktreePath, ".COMMIT_EDITMSG");
1287
+ const initialContent = `${message}
1288
+
1289
+ # Please enter the commit message for your changes. Lines starting
1290
+ # with '#' will be ignored, and an empty message aborts the commit.
1291
+ #
1292
+ # Save and close the file to complete the commit.
1293
+ `;
1294
+ await writeFile(commitMsgPath, initialContent, "utf-8");
1295
+ try {
1296
+ getLogger().debug(`Opening commit message in VSCode: ${commitMsgPath}`);
1297
+ await execa2("code", ["--wait", commitMsgPath], {
1298
+ cwd: worktreePath,
1299
+ stdio: "inherit"
1300
+ });
1301
+ const editedContent = await readFile2(commitMsgPath, "utf-8");
1302
+ const finalMessage = editedContent.split("\n").filter((line) => !line.startsWith("#")).join("\n").trim();
1303
+ if (!finalMessage) {
1304
+ throw new UserAbortedCommitError();
1305
+ }
1306
+ const commitArgs = ["commit", "-F", commitMsgPath];
1307
+ if (options.skipVerify) {
1308
+ commitArgs.push("--no-verify");
1309
+ }
1310
+ await writeFile(commitMsgPath, finalMessage, "utf-8");
1311
+ await executeGitCommand(commitArgs, { cwd: worktreePath });
1312
+ } finally {
1313
+ try {
1314
+ await unlink(commitMsgPath);
1315
+ } catch {
1316
+ }
1317
+ }
1318
+ }
1172
1319
  /**
1173
1320
  * Generate simple fallback commit message when Claude unavailable
1174
1321
  * Used as fallback for Claude-powered commit messages
@@ -1222,61 +1369,62 @@ Fixes #${options.issueNumber}`;
1222
1369
  */
1223
1370
  async generateClaudeCommitMessage(worktreePath, issueNumber) {
1224
1371
  const startTime = Date.now();
1225
- logger.info("Starting Claude commit message generation...", {
1372
+ getLogger().info("Starting Claude commit message generation...", {
1226
1373
  worktreePath: worktreePath.split("/").pop(),
1227
1374
  // Just show the folder name for privacy
1228
1375
  issueNumber
1229
1376
  });
1230
- logger.debug("Checking Claude CLI availability...");
1377
+ getLogger().debug("Checking Claude CLI availability...");
1231
1378
  const isClaudeAvailable = await detectClaudeCli();
1232
1379
  if (!isClaudeAvailable) {
1233
- logger.info("Claude CLI not available, skipping Claude commit message generation");
1380
+ getLogger().info("Claude CLI not available, skipping Claude commit message generation");
1234
1381
  return null;
1235
1382
  }
1236
- logger.debug("Claude CLI is available");
1237
- logger.debug("Building commit message prompt...");
1383
+ getLogger().debug("Claude CLI is available");
1384
+ getLogger().debug("Building commit message prompt...");
1238
1385
  const prompt = this.buildCommitMessagePrompt(issueNumber);
1239
- logger.debug("Prompt built", { promptLength: prompt.length });
1240
- logger.debug("Claude prompt content:", {
1386
+ getLogger().debug("Prompt built", { promptLength: prompt.length });
1387
+ getLogger().debug("Claude prompt content:", {
1241
1388
  prompt,
1242
1389
  truncatedPreview: prompt.substring(0, 500) + (prompt.length > 500 ? "...[truncated]" : "")
1243
1390
  });
1244
1391
  try {
1245
- logger.info("Calling Claude CLI for commit message generation...");
1392
+ getLogger().info("Calling Claude CLI for commit message generation...");
1246
1393
  const claudeStartTime = Date.now();
1247
1394
  const claudeOptions = {
1248
1395
  headless: true,
1249
1396
  addDir: worktreePath,
1250
1397
  model: "claude-haiku-4-5-20251001",
1251
1398
  // Fast, cost-effective model
1252
- timeout: 12e4
1399
+ timeout: 12e4,
1253
1400
  // 120 second timeout
1401
+ appendSystemPrompt: "Output only the requested content. Never include preamble, analysis, or meta-commentary. Your response is used verbatim."
1254
1402
  };
1255
- logger.debug("Claude CLI call parameters:", {
1403
+ getLogger().debug("Claude CLI call parameters:", {
1256
1404
  options: claudeOptions,
1257
1405
  worktreePathForAnalysis: worktreePath,
1258
1406
  addDirContents: "Will include entire worktree directory for analysis"
1259
1407
  });
1260
1408
  const result = await launchClaude(prompt, claudeOptions);
1261
1409
  const claudeDuration = Date.now() - claudeStartTime;
1262
- logger.debug("Claude API call completed", { duration: `${claudeDuration}ms` });
1410
+ getLogger().debug("Claude API call completed", { duration: `${claudeDuration}ms` });
1263
1411
  if (typeof result !== "string") {
1264
- logger.warn("Claude returned non-string result", { resultType: typeof result });
1412
+ getLogger().warn("Claude returned non-string result", { resultType: typeof result });
1265
1413
  return null;
1266
1414
  }
1267
- logger.debug("Raw Claude output received", {
1415
+ getLogger().debug("Raw Claude output received", {
1268
1416
  outputLength: result.length,
1269
1417
  preview: result.substring(0, 200) + (result.length > 200 ? "..." : "")
1270
1418
  });
1271
- logger.debug("Sanitizing Claude output...");
1419
+ getLogger().debug("Sanitizing Claude output...");
1272
1420
  const sanitized = this.sanitizeClaudeOutput(result);
1273
- logger.debug("Output sanitized", {
1421
+ getLogger().debug("Output sanitized", {
1274
1422
  originalLength: result.length,
1275
1423
  sanitizedLength: sanitized.length,
1276
1424
  sanitized: sanitized.substring(0, 200) + (sanitized.length > 200 ? "..." : "")
1277
1425
  });
1278
1426
  if (!sanitized) {
1279
- logger.warn("Claude returned empty message after sanitization");
1427
+ getLogger().warn("Claude returned empty message after sanitization");
1280
1428
  return null;
1281
1429
  }
1282
1430
  let finalMessage = sanitized;
@@ -1285,13 +1433,13 @@ Fixes #${options.issueNumber}`;
1285
1433
  finalMessage = `${finalMessage}
1286
1434
 
1287
1435
  Fixes #${issueNumber}`;
1288
- logger.debug(`Added "Fixes #${issueNumber}" trailer to commit message`);
1436
+ getLogger().debug(`Added "Fixes #${issueNumber}" trailer to commit message`);
1289
1437
  } else {
1290
- logger.debug(`"Fixes #${issueNumber}" already present in commit message`);
1438
+ getLogger().debug(`"Fixes #${issueNumber}" already present in commit message`);
1291
1439
  }
1292
1440
  }
1293
1441
  const totalDuration = Date.now() - startTime;
1294
- logger.info("Claude commit message generated successfully", {
1442
+ getLogger().info("Claude commit message generated successfully", {
1295
1443
  message: finalMessage,
1296
1444
  totalDuration: `${totalDuration}ms`,
1297
1445
  claudeApiDuration: `${claudeDuration}ms`
@@ -1301,12 +1449,12 @@ Fixes #${issueNumber}`;
1301
1449
  const totalDuration = Date.now() - startTime;
1302
1450
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
1303
1451
  if (errorMessage.includes("timed out") || errorMessage.includes("timeout")) {
1304
- logger.warn("Claude commit message generation timed out after 45 seconds", {
1452
+ getLogger().warn("Claude commit message generation timed out after 45 seconds", {
1305
1453
  totalDuration: `${totalDuration}ms`,
1306
1454
  worktreePath: worktreePath.split("/").pop()
1307
1455
  });
1308
1456
  } else {
1309
- logger.warn("Failed to generate commit message with Claude", {
1457
+ getLogger().warn("Failed to generate commit message with Claude", {
1310
1458
  error: errorMessage,
1311
1459
  totalDuration: `${totalDuration}ms`,
1312
1460
  worktreePath: worktreePath.split("/").pop()
@@ -1418,7 +1566,7 @@ var BuildRunner = class {
1418
1566
  const pkgJson = await readPackageJson(buildPath);
1419
1567
  const hasBuildScript = hasScript(pkgJson, "build");
1420
1568
  if (!hasBuildScript) {
1421
- logger.debug("Skipping build - no build script found");
1569
+ getLogger().debug("Skipping build - no build script found");
1422
1570
  return {
1423
1571
  success: true,
1424
1572
  skipped: true,
@@ -1428,7 +1576,7 @@ var BuildRunner = class {
1428
1576
  }
1429
1577
  } catch (error) {
1430
1578
  if (error instanceof Error && error.message.includes("package.json not found")) {
1431
- logger.debug("Skipping build - no package.json found (non-Node.js project)");
1579
+ getLogger().debug("Skipping build - no package.json found (non-Node.js project)");
1432
1580
  return {
1433
1581
  success: true,
1434
1582
  skipped: true,
@@ -1441,7 +1589,7 @@ var BuildRunner = class {
1441
1589
  const capabilities = await this.capabilityDetector.detectCapabilities(buildPath);
1442
1590
  const isCLIProject = capabilities.capabilities.includes("cli");
1443
1591
  if (!isCLIProject) {
1444
- logger.debug("Skipping build - not a CLI project (no bin field)");
1592
+ getLogger().debug("Skipping build - not a CLI project (no bin field)");
1445
1593
  return {
1446
1594
  success: true,
1447
1595
  skipped: true,
@@ -1452,17 +1600,17 @@ var BuildRunner = class {
1452
1600
  const packageManager = await detectPackageManager(buildPath);
1453
1601
  if (options.dryRun) {
1454
1602
  const command = packageManager === "npm" ? "npm run build" : `${packageManager} build`;
1455
- logger.info(`[DRY RUN] Would run: ${command}`);
1603
+ getLogger().info(`[DRY RUN] Would run: ${command}`);
1456
1604
  return {
1457
1605
  success: true,
1458
1606
  skipped: false,
1459
1607
  duration: Date.now() - startTime
1460
1608
  };
1461
1609
  }
1462
- logger.info("Running build...");
1610
+ getLogger().info("Running build...");
1463
1611
  try {
1464
1612
  await runScript("build", buildPath, [], { quiet: true });
1465
- logger.success("Build completed successfully");
1613
+ getLogger().success("Build completed successfully");
1466
1614
  return {
1467
1615
  success: true,
1468
1616
  skipped: false,
@@ -1502,7 +1650,7 @@ var PRManager = class {
1502
1650
  }
1503
1651
  return null;
1504
1652
  } catch (error) {
1505
- logger.debug("Error checking for existing PR", { error });
1653
+ getLogger().debug("Error checking for existing PR", { error });
1506
1654
  return null;
1507
1655
  }
1508
1656
  }
@@ -1529,7 +1677,7 @@ var PRManager = class {
1529
1677
  }
1530
1678
  }
1531
1679
  } catch (error) {
1532
- logger.debug("Claude PR body generation failed, using template", { error });
1680
+ getLogger().debug("Claude PR body generation failed, using template", { error });
1533
1681
  }
1534
1682
  }
1535
1683
  let body = "This PR contains changes from the iloom workflow.\n\n";
@@ -1647,7 +1795,7 @@ Start your response immediately with the PR body text.
1647
1795
  const originRemote = remotes.find((r) => r.name === "origin");
1648
1796
  if (originRemote) {
1649
1797
  headValue = `${originRemote.owner}:${branchName}`;
1650
- logger.debug(`Fork workflow detected, using head: ${headValue}`);
1798
+ getLogger().debug(`Fork workflow detected, using head: ${headValue}`);
1651
1799
  }
1652
1800
  }
1653
1801
  const args = ["pr", "create", "--head", headValue, "--title", title, "--body", body, "--base", baseBranch];
@@ -1686,9 +1834,9 @@ Then retry: il finish`
1686
1834
  async openPRInBrowser(url) {
1687
1835
  try {
1688
1836
  await openBrowser(url);
1689
- logger.debug("Opened PR in browser", { url });
1837
+ getLogger().debug("Opened PR in browser", { url });
1690
1838
  } catch (error) {
1691
- logger.warn("Failed to open PR in browser", { error });
1839
+ getLogger().warn("Failed to open PR in browser", { error });
1692
1840
  }
1693
1841
  }
1694
1842
  /**
@@ -1704,7 +1852,7 @@ Then retry: il finish`
1704
1852
  async createOrOpenPR(branchName, title, issueNumber, baseBranch, worktreePath, openInBrowser) {
1705
1853
  const existingPR = await this.checkForExistingPR(branchName, worktreePath);
1706
1854
  if (existingPR) {
1707
- logger.info(`Pull request already exists: ${existingPR.url}`);
1855
+ getLogger().info(`Pull request already exists: ${existingPR.url}`);
1708
1856
  if (openInBrowser) {
1709
1857
  await this.openPRInBrowser(existingPR.url);
1710
1858
  }
@@ -1715,7 +1863,7 @@ Then retry: il finish`
1715
1863
  };
1716
1864
  }
1717
1865
  const body = await this.generatePRBody(issueNumber, worktreePath);
1718
- logger.info("Creating pull request...");
1866
+ getLogger().info("Creating pull request...");
1719
1867
  const url = await this.createPR(branchName, title, body, baseBranch, worktreePath);
1720
1868
  const prNumber = this.extractPRNumberFromUrl(url);
1721
1869
  if (openInBrowser) {
@@ -1747,10 +1895,10 @@ var FinishCommand = class {
1747
1895
  constructor(issueTracker, gitWorktreeManager, validationRunner, commitManager, mergeManager, identifierParser, resourceCleanup, buildRunner, settingsManager, loomManager) {
1748
1896
  const envResult = loadEnvIntoProcess();
1749
1897
  if (envResult.error) {
1750
- logger.debug(`Environment loading warning: ${envResult.error.message}`);
1898
+ getLogger().debug(`Environment loading warning: ${envResult.error.message}`);
1751
1899
  }
1752
1900
  if (envResult.parsed) {
1753
- logger.debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`);
1901
+ getLogger().debug(`Loaded ${Object.keys(envResult.parsed).length} environment variables`);
1754
1902
  }
1755
1903
  this.issueTracker = issueTracker;
1756
1904
  this.gitWorktreeManager = gitWorktreeManager ?? new GitWorktreeManager();
@@ -1781,7 +1929,7 @@ var FinishCommand = class {
1781
1929
  const neonProvider = createNeonProviderFromSettings(settings);
1782
1930
  const databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName);
1783
1931
  const cliIsolationManager = new CLIIsolationManager();
1784
- const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-A77VI6AI.js");
1932
+ const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-TOM2KAUT.js");
1785
1933
  this.loomManager ??= new LoomManager(
1786
1934
  this.gitWorktreeManager,
1787
1935
  this.issueTracker,
@@ -1826,12 +1974,12 @@ var FinishCommand = class {
1826
1974
  targetBranch = worktree == null ? void 0 : worktree.branch;
1827
1975
  }
1828
1976
  if (!targetBranch) {
1829
- logger.debug(`Cannot determine target branch for child loom check`);
1977
+ getLogger().debug(`Cannot determine target branch for child loom check`);
1830
1978
  return;
1831
1979
  }
1832
1980
  const hasChildLooms = await this.loomManager.checkAndWarnChildLooms(targetBranch);
1833
1981
  if (hasChildLooms) {
1834
- logger.error("Cannot finish loom while child looms exist. Please finish child looms first.");
1982
+ getLogger().error("Cannot finish loom while child looms exist. Please 'finish' or 'cleanup' child looms first.");
1835
1983
  process.exit(1);
1836
1984
  }
1837
1985
  }
@@ -1839,42 +1987,53 @@ var FinishCommand = class {
1839
1987
  * Main entry point for finish command
1840
1988
  */
1841
1989
  async execute(input) {
1842
- var _a;
1843
- try {
1844
- const settings = await this.settingsManager.loadSettings();
1845
- let repo;
1846
- const needsRepo = ((_a = settings.mergeBehavior) == null ? void 0 : _a.mode) === "github-pr" || this.issueTracker.providerName === "github";
1847
- if (needsRepo && await hasMultipleRemotes()) {
1848
- repo = await getConfiguredRepoFromSettings(settings);
1849
- logger.info(`Using GitHub repository: ${repo}`);
1850
- }
1851
- const parsed = await this.parseInput(input.identifier, input.options);
1852
- await this.checkForChildLooms(parsed);
1853
- const worktrees = await this.validateInput(parsed, input.options, repo);
1854
- logger.info(`Validated input: ${this.formatParsedInput(parsed)}`);
1855
- const worktree = worktrees[0];
1856
- if (!worktree) {
1857
- throw new Error("No worktree found");
1858
- }
1859
- if (parsed.type === "pr") {
1860
- if (!parsed.number) {
1861
- throw new Error("Invalid PR number");
1862
- }
1863
- if (!this.issueTracker.supportsPullRequests || !this.issueTracker.fetchPR) {
1864
- throw new Error("Issue tracker does not support pull requests");
1865
- }
1866
- const pr = await this.issueTracker.fetchPR(parsed.number, repo);
1867
- await this.executePRWorkflow(parsed, input.options, worktree, pr);
1868
- } else {
1869
- await this.executeIssueWorkflow(parsed, input.options, worktree);
1990
+ var _a, _b;
1991
+ const isJsonMode = input.options.json === true;
1992
+ const result = {
1993
+ success: false,
1994
+ type: "issue",
1995
+ identifier: "",
1996
+ dryRun: input.options.dryRun ?? false,
1997
+ operations: []
1998
+ };
1999
+ if (isJsonMode) {
2000
+ const settings2 = await this.settingsManager.loadSettings();
2001
+ if (((_a = settings2.mergeBehavior) == null ? void 0 : _a.mode) === "github-pr" && input.options.cleanup === void 0) {
2002
+ throw new Error("JSON mode with github-pr workflow requires --cleanup or --no-cleanup flag. Use: il finish --json --cleanup <identifier>");
1870
2003
  }
1871
- } catch (error) {
1872
- if (error instanceof Error) {
1873
- logger.error(`${error.message}`);
1874
- } else {
1875
- logger.error("An unknown error occurred");
2004
+ }
2005
+ const settings = await this.settingsManager.loadSettings();
2006
+ let repo;
2007
+ const needsRepo = ((_b = settings.mergeBehavior) == null ? void 0 : _b.mode) === "github-pr" || this.issueTracker.providerName === "github";
2008
+ if (needsRepo && await hasMultipleRemotes()) {
2009
+ repo = await getConfiguredRepoFromSettings(settings);
2010
+ getLogger().info(`Using GitHub repository: ${repo}`);
2011
+ }
2012
+ const parsed = await this.parseInput(input.identifier, input.options);
2013
+ result.type = parsed.type;
2014
+ result.identifier = parsed.number ?? parsed.branchName ?? "";
2015
+ await this.checkForChildLooms(parsed);
2016
+ const worktrees = await this.validateInput(parsed, input.options, repo);
2017
+ getLogger().info(`Validated input: ${this.formatParsedInput(parsed)}`);
2018
+ const worktree = worktrees[0];
2019
+ if (!worktree) {
2020
+ throw new Error("No worktree found");
2021
+ }
2022
+ if (parsed.type === "pr") {
2023
+ if (!parsed.number) {
2024
+ throw new Error("Invalid PR number");
1876
2025
  }
1877
- throw error;
2026
+ if (!this.issueTracker.supportsPullRequests || !this.issueTracker.fetchPR) {
2027
+ throw new Error("Issue tracker does not support pull requests");
2028
+ }
2029
+ const pr = await this.issueTracker.fetchPR(parsed.number, repo);
2030
+ await this.executePRWorkflow(parsed, input.options, worktree, pr, result);
2031
+ } else {
2032
+ await this.executeIssueWorkflow(parsed, input.options, worktree, result);
2033
+ }
2034
+ result.success = true;
2035
+ if (isJsonMode) {
2036
+ return result;
1878
2037
  }
1879
2038
  }
1880
2039
  /**
@@ -1937,7 +2096,7 @@ var FinishCommand = class {
1937
2096
  const prMatch = currentDir.match(prPattern);
1938
2097
  if (prMatch == null ? void 0 : prMatch[1]) {
1939
2098
  const prNumber = parseInt(prMatch[1], 10);
1940
- logger.debug(`Auto-detected PR #${prNumber} from directory: ${currentDir}`);
2099
+ getLogger().debug(`Auto-detected PR #${prNumber} from directory: ${currentDir}`);
1941
2100
  return {
1942
2101
  type: "pr",
1943
2102
  number: prNumber,
@@ -1947,7 +2106,7 @@ var FinishCommand = class {
1947
2106
  }
1948
2107
  const issueNumber = extractIssueNumber(currentDir);
1949
2108
  if (issueNumber !== null) {
1950
- logger.debug(
2109
+ getLogger().debug(
1951
2110
  `Auto-detected issue #${issueNumber} from directory: ${currentDir}`
1952
2111
  );
1953
2112
  return {
@@ -1966,7 +2125,7 @@ var FinishCommand = class {
1966
2125
  }
1967
2126
  const branchIssueNumber = extractIssueNumber(currentBranch);
1968
2127
  if (branchIssueNumber !== null) {
1969
- logger.debug(
2128
+ getLogger().debug(
1970
2129
  `Auto-detected issue #${branchIssueNumber} from branch: ${currentBranch}`
1971
2130
  );
1972
2131
  return {
@@ -1996,7 +2155,7 @@ var FinishCommand = class {
1996
2155
  throw new Error("Issue tracker does not support pull requests");
1997
2156
  }
1998
2157
  const pr = await this.issueTracker.fetchPR(parsed.number);
1999
- logger.debug(`Validated PR #${parsed.number} (state: ${pr.state})`);
2158
+ getLogger().debug(`Validated PR #${parsed.number} (state: ${pr.state})`);
2000
2159
  return await this.findWorktreeForIdentifier(parsed);
2001
2160
  }
2002
2161
  case "issue": {
@@ -2009,7 +2168,7 @@ var FinishCommand = class {
2009
2168
  `Issue #${parsed.number} is closed. Use --force to finish anyway.`
2010
2169
  );
2011
2170
  }
2012
- logger.debug(`Validated issue #${parsed.number} (state: ${issue.state})`);
2171
+ getLogger().debug(`Validated issue #${parsed.number} (state: ${issue.state})`);
2013
2172
  return await this.findWorktreeForIdentifier(parsed);
2014
2173
  }
2015
2174
  case "branch": {
@@ -2021,7 +2180,7 @@ var FinishCommand = class {
2021
2180
  "Invalid branch name. Use only letters, numbers, hyphens, underscores, and slashes"
2022
2181
  );
2023
2182
  }
2024
- logger.debug(`Validated branch name: ${parsed.branchName}`);
2183
+ getLogger().debug(`Validated branch name: ${parsed.branchName}`);
2025
2184
  return await this.findWorktreeForIdentifier(parsed);
2026
2185
  }
2027
2186
  default: {
@@ -2080,7 +2239,7 @@ var FinishCommand = class {
2080
2239
  `No worktree found for ${this.formatParsedInput(parsed)}. Use 'il list' to see available worktrees.`
2081
2240
  );
2082
2241
  }
2083
- logger.debug(`Found worktree: ${worktree.path}`);
2242
+ getLogger().debug(`Found worktree: ${worktree.path}`);
2084
2243
  return [worktree];
2085
2244
  }
2086
2245
  /**
@@ -2109,23 +2268,38 @@ var FinishCommand = class {
2109
2268
  * Execute workflow for issues and branches (merge into main)
2110
2269
  * This is the traditional workflow: validate → commit → rebase → merge → cleanup
2111
2270
  */
2112
- async executeIssueWorkflow(parsed, options, worktree) {
2271
+ async executeIssueWorkflow(parsed, options, worktree, result) {
2113
2272
  var _a, _b;
2114
2273
  if (!options.dryRun) {
2115
- logger.info("Running pre-merge validations...");
2274
+ getLogger().info("Running pre-merge validations...");
2116
2275
  await this.validationRunner.runValidations(worktree.path, {
2117
2276
  dryRun: options.dryRun ?? false
2118
2277
  });
2119
- logger.success("All validations passed");
2278
+ getLogger().success("All validations passed");
2279
+ result.operations.push({
2280
+ type: "validation",
2281
+ message: "Pre-merge validations passed",
2282
+ success: true
2283
+ });
2120
2284
  } else {
2121
- logger.info("[DRY RUN] Would run pre-merge validations");
2285
+ getLogger().info("[DRY RUN] Would run pre-merge validations");
2286
+ result.operations.push({
2287
+ type: "validation",
2288
+ message: "Would run pre-merge validations (dry-run)",
2289
+ success: true
2290
+ });
2122
2291
  }
2123
2292
  const gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path);
2124
2293
  if (gitStatus.hasUncommittedChanges) {
2125
2294
  if (options.dryRun) {
2126
- logger.info("[DRY RUN] Would auto-commit uncommitted changes (validation passed)");
2295
+ getLogger().info("[DRY RUN] Would auto-commit uncommitted changes (validation passed)");
2296
+ result.operations.push({
2297
+ type: "commit",
2298
+ message: "Would auto-commit uncommitted changes (dry-run)",
2299
+ success: true
2300
+ });
2127
2301
  } else {
2128
- logger.info("Validation passed, auto-committing uncommitted changes...");
2302
+ getLogger().info("Validation passed, auto-committing uncommitted changes...");
2129
2303
  const settings2 = await this.settingsManager.loadSettings(worktree.path);
2130
2304
  const skipVerify = ((_b = (_a = settings2.workflows) == null ? void 0 : _a.issue) == null ? void 0 : _b.noVerify) ?? false;
2131
2305
  const commitOptions = {
@@ -2137,17 +2311,27 @@ var FinishCommand = class {
2137
2311
  }
2138
2312
  try {
2139
2313
  await this.commitManager.commitChanges(worktree.path, commitOptions);
2140
- logger.success("Changes committed successfully");
2314
+ getLogger().success("Changes committed successfully");
2315
+ result.operations.push({
2316
+ type: "commit",
2317
+ message: "Changes committed successfully",
2318
+ success: true
2319
+ });
2141
2320
  } catch (error) {
2142
2321
  if (error instanceof UserAbortedCommitError) {
2143
- logger.info("Commit aborted by user");
2322
+ getLogger().info("Commit aborted by user");
2323
+ result.operations.push({
2324
+ type: "commit",
2325
+ message: "Commit aborted by user",
2326
+ success: false
2327
+ });
2144
2328
  return;
2145
2329
  }
2146
2330
  throw error;
2147
2331
  }
2148
2332
  }
2149
2333
  } else {
2150
- logger.debug("No uncommitted changes found");
2334
+ getLogger().debug("No uncommitted changes found");
2151
2335
  }
2152
2336
  const settings = await this.settingsManager.loadSettings(worktree.path);
2153
2337
  const mergeBehavior = settings.mergeBehavior ?? { mode: "local" };
@@ -2157,32 +2341,43 @@ var FinishCommand = class {
2157
2341
  `The 'github-pr' merge mode requires a GitHub-compatible issue tracker. Your current provider (${this.issueTracker.providerName}) does not support pull requests. Either change mergeBehavior.mode to 'local' in your settings, or use GitHub as your issue tracker.`
2158
2342
  );
2159
2343
  }
2160
- await this.executeGitHubPRWorkflow(parsed, options, worktree, settings);
2344
+ await this.executeGitHubPRWorkflow(parsed, options, worktree, settings, result);
2161
2345
  return;
2162
2346
  }
2163
- logger.info("Rebasing branch on main...");
2347
+ getLogger().info("Rebasing branch on main...");
2164
2348
  const mergeOptions = {
2165
2349
  dryRun: options.dryRun ?? false,
2166
2350
  force: options.force ?? false
2167
2351
  };
2168
2352
  await this.mergeManager.rebaseOnMain(worktree.path, mergeOptions);
2169
- logger.success("Branch rebased successfully");
2170
- logger.info("Performing fast-forward merge...");
2353
+ getLogger().success("Branch rebased successfully");
2354
+ result.operations.push({
2355
+ type: "rebase",
2356
+ message: "Branch rebased on main",
2357
+ success: true
2358
+ });
2359
+ getLogger().info("Performing fast-forward merge...");
2171
2360
  await this.mergeManager.performFastForwardMerge(worktree.branch, worktree.path, mergeOptions);
2172
- logger.success("Fast-forward merge completed successfully");
2361
+ getLogger().success("Fast-forward merge completed successfully");
2362
+ result.operations.push({
2363
+ type: "merge",
2364
+ message: "Fast-forward merge completed",
2365
+ success: true
2366
+ });
2173
2367
  if (options.dryRun) {
2174
- logger.info("[DRY RUN] Would install dependencies in main worktree");
2368
+ getLogger().info("[DRY RUN] Would install dependencies in main worktree");
2175
2369
  } else {
2176
- logger.info("Installing dependencies in main worktree...");
2370
+ getLogger().info("Installing dependencies in main worktree...");
2177
2371
  const mainWorktreePath = await findMainWorktreePathWithSettings(worktree.path, this.settingsManager);
2178
2372
  await installDependencies(mainWorktreePath, true, true);
2179
2373
  }
2180
2374
  if (!options.skipBuild) {
2181
- await this.runPostMergeBuild(worktree.path, options);
2375
+ await this.runPostMergeBuild(worktree.path, options, result);
2182
2376
  } else {
2183
- logger.debug("Skipping build verification (--skip-build flag provided)");
2377
+ getLogger().debug("Skipping build verification (--skip-build flag provided)");
2184
2378
  }
2185
- await this.performPostMergeCleanup(parsed, options, worktree);
2379
+ await this.generateSessionSummaryIfConfigured(parsed, worktree, options);
2380
+ await this.performPostMergeCleanup(parsed, options, worktree, result);
2186
2381
  }
2187
2382
  /**
2188
2383
  * Execute workflow for Pull Requests
@@ -2190,27 +2385,37 @@ var FinishCommand = class {
2190
2385
  * - OPEN: Commit changes, push to remote, keep worktree active
2191
2386
  * - CLOSED/MERGED: Skip to cleanup
2192
2387
  */
2193
- async executePRWorkflow(parsed, options, worktree, pr) {
2388
+ async executePRWorkflow(parsed, options, worktree, pr, result) {
2194
2389
  var _a, _b;
2195
2390
  if (pr.state === "closed" || pr.state === "merged") {
2196
- logger.info(`PR #${parsed.number} is ${pr.state.toUpperCase()} - skipping to cleanup`);
2391
+ getLogger().info(`PR #${parsed.number} is ${pr.state.toUpperCase()} - skipping to cleanup`);
2197
2392
  const gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path);
2198
2393
  if (gitStatus.hasUncommittedChanges && !options.force) {
2199
- logger.warn("PR has uncommitted changes");
2394
+ getLogger().warn("PR has uncommitted changes");
2200
2395
  throw new Error(
2201
2396
  "Cannot cleanup PR with uncommitted changes. Commit or stash changes, then run again with --force to cleanup anyway."
2202
2397
  );
2203
2398
  }
2204
- await this.performPRCleanup(parsed, options, worktree);
2205
- logger.success(`PR #${parsed.number} cleanup completed`);
2399
+ await this.performPRCleanup(parsed, options, worktree, pr.state, result);
2400
+ getLogger().success(`PR #${parsed.number} cleanup completed`);
2401
+ result.operations.push({
2402
+ type: "cleanup",
2403
+ message: `PR #${parsed.number} cleanup completed`,
2404
+ success: true
2405
+ });
2206
2406
  } else {
2207
- logger.info(`PR #${parsed.number} is OPEN - will push changes and keep worktree active`);
2407
+ getLogger().info(`PR #${parsed.number} is OPEN - will push changes and keep worktree active`);
2208
2408
  const gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path);
2209
2409
  if (gitStatus.hasUncommittedChanges) {
2210
2410
  if (options.dryRun) {
2211
- logger.info("[DRY RUN] Would commit uncommitted changes");
2411
+ getLogger().info("[DRY RUN] Would commit uncommitted changes");
2412
+ result.operations.push({
2413
+ type: "commit",
2414
+ message: "Would commit uncommitted changes (dry-run)",
2415
+ success: true
2416
+ });
2212
2417
  } else {
2213
- logger.info("Committing uncommitted changes...");
2418
+ getLogger().info("Committing uncommitted changes...");
2214
2419
  const settings = await this.settingsManager.loadSettings(worktree.path);
2215
2420
  const skipVerify = ((_b = (_a = settings.workflows) == null ? void 0 : _a.pr) == null ? void 0 : _b.noVerify) ?? false;
2216
2421
  try {
@@ -2219,43 +2424,54 @@ var FinishCommand = class {
2219
2424
  skipVerify
2220
2425
  // Do NOT pass issueNumber for PRs - no "Fixes #" trailer needed
2221
2426
  });
2222
- logger.success("Changes committed");
2427
+ getLogger().success("Changes committed");
2428
+ result.operations.push({
2429
+ type: "commit",
2430
+ message: "Changes committed successfully",
2431
+ success: true
2432
+ });
2223
2433
  } catch (error) {
2224
2434
  if (error instanceof UserAbortedCommitError) {
2225
- logger.info("Commit aborted by user");
2435
+ getLogger().info("Commit aborted by user");
2436
+ result.operations.push({
2437
+ type: "commit",
2438
+ message: "Commit aborted by user",
2439
+ success: false
2440
+ });
2226
2441
  return;
2227
2442
  }
2228
2443
  throw error;
2229
2444
  }
2230
2445
  }
2231
2446
  } else {
2232
- logger.debug("No uncommitted changes found");
2447
+ getLogger().debug("No uncommitted changes found");
2233
2448
  }
2234
2449
  if (options.dryRun) {
2235
- logger.info(`[DRY RUN] Would push changes to origin/${pr.branch}`);
2450
+ getLogger().info(`[DRY RUN] Would push changes to origin/${pr.branch}`);
2236
2451
  } else {
2237
- logger.info("Pushing changes to remote...");
2452
+ getLogger().info("Pushing changes to remote...");
2238
2453
  await pushBranchToRemote(pr.branch, worktree.path, {
2239
2454
  dryRun: false
2240
2455
  });
2241
- logger.success(`Changes pushed to PR #${parsed.number}`);
2456
+ getLogger().success(`Changes pushed to PR #${parsed.number}`);
2242
2457
  }
2243
- logger.success(`PR #${parsed.number} updated successfully`);
2244
- logger.info("Worktree remains active for continued work");
2245
- logger.info(`To cleanup when done: il cleanup ${parsed.number}`);
2458
+ getLogger().success(`PR #${parsed.number} updated successfully`);
2459
+ getLogger().info("Worktree remains active for continued work");
2460
+ getLogger().info(`To cleanup when done: il cleanup ${parsed.number}`);
2461
+ result.prUrl = pr.url;
2246
2462
  }
2247
2463
  }
2248
2464
  /**
2249
2465
  * Execute workflow for GitHub PR creation (github-pr merge mode)
2250
2466
  * Validates → Commits → Pushes → Creates PR → Prompts for cleanup
2251
2467
  */
2252
- async executeGitHubPRWorkflow(parsed, options, worktree, settings) {
2468
+ async executeGitHubPRWorkflow(parsed, options, worktree, settings, finishResult) {
2253
2469
  if (options.dryRun) {
2254
- logger.info("[DRY RUN] Would push branch to origin");
2470
+ getLogger().info("[DRY RUN] Would push branch to origin");
2255
2471
  } else {
2256
- logger.info("Pushing branch to origin...");
2472
+ getLogger().info("Pushing branch to origin...");
2257
2473
  await pushBranchToRemote(worktree.branch, worktree.path, { dryRun: false });
2258
- logger.success("Branch pushed successfully");
2474
+ getLogger().success("Branch pushed successfully");
2259
2475
  }
2260
2476
  const prManager = new PRManager(settings);
2261
2477
  let prTitle = `Work from ${worktree.branch}`;
@@ -2264,17 +2480,22 @@ var FinishCommand = class {
2264
2480
  const issue = await this.issueTracker.fetchIssue(parsed.number);
2265
2481
  prTitle = issue.title;
2266
2482
  } catch (error) {
2267
- logger.debug("Could not fetch issue title, using branch name", { error });
2483
+ getLogger().debug("Could not fetch issue title, using branch name", { error });
2268
2484
  }
2269
2485
  }
2270
2486
  if (options.dryRun) {
2271
- logger.info("[DRY RUN] Would create GitHub PR");
2272
- logger.info(` Title: ${prTitle}`);
2273
- logger.info(` Base: ${settings.mainBranch ?? "main"}`);
2487
+ getLogger().info("[DRY RUN] Would create GitHub PR");
2488
+ getLogger().info(` Title: ${prTitle}`);
2489
+ getLogger().info(` Base: ${settings.mainBranch ?? "main"}`);
2490
+ finishResult.operations.push({
2491
+ type: "pr-creation",
2492
+ message: "Would create GitHub PR (dry-run)",
2493
+ success: true
2494
+ });
2274
2495
  } else {
2275
2496
  const baseBranch = settings.mainBranch ?? "main";
2276
2497
  const openInBrowser = options.noBrowser !== true;
2277
- const result = await prManager.createOrOpenPR(
2498
+ const prResult = await prManager.createOrOpenPR(
2278
2499
  worktree.branch,
2279
2500
  prTitle,
2280
2501
  parsed.type === "issue" ? parsed.number : void 0,
@@ -2282,40 +2503,52 @@ var FinishCommand = class {
2282
2503
  worktree.path,
2283
2504
  openInBrowser
2284
2505
  );
2285
- if (result.wasExisting) {
2286
- logger.success(`Existing pull request: ${result.url}`);
2506
+ if (prResult.wasExisting) {
2507
+ getLogger().success(`Existing pull request: ${prResult.url}`);
2508
+ finishResult.operations.push({
2509
+ type: "pr-creation",
2510
+ message: `Found existing pull request`,
2511
+ success: true
2512
+ });
2287
2513
  } else {
2288
- logger.success(`Pull request created: ${result.url}`);
2514
+ getLogger().success(`Pull request created: ${prResult.url}`);
2515
+ finishResult.operations.push({
2516
+ type: "pr-creation",
2517
+ message: `Pull request created`,
2518
+ success: true
2519
+ });
2289
2520
  }
2290
- await this.handlePRCleanupPrompt(parsed, options, worktree);
2521
+ finishResult.prUrl = prResult.url;
2522
+ await this.generateSessionSummaryIfConfigured(parsed, worktree, options);
2523
+ await this.handlePRCleanupPrompt(parsed, options, worktree, finishResult);
2291
2524
  }
2292
2525
  }
2293
2526
  /**
2294
2527
  * Handle cleanup prompt after PR creation
2295
2528
  * Respects --cleanup and --no-cleanup flags, otherwise prompts user
2296
2529
  */
2297
- async handlePRCleanupPrompt(parsed, options, worktree) {
2530
+ async handlePRCleanupPrompt(parsed, options, worktree, finishResult) {
2298
2531
  if (options.cleanup === true) {
2299
- logger.info("Cleaning up worktree (--cleanup flag)...");
2300
- await this.performWorktreeCleanup(parsed, options, worktree);
2532
+ getLogger().info("Cleaning up worktree (--cleanup flag)...");
2533
+ await this.performWorktreeCleanup(parsed, options, worktree, finishResult);
2301
2534
  } else if (options.cleanup === false) {
2302
- logger.info("Worktree kept active for continued work (--no-cleanup flag)");
2303
- logger.info(`To cleanup later: il cleanup ${parsed.originalInput}`);
2535
+ getLogger().info("Worktree kept active for continued work (--no-cleanup flag)");
2536
+ getLogger().info(`To cleanup later: il cleanup ${parsed.originalInput}`);
2304
2537
  } else {
2305
- logger.info("");
2306
- logger.info("PR created successfully. Would you like to clean up the worktree?");
2307
- logger.info(` Worktree: ${worktree.path}`);
2308
- logger.info(` Branch: ${worktree.branch}`);
2309
- logger.info("");
2538
+ getLogger().info("");
2539
+ getLogger().info("PR created successfully. Would you like to clean up the worktree?");
2540
+ getLogger().info(` Worktree: ${worktree.path}`);
2541
+ getLogger().info(` Branch: ${worktree.branch}`);
2542
+ getLogger().info("");
2310
2543
  const shouldCleanup = await promptConfirmation(
2311
2544
  "Clean up worktree now?",
2312
2545
  false
2313
2546
  // Default to keeping worktree (safer option)
2314
2547
  );
2315
2548
  if (shouldCleanup) {
2316
- await this.performWorktreeCleanup(parsed, options, worktree);
2549
+ await this.performWorktreeCleanup(parsed, options, worktree, finishResult);
2317
2550
  } else {
2318
- logger.info("Worktree kept active. Run `il cleanup` when ready.");
2551
+ getLogger().info("Worktree kept active. Run `il cleanup` when ready.");
2319
2552
  }
2320
2553
  }
2321
2554
  }
@@ -2323,7 +2556,7 @@ var FinishCommand = class {
2323
2556
  * Perform worktree cleanup (used by GitHub PR workflow)
2324
2557
  * Similar to performPostMergeCleanup but for PR workflow
2325
2558
  */
2326
- async performWorktreeCleanup(parsed, options, worktree) {
2559
+ async performWorktreeCleanup(parsed, options, worktree, finishResult) {
2327
2560
  const cleanupInput = {
2328
2561
  type: parsed.type,
2329
2562
  originalInput: parsed.originalInput,
@@ -2339,56 +2572,98 @@ var FinishCommand = class {
2339
2572
  force: options.force ?? false
2340
2573
  };
2341
2574
  try {
2342
- logger.info("Starting worktree cleanup...");
2575
+ getLogger().info("Starting worktree cleanup...");
2343
2576
  await this.ensureResourceCleanup();
2344
2577
  if (!this.resourceCleanup) {
2345
2578
  throw new Error("Failed to initialize ResourceCleanup");
2346
2579
  }
2347
- const result = await this.resourceCleanup.cleanupWorktree(cleanupInput, cleanupOptions);
2348
- this.reportCleanupResults(result);
2349
- if (!result.success) {
2350
- logger.warn("Some cleanup operations failed - manual cleanup may be required");
2580
+ const cleanupResult = await this.resourceCleanup.cleanupWorktree(cleanupInput, cleanupOptions);
2581
+ this.reportCleanupResults(cleanupResult);
2582
+ finishResult.cleanupResult = cleanupResult;
2583
+ if (!cleanupResult.success) {
2584
+ getLogger().warn("Some cleanup operations failed - manual cleanup may be required");
2351
2585
  this.showManualCleanupInstructions(worktree);
2586
+ finishResult.operations.push({
2587
+ type: "cleanup",
2588
+ message: "Worktree cleanup partially failed",
2589
+ success: false
2590
+ });
2352
2591
  } else {
2353
- logger.success("Worktree cleanup completed successfully");
2592
+ getLogger().success("Worktree cleanup completed successfully");
2593
+ finishResult.operations.push({
2594
+ type: "cleanup",
2595
+ message: "Worktree cleanup completed",
2596
+ success: true
2597
+ });
2354
2598
  }
2355
2599
  if (this.isRunningFromWithinWorktree(worktree.path)) {
2356
2600
  this.showTerminalCloseWarning(worktree);
2357
2601
  }
2358
2602
  } catch (error) {
2359
2603
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
2360
- logger.warn(`Cleanup failed: ${errorMessage}`);
2361
- logger.warn("Manual cleanup may be required");
2604
+ getLogger().warn(`Cleanup failed: ${errorMessage}`);
2605
+ getLogger().warn("Manual cleanup may be required");
2362
2606
  this.showManualCleanupInstructions(worktree);
2607
+ finishResult.operations.push({
2608
+ type: "cleanup",
2609
+ message: "Worktree cleanup failed",
2610
+ success: false,
2611
+ error: errorMessage
2612
+ });
2363
2613
  }
2364
2614
  }
2365
2615
  /**
2366
2616
  * Perform cleanup for closed/merged PRs
2367
2617
  * Similar to performPostMergeCleanup but with different messaging
2618
+ *
2619
+ * Safety check behavior differs based on PR state:
2620
+ * - MERGED: Skip safety checks - work is safely in main branch
2621
+ * - CLOSED (not merged): Enable safety checks - PR was rejected/abandoned,
2622
+ * local commits may not exist anywhere else
2623
+ *
2624
+ * @param parsed - Parsed input identifying the PR
2625
+ * @param options - Finish options
2626
+ * @param worktree - The worktree to clean up
2627
+ * @param prState - The PR state ('closed' or 'merged')
2628
+ * @param finishResult - Result object to populate
2368
2629
  */
2369
- async performPRCleanup(parsed, options, worktree) {
2630
+ async performPRCleanup(parsed, options, worktree, prState, finishResult) {
2370
2631
  const cleanupInput = {
2371
2632
  type: parsed.type,
2372
2633
  originalInput: parsed.originalInput,
2373
2634
  ...parsed.number !== void 0 && { number: parsed.number },
2374
2635
  ...parsed.branchName !== void 0 && { branchName: parsed.branchName }
2375
2636
  };
2637
+ const isMerged = prState === "merged";
2376
2638
  const cleanupOptions = {
2377
2639
  dryRun: options.dryRun ?? false,
2378
2640
  deleteBranch: true,
2379
2641
  // Delete branch for closed/merged PRs
2380
2642
  keepDatabase: false,
2381
- force: options.force ?? false
2643
+ force: options.force ?? false,
2644
+ // For merged PRs: skip merge check (work is in main)
2645
+ // For closed PRs: enable merge check (may have unpushed local commits)
2646
+ checkMergeSafety: !isMerged,
2647
+ // Skip remote branch check for MERGED PRs because:
2648
+ // 1. The PR is merged - the work is safely in main
2649
+ // 2. GitHub may have auto-deleted the branch after merge
2650
+ // 3. The user may have manually deleted the remote branch post-merge
2651
+ //
2652
+ // For CLOSED PRs, we rely on checkMergeSafety to verify no unpushed commits
2653
+ // rather than checkRemoteBranch, since the remote branch may still exist
2654
+ // but local may have additional commits
2655
+ checkRemoteBranch: false
2382
2656
  };
2383
2657
  try {
2384
2658
  await this.ensureResourceCleanup();
2385
2659
  if (!this.resourceCleanup) {
2386
2660
  throw new Error("Failed to initialize ResourceCleanup");
2387
2661
  }
2388
- const result = await this.resourceCleanup.cleanupWorktree(cleanupInput, cleanupOptions);
2389
- this.reportCleanupResults(result);
2390
- if (!result.success) {
2391
- logger.warn("Some cleanup operations failed - manual cleanup may be required");
2662
+ const cleanupResult = await this.resourceCleanup.cleanupWorktree(cleanupInput, cleanupOptions);
2663
+ this.reportCleanupResults(cleanupResult);
2664
+ finishResult.cleanupResult = cleanupResult;
2665
+ if (!cleanupResult.success) {
2666
+ getLogger().warn("Some cleanup operations failed - manual cleanup may be required");
2392
2667
  this.showManualCleanupInstructions(worktree);
2393
2668
  } else {
2394
2669
  if (this.isRunningFromWithinWorktree(worktree.path)) {
@@ -2397,29 +2672,86 @@ var FinishCommand = class {
2397
2672
  }
2398
2673
  } catch (error) {
2399
2674
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
2400
- logger.warn(`Cleanup failed: ${errorMessage}`);
2675
+ getLogger().warn(`Cleanup failed: ${errorMessage}`);
2401
2676
  this.showManualCleanupInstructions(worktree);
2402
2677
  throw error;
2403
2678
  }
2404
2679
  }
2680
+ /**
2681
+ * Generate and post session summary if configured
2682
+ *
2683
+ * Non-blocking: Catches all errors and logs warnings instead of throwing
2684
+ * This ensures the finish workflow continues even if summary generation fails
2685
+ *
2686
+ * In dry-run mode: generates summary and shows preview, but doesn't post
2687
+ */
2688
+ async generateSessionSummaryIfConfigured(parsed, worktree, options) {
2689
+ if (parsed.type === "branch") {
2690
+ return;
2691
+ }
2692
+ this.sessionSummaryService ??= new SessionSummaryService(
2693
+ void 0,
2694
+ // Use default PromptTemplateManager
2695
+ void 0,
2696
+ // Use default MetadataManager
2697
+ this.settingsManager
2698
+ );
2699
+ if (options.dryRun) {
2700
+ try {
2701
+ const result = await this.sessionSummaryService.generateSummary(
2702
+ worktree.path,
2703
+ worktree.branch,
2704
+ parsed.type,
2705
+ parsed.number
2706
+ );
2707
+ const preview = result.summary.slice(0, 100).replace(/\n/g, " ");
2708
+ getLogger().info(`[DRY RUN] Would post session summary: "${preview}..."`);
2709
+ } catch (error) {
2710
+ const errorMessage = error instanceof Error ? error.message : String(error);
2711
+ getLogger().warn(`[DRY RUN] Session summary generation failed: ${errorMessage}`);
2712
+ }
2713
+ return;
2714
+ }
2715
+ await this.sessionSummaryService.generateAndPostSummary({
2716
+ worktreePath: worktree.path,
2717
+ issueNumber: parsed.number ?? 0,
2718
+ branchName: worktree.branch,
2719
+ loomType: parsed.type
2720
+ });
2721
+ }
2405
2722
  /**
2406
2723
  * Run post-merge build verification for CLI projects
2407
2724
  * Runs in main worktree to verify merged code builds successfully
2408
2725
  */
2409
- async runPostMergeBuild(worktreePath, options) {
2726
+ async runPostMergeBuild(worktreePath, options, finishResult) {
2410
2727
  const mainWorktreePath = await findMainWorktreePathWithSettings(worktreePath, this.settingsManager);
2411
2728
  if (options.dryRun) {
2412
- logger.info("[DRY RUN] Would run post-merge build");
2729
+ getLogger().info("[DRY RUN] Would run post-merge build");
2730
+ finishResult.operations.push({
2731
+ type: "build",
2732
+ message: "Would run post-merge build (dry-run)",
2733
+ success: true
2734
+ });
2413
2735
  return;
2414
2736
  }
2415
- logger.info("Running post-merge build...");
2416
- const result = await this.buildRunner.runBuild(mainWorktreePath, {
2737
+ getLogger().info("Running post-merge build...");
2738
+ const buildResult = await this.buildRunner.runBuild(mainWorktreePath, {
2417
2739
  dryRun: options.dryRun ?? false
2418
2740
  });
2419
- if (result.skipped) {
2420
- logger.debug(`Build skipped: ${result.reason}`);
2741
+ if (buildResult.skipped) {
2742
+ getLogger().debug(`Build skipped: ${buildResult.reason}`);
2743
+ finishResult.operations.push({
2744
+ type: "build",
2745
+ message: `Build skipped: ${buildResult.reason}`,
2746
+ success: true
2747
+ });
2421
2748
  } else {
2422
- logger.success("Post-merge build completed successfully");
2749
+ getLogger().success("Post-merge build completed successfully");
2750
+ finishResult.operations.push({
2751
+ type: "build",
2752
+ message: "Post-merge build completed",
2753
+ success: true
2754
+ });
2423
2755
  }
2424
2756
  }
2425
2757
  /**
@@ -2427,7 +2759,7 @@ var FinishCommand = class {
2427
2759
  * Converts ParsedFinishInput to ParsedInput and calls ResourceCleanup
2428
2760
  * Handles failures gracefully without throwing
2429
2761
  */
2430
- async performPostMergeCleanup(parsed, options, worktree) {
2762
+ async performPostMergeCleanup(parsed, options, worktree, finishResult) {
2431
2763
  await this.ensureResourceCleanup();
2432
2764
  if (!this.loomManager) {
2433
2765
  throw new Error("Failed to initialize LoomManager");
@@ -2448,26 +2780,43 @@ var FinishCommand = class {
2448
2780
  force: options.force ?? false
2449
2781
  };
2450
2782
  try {
2451
- logger.info("Starting post-merge cleanup...");
2783
+ getLogger().info("Starting post-merge cleanup...");
2452
2784
  if (!this.resourceCleanup) {
2453
2785
  throw new Error("Failed to initialize ResourceCleanup");
2454
2786
  }
2455
- const result = await this.resourceCleanup.cleanupWorktree(cleanupInput, cleanupOptions);
2456
- this.reportCleanupResults(result);
2457
- if (!result.success) {
2458
- logger.warn("Some cleanup operations failed - manual cleanup may be required");
2787
+ const cleanupResult = await this.resourceCleanup.cleanupWorktree(cleanupInput, cleanupOptions);
2788
+ this.reportCleanupResults(cleanupResult);
2789
+ finishResult.cleanupResult = cleanupResult;
2790
+ if (!cleanupResult.success) {
2791
+ getLogger().warn("Some cleanup operations failed - manual cleanup may be required");
2459
2792
  this.showManualCleanupInstructions(worktree);
2793
+ finishResult.operations.push({
2794
+ type: "cleanup",
2795
+ message: "Post-merge cleanup partially failed",
2796
+ success: false
2797
+ });
2460
2798
  } else {
2461
- logger.success("Post-merge cleanup completed successfully");
2799
+ getLogger().success("Post-merge cleanup completed successfully");
2800
+ finishResult.operations.push({
2801
+ type: "cleanup",
2802
+ message: "Post-merge cleanup completed",
2803
+ success: true
2804
+ });
2462
2805
  }
2463
2806
  if (this.isRunningFromWithinWorktree(worktree.path)) {
2464
2807
  this.showTerminalCloseWarning(worktree);
2465
2808
  }
2466
2809
  } catch (error) {
2467
2810
  const errorMessage = error instanceof Error ? error.message : "Unknown error";
2468
- logger.warn(`Cleanup failed: ${errorMessage}`);
2469
- logger.warn("Merge completed successfully, but manual cleanup is required");
2811
+ getLogger().warn(`Cleanup failed: ${errorMessage}`);
2812
+ getLogger().warn("Merge completed successfully, but manual cleanup is required");
2470
2813
  this.showManualCleanupInstructions(worktree);
2814
+ finishResult.operations.push({
2815
+ type: "cleanup",
2816
+ message: "Post-merge cleanup failed",
2817
+ success: false,
2818
+ error: errorMessage
2819
+ });
2471
2820
  }
2472
2821
  }
2473
2822
  /**
@@ -2477,14 +2826,14 @@ var FinishCommand = class {
2477
2826
  if (result.operations.length === 0) {
2478
2827
  return;
2479
2828
  }
2480
- logger.info("Cleanup operations:");
2829
+ getLogger().info("Cleanup operations:");
2481
2830
  for (const op of result.operations) {
2482
2831
  const status = op.success ? "\u2713" : "\u2717";
2483
2832
  const message = op.error ? `${op.message}: ${op.error}` : op.message;
2484
2833
  if (op.success) {
2485
- logger.info(` ${status} ${message}`);
2834
+ getLogger().info(` ${status} ${message}`);
2486
2835
  } else {
2487
- logger.warn(` ${status} ${message}`);
2836
+ getLogger().warn(` ${status} ${message}`);
2488
2837
  }
2489
2838
  }
2490
2839
  }
@@ -2492,10 +2841,10 @@ var FinishCommand = class {
2492
2841
  * Show manual cleanup instructions when cleanup fails
2493
2842
  */
2494
2843
  showManualCleanupInstructions(worktree) {
2495
- logger.info("\nManual cleanup commands:");
2496
- logger.info(` 1. Remove worktree: git worktree remove ${worktree.path}`);
2497
- logger.info(` 2. Delete branch: git branch -d ${worktree.branch}`);
2498
- logger.info(` 3. Check dev servers: lsof -i :PORT (and kill if needed)`);
2844
+ getLogger().info("\nManual cleanup commands:");
2845
+ getLogger().info(` 1. Remove worktree: git worktree remove ${worktree.path}`);
2846
+ getLogger().info(` 2. Delete branch: git branch -d ${worktree.branch}`);
2847
+ getLogger().info(` 3. Check dev servers: lsof -i :PORT (and kill if needed)`);
2499
2848
  }
2500
2849
  /**
2501
2850
  * Check if current working directory is within the target worktree
@@ -2509,17 +2858,17 @@ var FinishCommand = class {
2509
2858
  * Display warning to close terminal/IDE when running from within finished loom
2510
2859
  */
2511
2860
  showTerminalCloseWarning(worktree) {
2512
- logger.info("");
2513
- logger.info("You are currently in the directory of the loom that was just finished.");
2514
- logger.info("Please close this terminal and any IDE/terminal windows using this directory.");
2515
- logger.info(`Directory: ${worktree.path}`);
2861
+ getLogger().info("");
2862
+ getLogger().info("You are currently in the directory of the loom that was just finished.");
2863
+ getLogger().info("Please close this terminal and any IDE/terminal windows using this directory.");
2864
+ getLogger().info(`Directory: ${worktree.path}`);
2516
2865
  }
2517
2866
  };
2518
2867
 
2519
2868
  // src/utils/package-info.ts
2520
2869
  import { readFileSync } from "fs";
2521
2870
  import { fileURLToPath } from "url";
2522
- import { dirname, join } from "path";
2871
+ import { dirname, join as join2 } from "path";
2523
2872
  function getPackageInfo(scriptPath) {
2524
2873
  try {
2525
2874
  let basePath;
@@ -2530,7 +2879,7 @@ function getPackageInfo(scriptPath) {
2530
2879
  basePath = __filename2;
2531
2880
  }
2532
2881
  const __dirname = dirname(basePath);
2533
- const packageJsonPath = join(__dirname, "..", "package.json");
2882
+ const packageJsonPath = join2(__dirname, "..", "package.json");
2534
2883
  const packageJsonContent = readFileSync(packageJsonPath, "utf8");
2535
2884
  const packageJson2 = JSON.parse(packageJsonContent);
2536
2885
  return packageJson2;
@@ -2631,14 +2980,14 @@ program.name("iloom").description(packageJson.description).version(packageJson.v
2631
2980
  process.exit(0);
2632
2981
  }
2633
2982
  try {
2634
- const { checkAndNotifyUpdate } = await import("./update-notifier-QEX3CJHA.js");
2635
- const { detectInstallationMethod } = await import("./installation-detector-VARGFFRZ.js");
2983
+ const { checkAndNotifyUpdate } = await import("./update-notifier-H55ZK7NU.js");
2984
+ const { detectInstallationMethod } = await import("./installation-detector-6R6YOFVZ.js");
2636
2985
  const installMethod = detectInstallationMethod(__filename);
2637
2986
  await checkAndNotifyUpdate(packageJson.version, packageJson.name, installMethod);
2638
2987
  } catch {
2639
2988
  }
2640
2989
  try {
2641
- const { SettingsMigrationManager } = await import("./SettingsMigrationManager-TJ7UWZG5.js");
2990
+ const { SettingsMigrationManager } = await import("./SettingsMigrationManager-EH3J2TCN.js");
2642
2991
  const migrationManager = new SettingsMigrationManager();
2643
2992
  await migrationManager.migrateSettingsIfNeeded();
2644
2993
  } catch (error) {
@@ -2728,21 +3077,21 @@ async function autoLaunchInitForMultipleRemotes() {
2728
3077
  logger.info("iloom will now launch an interactive configuration session with Claude");
2729
3078
  logger.info("to help you select which remote to use for GitHub operations.");
2730
3079
  logger.info("");
2731
- const { waitForKeypress: waitForKeypress2 } = await import("./prompt-QALMYTVC.js");
3080
+ const { waitForKeypress: waitForKeypress2 } = await import("./prompt-A7GGRHSY.js");
2732
3081
  await waitForKeypress2("Press any key to start configuration...");
2733
3082
  logger.info("");
2734
3083
  try {
2735
- const { InitCommand: InitCommand2 } = await import("./init-4FHTAM3F.js");
3084
+ const { InitCommand: InitCommand2 } = await import("./init-SCR2LQ4A.js");
2736
3085
  const initCommand = new InitCommand2();
2737
3086
  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.";
2738
3087
  await initCommand.execute(customInitialMessage);
2739
3088
  logger.info("");
2740
3089
  logger.info("Configuration complete! Continuing with your original command...");
2741
3090
  logger.info("");
2742
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-I2LRCW2A.js");
3091
+ const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-FJFU6JJD.js");
2743
3092
  const settingsManager = new SettingsManager2();
2744
3093
  const settings = await settingsManager.loadSettings();
2745
- const { hasMultipleRemotes: hasMultipleRemotes2 } = await import("./remote-VUNCQZ6J.js");
3094
+ const { hasMultipleRemotes: hasMultipleRemotes2 } = await import("./remote-73TZ2ADI.js");
2746
3095
  const multipleRemotes = await hasMultipleRemotes2();
2747
3096
  if (multipleRemotes && !((_b = (_a = settings.issueManagement) == null ? void 0 : _a.github) == null ? void 0 : _b.remote)) {
2748
3097
  logger.error("Configuration incomplete: GitHub remote is still not configured.");
@@ -2758,50 +3107,82 @@ async function autoLaunchInitForMultipleRemotes() {
2758
3107
  }
2759
3108
  var shellCompletion = new ShellCompletion();
2760
3109
  shellCompletion.init();
2761
- 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)").addOption(
3110
+ 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(
2762
3111
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
2763
3112
  ).action(async (identifier, options) => {
2764
- try {
2765
- let finalIdentifier = identifier;
2766
- if (!finalIdentifier) {
2767
- const { promptInput } = await import("./prompt-QALMYTVC.js");
2768
- finalIdentifier = await promptInput("Enter issue number, PR number (pr/123), or branch name");
2769
- if (!(finalIdentifier == null ? void 0 : finalIdentifier.trim())) {
2770
- logger.error("Identifier is required");
2771
- process.exit(1);
3113
+ const executeAction = async () => {
3114
+ try {
3115
+ let finalIdentifier = identifier;
3116
+ if (!finalIdentifier) {
3117
+ if (options.json) {
3118
+ logger.error("JSON mode requires identifier argument");
3119
+ process.exit(1);
3120
+ }
3121
+ const { promptInput } = await import("./prompt-A7GGRHSY.js");
3122
+ finalIdentifier = await promptInput("Enter issue number, PR number (pr/123), or branch name");
3123
+ if (!(finalIdentifier == null ? void 0 : finalIdentifier.trim())) {
3124
+ logger.error("Identifier is required");
3125
+ process.exit(1);
3126
+ }
3127
+ }
3128
+ const settingsManager = new SettingsManager();
3129
+ const settings = await settingsManager.loadSettings();
3130
+ const issueTracker = IssueTrackerFactory.create(settings);
3131
+ const command = new StartCommand(issueTracker, void 0, void 0, settingsManager);
3132
+ const result = await command.execute({ identifier: finalIdentifier, options });
3133
+ if (options.json && result) {
3134
+ console.log(JSON.stringify(result, null, 2));
2772
3135
  }
3136
+ process.exit(0);
3137
+ } catch (error) {
3138
+ logger.error(`Failed to start workspace: ${error instanceof Error ? error.message : "Unknown error"}`);
3139
+ process.exit(1);
2773
3140
  }
2774
- const settingsManager = new SettingsManager();
2775
- const settings = await settingsManager.loadSettings();
2776
- const issueTracker = IssueTrackerFactory.create(settings);
2777
- const command = new StartCommand(issueTracker, void 0, void 0, settingsManager);
2778
- await command.execute({ identifier: finalIdentifier, options });
2779
- } catch (error) {
2780
- logger.error(`Failed to start workspace: ${error instanceof Error ? error.message : "Unknown error"}`);
2781
- process.exit(1);
3141
+ };
3142
+ if (options.json) {
3143
+ const jsonLogger = createStderrLogger();
3144
+ await withLogger(jsonLogger, executeAction);
3145
+ } else {
3146
+ await executeAction();
2782
3147
  }
2783
3148
  });
2784
- program.command("add-issue").alias("a").description("Create and enhance GitHub issue without starting workspace").argument("<description>", "Natural language description of the issue (>50 chars, >2 spaces)").option("--body <text>", "Body text for issue (skips AI enhancement)").action(async (description, options) => {
2785
- try {
2786
- const settingsManager = new SettingsManager();
2787
- const settings = await settingsManager.loadSettings();
2788
- const issueTracker = IssueTrackerFactory.create(settings);
2789
- const enhancementService = new IssueEnhancementService(issueTracker, new AgentManager(), settingsManager);
2790
- const command = new AddIssueCommand(enhancementService, settingsManager);
2791
- const issueNumber = await command.execute({
2792
- description,
2793
- options: options.body ? { body: options.body } : {}
2794
- });
2795
- logger.success(`Issue #${issueNumber} created successfully`);
2796
- process.exit(0);
2797
- } catch (error) {
2798
- logger.error(`Failed to create issue: ${error instanceof Error ? error.message : "Unknown error"}`);
2799
- process.exit(1);
3149
+ program.command("add-issue").alias("a").description("Create and enhance GitHub issue without starting workspace").argument("<description>", "Natural language description of the issue (>50 chars, >2 spaces)").option("--body <text>", "Body text for issue (skips AI enhancement)").option("--json", "Output result as JSON").action(async (description, options) => {
3150
+ const executeAction = async () => {
3151
+ try {
3152
+ const settingsManager = new SettingsManager();
3153
+ const settings = await settingsManager.loadSettings();
3154
+ const issueTracker = IssueTrackerFactory.create(settings);
3155
+ const enhancementService = new IssueEnhancementService(issueTracker, new AgentManager(), settingsManager);
3156
+ const command = new AddIssueCommand(enhancementService, settingsManager);
3157
+ const result = await command.execute({
3158
+ description,
3159
+ options: {
3160
+ ...options.body && { body: options.body },
3161
+ ...options.json && { json: options.json }
3162
+ }
3163
+ });
3164
+ if (options.json && result) {
3165
+ console.log(JSON.stringify(result, null, 2));
3166
+ } else if (result) {
3167
+ const issueNumber = typeof result === "object" ? result.id : result;
3168
+ logger.success(`Issue #${issueNumber} created successfully`);
3169
+ }
3170
+ process.exit(0);
3171
+ } catch (error) {
3172
+ logger.error(`Failed to create issue: ${error instanceof Error ? error.message : "Unknown error"}`);
3173
+ process.exit(1);
3174
+ }
3175
+ };
3176
+ if (options.json) {
3177
+ const jsonLogger = createStderrLogger();
3178
+ await withLogger(jsonLogger, executeAction);
3179
+ } else {
3180
+ await executeAction();
2800
3181
  }
2801
3182
  });
2802
3183
  program.command("feedback").alias("f").description("Submit feedback/bug report to iloom-cli repository").argument("<description>", "Natural language description of feedback (>50 chars, >2 spaces)").option("--body <text>", "Body text for feedback (added after diagnostics)").action(async (description, options) => {
2803
3184
  try {
2804
- const { FeedbackCommand } = await import("./feedback-XTUCKJNT.js");
3185
+ const { FeedbackCommand } = await import("./feedback-562KPG5U.js");
2805
3186
  const command = new FeedbackCommand();
2806
3187
  const feedbackOptions = {};
2807
3188
  if (options.body !== void 0) {
@@ -2818,41 +3199,70 @@ program.command("feedback").alias("f").description("Submit feedback/bug report t
2818
3199
  process.exit(1);
2819
3200
  }
2820
3201
  });
2821
- program.command("enhance").description("Apply enhancement agent to existing GitHub issue").argument("<issue-number>", "GitHub issue identifier to enhance", parseIssueIdentifier).option("--no-browser", "Skip browser opening prompt").option("--author <username>", "GitHub username to tag in questions (for CI usage)").action(async (issueNumber, options) => {
2822
- try {
2823
- const settingsManager = new SettingsManager();
2824
- const settings = await settingsManager.loadSettings();
2825
- const issueTracker = IssueTrackerFactory.create(settings);
2826
- const command = new EnhanceCommand(issueTracker);
2827
- await command.execute({
2828
- issueNumber,
2829
- options: {
2830
- noBrowser: options.browser === false,
2831
- ...options.author && { author: options.author }
3202
+ program.command("enhance").description("Apply enhancement agent to existing GitHub issue").argument("<issue-number>", "GitHub issue identifier to enhance", parseIssueIdentifier).option("--no-browser", "Skip browser opening prompt").option("--author <username>", "GitHub username to tag in questions (for CI usage)").option("--json", "Output result as JSON").action(async (issueNumber, options) => {
3203
+ const executeAction = async () => {
3204
+ try {
3205
+ const settingsManager = new SettingsManager();
3206
+ const settings = await settingsManager.loadSettings();
3207
+ const issueTracker = IssueTrackerFactory.create(settings);
3208
+ const command = new EnhanceCommand(issueTracker);
3209
+ const result = await command.execute({
3210
+ issueNumber,
3211
+ options: {
3212
+ noBrowser: options.browser === false,
3213
+ ...options.author && { author: options.author },
3214
+ ...options.json && { json: options.json }
3215
+ }
3216
+ });
3217
+ if (options.json && result) {
3218
+ console.log(JSON.stringify(result, null, 2));
3219
+ } else {
3220
+ logger.success(`Enhancement process completed for issue #${issueNumber}`);
2832
3221
  }
2833
- });
2834
- logger.success(`Enhancement process completed for issue #${issueNumber}`);
2835
- process.exit(0);
2836
- } catch (error) {
2837
- logger.error(`Failed to enhance issue: ${error instanceof Error ? error.message : "Unknown error"}`);
2838
- process.exit(1);
3222
+ process.exit(0);
3223
+ } catch (error) {
3224
+ logger.error(`Failed to enhance issue: ${error instanceof Error ? error.message : "Unknown error"}`);
3225
+ process.exit(1);
3226
+ }
3227
+ };
3228
+ if (options.json) {
3229
+ const jsonLogger = createStderrLogger();
3230
+ await withLogger(jsonLogger, executeAction);
3231
+ } else {
3232
+ await executeAction();
2839
3233
  }
2840
3234
  });
2841
- 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 PR creation (github-pr mode only)").option("--no-cleanup", "Keep worktree after PR creation (github-pr mode only)").action(async (identifier, options) => {
2842
- try {
2843
- const settingsManager = new SettingsManager();
2844
- const settings = await settingsManager.loadSettings();
2845
- const issueTracker = IssueTrackerFactory.create(settings);
2846
- const command = new FinishCommand(issueTracker);
2847
- await command.execute({ identifier, options });
2848
- } catch (error) {
2849
- logger.error(`Failed to finish workspace: ${error instanceof Error ? error.message : "Unknown error"}`);
2850
- process.exit(1);
3235
+ 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 PR creation (github-pr mode only)").option("--no-cleanup", "Keep worktree after PR creation (github-pr mode only)").option("--json", "Output result as JSON").action(async (identifier, options) => {
3236
+ const executeAction = async () => {
3237
+ try {
3238
+ const settingsManager = new SettingsManager();
3239
+ const settings = await settingsManager.loadSettings();
3240
+ const issueTracker = IssueTrackerFactory.create(settings);
3241
+ const command = new FinishCommand(issueTracker);
3242
+ const result = await command.execute({ identifier, options });
3243
+ if (options.json && result) {
3244
+ console.log(JSON.stringify(result, null, 2));
3245
+ }
3246
+ process.exit(0);
3247
+ } catch (error) {
3248
+ if (options.json) {
3249
+ console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : "Unknown error" }, null, 2));
3250
+ } else {
3251
+ logger.error(`Failed to finish workspace: ${error instanceof Error ? error.message : "Unknown error"}`);
3252
+ }
3253
+ process.exit(1);
3254
+ }
3255
+ };
3256
+ if (options.json) {
3257
+ const jsonLogger = createStderrLogger();
3258
+ await withLogger(jsonLogger, executeAction);
3259
+ } else {
3260
+ await executeAction();
2851
3261
  }
2852
3262
  });
2853
3263
  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) => {
2854
3264
  try {
2855
- const { RebaseCommand } = await import("./rebase-VJ2VKR6R.js");
3265
+ const { RebaseCommand } = await import("./rebase-55URTXZC.js");
2856
3266
  const command = new RebaseCommand();
2857
3267
  await command.execute(options);
2858
3268
  } catch (error) {
@@ -2864,7 +3274,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2864
3274
  new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
2865
3275
  ).action(async (options) => {
2866
3276
  try {
2867
- const { IgniteCommand } = await import("./ignite-T74RYXCA.js");
3277
+ const { IgniteCommand } = await import("./ignite-VSIPGKKG.js");
2868
3278
  const command = new IgniteCommand();
2869
3279
  await command.execute(options.oneShot ?? "default");
2870
3280
  } catch (error) {
@@ -2875,7 +3285,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
2875
3285
  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) => {
2876
3286
  try {
2877
3287
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2878
- const { OpenCommand } = await import("./open-UMXANW5S.js");
3288
+ const { OpenCommand } = await import("./open-CX7HUE26.js");
2879
3289
  const cmd = new OpenCommand();
2880
3290
  const input = identifier ? { identifier, args } : { args };
2881
3291
  await cmd.execute(input);
@@ -2887,7 +3297,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
2887
3297
  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) => {
2888
3298
  try {
2889
3299
  const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
2890
- const { RunCommand } = await import("./run-MJYY4PUT.js");
3300
+ const { RunCommand } = await import("./run-DP2U2CA2.js");
2891
3301
  const cmd = new RunCommand();
2892
3302
  const input = identifier ? { identifier, args } : { args };
2893
3303
  await cmd.execute(input);
@@ -2896,22 +3306,48 @@ program.command("run").description("Run CLI tool or open workspace in browser").
2896
3306
  process.exit(1);
2897
3307
  }
2898
3308
  });
2899
- 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").action(async (identifier, options) => {
3309
+ 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) => {
2900
3310
  try {
2901
- const { CleanupCommand } = await import("./cleanup-H4VXU3C3.js");
2902
- const command = new CleanupCommand();
2903
- const input = {
2904
- options: options ?? {}
2905
- };
2906
- if (identifier) {
2907
- input.identifier = identifier;
2908
- }
2909
- await command.execute(input);
3311
+ const { DevServerCommand } = await import("./dev-server-LOY7YWCP.js");
3312
+ const cmd = new DevServerCommand();
3313
+ await cmd.execute({ identifier, json: options == null ? void 0 : options.json });
2910
3314
  } catch (error) {
2911
- logger.error(`Failed to cleanup worktrees: ${error instanceof Error ? error.message : "Unknown error"}`);
3315
+ logger.error(`Failed to start dev server: ${error instanceof Error ? error.message : "Unknown error"}`);
2912
3316
  process.exit(1);
2913
3317
  }
2914
3318
  });
3319
+ 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").action(async (identifier, options) => {
3320
+ const executeAction = async () => {
3321
+ try {
3322
+ const { CleanupCommand } = await import("./cleanup-7QVPYBJJ.js");
3323
+ const command = new CleanupCommand();
3324
+ const input = {
3325
+ options: options ?? {}
3326
+ };
3327
+ if (identifier) {
3328
+ input.identifier = identifier;
3329
+ }
3330
+ const result = await command.execute(input);
3331
+ if ((options == null ? void 0 : options.json) && result) {
3332
+ console.log(JSON.stringify(result, null, 2));
3333
+ }
3334
+ process.exit(0);
3335
+ } catch (error) {
3336
+ if (options == null ? void 0 : options.json) {
3337
+ console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : "Unknown error" }, null, 2));
3338
+ } else {
3339
+ logger.error(error instanceof Error ? error.message : "Unknown error");
3340
+ }
3341
+ process.exit(1);
3342
+ }
3343
+ };
3344
+ if (options == null ? void 0 : options.json) {
3345
+ const jsonLogger = createStderrLogger();
3346
+ await withLogger(jsonLogger, executeAction);
3347
+ } else {
3348
+ await executeAction();
3349
+ }
3350
+ });
2915
3351
  program.command("list").description("Show active workspaces").option("--json", "Output as JSON").action(async (options) => {
2916
3352
  try {
2917
3353
  const manager = new GitWorktreeManager();
@@ -2955,9 +3391,20 @@ program.command("list").description("Show active workspaces").option("--json", "
2955
3391
  process.exit(1);
2956
3392
  }
2957
3393
  });
3394
+ program.command("projects").description("List configured iloom projects").option("--json", "Output as JSON (default behavior)").action(async (options) => {
3395
+ try {
3396
+ const { ProjectsCommand } = await import("./projects-6DTNDVLH.js");
3397
+ const command = new ProjectsCommand();
3398
+ const result = await command.execute(options);
3399
+ console.log(JSON.stringify(result, null, 2));
3400
+ } catch (error) {
3401
+ logger.error(`Failed to list projects: ${error instanceof Error ? error.message : "Unknown error"}`);
3402
+ process.exit(1);
3403
+ }
3404
+ });
2958
3405
  program.command("init").alias("config").description("Initialize iloom configuration and setup shell autocomplete").argument("[prompt]", 'Custom initial message to send to Claude (defaults to "Help me configure iloom settings.")').action(async (prompt) => {
2959
3406
  try {
2960
- const { InitCommand: InitCommand2 } = await import("./init-4FHTAM3F.js");
3407
+ const { InitCommand: InitCommand2 } = await import("./init-SCR2LQ4A.js");
2961
3408
  const command = new InitCommand2();
2962
3409
  const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
2963
3410
  const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
@@ -2969,7 +3416,7 @@ program.command("init").alias("config").description("Initialize iloom configurat
2969
3416
  });
2970
3417
  program.command("contribute").description("Set up local development environment for contributing to iloom").action(async () => {
2971
3418
  try {
2972
- const { ContributeCommand } = await import("./contribute-Y7IQV5QY.js");
3419
+ const { ContributeCommand } = await import("./contribute-RZYCYUDX.js");
2973
3420
  const command = new ContributeCommand();
2974
3421
  await command.execute();
2975
3422
  } catch (error) {
@@ -2979,7 +3426,7 @@ program.command("contribute").description("Set up local development environment
2979
3426
  });
2980
3427
  program.command("update").description("Update iloom-cli to the latest version").option("--dry-run", "Show what would be done without actually updating").action(async (options) => {
2981
3428
  try {
2982
- const { UpdateCommand } = await import("./update-4TDDUR5K.js");
3429
+ const { UpdateCommand } = await import("./update-LETF5ASC.js");
2983
3430
  const command = new UpdateCommand();
2984
3431
  await command.execute(options);
2985
3432
  } catch (error) {
@@ -2989,8 +3436,8 @@ program.command("update").description("Update iloom-cli to the latest version").
2989
3436
  });
2990
3437
  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) => {
2991
3438
  try {
2992
- const { GitHubService: GitHubService2 } = await import("./GitHubService-FZHHBOFG.js");
2993
- const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-A77VI6AI.js");
3439
+ const { GitHubService: GitHubService2 } = await import("./GitHubService-RPM27GWD.js");
3440
+ const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-TOM2KAUT.js");
2994
3441
  logger.info("Testing GitHub Integration\n");
2995
3442
  const service = new GitHubService2();
2996
3443
  const branchNaming = new DefaultBranchNamingService2({ useClaude: options.claude !== false });
@@ -3048,10 +3495,10 @@ program.command("test-github").description("Test GitHub integration (Issue #3)")
3048
3495
  });
3049
3496
  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) => {
3050
3497
  try {
3051
- const { detectClaudeCli: detectClaudeCli2, getClaudeVersion, generateBranchName, launchClaude: launchClaude2 } = await import("./claude-W52VKI6L.js");
3052
- const { PromptTemplateManager } = await import("./PromptTemplateManager-6HH3PVXV.js");
3053
- const { ClaudeService } = await import("./ClaudeService-DLYLJUPA.js");
3054
- const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-BN7RE5ZQ.js");
3498
+ const { detectClaudeCli: detectClaudeCli2, getClaudeVersion, generateBranchName, launchClaude: launchClaude2 } = await import("./claude-X7EBJRB2.js");
3499
+ const { PromptTemplateManager } = await import("./PromptTemplateManager-2TDZAUC6.js");
3500
+ const { ClaudeService } = await import("./ClaudeService-ICSHJMQ5.js");
3501
+ const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-VEGJTS5E.js");
3055
3502
  logger.info("Testing Claude Integration\n");
3056
3503
  if (options.detect) {
3057
3504
  logger.info("Detecting Claude CLI...");
@@ -3186,7 +3633,7 @@ program.command("test-claude").description("Test Claude integration (Issue #10)"
3186
3633
  });
3187
3634
  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) => {
3188
3635
  try {
3189
- const { TestWebserverCommand } = await import("./test-webserver-DAHONWCS.js");
3636
+ const { TestWebserverCommand } = await import("./test-webserver-VPNLAFZ3.js");
3190
3637
  const command = new TestWebserverCommand();
3191
3638
  await command.execute({ issueNumber, options });
3192
3639
  } catch (error) {
@@ -3199,7 +3646,7 @@ program.command("test-webserver").description("Test if a web server is running o
3199
3646
  });
3200
3647
  program.command("test-git").description("Test Git integration - findMainWorktreePath() function (reads .iloom/settings.json)").action(async () => {
3201
3648
  try {
3202
- const { TestGitCommand } = await import("./test-git-IT5EWQ5C.js");
3649
+ const { TestGitCommand } = await import("./test-git-QLAIBJLX.js");
3203
3650
  const command = new TestGitCommand();
3204
3651
  await command.execute();
3205
3652
  } catch (error) {
@@ -3212,7 +3659,7 @@ program.command("test-git").description("Test Git integration - findMainWorktree
3212
3659
  });
3213
3660
  program.command("test-tabs").description("Test iTerm2 dual tab functionality - opens two tabs with test commands").action(async () => {
3214
3661
  try {
3215
- const { TestTabsCommand } = await import("./test-tabs-PRMRSHKI.js");
3662
+ const { TestTabsCommand } = await import("./test-tabs-JGO3VOXJ.js");
3216
3663
  const command = new TestTabsCommand();
3217
3664
  await command.execute();
3218
3665
  } catch (error) {
@@ -3225,7 +3672,7 @@ program.command("test-tabs").description("Test iTerm2 dual tab functionality - o
3225
3672
  });
3226
3673
  program.command("test-prefix").description("Test worktree prefix configuration - preview worktree paths (reads .iloom/settings.json)").action(async () => {
3227
3674
  try {
3228
- const { TestPrefixCommand } = await import("./test-prefix-NPWDPUUH.js");
3675
+ const { TestPrefixCommand } = await import("./test-prefix-6YM2ZOON.js");
3229
3676
  const command = new TestPrefixCommand();
3230
3677
  await command.execute();
3231
3678
  } catch (error) {
@@ -3236,11 +3683,40 @@ program.command("test-prefix").description("Test worktree prefix configuration -
3236
3683
  process.exit(1);
3237
3684
  }
3238
3685
  });
3686
+ 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) => {
3687
+ const executeAction = async () => {
3688
+ try {
3689
+ const { SummaryCommand } = await import("./summary-J3CJSM7L.js");
3690
+ const command = new SummaryCommand();
3691
+ const result = await command.execute({ identifier, options });
3692
+ if (options.json && result) {
3693
+ console.log(JSON.stringify(result, null, 2));
3694
+ }
3695
+ process.exit(0);
3696
+ } catch (error) {
3697
+ if (options.json) {
3698
+ console.log(JSON.stringify({ error: error instanceof Error ? error.message : "Unknown error" }, null, 2));
3699
+ } else {
3700
+ logger.error(`Summary failed: ${error instanceof Error ? error.message : "Unknown error"}`);
3701
+ if (error instanceof Error && error.stack) {
3702
+ logger.debug(error.stack);
3703
+ }
3704
+ }
3705
+ process.exit(1);
3706
+ }
3707
+ };
3708
+ if (options.json) {
3709
+ const jsonLogger = createStderrLogger();
3710
+ await withLogger(jsonLogger, executeAction);
3711
+ } else {
3712
+ await executeAction();
3713
+ }
3714
+ });
3239
3715
  program.command("test-neon").description("Test Neon integration and debug configuration").action(async () => {
3240
3716
  var _a;
3241
3717
  try {
3242
- const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-I2LRCW2A.js");
3243
- const { createNeonProviderFromSettings: createNeonProviderFromSettings2 } = await import("./neon-helpers-77PBPGJ5.js");
3718
+ const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-FJFU6JJD.js");
3719
+ const { createNeonProviderFromSettings: createNeonProviderFromSettings2 } = await import("./neon-helpers-L5CXQ5CT.js");
3244
3720
  logger.info("Testing Neon Integration\n");
3245
3721
  logger.info("1. Settings Configuration:");
3246
3722
  const settingsManager = new SettingsManager2();