@iloom/cli 0.3.4 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/README.md +13 -3
  2. package/dist/{BranchNamingService-A77VI6AI.js → BranchNamingService-GCCWB3LK.js} +4 -3
  3. package/dist/ClaudeContextManager-DK77227F.js +16 -0
  4. package/dist/ClaudeService-W3SA7HVG.js +15 -0
  5. package/dist/GitHubService-RPM27GWD.js +12 -0
  6. package/dist/{LoomLauncher-ZV3ZZIBA.js → LoomLauncher-S3YGJRJQ.js} +43 -27
  7. package/dist/LoomLauncher-S3YGJRJQ.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-5Q3NDNNV.js → chunk-2W2FBL5G.js} +153 -6
  13. package/dist/chunk-2W2FBL5G.js.map +1 -0
  14. package/dist/{chunk-OXAM2WVC.js → chunk-55TB3FSG.js} +21 -1
  15. package/dist/chunk-55TB3FSG.js.map +1 -0
  16. package/dist/chunk-6UIGZD2N.js +20 -0
  17. package/dist/chunk-6UIGZD2N.js.map +1 -0
  18. package/dist/{chunk-RIEO2WML.js → chunk-74VMN2KC.js} +26 -2
  19. package/dist/chunk-74VMN2KC.js.map +1 -0
  20. package/dist/{chunk-2MAIX45J.js → chunk-BIIQHEXJ.js} +104 -43
  21. package/dist/chunk-BIIQHEXJ.js.map +1 -0
  22. package/dist/{chunk-UAN4A3YU.js → chunk-G6CIIJLT.js} +11 -11
  23. package/dist/{chunk-DLHA5VQ3.js → chunk-HD5SUKI2.js} +36 -179
  24. package/dist/chunk-HD5SUKI2.js.map +1 -0
  25. package/dist/{chunk-2IJEMXOB.js → chunk-IARWMDAX.js} +427 -428
  26. package/dist/chunk-IARWMDAX.js.map +1 -0
  27. package/dist/chunk-IJ7IGJT3.js +192 -0
  28. package/dist/chunk-IJ7IGJT3.js.map +1 -0
  29. package/dist/{chunk-2CXREBLZ.js → chunk-JC5HXN75.js} +8 -6
  30. package/dist/chunk-JC5HXN75.js.map +1 -0
  31. package/dist/{chunk-3RUPPQRG.js → chunk-KO2FOMHL.js} +43 -2
  32. package/dist/{chunk-3RUPPQRG.js.map → chunk-KO2FOMHL.js.map} +1 -1
  33. package/dist/{chunk-4XIDC3NF.js → chunk-MD6HA5IK.js} +2 -2
  34. package/dist/{chunk-OC4H6HJD.js → chunk-O7WHXLCB.js} +2 -2
  35. package/dist/{chunk-M7JJCX53.js → chunk-OEGECBFS.js} +20 -20
  36. package/dist/chunk-OEGECBFS.js.map +1 -0
  37. package/dist/{chunk-MKWYLDFK.js → chunk-OF7BNW4D.js} +43 -3
  38. package/dist/chunk-OF7BNW4D.js.map +1 -0
  39. package/dist/{chunk-PGPI5LR4.js → chunk-POI7KLBH.js} +7 -21
  40. package/dist/chunk-POI7KLBH.js.map +1 -0
  41. package/dist/{chunk-PA6Q6AWM.js → chunk-PSFVTBM7.js} +2 -2
  42. package/dist/chunk-QHA67Q7A.js +281 -0
  43. package/dist/chunk-QHA67Q7A.js.map +1 -0
  44. package/dist/{chunk-SUOXY5WJ.js → chunk-QIUJPPJQ.js} +5 -5
  45. package/dist/chunk-QIUJPPJQ.js.map +1 -0
  46. package/dist/{chunk-ZM3CFL5L.js → chunk-QRBOPFAA.js} +3 -3
  47. package/dist/{chunk-OYF4VIFI.js → chunk-RUC7OULH.js} +147 -22
  48. package/dist/chunk-RUC7OULH.js.map +1 -0
  49. package/dist/{chunk-CE26YH2U.js → chunk-SJ2GZ6RF.js} +48 -50
  50. package/dist/chunk-SJ2GZ6RF.js.map +1 -0
  51. package/dist/{chunk-SSCQCCJ7.js → chunk-THF25ICZ.js} +2 -2
  52. package/dist/chunk-TMZAVPGF.js +667 -0
  53. package/dist/chunk-TMZAVPGF.js.map +1 -0
  54. package/dist/{chunk-5VK4NRSF.js → chunk-UNXRACJ7.js} +35 -36
  55. package/dist/chunk-UNXRACJ7.js.map +1 -0
  56. package/dist/{chunk-AKUJXDNW.js → chunk-UPUAQYAW.js} +3 -3
  57. package/dist/{chunk-GEHQXLEI.js → chunk-UYVWLISQ.js} +18 -35
  58. package/dist/chunk-UYVWLISQ.js.map +1 -0
  59. package/dist/{chunk-OSCLCMDG.js → chunk-UYWAESOT.js} +3 -3
  60. package/dist/{chunk-RW54ZMBM.js → chunk-VAYGNQTE.js} +2 -2
  61. package/dist/{chunk-ZT3YZB4K.js → chunk-VBFDVGAE.js} +12 -12
  62. package/dist/chunk-VBFDVGAE.js.map +1 -0
  63. package/dist/{chunk-IFB4Z76W.js → chunk-VTXCGKV5.js} +13 -12
  64. package/dist/chunk-VTXCGKV5.js.map +1 -0
  65. package/dist/{chunk-CDZERT7Z.js → chunk-VWNS6DH5.js} +48 -4
  66. package/dist/chunk-VWNS6DH5.js.map +1 -0
  67. package/dist/{chunk-CFFQ2Z7A.js → chunk-WUQQNE63.js} +2 -2
  68. package/dist/{chunk-UJL4HI2R.js → chunk-Z5NXYJIG.js} +20 -2
  69. package/dist/chunk-Z5NXYJIG.js.map +1 -0
  70. package/dist/{claude-W52VKI6L.js → claude-ACVXNB6N.js} +8 -5
  71. package/dist/{cleanup-H4VXU3C3.js → cleanup-KDLVTT7M.js} +133 -122
  72. package/dist/cleanup-KDLVTT7M.js.map +1 -0
  73. package/dist/cli.js +953 -430
  74. package/dist/cli.js.map +1 -1
  75. package/dist/{color-F7RU6B6Z.js → color-ZPIIUADB.js} +3 -3
  76. package/dist/{contribute-Y7IQV5QY.js → contribute-HY372S6F.js} +8 -6
  77. package/dist/{contribute-Y7IQV5QY.js.map → contribute-HY372S6F.js.map} +1 -1
  78. package/dist/dev-server-JCJGQ3PV.js +298 -0
  79. package/dist/dev-server-JCJGQ3PV.js.map +1 -0
  80. package/dist/{feedback-XTUCKJNT.js → feedback-7PVBQNLJ.js} +13 -12
  81. package/dist/{feedback-XTUCKJNT.js.map → feedback-7PVBQNLJ.js.map} +1 -1
  82. package/dist/{git-IYA53VIC.js → git-4BVOOOOV.js} +16 -4
  83. package/dist/hooks/iloom-hook.js +258 -0
  84. package/dist/{ignite-T74RYXCA.js → ignite-3B264M7K.js} +245 -39
  85. package/dist/ignite-3B264M7K.js.map +1 -0
  86. package/dist/index.d.ts +461 -124
  87. package/dist/index.js +743 -210
  88. package/dist/index.js.map +1 -1
  89. package/dist/init-LBA6NUK2.js +21 -0
  90. package/dist/{installation-detector-VARGFFRZ.js → installation-detector-6R6YOFVZ.js} +3 -3
  91. package/dist/mcp/issue-management-server.js +2 -1
  92. package/dist/mcp/issue-management-server.js.map +1 -1
  93. package/dist/neon-helpers-L5CXQ5CT.js +11 -0
  94. package/dist/{open-UMXANW5S.js → open-OGCV32Z4.js} +15 -13
  95. package/dist/{open-UMXANW5S.js.map → open-OGCV32Z4.js.map} +1 -1
  96. package/dist/projects-P55273AB.js +73 -0
  97. package/dist/projects-P55273AB.js.map +1 -0
  98. package/dist/{prompt-QALMYTVC.js → prompt-A7GGRHSY.js} +3 -3
  99. package/dist/prompts/init-prompt.txt +49 -0
  100. package/dist/prompts/issue-prompt.txt +110 -8
  101. package/dist/prompts/regular-prompt.txt +90 -0
  102. package/dist/prompts/session-summary-prompt.txt +82 -0
  103. package/dist/{rebase-VJ2VKR6R.js → rebase-4T5FQHNH.js} +11 -9
  104. package/dist/{rebase-VJ2VKR6R.js.map → rebase-4T5FQHNH.js.map} +1 -1
  105. package/dist/{remote-VUNCQZ6J.js → remote-73TZ2ADI.js} +3 -3
  106. package/dist/{run-MJYY4PUT.js → run-HNOP6WE2.js} +15 -13
  107. package/dist/{run-MJYY4PUT.js.map → run-HNOP6WE2.js.map} +1 -1
  108. package/dist/schema/settings.schema.json +49 -0
  109. package/dist/shell-DE3HKJSM.js +240 -0
  110. package/dist/shell-DE3HKJSM.js.map +1 -0
  111. package/dist/summary-GDT7DTRI.js +244 -0
  112. package/dist/summary-GDT7DTRI.js.map +1 -0
  113. package/dist/{test-git-IT5EWQ5C.js → test-git-YMAE57UP.js} +6 -4
  114. package/dist/{test-git-IT5EWQ5C.js.map → test-git-YMAE57UP.js.map} +1 -1
  115. package/dist/{test-prefix-NPWDPUUH.js → test-prefix-YCKL6CMT.js} +6 -4
  116. package/dist/{test-prefix-NPWDPUUH.js.map → test-prefix-YCKL6CMT.js.map} +1 -1
  117. package/dist/{test-tabs-PRMRSHKI.js → test-tabs-3SCJWRKT.js} +4 -4
  118. package/dist/{test-webserver-DAHONWCS.js → test-webserver-VPNLAFZ3.js} +2 -2
  119. package/dist/{update-4TDDUR5K.js → update-LETF5ASC.js} +4 -4
  120. package/dist/{update-notifier-QEX3CJHA.js → update-notifier-H55ZK7NU.js} +3 -3
  121. package/package.json +6 -6
  122. package/dist/ClaudeContextManager-BN7RE5ZQ.js +0 -15
  123. package/dist/ClaudeService-DLYLJUPA.js +0 -14
  124. package/dist/GitHubService-FZHHBOFG.js +0 -11
  125. package/dist/LoomLauncher-ZV3ZZIBA.js.map +0 -1
  126. package/dist/PromptTemplateManager-6HH3PVXV.js +0 -9
  127. package/dist/SettingsMigrationManager-TJ7UWZG5.js +0 -10
  128. package/dist/chunk-2CXREBLZ.js.map +0 -1
  129. package/dist/chunk-2IJEMXOB.js.map +0 -1
  130. package/dist/chunk-2MAIX45J.js.map +0 -1
  131. package/dist/chunk-5Q3NDNNV.js.map +0 -1
  132. package/dist/chunk-5VK4NRSF.js.map +0 -1
  133. package/dist/chunk-CDZERT7Z.js.map +0 -1
  134. package/dist/chunk-CE26YH2U.js.map +0 -1
  135. package/dist/chunk-DLHA5VQ3.js.map +0 -1
  136. package/dist/chunk-GEHQXLEI.js.map +0 -1
  137. package/dist/chunk-IFB4Z76W.js.map +0 -1
  138. package/dist/chunk-M7JJCX53.js.map +0 -1
  139. package/dist/chunk-MKWYLDFK.js.map +0 -1
  140. package/dist/chunk-OXAM2WVC.js.map +0 -1
  141. package/dist/chunk-OYF4VIFI.js.map +0 -1
  142. package/dist/chunk-PGPI5LR4.js.map +0 -1
  143. package/dist/chunk-RIEO2WML.js.map +0 -1
  144. package/dist/chunk-SUOXY5WJ.js.map +0 -1
  145. package/dist/chunk-UJL4HI2R.js.map +0 -1
  146. package/dist/chunk-ZT3YZB4K.js.map +0 -1
  147. package/dist/cleanup-H4VXU3C3.js.map +0 -1
  148. package/dist/ignite-T74RYXCA.js.map +0 -1
  149. package/dist/init-4FHTAM3F.js +0 -19
  150. package/dist/logger-MKYH4UDV.js +0 -12
  151. package/dist/neon-helpers-77PBPGJ5.js +0 -10
  152. package/dist/update-notifier-QEX3CJHA.js.map +0 -1
  153. /package/dist/{BranchNamingService-A77VI6AI.js.map → BranchNamingService-GCCWB3LK.js.map} +0 -0
  154. /package/dist/{ClaudeContextManager-BN7RE5ZQ.js.map → ClaudeContextManager-DK77227F.js.map} +0 -0
  155. /package/dist/{ClaudeService-DLYLJUPA.js.map → ClaudeService-W3SA7HVG.js.map} +0 -0
  156. /package/dist/{GitHubService-FZHHBOFG.js.map → GitHubService-RPM27GWD.js.map} +0 -0
  157. /package/dist/{PromptTemplateManager-6HH3PVXV.js.map → PromptTemplateManager-2TDZAUC6.js.map} +0 -0
  158. /package/dist/{SettingsManager-I2LRCW2A.js.map → SettingsManager-FJFU6JJD.js.map} +0 -0
  159. /package/dist/{SettingsMigrationManager-TJ7UWZG5.js.map → SettingsMigrationManager-EH3J2TCN.js.map} +0 -0
  160. /package/dist/{chunk-UAN4A3YU.js.map → chunk-G6CIIJLT.js.map} +0 -0
  161. /package/dist/{chunk-4XIDC3NF.js.map → chunk-MD6HA5IK.js.map} +0 -0
  162. /package/dist/{chunk-OC4H6HJD.js.map → chunk-O7WHXLCB.js.map} +0 -0
  163. /package/dist/{chunk-PA6Q6AWM.js.map → chunk-PSFVTBM7.js.map} +0 -0
  164. /package/dist/{chunk-ZM3CFL5L.js.map → chunk-QRBOPFAA.js.map} +0 -0
  165. /package/dist/{chunk-SSCQCCJ7.js.map → chunk-THF25ICZ.js.map} +0 -0
  166. /package/dist/{chunk-AKUJXDNW.js.map → chunk-UPUAQYAW.js.map} +0 -0
  167. /package/dist/{chunk-OSCLCMDG.js.map → chunk-UYWAESOT.js.map} +0 -0
  168. /package/dist/{chunk-RW54ZMBM.js.map → chunk-VAYGNQTE.js.map} +0 -0
  169. /package/dist/{chunk-CFFQ2Z7A.js.map → chunk-WUQQNE63.js.map} +0 -0
  170. /package/dist/{claude-W52VKI6L.js.map → claude-ACVXNB6N.js.map} +0 -0
  171. /package/dist/{color-F7RU6B6Z.js.map → color-ZPIIUADB.js.map} +0 -0
  172. /package/dist/{git-IYA53VIC.js.map → git-4BVOOOOV.js.map} +0 -0
  173. /package/dist/{init-4FHTAM3F.js.map → init-LBA6NUK2.js.map} +0 -0
  174. /package/dist/{installation-detector-VARGFFRZ.js.map → installation-detector-6R6YOFVZ.js.map} +0 -0
  175. /package/dist/{logger-MKYH4UDV.js.map → neon-helpers-L5CXQ5CT.js.map} +0 -0
  176. /package/dist/{neon-helpers-77PBPGJ5.js.map → prompt-A7GGRHSY.js.map} +0 -0
  177. /package/dist/{prompt-QALMYTVC.js.map → remote-73TZ2ADI.js.map} +0 -0
  178. /package/dist/{test-tabs-PRMRSHKI.js.map → test-tabs-3SCJWRKT.js.map} +0 -0
  179. /package/dist/{test-webserver-DAHONWCS.js.map → test-webserver-VPNLAFZ3.js.map} +0 -0
  180. /package/dist/{update-4TDDUR5K.js.map → update-LETF5ASC.js.map} +0 -0
  181. /package/dist/{remote-VUNCQZ6J.js.map → update-notifier-H55ZK7NU.js.map} +0 -0
package/dist/index.js CHANGED
@@ -9,12 +9,6 @@ var __export = (target, all) => {
9
9
  };
10
10
 
11
11
  // src/utils/logger.ts
12
- var logger_exports = {};
13
- __export(logger_exports, {
14
- createLogger: () => createLogger,
15
- default: () => logger_default,
16
- logger: () => logger
17
- });
18
12
  import chalk, { Chalk } from "chalk";
19
13
  function formatMessage(message, ...args) {
20
14
  const formattedArgs = args.map(
@@ -52,7 +46,8 @@ function createLogger(options = {}) {
52
46
  },
53
47
  isDebugEnabled: () => {
54
48
  return false;
55
- }
49
+ },
50
+ stdout: process.stdout
56
51
  };
57
52
  }
58
53
  return {
@@ -93,7 +88,57 @@ function createLogger(options = {}) {
93
88
  },
94
89
  isDebugEnabled: () => {
95
90
  return globalDebugEnabled;
96
- }
91
+ },
92
+ stdout: process.stdout
93
+ };
94
+ }
95
+ function createStderrLogger(options = {}) {
96
+ const { prefix = "", timestamp = false, forceColor, debug = globalDebugEnabled } = options;
97
+ let localDebugEnabled = debug;
98
+ const customChalk = forceColor !== void 0 ? new Chalk({ level: forceColor ? 3 : 0 }) : stderrChalk;
99
+ const prefixStr = prefix ? `[${prefix}] ` : "";
100
+ const getTimestamp = () => timestamp ? `[${(/* @__PURE__ */ new Date()).toISOString()}] ` : "";
101
+ return {
102
+ info: (message, ...args) => {
103
+ const formatted = formatMessage(message, ...args);
104
+ const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`;
105
+ const output = formatWithEmoji(fullMessage, "\u{1F5C2}\uFE0F ", customChalk.blue);
106
+ console.error(output);
107
+ },
108
+ success: (message, ...args) => {
109
+ const formatted = formatMessage(message, ...args);
110
+ const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`;
111
+ const output = formatWithEmoji(fullMessage, "\u2705", customChalk.green);
112
+ console.error(output);
113
+ },
114
+ warn: (message, ...args) => {
115
+ const formatted = formatMessage(message, ...args);
116
+ const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`;
117
+ const output = formatWithEmoji(fullMessage, "\u26A0\uFE0F ", customChalk.yellow);
118
+ console.error(output);
119
+ },
120
+ error: (message, ...args) => {
121
+ const formatted = formatMessage(message, ...args);
122
+ const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`;
123
+ const output = formatWithEmoji(fullMessage, "\u274C", customChalk.red);
124
+ console.error(output);
125
+ },
126
+ debug: (message, ...args) => {
127
+ if (localDebugEnabled) {
128
+ const formatted = formatMessage(message, ...args);
129
+ const fullMessage = `${getTimestamp()}${prefixStr}${formatted}`;
130
+ const output = formatWithEmoji(fullMessage, "\u{1F50D}", customChalk.gray);
131
+ console.error(output);
132
+ }
133
+ },
134
+ setDebug: (enabled) => {
135
+ localDebugEnabled = enabled;
136
+ },
137
+ isDebugEnabled: () => {
138
+ return globalDebugEnabled;
139
+ },
140
+ stdout: process.stderr
141
+ // Use stderr for progress output in JSON mode
97
142
  };
98
143
  }
99
144
  var stdoutChalk, stderrChalk, globalDebugEnabled, logger, logger_default;
@@ -136,7 +181,8 @@ var init_logger = __esm({
136
181
  },
137
182
  isDebugEnabled: () => {
138
183
  return globalDebugEnabled;
139
- }
184
+ },
185
+ stdout: process.stdout
140
186
  };
141
187
  logger_default = logger;
142
188
  }
@@ -153,6 +199,8 @@ __export(SettingsManager_exports, {
153
199
  IloomSettingsSchemaNoDefaults: () => IloomSettingsSchemaNoDefaults,
154
200
  NeonSettingsSchema: () => NeonSettingsSchema,
155
201
  SettingsManager: () => SettingsManager,
202
+ SpinAgentSettingsSchema: () => SpinAgentSettingsSchema,
203
+ SummarySettingsSchema: () => SummarySettingsSchema,
156
204
  WorkflowPermissionSchema: () => WorkflowPermissionSchema,
157
205
  WorkflowPermissionSchemaNoDefaults: () => WorkflowPermissionSchemaNoDefaults,
158
206
  WorkflowsSettingsSchema: () => WorkflowsSettingsSchema,
@@ -163,7 +211,7 @@ import path from "path";
163
211
  import os from "os";
164
212
  import { z } from "zod";
165
213
  import deepmerge from "deepmerge";
166
- var AgentSettingsSchema, WorkflowPermissionSchema, WorkflowPermissionSchemaNoDefaults, WorkflowsSettingsSchema, WorkflowsSettingsSchemaNoDefaults, CapabilitiesSettingsSchema, CapabilitiesSettingsSchemaNoDefaults, NeonSettingsSchema, DatabaseProvidersSettingsSchema, IloomSettingsSchema, IloomSettingsSchemaNoDefaults, SettingsManager;
214
+ var AgentSettingsSchema, SpinAgentSettingsSchema, SummarySettingsSchema, WorkflowPermissionSchema, WorkflowPermissionSchemaNoDefaults, WorkflowsSettingsSchema, WorkflowsSettingsSchemaNoDefaults, CapabilitiesSettingsSchema, CapabilitiesSettingsSchemaNoDefaults, NeonSettingsSchema, DatabaseProvidersSettingsSchema, IloomSettingsSchema, IloomSettingsSchemaNoDefaults, SettingsManager;
167
215
  var init_SettingsManager = __esm({
168
216
  "src/lib/SettingsManager.ts"() {
169
217
  "use strict";
@@ -172,13 +220,20 @@ var init_SettingsManager = __esm({
172
220
  model: z.enum(["sonnet", "opus", "haiku"]).optional().describe("Claude model shorthand: sonnet, opus, or haiku")
173
221
  // Future: could add other per-agent overrides
174
222
  });
223
+ SpinAgentSettingsSchema = z.object({
224
+ model: z.enum(["sonnet", "opus", "haiku"]).default("opus").describe("Claude model shorthand for spin orchestrator")
225
+ });
226
+ SummarySettingsSchema = z.object({
227
+ model: z.enum(["sonnet", "opus", "haiku"]).default("sonnet").describe("Claude model shorthand for session summary generation")
228
+ });
175
229
  WorkflowPermissionSchema = z.object({
176
230
  permissionMode: z.enum(["plan", "acceptEdits", "bypassPermissions", "default"]).optional().describe("Permission mode for Claude CLI in this workflow type"),
177
231
  noVerify: z.boolean().optional().describe("Skip pre-commit hooks (--no-verify) when committing during finish workflow"),
178
232
  startIde: z.boolean().default(true).describe("Launch IDE (code) when starting this workflow type"),
179
233
  startDevServer: z.boolean().default(true).describe("Launch development server when starting this workflow type"),
180
234
  startAiAgent: z.boolean().default(true).describe("Launch Claude Code agent when starting this workflow type"),
181
- startTerminal: z.boolean().default(false).describe("Launch terminal window without dev server when starting this workflow type")
235
+ startTerminal: z.boolean().default(false).describe("Launch terminal window without dev server when starting this workflow type"),
236
+ generateSummary: z.boolean().default(true).describe("Generate and post Claude session summary when finishing this workflow type")
182
237
  });
183
238
  WorkflowPermissionSchemaNoDefaults = z.object({
184
239
  permissionMode: z.enum(["plan", "acceptEdits", "bypassPermissions", "default"]).optional().describe("Permission mode for Claude CLI in this workflow type"),
@@ -186,7 +241,8 @@ var init_SettingsManager = __esm({
186
241
  startIde: z.boolean().optional().describe("Launch IDE (code) when starting this workflow type"),
187
242
  startDevServer: z.boolean().optional().describe("Launch development server when starting this workflow type"),
188
243
  startAiAgent: z.boolean().optional().describe("Launch Claude Code agent when starting this workflow type"),
189
- startTerminal: z.boolean().optional().describe("Launch terminal window without dev server when starting this workflow type")
244
+ startTerminal: z.boolean().optional().describe("Launch terminal window without dev server when starting this workflow type"),
245
+ generateSummary: z.boolean().optional().describe("Generate and post Claude session summary when finishing this workflow type")
190
246
  });
191
247
  WorkflowsSettingsSchema = z.object({
192
248
  issue: WorkflowPermissionSchema.optional(),
@@ -254,6 +310,12 @@ var init_SettingsManager = __esm({
254
310
  agents: z.record(z.string(), AgentSettingsSchema).optional().nullable().describe(
255
311
  "Per-agent configuration overrides. Available agents: iloom-issue-analyzer (analyzes issues), iloom-issue-planner (creates implementation plans), iloom-issue-analyze-and-plan (combined analysis and planning), iloom-issue-complexity-evaluator (evaluates complexity), iloom-issue-enhancer (enhances issue descriptions), iloom-issue-implementer (implements code changes), iloom-issue-reviewer (reviews code changes against requirements)"
256
312
  ),
313
+ spin: SpinAgentSettingsSchema.optional().describe(
314
+ "Spin orchestrator configuration. Model defaults to opus when not configured."
315
+ ),
316
+ summary: SummarySettingsSchema.optional().describe(
317
+ "Session summary generation configuration. Model defaults to sonnet when not configured."
318
+ ),
257
319
  capabilities: CapabilitiesSettingsSchema.describe("Project capability configurations"),
258
320
  databaseProviders: DatabaseProvidersSettingsSchema.describe("Database provider configurations"),
259
321
  issueManagement: z.object({
@@ -316,6 +378,12 @@ var init_SettingsManager = __esm({
316
378
  agents: z.record(z.string(), AgentSettingsSchema).optional().nullable().describe(
317
379
  "Per-agent configuration overrides. Available agents: iloom-issue-analyzer (analyzes issues), iloom-issue-planner (creates implementation plans), iloom-issue-analyze-and-plan (combined analysis and planning), iloom-issue-complexity-evaluator (evaluates complexity), iloom-issue-enhancer (enhances issue descriptions), iloom-issue-implementer (implements code changes), iloom-issue-reviewer (reviews code changes against requirements)"
318
380
  ),
381
+ spin: z.object({
382
+ model: z.enum(["sonnet", "opus", "haiku"]).optional()
383
+ }).optional().describe("Spin orchestrator configuration"),
384
+ summary: z.object({
385
+ model: z.enum(["sonnet", "opus", "haiku"]).optional()
386
+ }).optional().describe("Session summary generation configuration"),
319
387
  capabilities: CapabilitiesSettingsSchemaNoDefaults.describe("Project capability configurations"),
320
388
  databaseProviders: DatabaseProvidersSettingsSchema.describe("Database provider configurations"),
321
389
  issueManagement: z.object({
@@ -445,8 +513,8 @@ Note: CLI overrides were applied. Check your --set arguments.`);
445
513
  */
446
514
  formatAllZodErrors(error, settingsPath) {
447
515
  const errorMessages = error.issues.map((issue) => {
448
- const path6 = issue.path.length > 0 ? issue.path.join(".") : "root";
449
- return ` - ${path6}: ${issue.message}`;
516
+ const path7 = issue.path.length > 0 ? issue.path.join(".") : "root";
517
+ return ` - ${path7}: ${issue.message}`;
450
518
  });
451
519
  return new Error(
452
520
  `Settings validation failed at ${settingsPath}:
@@ -548,6 +616,28 @@ ${errorMessages.join("\n")}`
548
616
  }
549
617
  return protectedBranches;
550
618
  }
619
+ /**
620
+ * Get the spin orchestrator model with default applied
621
+ * Default is defined in SpinAgentSettingsSchema
622
+ *
623
+ * @param settings - Pre-loaded settings object
624
+ * @returns Model shorthand ('opus', 'sonnet', or 'haiku')
625
+ */
626
+ getSpinModel(settings) {
627
+ var _a;
628
+ return ((_a = settings == null ? void 0 : settings.spin) == null ? void 0 : _a.model) ?? SpinAgentSettingsSchema.parse({}).model;
629
+ }
630
+ /**
631
+ * Get the session summary model with default applied
632
+ * Default is defined in SummarySettingsSchema
633
+ *
634
+ * @param settings - Pre-loaded settings object
635
+ * @returns Model shorthand ('opus', 'sonnet', or 'haiku')
636
+ */
637
+ getSummaryModel(settings) {
638
+ var _a;
639
+ return ((_a = settings == null ? void 0 : settings.summary) == null ? void 0 : _a.model) ?? SummarySettingsSchema.parse({}).model;
640
+ }
551
641
  };
552
642
  }
553
643
  });
@@ -728,14 +818,209 @@ var WorkspaceManager = class {
728
818
  };
729
819
 
730
820
  // src/lib/GitWorktreeManager.ts
821
+ import path4 from "path";
822
+ import fs2 from "fs-extra";
823
+
824
+ // src/utils/git.ts
825
+ init_SettingsManager();
731
826
  import path3 from "path";
827
+ import { execa } from "execa";
828
+
829
+ // src/lib/MetadataManager.ts
830
+ import path2 from "path";
831
+ import os2 from "os";
732
832
  import fs from "fs-extra";
733
833
 
834
+ // src/utils/logger-context.ts
835
+ init_logger();
836
+ import { AsyncLocalStorage } from "async_hooks";
837
+ var loggerStorage = new AsyncLocalStorage();
838
+ function getLogger() {
839
+ return loggerStorage.getStore() ?? logger;
840
+ }
841
+
842
+ // src/lib/MetadataManager.ts
843
+ var MetadataManager = class {
844
+ constructor() {
845
+ this.loomsDir = path2.join(os2.homedir(), ".config", "iloom-ai", "looms");
846
+ }
847
+ /**
848
+ * Convert worktree path to filename slug per spec section 2.2
849
+ *
850
+ * Algorithm:
851
+ * 1. Trim trailing slashes
852
+ * 2. Replace all path separators (/ or \) with __ (double underscore)
853
+ * 3. Replace any other non-alphanumeric characters (except _ and -) with -
854
+ * 4. Append .json
855
+ *
856
+ * Example:
857
+ * - Worktree: /Users/jane/dev/repo
858
+ * - Filename: _Users__jane__dev__repo.json
859
+ */
860
+ slugifyPath(worktreePath) {
861
+ let slug = worktreePath.replace(/[/\\]+$/, "");
862
+ slug = slug.replace(/[/\\]/g, "___");
863
+ slug = slug.replace(/[^a-zA-Z0-9_-]/g, "-");
864
+ return `${slug}.json`;
865
+ }
866
+ /**
867
+ * Get the full path to the metadata file for a worktree
868
+ */
869
+ getFilePath(worktreePath) {
870
+ const filename = this.slugifyPath(worktreePath);
871
+ return path2.join(this.loomsDir, filename);
872
+ }
873
+ /**
874
+ * Write metadata for a worktree (spec section 3.1)
875
+ *
876
+ * @param worktreePath - Absolute path to the worktree (used for file naming)
877
+ * @param input - Metadata to write (description plus additional fields)
878
+ */
879
+ async writeMetadata(worktreePath, input) {
880
+ try {
881
+ await fs.ensureDir(this.loomsDir, { mode: 493 });
882
+ const content = {
883
+ description: input.description,
884
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
885
+ version: 1,
886
+ branchName: input.branchName,
887
+ worktreePath: input.worktreePath,
888
+ issueType: input.issueType,
889
+ issue_numbers: input.issue_numbers,
890
+ pr_numbers: input.pr_numbers,
891
+ issueTracker: input.issueTracker,
892
+ colorHex: input.colorHex,
893
+ sessionId: input.sessionId,
894
+ projectPath: input.projectPath,
895
+ ...input.parentLoom && { parentLoom: input.parentLoom }
896
+ };
897
+ const filePath = this.getFilePath(worktreePath);
898
+ await fs.writeFile(filePath, JSON.stringify(content, null, 2), { mode: 420 });
899
+ getLogger().debug(`Metadata written for worktree: ${worktreePath}`);
900
+ } catch (error) {
901
+ getLogger().warn(
902
+ `Failed to write metadata for worktree: ${error instanceof Error ? error.message : String(error)}`
903
+ );
904
+ }
905
+ }
906
+ /**
907
+ * Read metadata for a worktree (spec section 3.2)
908
+ *
909
+ * @param worktreePath - Absolute path to the worktree
910
+ * @returns The metadata object with all fields, or null if not found/invalid
911
+ */
912
+ async readMetadata(worktreePath) {
913
+ try {
914
+ const filePath = this.getFilePath(worktreePath);
915
+ if (!await fs.pathExists(filePath)) {
916
+ return null;
917
+ }
918
+ const content = await fs.readFile(filePath, "utf8");
919
+ const data = JSON.parse(content);
920
+ if (!data.description) {
921
+ return null;
922
+ }
923
+ return {
924
+ description: data.description,
925
+ created_at: data.created_at ?? null,
926
+ branchName: data.branchName ?? null,
927
+ worktreePath: data.worktreePath ?? null,
928
+ issueType: data.issueType ?? null,
929
+ issue_numbers: data.issue_numbers ?? [],
930
+ pr_numbers: data.pr_numbers ?? [],
931
+ issueTracker: data.issueTracker ?? null,
932
+ colorHex: data.colorHex ?? null,
933
+ sessionId: data.sessionId ?? null,
934
+ projectPath: data.projectPath ?? null,
935
+ parentLoom: data.parentLoom ?? null
936
+ };
937
+ } catch (error) {
938
+ getLogger().debug(
939
+ `Could not read metadata for worktree ${worktreePath}: ${error instanceof Error ? error.message : String(error)}`
940
+ );
941
+ return null;
942
+ }
943
+ }
944
+ /**
945
+ * List all stored loom metadata files
946
+ *
947
+ * Returns an array of LoomMetadata objects for all valid metadata files
948
+ * in the looms directory. Invalid or unreadable files are skipped.
949
+ *
950
+ * @returns Array of LoomMetadata objects from all stored files
951
+ */
952
+ async listAllMetadata() {
953
+ const results = [];
954
+ try {
955
+ if (!await fs.pathExists(this.loomsDir)) {
956
+ return results;
957
+ }
958
+ const files = await fs.readdir(this.loomsDir);
959
+ for (const file of files) {
960
+ if (!file.endsWith(".json")) {
961
+ continue;
962
+ }
963
+ try {
964
+ const filePath = path2.join(this.loomsDir, file);
965
+ const content = await fs.readFile(filePath, "utf8");
966
+ const data = JSON.parse(content);
967
+ if (!data.description) {
968
+ continue;
969
+ }
970
+ results.push({
971
+ description: data.description,
972
+ created_at: data.created_at ?? null,
973
+ branchName: data.branchName ?? null,
974
+ worktreePath: data.worktreePath ?? null,
975
+ issueType: data.issueType ?? null,
976
+ issue_numbers: data.issue_numbers ?? [],
977
+ pr_numbers: data.pr_numbers ?? [],
978
+ issueTracker: data.issueTracker ?? null,
979
+ colorHex: data.colorHex ?? null,
980
+ sessionId: data.sessionId ?? null,
981
+ projectPath: data.projectPath ?? null,
982
+ parentLoom: data.parentLoom ?? null
983
+ });
984
+ } catch (error) {
985
+ getLogger().debug(
986
+ `Skipping metadata file ${file}: ${error instanceof Error ? error.message : String(error)}`
987
+ );
988
+ }
989
+ }
990
+ } catch (error) {
991
+ getLogger().debug(
992
+ `Could not list metadata files: ${error instanceof Error ? error.message : String(error)}`
993
+ );
994
+ }
995
+ return results;
996
+ }
997
+ /**
998
+ * Delete metadata for a worktree (spec section 3.3)
999
+ *
1000
+ * Idempotent: silently succeeds if file doesn't exist
1001
+ * Non-fatal: logs warning on permission errors but doesn't throw
1002
+ *
1003
+ * @param worktreePath - Absolute path to the worktree
1004
+ */
1005
+ async deleteMetadata(worktreePath) {
1006
+ try {
1007
+ const filePath = this.getFilePath(worktreePath);
1008
+ if (!await fs.pathExists(filePath)) {
1009
+ getLogger().debug(`No metadata file to delete for worktree: ${worktreePath}`);
1010
+ return;
1011
+ }
1012
+ await fs.unlink(filePath);
1013
+ getLogger().debug(`Metadata deleted for worktree: ${worktreePath}`);
1014
+ } catch (error) {
1015
+ getLogger().warn(
1016
+ `Failed to delete metadata for worktree: ${error instanceof Error ? error.message : String(error)}`
1017
+ );
1018
+ }
1019
+ }
1020
+ };
1021
+
734
1022
  // src/utils/git.ts
735
- init_SettingsManager();
736
1023
  init_logger();
737
- import path2 from "path";
738
- import { execa } from "execa";
739
1024
  async function executeGitCommand(args, options) {
740
1025
  try {
741
1026
  const result = await execa("git", args, {
@@ -743,7 +1028,9 @@ async function executeGitCommand(args, options) {
743
1028
  timeout: (options == null ? void 0 : options.timeout) ?? 3e4,
744
1029
  encoding: "utf8",
745
1030
  stdio: (options == null ? void 0 : options.stdio) ?? "pipe",
746
- verbose: logger.isDebugEnabled()
1031
+ verbose: logger.isDebugEnabled(),
1032
+ // Spread env conditionally - only include if defined
1033
+ ...(options == null ? void 0 : options.env) && { env: options.env }
747
1034
  });
748
1035
  return result.stdout;
749
1036
  } catch (error) {
@@ -879,7 +1166,7 @@ function extractIssueNumber(branchName) {
879
1166
  }
880
1167
  return null;
881
1168
  }
882
- function isWorktreePath(path6) {
1169
+ function isWorktreePath(path7) {
883
1170
  const worktreePatterns = [
884
1171
  /\/worktrees?\//i,
885
1172
  // Contains /worktree/ or /worktrees/
@@ -894,17 +1181,17 @@ function isWorktreePath(path6) {
894
1181
  /\.worktree$/i
895
1182
  // ends with .worktree
896
1183
  ];
897
- return worktreePatterns.some((pattern) => pattern.test(path6));
1184
+ return worktreePatterns.some((pattern) => pattern.test(path7));
898
1185
  }
899
1186
  function generateWorktreePath(branchName, rootDir = process.cwd(), options) {
900
1187
  let sanitized = branchName.replace(/\//g, "-");
901
1188
  if ((options == null ? void 0 : options.isPR) && (options == null ? void 0 : options.prNumber)) {
902
1189
  sanitized = `${sanitized}_pr_${options.prNumber}`;
903
1190
  }
904
- const parentDir = path2.dirname(rootDir);
1191
+ const parentDir = path3.dirname(rootDir);
905
1192
  let prefix;
906
1193
  if ((options == null ? void 0 : options.prefix) === void 0) {
907
- const mainFolderName = path2.basename(rootDir);
1194
+ const mainFolderName = path3.basename(rootDir);
908
1195
  prefix = mainFolderName ? `${mainFolderName}-looms/` : "looms/";
909
1196
  } else if (options.prefix === "") {
910
1197
  prefix = "";
@@ -924,43 +1211,43 @@ function generateWorktreePath(branchName, rootDir = process.cwd(), options) {
924
1211
  }
925
1212
  }
926
1213
  if (prefix === "") {
927
- return path2.join(parentDir, sanitized);
1214
+ return path3.join(parentDir, sanitized);
928
1215
  } else if (prefix.endsWith("/")) {
929
- return path2.join(parentDir, prefix, sanitized);
1216
+ return path3.join(parentDir, prefix, sanitized);
930
1217
  } else if (prefix.includes("/")) {
931
1218
  const lastSlashIndex = prefix.lastIndexOf("/");
932
1219
  const dirPath = prefix.substring(0, lastSlashIndex);
933
1220
  const prefixWithSeparator = prefix.substring(lastSlashIndex + 1);
934
- return path2.join(parentDir, dirPath, `${prefixWithSeparator}${sanitized}`);
1221
+ return path3.join(parentDir, dirPath, `${prefixWithSeparator}${sanitized}`);
935
1222
  } else {
936
- return path2.join(parentDir, `${prefix}${sanitized}`);
1223
+ return path3.join(parentDir, `${prefix}${sanitized}`);
937
1224
  }
938
1225
  }
939
- async function isValidGitRepo(path6) {
1226
+ async function isValidGitRepo(path7) {
940
1227
  try {
941
- await executeGitCommand(["rev-parse", "--git-dir"], { cwd: path6 });
1228
+ await executeGitCommand(["rev-parse", "--git-dir"], { cwd: path7 });
942
1229
  return true;
943
1230
  } catch {
944
1231
  return false;
945
1232
  }
946
1233
  }
947
- async function getCurrentBranch(path6 = process.cwd()) {
1234
+ async function getCurrentBranch(path7 = process.cwd()) {
948
1235
  try {
949
- const result = await executeGitCommand(["branch", "--show-current"], { cwd: path6 });
1236
+ const result = await executeGitCommand(["branch", "--show-current"], { cwd: path7 });
950
1237
  return result.trim();
951
1238
  } catch {
952
1239
  return null;
953
1240
  }
954
1241
  }
955
- async function branchExists(branchName, path6 = process.cwd(), includeRemote = true) {
1242
+ async function branchExists(branchName, path7 = process.cwd(), includeRemote = true) {
956
1243
  try {
957
- const localResult = await executeGitCommand(["branch", "--list", branchName], { cwd: path6 });
1244
+ const localResult = await executeGitCommand(["branch", "--list", branchName], { cwd: path7 });
958
1245
  if (localResult.trim()) {
959
1246
  return true;
960
1247
  }
961
1248
  if (includeRemote) {
962
1249
  const remoteResult = await executeGitCommand(["branch", "-r", "--list", `*/${branchName}`], {
963
- cwd: path6
1250
+ cwd: path7
964
1251
  });
965
1252
  if (remoteResult.trim()) {
966
1253
  return true;
@@ -971,31 +1258,31 @@ async function branchExists(branchName, path6 = process.cwd(), includeRemote = t
971
1258
  return false;
972
1259
  }
973
1260
  }
974
- async function getWorktreeRoot(path6 = process.cwd()) {
1261
+ async function getWorktreeRoot(path7 = process.cwd()) {
975
1262
  try {
976
- const result = await executeGitCommand(["rev-parse", "--show-toplevel"], { cwd: path6 });
1263
+ const result = await executeGitCommand(["rev-parse", "--show-toplevel"], { cwd: path7 });
977
1264
  return result.trim();
978
1265
  } catch {
979
1266
  return null;
980
1267
  }
981
1268
  }
982
- async function getRepoRoot(path6 = process.cwd()) {
1269
+ async function getRepoRoot(path7 = process.cwd()) {
983
1270
  try {
984
1271
  const gitCommonDir = await executeGitCommand(
985
1272
  ["rev-parse", "--path-format=absolute", "--git-common-dir"],
986
- { cwd: path6 }
1273
+ { cwd: path7 }
987
1274
  );
988
1275
  const trimmedPath = gitCommonDir.trim();
989
1276
  const repoRoot = trimmedPath.replace(/\/\.git\/worktrees\/[^/]+$/, "").replace(/\/\.git$/, "");
990
1277
  return repoRoot;
991
1278
  } catch (error) {
992
- logger.warn(`Failed to determine repo root from git-common-dir: ${path6}`, error instanceof Error ? error.message : String(error));
1279
+ logger.warn(`Failed to determine repo root from git-common-dir: ${path7}`, error instanceof Error ? error.message : String(error));
993
1280
  return null;
994
1281
  }
995
1282
  }
996
- async function findMainWorktreePath(path6 = process.cwd(), options) {
1283
+ async function findMainWorktreePath(path7 = process.cwd(), options) {
997
1284
  try {
998
- const output = await executeGitCommand(["worktree", "list", "--porcelain"], { cwd: path6 });
1285
+ const output = await executeGitCommand(["worktree", "list", "--porcelain"], { cwd: path7 });
999
1286
  const worktrees = parseWorktreeList(output, options == null ? void 0 : options.mainBranch);
1000
1287
  if (worktrees.length === 0) {
1001
1288
  throw new Error("No worktrees found in repository");
@@ -1025,30 +1312,51 @@ async function findMainWorktreePath(path6 = process.cwd(), options) {
1025
1312
  throw new Error(`Failed to find main worktree: ${error instanceof Error ? error.message : String(error)}`);
1026
1313
  }
1027
1314
  }
1028
- async function findMainWorktreePathWithSettings(path6, settingsManager) {
1315
+ async function findMainWorktreePathWithSettings(path7, settingsManager) {
1029
1316
  settingsManager ??= new SettingsManager();
1030
- const settings = await settingsManager.loadSettings(path6);
1317
+ const settings = await settingsManager.loadSettings(path7);
1031
1318
  const findOptions = settings.mainBranch ? { mainBranch: settings.mainBranch } : void 0;
1032
- return findMainWorktreePath(path6, findOptions);
1319
+ return findMainWorktreePath(path7, findOptions);
1033
1320
  }
1034
- async function hasUncommittedChanges(path6 = process.cwd()) {
1321
+ async function findWorktreeForBranch(branchName, path7 = process.cwd()) {
1035
1322
  try {
1036
- const result = await executeGitCommand(["status", "--porcelain"], { cwd: path6 });
1323
+ const output = await executeGitCommand(["worktree", "list", "--porcelain"], { cwd: path7 });
1324
+ const worktrees = parseWorktreeList(output, branchName);
1325
+ if (worktrees.length === 0) {
1326
+ throw new Error("No worktrees found in repository");
1327
+ }
1328
+ const targetWorktree = worktrees.find((wt) => wt.branch === branchName);
1329
+ if (!(targetWorktree == null ? void 0 : targetWorktree.path)) {
1330
+ throw new Error(
1331
+ `No worktree found with branch '${branchName}' checked out. Available worktrees: ${worktrees.map((wt) => `${wt.path} (${wt.branch})`).join(", ")}`
1332
+ );
1333
+ }
1334
+ return targetWorktree.path;
1335
+ } catch (error) {
1336
+ if (error instanceof Error && (error.message.includes("No worktree found with branch") || error.message.includes("No worktrees found"))) {
1337
+ throw error;
1338
+ }
1339
+ throw new Error(`Failed to find worktree for branch '${branchName}': ${error instanceof Error ? error.message : String(error)}`);
1340
+ }
1341
+ }
1342
+ async function hasUncommittedChanges(path7 = process.cwd()) {
1343
+ try {
1344
+ const result = await executeGitCommand(["status", "--porcelain"], { cwd: path7 });
1037
1345
  return result.trim().length > 0;
1038
1346
  } catch {
1039
1347
  return false;
1040
1348
  }
1041
1349
  }
1042
- async function getDefaultBranch(path6 = process.cwd()) {
1350
+ async function getDefaultBranch(path7 = process.cwd()) {
1043
1351
  try {
1044
1352
  const remoteResult = await executeGitCommand(["symbolic-ref", "refs/remotes/origin/HEAD"], {
1045
- cwd: path6
1353
+ cwd: path7
1046
1354
  });
1047
1355
  const match = remoteResult.match(/refs\/remotes\/origin\/(.+)/);
1048
1356
  if (match) return match[1] ?? "main";
1049
1357
  const commonDefaults = ["main", "master", "develop"];
1050
1358
  for (const branch of commonDefaults) {
1051
- if (await branchExists(branch, path6)) {
1359
+ if (await branchExists(branch, path7)) {
1052
1360
  return branch;
1053
1361
  }
1054
1362
  }
@@ -1057,13 +1365,13 @@ async function getDefaultBranch(path6 = process.cwd()) {
1057
1365
  return "main";
1058
1366
  }
1059
1367
  }
1060
- async function findAllBranchesForIssue(issueNumber, path6 = process.cwd(), settingsManager) {
1368
+ async function findAllBranchesForIssue(issueNumber, path7 = process.cwd(), settingsManager) {
1061
1369
  if (!settingsManager) {
1062
1370
  const { SettingsManager: SM } = await Promise.resolve().then(() => (init_SettingsManager(), SettingsManager_exports));
1063
1371
  settingsManager = new SM();
1064
1372
  }
1065
- const protectedBranches = await settingsManager.getProtectedBranches(path6);
1066
- const output = await executeGitCommand(["branch", "-a"], { cwd: path6 });
1373
+ const protectedBranches = await settingsManager.getProtectedBranches(path7);
1374
+ const output = await executeGitCommand(["branch", "-a"], { cwd: path7 });
1067
1375
  const branches = [];
1068
1376
  const lines = output.split("\n").filter(Boolean);
1069
1377
  for (const line of lines) {
@@ -1120,18 +1428,18 @@ async function findAllBranchesForIssue(issueNumber, path6 = process.cwd(), setti
1120
1428
  }
1121
1429
  return branches;
1122
1430
  }
1123
- async function isEmptyRepository(path6 = process.cwd()) {
1431
+ async function isEmptyRepository(path7 = process.cwd()) {
1124
1432
  try {
1125
- await executeGitCommand(["rev-parse", "--verify", "HEAD"], { cwd: path6 });
1433
+ await executeGitCommand(["rev-parse", "--verify", "HEAD"], { cwd: path7 });
1126
1434
  return false;
1127
1435
  } catch {
1128
1436
  return true;
1129
1437
  }
1130
1438
  }
1131
- async function ensureRepositoryHasCommits(path6 = process.cwd()) {
1132
- const isEmpty = await isEmptyRepository(path6);
1439
+ async function ensureRepositoryHasCommits(path7 = process.cwd()) {
1440
+ const isEmpty = await isEmptyRepository(path7);
1133
1441
  if (isEmpty) {
1134
- await executeGitCommand(["commit", "--no-verify", "--allow-empty", "-m", "Initial commit"], { cwd: path6 });
1442
+ await executeGitCommand(["commit", "--no-verify", "--allow-empty", "-m", "Initial commit"], { cwd: path7 });
1135
1443
  }
1136
1444
  }
1137
1445
  async function pushBranchToRemote(branchName, worktreePath, options) {
@@ -1199,6 +1507,122 @@ async function isFileGitignored(filePath, cwd = process.cwd()) {
1199
1507
  return false;
1200
1508
  }
1201
1509
  }
1510
+ async function isBranchMergedIntoMain(branchName, mainBranch = "main", cwd = process.cwd()) {
1511
+ try {
1512
+ await executeGitCommand(["merge-base", "--is-ancestor", branchName, mainBranch], { cwd });
1513
+ return true;
1514
+ } catch {
1515
+ return false;
1516
+ }
1517
+ }
1518
+ async function isRemoteBranchUpToDate(branchName, cwd) {
1519
+ try {
1520
+ const remoteResult = await executeGitCommand(["ls-remote", "--heads", "origin", branchName], { cwd });
1521
+ if (remoteResult.trim().length === 0) {
1522
+ return false;
1523
+ }
1524
+ const remoteCommit = remoteResult.trim().split(" ")[0];
1525
+ const localCommit = await executeGitCommand(["rev-parse", branchName], { cwd });
1526
+ return localCommit.trim() === remoteCommit;
1527
+ } catch {
1528
+ return false;
1529
+ }
1530
+ }
1531
+ async function checkRemoteBranchStatus(branchName, cwd) {
1532
+ try {
1533
+ try {
1534
+ await executeGitCommand(["fetch", "origin", branchName], { cwd, timeout: 3e4 });
1535
+ } catch (fetchError) {
1536
+ const fetchErrorMessage = fetchError instanceof Error ? fetchError.message : String(fetchError);
1537
+ if (fetchErrorMessage.includes("Could not resolve host") || fetchErrorMessage.includes("unable to access") || fetchErrorMessage.includes("network") || fetchErrorMessage.includes("Connection refused") || fetchErrorMessage.includes("Connection timed out")) {
1538
+ return {
1539
+ exists: false,
1540
+ remoteAhead: false,
1541
+ localAhead: false,
1542
+ networkError: true,
1543
+ errorMessage: fetchErrorMessage
1544
+ };
1545
+ }
1546
+ }
1547
+ const remoteResult = await executeGitCommand(["ls-remote", "--heads", "origin", branchName], { cwd });
1548
+ if (remoteResult.trim().length === 0) {
1549
+ return {
1550
+ exists: false,
1551
+ remoteAhead: false,
1552
+ localAhead: false,
1553
+ networkError: false
1554
+ };
1555
+ }
1556
+ const remoteCommit = remoteResult.trim().split(" ")[0];
1557
+ if (!remoteCommit) {
1558
+ return {
1559
+ exists: false,
1560
+ remoteAhead: false,
1561
+ localAhead: false,
1562
+ networkError: false
1563
+ };
1564
+ }
1565
+ const localCommit = await executeGitCommand(["rev-parse", branchName], { cwd });
1566
+ const localCommitTrimmed = localCommit.trim();
1567
+ if (remoteCommit === localCommitTrimmed) {
1568
+ return {
1569
+ exists: true,
1570
+ remoteAhead: false,
1571
+ localAhead: false,
1572
+ networkError: false
1573
+ };
1574
+ }
1575
+ try {
1576
+ await executeGitCommand(["merge-base", "--is-ancestor", localCommitTrimmed, remoteCommit], { cwd });
1577
+ return {
1578
+ exists: true,
1579
+ remoteAhead: true,
1580
+ localAhead: false,
1581
+ networkError: false
1582
+ };
1583
+ } catch {
1584
+ return {
1585
+ exists: true,
1586
+ remoteAhead: false,
1587
+ localAhead: true,
1588
+ networkError: false
1589
+ };
1590
+ }
1591
+ } catch (error) {
1592
+ const errorMessage = error instanceof Error ? error.message : String(error);
1593
+ if (errorMessage.includes("Could not resolve host") || errorMessage.includes("unable to access") || errorMessage.includes("network") || errorMessage.includes("Connection refused") || errorMessage.includes("Connection timed out")) {
1594
+ return {
1595
+ exists: false,
1596
+ remoteAhead: false,
1597
+ localAhead: false,
1598
+ networkError: true,
1599
+ errorMessage
1600
+ };
1601
+ }
1602
+ return {
1603
+ exists: false,
1604
+ remoteAhead: false,
1605
+ localAhead: false,
1606
+ networkError: false
1607
+ };
1608
+ }
1609
+ }
1610
+ async function getMergeTargetBranch(worktreePath = process.cwd(), options) {
1611
+ var _a;
1612
+ const settingsManager = (options == null ? void 0 : options.settingsManager) ?? new SettingsManager();
1613
+ const metadataManager = (options == null ? void 0 : options.metadataManager) ?? new MetadataManager();
1614
+ logger.debug(`Checking for parent loom metadata at: ${worktreePath}`);
1615
+ const metadata = await metadataManager.readMetadata(worktreePath);
1616
+ if ((_a = metadata == null ? void 0 : metadata.parentLoom) == null ? void 0 : _a.branchName) {
1617
+ logger.debug(`Using parent branch as merge target: ${metadata.parentLoom.branchName}`);
1618
+ return metadata.parentLoom.branchName;
1619
+ }
1620
+ logger.debug("No parent loom metadata found, falling back to settings");
1621
+ const settings = await settingsManager.loadSettings(worktreePath);
1622
+ const mainBranch = settings.mainBranch ?? "main";
1623
+ logger.debug(`Using configured main branch as merge target: ${mainBranch}`);
1624
+ return mainBranch;
1625
+ }
1202
1626
 
1203
1627
  // src/lib/GitWorktreeManager.ts
1204
1628
  var GitWorktreeManager = class {
@@ -1266,12 +1690,12 @@ var GitWorktreeManager = class {
1266
1690
  if (!options.branch) {
1267
1691
  throw new Error("Branch name is required");
1268
1692
  }
1269
- const absolutePath = path3.resolve(options.path);
1270
- if (await fs.pathExists(absolutePath)) {
1693
+ const absolutePath = path4.resolve(options.path);
1694
+ if (await fs2.pathExists(absolutePath)) {
1271
1695
  if (!options.force) {
1272
1696
  throw new Error(`Path already exists: ${absolutePath}`);
1273
1697
  }
1274
- await fs.remove(absolutePath);
1698
+ await fs2.remove(absolutePath);
1275
1699
  }
1276
1700
  const args = ["worktree", "add"];
1277
1701
  if (options.createBranch) {
@@ -1298,11 +1722,10 @@ var GitWorktreeManager = class {
1298
1722
  const worktrees = await this.listWorktrees({ porcelain: true });
1299
1723
  const worktree = worktrees.find((wt) => wt.path === worktreePath);
1300
1724
  if (!worktree) {
1301
- const { logger: logger4 } = await Promise.resolve().then(() => (init_logger(), logger_exports));
1302
- logger4.debug(`Looking for worktree path: ${worktreePath}`);
1303
- logger4.debug(`Found ${worktrees.length} worktrees:`);
1725
+ getLogger().debug(`Looking for worktree path: ${worktreePath}`);
1726
+ getLogger().debug(`Found ${worktrees.length} worktrees:`);
1304
1727
  worktrees.forEach((wt, i) => {
1305
- logger4.debug(` ${i}: path="${wt.path}", branch="${wt.branch}"`);
1728
+ getLogger().debug(` ${i}: path="${wt.path}", branch="${wt.branch}"`);
1306
1729
  });
1307
1730
  throw new Error(`Worktree not found: ${worktreePath}`);
1308
1731
  }
@@ -1322,8 +1745,8 @@ var GitWorktreeManager = class {
1322
1745
  if (options.force) args.push("--force");
1323
1746
  args.push(worktreePath);
1324
1747
  await executeGitCommand(args, { cwd: this._workingDirectory });
1325
- if (options.removeDirectory && await fs.pathExists(worktreePath)) {
1326
- await fs.remove(worktreePath);
1748
+ if (options.removeDirectory && await fs2.pathExists(worktreePath)) {
1749
+ await fs2.remove(worktreePath);
1327
1750
  }
1328
1751
  if (options.removeBranch && !worktree.bare) {
1329
1752
  try {
@@ -1346,7 +1769,7 @@ var GitWorktreeManager = class {
1346
1769
  let isValidRepo = false;
1347
1770
  let hasValidBranch = false;
1348
1771
  try {
1349
- existsOnDisk = await fs.pathExists(worktreePath);
1772
+ existsOnDisk = await fs2.pathExists(worktreePath);
1350
1773
  if (!existsOnDisk) {
1351
1774
  issues.push("Worktree directory does not exist on disk");
1352
1775
  }
@@ -1764,42 +2187,35 @@ async function createIssue(title, body, options) {
1764
2187
  };
1765
2188
  }
1766
2189
 
1767
- // src/lib/GitHubService.ts
1768
- init_logger();
1769
-
1770
2190
  // src/utils/prompt.ts
1771
2191
  init_logger();
1772
2192
  import * as readline from "readline";
1773
2193
  async function promptConfirmation(message, defaultValue = false) {
1774
- const rl = readline.createInterface({
1775
- input: process.stdin,
1776
- output: process.stdout
1777
- });
1778
2194
  const suffix = defaultValue ? "[Y/n]" : "[y/N]";
1779
2195
  const fullMessage = `${message} ${suffix}: `;
1780
- return new Promise((resolve) => {
1781
- rl.question(fullMessage, (answer) => {
1782
- rl.close();
1783
- const normalized = answer.trim().toLowerCase();
1784
- if (normalized === "") {
1785
- resolve(defaultValue);
1786
- return;
1787
- }
1788
- if (normalized === "y" || normalized === "yes") {
1789
- resolve(true);
1790
- return;
1791
- }
1792
- if (normalized === "n" || normalized === "no") {
1793
- resolve(false);
1794
- return;
1795
- }
1796
- logger.warn("Invalid input, using default value", {
1797
- input: answer,
1798
- defaultValue
2196
+ while (true) {
2197
+ const rl = readline.createInterface({
2198
+ input: process.stdin,
2199
+ output: process.stdout
2200
+ });
2201
+ const answer = await new Promise((resolve) => {
2202
+ rl.question(fullMessage, (ans) => {
2203
+ rl.close();
2204
+ resolve(ans);
1799
2205
  });
1800
- resolve(defaultValue);
1801
2206
  });
1802
- });
2207
+ const normalized = answer.trim().toLowerCase();
2208
+ if (normalized === "") {
2209
+ return defaultValue;
2210
+ }
2211
+ if (normalized === "y" || normalized === "yes") {
2212
+ return true;
2213
+ }
2214
+ if (normalized === "n" || normalized === "no") {
2215
+ return false;
2216
+ }
2217
+ logger.warn("Invalid input. Please enter y/yes or n/no.");
2218
+ }
1803
2219
  }
1804
2220
 
1805
2221
  // src/lib/GitHubService.ts
@@ -1829,12 +2245,12 @@ var GitHubService = class {
1829
2245
  return { type: "unknown", identifier: null, rawInput: input };
1830
2246
  }
1831
2247
  const number = parseInt(numberMatch[1], 10);
1832
- logger.debug("Checking if input is a PR", { number });
2248
+ getLogger().debug("Checking if input is a PR", { number });
1833
2249
  const pr = await this.isValidPR(number, repo);
1834
2250
  if (pr) {
1835
2251
  return { type: "pr", identifier: number.toString(), rawInput: input };
1836
2252
  }
1837
- logger.debug("Checking if input is an issue", { number });
2253
+ getLogger().debug("Checking if input is an issue", { number });
1838
2254
  const issue = await this.isValidIssue(number, repo);
1839
2255
  if (issue) {
1840
2256
  return { type: "issue", identifier: number.toString(), rawInput: input };
@@ -1938,17 +2354,17 @@ var GitHubService = class {
1938
2354
  return createIssue(title, body, { repo: repository, labels });
1939
2355
  }
1940
2356
  async getIssueUrl(issueNumber, repo) {
1941
- logger.debug("Fetching issue URL", { issueNumber, repo });
2357
+ getLogger().debug("Fetching issue URL", { issueNumber, repo });
1942
2358
  const issue = await fetchGhIssue(issueNumber, repo);
1943
2359
  return issue.url;
1944
2360
  }
1945
2361
  // GitHub Projects integration
1946
2362
  async moveIssueToInProgress(issueNumber) {
1947
- logger.info("Moving issue to In Progress in GitHub Projects", {
2363
+ getLogger().info("Moving issue to In Progress in GitHub Projects", {
1948
2364
  issueNumber
1949
2365
  });
1950
2366
  if (!await hasProjectScope()) {
1951
- logger.warn("Missing project scope in GitHub CLI auth");
2367
+ getLogger().warn("Missing project scope in GitHub CLI auth");
1952
2368
  throw new GitHubError(
1953
2369
  "MISSING_SCOPE" /* MISSING_SCOPE */,
1954
2370
  "GitHub CLI lacks project scope. Run: gh auth refresh -s project"
@@ -1959,18 +2375,18 @@ var GitHubService = class {
1959
2375
  const repoInfo = await executeGhCommand(["repo", "view", "--json", "owner,name"]);
1960
2376
  owner = repoInfo.owner.login;
1961
2377
  } catch (error) {
1962
- logger.warn("Could not determine repository info", { error });
2378
+ getLogger().warn("Could not determine repository info", { error });
1963
2379
  return;
1964
2380
  }
1965
2381
  let projects;
1966
2382
  try {
1967
2383
  projects = await fetchProjectList(owner);
1968
2384
  } catch (error) {
1969
- logger.warn("Could not fetch projects", { owner, error });
2385
+ getLogger().warn("Could not fetch projects", { owner, error });
1970
2386
  return;
1971
2387
  }
1972
2388
  if (!projects.length) {
1973
- logger.warn("No projects found", { owner });
2389
+ getLogger().warn("No projects found", { owner });
1974
2390
  return;
1975
2391
  }
1976
2392
  for (const project of projects) {
@@ -1983,14 +2399,14 @@ var GitHubService = class {
1983
2399
  try {
1984
2400
  items = await fetchProjectItems(project.number, owner);
1985
2401
  } catch (error) {
1986
- logger.debug("Could not fetch project items", { project: project.number, error });
2402
+ getLogger().debug("Could not fetch project items", { project: project.number, error });
1987
2403
  return;
1988
2404
  }
1989
2405
  const item = items.find(
1990
2406
  (i) => i.content.type === "Issue" && i.content.number === issueNumber
1991
2407
  );
1992
2408
  if (!item) {
1993
- logger.debug("Issue not found in project", {
2409
+ getLogger().debug("Issue not found in project", {
1994
2410
  issueNumber,
1995
2411
  projectNumber: project.number
1996
2412
  });
@@ -2000,19 +2416,19 @@ var GitHubService = class {
2000
2416
  try {
2001
2417
  fieldsData = await fetchProjectFields(project.number, owner);
2002
2418
  } catch (error) {
2003
- logger.debug("Could not fetch project fields", { project: project.number, error });
2419
+ getLogger().debug("Could not fetch project fields", { project: project.number, error });
2004
2420
  return;
2005
2421
  }
2006
2422
  const statusField = fieldsData.fields.find((f) => f.name === "Status");
2007
2423
  if (!statusField) {
2008
- logger.debug("No Status field found in project", { projectNumber: project.number });
2424
+ getLogger().debug("No Status field found in project", { projectNumber: project.number });
2009
2425
  return;
2010
2426
  }
2011
2427
  const inProgressOption = (_a = statusField.options) == null ? void 0 : _a.find(
2012
2428
  (o) => o.name === "In Progress" || o.name === "In progress"
2013
2429
  );
2014
2430
  if (!inProgressOption) {
2015
- logger.debug("No In Progress option found in Status field", { projectNumber: project.number });
2431
+ getLogger().debug("No In Progress option found in Status field", { projectNumber: project.number });
2016
2432
  return;
2017
2433
  }
2018
2434
  try {
@@ -2022,12 +2438,12 @@ var GitHubService = class {
2022
2438
  statusField.id,
2023
2439
  inProgressOption.id
2024
2440
  );
2025
- logger.info("Updated issue status in project", {
2441
+ getLogger().info("Updated issue status in project", {
2026
2442
  issueNumber,
2027
2443
  projectNumber: project.number
2028
2444
  });
2029
2445
  } catch (error) {
2030
- logger.debug("Could not update project item", { item: item.id, error });
2446
+ getLogger().debug("Could not update project item", { item: item.id, error });
2031
2447
  }
2032
2448
  }
2033
2449
  // Utility methods
@@ -2388,7 +2804,6 @@ ${issue.body}`;
2388
2804
  };
2389
2805
 
2390
2806
  // src/lib/IssueTrackerFactory.ts
2391
- init_logger();
2392
2807
  var IssueTrackerFactory = class {
2393
2808
  /**
2394
2809
  * Create an IssueTracker instance based on settings configuration
@@ -2401,11 +2816,11 @@ var IssueTrackerFactory = class {
2401
2816
  static create(settings) {
2402
2817
  var _a, _b;
2403
2818
  const provider = ((_a = settings.issueManagement) == null ? void 0 : _a.provider) ?? "github";
2404
- logger.debug(`IssueTrackerFactory: Creating tracker for provider "${provider}"`);
2405
- logger.debug(`IssueTrackerFactory: issueManagement settings:`, JSON.stringify(settings.issueManagement, null, 2));
2819
+ getLogger().debug(`IssueTrackerFactory: Creating tracker for provider "${provider}"`);
2820
+ getLogger().debug(`IssueTrackerFactory: issueManagement settings:`, JSON.stringify(settings.issueManagement, null, 2));
2406
2821
  switch (provider) {
2407
2822
  case "github":
2408
- logger.debug("IssueTrackerFactory: Creating GitHubService");
2823
+ getLogger().debug("IssueTrackerFactory: Creating GitHubService");
2409
2824
  return new GitHubService();
2410
2825
  case "linear": {
2411
2826
  const linearSettings = (_b = settings.issueManagement) == null ? void 0 : _b.linear;
@@ -2416,7 +2831,7 @@ var IssueTrackerFactory = class {
2416
2831
  if (linearSettings == null ? void 0 : linearSettings.branchFormat) {
2417
2832
  linearConfig.branchFormat = linearSettings.branchFormat;
2418
2833
  }
2419
- logger.debug(`IssueTrackerFactory: Creating LinearService with config:`, JSON.stringify(linearConfig, null, 2));
2834
+ getLogger().debug(`IssueTrackerFactory: Creating LinearService with config:`, JSON.stringify(linearConfig, null, 2));
2420
2835
  return new LinearService(linearConfig);
2421
2836
  }
2422
2837
  default:
@@ -2437,12 +2852,11 @@ var IssueTrackerFactory = class {
2437
2852
  };
2438
2853
 
2439
2854
  // src/lib/EnvironmentManager.ts
2440
- init_logger();
2441
- import fs2 from "fs-extra";
2855
+ import fs3 from "fs-extra";
2442
2856
 
2443
2857
  // src/utils/env.ts
2444
2858
  init_logger();
2445
- import path4 from "path";
2859
+ import path5 from "path";
2446
2860
  import dotenvFlow from "dotenv-flow";
2447
2861
  function parseEnvFile(content) {
2448
2862
  const envMap = /* @__PURE__ */ new Map();
@@ -2509,7 +2923,7 @@ async function buildEnvSourceCommands(workspacePath, fileExists) {
2509
2923
  const files = getDotenvFlowFiles();
2510
2924
  const commands = [];
2511
2925
  for (const file of files) {
2512
- const fullPath = path4.join(workspacePath, file);
2926
+ const fullPath = path5.join(workspacePath, file);
2513
2927
  const exists = await fileExists(fullPath);
2514
2928
  if (exists) {
2515
2929
  commands.push(`source ${file}`);
@@ -2520,7 +2934,7 @@ async function buildEnvSourceCommands(workspacePath, fileExists) {
2520
2934
  async function findEnvFileContainingVariable(workspacePath, variableName, fileExists, getEnvVariable) {
2521
2935
  const files = getDotenvFlowFiles().reverse();
2522
2936
  for (const file of files) {
2523
- const fullPath = path4.join(workspacePath, file);
2937
+ const fullPath = path5.join(workspacePath, file);
2524
2938
  if (!await fileExists(fullPath)) {
2525
2939
  continue;
2526
2940
  }
@@ -2560,7 +2974,6 @@ function calculatePortForBranch(branchName, basePort = 3e3) {
2560
2974
  }
2561
2975
 
2562
2976
  // src/lib/EnvironmentManager.ts
2563
- var logger2 = createLogger({ prefix: "\u{1F4DD}" });
2564
2977
  var EnvironmentManager = class {
2565
2978
  constructor() {
2566
2979
  this.backupSuffix = ".backup";
@@ -2575,15 +2988,15 @@ var EnvironmentManager = class {
2575
2988
  if (!validation.valid) {
2576
2989
  throw new Error(validation.error ?? "Invalid variable name");
2577
2990
  }
2578
- const fileExists = await fs2.pathExists(filePath);
2991
+ const fileExists = await fs3.pathExists(filePath);
2579
2992
  if (!fileExists) {
2580
- logger2.info(`Creating ${filePath} with ${key}...`);
2993
+ getLogger().info(`Creating ${filePath} with ${key}...`);
2581
2994
  const content = formatEnvLine(key, value);
2582
- await fs2.writeFile(filePath, content, "utf8");
2583
- logger2.success(`${filePath} created with ${key}`);
2995
+ await fs3.writeFile(filePath, content, "utf8");
2996
+ getLogger().success(`${filePath} created with ${key}`);
2584
2997
  return;
2585
2998
  }
2586
- const existingContent = await fs2.readFile(filePath, "utf8");
2999
+ const existingContent = await fs3.readFile(filePath, "utf8");
2587
3000
  const envMap = parseEnvFile(existingContent);
2588
3001
  let backupPath;
2589
3002
  if (backup) {
@@ -2612,15 +3025,15 @@ var EnvironmentManager = class {
2612
3025
  newLines.push(line);
2613
3026
  }
2614
3027
  if (!variableUpdated) {
2615
- logger2.info(`Adding ${key} to ${filePath}...`);
3028
+ getLogger().info(`Adding ${key} to ${filePath}...`);
2616
3029
  newLines.push(formatEnvLine(key, value));
2617
- logger2.success(`${key} added successfully`);
3030
+ getLogger().success(`${key} added successfully`);
2618
3031
  } else {
2619
- logger2.info(`Updating ${key} in ${filePath}...`);
2620
- logger2.success(`${key} updated successfully`);
3032
+ getLogger().info(`Updating ${key} in ${filePath}...`);
3033
+ getLogger().success(`${key} updated successfully`);
2621
3034
  }
2622
3035
  const newContent = newLines.join("\n");
2623
- await fs2.writeFile(filePath, newContent, "utf8");
3036
+ await fs3.writeFile(filePath, newContent, "utf8");
2624
3037
  return backupPath;
2625
3038
  }
2626
3039
  /**
@@ -2628,10 +3041,10 @@ var EnvironmentManager = class {
2628
3041
  */
2629
3042
  async readEnvFile(filePath) {
2630
3043
  try {
2631
- const content = await fs2.readFile(filePath, "utf8");
3044
+ const content = await fs3.readFile(filePath, "utf8");
2632
3045
  return parseEnvFile(content);
2633
3046
  } catch (error) {
2634
- logger2.debug(
3047
+ getLogger().debug(
2635
3048
  `Could not read env file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
2636
3049
  );
2637
3050
  return /* @__PURE__ */ new Map();
@@ -2651,13 +3064,13 @@ var EnvironmentManager = class {
2651
3064
  * @private
2652
3065
  */
2653
3066
  async copyIfExists(source, destination) {
2654
- const sourceExists = await fs2.pathExists(source);
3067
+ const sourceExists = await fs3.pathExists(source);
2655
3068
  if (!sourceExists) {
2656
- logger2.debug(`Source file ${source} does not exist, skipping copy`);
3069
+ getLogger().debug(`Source file ${source} does not exist, skipping copy`);
2657
3070
  return;
2658
3071
  }
2659
- await fs2.copy(source, destination, { overwrite: false });
2660
- logger2.success(`Copied ${source} to ${destination}`);
3072
+ await fs3.copy(source, destination, { overwrite: false });
3073
+ getLogger().success(`Copied ${source} to ${destination}`);
2661
3074
  }
2662
3075
  /**
2663
3076
  * Calculate unique port for workspace
@@ -2717,7 +3130,7 @@ var EnvironmentManager = class {
2717
3130
  */
2718
3131
  async validateEnvFile(filePath) {
2719
3132
  try {
2720
- const content = await fs2.readFile(filePath, "utf8");
3133
+ const content = await fs3.readFile(filePath, "utf8");
2721
3134
  const envMap = parseEnvFile(content);
2722
3135
  const errors = [];
2723
3136
  for (const [key, value] of envMap.entries()) {
@@ -2745,25 +3158,23 @@ var EnvironmentManager = class {
2745
3158
  async createBackup(filePath) {
2746
3159
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2747
3160
  const backupPath = `${filePath}${this.backupSuffix}-${timestamp}`;
2748
- await fs2.copy(filePath, backupPath);
2749
- logger2.debug(`Created backup at ${backupPath}`);
3161
+ await fs3.copy(filePath, backupPath);
3162
+ getLogger().debug(`Created backup at ${backupPath}`);
2750
3163
  return backupPath;
2751
3164
  }
2752
3165
  };
2753
3166
 
2754
3167
  // src/lib/DatabaseManager.ts
2755
- init_logger();
2756
- import fs3 from "fs-extra";
2757
- var logger3 = createLogger({ prefix: "\u{1F5C2}\uFE0F" });
3168
+ import fs4 from "fs-extra";
2758
3169
  var DatabaseManager = class {
2759
3170
  constructor(provider, environment, databaseUrlEnvVarName = "DATABASE_URL") {
2760
3171
  this.provider = provider;
2761
3172
  this.environment = environment;
2762
3173
  this.databaseUrlEnvVarName = databaseUrlEnvVarName;
2763
3174
  if (databaseUrlEnvVarName !== "DATABASE_URL") {
2764
- logger3.debug(`\u{1F527} DatabaseManager configured with custom variable: ${databaseUrlEnvVarName}`);
3175
+ getLogger().debug(`DatabaseManager configured with custom variable: ${databaseUrlEnvVarName}`);
2765
3176
  } else {
2766
- logger3.debug("\u{1F527} DatabaseManager using default variable: DATABASE_URL");
3177
+ getLogger().debug("DatabaseManager using default variable: DATABASE_URL");
2767
3178
  }
2768
3179
  }
2769
3180
  /**
@@ -2780,12 +3191,12 @@ var DatabaseManager = class {
2780
3191
  */
2781
3192
  async shouldUseDatabaseBranching(workspacePath) {
2782
3193
  if (!this.provider.isConfigured()) {
2783
- logger3.debug("Skipping database branching: Database provider not configured");
3194
+ getLogger().debug("Skipping database branching: Database provider not configured");
2784
3195
  return false;
2785
3196
  }
2786
3197
  const hasDatabaseUrl = await this.hasDatabaseUrlInEnv(workspacePath);
2787
3198
  if (!hasDatabaseUrl) {
2788
- logger3.debug(
3199
+ getLogger().debug(
2789
3200
  "Skipping database branching: configured database URL variable not found in any env file"
2790
3201
  );
2791
3202
  return false;
@@ -2806,28 +3217,28 @@ var DatabaseManager = class {
2806
3217
  return null;
2807
3218
  }
2808
3219
  if (!await this.provider.isCliAvailable()) {
2809
- logger3.warn("Skipping database branch creation: Neon CLI not available");
2810
- logger3.warn("Install with: npm install -g neonctl");
3220
+ getLogger().warn("Skipping database branch creation: Neon CLI not available");
3221
+ getLogger().warn("Install with: npm install -g neonctl");
2811
3222
  return null;
2812
3223
  }
2813
3224
  try {
2814
3225
  const isAuth = await this.provider.isAuthenticated(cwd);
2815
3226
  if (!isAuth) {
2816
- logger3.warn("Skipping database branch creation: Not authenticated with Neon CLI");
2817
- logger3.warn("Run: neon auth");
3227
+ getLogger().warn("Skipping database branch creation: Not authenticated with Neon CLI");
3228
+ getLogger().warn("Run: neon auth");
2818
3229
  return null;
2819
3230
  }
2820
3231
  } catch (error) {
2821
3232
  const errorMessage = error instanceof Error ? error.message : String(error);
2822
- logger3.error(`Database authentication check failed: ${errorMessage}`);
3233
+ getLogger().error(`Database authentication check failed: ${errorMessage}`);
2823
3234
  throw error;
2824
3235
  }
2825
3236
  try {
2826
3237
  const connectionString = await this.provider.createBranch(branchName, fromBranch, cwd);
2827
- logger3.success(`Database branch ready: ${this.provider.sanitizeBranchName(branchName)}`);
3238
+ getLogger().success(`Database branch ready: ${this.provider.sanitizeBranchName(branchName)}`);
2828
3239
  return connectionString;
2829
3240
  } catch (error) {
2830
- logger3.error(
3241
+ getLogger().error(
2831
3242
  `Failed to create database branch: ${error instanceof Error ? error.message : String(error)}`
2832
3243
  );
2833
3244
  throw error;
@@ -2853,7 +3264,7 @@ var DatabaseManager = class {
2853
3264
  };
2854
3265
  }
2855
3266
  if (!this.provider.isConfigured()) {
2856
- logger3.debug("Skipping database branch deletion: Database provider not configured");
3267
+ getLogger().debug("Skipping database branch deletion: Database provider not configured");
2857
3268
  return {
2858
3269
  success: true,
2859
3270
  deleted: false,
@@ -2862,7 +3273,7 @@ var DatabaseManager = class {
2862
3273
  };
2863
3274
  }
2864
3275
  if (!await this.provider.isCliAvailable()) {
2865
- logger3.info("Skipping database branch deletion: CLI tool not available");
3276
+ getLogger().info("Skipping database branch deletion: CLI tool not available");
2866
3277
  return {
2867
3278
  success: false,
2868
3279
  deleted: false,
@@ -2874,7 +3285,7 @@ var DatabaseManager = class {
2874
3285
  try {
2875
3286
  const isAuth = await this.provider.isAuthenticated(cwd);
2876
3287
  if (!isAuth) {
2877
- logger3.warn("Skipping database branch deletion: Not authenticated with DB Provider");
3288
+ getLogger().warn("Skipping database branch deletion: Not authenticated with DB Provider");
2878
3289
  return {
2879
3290
  success: false,
2880
3291
  deleted: false,
@@ -2885,7 +3296,7 @@ var DatabaseManager = class {
2885
3296
  }
2886
3297
  } catch (error) {
2887
3298
  const errorMessage = error instanceof Error ? error.message : String(error);
2888
- logger3.error(`Database authentication check failed: ${errorMessage}`);
3299
+ getLogger().error(`Database authentication check failed: ${errorMessage}`);
2889
3300
  return {
2890
3301
  success: false,
2891
3302
  deleted: false,
@@ -2898,7 +3309,7 @@ var DatabaseManager = class {
2898
3309
  const result = await this.provider.deleteBranch(branchName, isPreview, cwd);
2899
3310
  return result;
2900
3311
  } catch (error) {
2901
- logger3.warn(
3312
+ getLogger().warn(
2902
3313
  `Unexpected error in database deletion: ${error instanceof Error ? error.message : String(error)}`
2903
3314
  );
2904
3315
  return {
@@ -2919,13 +3330,13 @@ var DatabaseManager = class {
2919
3330
  */
2920
3331
  async getBranchNameFromConnectionString(connectionString, cwd) {
2921
3332
  if (!this.provider.isConfigured()) {
2922
- logger3.debug("Provider not configured, skipping reverse lookup");
3333
+ getLogger().debug("Provider not configured, skipping reverse lookup");
2923
3334
  return null;
2924
3335
  }
2925
3336
  if ("getBranchNameFromConnectionString" in this.provider && typeof this.provider.getBranchNameFromConnectionString === "function") {
2926
3337
  return this.provider.getBranchNameFromConnectionString(connectionString, cwd);
2927
3338
  }
2928
- logger3.debug("Provider does not support reverse lookup");
3339
+ getLogger().debug("Provider does not support reverse lookup");
2929
3340
  return null;
2930
3341
  }
2931
3342
  /**
@@ -2936,26 +3347,26 @@ var DatabaseManager = class {
2936
3347
  async hasDatabaseUrlInEnv(workspacePath) {
2937
3348
  try {
2938
3349
  if (this.databaseUrlEnvVarName !== "DATABASE_URL") {
2939
- logger3.debug(`Looking for custom database URL variable: ${this.databaseUrlEnvVarName}`);
3350
+ getLogger().debug(`Looking for custom database URL variable: ${this.databaseUrlEnvVarName}`);
2940
3351
  } else {
2941
- logger3.debug("Looking for default database URL variable: DATABASE_URL");
3352
+ getLogger().debug("Looking for default database URL variable: DATABASE_URL");
2942
3353
  }
2943
3354
  const hasConfiguredVar = await hasVariableInAnyEnvFile(
2944
3355
  workspacePath,
2945
3356
  this.databaseUrlEnvVarName,
2946
- async (p) => fs3.pathExists(p),
3357
+ async (p) => fs4.pathExists(p),
2947
3358
  async (p, v) => this.environment.getEnvVariable(p, v)
2948
3359
  );
2949
3360
  if (hasConfiguredVar) {
2950
3361
  if (this.databaseUrlEnvVarName !== "DATABASE_URL") {
2951
- logger3.debug(`\u2705 Found custom database URL variable: ${this.databaseUrlEnvVarName}`);
3362
+ getLogger().debug(`\u2705 Found custom database URL variable: ${this.databaseUrlEnvVarName}`);
2952
3363
  } else {
2953
- logger3.debug(`\u2705 Found default database URL variable: DATABASE_URL`);
3364
+ getLogger().debug(`\u2705 Found default database URL variable: DATABASE_URL`);
2954
3365
  }
2955
3366
  return true;
2956
3367
  }
2957
3368
  if (this.databaseUrlEnvVarName !== "DATABASE_URL") {
2958
- logger3.debug(`\u274C Custom database URL variable '${this.databaseUrlEnvVarName}' not found in any env file`);
3369
+ getLogger().debug(`\u274C Custom database URL variable '${this.databaseUrlEnvVarName}' not found in any env file`);
2959
3370
  throw new Error(
2960
3371
  `Configured database URL environment variable '${this.databaseUrlEnvVarName}' not found in any dotenv-flow file. Please add it to an .env file or update your iloom configuration.`
2961
3372
  );
@@ -2963,13 +3374,13 @@ var DatabaseManager = class {
2963
3374
  const hasDefaultVar = await hasVariableInAnyEnvFile(
2964
3375
  workspacePath,
2965
3376
  "DATABASE_URL",
2966
- async (p) => fs3.pathExists(p),
3377
+ async (p) => fs4.pathExists(p),
2967
3378
  async (p, v) => this.environment.getEnvVariable(p, v)
2968
3379
  );
2969
3380
  if (hasDefaultVar) {
2970
- logger3.debug("\u2705 Found fallback DATABASE_URL variable");
3381
+ getLogger().debug("\u2705 Found fallback DATABASE_URL variable");
2971
3382
  } else {
2972
- logger3.debug("\u274C No DATABASE_URL variable found in any env file");
3383
+ getLogger().debug("\u274C No DATABASE_URL variable found in any env file");
2973
3384
  }
2974
3385
  return hasDefaultVar;
2975
3386
  } catch (error) {
@@ -2986,6 +3397,7 @@ init_logger();
2986
3397
  import { execa as execa4 } from "execa";
2987
3398
  import { existsSync as existsSync2 } from "fs";
2988
3399
  import { join } from "path";
3400
+ import { createHash as createHash3 } from "crypto";
2989
3401
 
2990
3402
  // src/utils/terminal.ts
2991
3403
  import { execa as execa3 } from "execa";
@@ -3062,8 +3474,8 @@ async function buildAppleScript(options) {
3062
3474
  script += `end tell`;
3063
3475
  return script;
3064
3476
  }
3065
- function escapePathForAppleScript(path6) {
3066
- return path6.replace(/'/g, "'\\''");
3477
+ function escapePathForAppleScript(path7) {
3478
+ return path7.replace(/'/g, "'\\''");
3067
3479
  }
3068
3480
  function escapeForAppleScript(command) {
3069
3481
  return command.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -3152,7 +3564,8 @@ function parseJsonStreamOutput(output) {
3152
3564
  }
3153
3565
  }
3154
3566
  async function launchClaude(prompt, options = {}) {
3155
- const { model, permissionMode, addDir, headless = false, appendSystemPrompt, mcpConfig, allowedTools, disallowedTools, agents } = options;
3567
+ const { model, permissionMode, addDir, headless = false, appendSystemPrompt, mcpConfig, allowedTools, disallowedTools, agents, sessionId } = options;
3568
+ const log = getLogger();
3156
3569
  const args = [];
3157
3570
  if (headless) {
3158
3571
  args.push("-p");
@@ -3186,6 +3599,9 @@ async function launchClaude(prompt, options = {}) {
3186
3599
  if (agents) {
3187
3600
  args.push("--agents", JSON.stringify(agents));
3188
3601
  }
3602
+ if (sessionId) {
3603
+ args.push("--session-id", sessionId);
3604
+ }
3189
3605
  try {
3190
3606
  if (headless) {
3191
3607
  const isDebugMode = logger.isDebugEnabled();
@@ -3210,13 +3626,13 @@ async function launchClaude(prompt, options = {}) {
3210
3626
  const text = chunk.toString();
3211
3627
  outputBuffer += text;
3212
3628
  if (isDebugMode) {
3213
- process.stdout.write(text);
3629
+ log.stdout.write(text);
3214
3630
  } else {
3215
3631
  if (isFirstProgress) {
3216
- process.stdout.write("\u{1F916} .");
3632
+ log.stdout.write("\u{1F916} .");
3217
3633
  isFirstProgress = false;
3218
3634
  } else {
3219
- process.stdout.write(".");
3635
+ log.stdout.write(".");
3220
3636
  }
3221
3637
  }
3222
3638
  });
@@ -3225,36 +3641,137 @@ async function launchClaude(prompt, options = {}) {
3225
3641
  if (isStreaming) {
3226
3642
  const rawOutput = outputBuffer.trim();
3227
3643
  if (!isDebugMode) {
3228
- process.stdout.write("\n");
3644
+ log.stdout.write("\n");
3229
3645
  }
3230
3646
  return isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput;
3231
3647
  } else {
3232
3648
  if (isDebugMode) {
3233
- process.stdout.write(result.stdout);
3649
+ log.stdout.write(result.stdout);
3234
3650
  if (result.stdout && !result.stdout.endsWith("\n")) {
3235
- process.stdout.write("\n");
3651
+ log.stdout.write("\n");
3236
3652
  }
3237
3653
  } else {
3238
- process.stdout.write("\u{1F916} .");
3239
- process.stdout.write("\n");
3654
+ log.stdout.write("\u{1F916} .");
3655
+ log.stdout.write("\n");
3240
3656
  }
3241
3657
  const rawOutput = result.stdout.trim();
3242
3658
  return isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput;
3243
3659
  }
3244
3660
  } else {
3245
- await execa4("claude", [...args, "--", prompt], {
3246
- ...addDir && { cwd: addDir },
3247
- stdio: "inherit",
3248
- // Let user interact directly in current terminal
3249
- timeout: 0,
3250
- // Disable timeout
3251
- verbose: logger.isDebugEnabled()
3252
- });
3253
- return;
3661
+ try {
3662
+ await execa4("claude", [...args, "--", prompt], {
3663
+ ...addDir && { cwd: addDir },
3664
+ stdio: ["inherit", "inherit", "pipe"],
3665
+ // Capture stderr to detect session conflicts
3666
+ timeout: 0,
3667
+ // Disable timeout
3668
+ verbose: logger.isDebugEnabled()
3669
+ });
3670
+ return;
3671
+ } catch (interactiveError) {
3672
+ const interactiveExecaError = interactiveError;
3673
+ const interactiveErrorMessage = interactiveExecaError.stderr ?? interactiveExecaError.message ?? "";
3674
+ const sessionMatch = interactiveErrorMessage.match(/Session ID ([0-9a-f-]+) is already in use/i);
3675
+ const conflictSessionId = sessionMatch == null ? void 0 : sessionMatch[1];
3676
+ if (sessionMatch && sessionId && conflictSessionId) {
3677
+ log.debug(`Session ID ${conflictSessionId} already in use, retrying with --resume`);
3678
+ const resumeArgs = args.filter((arg, idx) => {
3679
+ if (arg === "--session-id") return false;
3680
+ if (idx > 0 && args[idx - 1] === "--session-id") return false;
3681
+ return true;
3682
+ });
3683
+ resumeArgs.push("--resume", conflictSessionId);
3684
+ await execa4("claude", resumeArgs, {
3685
+ ...addDir && { cwd: addDir },
3686
+ stdio: "inherit",
3687
+ timeout: 0,
3688
+ verbose: logger.isDebugEnabled()
3689
+ });
3690
+ return;
3691
+ }
3692
+ throw interactiveError;
3693
+ }
3254
3694
  }
3255
3695
  } catch (error) {
3256
3696
  const execaError = error;
3257
3697
  const errorMessage = execaError.stderr ?? execaError.message ?? "Unknown Claude CLI error";
3698
+ const sessionInUseMatch = errorMessage.match(/Session ID ([0-9a-f-]+) is already in use/i);
3699
+ const extractedSessionId = sessionInUseMatch == null ? void 0 : sessionInUseMatch[1];
3700
+ if (sessionInUseMatch && sessionId && extractedSessionId) {
3701
+ log.debug(`Session ID ${extractedSessionId} already in use, retrying with --resume`);
3702
+ const resumeArgs = args.filter((arg, idx) => {
3703
+ if (arg === "--session-id") return false;
3704
+ if (idx > 0 && args[idx - 1] === "--session-id") return false;
3705
+ return true;
3706
+ });
3707
+ resumeArgs.push("--resume", extractedSessionId);
3708
+ try {
3709
+ if (headless) {
3710
+ const isDebugMode = logger.isDebugEnabled();
3711
+ const execaOptions = {
3712
+ input: prompt,
3713
+ timeout: 0,
3714
+ ...addDir && { cwd: addDir },
3715
+ verbose: isDebugMode,
3716
+ ...isDebugMode && { stdio: ["pipe", "pipe", "pipe"] }
3717
+ };
3718
+ const subprocess = execa4("claude", resumeArgs, execaOptions);
3719
+ const isJsonStreamFormat = resumeArgs.includes("--output-format") && resumeArgs.includes("stream-json");
3720
+ let outputBuffer = "";
3721
+ let isStreaming = false;
3722
+ let isFirstProgress = true;
3723
+ if (subprocess.stdout && typeof subprocess.stdout.on === "function") {
3724
+ isStreaming = true;
3725
+ subprocess.stdout.on("data", (chunk) => {
3726
+ const text = chunk.toString();
3727
+ outputBuffer += text;
3728
+ if (isDebugMode) {
3729
+ log.stdout.write(text);
3730
+ } else {
3731
+ if (isFirstProgress) {
3732
+ log.stdout.write("\u{1F916} .");
3733
+ isFirstProgress = false;
3734
+ } else {
3735
+ log.stdout.write(".");
3736
+ }
3737
+ }
3738
+ });
3739
+ }
3740
+ const result = await subprocess;
3741
+ if (isStreaming) {
3742
+ const rawOutput = outputBuffer.trim();
3743
+ if (!isDebugMode) {
3744
+ log.stdout.write("\n");
3745
+ }
3746
+ return isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput;
3747
+ } else {
3748
+ if (isDebugMode) {
3749
+ log.stdout.write(result.stdout);
3750
+ if (result.stdout && !result.stdout.endsWith("\n")) {
3751
+ log.stdout.write("\n");
3752
+ }
3753
+ } else {
3754
+ log.stdout.write("\u{1F916} .");
3755
+ log.stdout.write("\n");
3756
+ }
3757
+ const rawOutput = result.stdout.trim();
3758
+ return isJsonStreamFormat ? parseJsonStreamOutput(rawOutput) : rawOutput;
3759
+ }
3760
+ } else {
3761
+ await execa4("claude", resumeArgs, {
3762
+ ...addDir && { cwd: addDir },
3763
+ stdio: "inherit",
3764
+ timeout: 0,
3765
+ verbose: logger.isDebugEnabled()
3766
+ });
3767
+ return;
3768
+ }
3769
+ } catch (retryError) {
3770
+ const retryExecaError = retryError;
3771
+ const retryErrorMessage = retryExecaError.stderr ?? retryExecaError.message ?? "Unknown Claude CLI error";
3772
+ throw new Error(`Claude CLI error: ${retryErrorMessage}`);
3773
+ }
3774
+ }
3258
3775
  throw new Error(`Claude CLI error: ${errorMessage}`);
3259
3776
  }
3260
3777
  }
@@ -3300,7 +3817,7 @@ async function launchClaudeInNewTerminalWindow(_prompt, options) {
3300
3817
  init_logger();
3301
3818
  import { readFile as readFile2 } from "fs/promises";
3302
3819
  import { accessSync } from "fs";
3303
- import path5 from "path";
3820
+ import path6 from "path";
3304
3821
  import { fileURLToPath } from "url";
3305
3822
  var PromptTemplateManager = class {
3306
3823
  constructor(templateDir) {
@@ -3309,17 +3826,17 @@ var PromptTemplateManager = class {
3309
3826
  } else {
3310
3827
  const currentFileUrl = import.meta.url;
3311
3828
  const currentFilePath = fileURLToPath(currentFileUrl);
3312
- const distDir = path5.dirname(currentFilePath);
3313
- let templateDir2 = path5.join(distDir, "prompts");
3829
+ const distDir = path6.dirname(currentFilePath);
3830
+ let templateDir2 = path6.join(distDir, "prompts");
3314
3831
  let currentDir = distDir;
3315
- while (currentDir !== path5.dirname(currentDir)) {
3316
- const candidatePath = path5.join(currentDir, "prompts");
3832
+ while (currentDir !== path6.dirname(currentDir)) {
3833
+ const candidatePath = path6.join(currentDir, "prompts");
3317
3834
  try {
3318
3835
  accessSync(candidatePath);
3319
3836
  templateDir2 = candidatePath;
3320
3837
  break;
3321
3838
  } catch {
3322
- currentDir = path5.dirname(currentDir);
3839
+ currentDir = path6.dirname(currentDir);
3323
3840
  }
3324
3841
  }
3325
3842
  this.templateDir = templateDir2;
@@ -3334,7 +3851,7 @@ var PromptTemplateManager = class {
3334
3851
  * Load a template file by name
3335
3852
  */
3336
3853
  async loadTemplate(templateName) {
3337
- const templatePath = path5.join(this.templateDir, `${templateName}-prompt.txt`);
3854
+ const templatePath = path6.join(this.templateDir, `${templateName}-prompt.txt`);
3338
3855
  logger.debug("Loading template", {
3339
3856
  templateName,
3340
3857
  templateDir: this.templateDir,
@@ -3419,6 +3936,18 @@ var PromptTemplateManager = class {
3419
3936
  if (variables.VSCODE_SETTINGS_GITIGNORED !== void 0) {
3420
3937
  result = result.replace(/VSCODE_SETTINGS_GITIGNORED/g, variables.VSCODE_SETTINGS_GITIGNORED);
3421
3938
  }
3939
+ if (variables.SESSION_CONTEXT !== void 0) {
3940
+ result = result.replace(/SESSION_CONTEXT/g, variables.SESSION_CONTEXT);
3941
+ }
3942
+ if (variables.BRANCH_NAME !== void 0) {
3943
+ result = result.replace(/BRANCH_NAME/g, variables.BRANCH_NAME);
3944
+ }
3945
+ if (variables.LOOM_TYPE !== void 0) {
3946
+ result = result.replace(/LOOM_TYPE/g, variables.LOOM_TYPE);
3947
+ }
3948
+ if (variables.COMPACT_SUMMARIES !== void 0) {
3949
+ result = result.replace(/COMPACT_SUMMARIES/g, variables.COMPACT_SUMMARIES);
3950
+ }
3422
3951
  return result;
3423
3952
  }
3424
3953
  /**
@@ -3477,6 +4006,18 @@ var PromptTemplateManager = class {
3477
4006
  } else {
3478
4007
  result = result.replace(firstTimeUserRegex, "");
3479
4008
  }
4009
+ const interactiveModeRegex = /\{\{#IF INTERACTIVE_MODE\}\}(.*?)\{\{\/IF INTERACTIVE_MODE\}\}/gs;
4010
+ if (variables.INTERACTIVE_MODE === true) {
4011
+ result = result.replace(interactiveModeRegex, "$1");
4012
+ } else {
4013
+ result = result.replace(interactiveModeRegex, "");
4014
+ }
4015
+ const compactSummariesRegex = /\{\{#IF COMPACT_SUMMARIES\}\}(.*?)\{\{\/IF COMPACT_SUMMARIES\}\}/gs;
4016
+ if (variables.COMPACT_SUMMARIES !== void 0 && variables.COMPACT_SUMMARIES !== "") {
4017
+ result = result.replace(compactSummariesRegex, "$1");
4018
+ } else {
4019
+ result = result.replace(compactSummariesRegex, "");
4020
+ }
3480
4021
  return result;
3481
4022
  }
3482
4023
  /**
@@ -3502,15 +4043,6 @@ var ClaudeService = class {
3502
4043
  async isAvailable() {
3503
4044
  return detectClaudeCli();
3504
4045
  }
3505
- /**
3506
- * Get the appropriate model for a workflow type
3507
- */
3508
- getModelForWorkflow(type) {
3509
- if (type === "issue") {
3510
- return "claude-sonnet-4-20250514";
3511
- }
3512
- return void 0;
3513
- }
3514
4046
  /**
3515
4047
  * Get the appropriate permission mode for a workflow type
3516
4048
  */
@@ -3554,7 +4086,6 @@ var ClaudeService = class {
3554
4086
  variables.PORT = port;
3555
4087
  }
3556
4088
  const prompt = await this.templateManager.getPrompt(type, variables);
3557
- const model = this.getModelForWorkflow(type);
3558
4089
  const permissionMode = this.getPermissionModeForWorkflow(type);
3559
4090
  if (permissionMode === "bypassPermissions") {
3560
4091
  logger.warn(
@@ -3565,9 +4096,6 @@ var ClaudeService = class {
3565
4096
  addDir: workspacePath,
3566
4097
  headless
3567
4098
  };
3568
- if (model !== void 0) {
3569
- claudeOptions.model = model;
3570
- }
3571
4099
  if (permissionMode !== void 0 && permissionMode !== "default") {
3572
4100
  claudeOptions.permissionMode = permissionMode;
3573
4101
  }
@@ -3585,7 +4113,6 @@ var ClaudeService = class {
3585
4113
  }
3586
4114
  logger.debug("Launching Claude for workflow", {
3587
4115
  type,
3588
- model,
3589
4116
  permissionMode,
3590
4117
  headless,
3591
4118
  workspacePath
@@ -3987,7 +4514,9 @@ export {
3987
4514
  UserAbortedCommitError,
3988
4515
  WorkspaceManager,
3989
4516
  branchExists,
4517
+ checkRemoteBranchStatus,
3990
4518
  createLogger,
4519
+ createStderrLogger,
3991
4520
  ensureRepositoryHasCommits,
3992
4521
  executeGitCommand,
3993
4522
  extractIssueNumber,
@@ -3995,16 +4524,20 @@ export {
3995
4524
  findAllBranchesForIssue,
3996
4525
  findMainWorktreePath,
3997
4526
  findMainWorktreePathWithSettings,
4527
+ findWorktreeForBranch,
3998
4528
  generateWorktreePath,
3999
4529
  getCurrentBranch,
4000
4530
  getDefaultBranch,
4531
+ getMergeTargetBranch,
4001
4532
  getRepoRoot,
4002
4533
  getWorktreeRoot,
4003
4534
  hasUncommittedChanges,
4535
+ isBranchMergedIntoMain,
4004
4536
  isEmptyRepository,
4005
4537
  isFileGitignored,
4006
4538
  isFileTrackedByGit,
4007
4539
  isPRBranch,
4540
+ isRemoteBranchUpToDate,
4008
4541
  isValidGitRepo,
4009
4542
  isWorktreePath,
4010
4543
  logger,