@iloom/cli 0.3.1 → 0.3.3

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 (128) hide show
  1. package/README.md +8 -6
  2. package/dist/{BranchNamingService-OMWKUYMM.js → BranchNamingService-A77VI6AI.js} +2 -2
  3. package/dist/ClaudeContextManager-BN7RE5ZQ.js +15 -0
  4. package/dist/ClaudeService-DLYLJUPA.js +14 -0
  5. package/dist/{GitHubService-EBOETDIW.js → GitHubService-FZHHBOFG.js} +3 -3
  6. package/dist/{LoomLauncher-JF7JZMTZ.js → LoomLauncher-ZV3ZZIBA.js} +40 -26
  7. package/dist/LoomLauncher-ZV3ZZIBA.js.map +1 -0
  8. package/dist/{PromptTemplateManager-A52RUAMS.js → PromptTemplateManager-6HH3PVXV.js} +2 -2
  9. package/dist/README.md +8 -6
  10. package/dist/{SettingsManager-ZCWJ56WP.js → SettingsManager-I2LRCW2A.js} +2 -2
  11. package/dist/{SettingsMigrationManager-AGIIIPDQ.js → SettingsMigrationManager-TJ7UWZG5.js} +3 -3
  12. package/dist/agents/iloom-issue-complexity-evaluator.md +18 -3
  13. package/dist/agents/iloom-issue-enhancer.md +1 -1
  14. package/dist/{chunk-TSKY3JI7.js → chunk-2CXREBLZ.js} +2 -2
  15. package/dist/{chunk-HBYZH6GD.js → chunk-2IJEMXOB.js} +431 -128
  16. package/dist/chunk-2IJEMXOB.js.map +1 -0
  17. package/dist/{chunk-IXKLYTWO.js → chunk-2MAIX45J.js} +8 -8
  18. package/dist/{chunk-4BGK7T6X.js → chunk-5Q3NDNNV.js} +48 -8
  19. package/dist/chunk-5Q3NDNNV.js.map +1 -0
  20. package/dist/{chunk-JQFO7QQN.js → chunk-5VK4NRSF.js} +3 -3
  21. package/dist/{chunk-JQFO7QQN.js.map → chunk-5VK4NRSF.js.map} +1 -1
  22. package/dist/{chunk-XPKDPZ5D.js → chunk-AKUJXDNW.js} +2 -2
  23. package/dist/{chunk-O5OH5MRX.js → chunk-CDZERT7Z.js} +23 -11
  24. package/dist/chunk-CDZERT7Z.js.map +1 -0
  25. package/dist/{chunk-JKXJ7BGL.js → chunk-CE26YH2U.js} +42 -3
  26. package/dist/chunk-CE26YH2U.js.map +1 -0
  27. package/dist/{chunk-ZZZWQGTS.js → chunk-CFFQ2Z7A.js} +74 -75
  28. package/dist/chunk-CFFQ2Z7A.js.map +1 -0
  29. package/dist/{chunk-RO26VS3W.js → chunk-DLHA5VQ3.js} +174 -5
  30. package/dist/chunk-DLHA5VQ3.js.map +1 -0
  31. package/dist/{chunk-ZBQVSHVT.js → chunk-IFB4Z76W.js} +35 -10
  32. package/dist/chunk-IFB4Z76W.js.map +1 -0
  33. package/dist/{chunk-G2IEYOLQ.js → chunk-M7JJCX53.js} +17 -2
  34. package/dist/chunk-M7JJCX53.js.map +1 -0
  35. package/dist/{chunk-KLBYVHPK.js → chunk-OSCLCMDG.js} +2 -2
  36. package/dist/chunk-OXAM2WVC.js +68 -0
  37. package/dist/chunk-OXAM2WVC.js.map +1 -0
  38. package/dist/{chunk-ZWFBBPJI.js → chunk-OYF4VIFI.js} +5 -3
  39. package/dist/chunk-OYF4VIFI.js.map +1 -0
  40. package/dist/{chunk-U5QDY7ZD.js → chunk-PGPI5LR4.js} +8 -8
  41. package/dist/{chunk-WEN5C5DM.js → chunk-RIEO2WML.js} +4 -1
  42. package/dist/chunk-RIEO2WML.js.map +1 -0
  43. package/dist/{chunk-ZE74H5BR.js → chunk-RW54ZMBM.js} +26 -20
  44. package/dist/chunk-RW54ZMBM.js.map +1 -0
  45. package/dist/{chunk-INW24J2W.js → chunk-SUOXY5WJ.js} +2 -2
  46. package/dist/{init-L55Q73H4.js → chunk-UAN4A3YU.js} +345 -45
  47. package/dist/chunk-UAN4A3YU.js.map +1 -0
  48. package/dist/{chunk-IP7SMKIF.js → chunk-UJL4HI2R.js} +59 -60
  49. package/dist/chunk-UJL4HI2R.js.map +1 -0
  50. package/dist/{claude-LUZ35IMK.js → claude-W52VKI6L.js} +4 -2
  51. package/dist/{cleanup-3MONU4PU.js → cleanup-H4VXU3C3.js} +19 -17
  52. package/dist/{cleanup-3MONU4PU.js.map → cleanup-H4VXU3C3.js.map} +1 -1
  53. package/dist/cli.js +347 -114
  54. package/dist/cli.js.map +1 -1
  55. package/dist/{color-ZVALX37U.js → color-F7RU6B6Z.js} +10 -4
  56. package/dist/{contribute-UWJAGIG7.js → contribute-Y7IQV5QY.js} +4 -3
  57. package/dist/{contribute-UWJAGIG7.js.map → contribute-Y7IQV5QY.js.map} +1 -1
  58. package/dist/{feedback-W3BXTGIM.js → feedback-XTUCKJNT.js} +16 -12
  59. package/dist/{feedback-W3BXTGIM.js.map → feedback-XTUCKJNT.js.map} +1 -1
  60. package/dist/{git-34Z6QVDS.js → git-IYA53VIC.js} +9 -2
  61. package/dist/{ignite-KVJEFXNO.js → ignite-T74RYXCA.js} +25 -75
  62. package/dist/ignite-T74RYXCA.js.map +1 -0
  63. package/dist/index.d.ts +71 -14
  64. package/dist/index.js +407 -377
  65. package/dist/index.js.map +1 -1
  66. package/dist/init-4FHTAM3F.js +19 -0
  67. package/dist/mcp/issue-management-server.js +8 -1
  68. package/dist/mcp/issue-management-server.js.map +1 -1
  69. package/dist/{neon-helpers-WPUACUVC.js → neon-helpers-77PBPGJ5.js} +3 -3
  70. package/dist/{open-LNRZL3UU.js → open-UMXANW5S.js} +27 -14
  71. package/dist/open-UMXANW5S.js.map +1 -0
  72. package/dist/{prompt-7INJ7YRU.js → prompt-QALMYTVC.js} +4 -2
  73. package/dist/prompts/init-prompt.txt +89 -9
  74. package/dist/prompts/issue-prompt.txt +18 -11
  75. package/dist/{rebase-C4WNCVGM.js → rebase-VJ2VKR6R.js} +15 -13
  76. package/dist/rebase-VJ2VKR6R.js.map +1 -0
  77. package/dist/{run-IOGNIOYN.js → run-MJYY4PUT.js} +27 -14
  78. package/dist/run-MJYY4PUT.js.map +1 -0
  79. package/dist/schema/settings.schema.json +22 -4
  80. package/dist/{test-git-J7I5MFYH.js → test-git-IT5EWQ5C.js} +5 -5
  81. package/dist/{test-prefix-ZCONBCBX.js → test-prefix-NPWDPUUH.js} +5 -5
  82. package/dist/{test-tabs-RXDBZ6J7.js → test-tabs-PRMRSHKI.js} +3 -2
  83. package/dist/{test-tabs-RXDBZ6J7.js.map → test-tabs-PRMRSHKI.js.map} +1 -1
  84. package/package.json +2 -1
  85. package/dist/ClaudeContextManager-3VXA6UPR.js +0 -13
  86. package/dist/ClaudeService-6CPK43N4.js +0 -12
  87. package/dist/LoomLauncher-JF7JZMTZ.js.map +0 -1
  88. package/dist/chunk-4BGK7T6X.js.map +0 -1
  89. package/dist/chunk-4E4LD3QR.js +0 -302
  90. package/dist/chunk-4E4LD3QR.js.map +0 -1
  91. package/dist/chunk-G2IEYOLQ.js.map +0 -1
  92. package/dist/chunk-HBYZH6GD.js.map +0 -1
  93. package/dist/chunk-IP7SMKIF.js.map +0 -1
  94. package/dist/chunk-JKXJ7BGL.js.map +0 -1
  95. package/dist/chunk-O5OH5MRX.js.map +0 -1
  96. package/dist/chunk-RO26VS3W.js.map +0 -1
  97. package/dist/chunk-WEN5C5DM.js.map +0 -1
  98. package/dist/chunk-ZBQVSHVT.js.map +0 -1
  99. package/dist/chunk-ZE74H5BR.js.map +0 -1
  100. package/dist/chunk-ZWFBBPJI.js.map +0 -1
  101. package/dist/chunk-ZZZWQGTS.js.map +0 -1
  102. package/dist/ignite-KVJEFXNO.js.map +0 -1
  103. package/dist/init-L55Q73H4.js.map +0 -1
  104. package/dist/open-LNRZL3UU.js.map +0 -1
  105. package/dist/rebase-C4WNCVGM.js.map +0 -1
  106. package/dist/run-IOGNIOYN.js.map +0 -1
  107. package/dist/terminal-BIRBZ4AZ.js +0 -16
  108. /package/dist/{BranchNamingService-OMWKUYMM.js.map → BranchNamingService-A77VI6AI.js.map} +0 -0
  109. /package/dist/{ClaudeContextManager-3VXA6UPR.js.map → ClaudeContextManager-BN7RE5ZQ.js.map} +0 -0
  110. /package/dist/{ClaudeService-6CPK43N4.js.map → ClaudeService-DLYLJUPA.js.map} +0 -0
  111. /package/dist/{GitHubService-EBOETDIW.js.map → GitHubService-FZHHBOFG.js.map} +0 -0
  112. /package/dist/{PromptTemplateManager-A52RUAMS.js.map → PromptTemplateManager-6HH3PVXV.js.map} +0 -0
  113. /package/dist/{SettingsManager-ZCWJ56WP.js.map → SettingsManager-I2LRCW2A.js.map} +0 -0
  114. /package/dist/{SettingsMigrationManager-AGIIIPDQ.js.map → SettingsMigrationManager-TJ7UWZG5.js.map} +0 -0
  115. /package/dist/{chunk-TSKY3JI7.js.map → chunk-2CXREBLZ.js.map} +0 -0
  116. /package/dist/{chunk-IXKLYTWO.js.map → chunk-2MAIX45J.js.map} +0 -0
  117. /package/dist/{chunk-XPKDPZ5D.js.map → chunk-AKUJXDNW.js.map} +0 -0
  118. /package/dist/{chunk-KLBYVHPK.js.map → chunk-OSCLCMDG.js.map} +0 -0
  119. /package/dist/{chunk-U5QDY7ZD.js.map → chunk-PGPI5LR4.js.map} +0 -0
  120. /package/dist/{chunk-INW24J2W.js.map → chunk-SUOXY5WJ.js.map} +0 -0
  121. /package/dist/{claude-LUZ35IMK.js.map → claude-W52VKI6L.js.map} +0 -0
  122. /package/dist/{color-ZVALX37U.js.map → color-F7RU6B6Z.js.map} +0 -0
  123. /package/dist/{git-34Z6QVDS.js.map → git-IYA53VIC.js.map} +0 -0
  124. /package/dist/{neon-helpers-WPUACUVC.js.map → init-4FHTAM3F.js.map} +0 -0
  125. /package/dist/{prompt-7INJ7YRU.js.map → neon-helpers-77PBPGJ5.js.map} +0 -0
  126. /package/dist/{terminal-BIRBZ4AZ.js.map → prompt-QALMYTVC.js.map} +0 -0
  127. /package/dist/{test-git-J7I5MFYH.js.map → test-git-IT5EWQ5C.js.map} +0 -0
  128. /package/dist/{test-prefix-ZCONBCBX.js.map → test-prefix-NPWDPUUH.js.map} +0 -0
@@ -1,15 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  isInteractiveEnvironment,
4
+ promptCommitAction,
4
5
  promptConfirmation,
5
6
  promptInput,
6
7
  waitForKeypress
7
- } from "./chunk-JKXJ7BGL.js";
8
+ } from "./chunk-CE26YH2U.js";
8
9
  import "./chunk-GEHQXLEI.js";
9
10
  export {
10
11
  isInteractiveEnvironment,
12
+ promptCommitAction,
11
13
  promptConfirmation,
12
14
  promptInput,
13
15
  waitForKeypress
14
16
  };
15
- //# sourceMappingURL=prompt-7INJ7YRU.js.map
17
+ //# sourceMappingURL=prompt-QALMYTVC.js.map
@@ -101,7 +101,7 @@ The following JSON Schema defines valid iloom settings:
101
101
  "sourceEnvOnStart": {
102
102
  "type": "boolean",
103
103
  "default": false,
104
- "description": "Source .env file when launching terminal processes (Claude, dev server, terminal). NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env compatibility. WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. Before enabling, verify your .env file does not contain unquoted special characters (e.g., database URLs with ?, &, or other shell metacharacters). Shell compatibility issues may cause processes to fail or behave unexpectedly."
104
+ "description": "Source all dotenv-flow files (.env, .env.local, .env.development, .env.development.local) when launching terminal processes (Claude, dev server, terminal). Files are sourced in precedence order so later files override earlier ones. NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env file compatibility. WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. Before enabling, verify ALL your .env.* files do not contain unquoted special characters (e.g., database URLs with ?, &, or other shell metacharacters). Shell compatibility issues may cause processes to fail or behave unexpectedly."
105
105
  },
106
106
  "worktreePrefix": {
107
107
  "type": "string",
@@ -417,14 +417,32 @@ The following JSON Schema defines valid iloom settings:
417
417
  "webstorm",
418
418
  "sublime",
419
419
  "intellij",
420
- "windsurf"
420
+ "windsurf",
421
+ "antigravity"
421
422
  ],
422
423
  "default": "vscode",
423
- "description": "IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), windsurf (Windsurf editor)."
424
+ "description": "IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), windsurf (Windsurf editor), antigravity (Antigravity IDE)."
424
425
  }
425
426
  },
426
427
  "additionalProperties": false,
427
- "description": "IDE configuration for workspace launches. Controls which editor opens when you start a loom. Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, and Windsurf. Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf)."
428
+ "description": "IDE configuration for workspace launches. Controls which editor opens when you start a loom. Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, Windsurf, and Antigravity. Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf, antigravity)."
429
+ },
430
+ "colors": {
431
+ "type": "object",
432
+ "properties": {
433
+ "terminal": {
434
+ "type": "boolean",
435
+ "default": true,
436
+ "description": "Apply terminal background colors based on branch name (macOS only)"
437
+ },
438
+ "vscode": {
439
+ "type": "boolean",
440
+ "default": false,
441
+ "description": "Apply VSCode/Cursor title bar colors based on branch name. Note: This modifies .vscode/settings.json which may be in source control. Default is false for safety; enable via init or explicitly if .vscode is gitignored."
442
+ }
443
+ },
444
+ "additionalProperties": false,
445
+ "description": "Color synchronization settings for workspace identification"
428
446
  }
429
447
  },
430
448
  "additionalProperties": false
@@ -647,7 +665,7 @@ Use AskUserQuestion to ask ALL local development settings questions **IN A SINGL
647
665
  - "bypassPermissions" - Claude executes without confirmation (use with caution)
648
666
  - Default: currentPermissionMode or "acceptEdits"
649
667
  - Validation: Must be one of: default, plan, acceptEdits, bypassPermissions
650
- - Store answer as: `workflows.issue.permissionMode`
668
+ - Store answer as: `workflows.issue.permissionMode` - NOTE: this is a personal preference - recommend it be stored in the gitignored local settings file.
651
669
 
652
670
  4. **Base Port**
653
671
  - Question format: "What base port should web development servers use?{{#IF currentBasePort}} (Currently: [currentBasePort]){{/IF currentBasePort}}"
@@ -684,6 +702,11 @@ Since this repository has multiple git remotes, GitHub Issues is suggested as th
684
702
  - Validation: Must be one of: github, linear
685
703
  - Store answer as: `issueManagement.provider`
686
704
 
705
+ **Note on Provider + Merge Mode Combinations:**
706
+ - GitHub Issues + local merge or github-pr: Requires authorized GitHub CLI (`gh`)
707
+ - Linear Issues + local merge: Requires Linear API token only
708
+ - Linear Issues + github-pr merge: Requires BOTH Linear API token AND authorized GitHub CLI (`gh`)
709
+
687
710
  **Step 2: Provider-Specific Configuration**
688
711
 
689
712
  Based on the answer to Step 1, ask the appropriate follow-up questions:
@@ -749,10 +772,11 @@ REMOTES_INFO
749
772
  - "sublime" - Sublime Text
750
773
  - "intellij" - JetBrains IntelliJ IDEA
751
774
  - "windsurf" - Windsurf editor
775
+ - "antigravity" - Antigravity IDE
752
776
  - Default: currentIdeType or "vscode"
753
777
  - Validation: Must be one of the listed options
754
778
  - Store answer as: `ide.type`
755
- - Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf). Other IDEs will launch without color theming.
779
+ - Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf, antigravity). Other IDEs will launch without color theming.
756
780
 
757
781
  **Step 4: Merge Mode** (only ask if multiple remotes detected OR user requests advanced config)
758
782
 
@@ -765,6 +789,7 @@ REMOTES_INFO
765
789
  - Validation: Must be one of: local, github-pr
766
790
  - Store answer as: `mergeBehavior.mode`
767
791
  - Context: Fork workflows (with upstream remote) should typically use "github-pr" mode
792
+ - **IMPORTANT**: The "github-pr" mode requires GitHub CLI (`gh`) to be installed and authenticated, regardless of your issue tracker provider. If you use Linear for issue tracking but want to create GitHub PRs, ensure `gh` is installed.
768
793
 
769
794
  **Implementation Details:**
770
795
  - Ask Step 1 first to determine provider
@@ -774,6 +799,40 @@ REMOTES_INFO
774
799
  - Set multiSelect: false for all questions
775
800
  - Process answers sequentially as they depend on each other
776
801
 
802
+ ### Phase 2.5: Color Synchronization Settings - ONLY IF USER HAS CHOSEN the vscode, cursor, windsurf, or antigravity IDE
803
+
804
+ After Phase 2, handle color settings based on gitignore status.
805
+
806
+ Analyis of system: Is VSCode Settings ignore? VSCODE_SETTINGS_GITIGNORED
807
+
808
+ **IMPORTANT DISTINCTION:**
809
+ - Schema defaults are: terminal=true, vscode=false (for safety)
810
+ - Your job in init is to RECOMMEND optimal settings based on the project
811
+ - IMPORTANT: This is a per-project setting - recommend to save it in shared project settings (not globally). EVEN IF OTHER SETTINGS ARE SAVED ELSEHWERE
812
+
813
+ **Terminal Color Recommendation:**
814
+ - Always recommend `true` - terminal colors only affect macOS Terminal.app, no file changes
815
+
816
+ **VSCode Color Recommendation:**
817
+
818
+ **If "VSCODE_SETTINGS_GITIGNORED" == "true":**
819
+ - Recommend `colors.vscode: true` (safe since file is gitignored)
820
+ - Explain: "VSCode title bar coloring is safe to enable since .vscode/settings.json is gitignored"
821
+
822
+ **If "VSCODE_SETTINGS_GITIGNORED" == "false":**
823
+ - Warn user: "VSCode/Cursor title bar coloring modifies .vscode/settings.json which is tracked in git."
824
+ - Ask user: "Would you like to:
825
+ 1. Add .vscode/settings.json to .gitignore (recommended - enables color sync without git pollution)
826
+ 2. Keep VSCode color sync disabled (default - keeps .vscode/settings.json in source control unchanged)
827
+ 3. Enable anyway (Please don't do this - colors will appear in git diffs)"
828
+
829
+ Based on the users answer:
830
+ - Option 1: Add to .gitignore, set `colors.vscode: true`
831
+ - Option 2: Set `colors.vscode: false` (matches safe default)
832
+ - Option 3: Set `colors.vscode: true` (with warning noted)
833
+
834
+ **Note:** Terminal colors default to `true` (always recommend unless user explicitly disables).
835
+
777
836
  ### Phase 3: Configuration Summary
778
837
 
779
838
  After gathering all answers from Phase 1 and Phase 2, display a summary like this:
@@ -947,9 +1006,24 @@ When both settings.json and settings.local.json exist, you MUST prevent duplicat
947
1006
  }
948
1007
  ```
949
1008
 
950
- 7. **Combine all applicable sections** into a single JSON object. Only include sections where the value differs from the default.
1009
+ 7. **Add colors settings based on Phase 2.5 recommendations (if vscode or cursor IDE):**
1010
+ ```json
1011
+ {
1012
+ "colors": {
1013
+ "terminal": true, // Always recommend true unless user explicitly disabled
1014
+ "vscode": <based on gitignore status and user choice>
1015
+ }
1016
+ }
1017
+ ```
1018
+ - Default behavior: Only include if vscode differs from default (false) or terminal is disabled
1019
+ - If "VSCODE_SETTINGS_GITIGNORED" == "true" (note: variable has been subsituted) and user accepted recommendation: `"vscode": true`
1020
+ - If user chose to add .vscode/settings.json to .gitignore: `"vscode": true`
1021
+ - If user chose to keep disabled or enable anyway: set accordingly
1022
+ - Terminal should be true unless user explicitly disabled it
951
1023
 
952
- 8. **If existing settings exist, MERGE** the new values with existing ones. Don't overwrite settings the user didn't modify.
1024
+ 8. **Combine all applicable sections** into a single JSON object. Only include sections where the value differs from the default.
1025
+
1026
+ 9. **If existing settings exist, MERGE** the new values with existing ones. Don't overwrite settings the user didn't modify.
953
1027
 
954
1028
  ### Phase 6: Write File
955
1029
 
@@ -957,6 +1031,8 @@ When both settings.json and settings.local.json exist, you MUST prevent duplicat
957
1031
 
958
1032
  Before writing the file, perform a final duplication check:
959
1033
 
1034
+ **You might need to create/update multiple files - if some settigns should be not commitedd (ie. API Keys, permissionMode etc), then recommend create a local settings file for those settings and a shared one for others.
1035
+
960
1036
  **If writing to settings.local.json:**
961
1037
  1. Load the current settings.json (if it exists)
962
1038
  2. Compare EVERY setting in the generated local config against settings.json
@@ -986,7 +1062,7 @@ Reason: mainBranch has same value in both files, so it's removed from local
986
1062
  - For global: Ensure `~/.config/iloom-ai/` directory exists (create if needed)
987
1063
  - For project/local: Ensure `.iloom/` directory exists (create if needed)
988
1064
  2. Perform duplication check as described above
989
- 3. Write the deduplicated settings to the chosen file:
1065
+ 3. For each settings file you need to update, write the deduplicated settings to the chosen file:
990
1066
  - `~/.config/iloom-ai/settings.json` if user chose Global
991
1067
  - `.iloom/settings.json` if user chose Project
992
1068
  - `.iloom/settings.local.json` if user chose Local
@@ -1067,9 +1143,12 @@ Would you like to commit these changes?
1067
1143
  - **NEVER stage or commit unrelated files** - even if they appear in `git status`
1068
1144
  - **If the commit fails, you must then subsequently request to use --no-verify flag** to bypass pre-commit hooks that might fail due to unrelated codebase state
1069
1145
  - **Do NOT commit settings.local.json** - it should be gitignored, not committed
1146
+ - **YOU MAY NEED TO EDIT/UPDATE MORE THAN ONE FILE if the user is changing something like API Keys (local only), permissionsMode (local only), IDE (recommened global) as well as shared settings.
1070
1147
 
1071
1148
  **Step 3: If user says yes, commit the changes**
1072
1149
 
1150
+ VERIFY YOU'RE NOT BUNDLING ALL CHANGES IN ONE FILE DESPITE GUIDANCE TO SPLIT ACCORDING TO RULES/RECOMMENDATIONS ABOVE
1151
+
1073
1152
  Stage ONLY the iloom-related files that should be committed:
1074
1153
  ```bash
1075
1154
  git add .iloom/settings.json .gitignore 2>/dev/null || true
@@ -1213,6 +1292,7 @@ If users ask about specific configurations, help them add these sections to thei
1213
1292
  - **Phase 1 = Local dev settings** (main branch, worktree prefix, permission mode, base port)
1214
1293
  - **Phase 2 = Tooling integrations** (issue tracker provider, provider-specific config, IDE, merge mode)
1215
1294
  - **Keep configuration minimal** - only include non-default values
1295
+ - **Honor recommendations/requirements of where to save certain settings - this may mean you have to create/update multiple settings files. (e.g when adding API keys for permissions mode settings)
1216
1296
  - **Merge carefully** when updating existing settings - preserve any settings the user didn't modify
1217
1297
  - **Handle errors gracefully** - if schema validation fails, explain what went wrong and ask the user to try again
1218
1298
  - **CRITICAL: PREVENT DUPLICATION** - When writing settings.local.json, ONLY include settings that differ from settings.json. If a setting has the same value in both files, it MUST be removed from the local file. Local should only contain overrides, never duplicates.
@@ -30,7 +30,7 @@ This is the user's first time running through the `iloom` workflow. You have add
30
30
  iloom is a CLI tool for scaling a human's understanding of the AI's work, as the AI's output scales. It does this by managing isolated Git worktrees in a guided workflow, with significant AI integration. It orchestrates multi-phase workflows:
31
31
 
32
32
  1. **Enhancement** - Expands brief issues into detailed requirements
33
- 2. **Complexity Evaluation** - Categorizes as SIMPLE or COMPLEX based on scope
33
+ 2. **Complexity Evaluation** - Categorizes as TRIVIAL, SIMPLE, or COMPLEX based on scope
34
34
  3. **Analysis** - Investigates root causes and technical constraints
35
35
  4. **Planning** - Creates implementation roadmap with file specifications
36
36
  5. **Implementation** - Executes the plan with validation
@@ -121,7 +121,7 @@ You are orchestrating a set of agents through a development process, with human
121
121
  5. Run complexity evaluation for ISSUE_NUMBER using @agent-iloom-issue-complexity-evaluator
122
122
  6. Extract issue link that includes comment id from agent output, display complexity assessment to user
123
123
  7. WAIT for human confirmation of complexity classification before proceeding to next phase
124
- 8. Route to appropriate workflow based on confirmed complexity (SIMPLE or COMPLEX)
124
+ 8. Route to appropriate workflow based on confirmed complexity (TRIVIAL, SIMPLE, or COMPLEX)
125
125
  9. If SIMPLE: Run combined analysis and planning for ISSUE_NUMBER using @agent-iloom-issue-analyze-and-plan
126
126
  10. If COMPLEX: Run separate analysis for ISSUE_NUMBER using @agent-iloom-issue-analyzer
127
127
  11. Extract issue link that includes comment id from agent output, display to user
@@ -152,10 +152,10 @@ Perform ONE comprehensive scan to determine which agents need to run:
152
152
  **Complexity Evaluation Decision:**
153
153
  - Search ALL comments for existing complexity evaluation. Consider "already evaluated" if ANY comment has:
154
154
  * Header containing "Complexity Assessment" or "Complexity Evaluation"
155
- * Section with "**Classification**: [SIMPLE / COMPLEX]"
155
+ * Section with "**Classification**: [TRIVIAL / SIMPLE / COMPLEX]"
156
156
  * Metrics section with estimated files, LOC, breaking changes, DB migrations, and risk level
157
157
  - Decision: NEEDS_COMPLEXITY_EVAL or SKIP_COMPLEXITY_EVAL
158
- - If skipping, log: "Issue #ISSUE_NUMBER already has complexity evaluation by @[author] from [date] showing [SIMPLE/COMPLEX] classification, skipping evaluation"
158
+ - If skipping, log: "Issue #ISSUE_NUMBER already has complexity evaluation by @[author] from [date] showing [TRIVIAL/SIMPLE/COMPLEX] classification, skipping evaluation"
159
159
 
160
160
  **Analysis Decision:**
161
161
  - Search ALL comments for existing analysis. Consider "already analyzed" if ANY comment has ALL:
@@ -227,13 +227,13 @@ Only execute if workflow plan determined NEEDS_COMPLEXITY_EVAL:
227
227
  2. Upon completion: Extract issue+comment link from agent output and provide link to issue comment (including comment ID)
228
228
  3. Extract complexity classification from evaluator output:
229
229
  - Search the evaluator's output for the "Complexity Assessment" section
230
- - Extract: Classification (SIMPLE/COMPLEX), Metrics (files, LOC, breaking changes, DB migrations, risk level), and Reasoning
230
+ - Extract: Classification (TRIVIAL/SIMPLE/COMPLEX), Metrics (files, LOC, breaking changes, DB migrations, risk level), and Reasoning
231
231
  - The evaluator uses deterministic format - parse exactly as specified
232
232
  4. Display complexity assessment to user:
233
233
  Display the extracted assessment in this format:
234
234
  ```
235
235
  Complexity Assessment from Evaluator:
236
- - Classification: [SIMPLE/COMPLEX]
236
+ - Classification: [TRIVIAL/SIMPLE/COMPLEX]
237
237
  - Estimated files: [N]
238
238
  - Estimated LOC: [N]
239
239
  - Breaking changes: [Yes/No]
@@ -243,9 +243,10 @@ Only execute if workflow plan determined NEEDS_COMPLEXITY_EVAL:
243
243
  Reasoning: [reasoning text from evaluator]
244
244
  ```
245
245
  5. Use AskUserQuestion tool with a single question:
246
- - Question: "Complexity evaluated as [SIMPLE/COMPLEX]. See assessment at: [issue comment URL]. Do you agree with this classification?"
246
+ - Question: "Complexity evaluated as [TRIVIAL/SIMPLE/COMPLEX]. See assessment at: [issue comment URL]. Do you agree with this classification?"
247
247
  - Options:
248
- - "Yes, proceed with [SIMPLE/COMPLEX] workflow" (default)
248
+ - "Yes, proceed with [TRIVIAL/SIMPLE/COMPLEX] workflow" (default)
249
+ - "No, reclassify as TRIVIAL"
249
250
  - "No, reclassify as SIMPLE"
250
251
  - "No, reclassify as COMPLEX"
251
252
  - "Provide feedback before deciding"
@@ -260,11 +261,11 @@ Only execute if workflow plan determined NEEDS_COMPLEXITY_EVAL:
260
261
  If workflow plan determined SKIP_COMPLEXITY_EVAL:
261
262
  1. Mark todos #5, #6, and #7 as completed
262
263
  2. Extract complexity from existing evaluation comment:
263
- - Search ALL issue comments for "**Classification**: [SIMPLE / COMPLEX]"
264
- - If found: Extract the classification (SIMPLE or COMPLEX)
264
+ - Search ALL issue comments for "**Classification**: [TRIVIAL / SIMPLE / COMPLEX]"
265
+ - If found: Extract the classification (TRIVIAL, SIMPLE, or COMPLEX)
265
266
  - If not found: Default to COMPLEX workflow
266
267
  3. Display classification to user:
267
- If complexity found: "Previous evaluation classified this as [SIMPLE/COMPLEX]. Proceeding with [SIMPLE/COMPLEX] workflow."
268
+ If complexity found: "Previous evaluation classified this as [TRIVIAL/SIMPLE/COMPLEX]. Proceeding with [TRIVIAL/SIMPLE/COMPLEX] workflow."
268
269
  If not found: "No complexity classification found - defaulting to COMPLEX workflow."
269
270
  4. Proceed to ROUTING DECISION POINT with extracted complexity (no confirmation needed)
270
271
 
@@ -297,6 +298,12 @@ After STEP 1.5 completes and complexity is confirmed, determine which workflow p
297
298
 
298
299
  **Check the confirmed complexity:**
299
300
 
301
+ **IF TRIVIAL complexity confirmed:**
302
+ 1. Display to user: "Using TRIVIAL workflow: Skipping analysis and planning, proceeding directly to implementation"
303
+ 2. Mark todo #8 as completed
304
+ 3. Mark todos #9, #10, #11, #12, #13, #14, and #15 as completed (analysis/planning steps that will not execute)
305
+ 4. Skip directly to **STEP 4** (Implementation Phase)
306
+
300
307
  **IF SIMPLE complexity confirmed:**
301
308
  1. Display to user: "✓ Using SIMPLE workflow: Combined analysis and planning via @agent-iloom-issue-analyze-and-plan, then implementation"
302
309
  2. Mark todo #8 as completed
@@ -1,18 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  MergeManager
4
- } from "./chunk-IXKLYTWO.js";
4
+ } from "./chunk-2MAIX45J.js";
5
5
  import {
6
6
  GitWorktreeManager
7
- } from "./chunk-TSKY3JI7.js";
8
- import "./chunk-ZWFBBPJI.js";
7
+ } from "./chunk-2CXREBLZ.js";
9
8
  import {
10
- SettingsManager
11
- } from "./chunk-O5OH5MRX.js";
12
- import {
13
- getRepoRoot,
9
+ getWorktreeRoot,
14
10
  isValidGitRepo
15
- } from "./chunk-4BGK7T6X.js";
11
+ } from "./chunk-5Q3NDNNV.js";
12
+ import {
13
+ SettingsManager
14
+ } from "./chunk-CDZERT7Z.js";
15
+ import "./chunk-OYF4VIFI.js";
16
+ import "./chunk-RW54ZMBM.js";
17
+ import "./chunk-UJL4HI2R.js";
16
18
  import {
17
19
  logger
18
20
  } from "./chunk-GEHQXLEI.js";
@@ -45,15 +47,15 @@ var RebaseCommand = class {
45
47
  "Run 'il rebase' from within an iloom worktree created by 'il start'."
46
48
  );
47
49
  }
48
- const repoRoot = await getRepoRoot(currentDir);
49
- if (!repoRoot) {
50
+ const worktreeRoot = await getWorktreeRoot(currentDir);
51
+ if (!worktreeRoot) {
50
52
  throw new WorktreeValidationError(
51
53
  "Could not determine repository root.",
52
54
  "Run 'il rebase' from within an iloom worktree created by 'il start'."
53
55
  );
54
56
  }
55
57
  const worktrees = await this.gitWorktreeManager.listWorktrees();
56
- const currentWorktree = worktrees.find((wt) => wt.path === repoRoot);
58
+ const currentWorktree = worktrees.find((wt) => wt.path === worktreeRoot);
57
59
  if (!currentWorktree) {
58
60
  throw new WorktreeValidationError(
59
61
  "This directory is not an iloom worktree.",
@@ -67,7 +69,7 @@ var RebaseCommand = class {
67
69
  "Navigate to a feature worktree created by 'il start <issue>' and run 'il rebase' from there."
68
70
  );
69
71
  }
70
- return repoRoot;
72
+ return worktreeRoot;
71
73
  }
72
74
  async execute(options = {}) {
73
75
  let worktreePath;
@@ -92,4 +94,4 @@ export {
92
94
  RebaseCommand,
93
95
  WorktreeValidationError
94
96
  };
95
- //# sourceMappingURL=rebase-C4WNCVGM.js.map
97
+ //# sourceMappingURL=rebase-VJ2VKR6R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/rebase.ts"],"sourcesContent":["import { logger } from '../utils/logger.js'\nimport { MergeManager } from '../lib/MergeManager.js'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { isValidGitRepo, getWorktreeRoot } from '../utils/git.js'\nimport type { MergeOptions } from '../types/index.js'\n\nexport interface RebaseOptions {\n\tforce?: boolean\n\tdryRun?: boolean\n}\n\n/**\n * Error thrown when the rebase command is run from an invalid location\n */\nexport class WorktreeValidationError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly suggestion: string\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'WorktreeValidationError'\n\t}\n}\n\n/**\n * RebaseCommand: Rebase current branch on main with Claude-assisted conflict resolution\n *\n * This command:\n * 1. Validates the current directory is an iloom-managed worktree\n * 2. Detects the worktree root (supports running from subdirectories)\n * 3. Delegates to MergeManager.rebaseOnMain() which handles:\n * - Checking main branch exists\n * - Detecting uncommitted changes (throws if found)\n * - Checking if already up-to-date\n * - Executing rebase\n * - Claude-assisted conflict resolution\n * 4. Reports success\n */\nexport class RebaseCommand {\n\tprivate mergeManager: MergeManager\n\tprivate gitWorktreeManager: GitWorktreeManager\n\tprivate settingsManager: SettingsManager\n\n\tconstructor(mergeManager?: MergeManager, gitWorktreeManager?: GitWorktreeManager, settingsManager?: SettingsManager) {\n\t\tthis.mergeManager = mergeManager ?? new MergeManager()\n\t\tthis.gitWorktreeManager = gitWorktreeManager ?? new GitWorktreeManager()\n\t\tthis.settingsManager = settingsManager ?? new SettingsManager()\n\t}\n\n\t/**\n\t * Validate that the current directory is within an iloom-managed worktree\n\t * Returns the worktree root path if valid\n\t * @throws WorktreeValidationError if validation fails\n\t */\n\tprivate async validateWorktreeContext(): Promise<string> {\n\t\tconst currentDir = process.cwd()\n\n\t\t// Step 1: Check if we're in a git repository at all\n\t\tconst isGitRepo = await isValidGitRepo(currentDir)\n\t\tif (!isGitRepo) {\n\t\t\tthrow new WorktreeValidationError(\n\t\t\t\t'Not a git repository.',\n\t\t\t\t\"Run 'il rebase' from within an iloom worktree created by 'il start'.\"\n\t\t\t)\n\t\t}\n\n\t\t// Step 2: Get the worktree root (handles subdirectories)\n\t\tconst worktreeRoot = await getWorktreeRoot(currentDir)\n\t\tif (!worktreeRoot) {\n\t\t\tthrow new WorktreeValidationError(\n\t\t\t\t'Could not determine repository root.',\n\t\t\t\t\"Run 'il rebase' from within an iloom worktree created by 'il start'.\"\n\t\t\t)\n\t\t}\n\n\t\t// Step 3: Check if this path is a registered git worktree\n\t\tconst worktrees = await this.gitWorktreeManager.listWorktrees()\n\t\tconst currentWorktree = worktrees.find(wt => wt.path === worktreeRoot)\n\n\t\tif (!currentWorktree) {\n\t\t\tthrow new WorktreeValidationError(\n\t\t\t\t'This directory is not an iloom worktree.',\n\t\t\t\t\"Run 'il rebase' from within a worktree created by 'il start <issue>'. Use 'il list' to see available worktrees.\"\n\t\t\t)\n\t\t}\n\n\t\t// Step 4: Check if this is the main worktree (we shouldn't rebase from main)\n\t\tconst isMain = await this.gitWorktreeManager.isMainWorktree(currentWorktree, this.settingsManager)\n\t\tif (isMain) {\n\t\t\tthrow new WorktreeValidationError(\n\t\t\t\t'Cannot rebase from the main worktree.',\n\t\t\t\t\"Navigate to a feature worktree created by 'il start <issue>' and run 'il rebase' from there.\"\n\t\t\t)\n\t\t}\n\n\t\treturn worktreeRoot\n\t}\n\n\tasync execute(options: RebaseOptions = {}): Promise<void> {\n\t\t// Step 1: Validate we're in a valid iloom worktree\n\t\tlet worktreePath: string\n\t\ttry {\n\t\t\tworktreePath = await this.validateWorktreeContext()\n\t\t} catch (error) {\n\t\t\tif (error instanceof WorktreeValidationError) {\n\t\t\t\tlogger.error(error.message)\n\t\t\t\tlogger.info(error.suggestion)\n\t\t\t\tthrow error\n\t\t\t}\n\t\t\tthrow error\n\t\t}\n\n\t\tconst mergeOptions: MergeOptions = {\n\t\t\tdryRun: options.dryRun ?? false,\n\t\t\tforce: options.force ?? false,\n\t\t}\n\n\t\t// MergeManager.rebaseOnMain() handles:\n\t\t// - Checking main branch exists\n\t\t// - Detecting uncommitted changes (throws if found)\n\t\t// - Checking if already up-to-date\n\t\t// - Executing rebase\n\t\t// - Claude-assisted conflict resolution\n\t\tawait this.mergeManager.rebaseOnMain(worktreePath, mergeOptions)\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAeO,IAAM,0BAAN,cAAsC,MAAM;AAAA,EAClD,YACC,SACgB,YACf;AACD,UAAM,OAAO;AAFG;AAGhB,SAAK,OAAO;AAAA,EACb;AACD;AAgBO,IAAM,gBAAN,MAAoB;AAAA,EAK1B,YAAY,cAA6B,oBAAyC,iBAAmC;AACpH,SAAK,eAAe,gBAAgB,IAAI,aAAa;AACrD,SAAK,qBAAqB,sBAAsB,IAAI,mBAAmB;AACvE,SAAK,kBAAkB,mBAAmB,IAAI,gBAAgB;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,0BAA2C;AACxD,UAAM,aAAa,QAAQ,IAAI;AAG/B,UAAM,YAAY,MAAM,eAAe,UAAU;AACjD,QAAI,CAAC,WAAW;AACf,YAAM,IAAI;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAGA,UAAM,eAAe,MAAM,gBAAgB,UAAU;AACrD,QAAI,CAAC,cAAc;AAClB,YAAM,IAAI;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAGA,UAAM,YAAY,MAAM,KAAK,mBAAmB,cAAc;AAC9D,UAAM,kBAAkB,UAAU,KAAK,QAAM,GAAG,SAAS,YAAY;AAErE,QAAI,CAAC,iBAAiB;AACrB,YAAM,IAAI;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAGA,UAAM,SAAS,MAAM,KAAK,mBAAmB,eAAe,iBAAiB,KAAK,eAAe;AACjG,QAAI,QAAQ;AACX,YAAM,IAAI;AAAA,QACT;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA,EAEA,MAAM,QAAQ,UAAyB,CAAC,GAAkB;AAEzD,QAAI;AACJ,QAAI;AACH,qBAAe,MAAM,KAAK,wBAAwB;AAAA,IACnD,SAAS,OAAO;AACf,UAAI,iBAAiB,yBAAyB;AAC7C,eAAO,MAAM,MAAM,OAAO;AAC1B,eAAO,KAAK,MAAM,UAAU;AAC5B,cAAM;AAAA,MACP;AACA,YAAM;AAAA,IACP;AAEA,UAAM,eAA6B;AAAA,MAClC,QAAQ,QAAQ,UAAU;AAAA,MAC1B,OAAO,QAAQ,SAAS;AAAA,IACzB;AAQA,UAAM,KAAK,aAAa,aAAa,cAAc,YAAY;AAAA,EAChE;AACD;","names":[]}
@@ -4,10 +4,8 @@ import {
4
4
  } from "./chunk-MKWYLDFK.js";
5
5
  import "./chunk-ZM3CFL5L.js";
6
6
  import {
7
- IdentifierParser,
8
- extractPort,
9
- parseEnvFile
10
- } from "./chunk-IP7SMKIF.js";
7
+ IdentifierParser
8
+ } from "./chunk-OXAM2WVC.js";
11
9
  import {
12
10
  calculatePortForBranch
13
11
  } from "./chunk-VU3QMIP2.js";
@@ -16,7 +14,7 @@ import {
16
14
  } from "./chunk-YETJNRQM.js";
17
15
  import {
18
16
  GitWorktreeManager
19
- } from "./chunk-TSKY3JI7.js";
17
+ } from "./chunk-2CXREBLZ.js";
20
18
  import "./chunk-ZT3YZB4K.js";
21
19
  import {
22
20
  ProjectCapabilityDetector
@@ -25,12 +23,17 @@ import "./chunk-2ZPFJQ3B.js";
25
23
  import {
26
24
  extractSettingsOverrides
27
25
  } from "./chunk-GYCR2LOU.js";
26
+ import {
27
+ extractIssueNumber
28
+ } from "./chunk-5Q3NDNNV.js";
28
29
  import {
29
30
  SettingsManager
30
- } from "./chunk-O5OH5MRX.js";
31
+ } from "./chunk-CDZERT7Z.js";
31
32
  import {
32
- extractIssueNumber
33
- } from "./chunk-4BGK7T6X.js";
33
+ extractPort,
34
+ findEnvFileContainingVariable,
35
+ parseEnvFile
36
+ } from "./chunk-UJL4HI2R.js";
34
37
  import {
35
38
  logger
36
39
  } from "./chunk-GEHQXLEI.js";
@@ -227,24 +230,34 @@ Make sure the project is built (run 'il start' first)`
227
230
  logger.success("Browser opened");
228
231
  }
229
232
  /**
230
- * Get port for workspace - reads from .env or calculates based on workspace type
233
+ * Get port for workspace - reads from dotenv-flow files or calculates based on workspace type
231
234
  */
232
235
  async getWorkspacePort(worktreePath) {
233
236
  var _a, _b;
234
237
  const cliOverrides = extractSettingsOverrides();
235
238
  const settings = await this.settingsManager.loadSettings(void 0, cliOverrides);
236
239
  const basePort = ((_b = (_a = settings.capabilities) == null ? void 0 : _a.web) == null ? void 0 : _b.basePort) ?? 3e3;
237
- const envPath = path.join(worktreePath, ".env");
238
- if (await fs.pathExists(envPath)) {
240
+ const envFile = await findEnvFileContainingVariable(
241
+ worktreePath,
242
+ "PORT",
243
+ async (p) => fs.pathExists(p),
244
+ async (p, varName) => {
245
+ const content = await fs.readFile(p, "utf8");
246
+ const envMap = parseEnvFile(content);
247
+ return envMap.get(varName) ?? null;
248
+ }
249
+ );
250
+ if (envFile) {
251
+ const envPath = path.join(worktreePath, envFile);
239
252
  const envContent = await fs.readFile(envPath, "utf8");
240
253
  const envMap = parseEnvFile(envContent);
241
254
  const port2 = extractPort(envMap);
242
255
  if (port2) {
243
- logger.debug(`Using PORT from .env: ${port2}`);
256
+ logger.debug(`Using PORT from ${envFile}: ${port2}`);
244
257
  return port2;
245
258
  }
246
259
  }
247
- logger.debug("PORT not found in .env, calculating from workspace identifier");
260
+ logger.debug("PORT not found in any dotenv-flow file, calculating from workspace identifier");
248
261
  const worktrees = await this.gitWorktreeManager.listWorktrees();
249
262
  const worktree = worktrees.find((wt) => wt.path === worktreePath);
250
263
  if (!worktree) {
@@ -276,4 +289,4 @@ Make sure the project is built (run 'il start' first)`
276
289
  export {
277
290
  RunCommand
278
291
  };
279
- //# sourceMappingURL=run-IOGNIOYN.js.map
292
+ //# sourceMappingURL=run-MJYY4PUT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/run.ts"],"sourcesContent":["import path from 'path'\nimport fs from 'fs-extra'\nimport { execa } from 'execa'\nimport { GitWorktreeManager } from '../lib/GitWorktreeManager.js'\nimport { ProjectCapabilityDetector } from '../lib/ProjectCapabilityDetector.js'\nimport { DevServerManager } from '../lib/DevServerManager.js'\nimport { SettingsManager } from '../lib/SettingsManager.js'\nimport { IdentifierParser } from '../utils/IdentifierParser.js'\nimport { openBrowser } from '../utils/browser.js'\nimport { parseEnvFile, extractPort, findEnvFileContainingVariable } from '../utils/env.js'\nimport { calculatePortForBranch } from '../utils/port.js'\nimport { extractIssueNumber } from '../utils/git.js'\nimport { logger } from '../utils/logger.js'\nimport { extractSettingsOverrides } from '../utils/cli-overrides.js'\nimport type { GitWorktree } from '../types/worktree.js'\n\nexport interface RunCommandInput {\n\tidentifier?: string\n\targs?: string[]\n}\n\ninterface ParsedRunInput {\n\ttype: 'issue' | 'pr' | 'branch'\n\tnumber?: string | number // For issues and PRs\n\tbranchName?: string // For branches\n\toriginalInput: string\n\tautoDetected: boolean\n}\n\n/**\n * RunCommand - Runs CLI tool or opens workspace in browser\n * Priority: CLI first, Web fallback\n */\nexport class RunCommand {\n\tconstructor(\n\t\tprivate gitWorktreeManager = new GitWorktreeManager(),\n\t\tprivate capabilityDetector = new ProjectCapabilityDetector(),\n\t\tprivate identifierParser = new IdentifierParser(new GitWorktreeManager()),\n\t\tprivate devServerManager = new DevServerManager(),\n\t\tprivate settingsManager = new SettingsManager()\n\t) {}\n\n\tasync execute(input: RunCommandInput): Promise<void> {\n\t\t// 1. Parse or auto-detect identifier\n\t\tconst parsed = input.identifier\n\t\t\t? await this.parseExplicitInput(input.identifier)\n\t\t\t: await this.autoDetectFromCurrentDirectory()\n\n\t\tlogger.debug(`Parsed input: ${JSON.stringify(parsed)}`)\n\n\t\t// 2. Find worktree path based on identifier\n\t\tconst worktree = await this.findWorktreeForIdentifier(parsed)\n\n\t\tlogger.info(`Found worktree at: ${worktree.path}`)\n\n\t\t// 3. Detect project capabilities\n\t\tconst { capabilities, binEntries } =\n\t\t\tawait this.capabilityDetector.detectCapabilities(worktree.path)\n\n\t\tlogger.debug(`Detected capabilities: ${capabilities.join(', ')}`)\n\n\t\t// 4. Execute based on capabilities (CLI first, web fallback)\n\t\tif (capabilities.includes('cli')) {\n\t\t\tawait this.runCLITool(worktree.path, binEntries, input.args ?? [])\n\t\t} else if (capabilities.includes('web')) {\n\t\t\tawait this.openWebBrowser(worktree.path)\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`No CLI or web capabilities detected for workspace at ${worktree.path}`\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Parse explicit identifier input\n\t */\n\tprivate async parseExplicitInput(identifier: string): Promise<ParsedRunInput> {\n\t\tconst parsed = await this.identifierParser.parseForPatternDetection(identifier)\n\n\t\t// Description type should never reach run command (converted in start)\n\t\tif (parsed.type === 'description') {\n\t\t\tthrow new Error('Description input type is not supported in run command')\n\t\t}\n\n\t\tconst result: ParsedRunInput = {\n\t\t\ttype: parsed.type,\n\t\t\toriginalInput: parsed.originalInput,\n\t\t\tautoDetected: false,\n\t\t}\n\n\t\tif (parsed.number !== undefined) {\n\t\t\tresult.number = parsed.number\n\t\t}\n\t\tif (parsed.branchName !== undefined) {\n\t\t\tresult.branchName = parsed.branchName\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Auto-detect identifier from current directory\n\t * Same logic as FinishCommand.autoDetectFromCurrentDirectory()\n\t */\n\tprivate async autoDetectFromCurrentDirectory(): Promise<ParsedRunInput> {\n\t\tconst currentDir = path.basename(process.cwd())\n\n\t\t// Check for PR worktree pattern: _pr_N suffix\n\t\tconst prPattern = /_pr_(\\d+)$/\n\t\tconst prMatch = currentDir.match(prPattern)\n\n\t\tif (prMatch?.[1]) {\n\t\t\tconst prNumber = parseInt(prMatch[1], 10)\n\t\t\tlogger.debug(`Auto-detected PR #${prNumber} from directory: ${currentDir}`)\n\t\t\treturn {\n\t\t\t\ttype: 'pr',\n\t\t\t\tnumber: prNumber,\n\t\t\t\toriginalInput: currentDir,\n\t\t\t\tautoDetected: true,\n\t\t\t}\n\t\t}\n\n\t\t// Check for issue pattern in directory\n\t\tconst issueNumber = extractIssueNumber(currentDir)\n\n\t\tif (issueNumber !== null) {\n\t\t\tlogger.debug(`Auto-detected issue #${issueNumber} from directory: ${currentDir}`)\n\t\t\treturn {\n\t\t\t\ttype: 'issue',\n\t\t\t\tnumber: issueNumber,\n\t\t\t\toriginalInput: currentDir,\n\t\t\t\tautoDetected: true,\n\t\t\t}\n\t\t}\n\n\t\t// Fallback: get current branch name\n\t\tconst repoInfo = await this.gitWorktreeManager.getRepoInfo()\n\t\tconst currentBranch = repoInfo.currentBranch\n\n\t\tif (!currentBranch) {\n\t\t\tthrow new Error(\n\t\t\t\t'Could not auto-detect identifier. Please provide an issue number, PR number, or branch name.\\n' +\n\t\t\t\t\t'Expected directory pattern: feat/issue-XX-description OR worktree with _pr_N suffix'\n\t\t\t)\n\t\t}\n\n\t\t// Try to extract issue from branch name\n\t\tconst branchIssueNumber = extractIssueNumber(currentBranch)\n\t\tif (branchIssueNumber !== null) {\n\t\t\tlogger.debug(`Auto-detected issue #${branchIssueNumber} from branch: ${currentBranch}`)\n\t\t\treturn {\n\t\t\t\ttype: 'issue',\n\t\t\t\tnumber: branchIssueNumber,\n\t\t\t\toriginalInput: currentBranch,\n\t\t\t\tautoDetected: true,\n\t\t\t}\n\t\t}\n\n\t\t// Last resort: use branch name\n\t\treturn {\n\t\t\ttype: 'branch',\n\t\t\tbranchName: currentBranch,\n\t\t\toriginalInput: currentBranch,\n\t\t\tautoDetected: true,\n\t\t}\n\t}\n\n\t/**\n\t * Find worktree for the given identifier\n\t */\n\tprivate async findWorktreeForIdentifier(parsed: ParsedRunInput): Promise<GitWorktree> {\n\t\tlet worktree: GitWorktree | null = null\n\n\t\tif (parsed.type === 'issue' && parsed.number !== undefined) {\n\t\t\tworktree = await this.gitWorktreeManager.findWorktreeForIssue(parsed.number)\n\t\t} else if (parsed.type === 'pr' && parsed.number !== undefined) {\n\t\t\t// For PRs, ensure the number is numeric (PRs are always numeric per GitHub)\n\t\t\tconst prNumber = typeof parsed.number === 'number' ? parsed.number : Number(parsed.number)\n\t\t\tif (isNaN(prNumber) || !isFinite(prNumber)) {\n\t\t\t\tthrow new Error(`Invalid PR number: ${parsed.number}. PR numbers must be numeric.`)\n\t\t\t}\n\t\t\t// Pass empty string for branch name since we don't know it yet\n\t\t\tworktree = await this.gitWorktreeManager.findWorktreeForPR(prNumber, '')\n\t\t} else if (parsed.type === 'branch' && parsed.branchName) {\n\t\t\tworktree = await this.gitWorktreeManager.findWorktreeForBranch(\n\t\t\t\tparsed.branchName\n\t\t\t)\n\t\t}\n\n\t\tif (!worktree) {\n\t\t\tthrow new Error(\n\t\t\t\t`No worktree found for ${this.formatParsedInput(parsed)}. ` +\n\t\t\t\t\t`Run 'il start ${parsed.originalInput}' to create one.`\n\t\t\t)\n\t\t}\n\n\t\treturn worktree\n\t}\n\n\t/**\n\t * Format parsed input for display\n\t */\n\tprivate formatParsedInput(parsed: ParsedRunInput): string {\n\t\tconst autoLabel = parsed.autoDetected ? ' (auto-detected)' : ''\n\n\t\tif (parsed.type === 'issue') {\n\t\t\treturn `issue #${parsed.number}${autoLabel}`\n\t\t}\n\t\tif (parsed.type === 'pr') {\n\t\t\treturn `PR #${parsed.number}${autoLabel}`\n\t\t}\n\t\treturn `branch \"${parsed.branchName}\"${autoLabel}`\n\t}\n\n\t/**\n\t * Run CLI tool directly from worktree bin path (NO SYMLINKS!)\n\t */\n\tprivate async runCLITool(\n\t\tworktreePath: string,\n\t\tbinEntries: Record<string, string>,\n\t\targs: string[]\n\t): Promise<void> {\n\t\t// Validate binEntries exist\n\t\tif (Object.keys(binEntries).length === 0) {\n\t\t\tthrow new Error('No bin entries found in package.json')\n\t\t}\n\n\t\t// Get first bin entry (deterministic)\n\t\tconst firstEntry = Object.entries(binEntries)[0]\n\t\tif (!firstEntry) {\n\t\t\tthrow new Error('No bin entries found in package.json')\n\t\t}\n\t\tconst [binName, binPath] = firstEntry\n\t\tlogger.debug(`Using bin entry: ${binName} -> ${binPath}`)\n\n\t\t// CRITICAL: Construct absolute path (NO SYMLINKS!)\n\t\tconst binFilePath = path.resolve(worktreePath, binPath)\n\t\tlogger.debug(`Resolved bin file path: ${binFilePath}`)\n\n\t\t// Verify file exists\n\t\tif (!(await fs.pathExists(binFilePath))) {\n\t\t\tthrow new Error(\n\t\t\t\t`CLI executable not found: ${binFilePath}\\n` +\n\t\t\t\t\t`Make sure the project is built (run 'il start' first)`\n\t\t\t)\n\t\t}\n\n\t\t// Execute with Node.js\n\t\tlogger.info(`Running CLI: node ${binFilePath} ${args.join(' ')}`)\n\t\tawait execa('node', [binFilePath, ...args], {\n\t\t\tstdio: 'inherit', // Allow interactive CLIs (prompts, colors, etc.)\n\t\t\tcwd: worktreePath, // Execute in worktree context\n\t\t\tenv: process.env, // Inherit environment\n\t\t})\n\t}\n\n\t/**\n\t * Open web browser with workspace URL\n\t * Auto-starts dev server if not already running\n\t */\n\tprivate async openWebBrowser(worktreePath: string): Promise<void> {\n\t\tconst port = await this.getWorkspacePort(worktreePath)\n\n\t\t// Ensure dev server is running on the port\n\t\tconst serverReady = await this.devServerManager.ensureServerRunning(\n\t\t\tworktreePath,\n\t\t\tport\n\t\t)\n\n\t\tif (!serverReady) {\n\t\t\tlogger.warn(\n\t\t\t\t`Dev server failed to start on port ${port}. Opening browser anyway...`\n\t\t\t)\n\t\t}\n\n\t\t// Construct URL and open browser\n\t\tconst url = `http://localhost:${port}`\n\t\tlogger.info(`Opening browser: ${url}`)\n\t\tawait openBrowser(url)\n\t\tlogger.success('Browser opened')\n\t}\n\n\t/**\n\t * Get port for workspace - reads from dotenv-flow files or calculates based on workspace type\n\t */\n\tprivate async getWorkspacePort(worktreePath: string): Promise<number> {\n\t\t// Load base port from settings with CLI overrides\n\t\tconst cliOverrides = extractSettingsOverrides()\n\t\tconst settings = await this.settingsManager.loadSettings(undefined, cliOverrides)\n\t\tconst basePort = settings.capabilities?.web?.basePort ?? 3000\n\n\t\t// Try to read PORT from any dotenv-flow file (as override)\n\t\tconst envFile = await findEnvFileContainingVariable(\n\t\t\tworktreePath,\n\t\t\t'PORT',\n\t\t\tasync (p) => fs.pathExists(p),\n\t\t\tasync (p, varName) => {\n\t\t\t\tconst content = await fs.readFile(p, 'utf8')\n\t\t\t\tconst envMap = parseEnvFile(content)\n\t\t\t\treturn envMap.get(varName) ?? null\n\t\t\t}\n\t\t)\n\n\t\tif (envFile) {\n\t\t\tconst envPath = path.join(worktreePath, envFile)\n\t\t\tconst envContent = await fs.readFile(envPath, 'utf8')\n\t\t\tconst envMap = parseEnvFile(envContent)\n\t\t\tconst port = extractPort(envMap)\n\n\t\t\tif (port) {\n\t\t\t\tlogger.debug(`Using PORT from ${envFile}: ${port}`)\n\t\t\t\treturn port\n\t\t\t}\n\t\t}\n\n\t\t// PORT not in any dotenv-flow file, calculate based on workspace identifier\n\t\tlogger.debug('PORT not found in any dotenv-flow file, calculating from workspace identifier')\n\n\t\t// Get worktree to determine type\n\t\tconst worktrees = await this.gitWorktreeManager.listWorktrees()\n\t\tconst worktree = worktrees.find(wt => wt.path === worktreePath)\n\n\t\tif (!worktree) {\n\t\t\tthrow new Error(`Could not find worktree for path: ${worktreePath}`)\n\t\t}\n\n\t\t// Extract identifier from worktree path/branch\n\t\tconst dirName = path.basename(worktreePath)\n\n\t\t// Check for PR pattern: _pr_N\n\t\tconst prPattern = /_pr_(\\d+)$/\n\t\tconst prMatch = dirName.match(prPattern)\n\t\tif (prMatch?.[1]) {\n\t\t\tconst prNumber = parseInt(prMatch[1], 10)\n\t\t\tconst port = basePort + prNumber\n\t\t\tlogger.debug(`Calculated PORT for PR #${prNumber}: ${port}`)\n\t\t\treturn port\n\t\t}\n\n\t\t// Check for issue pattern: issue-N\n\t\tconst issueId = extractIssueNumber(dirName) ?? extractIssueNumber(worktree.branch)\n\t\tif (issueId !== null) {\n\t\t\tconst issueNumber = parseInt(issueId, 10)\n\t\t\tif (!isNaN(issueNumber)) {\n\t\t\t\tconst port = basePort + issueNumber\n\t\t\t\tlogger.debug(`Calculated PORT for issue #${issueId}: ${port}`)\n\t\t\t\treturn port\n\t\t\t}\n\t\t\t// For alphanumeric IDs, fall through to branch-based hash\n\t\t}\n\n\t\t// Branch-based workspace - use deterministic hash\n\t\tconst port = calculatePortForBranch(worktree.branch, basePort)\n\t\tlogger.debug(`Calculated PORT for branch \"${worktree.branch}\": ${port}`)\n\t\treturn port\n\t}\n}\n"],"mappings":"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","names":["port"]}
@@ -12,7 +12,7 @@
12
12
  "sourceEnvOnStart": {
13
13
  "type": "boolean",
14
14
  "default": false,
15
- "description": "Source .env file when launching terminal processes (Claude, dev server, terminal). NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env compatibility. WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. Before enabling, verify your .env file does not contain unquoted special characters (e.g., database URLs with ?, &, or other shell metacharacters). Shell compatibility issues may cause processes to fail or behave unexpectedly."
15
+ "description": "Source all dotenv-flow files (.env, .env.local, .env.development, .env.development.local) when launching terminal processes (Claude, dev server, terminal). Files are sourced in precedence order so later files override earlier ones. NOTE TO AI AGENTS: Before making changes to settings files, YOU MUST OFFER to check .env file compatibility. WARNING: Unquoted values in .env files may break sourcing in bash/zsh shells. Before enabling, verify ALL your .env.* files do not contain unquoted special characters (e.g., database URLs with ?, &, or other shell metacharacters). Shell compatibility issues may cause processes to fail or behave unexpectedly."
16
16
  },
17
17
  "worktreePrefix": {
18
18
  "type": "string",
@@ -328,14 +328,32 @@
328
328
  "webstorm",
329
329
  "sublime",
330
330
  "intellij",
331
- "windsurf"
331
+ "windsurf",
332
+ "antigravity"
332
333
  ],
333
334
  "default": "vscode",
334
- "description": "IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), windsurf (Windsurf editor)."
335
+ "description": "IDE to launch when starting a loom. Options: vscode (Visual Studio Code), cursor (Cursor AI editor), webstorm (JetBrains WebStorm), sublime (Sublime Text), intellij (JetBrains IntelliJ IDEA), windsurf (Windsurf editor), antigravity (Antigravity IDE)."
335
336
  }
336
337
  },
337
338
  "additionalProperties": false,
338
- "description": "IDE configuration for workspace launches. Controls which editor opens when you start a loom. Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, and Windsurf. Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf)."
339
+ "description": "IDE configuration for workspace launches. Controls which editor opens when you start a loom. Supports VSCode, Cursor, WebStorm, Sublime Text, IntelliJ, Windsurf, and Antigravity. Note: Color synchronization (title bar colors) only works with VSCode-compatible editors (vscode, cursor, windsurf, antigravity)."
340
+ },
341
+ "colors": {
342
+ "type": "object",
343
+ "properties": {
344
+ "terminal": {
345
+ "type": "boolean",
346
+ "default": true,
347
+ "description": "Apply terminal background colors based on branch name (macOS only)"
348
+ },
349
+ "vscode": {
350
+ "type": "boolean",
351
+ "default": false,
352
+ "description": "Apply VSCode/Cursor title bar colors based on branch name. Note: This modifies .vscode/settings.json which may be in source control. Default is false for safety; enable via init or explicitly if .vscode is gitignored."
353
+ }
354
+ },
355
+ "additionalProperties": false,
356
+ "description": "Color synchronization settings for workspace identification"
339
357
  }
340
358
  },
341
359
  "additionalProperties": false
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- SettingsManager
4
- } from "./chunk-O5OH5MRX.js";
5
2
  import {
6
3
  findMainWorktreePath
7
- } from "./chunk-4BGK7T6X.js";
4
+ } from "./chunk-5Q3NDNNV.js";
5
+ import {
6
+ SettingsManager
7
+ } from "./chunk-CDZERT7Z.js";
8
8
  import {
9
9
  logger
10
10
  } from "./chunk-GEHQXLEI.js";
@@ -49,4 +49,4 @@ var TestGitCommand = class {
49
49
  export {
50
50
  TestGitCommand
51
51
  };
52
- //# sourceMappingURL=test-git-J7I5MFYH.js.map
52
+ //# sourceMappingURL=test-git-IT5EWQ5C.js.map
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- SettingsManager
4
- } from "./chunk-O5OH5MRX.js";
5
2
  import {
6
3
  generateWorktreePath
7
- } from "./chunk-4BGK7T6X.js";
4
+ } from "./chunk-5Q3NDNNV.js";
5
+ import {
6
+ SettingsManager
7
+ } from "./chunk-CDZERT7Z.js";
8
8
  import {
9
9
  logger
10
10
  } from "./chunk-GEHQXLEI.js";
@@ -65,4 +65,4 @@ var TestPrefixCommand = class {
65
65
  export {
66
66
  TestPrefixCommand
67
67
  };
68
- //# sourceMappingURL=test-prefix-ZCONBCBX.js.map
68
+ //# sourceMappingURL=test-prefix-NPWDPUUH.js.map
@@ -2,7 +2,8 @@
2
2
  import {
3
3
  detectITerm2,
4
4
  openMultipleTerminalWindows
5
- } from "./chunk-ZE74H5BR.js";
5
+ } from "./chunk-RW54ZMBM.js";
6
+ import "./chunk-UJL4HI2R.js";
6
7
  import {
7
8
  logger
8
9
  } from "./chunk-GEHQXLEI.js";
@@ -66,4 +67,4 @@ var TestTabsCommand = class {
66
67
  export {
67
68
  TestTabsCommand
68
69
  };
69
- //# sourceMappingURL=test-tabs-RXDBZ6J7.js.map
70
+ //# sourceMappingURL=test-tabs-PRMRSHKI.js.map