@iloom/cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +274 -30
  2. package/dist/BranchNamingService-3OQPRSWT.js +13 -0
  3. package/dist/ClaudeContextManager-MUQSDY2E.js +13 -0
  4. package/dist/ClaudeService-HG4VQ7AW.js +12 -0
  5. package/dist/GitHubService-EBOETDIW.js +11 -0
  6. package/dist/{LoomLauncher-CTSWJL35.js → LoomLauncher-FLEMBCSQ.js} +63 -32
  7. package/dist/LoomLauncher-FLEMBCSQ.js.map +1 -0
  8. package/dist/ProjectCapabilityDetector-34LU7JJ4.js +9 -0
  9. package/dist/{PromptTemplateManager-WII75TKH.js → PromptTemplateManager-A52RUAMS.js} +2 -2
  10. package/dist/README.md +274 -30
  11. package/dist/{SettingsManager-XOYCLH3D.js → SettingsManager-WHHFGSL7.js} +12 -4
  12. package/dist/SettingsMigrationManager-AGIIIPDQ.js +10 -0
  13. package/dist/agents/iloom-issue-analyze-and-plan.md +125 -35
  14. package/dist/agents/iloom-issue-analyzer.md +284 -32
  15. package/dist/agents/iloom-issue-complexity-evaluator.md +40 -21
  16. package/dist/agents/iloom-issue-enhancer.md +69 -48
  17. package/dist/agents/iloom-issue-implementer.md +36 -25
  18. package/dist/agents/iloom-issue-planner.md +35 -24
  19. package/dist/agents/iloom-issue-reviewer.md +62 -9
  20. package/dist/chunk-3KATJIKO.js +55 -0
  21. package/dist/chunk-3KATJIKO.js.map +1 -0
  22. package/dist/{chunk-SWCRXDZC.js → chunk-3RUPPQRG.js} +1 -18
  23. package/dist/chunk-3RUPPQRG.js.map +1 -0
  24. package/dist/{chunk-RF2YI2XJ.js → chunk-47KSHUCR.js} +3 -3
  25. package/dist/chunk-47KSHUCR.js.map +1 -0
  26. package/dist/{chunk-VETG35MF.js → chunk-4HHRTA7Q.js} +3 -3
  27. package/dist/{chunk-VETG35MF.js.map → chunk-4HHRTA7Q.js.map} +1 -1
  28. package/dist/chunk-5EF7Z346.js +1987 -0
  29. package/dist/chunk-5EF7Z346.js.map +1 -0
  30. package/dist/{chunk-4IV6W4U5.js → chunk-AWOFAD5O.js} +12 -12
  31. package/dist/chunk-AWOFAD5O.js.map +1 -0
  32. package/dist/{chunk-2PLUQT6J.js → chunk-C5QCTEQK.js} +2 -2
  33. package/dist/{chunk-CWR2SANQ.js → chunk-EBISESAP.js} +1 -1
  34. package/dist/{chunk-LHP6ROUM.js → chunk-FIAT22G7.js} +4 -16
  35. package/dist/chunk-FIAT22G7.js.map +1 -0
  36. package/dist/{chunk-TS6DL67T.js → chunk-G2IEYOLQ.js} +11 -38
  37. package/dist/chunk-G2IEYOLQ.js.map +1 -0
  38. package/dist/{chunk-ZMNQBJUI.js → chunk-IP7SMKIF.js} +61 -22
  39. package/dist/chunk-IP7SMKIF.js.map +1 -0
  40. package/dist/{chunk-JNKJ7NJV.js → chunk-JKXJ7BGL.js} +6 -2
  41. package/dist/{chunk-JNKJ7NJV.js.map → chunk-JKXJ7BGL.js.map} +1 -1
  42. package/dist/{chunk-LAPY6NAE.js → chunk-JQFO7QQN.js} +68 -12
  43. package/dist/{chunk-LAPY6NAE.js.map → chunk-JQFO7QQN.js.map} +1 -1
  44. package/dist/{SettingsMigrationManager-MTQIMI54.js → chunk-KLBYVHPK.js} +3 -2
  45. package/dist/{chunk-HBVFXN7R.js → chunk-MAVL6PJF.js} +26 -3
  46. package/dist/chunk-MAVL6PJF.js.map +1 -0
  47. package/dist/{chunk-USVVV3FP.js → chunk-MKWYLDFK.js} +5 -5
  48. package/dist/chunk-ML3NRPNB.js +396 -0
  49. package/dist/chunk-ML3NRPNB.js.map +1 -0
  50. package/dist/{chunk-DJUGYNQE.js → chunk-PA6Q6AWM.js} +16 -3
  51. package/dist/chunk-PA6Q6AWM.js.map +1 -0
  52. package/dist/chunk-RO26VS3W.js +444 -0
  53. package/dist/chunk-RO26VS3W.js.map +1 -0
  54. package/dist/{chunk-6LEQW46Y.js → chunk-VAYCCUXW.js} +72 -2
  55. package/dist/{chunk-6LEQW46Y.js.map → chunk-VAYCCUXW.js.map} +1 -1
  56. package/dist/{chunk-SPYPLHMK.js → chunk-VU3QMIP2.js} +34 -2
  57. package/dist/chunk-VU3QMIP2.js.map +1 -0
  58. package/dist/{chunk-PVAVNJKS.js → chunk-WEN5C5DM.js} +10 -1
  59. package/dist/chunk-WEN5C5DM.js.map +1 -0
  60. package/dist/{chunk-MFU53H6J.js → chunk-XXV3UFZL.js} +3 -3
  61. package/dist/{chunk-MFU53H6J.js.map → chunk-XXV3UFZL.js.map} +1 -1
  62. package/dist/{chunk-GZP4UGGM.js → chunk-ZM3CFL5L.js} +2 -2
  63. package/dist/{chunk-BLCTGFZN.js → chunk-ZT3YZB4K.js} +3 -4
  64. package/dist/chunk-ZT3YZB4K.js.map +1 -0
  65. package/dist/{claude-ZIWDG4XG.js → claude-GOP6PFC7.js} +2 -2
  66. package/dist/{cleanup-FEIVZSIV.js → cleanup-7RWLBSLE.js} +86 -25
  67. package/dist/cleanup-7RWLBSLE.js.map +1 -0
  68. package/dist/cli.js +2511 -62
  69. package/dist/cli.js.map +1 -1
  70. package/dist/{contribute-EMZKCAC6.js → contribute-BS2L4FZR.js} +6 -6
  71. package/dist/{feedback-LFNMQBAZ.js → feedback-N4ECWIPF.js} +15 -14
  72. package/dist/{feedback-LFNMQBAZ.js.map → feedback-N4ECWIPF.js.map} +1 -1
  73. package/dist/{git-WC6HZLOT.js → git-TDXKRTXM.js} +4 -2
  74. package/dist/{ignite-MQWVJEAB.js → ignite-VM64QO3J.js} +32 -27
  75. package/dist/ignite-VM64QO3J.js.map +1 -0
  76. package/dist/index.d.ts +359 -45
  77. package/dist/index.js +1266 -502
  78. package/dist/index.js.map +1 -1
  79. package/dist/{init-GJDYN2IK.js → init-G3T64SC4.js} +104 -40
  80. package/dist/init-G3T64SC4.js.map +1 -0
  81. package/dist/mcp/issue-management-server.js +934 -0
  82. package/dist/mcp/issue-management-server.js.map +1 -0
  83. package/dist/{neon-helpers-ZVIRPKCI.js → neon-helpers-WPUACUVC.js} +3 -3
  84. package/dist/neon-helpers-WPUACUVC.js.map +1 -0
  85. package/dist/{open-NXSN7XOC.js → open-KXDXEKRZ.js} +39 -36
  86. package/dist/open-KXDXEKRZ.js.map +1 -0
  87. package/dist/{prompt-ANTQWHUF.js → prompt-7INJ7YRU.js} +4 -2
  88. package/dist/prompt-7INJ7YRU.js.map +1 -0
  89. package/dist/prompts/init-prompt.txt +538 -95
  90. package/dist/prompts/issue-prompt.txt +27 -27
  91. package/dist/{rebase-DUNFOJVS.js → rebase-Q7GMM7EI.js} +6 -6
  92. package/dist/{remote-ZCXJVVNW.js → remote-VUNCQZ6J.js} +3 -2
  93. package/dist/remote-VUNCQZ6J.js.map +1 -0
  94. package/dist/{run-O7ZK7CKA.js → run-PAWJJCSX.js} +39 -36
  95. package/dist/run-PAWJJCSX.js.map +1 -0
  96. package/dist/schema/settings.schema.json +56 -0
  97. package/dist/{test-git-T76HOTIA.js → test-git-3WDLNQCA.js} +3 -3
  98. package/dist/{test-prefix-6HJUVQMH.js → test-prefix-EVGAWAJW.js} +3 -3
  99. package/dist/{test-webserver-M2I3EV4J.js → test-webserver-DAHONWCS.js} +4 -4
  100. package/dist/test-webserver-DAHONWCS.js.map +1 -0
  101. package/package.json +2 -1
  102. package/dist/ClaudeContextManager-LVCYRM6Q.js +0 -13
  103. package/dist/ClaudeService-WVTWB3DK.js +0 -12
  104. package/dist/GitHubService-7E2S5NNZ.js +0 -11
  105. package/dist/LoomLauncher-CTSWJL35.js.map +0 -1
  106. package/dist/add-issue-OBI325W7.js +0 -69
  107. package/dist/add-issue-OBI325W7.js.map +0 -1
  108. package/dist/chunk-4IV6W4U5.js.map +0 -1
  109. package/dist/chunk-BLCTGFZN.js.map +0 -1
  110. package/dist/chunk-CVLAZRNB.js +0 -54
  111. package/dist/chunk-CVLAZRNB.js.map +0 -1
  112. package/dist/chunk-DJUGYNQE.js.map +0 -1
  113. package/dist/chunk-H4E4THUZ.js +0 -55
  114. package/dist/chunk-H4E4THUZ.js.map +0 -1
  115. package/dist/chunk-H5LDRGVK.js +0 -642
  116. package/dist/chunk-H5LDRGVK.js.map +0 -1
  117. package/dist/chunk-HBVFXN7R.js.map +0 -1
  118. package/dist/chunk-LHP6ROUM.js.map +0 -1
  119. package/dist/chunk-PVAVNJKS.js.map +0 -1
  120. package/dist/chunk-RF2YI2XJ.js.map +0 -1
  121. package/dist/chunk-SPYPLHMK.js.map +0 -1
  122. package/dist/chunk-SWCRXDZC.js.map +0 -1
  123. package/dist/chunk-SYOSCMIT.js +0 -545
  124. package/dist/chunk-SYOSCMIT.js.map +0 -1
  125. package/dist/chunk-T3KEIB4D.js +0 -243
  126. package/dist/chunk-T3KEIB4D.js.map +0 -1
  127. package/dist/chunk-TS6DL67T.js.map +0 -1
  128. package/dist/chunk-ZMNQBJUI.js.map +0 -1
  129. package/dist/cleanup-FEIVZSIV.js.map +0 -1
  130. package/dist/enhance-MNA4ZGXW.js +0 -176
  131. package/dist/enhance-MNA4ZGXW.js.map +0 -1
  132. package/dist/finish-TX5CJICB.js +0 -1749
  133. package/dist/finish-TX5CJICB.js.map +0 -1
  134. package/dist/ignite-MQWVJEAB.js.map +0 -1
  135. package/dist/init-GJDYN2IK.js.map +0 -1
  136. package/dist/mcp/chunk-6SDFJ42P.js +0 -62
  137. package/dist/mcp/chunk-6SDFJ42P.js.map +0 -1
  138. package/dist/mcp/claude-NDFOCQQQ.js +0 -249
  139. package/dist/mcp/claude-NDFOCQQQ.js.map +0 -1
  140. package/dist/mcp/color-QS5BFCNN.js +0 -168
  141. package/dist/mcp/color-QS5BFCNN.js.map +0 -1
  142. package/dist/mcp/github-comment-server.js +0 -168
  143. package/dist/mcp/github-comment-server.js.map +0 -1
  144. package/dist/mcp/terminal-OMNRFWB3.js +0 -227
  145. package/dist/mcp/terminal-OMNRFWB3.js.map +0 -1
  146. package/dist/open-NXSN7XOC.js.map +0 -1
  147. package/dist/run-O7ZK7CKA.js.map +0 -1
  148. package/dist/start-73I5W7WW.js +0 -983
  149. package/dist/start-73I5W7WW.js.map +0 -1
  150. package/dist/test-webserver-M2I3EV4J.js.map +0 -1
  151. /package/dist/{ClaudeContextManager-LVCYRM6Q.js.map → BranchNamingService-3OQPRSWT.js.map} +0 -0
  152. /package/dist/{ClaudeService-WVTWB3DK.js.map → ClaudeContextManager-MUQSDY2E.js.map} +0 -0
  153. /package/dist/{GitHubService-7E2S5NNZ.js.map → ClaudeService-HG4VQ7AW.js.map} +0 -0
  154. /package/dist/{PromptTemplateManager-WII75TKH.js.map → GitHubService-EBOETDIW.js.map} +0 -0
  155. /package/dist/{SettingsManager-XOYCLH3D.js.map → ProjectCapabilityDetector-34LU7JJ4.js.map} +0 -0
  156. /package/dist/{claude-ZIWDG4XG.js.map → PromptTemplateManager-A52RUAMS.js.map} +0 -0
  157. /package/dist/{git-WC6HZLOT.js.map → SettingsManager-WHHFGSL7.js.map} +0 -0
  158. /package/dist/{neon-helpers-ZVIRPKCI.js.map → SettingsMigrationManager-AGIIIPDQ.js.map} +0 -0
  159. /package/dist/{chunk-2PLUQT6J.js.map → chunk-C5QCTEQK.js.map} +0 -0
  160. /package/dist/{chunk-CWR2SANQ.js.map → chunk-EBISESAP.js.map} +0 -0
  161. /package/dist/{SettingsMigrationManager-MTQIMI54.js.map → chunk-KLBYVHPK.js.map} +0 -0
  162. /package/dist/{chunk-USVVV3FP.js.map → chunk-MKWYLDFK.js.map} +0 -0
  163. /package/dist/{chunk-GZP4UGGM.js.map → chunk-ZM3CFL5L.js.map} +0 -0
  164. /package/dist/{prompt-ANTQWHUF.js.map → claude-GOP6PFC7.js.map} +0 -0
  165. /package/dist/{contribute-EMZKCAC6.js.map → contribute-BS2L4FZR.js.map} +0 -0
  166. /package/dist/{remote-ZCXJVVNW.js.map → git-TDXKRTXM.js.map} +0 -0
  167. /package/dist/{rebase-DUNFOJVS.js.map → rebase-Q7GMM7EI.js.map} +0 -0
  168. /package/dist/{test-git-T76HOTIA.js.map → test-git-3WDLNQCA.js.map} +0 -0
  169. /package/dist/{test-prefix-6HJUVQMH.js.map → test-prefix-EVGAWAJW.js.map} +0 -0
package/README.md CHANGED
@@ -10,13 +10,12 @@
10
10
  </div>
11
11
 
12
12
  <div align="center">
13
- <img width="327" height="328" alt="iloom-ai-logo" src="https://raw.githubusercontent.com/iloom-ai/iloom-cli/main/assets/iloom-logo.png" />
14
- <div>Scale understanding, not just output.</div>
15
-
13
+ <img width="600" alt="iloom-ai-screenshot" src="https://raw.githubusercontent.com/iloom-ai/iloom-cli/main/assets/iloom-screenshot.png" />
14
+ <div>iloom in action: Scale understanding, not just output.</div>
16
15
  </div>
17
16
 
18
17
  #### Links to key sections
19
- [How It Works](#how-it-works) • [Installation](#installation) • [Commands](#commands) • [Feedback](#providing-feedback) • [Limitations](#platform--integration-support) • [Configuration](#configuration)
18
+ [How It Works](#how-it-works) • [Installation](#installation) • [Commands](#commands) • [Nested Looms](#child-looms-nested-looms) • [Limitations](#platform--integration-support) • [Configuration](#configuration) • [Feedback](#providing-feedback)
20
19
 
21
20
 
22
21
  ## Built For Modern Tools...
@@ -313,6 +312,8 @@ iloom start <issue-number | pr-number | issue-description | branch-name>
313
312
  # default: Standard behavior with prompts
314
313
  # noReview: Skip phase approval prompts
315
314
  # bypassPermissions: Full automation, skip all permission prompts. Be careful!
315
+ # --child-loom - Force create as child loom (skip prompt, requires parent loom)
316
+ # --no-child-loom - Force create as independent loom (skip prompt)
316
317
 
317
318
  iloom finish
318
319
  # AI assisted validation, commit, merge steps, as well as loom cleanup (run this from the loom directory)
@@ -362,6 +363,100 @@ iloom enhance <issue-number>
362
363
  # Expands requirements, asks clarifying questions and adds implementation context
363
364
  ```
364
365
 
366
+ ## Child Looms (Nested Looms)
367
+
368
+ Child looms let you create isolated workspaces from within an existing loom. This is useful when you need to work on a subtask, bug fix, or experiment while keeping your parent work intact.
369
+
370
+ ### When to Use Child Looms
371
+
372
+ - **Break down complex issues**: Large features can spawn smaller issues that become child looms
373
+ - **Fix bugs discovered during work**: Create a child loom to fix a bug without mixing commits
374
+ - **Experiment safely**: Try different approaches in child looms without affecting parent work
375
+ - **Handle interrupts**: Start urgent work from your current context without losing it
376
+
377
+ ### How Child Looms Work
378
+
379
+ When you run `il start` from inside an existing loom, iloom detects the parent context and prompts you:
380
+
381
+ ```bash
382
+ # Inside a loom working on issue #25
383
+ > il start 42
384
+ ? Create as child loom of issue #25? (Y/n)
385
+ ```
386
+
387
+ **Automatic inheritance:**
388
+ - **Database branch**: Child looms branch from the parent's database state, not the main branch
389
+ - **Base branch**: Git branch is created from the parent's branch
390
+ - **Main branch config**: Child's `mainBranch` setting points to parent branch (for `il finish`)
391
+
392
+ ### CLI Flags
393
+
394
+ Skip the prompt with explicit flags:
395
+
396
+ ```bash
397
+ # Force child loom creation (no prompt)
398
+ il start 42 --child-loom
399
+
400
+ # Force independent loom (no prompt)
401
+ il start 42 --no-child-loom
402
+ ```
403
+
404
+ The `--child-loom` flag is ignored when not running from inside a loom.
405
+
406
+ ### Directory Structure
407
+
408
+ Child looms are created in a dedicated subdirectory based on the parent branch name:
409
+
410
+ ```
411
+ ~/project-looms/
412
+ ├── feat-issue-25-auth-refactor/ # Parent loom
413
+ ├── feat-issue-25-auth-refactor-looms/ # Child looms directory
414
+ │ ├── fix-issue-42-token-validation/ # Child loom 1
415
+ │ └── feat-issue-43-oauth-support/ # Child loom 2
416
+ ```
417
+
418
+ ### Finishing Child Looms
419
+
420
+ When finishing a parent loom, iloom warns about existing child looms:
421
+
422
+ ```bash
423
+ > il finish
424
+ ⚠ Found 2 child loom(s) that should be cleaned up first:
425
+ - ~/project-looms/feat-issue-25-auth-refactor-looms/fix-issue-42-token-validation
426
+ - ~/project-looms/feat-issue-25-auth-refactor-looms/feat-issue-43-oauth-support
427
+
428
+ To clean up child looms:
429
+ il cleanup 42
430
+ il cleanup 43
431
+ ```
432
+
433
+ Child looms should typically be finished or cleaned up before finishing the parent.
434
+
435
+ ### Example Workflow
436
+
437
+ ```bash
438
+ # Start working on a feature
439
+ > il start 25
440
+ # ... working on authentication refactor
441
+
442
+ # Discover a bug that needs immediate attention
443
+ > il start 42
444
+ ? Create as child loom of issue #25? Y
445
+ # Creates child loom with parent's database state
446
+
447
+ # Fix the bug in isolation
448
+ > cd ~/project-looms/feat-issue-25-auth-refactor-looms/fix-issue-42-...
449
+
450
+ # Finish the child work (merges to parent branch, not main)
451
+ > il finish
452
+
453
+ # Return to parent loom
454
+ > cd ~/project-looms/feat-issue-25-auth-refactor
455
+
456
+ # Continue feature work, then finish
457
+ > il finish
458
+ ```
459
+
365
460
  ## Providing Feedback
366
461
 
367
462
  Found a bug, have a feature request, or want to contribute ideas to improve iloom CLI? Submit feedback directly from your terminal.
@@ -391,19 +486,6 @@ Your feedback helps make iloom better for everyone! Issues created through `iloo
391
486
  ### Maintenance
392
487
 
393
488
  ```bash
394
- iloom init
395
- # Interactive Claude-powered configuration wizard
396
- # Sets up settings.json, .gitignore, and guides you through all configuration options
397
- # Automatically detects multi-remote setups and helps you configure GitHub integration
398
- # Alias: il config
399
- # Run this once per project
400
-
401
- iloom contribute
402
- # Set up local development environment for contributing to iloom
403
- # Automatically forks the repository, clones it locally, configures upstream remote,
404
- # and runs il init to complete setup
405
- # Streamlines contributor onboarding with a single command
406
-
407
489
  iloom update
408
490
  # Update iloom-cli to the latest version
409
491
  ```
@@ -417,7 +499,7 @@ The recommended way to configure iloom:
417
499
  ```bash
418
500
  iloom init
419
501
  # or
420
- il config
502
+ iloom config
421
503
  ```
422
504
 
423
505
  This Claude-powered assistant will guide you through all configuration options and automatically:
@@ -437,14 +519,18 @@ If you prefer manual configuration, iloom uses these files (highest to lowest pr
437
519
  1. **CLI arguments** - Command-line flags (e.g., `--one-shot bypassPermissions`)
438
520
  2. **`.iloom/settings.local.json`** - Local machine settings (gitignored, not committed)
439
521
  3. **`.iloom/settings.json`** - Project-wide settings (committed to repository)
440
- 4. **Built-in defaults** - Hardcoded fallback values
522
+ 4. **`~/.config/iloom-ai/settings.json`** - Global user settings (applies to all projects)
523
+ 5. **Built-in defaults** - Hardcoded fallback values
441
524
 
442
- This allows teams to share project defaults via `settings.json` while individual developers maintain personal overrides in `settings.local.json`.
525
+ This allows teams to share project defaults via `settings.json` while individual developers maintain personal overrides in `settings.local.json` or global preferences in `~/.config/iloom-ai/settings.json`.
443
526
 
444
527
  **Example Use Cases:**
445
- - Developer needs different `basePort` due to port conflicts
446
- - Local database connection strings that differ from team defaults
447
- - Personal preferences for `permissionMode` or component launch flags
528
+ - **Global settings**: Default agent models or workflow permission modes that apply to all your projects
529
+ - **Project settings**: Team defaults like `mainBranch`, database configuration, GitHub remote
530
+ - **Local settings**: Machine-specific overrides like different `basePort` due to port conflicts, local database URLs, personal workflow preferences
531
+
532
+ **Global Settings:**
533
+ Global settings are stored in `~/.config/iloom-ai/settings.json` and apply to all iloom projects on your machine. Use these for personal preferences like default agent models or workflow permission modes. Project-specific settings (like database configuration) should remain in project config files.
448
534
 
449
535
  **Note:** The `.iloom/settings.local.json` file is automatically created and gitignored when you run `il init`.
450
536
 
@@ -453,6 +539,7 @@ This allows teams to share project defaults via `settings.json` while individual
453
539
  ```jsonc
454
540
  {
455
541
  "mainBranch": "main",
542
+ "sourceEnvOnStart": false, // Source .env in terminal launches (default: false)
456
543
  "mergeBehavior": {
457
544
  "mode": "local", // or "github-pr" for PR-based workflows
458
545
  "remote": "upstream" // optional, defaults to issueManagement.github.remote
@@ -491,6 +578,7 @@ This allows teams to share project defaults via `settings.json` while individual
491
578
 
492
579
  ** Common configuration options:**
493
580
  - `mainBranch` - Primary branch for merging (default: "main")
581
+ - `sourceEnvOnStart` - Source .env file when launching terminal processes (default: false)
494
582
  - `mergeBehavior.mode` - How to finish work: "local" (merge locally) or "github-pr" (create PR) (default: "local")
495
583
  - `mergeBehavior.remote` - Remote to target for PRs (optional, defaults to `issueManagement.github.remote`)
496
584
  - `capabilities.web.basePort` - Base port for dev servers (default: 3000)
@@ -507,15 +595,149 @@ Example: Issue #25 with basePort 3000 = port 3025
507
595
 
508
596
  For complete configuration reference, see [.iloom/README.md](./.iloom/README.md)
509
597
 
598
+ ### IDE Configuration
599
+
600
+ Configure which IDE launches when starting a loom:
601
+
602
+ ```jsonc
603
+ {
604
+ "ide": {
605
+ "type": "cursor" // or: vscode, webstorm, sublime, intellij, windsurf
606
+ }
607
+ }
608
+ ```
609
+
610
+ **Supported IDEs:**
611
+
612
+ | Type | Command | Notes |
613
+ |------|---------|-------|
614
+ | `vscode` | `code` | Default. Visual Studio Code |
615
+ | `cursor` | `cursor` | Cursor AI editor |
616
+ | `webstorm` | `webstorm` | JetBrains WebStorm (launches with --nosplash) |
617
+ | `sublime` | `subl` | Sublime Text |
618
+ | `intellij` | `idea` | JetBrains IntelliJ IDEA (launches with --nosplash) |
619
+ | `windsurf` | `windsurf` | Windsurf editor |
620
+
621
+ **Configure via CLI:** Use the existing `--set` flag:
622
+
623
+ ```bash
624
+ il start 25 --set ide.type=cursor
625
+ ```
626
+
627
+ **Configure during setup:** Run `il init` to configure IDE preference interactively along with other settings.
628
+
629
+ **Note:** Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf). Other IDEs will launch without color theming.
630
+
631
+ ## Issue Tracker Integration
632
+
633
+ iloom supports multiple issue tracking systems through a provider abstraction. Choose GitHub or Linear based on your team's workflow.
634
+
635
+ ### GitHub (Default)
636
+
637
+ GitHub is the default issue tracker and requires no additional configuration beyond authentication with the `gh` CLI.
638
+
639
+ **Setup:**
640
+ ```bash
641
+ # Authenticate with GitHub CLI
642
+ gh auth login
643
+
644
+ # Start using iloom with GitHub issues
645
+ il start 123
646
+ il start PR-456
647
+ ```
648
+
649
+ **Configuration:**
650
+ ```jsonc
651
+ {
652
+ "issueManagement": {
653
+ "provider": "github", // Default, can be omitted
654
+ "github": {
655
+ "remote": "origin" // Optional, defaults to "origin"
656
+ }
657
+ }
658
+ }
659
+ ```
660
+
661
+ ### Linear
662
+
663
+ iloom integrates with Linear through the official `@linear/sdk`, enabling full Linear issue tracking support.
664
+
665
+ **Setup:**
666
+
667
+ 1. Get your Linear API token from [Linear Settings → API → Personal API Keys](https://linear.app/settings/api)
668
+
669
+ 2. Configure iloom to use Linear:
670
+ ```bash
671
+ il init
672
+ # Follow prompts to:
673
+ # - Select Linear as your issue tracker
674
+ # - Enter your Linear team ID (e.g., "ENG")
675
+ # - Enter your Linear API token (saved securely to settings.local.json)
676
+ ```
677
+
678
+ Or manually configure:
679
+
680
+ Edit `.iloom/settings.local.json` (for sensitive data):
681
+ ```jsonc
682
+ {
683
+ "issueManagement": {
684
+ "provider": "linear",
685
+ "linear": {
686
+ "teamId": "ENG", // Required: Your Linear team key
687
+ "apiToken": "lin_api_..." // Required: Your Linear API token
688
+ }
689
+ }
690
+ }
691
+ ```
692
+
693
+ **Important:** The `apiToken` should be stored in `settings.local.json` (not committed to git), not in `settings.json`. The init command will automatically save it to the correct location.
694
+
695
+ Alternatively, use an environment variable:
696
+ ```bash
697
+ export LINEAR_API_TOKEN="lin_api_..."
698
+ ```
699
+
700
+ Settings take precedence over environment variables.
701
+
702
+ **Usage:**
703
+
704
+ ```bash
705
+ # Start working on a Linear issue
706
+ il start ENG-123
707
+
708
+ # Create a new Linear issue
709
+ il start "Add user authentication"
710
+
711
+ # Finish and merge
712
+ il finish
713
+ ```
714
+
715
+ **Features:**
716
+
717
+ - Full CRUD operations on issues and comments via the official Linear SDK
718
+ - MCP integration for Claude AI assistance with Linear issues
719
+ - Automatic workspace creation with Linear issue context
720
+
721
+ **Limitations:**
722
+
723
+ - Linear does not have pull requests. Use `il finish` with `mergeBehavior.mode: "local"` or `"github-pr"` to merge your code.
724
+
725
+ **Port Calculation:**
726
+
727
+ Linear issue identifiers (e.g., ENG-123) use hash-based port calculation instead of simple numeric addition. The port is deterministically generated from the branch name, ensuring consistency across sessions.
728
+
510
729
  ## Requirements
511
730
 
512
731
  **Essential:**
513
732
  - Claude CLI - AI assistance with issue context preloaded
514
733
  - Node.js 16+
515
734
  - Git 2.5+ (for worktree support)
516
- - GitHub CLI (`gh`) - authenticated with your repository
517
735
 
518
- **Recommended**
736
+ **Issue Tracker (choose one):**
737
+ - **GitHub CLI (`gh`)** - For GitHub issue tracking (default)
738
+ - **Linear CLI (`linearis`)** - For Linear issue tracking (install with `npm install -g linearis`)
739
+
740
+ **Recommended:**
519
741
  - A Claude Max subscription - iloom uses your own subscription
520
742
 
521
743
  **Optional (auto-detected):**
@@ -544,6 +766,8 @@ This is an early stage product - platform/tech stack support is limited for now.
544
766
 
545
767
  We (Claude and I) are actively working on expanding platform and integration support. Contributions welcome!
546
768
 
769
+ See all [`known-limitation`](https://github.com/iloom-ai/iloom-cli/issues?q=is%3Aissue+is%3Aopen+label%3Aknown-limitation) issues for details and to [contribute](CONTRIBUTING.md) solutions.
770
+
547
771
  ## Installation
548
772
 
549
773
  ```bash
@@ -740,11 +964,31 @@ Other tools increase code output with minimal process change. iloom increases **
740
964
 
741
965
  ## Contributing
742
966
 
743
- This project follows Test-Driven Development. All code must:
744
- - Be written test-first with comprehensive unit tests
745
- - Achieve >70% code coverage
746
- - Include regression tests against bash script behavior
747
- - Use mock factories for all external dependencies
967
+ We welcome contributions! Whether you're fixing a bug, adding a feature, or improving documentation, there are multiple ways to get involved.
968
+
969
+ ### Quick Start for Contributors
970
+
971
+ The fastest way to get started contributing:
972
+
973
+ ```bash
974
+ iloom contribute # requires the github CLI (gh)
975
+ ```
976
+
977
+ This automated command handles forking, cloning, and setting up your development environment.
978
+
979
+ ### Finding Your First Issue
980
+
981
+ New contributors should start with issues labeled [`starter-task`](https://github.com/iloom-ai/iloom-cli/issues?q=is%3Aissue+is%3Aopen+label%3Astarter-task) - these are designed to help you learn the iloom workflow and codebase while making meaningful contributions.
982
+
983
+ ### Full Contributing Guide
984
+
985
+ For detailed information about our development process, testing requirements, and workflow, see our comprehensive [Contributing Guide](CONTRIBUTING.md).
986
+
987
+ **Key highlights:**
988
+ - Behavior-focused testing principles
989
+ - AI-assisted development workflow using iloom itself
990
+ - Clear PR process and code quality standards
991
+ - Test-Driven Development with >70% coverage requirement
748
992
 
749
993
  ## License
750
994
 
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ClaudeBranchNameStrategy,
4
+ DefaultBranchNamingService,
5
+ SimpleBranchNameStrategy
6
+ } from "./chunk-3KATJIKO.js";
7
+ import "./chunk-GEHQXLEI.js";
8
+ export {
9
+ ClaudeBranchNameStrategy,
10
+ DefaultBranchNamingService,
11
+ SimpleBranchNameStrategy
12
+ };
13
+ //# sourceMappingURL=BranchNamingService-3OQPRSWT.js.map
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ClaudeContextManager
4
+ } from "./chunk-C5QCTEQK.js";
5
+ import "./chunk-FIAT22G7.js";
6
+ import "./chunk-XXV3UFZL.js";
7
+ import "./chunk-WEN5C5DM.js";
8
+ import "./chunk-ML3NRPNB.js";
9
+ import "./chunk-GEHQXLEI.js";
10
+ export {
11
+ ClaudeContextManager
12
+ };
13
+ //# sourceMappingURL=ClaudeContextManager-MUQSDY2E.js.map
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ ClaudeService
4
+ } from "./chunk-FIAT22G7.js";
5
+ import "./chunk-XXV3UFZL.js";
6
+ import "./chunk-WEN5C5DM.js";
7
+ import "./chunk-ML3NRPNB.js";
8
+ import "./chunk-GEHQXLEI.js";
9
+ export {
10
+ ClaudeService
11
+ };
12
+ //# sourceMappingURL=ClaudeService-HG4VQ7AW.js.map
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ GitHubService
4
+ } from "./chunk-G2IEYOLQ.js";
5
+ import "./chunk-3RUPPQRG.js";
6
+ import "./chunk-JKXJ7BGL.js";
7
+ import "./chunk-GEHQXLEI.js";
8
+ export {
9
+ GitHubService
10
+ };
11
+ //# sourceMappingURL=GitHubService-EBOETDIW.js.map
@@ -1,11 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getDevServerLaunchCommand
4
- } from "./chunk-GZP4UGGM.js";
5
- import "./chunk-BLCTGFZN.js";
4
+ } from "./chunk-ZM3CFL5L.js";
5
+ import "./chunk-ZT3YZB4K.js";
6
6
  import {
7
7
  ClaudeContextManager
8
- } from "./chunk-2PLUQT6J.js";
8
+ } from "./chunk-C5QCTEQK.js";
9
+ import "./chunk-FIAT22G7.js";
10
+ import "./chunk-XXV3UFZL.js";
11
+ import "./chunk-WEN5C5DM.js";
12
+ import "./chunk-ML3NRPNB.js";
9
13
  import {
10
14
  openMultipleTerminalWindows,
11
15
  openTerminalWindow
@@ -13,10 +17,6 @@ import {
13
17
  import {
14
18
  generateColorFromBranchName
15
19
  } from "./chunk-ZZZWQGTS.js";
16
- import "./chunk-LHP6ROUM.js";
17
- import "./chunk-MFU53H6J.js";
18
- import "./chunk-PVAVNJKS.js";
19
- import "./chunk-T3KEIB4D.js";
20
20
  import {
21
21
  logger
22
22
  } from "./chunk-GEHQXLEI.js";
@@ -25,42 +25,71 @@ import {
25
25
  import { existsSync } from "fs";
26
26
  import { join } from "path";
27
27
 
28
- // src/utils/vscode.ts
28
+ // src/utils/ide.ts
29
29
  import { execa } from "execa";
30
- async function isVSCodeAvailable() {
30
+ var IDE_PRESETS = {
31
+ vscode: { command: "code", name: "Visual Studio Code", args: [] },
32
+ cursor: { command: "cursor", name: "Cursor", args: [] },
33
+ webstorm: { command: "webstorm", name: "WebStorm", args: ["--nosplash"] },
34
+ sublime: { command: "subl", name: "Sublime Text", args: [] },
35
+ intellij: { command: "idea", name: "IntelliJ IDEA", args: ["--nosplash"] },
36
+ windsurf: { command: "surf", name: "Windsurf", args: [] }
37
+ };
38
+ function getIdeConfig(ideSettings) {
39
+ const type = (ideSettings == null ? void 0 : ideSettings.type) ?? "vscode";
40
+ const preset = IDE_PRESETS[type];
41
+ return {
42
+ command: preset.command,
43
+ args: [...preset.args],
44
+ name: preset.name
45
+ };
46
+ }
47
+ async function isIdeAvailable(command) {
31
48
  try {
32
- await execa("command", ["-v", "code"], {
33
- shell: true,
34
- timeout: 5e3
35
- });
49
+ await execa("command", ["-v", command], { shell: true, timeout: 5e3 });
36
50
  return true;
37
- } catch (error) {
38
- logger.debug("VSCode CLI not available", { error });
51
+ } catch {
39
52
  return false;
40
53
  }
41
54
  }
42
- async function openVSCodeWindow(workspacePath) {
43
- const available = await isVSCodeAvailable();
55
+ function getInstallHint(type) {
56
+ const hints = {
57
+ vscode: `Install command-line tools: Open VSCode > Command Palette > "Shell Command: Install 'code' command in PATH"`,
58
+ cursor: `Install command-line tools: Open Cursor > Command Palette > "Install 'cursor' command in PATH"`,
59
+ webstorm: "Install via JetBrains Toolbox > Settings > Shell Scripts > Enable",
60
+ sublime: 'Create symlink: ln -s "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" /usr/local/bin/subl',
61
+ intellij: "Install via JetBrains Toolbox > Settings > Shell Scripts > Enable",
62
+ windsurf: "Install command-line tools during Windsurf installation or create symlink manually"
63
+ };
64
+ return hints[type] ?? `Ensure the IDE command is available in your PATH`;
65
+ }
66
+ async function openIdeWindow(workspacePath, ideSettings) {
67
+ const config = getIdeConfig(ideSettings);
68
+ const available = await isIdeAvailable(config.command);
44
69
  if (!available) {
70
+ const type = (ideSettings == null ? void 0 : ideSettings.type) ?? "vscode";
45
71
  throw new Error(
46
- `VSCode is not available. Please install VSCode and ensure the "code" command is in your PATH.
47
- Install command-line tools: Open VSCode > Command Palette > "Shell Command: Install 'code' command in PATH"`
72
+ `${config.name} is not available. The "${config.command}" command was not found in PATH.
73
+ ` + getInstallHint(type)
48
74
  );
49
75
  }
50
76
  try {
51
- await execa("code", [workspacePath]);
52
- logger.debug(`Opened VSCode for workspace: ${workspacePath}`);
77
+ await execa(config.command, [...config.args, workspacePath]);
78
+ logger.debug(`Opened ${config.name} for workspace: ${workspacePath}`);
53
79
  } catch (error) {
54
80
  throw new Error(
55
- `Failed to open VSCode: ${error instanceof Error ? error.message : "Unknown error"}`
81
+ `Failed to open ${config.name}: ${error instanceof Error ? error.message : "Unknown error"}`
56
82
  );
57
83
  }
58
84
  }
59
85
 
60
86
  // src/lib/LoomLauncher.ts
61
87
  var LoomLauncher = class {
62
- constructor(claudeContext) {
88
+ constructor(claudeContext, settings) {
63
89
  this.claudeContext = claudeContext ?? new ClaudeContextManager();
90
+ if (settings !== void 0) {
91
+ this.settings = settings;
92
+ }
64
93
  }
65
94
  /**
66
95
  * Launch loom components based on individual flags
@@ -114,11 +143,13 @@ var LoomLauncher = class {
114
143
  logger.success("loom launched successfully");
115
144
  }
116
145
  /**
117
- * Launch VSCode
146
+ * Launch IDE (VSCode or configured alternative)
118
147
  */
119
148
  async launchVSCode(options) {
120
- await openVSCodeWindow(options.worktreePath);
121
- logger.info("VSCode opened");
149
+ var _a;
150
+ const ideConfig = await ((_a = this.settings) == null ? void 0 : _a.loadSettings().then((s) => s.ide));
151
+ await openIdeWindow(options.worktreePath, ideConfig);
152
+ logger.info("IDE opened");
122
153
  }
123
154
  /**
124
155
  * Launch Claude terminal
@@ -151,7 +182,7 @@ var LoomLauncher = class {
151
182
  workspacePath: options.worktreePath,
152
183
  command: devServerCommand,
153
184
  backgroundColor: colorData.rgb,
154
- includeEnvSetup: existsSync(join(options.worktreePath, ".env")),
185
+ includeEnvSetup: (options.sourceEnvOnStart ?? false) && existsSync(join(options.worktreePath, ".env")),
155
186
  includePortExport: options.capabilities.includes("web"),
156
187
  ...options.port !== void 0 && { port: options.port }
157
188
  });
@@ -165,7 +196,7 @@ var LoomLauncher = class {
165
196
  await openTerminalWindow({
166
197
  workspacePath: options.worktreePath,
167
198
  backgroundColor: colorData.rgb,
168
- includeEnvSetup: existsSync(join(options.worktreePath, ".env")),
199
+ includeEnvSetup: (options.sourceEnvOnStart ?? false) && existsSync(join(options.worktreePath, ".env")),
169
200
  includePortExport: options.capabilities.includes("web"),
170
201
  ...options.port !== void 0 && { port: options.port }
171
202
  });
@@ -193,7 +224,7 @@ var LoomLauncher = class {
193
224
  command: claudeCommand,
194
225
  backgroundColor: colorData.rgb,
195
226
  title: claudeTitle,
196
- includeEnvSetup: hasEnvFile,
227
+ includeEnvSetup: (options.sourceEnvOnStart ?? false) && hasEnvFile,
197
228
  ...options.port !== void 0 && { port: options.port, includePortExport: true }
198
229
  };
199
230
  }
@@ -214,7 +245,7 @@ var LoomLauncher = class {
214
245
  command: devServerCommand,
215
246
  backgroundColor: colorData.rgb,
216
247
  title: devServerTitle,
217
- includeEnvSetup: hasEnvFile,
248
+ includeEnvSetup: (options.sourceEnvOnStart ?? false) && hasEnvFile,
218
249
  includePortExport: options.capabilities.includes("web"),
219
250
  ...options.port !== void 0 && { port: options.port }
220
251
  };
@@ -230,7 +261,7 @@ var LoomLauncher = class {
230
261
  workspacePath: options.worktreePath,
231
262
  backgroundColor: colorData.rgb,
232
263
  title: terminalTitle,
233
- includeEnvSetup: hasEnvFile,
264
+ includeEnvSetup: (options.sourceEnvOnStart ?? false) && hasEnvFile,
234
265
  includePortExport: options.capabilities.includes("web"),
235
266
  ...options.port !== void 0 && { port: options.port }
236
267
  };
@@ -260,4 +291,4 @@ var LoomLauncher = class {
260
291
  export {
261
292
  LoomLauncher
262
293
  };
263
- //# sourceMappingURL=LoomLauncher-CTSWJL35.js.map
294
+ //# sourceMappingURL=LoomLauncher-FLEMBCSQ.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 } from '../utils/color.js'\nimport { logger } from '../utils/logger.js'\nimport { ClaudeContextManager } from './ClaudeContextManager.js'\nimport type { SettingsManager } from './SettingsManager.js'\nimport type { Capability } from '../types/loom.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}\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\tlogger.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\tlogger.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\tlogger.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\tlogger.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\tlogger.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\tlogger.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\tlogger.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 colorData = generateColorFromBranchName(options.branchName)\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\tawait openTerminalWindow({\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tcommand: devServerCommand,\n\t\t\tbackgroundColor: colorData.rgb,\n\t\t\tincludeEnvSetup: (options.sourceEnvOnStart ?? false) && existsSync(join(options.worktreePath, '.env')),\n\t\t\tincludePortExport: options.capabilities.includes('web'),\n\t\t\t...(options.port !== undefined && { port: options.port }),\n\t\t})\n\t\tlogger.info('Dev server terminal opened')\n\t}\n\n\t/**\n\t * Launch standalone terminal (no command, just workspace with env vars)\n\t */\n\tprivate async launchStandaloneTerminal(options: LaunchLoomOptions): Promise<void> {\n\t\tconst colorData = generateColorFromBranchName(options.branchName)\n\n\t\tawait openTerminalWindow({\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tbackgroundColor: colorData.rgb,\n\t\t\tincludeEnvSetup: (options.sourceEnvOnStart ?? false) && existsSync(join(options.worktreePath, '.env')),\n\t\t\tincludePortExport: options.capabilities.includes('web'),\n\t\t\t...(options.port !== undefined && { port: options.port }),\n\t\t})\n\t\tlogger.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 colorData = generateColorFromBranchName(options.branchName)\n\t\tconst hasEnvFile = existsSync(join(options.worktreePath, '.env'))\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\treturn {\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tcommand: claudeCommand,\n\t\t\tbackgroundColor: colorData.rgb,\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 colorData = generateColorFromBranchName(options.branchName)\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 = existsSync(join(options.worktreePath, '.env'))\n\t\tconst devServerTitle = `Dev Server - ${this.formatIdentifier(options.workflowType, options.identifier)}`\n\n\t\treturn {\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tcommand: devServerCommand,\n\t\t\tbackgroundColor: colorData.rgb,\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 (no command)\n\t */\n\tprivate buildStandaloneTerminalOptions(\n\t\toptions: LaunchLoomOptions\n\t): TerminalWindowOptions {\n\t\tconst colorData = generateColorFromBranchName(options.branchName)\n\t\tconst hasEnvFile = existsSync(join(options.worktreePath, '.env'))\n\t\tconst terminalTitle = `Terminal - ${this.formatIdentifier(options.workflowType, options.identifier)}`\n\n\t\treturn {\n\t\t\tworkspacePath: options.worktreePath,\n\t\t\tbackgroundColor: colorData.rgb,\n\t\t\ttitle: terminalTitle,\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 * 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\tlogger.info(`Multiple terminals opened: ${terminalTypes}`)\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} 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}\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":[]}