@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/README.md CHANGED
@@ -51,7 +51,9 @@ iloom stops the "Context Window Tetris." It treats context as a first-class conc
51
51
  * **Scale Understanding:** Because every loom holds its own isolated environment (Git worktree, DB branch, local server), you can switch between 5 complex features without losing your place or your AI's context.
52
52
 
53
53
  * **Visible Reasoning:** The AI's decisions are documented publicly. Your team sees the plan, and "future you" knows exactly why a decision was made.
54
-
54
+
55
+ * **Automatic Session Summaries:** When you finish a loom, iloom captures key insights, decisions, and lessons learned from your Claude session and posts them to the issue. These summaries become institutional knowledge that informs future tasks.
56
+
55
57
 
56
58
  _iloom is not just a tool for managing git worktrees - it's a control plane for maintaining alignment between you and your AI assistant._
57
59
 
@@ -73,8 +75,8 @@ iloom uses your existing Claude subscription to build a shared mental model of y
73
75
 
74
76
  # ... You, the iloom agents and Claude build the feature together in the isolated environment ...
75
77
 
76
- # 4. Finish & Merge # Validates code (test/lint), handles merge conflicts, and cleans up the worktree/DB.
77
- il finish
78
+ # 4. Finish & Merge # Validates code, generates session summary, merges, and cleans up.
79
+ il finish
78
80
  ```
79
81
 
80
82
  **The iloom Difference:** il start doesn't just create a branch. It launches a multi-agent workflow that surfaces assumptions and creates a structured plan in your issue tracker **before you even need to look at your IDE.**
@@ -138,8 +140,10 @@ Command Reference
138
140
  | `il finish` | `dn` | Validate tests/lint, commit, handle conflicts, and merge/PR. |
139
141
  | `il cleanup` | `remove` | Safely remove a loom and its database branch without merging. |
140
142
  | `il list` | | Show active looms and paths. |
143
+ | `il projects` | | List configured projects (JSON output). |
141
144
  | `il spin` | | Launch Claude inside the current loom with context auto-detected. |
142
145
  | `il open` | `run` | Open loom in browser (web) or run your CLI tool. |
146
+ | `il dev-server` | `dev` | Start dev server in foreground for a workspace. |
143
147
  | `il add-issue` | `a` | Create and AI-enhance a new issue without starting work yet. |
144
148
  | `il init` | `config` | Interactive configuration wizard. |
145
149
  | `il feedback` | `f` | Submit bug reports/feedback directly from the CLI. |
@@ -218,6 +222,12 @@ This example shows how to configure a project-wide default (e.g., GitHub remote)
218
222
  "issue": {
219
223
  "permissionMode": "acceptEdits" // Control Claude Code permissions
220
224
  }
225
+ },
226
+ "spin": {
227
+ "model": "opus" // Claude model for spin orchestrator: opus (default), sonnet, or haiku
228
+ },
229
+ "summary": {
230
+ "model": "sonnet" // Claude model for session summaries: sonnet (default), opus, or haiku
221
231
  }
222
232
  }
223
233
  ```
@@ -3,11 +3,12 @@ import {
3
3
  ClaudeBranchNameStrategy,
4
4
  DefaultBranchNamingService,
5
5
  SimpleBranchNameStrategy
6
- } from "./chunk-SUOXY5WJ.js";
7
- import "./chunk-GEHQXLEI.js";
6
+ } from "./chunk-QIUJPPJQ.js";
7
+ import "./chunk-6UIGZD2N.js";
8
+ import "./chunk-UYVWLISQ.js";
8
9
  export {
9
10
  ClaudeBranchNameStrategy,
10
11
  DefaultBranchNamingService,
11
12
  SimpleBranchNameStrategy
12
13
  };
13
- //# sourceMappingURL=BranchNamingService-A77VI6AI.js.map
14
+ //# sourceMappingURL=BranchNamingService-GCCWB3LK.js.map
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ClaudeContextManager
4
+ } from "./chunk-UPUAQYAW.js";
5
+ import "./chunk-POI7KLBH.js";
6
+ import "./chunk-VWNS6DH5.js";
7
+ import "./chunk-RUC7OULH.js";
8
+ import "./chunk-VAYGNQTE.js";
9
+ import "./chunk-Z5NXYJIG.js";
10
+ import "./chunk-6UIGZD2N.js";
11
+ import "./chunk-74VMN2KC.js";
12
+ import "./chunk-UYVWLISQ.js";
13
+ export {
14
+ ClaudeContextManager
15
+ };
16
+ //# sourceMappingURL=ClaudeContextManager-DK77227F.js.map
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ClaudeService
4
+ } from "./chunk-POI7KLBH.js";
5
+ import "./chunk-VWNS6DH5.js";
6
+ import "./chunk-RUC7OULH.js";
7
+ import "./chunk-VAYGNQTE.js";
8
+ import "./chunk-Z5NXYJIG.js";
9
+ import "./chunk-6UIGZD2N.js";
10
+ import "./chunk-74VMN2KC.js";
11
+ import "./chunk-UYVWLISQ.js";
12
+ export {
13
+ ClaudeService
14
+ };
15
+ //# sourceMappingURL=ClaudeService-W3SA7HVG.js.map
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ GitHubService
4
+ } from "./chunk-OEGECBFS.js";
5
+ import "./chunk-KO2FOMHL.js";
6
+ import "./chunk-SJ2GZ6RF.js";
7
+ import "./chunk-6UIGZD2N.js";
8
+ import "./chunk-UYVWLISQ.js";
9
+ export {
10
+ GitHubService
11
+ };
12
+ //# sourceMappingURL=GitHubService-RPM27GWD.js.map
@@ -1,29 +1,35 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getDevServerLaunchCommand
4
- } from "./chunk-ZM3CFL5L.js";
5
- import "./chunk-ZT3YZB4K.js";
4
+ } from "./chunk-QRBOPFAA.js";
5
+ import "./chunk-VBFDVGAE.js";
6
6
  import {
7
7
  ClaudeContextManager
8
- } from "./chunk-AKUJXDNW.js";
9
- import "./chunk-PGPI5LR4.js";
10
- import "./chunk-RIEO2WML.js";
11
- import "./chunk-CDZERT7Z.js";
8
+ } from "./chunk-UPUAQYAW.js";
9
+ import "./chunk-POI7KLBH.js";
10
+ import {
11
+ getExecutablePath
12
+ } from "./chunk-GYCR2LOU.js";
13
+ import "./chunk-VWNS6DH5.js";
12
14
  import {
13
15
  generateColorFromBranchName,
14
16
  hexToRgb
15
- } from "./chunk-CFFQ2Z7A.js";
16
- import "./chunk-OYF4VIFI.js";
17
+ } from "./chunk-WUQQNE63.js";
18
+ import "./chunk-RUC7OULH.js";
17
19
  import {
18
20
  openMultipleTerminalWindows,
19
21
  openTerminalWindow
20
- } from "./chunk-RW54ZMBM.js";
22
+ } from "./chunk-VAYGNQTE.js";
21
23
  import {
22
24
  getDotenvFlowFiles
23
- } from "./chunk-UJL4HI2R.js";
25
+ } from "./chunk-Z5NXYJIG.js";
26
+ import {
27
+ getLogger
28
+ } from "./chunk-6UIGZD2N.js";
29
+ import "./chunk-74VMN2KC.js";
24
30
  import {
25
31
  logger
26
- } from "./chunk-GEHQXLEI.js";
32
+ } from "./chunk-UYVWLISQ.js";
27
33
 
28
34
  // src/lib/LoomLauncher.ts
29
35
  import { existsSync } from "fs";
@@ -102,10 +108,10 @@ var LoomLauncher = class {
102
108
  */
103
109
  async launchLoom(options) {
104
110
  const { enableClaude, enableCode, enableDevServer, enableTerminal } = options;
105
- logger.debug(`Launching loom components: Claude=${enableClaude}, Code=${enableCode}, DevServer=${enableDevServer}, Terminal=${enableTerminal}`);
111
+ getLogger().debug(`Launching loom components: Claude=${enableClaude}, Code=${enableCode}, DevServer=${enableDevServer}, Terminal=${enableTerminal}`);
106
112
  const launchPromises = [];
107
113
  if (enableCode) {
108
- logger.debug("Launching VSCode");
114
+ getLogger().debug("Launching VSCode");
109
115
  launchPromises.push(this.launchVSCode(options));
110
116
  }
111
117
  const terminalsToLaunch = [];
@@ -128,7 +134,7 @@ var LoomLauncher = class {
128
134
  });
129
135
  }
130
136
  if (terminalsToLaunch.length > 1) {
131
- logger.debug(`Launching ${terminalsToLaunch.length} terminals in single window`);
137
+ getLogger().debug(`Launching ${terminalsToLaunch.length} terminals in single window`);
132
138
  launchPromises.push(this.launchMultipleTerminals(terminalsToLaunch, options));
133
139
  } else if (terminalsToLaunch.length === 1) {
134
140
  const terminal = terminalsToLaunch[0];
@@ -136,7 +142,7 @@ var LoomLauncher = class {
136
142
  throw new Error("Terminal configuration is undefined");
137
143
  }
138
144
  const terminalType = terminal.type;
139
- logger.debug(`Launching single ${terminalType} terminal`);
145
+ getLogger().debug(`Launching single ${terminalType} terminal`);
140
146
  if (terminalType === "claude") {
141
147
  launchPromises.push(this.launchClaudeTerminal(options));
142
148
  } else if (terminalType === "devServer") {
@@ -146,7 +152,7 @@ var LoomLauncher = class {
146
152
  }
147
153
  }
148
154
  await Promise.all(launchPromises);
149
- logger.success("loom launched successfully");
155
+ getLogger().success("loom launched successfully");
150
156
  }
151
157
  /**
152
158
  * Launch IDE (VSCode or configured alternative)
@@ -155,7 +161,7 @@ var LoomLauncher = class {
155
161
  var _a;
156
162
  const ideConfig = await ((_a = this.settings) == null ? void 0 : _a.loadSettings().then((s) => s.ide));
157
163
  await openIdeWindow(options.worktreePath, ideConfig);
158
- logger.info("IDE opened");
164
+ getLogger().info("IDE opened");
159
165
  }
160
166
  /**
161
167
  * Launch Claude terminal
@@ -172,7 +178,7 @@ var LoomLauncher = class {
172
178
  ...options.setArguments && { setArguments: options.setArguments },
173
179
  ...options.executablePath && { executablePath: options.executablePath }
174
180
  });
175
- logger.info("Claude terminal opened");
181
+ getLogger().info("Claude terminal opened");
176
182
  }
177
183
  /**
178
184
  * Launch dev server terminal
@@ -192,21 +198,26 @@ var LoomLauncher = class {
192
198
  includePortExport: options.capabilities.includes("web"),
193
199
  ...options.port !== void 0 && { port: options.port }
194
200
  });
195
- logger.info("Dev server terminal opened");
201
+ getLogger().info("Dev server terminal opened");
196
202
  }
197
203
  /**
198
- * Launch standalone terminal (no command, just workspace with env vars)
204
+ * Launch standalone terminal running `il shell <identifier>`
199
205
  */
200
206
  async launchStandaloneTerminal(options) {
207
+ const executable = options.executablePath ?? getExecutablePath();
208
+ const shellIdentifier = String(options.identifier);
209
+ const shellCommand = `${executable} shell ${shellIdentifier}`;
201
210
  const backgroundColor = options.colorTerminal ?? true ? options.colorHex ? hexToRgb(options.colorHex) : generateColorFromBranchName(options.branchName).rgb : void 0;
202
211
  await openTerminalWindow({
203
212
  workspacePath: options.worktreePath,
213
+ command: shellCommand,
204
214
  ...backgroundColor && { backgroundColor },
205
- includeEnvSetup: (options.sourceEnvOnStart ?? false) && this.hasAnyEnvFiles(options.worktreePath),
215
+ // il shell handles env loading internally, so we don't need includeEnvSetup
216
+ includeEnvSetup: false,
206
217
  includePortExport: options.capabilities.includes("web"),
207
218
  ...options.port !== void 0 && { port: options.port }
208
219
  });
209
- logger.info("Standalone terminal opened");
220
+ getLogger().info("Standalone terminal opened");
210
221
  }
211
222
  /**
212
223
  * Build terminal options for Claude
@@ -257,17 +268,22 @@ var LoomLauncher = class {
257
268
  };
258
269
  }
259
270
  /**
260
- * Build terminal options for standalone terminal (no command)
271
+ * Build terminal options for standalone terminal
272
+ * Runs `il shell <identifier>` which handles env loading internally
261
273
  */
262
274
  buildStandaloneTerminalOptions(options) {
263
- const hasEnvFile = this.hasAnyEnvFiles(options.worktreePath);
264
275
  const terminalTitle = `Terminal - ${this.formatIdentifier(options.workflowType, options.identifier)}`;
276
+ const executable = options.executablePath ?? getExecutablePath();
277
+ const shellIdentifier = String(options.identifier);
278
+ const shellCommand = `${executable} shell ${shellIdentifier}`;
265
279
  const backgroundColor = options.colorTerminal ?? true ? options.colorHex ? hexToRgb(options.colorHex) : generateColorFromBranchName(options.branchName).rgb : void 0;
266
280
  return {
267
281
  workspacePath: options.worktreePath,
282
+ command: shellCommand,
268
283
  ...backgroundColor && { backgroundColor },
269
284
  title: terminalTitle,
270
- includeEnvSetup: (options.sourceEnvOnStart ?? false) && hasEnvFile,
285
+ // il shell handles env loading internally, so we don't need includeEnvSetup
286
+ includeEnvSetup: false,
271
287
  includePortExport: options.capabilities.includes("web"),
272
288
  ...options.port !== void 0 && { port: options.port }
273
289
  };
@@ -279,7 +295,7 @@ var LoomLauncher = class {
279
295
  const terminalOptions = terminals.map((t) => t.options);
280
296
  await openMultipleTerminalWindows(terminalOptions);
281
297
  const terminalTypes = terminals.map((t) => t.type).join(" + ");
282
- logger.info(`Multiple terminals opened: ${terminalTypes}`);
298
+ getLogger().info(`Multiple terminals opened: ${terminalTypes}`);
283
299
  }
284
300
  /**
285
301
  * Check if any dotenv-flow files exist in the workspace
@@ -305,4 +321,4 @@ var LoomLauncher = class {
305
321
  export {
306
322
  LoomLauncher
307
323
  };
308
- //# sourceMappingURL=LoomLauncher-ZV3ZZIBA.js.map
324
+ //# sourceMappingURL=LoomLauncher-S3YGJRJQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/LoomLauncher.ts","../src/utils/ide.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { openTerminalWindow, openMultipleTerminalWindows } from '../utils/terminal.js'\nimport type { TerminalWindowOptions } from '../utils/terminal.js'\nimport { openIdeWindow } from '../utils/ide.js'\nimport { getDevServerLaunchCommand } from '../utils/dev-server.js'\nimport { generateColorFromBranchName, hexToRgb } from '../utils/color.js'\nimport { getLogger } from '../utils/logger-context.js'\nimport { ClaudeContextManager } from './ClaudeContextManager.js'\nimport type { SettingsManager } from './SettingsManager.js'\nimport type { Capability } from '../types/loom.js'\nimport { getDotenvFlowFiles } from '../utils/env.js'\nimport { getExecutablePath } from '../utils/cli-overrides.js'\n\nexport interface LaunchLoomOptions {\n\tenableClaude: boolean\n\tenableCode: boolean\n\tenableDevServer: boolean\n\tenableTerminal: boolean\n\tworktreePath: string\n\tbranchName: string\n\tport?: number\n\tcapabilities: Capability[]\n\tworkflowType: 'issue' | 'pr' | 'regular'\n\tidentifier: string | number\n\ttitle?: string\n\toneShot?: import('../types/index.js').OneShotMode\n\tsetArguments?: string[] // Raw --set arguments to forward\n\texecutablePath?: string // Executable path to use for spin command\n\tsourceEnvOnStart?: boolean // defaults to false if undefined\n\tcolorTerminal?: boolean // defaults to true if undefined\n\tcolorHex?: string // Pre-calculated hex color from metadata, avoids recalculation\n}\n\n/**\n * LoomLauncher orchestrates opening loom components\n */\nexport class LoomLauncher {\n\tprivate claudeContext: ClaudeContextManager\n\tprivate settings?: SettingsManager\n\n\tconstructor(claudeContext?: ClaudeContextManager, settings?: SettingsManager) {\n\t\tthis.claudeContext = claudeContext ?? new ClaudeContextManager()\n\t\tif (settings !== undefined) {\n\t\t\tthis.settings = settings\n\t\t}\n\t}\n\n\t/**\n\t * Launch loom components based on individual flags\n\t */\n\tasync launchLoom(options: LaunchLoomOptions): Promise<void> {\n\t\tconst { enableClaude, enableCode, enableDevServer, enableTerminal } = options\n\n\t\tgetLogger().debug(`Launching loom components: Claude=${enableClaude}, Code=${enableCode}, DevServer=${enableDevServer}, Terminal=${enableTerminal}`)\n\n\t\tconst launchPromises: Promise<void>[] = []\n\n\t\t// Launch VSCode if enabled\n\t\tif (enableCode) {\n\t\t\tgetLogger().debug('Launching VSCode')\n\t\t\tlaunchPromises.push(this.launchVSCode(options))\n\t\t}\n\n\t\t// Build array of terminals to launch\n\t\tconst terminalsToLaunch: Array<{\n\t\t\ttype: 'claude' | 'devServer' | 'terminal'\n\t\t\toptions: TerminalWindowOptions\n\t\t}> = []\n\n\t\tif (enableDevServer) {\n\t\t\tterminalsToLaunch.push({\n\t\t\t\ttype: 'devServer',\n\t\t\t\toptions: await this.buildDevServerTerminalOptions(options),\n\t\t\t})\n\t\t}\n\n\t\tif (enableTerminal) {\n\t\t\tterminalsToLaunch.push({\n\t\t\t\ttype: 'terminal',\n\t\t\t\toptions: this.buildStandaloneTerminalOptions(options),\n\t\t\t})\n\t\t}\n\n\t\tif (enableClaude) {\n\t\t\tterminalsToLaunch.push({\n\t\t\t\ttype: 'claude',\n\t\t\t\toptions: await this.buildClaudeTerminalOptions(options),\n\t\t\t})\n\t\t}\n\n\t\t// Launch terminals based on count\n\t\tif (terminalsToLaunch.length > 1) {\n\t\t\t// Multiple terminals - launch as tabs in single window\n\t\t\tgetLogger().debug(`Launching ${terminalsToLaunch.length} terminals in single window`)\n\t\t\tlaunchPromises.push(this.launchMultipleTerminals(terminalsToLaunch, options))\n\t\t} else if (terminalsToLaunch.length === 1) {\n\t\t\t// Single terminal - launch standalone\n\t\t\tconst terminal = terminalsToLaunch[0]\n\t\t\tif (!terminal) {\n\t\t\t\tthrow new Error('Terminal configuration is undefined')\n\t\t\t}\n\t\t\tconst terminalType = terminal.type\n\t\t\tgetLogger().debug(`Launching single ${terminalType} terminal`)\n\n\t\t\tif (terminalType === 'claude') {\n\t\t\t\tlaunchPromises.push(this.launchClaudeTerminal(options))\n\t\t\t} else if (terminalType === 'devServer') {\n\t\t\t\tlaunchPromises.push(this.launchDevServerTerminal(options))\n\t\t\t} else {\n\t\t\t\tlaunchPromises.push(this.launchStandaloneTerminal(options))\n\t\t\t}\n\t\t}\n\n\t\t// Wait for all components to launch\n\t\tawait Promise.all(launchPromises)\n\n\t\tgetLogger().success('loom launched successfully')\n\t}\n\n\t/**\n\t * Launch IDE (VSCode or configured alternative)\n\t */\n\tprivate async launchVSCode(options: LaunchLoomOptions): Promise<void> {\n\t\tconst ideConfig = await this.settings?.loadSettings().then((s) => s.ide)\n\t\tawait openIdeWindow(options.worktreePath, ideConfig)\n\t\tgetLogger().info('IDE opened')\n\t}\n\n\t/**\n\t * Launch Claude terminal\n\t */\n\tprivate async launchClaudeTerminal(options: LaunchLoomOptions): Promise<void> {\n\t\tawait this.claudeContext.launchWithContext({\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\ttype: options.workflowType,\n\t\t\tidentifier: options.identifier,\n\t\t\tbranchName: options.branchName,\n\t\t\t...(options.title && { title: options.title }),\n\t\t\t...(options.port !== undefined && { port: options.port }),\n\t\t\toneShot: options.oneShot ?? 'default',\n\t\t\t...(options.setArguments && { setArguments: options.setArguments }),\n\t\t\t...(options.executablePath && { executablePath: options.executablePath }),\n\t\t})\n\t\tgetLogger().info('Claude terminal opened')\n\t}\n\n\t/**\n\t * Launch dev server terminal\n\t */\n\tprivate async launchDevServerTerminal(options: LaunchLoomOptions): Promise<void> {\n\t\tconst devServerCommand = await getDevServerLaunchCommand(\n\t\t\toptions.worktreePath,\n\t\t\toptions.port,\n\t\t\toptions.capabilities\n\t\t)\n\n\t\t// Only generate color if terminal coloring is enabled (default: true)\n\t\tconst backgroundColor = (options.colorTerminal ?? true)\n\t\t\t? options.colorHex\n\t\t\t\t? hexToRgb(options.colorHex)\n\t\t\t\t: generateColorFromBranchName(options.branchName).rgb\n\t\t\t: undefined\n\n\t\tawait openTerminalWindow({\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tcommand: devServerCommand,\n\t\t\t...(backgroundColor && { backgroundColor }),\n\t\t\tincludeEnvSetup: (options.sourceEnvOnStart ?? false) && this.hasAnyEnvFiles(options.worktreePath),\n\t\t\tincludePortExport: options.capabilities.includes('web'),\n\t\t\t...(options.port !== undefined && { port: options.port }),\n\t\t})\n\t\tgetLogger().info('Dev server terminal opened')\n\t}\n\n\t/**\n\t * Launch standalone terminal running `il shell <identifier>`\n\t */\n\tprivate async launchStandaloneTerminal(options: LaunchLoomOptions): Promise<void> {\n\t\t// Build shell command with identifier\n\t\tconst executable = options.executablePath ?? getExecutablePath()\n\t\tconst shellIdentifier = String(options.identifier)\n\t\tconst shellCommand = `${executable} shell ${shellIdentifier}`\n\n\t\t// Only generate color if terminal coloring is enabled (default: true)\n\t\tconst backgroundColor = (options.colorTerminal ?? true)\n\t\t\t? options.colorHex\n\t\t\t\t? hexToRgb(options.colorHex)\n\t\t\t\t: generateColorFromBranchName(options.branchName).rgb\n\t\t\t: undefined\n\n\t\tawait openTerminalWindow({\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tcommand: shellCommand,\n\t\t\t...(backgroundColor && { backgroundColor }),\n\t\t\t// il shell handles env loading internally, so we don't need includeEnvSetup\n\t\t\tincludeEnvSetup: false,\n\t\t\tincludePortExport: options.capabilities.includes('web'),\n\t\t\t...(options.port !== undefined && { port: options.port }),\n\t\t})\n\t\tgetLogger().info('Standalone terminal opened')\n\t}\n\n\t/**\n\t * Build terminal options for Claude\n\t */\n\tprivate async buildClaudeTerminalOptions(\n\t\toptions: LaunchLoomOptions\n\t): Promise<TerminalWindowOptions> {\n\t\tconst hasEnvFile = this.hasAnyEnvFiles(options.worktreePath)\n\t\tconst claudeTitle = `Claude - ${this.formatIdentifier(options.workflowType, options.identifier)}`\n\n\t\tconst executable = options.executablePath ?? 'iloom'\n\t\tlet claudeCommand = `${executable} spin`\n\t\tif (options.oneShot !== undefined && options.oneShot !== 'default') {\n\t\t\tclaudeCommand += ` --one-shot=${options.oneShot}`\n\t\t}\n\t\tif (options.setArguments && options.setArguments.length > 0) {\n\t\t\tfor (const setArg of options.setArguments) {\n\t\t\t\tclaudeCommand += ` --set ${setArg}`\n\t\t\t}\n\t\t}\n\n\t\t// Only generate color if terminal coloring is enabled (default: true)\n\t\tconst backgroundColor = (options.colorTerminal ?? true)\n\t\t\t? options.colorHex\n\t\t\t\t? hexToRgb(options.colorHex)\n\t\t\t\t: generateColorFromBranchName(options.branchName).rgb\n\t\t\t: undefined\n\n\t\treturn {\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tcommand: claudeCommand,\n\t\t\t...(backgroundColor && { backgroundColor }),\n\t\t\ttitle: claudeTitle,\n\t\t\tincludeEnvSetup: (options.sourceEnvOnStart ?? false) && hasEnvFile,\n\t\t\t...(options.port !== undefined && { port: options.port, includePortExport: true }),\n\t\t}\n\t}\n\n\t/**\n\t * Build terminal options for dev server\n\t */\n\tprivate async buildDevServerTerminalOptions(\n\t\toptions: LaunchLoomOptions\n\t): Promise<TerminalWindowOptions> {\n\t\tconst devServerCommand = await getDevServerLaunchCommand(\n\t\t\toptions.worktreePath,\n\t\t\toptions.port,\n\t\t\toptions.capabilities\n\t\t)\n\t\tconst hasEnvFile = this.hasAnyEnvFiles(options.worktreePath)\n\t\tconst devServerTitle = `Dev Server - ${this.formatIdentifier(options.workflowType, options.identifier)}`\n\n\t\t// Only generate color if terminal coloring is enabled (default: true)\n\t\tconst backgroundColor = (options.colorTerminal ?? true)\n\t\t\t? options.colorHex\n\t\t\t\t? hexToRgb(options.colorHex)\n\t\t\t\t: generateColorFromBranchName(options.branchName).rgb\n\t\t\t: undefined\n\n\t\treturn {\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tcommand: devServerCommand,\n\t\t\t...(backgroundColor && { backgroundColor }),\n\t\t\ttitle: devServerTitle,\n\t\t\tincludeEnvSetup: (options.sourceEnvOnStart ?? false) && hasEnvFile,\n\t\t\tincludePortExport: options.capabilities.includes('web'),\n\t\t\t...(options.port !== undefined && { port: options.port }),\n\t\t}\n\t}\n\n\t/**\n\t * Build terminal options for standalone terminal\n\t * Runs `il shell <identifier>` which handles env loading internally\n\t */\n\tprivate buildStandaloneTerminalOptions(\n\t\toptions: LaunchLoomOptions\n\t): TerminalWindowOptions {\n\t\tconst terminalTitle = `Terminal - ${this.formatIdentifier(options.workflowType, options.identifier)}`\n\n\t\t// Build shell command with identifier\n\t\t// Use the same executable path pattern as buildClaudeTerminalOptions\n\t\tconst executable = options.executablePath ?? getExecutablePath()\n\t\tconst shellIdentifier = String(options.identifier)\n\t\tconst shellCommand = `${executable} shell ${shellIdentifier}`\n\n\t\t// Only generate color if terminal coloring is enabled (default: true)\n\t\tconst backgroundColor = (options.colorTerminal ?? true)\n\t\t\t? options.colorHex\n\t\t\t\t? hexToRgb(options.colorHex)\n\t\t\t\t: generateColorFromBranchName(options.branchName).rgb\n\t\t\t: undefined\n\n\t\treturn {\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tcommand: shellCommand,\n\t\t\t...(backgroundColor && { backgroundColor }),\n\t\t\ttitle: terminalTitle,\n\t\t\t// il shell handles env loading internally, so we don't need includeEnvSetup\n\t\t\tincludeEnvSetup: false,\n\t\t\tincludePortExport: options.capabilities.includes('web'),\n\t\t\t...(options.port !== undefined && { port: options.port }),\n\t\t}\n\t}\n\n\t/**\n\t * Launch multiple terminals (2+) as tabs in single window\n\t */\n\tprivate async launchMultipleTerminals(\n\t\tterminals: Array<{ type: string; options: TerminalWindowOptions }>,\n\t\t_options: LaunchLoomOptions\n\t): Promise<void> {\n\t\tconst terminalOptions = terminals.map((t) => t.options)\n\n\t\tawait openMultipleTerminalWindows(terminalOptions)\n\n\t\tconst terminalTypes = terminals.map((t) => t.type).join(' + ')\n\t\tgetLogger().info(`Multiple terminals opened: ${terminalTypes}`)\n\t}\n\n\t/**\n\t * Check if any dotenv-flow files exist in the workspace\n\t * Checks all files: .env, .env.local, .env.{NODE_ENV}, .env.{NODE_ENV}.local\n\t */\n\tprivate hasAnyEnvFiles(workspacePath: string): boolean {\n\t\tconst envFiles = getDotenvFlowFiles()\n\t\treturn envFiles.some(file => existsSync(join(workspacePath, file)))\n\t}\n\n\t/**\n\t * Format identifier for terminal tab titles\n\t */\n\tprivate formatIdentifier(workflowType: 'issue' | 'pr' | 'regular', identifier: string | number): string {\n\t\tif (workflowType === 'issue') {\n\t\t\treturn `Issue #${identifier}`\n\t\t} else if (workflowType === 'pr') {\n\t\t\treturn `PR #${identifier}`\n\t\t} else {\n\t\t\treturn `Branch: ${identifier}`\n\t\t}\n\t}\n}\n","import { execa } from 'execa'\nimport { logger } from './logger.js'\nimport type { IdeSettings } from '../lib/SettingsManager.js'\n\n// IDE preset configuration\nconst IDE_PRESETS = {\n\tvscode: { command: 'code', name: 'Visual Studio Code', args: [] },\n\tcursor: { command: 'cursor', name: 'Cursor', args: [] },\n\twebstorm: { command: 'webstorm', name: 'WebStorm', args: ['--nosplash'] },\n\tsublime: { command: 'subl', name: 'Sublime Text', args: [] },\n\tintellij: { command: 'idea', name: 'IntelliJ IDEA', args: ['--nosplash'] },\n\twindsurf: { command: 'surf', name: 'Windsurf', args: [] },\n\tantigravity: { command: 'agy', name: 'Antigravity', args: [] },\n} as const\n\ntype IdePreset = keyof typeof IDE_PRESETS\n\n// Resolve IDE configuration to command and args\nexport function getIdeConfig(ideSettings?: IdeSettings): {\n\tcommand: string\n\targs: string[]\n\tname: string\n} {\n\t// Default to vscode if not configured\n\tconst type = ideSettings?.type ?? 'vscode'\n\n\tconst preset = IDE_PRESETS[type as IdePreset]\n\treturn {\n\t\tcommand: preset.command,\n\t\targs: [...preset.args],\n\t\tname: preset.name,\n\t}\n}\n\n// Check if IDE is available\nexport async function isIdeAvailable(command: string): Promise<boolean> {\n\ttry {\n\t\tawait execa('command', ['-v', command], { shell: true, timeout: 5000 })\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\n// Get installation hint for IDE\nfunction getInstallHint(type: string): string {\n\tconst hints: Record<string, string> = {\n\t\tvscode:\n\t\t\t'Install command-line tools: Open VSCode > Command Palette > \"Shell Command: Install \\'code\\' command in PATH\"',\n\t\tcursor:\n\t\t\t'Install command-line tools: Open Cursor > Command Palette > \"Install \\'cursor\\' command in PATH\"',\n\t\twebstorm: 'Install via JetBrains Toolbox > Settings > Shell Scripts > Enable',\n\t\tsublime:\n\t\t\t'Create symlink: ln -s \"/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl\" /usr/local/bin/subl',\n\t\tintellij: 'Install via JetBrains Toolbox > Settings > Shell Scripts > Enable',\n\t\twindsurf:\n\t\t\t'Install command-line tools during Windsurf installation or create symlink manually',\n\t\tantigravity:\n\t\t\t'Install command-line tools during Antigravity installation or create symlink manually',\n\t}\n\treturn hints[type] ?? `Ensure the IDE command is available in your PATH`\n}\n\n// Open IDE window for workspace\nexport async function openIdeWindow(\n\tworkspacePath: string,\n\tideSettings?: IdeSettings\n): Promise<void> {\n\tconst config = getIdeConfig(ideSettings)\n\tconst available = await isIdeAvailable(config.command)\n\n\tif (!available) {\n\t\tconst type = ideSettings?.type ?? 'vscode'\n\t\tthrow new Error(\n\t\t\t`${config.name} is not available. The \"${config.command}\" command was not found in PATH.\\n` +\n\t\t\t\tgetInstallHint(type)\n\t\t)\n\t}\n\n\ttry {\n\t\tawait execa(config.command, [...config.args, workspacePath])\n\t\tlogger.debug(`Opened ${config.name} for workspace: ${workspacePath}`)\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to open ${config.name}: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t)\n\t}\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ PromptTemplateManager
4
+ } from "./chunk-74VMN2KC.js";
5
+ import "./chunk-UYVWLISQ.js";
6
+ export {
7
+ PromptTemplateManager
8
+ };
9
+ //# sourceMappingURL=PromptTemplateManager-2TDZAUC6.js.map
package/dist/README.md CHANGED
@@ -51,7 +51,9 @@ iloom stops the "Context Window Tetris." It treats context as a first-class conc
51
51
  * **Scale Understanding:** Because every loom holds its own isolated environment (Git worktree, DB branch, local server), you can switch between 5 complex features without losing your place or your AI's context.
52
52
 
53
53
  * **Visible Reasoning:** The AI's decisions are documented publicly. Your team sees the plan, and "future you" knows exactly why a decision was made.
54
-
54
+
55
+ * **Automatic Session Summaries:** When you finish a loom, iloom captures key insights, decisions, and lessons learned from your Claude session and posts them to the issue. These summaries become institutional knowledge that informs future tasks.
56
+
55
57
 
56
58
  _iloom is not just a tool for managing git worktrees - it's a control plane for maintaining alignment between you and your AI assistant._
57
59
 
@@ -73,8 +75,8 @@ iloom uses your existing Claude subscription to build a shared mental model of y
73
75
 
74
76
  # ... You, the iloom agents and Claude build the feature together in the isolated environment ...
75
77
 
76
- # 4. Finish & Merge # Validates code (test/lint), handles merge conflicts, and cleans up the worktree/DB.
77
- il finish
78
+ # 4. Finish & Merge # Validates code, generates session summary, merges, and cleans up.
79
+ il finish
78
80
  ```
79
81
 
80
82
  **The iloom Difference:** il start doesn't just create a branch. It launches a multi-agent workflow that surfaces assumptions and creates a structured plan in your issue tracker **before you even need to look at your IDE.**
@@ -138,8 +140,10 @@ Command Reference
138
140
  | `il finish` | `dn` | Validate tests/lint, commit, handle conflicts, and merge/PR. |
139
141
  | `il cleanup` | `remove` | Safely remove a loom and its database branch without merging. |
140
142
  | `il list` | | Show active looms and paths. |
143
+ | `il projects` | | List configured projects (JSON output). |
141
144
  | `il spin` | | Launch Claude inside the current loom with context auto-detected. |
142
145
  | `il open` | `run` | Open loom in browser (web) or run your CLI tool. |
146
+ | `il dev-server` | `dev` | Start dev server in foreground for a workspace. |
143
147
  | `il add-issue` | `a` | Create and AI-enhance a new issue without starting work yet. |
144
148
  | `il init` | `config` | Interactive configuration wizard. |
145
149
  | `il feedback` | `f` | Submit bug reports/feedback directly from the CLI. |
@@ -218,6 +222,12 @@ This example shows how to configure a project-wide default (e.g., GitHub remote)
218
222
  "issue": {
219
223
  "permissionMode": "acceptEdits" // Control Claude Code permissions
220
224
  }
225
+ },
226
+ "spin": {
227
+ "model": "opus" // Claude model for spin orchestrator: opus (default), sonnet, or haiku
228
+ },
229
+ "summary": {
230
+ "model": "sonnet" // Claude model for session summaries: sonnet (default), opus, or haiku
221
231
  }
222
232
  }
223
233
  ```
@@ -8,12 +8,14 @@ import {
8
8
  IloomSettingsSchemaNoDefaults,
9
9
  NeonSettingsSchema,
10
10
  SettingsManager,
11
+ SpinAgentSettingsSchema,
12
+ SummarySettingsSchema,
11
13
  WorkflowPermissionSchema,
12
14
  WorkflowPermissionSchemaNoDefaults,
13
15
  WorkflowsSettingsSchema,
14
16
  WorkflowsSettingsSchemaNoDefaults
15
- } from "./chunk-CDZERT7Z.js";
16
- import "./chunk-GEHQXLEI.js";
17
+ } from "./chunk-VWNS6DH5.js";
18
+ import "./chunk-UYVWLISQ.js";
17
19
  export {
18
20
  AgentSettingsSchema,
19
21
  CapabilitiesSettingsSchema,
@@ -23,9 +25,11 @@ export {
23
25
  IloomSettingsSchemaNoDefaults,
24
26
  NeonSettingsSchema,
25
27
  SettingsManager,
28
+ SpinAgentSettingsSchema,
29
+ SummarySettingsSchema,
26
30
  WorkflowPermissionSchema,
27
31
  WorkflowPermissionSchemaNoDefaults,
28
32
  WorkflowsSettingsSchema,
29
33
  WorkflowsSettingsSchemaNoDefaults
30
34
  };
31
- //# sourceMappingURL=SettingsManager-I2LRCW2A.js.map
35
+ //# sourceMappingURL=SettingsManager-FJFU6JJD.js.map
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ SettingsMigrationManager
4
+ } from "./chunk-UYWAESOT.js";
5
+ import "./chunk-SJ2GZ6RF.js";
6
+ import "./chunk-UYVWLISQ.js";
7
+ export {
8
+ SettingsMigrationManager
9
+ };
10
+ //# sourceMappingURL=SettingsMigrationManager-EH3J2TCN.js.map
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ MetadataManager
4
+ } from "./chunk-IJ7IGJT3.js";
2
5
  import {
3
6
  SettingsManager
4
- } from "./chunk-CDZERT7Z.js";
7
+ } from "./chunk-VWNS6DH5.js";
5
8
  import {
6
9
  logger
7
- } from "./chunk-GEHQXLEI.js";
10
+ } from "./chunk-UYVWLISQ.js";
8
11
 
9
12
  // src/utils/git.ts
10
13
  import path from "path";
@@ -16,7 +19,9 @@ async function executeGitCommand(args, options) {
16
19
  timeout: (options == null ? void 0 : options.timeout) ?? 3e4,
17
20
  encoding: "utf8",
18
21
  stdio: (options == null ? void 0 : options.stdio) ?? "pipe",
19
- verbose: logger.isDebugEnabled()
22
+ verbose: logger.isDebugEnabled(),
23
+ // Spread env conditionally - only include if defined
24
+ ...(options == null ? void 0 : options.env) && { env: options.env }
20
25
  });
21
26
  return result.stdout;
22
27
  } catch (error) {
@@ -304,6 +309,27 @@ async function findMainWorktreePathWithSettings(path2, settingsManager) {
304
309
  const findOptions = settings.mainBranch ? { mainBranch: settings.mainBranch } : void 0;
305
310
  return findMainWorktreePath(path2, findOptions);
306
311
  }
312
+ async function findWorktreeForBranch(branchName, path2 = process.cwd()) {
313
+ try {
314
+ const output = await executeGitCommand(["worktree", "list", "--porcelain"], { cwd: path2 });
315
+ const worktrees = parseWorktreeList(output, branchName);
316
+ if (worktrees.length === 0) {
317
+ throw new Error("No worktrees found in repository");
318
+ }
319
+ const targetWorktree = worktrees.find((wt) => wt.branch === branchName);
320
+ if (!(targetWorktree == null ? void 0 : targetWorktree.path)) {
321
+ throw new Error(
322
+ `No worktree found with branch '${branchName}' checked out. Available worktrees: ${worktrees.map((wt) => `${wt.path} (${wt.branch})`).join(", ")}`
323
+ );
324
+ }
325
+ return targetWorktree.path;
326
+ } catch (error) {
327
+ if (error instanceof Error && (error.message.includes("No worktree found with branch") || error.message.includes("No worktrees found"))) {
328
+ throw error;
329
+ }
330
+ throw new Error(`Failed to find worktree for branch '${branchName}': ${error instanceof Error ? error.message : String(error)}`);
331
+ }
332
+ }
307
333
  async function hasUncommittedChanges(path2 = process.cwd()) {
308
334
  try {
309
335
  const result = await executeGitCommand(["status", "--porcelain"], { cwd: path2 });
@@ -332,7 +358,7 @@ async function getDefaultBranch(path2 = process.cwd()) {
332
358
  }
333
359
  async function findAllBranchesForIssue(issueNumber, path2 = process.cwd(), settingsManager) {
334
360
  if (!settingsManager) {
335
- const { SettingsManager: SM } = await import("./SettingsManager-I2LRCW2A.js");
361
+ const { SettingsManager: SM } = await import("./SettingsManager-FJFU6JJD.js");
336
362
  settingsManager = new SM();
337
363
  }
338
364
  const protectedBranches = await settingsManager.getProtectedBranches(path2);
@@ -472,6 +498,122 @@ async function isFileGitignored(filePath, cwd = process.cwd()) {
472
498
  return false;
473
499
  }
474
500
  }
501
+ async function isBranchMergedIntoMain(branchName, mainBranch = "main", cwd = process.cwd()) {
502
+ try {
503
+ await executeGitCommand(["merge-base", "--is-ancestor", branchName, mainBranch], { cwd });
504
+ return true;
505
+ } catch {
506
+ return false;
507
+ }
508
+ }
509
+ async function isRemoteBranchUpToDate(branchName, cwd) {
510
+ try {
511
+ const remoteResult = await executeGitCommand(["ls-remote", "--heads", "origin", branchName], { cwd });
512
+ if (remoteResult.trim().length === 0) {
513
+ return false;
514
+ }
515
+ const remoteCommit = remoteResult.trim().split(" ")[0];
516
+ const localCommit = await executeGitCommand(["rev-parse", branchName], { cwd });
517
+ return localCommit.trim() === remoteCommit;
518
+ } catch {
519
+ return false;
520
+ }
521
+ }
522
+ async function checkRemoteBranchStatus(branchName, cwd) {
523
+ try {
524
+ try {
525
+ await executeGitCommand(["fetch", "origin", branchName], { cwd, timeout: 3e4 });
526
+ } catch (fetchError) {
527
+ const fetchErrorMessage = fetchError instanceof Error ? fetchError.message : String(fetchError);
528
+ if (fetchErrorMessage.includes("Could not resolve host") || fetchErrorMessage.includes("unable to access") || fetchErrorMessage.includes("network") || fetchErrorMessage.includes("Connection refused") || fetchErrorMessage.includes("Connection timed out")) {
529
+ return {
530
+ exists: false,
531
+ remoteAhead: false,
532
+ localAhead: false,
533
+ networkError: true,
534
+ errorMessage: fetchErrorMessage
535
+ };
536
+ }
537
+ }
538
+ const remoteResult = await executeGitCommand(["ls-remote", "--heads", "origin", branchName], { cwd });
539
+ if (remoteResult.trim().length === 0) {
540
+ return {
541
+ exists: false,
542
+ remoteAhead: false,
543
+ localAhead: false,
544
+ networkError: false
545
+ };
546
+ }
547
+ const remoteCommit = remoteResult.trim().split(" ")[0];
548
+ if (!remoteCommit) {
549
+ return {
550
+ exists: false,
551
+ remoteAhead: false,
552
+ localAhead: false,
553
+ networkError: false
554
+ };
555
+ }
556
+ const localCommit = await executeGitCommand(["rev-parse", branchName], { cwd });
557
+ const localCommitTrimmed = localCommit.trim();
558
+ if (remoteCommit === localCommitTrimmed) {
559
+ return {
560
+ exists: true,
561
+ remoteAhead: false,
562
+ localAhead: false,
563
+ networkError: false
564
+ };
565
+ }
566
+ try {
567
+ await executeGitCommand(["merge-base", "--is-ancestor", localCommitTrimmed, remoteCommit], { cwd });
568
+ return {
569
+ exists: true,
570
+ remoteAhead: true,
571
+ localAhead: false,
572
+ networkError: false
573
+ };
574
+ } catch {
575
+ return {
576
+ exists: true,
577
+ remoteAhead: false,
578
+ localAhead: true,
579
+ networkError: false
580
+ };
581
+ }
582
+ } catch (error) {
583
+ const errorMessage = error instanceof Error ? error.message : String(error);
584
+ if (errorMessage.includes("Could not resolve host") || errorMessage.includes("unable to access") || errorMessage.includes("network") || errorMessage.includes("Connection refused") || errorMessage.includes("Connection timed out")) {
585
+ return {
586
+ exists: false,
587
+ remoteAhead: false,
588
+ localAhead: false,
589
+ networkError: true,
590
+ errorMessage
591
+ };
592
+ }
593
+ return {
594
+ exists: false,
595
+ remoteAhead: false,
596
+ localAhead: false,
597
+ networkError: false
598
+ };
599
+ }
600
+ }
601
+ async function getMergeTargetBranch(worktreePath = process.cwd(), options) {
602
+ var _a;
603
+ const settingsManager = (options == null ? void 0 : options.settingsManager) ?? new SettingsManager();
604
+ const metadataManager = (options == null ? void 0 : options.metadataManager) ?? new MetadataManager();
605
+ logger.debug(`Checking for parent loom metadata at: ${worktreePath}`);
606
+ const metadata = await metadataManager.readMetadata(worktreePath);
607
+ if ((_a = metadata == null ? void 0 : metadata.parentLoom) == null ? void 0 : _a.branchName) {
608
+ logger.debug(`Using parent branch as merge target: ${metadata.parentLoom.branchName}`);
609
+ return metadata.parentLoom.branchName;
610
+ }
611
+ logger.debug("No parent loom metadata found, falling back to settings");
612
+ const settings = await settingsManager.loadSettings(worktreePath);
613
+ const mainBranch = settings.mainBranch ?? "main";
614
+ logger.debug(`Using configured main branch as merge target: ${mainBranch}`);
615
+ return mainBranch;
616
+ }
475
617
 
476
618
  export {
477
619
  executeGitCommand,
@@ -488,6 +630,7 @@ export {
488
630
  getRepoRoot,
489
631
  findMainWorktreePath,
490
632
  findMainWorktreePathWithSettings,
633
+ findWorktreeForBranch,
491
634
  hasUncommittedChanges,
492
635
  getDefaultBranch,
493
636
  findAllBranchesForIssue,
@@ -495,6 +638,10 @@ export {
495
638
  ensureRepositoryHasCommits,
496
639
  pushBranchToRemote,
497
640
  isFileTrackedByGit,
498
- isFileGitignored
641
+ isFileGitignored,
642
+ isBranchMergedIntoMain,
643
+ isRemoteBranchUpToDate,
644
+ checkRemoteBranchStatus,
645
+ getMergeTargetBranch
499
646
  };
500
- //# sourceMappingURL=chunk-5Q3NDNNV.js.map
647
+ //# sourceMappingURL=chunk-2W2FBL5G.js.map