@iloom/cli 0.6.0 → 0.7.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.
- package/LICENSE +1 -1
- package/README.md +58 -16
- package/dist/{BranchNamingService-B5PVRR7F.js → BranchNamingService-FLPUUFOB.js} +2 -2
- package/dist/ClaudeContextManager-KE5TBZVZ.js +14 -0
- package/dist/ClaudeService-CRSETT3A.js +13 -0
- package/dist/{GitHubService-S2OGUTDR.js → GitHubService-O7U4UQ7N.js} +3 -3
- package/dist/{LoomLauncher-5LFM4LXB.js → LoomLauncher-NL65LSKP.js} +6 -6
- package/dist/{MetadataManager-DFI73J3G.js → MetadataManager-XJ2YB762.js} +2 -2
- package/dist/PRManager-2ABCWXHW.js +16 -0
- package/dist/{ProjectCapabilityDetector-S5FLNCFI.js → ProjectCapabilityDetector-UZYW32SY.js} +3 -3
- package/dist/{PromptTemplateManager-C3DK6XZL.js → PromptTemplateManager-7L3HJQQU.js} +2 -2
- package/dist/README.md +58 -16
- package/dist/{SettingsManager-35F5RUJH.js → SettingsManager-YU4VYPTW.js} +2 -2
- package/dist/agents/iloom-issue-analyze-and-plan.md +42 -17
- package/dist/agents/iloom-issue-analyzer.md +14 -14
- package/dist/agents/iloom-issue-complexity-evaluator.md +38 -15
- package/dist/agents/iloom-issue-enhancer.md +15 -15
- package/dist/agents/iloom-issue-implementer.md +44 -15
- package/dist/agents/iloom-issue-planner.md +121 -17
- package/dist/agents/iloom-issue-reviewer.md +15 -15
- package/dist/{build-FJVYP7EV.js → build-O2EJHDEW.js} +9 -9
- package/dist/{chunk-ZPSTA5PR.js → chunk-3CDWFEGL.js} +2 -2
- package/dist/{chunk-VU3QMIP2.js → chunk-453NC377.js} +91 -15
- package/dist/chunk-453NC377.js.map +1 -0
- package/dist/{chunk-UQIXZ3BA.js → chunk-5V74K5ZA.js} +2 -2
- package/dist/{chunk-7WANFUIK.js → chunk-6TL3BYH6.js} +2 -2
- package/dist/{chunk-5TXLVEXT.js → chunk-C3AKFAIR.js} +2 -2
- package/dist/{chunk-K7SEEHKO.js → chunk-CNSTXBJ3.js} +7 -419
- package/dist/chunk-CNSTXBJ3.js.map +1 -0
- package/dist/{chunk-5IWU3HXE.js → chunk-EPPPDVHD.js} +23 -11
- package/dist/chunk-EPPPDVHD.js.map +1 -0
- package/dist/{chunk-UB4TFAXJ.js → chunk-FEAJR6PN.js} +9 -55
- package/dist/chunk-FEAJR6PN.js.map +1 -0
- package/dist/{chunk-6YSFTPKW.js → chunk-FM4KBPVA.js} +18 -13
- package/dist/chunk-FM4KBPVA.js.map +1 -0
- package/dist/{chunk-AEIMYF4P.js → chunk-FP7G7DG3.js} +6 -2
- package/dist/chunk-FP7G7DG3.js.map +1 -0
- package/dist/{chunk-LT3SGBR7.js → chunk-GCPAZSGV.js} +36 -2
- package/dist/{chunk-LT3SGBR7.js.map → chunk-GCPAZSGV.js.map} +1 -1
- package/dist/chunk-GJMEKEI5.js +517 -0
- package/dist/chunk-GJMEKEI5.js.map +1 -0
- package/dist/{chunk-64O2UIWO.js → chunk-GV5X6XUE.js} +4 -4
- package/dist/{chunk-7Q66W4OH.js → chunk-HBJITKSZ.js} +37 -1
- package/dist/chunk-HBJITKSZ.js.map +1 -0
- package/dist/{chunk-7HIRPCKU.js → chunk-HVQNVRAF.js} +2 -2
- package/dist/{chunk-BXCPJJYM.js → chunk-ITN64ENQ.js} +1 -1
- package/dist/chunk-ITN64ENQ.js.map +1 -0
- package/dist/{chunk-6U6VI4SZ.js → chunk-KVS4XGBQ.js} +4 -4
- package/dist/{chunk-AXX3QIKK.js → chunk-LLWX3PCW.js} +2 -2
- package/dist/{chunk-WIJWIKAN.js → chunk-LQBLDI47.js} +105 -7
- package/dist/chunk-LQBLDI47.js.map +1 -0
- package/dist/{chunk-SN3Z6EZO.js → chunk-N7FVXZNI.js} +2 -2
- package/dist/chunk-NTIZLX42.js +822 -0
- package/dist/chunk-NTIZLX42.js.map +1 -0
- package/dist/{chunk-PMVWQBWS.js → chunk-S7YMZQUD.js} +31 -45
- package/dist/chunk-S7YMZQUD.js.map +1 -0
- package/dist/chunk-TIYJEEVO.js +79 -0
- package/dist/chunk-TIYJEEVO.js.map +1 -0
- package/dist/{chunk-EK3XCAAS.js → chunk-UDRZY65Y.js} +2 -2
- package/dist/{chunk-3PT7RKL5.js → chunk-USJSNHGG.js} +2 -2
- package/dist/{chunk-CFUWQHCJ.js → chunk-VWGKGNJP.js} +114 -35
- package/dist/chunk-VWGKGNJP.js.map +1 -0
- package/dist/{chunk-F6WVM437.js → chunk-WFQ5CLTR.js} +6 -3
- package/dist/chunk-WFQ5CLTR.js.map +1 -0
- package/dist/{chunk-TRQ76ISK.js → chunk-Z6BO53V7.js} +9 -9
- package/dist/{chunk-GEXP5IOF.js → chunk-ZA575VLF.js} +21 -8
- package/dist/chunk-ZA575VLF.js.map +1 -0
- package/dist/{claude-H33OQMXO.js → claude-6H36IBHO.js} +4 -2
- package/dist/{cleanup-OU2HFOOG.js → cleanup-ZPOMRSNN.js} +20 -16
- package/dist/cleanup-ZPOMRSNN.js.map +1 -0
- package/dist/cli.js +511 -959
- package/dist/cli.js.map +1 -1
- package/dist/commit-6S2RIA2K.js +237 -0
- package/dist/commit-6S2RIA2K.js.map +1 -0
- package/dist/{compile-ULNO5F7Q.js → compile-LRMAADUT.js} +9 -9
- package/dist/{contribute-T7ENST5N.js → contribute-GXKOIA42.js} +99 -31
- package/dist/contribute-GXKOIA42.js.map +1 -0
- package/dist/{dev-server-4RCDJ5MU.js → dev-server-GREJUEKW.js} +22 -74
- package/dist/dev-server-GREJUEKW.js.map +1 -0
- package/dist/{feedback-O4Q55SVS.js → feedback-G7G5QCY4.js} +10 -10
- package/dist/{git-FVMGBHC2.js → git-ENLT2VNI.js} +6 -4
- package/dist/hooks/iloom-hook.js +30 -2
- package/dist/{ignite-VHV65WEZ.js → ignite-YUAOJ5PP.js} +20 -20
- package/dist/ignite-YUAOJ5PP.js.map +1 -0
- package/dist/index.d.ts +71 -27
- package/dist/index.js +196 -266
- package/dist/index.js.map +1 -1
- package/dist/init-XQQMFDM6.js +21 -0
- package/dist/{lint-5JMCWE4Y.js → lint-OFVN7FT6.js} +9 -9
- package/dist/mcp/issue-management-server.js +359 -13
- package/dist/mcp/issue-management-server.js.map +1 -1
- package/dist/mcp/recap-server.js +13 -4
- package/dist/mcp/recap-server.js.map +1 -1
- package/dist/{open-WHVUYGPY.js → open-MCWQAPSZ.js} +25 -76
- package/dist/open-MCWQAPSZ.js.map +1 -0
- package/dist/{projects-SA76I4TZ.js → projects-PQOTWUII.js} +11 -4
- package/dist/projects-PQOTWUII.js.map +1 -0
- package/dist/prompts/init-prompt.txt +63 -59
- package/dist/prompts/issue-prompt.txt +132 -63
- package/dist/prompts/pr-prompt.txt +3 -3
- package/dist/prompts/regular-prompt.txt +16 -18
- package/dist/prompts/session-summary-prompt.txt +13 -13
- package/dist/{rebase-5EY3Q6XP.js → rebase-RKQED567.js} +53 -8
- package/dist/rebase-RKQED567.js.map +1 -0
- package/dist/{recap-VOOUXOGP.js → recap-ZKGHZCX6.js} +6 -6
- package/dist/{run-NCRK5NPR.js → run-CCG24PBC.js} +25 -76
- package/dist/run-CCG24PBC.js.map +1 -0
- package/dist/schema/settings.schema.json +14 -3
- package/dist/{shell-SBLXVOVJ.js → shell-2NNSIU34.js} +6 -6
- package/dist/{summary-CVFAMDOJ.js → summary-G6L3VAKK.js} +11 -10
- package/dist/{summary-CVFAMDOJ.js.map → summary-G6L3VAKK.js.map} +1 -1
- package/dist/{test-3KIVXI6J.js → test-QZDOEUIO.js} +9 -9
- package/dist/{test-git-ZB6AGGRW.js → test-git-E2BLXR6M.js} +4 -4
- package/dist/{test-prefix-FBGXKMPA.js → test-prefix-A7JGGYAA.js} +4 -4
- package/dist/{test-webserver-YVQD42W6.js → test-webserver-NRMGT2HB.js} +29 -8
- package/dist/test-webserver-NRMGT2HB.js.map +1 -0
- package/package.json +3 -1
- package/dist/ClaudeContextManager-6J2EB4QU.js +0 -14
- package/dist/ClaudeService-O2PB22GX.js +0 -13
- package/dist/PRManager-OCSB2HPT.js +0 -14
- package/dist/chunk-5IWU3HXE.js.map +0 -1
- package/dist/chunk-6YSFTPKW.js.map +0 -1
- package/dist/chunk-7Q66W4OH.js.map +0 -1
- package/dist/chunk-AEIMYF4P.js.map +0 -1
- package/dist/chunk-BXCPJJYM.js.map +0 -1
- package/dist/chunk-CFUWQHCJ.js.map +0 -1
- package/dist/chunk-F6WVM437.js.map +0 -1
- package/dist/chunk-GEXP5IOF.js.map +0 -1
- package/dist/chunk-K7SEEHKO.js.map +0 -1
- package/dist/chunk-PMVWQBWS.js.map +0 -1
- package/dist/chunk-UB4TFAXJ.js.map +0 -1
- package/dist/chunk-VU3QMIP2.js.map +0 -1
- package/dist/chunk-W6WVRHJ6.js +0 -251
- package/dist/chunk-W6WVRHJ6.js.map +0 -1
- package/dist/chunk-WIJWIKAN.js.map +0 -1
- package/dist/cleanup-OU2HFOOG.js.map +0 -1
- package/dist/contribute-T7ENST5N.js.map +0 -1
- package/dist/dev-server-4RCDJ5MU.js.map +0 -1
- package/dist/ignite-VHV65WEZ.js.map +0 -1
- package/dist/init-HB34Q5FH.js +0 -21
- package/dist/open-WHVUYGPY.js.map +0 -1
- package/dist/projects-SA76I4TZ.js.map +0 -1
- package/dist/rebase-5EY3Q6XP.js.map +0 -1
- package/dist/run-NCRK5NPR.js.map +0 -1
- package/dist/test-webserver-YVQD42W6.js.map +0 -1
- /package/dist/{BranchNamingService-B5PVRR7F.js.map → BranchNamingService-FLPUUFOB.js.map} +0 -0
- /package/dist/{ClaudeContextManager-6J2EB4QU.js.map → ClaudeContextManager-KE5TBZVZ.js.map} +0 -0
- /package/dist/{ClaudeService-O2PB22GX.js.map → ClaudeService-CRSETT3A.js.map} +0 -0
- /package/dist/{GitHubService-S2OGUTDR.js.map → GitHubService-O7U4UQ7N.js.map} +0 -0
- /package/dist/{LoomLauncher-5LFM4LXB.js.map → LoomLauncher-NL65LSKP.js.map} +0 -0
- /package/dist/{MetadataManager-DFI73J3G.js.map → MetadataManager-XJ2YB762.js.map} +0 -0
- /package/dist/{PRManager-OCSB2HPT.js.map → PRManager-2ABCWXHW.js.map} +0 -0
- /package/dist/{ProjectCapabilityDetector-S5FLNCFI.js.map → ProjectCapabilityDetector-UZYW32SY.js.map} +0 -0
- /package/dist/{PromptTemplateManager-C3DK6XZL.js.map → PromptTemplateManager-7L3HJQQU.js.map} +0 -0
- /package/dist/{SettingsManager-35F5RUJH.js.map → SettingsManager-YU4VYPTW.js.map} +0 -0
- /package/dist/{build-FJVYP7EV.js.map → build-O2EJHDEW.js.map} +0 -0
- /package/dist/{chunk-ZPSTA5PR.js.map → chunk-3CDWFEGL.js.map} +0 -0
- /package/dist/{chunk-UQIXZ3BA.js.map → chunk-5V74K5ZA.js.map} +0 -0
- /package/dist/{chunk-7WANFUIK.js.map → chunk-6TL3BYH6.js.map} +0 -0
- /package/dist/{chunk-5TXLVEXT.js.map → chunk-C3AKFAIR.js.map} +0 -0
- /package/dist/{chunk-64O2UIWO.js.map → chunk-GV5X6XUE.js.map} +0 -0
- /package/dist/{chunk-7HIRPCKU.js.map → chunk-HVQNVRAF.js.map} +0 -0
- /package/dist/{chunk-6U6VI4SZ.js.map → chunk-KVS4XGBQ.js.map} +0 -0
- /package/dist/{chunk-AXX3QIKK.js.map → chunk-LLWX3PCW.js.map} +0 -0
- /package/dist/{chunk-SN3Z6EZO.js.map → chunk-N7FVXZNI.js.map} +0 -0
- /package/dist/{chunk-EK3XCAAS.js.map → chunk-UDRZY65Y.js.map} +0 -0
- /package/dist/{chunk-3PT7RKL5.js.map → chunk-USJSNHGG.js.map} +0 -0
- /package/dist/{chunk-TRQ76ISK.js.map → chunk-Z6BO53V7.js.map} +0 -0
- /package/dist/{claude-H33OQMXO.js.map → claude-6H36IBHO.js.map} +0 -0
- /package/dist/{compile-ULNO5F7Q.js.map → compile-LRMAADUT.js.map} +0 -0
- /package/dist/{feedback-O4Q55SVS.js.map → feedback-G7G5QCY4.js.map} +0 -0
- /package/dist/{git-FVMGBHC2.js.map → git-ENLT2VNI.js.map} +0 -0
- /package/dist/{init-HB34Q5FH.js.map → init-XQQMFDM6.js.map} +0 -0
- /package/dist/{lint-5JMCWE4Y.js.map → lint-OFVN7FT6.js.map} +0 -0
- /package/dist/{recap-VOOUXOGP.js.map → recap-ZKGHZCX6.js.map} +0 -0
- /package/dist/{shell-SBLXVOVJ.js.map → shell-2NNSIU34.js.map} +0 -0
- /package/dist/{test-3KIVXI6J.js.map → test-QZDOEUIO.js.map} +0 -0
- /package/dist/{test-git-ZB6AGGRW.js.map → test-git-E2BLXR6M.js.map} +0 -0
- /package/dist/{test-prefix-FBGXKMPA.js.map → test-prefix-A7JGGYAA.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SessionSummaryService
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-CNSTXBJ3.js";
|
|
5
5
|
import "./chunk-NXMDEL3F.js";
|
|
6
6
|
import {
|
|
7
7
|
CLIIsolationManager,
|
|
@@ -9,30 +9,28 @@ import {
|
|
|
9
9
|
EnvironmentManager,
|
|
10
10
|
LoomManager,
|
|
11
11
|
ResourceCleanup
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-S7YMZQUD.js";
|
|
13
|
+
import {
|
|
14
|
+
BuildRunner,
|
|
15
|
+
MergeManager
|
|
16
|
+
} from "./chunk-LQBLDI47.js";
|
|
13
17
|
import {
|
|
14
18
|
IssueTrackerFactory,
|
|
15
19
|
generateIssueManagementMcpConfig
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-7Q66W4OH.js";
|
|
20
|
+
} from "./chunk-FM4KBPVA.js";
|
|
18
21
|
import {
|
|
19
22
|
ProcessManager
|
|
20
|
-
} from "./chunk-
|
|
21
|
-
import {
|
|
22
|
-
detectPackageManager,
|
|
23
|
-
installDependencies,
|
|
24
|
-
runScript
|
|
25
|
-
} from "./chunk-AXX3QIKK.js";
|
|
23
|
+
} from "./chunk-453NC377.js";
|
|
26
24
|
import {
|
|
27
25
|
IdentifierParser
|
|
28
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-5V74K5ZA.js";
|
|
29
27
|
import {
|
|
30
28
|
createNeonProviderFromSettings
|
|
31
29
|
} from "./chunk-7LSSNB7Y.js";
|
|
32
30
|
import {
|
|
33
31
|
InitCommand,
|
|
34
32
|
ShellCompletion
|
|
35
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-FEAJR6PN.js";
|
|
36
34
|
import {
|
|
37
35
|
FirstRunManager
|
|
38
36
|
} from "./chunk-Q7POFB5Q.js";
|
|
@@ -40,29 +38,35 @@ import "./chunk-F2PWIRV4.js";
|
|
|
40
38
|
import {
|
|
41
39
|
IssueEnhancementService,
|
|
42
40
|
capitalizeFirstLetter
|
|
43
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-HVQNVRAF.js";
|
|
44
42
|
import {
|
|
45
43
|
ProjectCapabilityDetector
|
|
46
|
-
} from "./chunk-
|
|
47
|
-
import {
|
|
48
|
-
getPackageConfig,
|
|
49
|
-
hasScript
|
|
50
|
-
} from "./chunk-BXCPJJYM.js";
|
|
44
|
+
} from "./chunk-3CDWFEGL.js";
|
|
51
45
|
import {
|
|
52
46
|
AgentManager
|
|
53
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-N7FVXZNI.js";
|
|
54
48
|
import {
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
CommitManager,
|
|
50
|
+
UserAbortedCommitError,
|
|
51
|
+
ValidationRunner
|
|
52
|
+
} from "./chunk-NTIZLX42.js";
|
|
53
|
+
import {
|
|
54
|
+
installDependencies
|
|
55
|
+
} from "./chunk-LLWX3PCW.js";
|
|
57
56
|
import {
|
|
58
57
|
GitWorktreeManager
|
|
59
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-UDRZY65Y.js";
|
|
59
|
+
import "./chunk-ITN64ENQ.js";
|
|
60
60
|
import {
|
|
61
61
|
PRManager
|
|
62
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-EPPPDVHD.js";
|
|
63
63
|
import {
|
|
64
64
|
openBrowser
|
|
65
65
|
} from "./chunk-YETJNRQM.js";
|
|
66
|
+
import {
|
|
67
|
+
IssueManagementProviderFactory
|
|
68
|
+
} from "./chunk-GJMEKEI5.js";
|
|
69
|
+
import "./chunk-HBJITKSZ.js";
|
|
66
70
|
import {
|
|
67
71
|
getConfiguredRepoFromSettings,
|
|
68
72
|
hasMultipleRemotes
|
|
@@ -74,16 +78,17 @@ import {
|
|
|
74
78
|
} from "./chunk-O7VL5N6S.js";
|
|
75
79
|
import {
|
|
76
80
|
ClaudeContextManager
|
|
77
|
-
} from "./chunk-
|
|
78
|
-
import "./chunk-
|
|
79
|
-
import "./chunk-
|
|
81
|
+
} from "./chunk-6TL3BYH6.js";
|
|
82
|
+
import "./chunk-KVS4XGBQ.js";
|
|
83
|
+
import "./chunk-TIYJEEVO.js";
|
|
80
84
|
import {
|
|
81
85
|
extractSettingsOverrides
|
|
82
86
|
} from "./chunk-GYCR2LOU.js";
|
|
83
87
|
import {
|
|
84
88
|
DefaultBranchNamingService
|
|
85
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-C3AKFAIR.js";
|
|
86
90
|
import {
|
|
91
|
+
GitCommandError,
|
|
87
92
|
executeGitCommand,
|
|
88
93
|
extractIssueNumber,
|
|
89
94
|
findMainWorktreePathWithSettings,
|
|
@@ -91,30 +96,29 @@ import {
|
|
|
91
96
|
getMergeTargetBranch,
|
|
92
97
|
getRepoRoot,
|
|
93
98
|
isPlaceholderCommit,
|
|
99
|
+
isValidGitRepo,
|
|
94
100
|
pushBranchToRemote,
|
|
95
101
|
removePlaceholderCommitFromHead,
|
|
96
102
|
removePlaceholderCommitFromHistory
|
|
97
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-ZA575VLF.js";
|
|
98
104
|
import {
|
|
99
105
|
SettingsManager
|
|
100
|
-
} from "./chunk-
|
|
106
|
+
} from "./chunk-WFQ5CLTR.js";
|
|
101
107
|
import {
|
|
102
108
|
MetadataManager
|
|
103
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-VWGKGNJP.js";
|
|
104
110
|
import {
|
|
105
111
|
GitHubService
|
|
106
|
-
} from "./chunk-
|
|
107
|
-
import "./chunk-
|
|
112
|
+
} from "./chunk-USJSNHGG.js";
|
|
113
|
+
import "./chunk-GCPAZSGV.js";
|
|
108
114
|
import {
|
|
109
|
-
promptCommitAction,
|
|
110
115
|
promptConfirmation,
|
|
111
116
|
waitForKeypress
|
|
112
117
|
} from "./chunk-ZX3GTM7O.js";
|
|
113
118
|
import "./chunk-433MOLAU.js";
|
|
114
119
|
import {
|
|
115
|
-
detectClaudeCli,
|
|
116
120
|
launchClaude
|
|
117
|
-
} from "./chunk-
|
|
121
|
+
} from "./chunk-FP7G7DG3.js";
|
|
118
122
|
import {
|
|
119
123
|
getLogger,
|
|
120
124
|
withLogger
|
|
@@ -687,7 +691,8 @@ var EnhanceCommand = class {
|
|
|
687
691
|
"mcp__issue_management__get_issue",
|
|
688
692
|
"mcp__issue_management__get_comment",
|
|
689
693
|
"mcp__issue_management__create_comment",
|
|
690
|
-
"mcp__issue_management__update_comment"
|
|
694
|
+
"mcp__issue_management__update_comment",
|
|
695
|
+
"mcp__issue_management__create_issue"
|
|
691
696
|
];
|
|
692
697
|
disallowedTools = ["Bash(gh api:*)"];
|
|
693
698
|
getLogger().debug("Configured tool filtering for issue workflow", { allowedTools, disallowedTools });
|
|
@@ -815,860 +820,6 @@ IMPORTANT: When you create your analysis comment, tag @${author} in the "Questio
|
|
|
815
820
|
}
|
|
816
821
|
};
|
|
817
822
|
|
|
818
|
-
// src/lib/ValidationRunner.ts
|
|
819
|
-
var ValidationRunner = class {
|
|
820
|
-
constructor() {
|
|
821
|
-
}
|
|
822
|
-
/**
|
|
823
|
-
* Run all validations in sequence: typecheck → lint → test
|
|
824
|
-
* Fails fast on first error
|
|
825
|
-
*/
|
|
826
|
-
async runValidations(worktreePath, options = {}) {
|
|
827
|
-
const startTime = Date.now();
|
|
828
|
-
const steps = [];
|
|
829
|
-
if (!options.skipTypecheck) {
|
|
830
|
-
const typecheckResult = await this.runTypecheck(
|
|
831
|
-
worktreePath,
|
|
832
|
-
options.dryRun ?? false
|
|
833
|
-
);
|
|
834
|
-
steps.push(typecheckResult);
|
|
835
|
-
if (!typecheckResult.passed && !typecheckResult.skipped) {
|
|
836
|
-
return {
|
|
837
|
-
success: false,
|
|
838
|
-
steps,
|
|
839
|
-
totalDuration: Date.now() - startTime
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
if (!options.skipLint) {
|
|
844
|
-
const lintResult = await this.runLint(worktreePath, options.dryRun ?? false);
|
|
845
|
-
steps.push(lintResult);
|
|
846
|
-
if (!lintResult.passed && !lintResult.skipped) {
|
|
847
|
-
return { success: false, steps, totalDuration: Date.now() - startTime };
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
if (!options.skipTests) {
|
|
851
|
-
const testResult = await this.runTests(
|
|
852
|
-
worktreePath,
|
|
853
|
-
options.dryRun ?? false
|
|
854
|
-
);
|
|
855
|
-
steps.push(testResult);
|
|
856
|
-
if (!testResult.passed && !testResult.skipped) {
|
|
857
|
-
return { success: false, steps, totalDuration: Date.now() - startTime };
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
return { success: true, steps, totalDuration: Date.now() - startTime };
|
|
861
|
-
}
|
|
862
|
-
/**
|
|
863
|
-
* Run typecheck validation
|
|
864
|
-
* Prefers 'compile' script over 'typecheck' if both exist
|
|
865
|
-
*/
|
|
866
|
-
async runTypecheck(worktreePath, dryRun) {
|
|
867
|
-
const stepStartTime = Date.now();
|
|
868
|
-
let scriptToRun = null;
|
|
869
|
-
try {
|
|
870
|
-
const pkgJson = await getPackageConfig(worktreePath);
|
|
871
|
-
const hasCompileScript = hasScript(pkgJson, "compile");
|
|
872
|
-
const hasTypecheckScript = hasScript(pkgJson, "typecheck");
|
|
873
|
-
if (hasCompileScript) {
|
|
874
|
-
scriptToRun = "compile";
|
|
875
|
-
} else if (hasTypecheckScript) {
|
|
876
|
-
scriptToRun = "typecheck";
|
|
877
|
-
}
|
|
878
|
-
if (!scriptToRun) {
|
|
879
|
-
getLogger().debug("Skipping typecheck - no compile or typecheck script found");
|
|
880
|
-
return {
|
|
881
|
-
step: "typecheck",
|
|
882
|
-
passed: true,
|
|
883
|
-
skipped: true,
|
|
884
|
-
duration: Date.now() - stepStartTime
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
} catch (error) {
|
|
888
|
-
if (error instanceof Error && error.message.includes("package.json not found")) {
|
|
889
|
-
getLogger().debug("Skipping typecheck - no package.json found (non-Node.js project)");
|
|
890
|
-
return {
|
|
891
|
-
step: "typecheck",
|
|
892
|
-
passed: true,
|
|
893
|
-
skipped: true,
|
|
894
|
-
duration: Date.now() - stepStartTime
|
|
895
|
-
};
|
|
896
|
-
}
|
|
897
|
-
throw error;
|
|
898
|
-
}
|
|
899
|
-
const packageManager = await detectPackageManager(worktreePath);
|
|
900
|
-
if (dryRun) {
|
|
901
|
-
const command = packageManager === "npm" ? `npm run ${scriptToRun}` : `${packageManager} ${scriptToRun}`;
|
|
902
|
-
getLogger().info(`[DRY RUN] Would run: ${command}`);
|
|
903
|
-
return {
|
|
904
|
-
step: scriptToRun,
|
|
905
|
-
passed: true,
|
|
906
|
-
skipped: false,
|
|
907
|
-
duration: Date.now() - stepStartTime
|
|
908
|
-
};
|
|
909
|
-
}
|
|
910
|
-
getLogger().info(`Running ${scriptToRun}...`);
|
|
911
|
-
try {
|
|
912
|
-
await runScript(scriptToRun, worktreePath, [], { quiet: true });
|
|
913
|
-
getLogger().success(`${scriptToRun.charAt(0).toUpperCase() + scriptToRun.slice(1)} passed`);
|
|
914
|
-
return {
|
|
915
|
-
step: scriptToRun,
|
|
916
|
-
passed: true,
|
|
917
|
-
skipped: false,
|
|
918
|
-
duration: Date.now() - stepStartTime
|
|
919
|
-
};
|
|
920
|
-
} catch {
|
|
921
|
-
const fixed = await this.attemptClaudeFix(
|
|
922
|
-
scriptToRun,
|
|
923
|
-
worktreePath,
|
|
924
|
-
packageManager
|
|
925
|
-
);
|
|
926
|
-
if (fixed) {
|
|
927
|
-
return {
|
|
928
|
-
step: scriptToRun,
|
|
929
|
-
passed: true,
|
|
930
|
-
skipped: false,
|
|
931
|
-
duration: Date.now() - stepStartTime
|
|
932
|
-
};
|
|
933
|
-
}
|
|
934
|
-
const runCommand = packageManager === "npm" ? `npm run ${scriptToRun}` : `${packageManager} ${scriptToRun}`;
|
|
935
|
-
const stepLabel = scriptToRun.charAt(0).toUpperCase() + scriptToRun.slice(1);
|
|
936
|
-
throw new Error(
|
|
937
|
-
`Error: ${stepLabel} failed.
|
|
938
|
-
Fix type errors before merging.
|
|
939
|
-
|
|
940
|
-
Run '${runCommand}' to see detailed errors.`
|
|
941
|
-
);
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
/**
|
|
945
|
-
* Run lint validation
|
|
946
|
-
*/
|
|
947
|
-
async runLint(worktreePath, dryRun) {
|
|
948
|
-
const stepStartTime = Date.now();
|
|
949
|
-
try {
|
|
950
|
-
const pkgJson = await getPackageConfig(worktreePath);
|
|
951
|
-
const hasLintScript = hasScript(pkgJson, "lint");
|
|
952
|
-
if (!hasLintScript) {
|
|
953
|
-
getLogger().debug("Skipping lint - no lint script found");
|
|
954
|
-
return {
|
|
955
|
-
step: "lint",
|
|
956
|
-
passed: true,
|
|
957
|
-
skipped: true,
|
|
958
|
-
duration: Date.now() - stepStartTime
|
|
959
|
-
};
|
|
960
|
-
}
|
|
961
|
-
} catch (error) {
|
|
962
|
-
if (error instanceof Error && error.message.includes("package.json not found")) {
|
|
963
|
-
getLogger().debug("Skipping lint - no package.json found (non-Node.js project)");
|
|
964
|
-
return {
|
|
965
|
-
step: "lint",
|
|
966
|
-
passed: true,
|
|
967
|
-
skipped: true,
|
|
968
|
-
duration: Date.now() - stepStartTime
|
|
969
|
-
};
|
|
970
|
-
}
|
|
971
|
-
throw error;
|
|
972
|
-
}
|
|
973
|
-
const packageManager = await detectPackageManager(worktreePath);
|
|
974
|
-
if (dryRun) {
|
|
975
|
-
const command = packageManager === "npm" ? "npm run lint" : `${packageManager} lint`;
|
|
976
|
-
getLogger().info(`[DRY RUN] Would run: ${command}`);
|
|
977
|
-
return {
|
|
978
|
-
step: "lint",
|
|
979
|
-
passed: true,
|
|
980
|
-
skipped: false,
|
|
981
|
-
duration: Date.now() - stepStartTime
|
|
982
|
-
};
|
|
983
|
-
}
|
|
984
|
-
getLogger().info("Running lint...");
|
|
985
|
-
try {
|
|
986
|
-
await runScript("lint", worktreePath, [], { quiet: true });
|
|
987
|
-
getLogger().success("Linting passed");
|
|
988
|
-
return {
|
|
989
|
-
step: "lint",
|
|
990
|
-
passed: true,
|
|
991
|
-
skipped: false,
|
|
992
|
-
duration: Date.now() - stepStartTime
|
|
993
|
-
};
|
|
994
|
-
} catch {
|
|
995
|
-
const fixed = await this.attemptClaudeFix(
|
|
996
|
-
"lint",
|
|
997
|
-
worktreePath,
|
|
998
|
-
packageManager
|
|
999
|
-
);
|
|
1000
|
-
if (fixed) {
|
|
1001
|
-
return {
|
|
1002
|
-
step: "lint",
|
|
1003
|
-
passed: true,
|
|
1004
|
-
skipped: false,
|
|
1005
|
-
duration: Date.now() - stepStartTime
|
|
1006
|
-
};
|
|
1007
|
-
}
|
|
1008
|
-
const runCommand = packageManager === "npm" ? "npm run lint" : `${packageManager} lint`;
|
|
1009
|
-
throw new Error(
|
|
1010
|
-
`Error: Linting failed.
|
|
1011
|
-
Fix linting errors before merging.
|
|
1012
|
-
|
|
1013
|
-
Run '${runCommand}' to see detailed errors.`
|
|
1014
|
-
);
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
/**
|
|
1018
|
-
* Run test validation
|
|
1019
|
-
*/
|
|
1020
|
-
async runTests(worktreePath, dryRun) {
|
|
1021
|
-
const stepStartTime = Date.now();
|
|
1022
|
-
try {
|
|
1023
|
-
const pkgJson = await getPackageConfig(worktreePath);
|
|
1024
|
-
const hasTestScript = hasScript(pkgJson, "test");
|
|
1025
|
-
if (!hasTestScript) {
|
|
1026
|
-
getLogger().debug("Skipping tests - no test script found");
|
|
1027
|
-
return {
|
|
1028
|
-
step: "test",
|
|
1029
|
-
passed: true,
|
|
1030
|
-
skipped: true,
|
|
1031
|
-
duration: Date.now() - stepStartTime
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
} catch (error) {
|
|
1035
|
-
if (error instanceof Error && error.message.includes("package.json not found")) {
|
|
1036
|
-
getLogger().debug("Skipping tests - no package.json found (non-Node.js project)");
|
|
1037
|
-
return {
|
|
1038
|
-
step: "test",
|
|
1039
|
-
passed: true,
|
|
1040
|
-
skipped: true,
|
|
1041
|
-
duration: Date.now() - stepStartTime
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
throw error;
|
|
1045
|
-
}
|
|
1046
|
-
const packageManager = await detectPackageManager(worktreePath);
|
|
1047
|
-
if (dryRun) {
|
|
1048
|
-
const command = packageManager === "npm" ? "npm run test" : `${packageManager} test`;
|
|
1049
|
-
getLogger().info(`[DRY RUN] Would run: ${command}`);
|
|
1050
|
-
return {
|
|
1051
|
-
step: "test",
|
|
1052
|
-
passed: true,
|
|
1053
|
-
skipped: false,
|
|
1054
|
-
duration: Date.now() - stepStartTime
|
|
1055
|
-
};
|
|
1056
|
-
}
|
|
1057
|
-
getLogger().info("Running tests...");
|
|
1058
|
-
try {
|
|
1059
|
-
await runScript("test", worktreePath, [], { quiet: true });
|
|
1060
|
-
getLogger().success("Tests passed");
|
|
1061
|
-
return {
|
|
1062
|
-
step: "test",
|
|
1063
|
-
passed: true,
|
|
1064
|
-
skipped: false,
|
|
1065
|
-
duration: Date.now() - stepStartTime
|
|
1066
|
-
};
|
|
1067
|
-
} catch {
|
|
1068
|
-
const fixed = await this.attemptClaudeFix(
|
|
1069
|
-
"test",
|
|
1070
|
-
worktreePath,
|
|
1071
|
-
packageManager
|
|
1072
|
-
);
|
|
1073
|
-
if (fixed) {
|
|
1074
|
-
return {
|
|
1075
|
-
step: "test",
|
|
1076
|
-
passed: true,
|
|
1077
|
-
skipped: false,
|
|
1078
|
-
duration: Date.now() - stepStartTime
|
|
1079
|
-
};
|
|
1080
|
-
}
|
|
1081
|
-
const runCommand = packageManager === "npm" ? "npm run test" : `${packageManager} test`;
|
|
1082
|
-
throw new Error(
|
|
1083
|
-
`Error: Tests failed.
|
|
1084
|
-
Fix test failures before merging.
|
|
1085
|
-
|
|
1086
|
-
Run '${runCommand}' to see detailed errors.`
|
|
1087
|
-
);
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
/**
|
|
1091
|
-
* Attempt to fix validation errors using Claude
|
|
1092
|
-
* Pattern based on MergeManager.attemptClaudeConflictResolution
|
|
1093
|
-
*
|
|
1094
|
-
* @param validationType - Type of validation that failed ('compile' | 'typecheck' | 'lint' | 'test')
|
|
1095
|
-
* @param worktreePath - Path to the worktree
|
|
1096
|
-
* @param packageManager - Detected package manager
|
|
1097
|
-
* @returns true if Claude fixed the issue, false otherwise
|
|
1098
|
-
*/
|
|
1099
|
-
async attemptClaudeFix(validationType, worktreePath, packageManager) {
|
|
1100
|
-
const isClaudeAvailable = await detectClaudeCli();
|
|
1101
|
-
if (!isClaudeAvailable) {
|
|
1102
|
-
getLogger().debug("Claude CLI not available, skipping auto-fix");
|
|
1103
|
-
return false;
|
|
1104
|
-
}
|
|
1105
|
-
const validationCommand = this.getValidationCommand(validationType, packageManager);
|
|
1106
|
-
const prompt = this.getClaudePrompt(validationType, validationCommand);
|
|
1107
|
-
const validationTypeCapitalized = validationType.charAt(0).toUpperCase() + validationType.slice(1);
|
|
1108
|
-
getLogger().info(`Launching Claude to help fix ${validationTypeCapitalized} errors...`);
|
|
1109
|
-
try {
|
|
1110
|
-
await launchClaude(prompt, {
|
|
1111
|
-
addDir: worktreePath,
|
|
1112
|
-
headless: false,
|
|
1113
|
-
// Interactive mode
|
|
1114
|
-
permissionMode: "acceptEdits",
|
|
1115
|
-
// Auto-accept edits
|
|
1116
|
-
model: "sonnet"
|
|
1117
|
-
// Use Sonnet model
|
|
1118
|
-
});
|
|
1119
|
-
getLogger().info(`Re-running ${validationTypeCapitalized} after Claude's fixes...`);
|
|
1120
|
-
try {
|
|
1121
|
-
await runScript(validationType, worktreePath, [], { quiet: true });
|
|
1122
|
-
getLogger().success(`${validationTypeCapitalized} passed after Claude auto-fix`);
|
|
1123
|
-
return true;
|
|
1124
|
-
} catch {
|
|
1125
|
-
getLogger().warn(`${validationTypeCapitalized} still failing after Claude's help`);
|
|
1126
|
-
return false;
|
|
1127
|
-
}
|
|
1128
|
-
} catch (error) {
|
|
1129
|
-
getLogger().warn("Claude auto-fix failed", {
|
|
1130
|
-
error: error instanceof Error ? error.message : String(error)
|
|
1131
|
-
});
|
|
1132
|
-
return false;
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
/**
|
|
1136
|
-
* Get validation command string for prompts
|
|
1137
|
-
* Uses il commands for multi-language project support
|
|
1138
|
-
*/
|
|
1139
|
-
getValidationCommand(validationType, _packageManager) {
|
|
1140
|
-
return `il ${validationType}`;
|
|
1141
|
-
}
|
|
1142
|
-
/**
|
|
1143
|
-
* Get Claude prompt for specific validation type
|
|
1144
|
-
* Matches bash script prompts exactly
|
|
1145
|
-
*/
|
|
1146
|
-
getClaudePrompt(validationType, validationCommand) {
|
|
1147
|
-
switch (validationType) {
|
|
1148
|
-
case "compile":
|
|
1149
|
-
case "typecheck":
|
|
1150
|
-
return `There are TypeScript errors in this codebase. Please analyze the ${validationType} output, identify all type errors, and fix them. Run '${validationCommand}' to see the errors, then make the necessary code changes to resolve all type issues. When you are done, tell the user to quit using /exit to continue the validation process.`;
|
|
1151
|
-
case "lint":
|
|
1152
|
-
return `There are ESLint errors in this codebase. Please analyze the linting output, identify all linting issues, and fix them. Run '${validationCommand}' to see the errors, then make the necessary code changes to resolve all linting issues. Focus on code quality, consistency, and following the project's linting rules. When you are done, tell the user to quit using /exit to continue the validation process.`;
|
|
1153
|
-
case "test":
|
|
1154
|
-
return `There are unit test failures in this codebase. Please analyze the test output to understand what's failing, then fix the issues. This might involve updating test code, fixing bugs in the source code, or updating tests to match new behavior. Run '${validationCommand}' to see the detailed test failures, then make the necessary changes to get all tests passing. When you are done, tell the user to quit using /exit to continue the validation process.`;
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
};
|
|
1158
|
-
|
|
1159
|
-
// src/utils/vscode.ts
|
|
1160
|
-
import { execa } from "execa";
|
|
1161
|
-
function isRunningInVSCode() {
|
|
1162
|
-
return process.env.TERM_PROGRAM === "vscode";
|
|
1163
|
-
}
|
|
1164
|
-
function isRunningInCursor() {
|
|
1165
|
-
return !!process.env.CURSOR_TRACE_ID;
|
|
1166
|
-
}
|
|
1167
|
-
function isRunningInAntigravity() {
|
|
1168
|
-
return !!process.env.ANTIGRAVITY_CLI_ALIAS;
|
|
1169
|
-
}
|
|
1170
|
-
async function isVSCodeAvailable() {
|
|
1171
|
-
try {
|
|
1172
|
-
await execa("command", ["-v", "code"], {
|
|
1173
|
-
shell: true,
|
|
1174
|
-
timeout: 5e3
|
|
1175
|
-
});
|
|
1176
|
-
return true;
|
|
1177
|
-
} catch (error) {
|
|
1178
|
-
logger.debug("VSCode CLI not available", { error });
|
|
1179
|
-
return false;
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
async function isCursorAvailable() {
|
|
1183
|
-
try {
|
|
1184
|
-
await execa("command", ["-v", "cursor"], {
|
|
1185
|
-
shell: true,
|
|
1186
|
-
timeout: 5e3
|
|
1187
|
-
});
|
|
1188
|
-
return true;
|
|
1189
|
-
} catch (error) {
|
|
1190
|
-
logger.debug("Cursor CLI not available", { error });
|
|
1191
|
-
return false;
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
async function isAntigravityAvailable() {
|
|
1195
|
-
try {
|
|
1196
|
-
await execa("command", ["-v", "agy"], {
|
|
1197
|
-
shell: true,
|
|
1198
|
-
timeout: 5e3
|
|
1199
|
-
});
|
|
1200
|
-
return true;
|
|
1201
|
-
} catch (error) {
|
|
1202
|
-
logger.debug("Antigravity CLI not available", { error });
|
|
1203
|
-
return false;
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
// src/types/index.ts
|
|
1208
|
-
var UserAbortedCommitError = class extends Error {
|
|
1209
|
-
constructor(message = "User aborted the commit") {
|
|
1210
|
-
super(message);
|
|
1211
|
-
this.name = "UserAbortedCommitError";
|
|
1212
|
-
}
|
|
1213
|
-
};
|
|
1214
|
-
|
|
1215
|
-
// src/lib/CommitManager.ts
|
|
1216
|
-
import { writeFile, readFile as readFile2, unlink } from "fs/promises";
|
|
1217
|
-
import { join } from "path";
|
|
1218
|
-
import { execa as execa2 } from "execa";
|
|
1219
|
-
var CommitManager = class {
|
|
1220
|
-
constructor() {
|
|
1221
|
-
}
|
|
1222
|
-
/**
|
|
1223
|
-
* Detect uncommitted changes in a worktree
|
|
1224
|
-
* Parses git status --porcelain output into structured GitStatus
|
|
1225
|
-
*/
|
|
1226
|
-
async detectUncommittedChanges(worktreePath) {
|
|
1227
|
-
const porcelainOutput = await executeGitCommand(["status", "--porcelain"], {
|
|
1228
|
-
cwd: worktreePath
|
|
1229
|
-
});
|
|
1230
|
-
const { stagedFiles, unstagedFiles } = this.parseGitStatus(porcelainOutput);
|
|
1231
|
-
const currentBranch = await executeGitCommand(["branch", "--show-current"], {
|
|
1232
|
-
cwd: worktreePath
|
|
1233
|
-
});
|
|
1234
|
-
return {
|
|
1235
|
-
hasUncommittedChanges: stagedFiles.length > 0 || unstagedFiles.length > 0,
|
|
1236
|
-
unstagedFiles,
|
|
1237
|
-
stagedFiles,
|
|
1238
|
-
currentBranch: currentBranch.trim(),
|
|
1239
|
-
// Defer these to future enhancement
|
|
1240
|
-
isAheadOfRemote: false,
|
|
1241
|
-
isBehindRemote: false
|
|
1242
|
-
};
|
|
1243
|
-
}
|
|
1244
|
-
/**
|
|
1245
|
-
* Stage all changes and commit with Claude-generated or simple message
|
|
1246
|
-
* Tries Claude first, falls back to simple message if Claude unavailable or fails
|
|
1247
|
-
*/
|
|
1248
|
-
async commitChanges(worktreePath, options) {
|
|
1249
|
-
if (options.dryRun) {
|
|
1250
|
-
getLogger().info("[DRY RUN] Would run: git add -A");
|
|
1251
|
-
getLogger().info("[DRY RUN] Would generate commit message with Claude (if available)");
|
|
1252
|
-
const fallbackMessage = this.generateFallbackMessage(options);
|
|
1253
|
-
const verifyFlag = options.skipVerify ? " --no-verify" : "";
|
|
1254
|
-
getLogger().info(`[DRY RUN] Would commit with message${verifyFlag}: ${fallbackMessage}`);
|
|
1255
|
-
return;
|
|
1256
|
-
}
|
|
1257
|
-
await executeGitCommand(["add", "-A"], { cwd: worktreePath });
|
|
1258
|
-
let message = null;
|
|
1259
|
-
if (!options.message) {
|
|
1260
|
-
try {
|
|
1261
|
-
message = await this.generateClaudeCommitMessage(worktreePath, options.issueNumber);
|
|
1262
|
-
} catch (error) {
|
|
1263
|
-
getLogger().debug("Claude commit message generation failed, using fallback", { error });
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
message ??= this.generateFallbackMessage(options);
|
|
1267
|
-
if (options.skipVerify) {
|
|
1268
|
-
getLogger().warn("Skipping pre-commit hooks (--no-verify configured in settings)");
|
|
1269
|
-
}
|
|
1270
|
-
try {
|
|
1271
|
-
if (options.noReview || options.message) {
|
|
1272
|
-
const commitArgs = ["commit", "-m", message];
|
|
1273
|
-
if (options.skipVerify) {
|
|
1274
|
-
commitArgs.push("--no-verify");
|
|
1275
|
-
}
|
|
1276
|
-
await executeGitCommand(commitArgs, { cwd: worktreePath });
|
|
1277
|
-
} else {
|
|
1278
|
-
const action = await promptCommitAction(message);
|
|
1279
|
-
if (action === "abort") {
|
|
1280
|
-
throw new UserAbortedCommitError();
|
|
1281
|
-
}
|
|
1282
|
-
if (action === "accept") {
|
|
1283
|
-
const commitArgs = ["commit", "-m", message];
|
|
1284
|
-
if (options.skipVerify) {
|
|
1285
|
-
commitArgs.push("--no-verify");
|
|
1286
|
-
}
|
|
1287
|
-
await executeGitCommand(commitArgs, { cwd: worktreePath });
|
|
1288
|
-
} else {
|
|
1289
|
-
getLogger().info("Opening editor for commit message review...");
|
|
1290
|
-
if (isRunningInAntigravity() && await isAntigravityAvailable()) {
|
|
1291
|
-
await this.commitWithExternalEditor(worktreePath, message, options, "agy", "Antigravity");
|
|
1292
|
-
} else if (isRunningInCursor() && await isCursorAvailable()) {
|
|
1293
|
-
await this.commitWithExternalEditor(worktreePath, message, options, "cursor", "Cursor");
|
|
1294
|
-
} else if (isRunningInVSCode() && await isVSCodeAvailable()) {
|
|
1295
|
-
await this.commitWithExternalEditor(worktreePath, message, options, "code", "VSCode");
|
|
1296
|
-
} else {
|
|
1297
|
-
const commitArgs = ["commit", "-e", "-m", message];
|
|
1298
|
-
if (options.skipVerify) {
|
|
1299
|
-
commitArgs.push("--no-verify");
|
|
1300
|
-
}
|
|
1301
|
-
await executeGitCommand(commitArgs, {
|
|
1302
|
-
cwd: worktreePath,
|
|
1303
|
-
stdio: "inherit",
|
|
1304
|
-
timeout: 3e5
|
|
1305
|
-
// 5 minutes for interactive editing
|
|
1306
|
-
});
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
} catch (error) {
|
|
1311
|
-
if (error instanceof UserAbortedCommitError) {
|
|
1312
|
-
throw error;
|
|
1313
|
-
}
|
|
1314
|
-
if (error instanceof Error && error.message.includes("nothing to commit")) {
|
|
1315
|
-
getLogger().info("No changes to commit");
|
|
1316
|
-
return;
|
|
1317
|
-
}
|
|
1318
|
-
throw error;
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
/**
|
|
1322
|
-
* Commit with external editor CLI (VSCode, Cursor, Antigravity, etc.)
|
|
1323
|
-
* Handles file creation, editing, and commit to ensure the file opens
|
|
1324
|
-
* in the current editor window (preserves IPC context)
|
|
1325
|
-
*/
|
|
1326
|
-
async commitWithExternalEditor(worktreePath, message, options, cliCommand, editorName) {
|
|
1327
|
-
const commitMsgPath = join(worktreePath, ".COMMIT_EDITMSG");
|
|
1328
|
-
const initialContent = `${message}
|
|
1329
|
-
|
|
1330
|
-
# Please enter the commit message for your changes. Lines starting
|
|
1331
|
-
# with '#' will be ignored, and an empty message aborts the commit.
|
|
1332
|
-
#
|
|
1333
|
-
# Save and close the file to complete the commit.
|
|
1334
|
-
`;
|
|
1335
|
-
await writeFile(commitMsgPath, initialContent, "utf-8");
|
|
1336
|
-
try {
|
|
1337
|
-
getLogger().debug(`Opening commit message in ${editorName}: ${commitMsgPath}`);
|
|
1338
|
-
await execa2(cliCommand, ["--wait", commitMsgPath], {
|
|
1339
|
-
cwd: worktreePath,
|
|
1340
|
-
stdio: "inherit"
|
|
1341
|
-
});
|
|
1342
|
-
const editedContent = await readFile2(commitMsgPath, "utf-8");
|
|
1343
|
-
const finalMessage = editedContent.split("\n").filter((line) => !line.startsWith("#")).join("\n").trim();
|
|
1344
|
-
if (!finalMessage) {
|
|
1345
|
-
throw new UserAbortedCommitError();
|
|
1346
|
-
}
|
|
1347
|
-
const commitArgs = ["commit", "-F", commitMsgPath];
|
|
1348
|
-
if (options.skipVerify) {
|
|
1349
|
-
commitArgs.push("--no-verify");
|
|
1350
|
-
}
|
|
1351
|
-
await writeFile(commitMsgPath, finalMessage, "utf-8");
|
|
1352
|
-
await executeGitCommand(commitArgs, { cwd: worktreePath });
|
|
1353
|
-
} finally {
|
|
1354
|
-
try {
|
|
1355
|
-
await unlink(commitMsgPath);
|
|
1356
|
-
} catch {
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
/**
|
|
1361
|
-
* Generate simple fallback commit message when Claude unavailable
|
|
1362
|
-
* Used as fallback for Claude-powered commit messages
|
|
1363
|
-
*/
|
|
1364
|
-
generateFallbackMessage(options) {
|
|
1365
|
-
if (options.message) {
|
|
1366
|
-
return options.message;
|
|
1367
|
-
}
|
|
1368
|
-
if (options.issueNumber) {
|
|
1369
|
-
return `WIP: Auto-commit for issue #${options.issueNumber}
|
|
1370
|
-
|
|
1371
|
-
Fixes #${options.issueNumber}`;
|
|
1372
|
-
} else {
|
|
1373
|
-
return "WIP: Auto-commit uncommitted changes";
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
/**
|
|
1377
|
-
* Parse git status --porcelain output
|
|
1378
|
-
* Format: "XY filename" where X=index, Y=worktree
|
|
1379
|
-
* Examples:
|
|
1380
|
-
* "M file.ts" - staged modification
|
|
1381
|
-
* " M file.ts" - unstaged modification
|
|
1382
|
-
* "MM file.ts" - both staged and unstaged
|
|
1383
|
-
* "?? file.ts" - untracked
|
|
1384
|
-
*/
|
|
1385
|
-
parseGitStatus(porcelainOutput) {
|
|
1386
|
-
const stagedFiles = [];
|
|
1387
|
-
const unstagedFiles = [];
|
|
1388
|
-
if (!porcelainOutput.trim()) {
|
|
1389
|
-
return { stagedFiles, unstagedFiles };
|
|
1390
|
-
}
|
|
1391
|
-
const lines = porcelainOutput.split("\n").filter((line) => line.trim());
|
|
1392
|
-
for (const line of lines) {
|
|
1393
|
-
if (line.length < 3) continue;
|
|
1394
|
-
const indexStatus = line[0];
|
|
1395
|
-
const worktreeStatus = line[1];
|
|
1396
|
-
const filename = line.substring(3);
|
|
1397
|
-
if (indexStatus !== " " && indexStatus !== "?") {
|
|
1398
|
-
stagedFiles.push(filename);
|
|
1399
|
-
}
|
|
1400
|
-
if (worktreeStatus !== " " || line.startsWith("??")) {
|
|
1401
|
-
unstagedFiles.push(filename);
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
return { stagedFiles, unstagedFiles };
|
|
1405
|
-
}
|
|
1406
|
-
/**
|
|
1407
|
-
* Generate commit message using Claude Code
|
|
1408
|
-
* Claude examines the git repository directly via --add-dir option
|
|
1409
|
-
* Returns null if Claude unavailable or fails validation
|
|
1410
|
-
*/
|
|
1411
|
-
async generateClaudeCommitMessage(worktreePath, issueNumber) {
|
|
1412
|
-
const startTime = Date.now();
|
|
1413
|
-
getLogger().info("Starting Claude commit message generation...", {
|
|
1414
|
-
worktreePath: worktreePath.split("/").pop(),
|
|
1415
|
-
// Just show the folder name for privacy
|
|
1416
|
-
issueNumber
|
|
1417
|
-
});
|
|
1418
|
-
getLogger().debug("Checking Claude CLI availability...");
|
|
1419
|
-
const isClaudeAvailable = await detectClaudeCli();
|
|
1420
|
-
if (!isClaudeAvailable) {
|
|
1421
|
-
getLogger().info("Claude CLI not available, skipping Claude commit message generation");
|
|
1422
|
-
return null;
|
|
1423
|
-
}
|
|
1424
|
-
getLogger().debug("Claude CLI is available");
|
|
1425
|
-
getLogger().debug("Building commit message prompt...");
|
|
1426
|
-
const prompt = this.buildCommitMessagePrompt(issueNumber);
|
|
1427
|
-
getLogger().debug("Prompt built", { promptLength: prompt.length });
|
|
1428
|
-
getLogger().debug("Claude prompt content:", {
|
|
1429
|
-
prompt,
|
|
1430
|
-
truncatedPreview: prompt.substring(0, 500) + (prompt.length > 500 ? "...[truncated]" : "")
|
|
1431
|
-
});
|
|
1432
|
-
try {
|
|
1433
|
-
getLogger().info("Calling Claude CLI for commit message generation...");
|
|
1434
|
-
const claudeStartTime = Date.now();
|
|
1435
|
-
const claudeOptions = {
|
|
1436
|
-
headless: true,
|
|
1437
|
-
addDir: worktreePath,
|
|
1438
|
-
model: "claude-haiku-4-5-20251001",
|
|
1439
|
-
// Fast, cost-effective model
|
|
1440
|
-
timeout: 12e4,
|
|
1441
|
-
// 120 second timeout
|
|
1442
|
-
appendSystemPrompt: "Output only the requested content. Never include preamble, analysis, or meta-commentary. Your response is used verbatim."
|
|
1443
|
-
};
|
|
1444
|
-
getLogger().debug("Claude CLI call parameters:", {
|
|
1445
|
-
options: claudeOptions,
|
|
1446
|
-
worktreePathForAnalysis: worktreePath,
|
|
1447
|
-
addDirContents: "Will include entire worktree directory for analysis"
|
|
1448
|
-
});
|
|
1449
|
-
const result = await launchClaude(prompt, claudeOptions);
|
|
1450
|
-
const claudeDuration = Date.now() - claudeStartTime;
|
|
1451
|
-
getLogger().debug("Claude API call completed", { duration: `${claudeDuration}ms` });
|
|
1452
|
-
if (typeof result !== "string") {
|
|
1453
|
-
getLogger().warn("Claude returned non-string result", { resultType: typeof result });
|
|
1454
|
-
return null;
|
|
1455
|
-
}
|
|
1456
|
-
getLogger().debug("Raw Claude output received", {
|
|
1457
|
-
outputLength: result.length,
|
|
1458
|
-
preview: result.substring(0, 200) + (result.length > 200 ? "..." : "")
|
|
1459
|
-
});
|
|
1460
|
-
getLogger().debug("Sanitizing Claude output...");
|
|
1461
|
-
const sanitized = this.sanitizeClaudeOutput(result);
|
|
1462
|
-
getLogger().debug("Output sanitized", {
|
|
1463
|
-
originalLength: result.length,
|
|
1464
|
-
sanitizedLength: sanitized.length,
|
|
1465
|
-
sanitized: sanitized.substring(0, 200) + (sanitized.length > 200 ? "..." : "")
|
|
1466
|
-
});
|
|
1467
|
-
if (!sanitized) {
|
|
1468
|
-
getLogger().warn("Claude returned empty message after sanitization");
|
|
1469
|
-
return null;
|
|
1470
|
-
}
|
|
1471
|
-
let finalMessage = sanitized;
|
|
1472
|
-
if (issueNumber) {
|
|
1473
|
-
if (!finalMessage.includes(`Fixes #${issueNumber}`)) {
|
|
1474
|
-
finalMessage = `${finalMessage}
|
|
1475
|
-
|
|
1476
|
-
Fixes #${issueNumber}`;
|
|
1477
|
-
getLogger().debug(`Added "Fixes #${issueNumber}" trailer to commit message`);
|
|
1478
|
-
} else {
|
|
1479
|
-
getLogger().debug(`"Fixes #${issueNumber}" already present in commit message`);
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
const totalDuration = Date.now() - startTime;
|
|
1483
|
-
getLogger().info("Claude commit message generated successfully", {
|
|
1484
|
-
message: finalMessage,
|
|
1485
|
-
totalDuration: `${totalDuration}ms`,
|
|
1486
|
-
claudeApiDuration: `${claudeDuration}ms`
|
|
1487
|
-
});
|
|
1488
|
-
return finalMessage;
|
|
1489
|
-
} catch (error) {
|
|
1490
|
-
const totalDuration = Date.now() - startTime;
|
|
1491
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1492
|
-
if (errorMessage.includes("timed out") || errorMessage.includes("timeout")) {
|
|
1493
|
-
getLogger().warn("Claude commit message generation timed out after 45 seconds", {
|
|
1494
|
-
totalDuration: `${totalDuration}ms`,
|
|
1495
|
-
worktreePath: worktreePath.split("/").pop()
|
|
1496
|
-
});
|
|
1497
|
-
} else {
|
|
1498
|
-
getLogger().warn("Failed to generate commit message with Claude", {
|
|
1499
|
-
error: errorMessage,
|
|
1500
|
-
totalDuration: `${totalDuration}ms`,
|
|
1501
|
-
worktreePath: worktreePath.split("/").pop()
|
|
1502
|
-
});
|
|
1503
|
-
}
|
|
1504
|
-
return null;
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
/**
|
|
1508
|
-
* Build structured XML prompt for commit message generation
|
|
1509
|
-
* Uses XML format for clear task definition and output expectations
|
|
1510
|
-
*/
|
|
1511
|
-
buildCommitMessagePrompt(issueNumber) {
|
|
1512
|
-
const issueContext = issueNumber ? `
|
|
1513
|
-
<IssueContext>
|
|
1514
|
-
This commit is associated with GitHub issue #${issueNumber}.
|
|
1515
|
-
If the changes appear to resolve the issue, include "Fixes #${issueNumber}" at the end of the first line of commit message.
|
|
1516
|
-
</IssueContext>` : "";
|
|
1517
|
-
return `<Task>
|
|
1518
|
-
You are a software engineer writing a commit message for this repository.
|
|
1519
|
-
Examine the staged changes in the git repository and generate a concise, meaningful commit message.
|
|
1520
|
-
</Task>
|
|
1521
|
-
|
|
1522
|
-
<Requirements>
|
|
1523
|
-
<Format>The first line must be a brief summary of the changes made as a full sentence. If it references an issue, include "Fixes #N" at the end of this line.
|
|
1524
|
-
|
|
1525
|
-
Add 2 newlines, then add a bullet-point form description of the changes made, each change on a new line.</Format>
|
|
1526
|
-
<Mood>Use imperative mood (e.g., "Add feature" not "Added feature")</Mood>
|
|
1527
|
-
<Focus>Be specific about what was changed and why</Focus>
|
|
1528
|
-
<Conciseness>Keep message under 72 characters for subject line when possible</Conciseness>
|
|
1529
|
-
<NoMeta>CRITICAL: Do NOT include ANY explanatory text, analysis, or meta-commentary. Output ONLY the raw commit message.</NoMeta>
|
|
1530
|
-
<Examples>
|
|
1531
|
-
Good: "Add user authentication with JWT tokens. Fixes #42
|
|
1532
|
-
|
|
1533
|
-
- Implement login and registration endpoints
|
|
1534
|
-
- Secure routes with JWT middleware
|
|
1535
|
-
- Update user model to store hashed passwords"
|
|
1536
|
-
Good: "Fix navigation bug in sidebar menu."
|
|
1537
|
-
Bad: "Based on the changes, I'll create: Add user authentication"
|
|
1538
|
-
Bad: "Looking at the files, this commit should be: Fix navigation bug"
|
|
1539
|
-
</Examples>
|
|
1540
|
-
${issueContext}
|
|
1541
|
-
</Requirements>
|
|
1542
|
-
|
|
1543
|
-
<Output>
|
|
1544
|
-
IMPORTANT: Your entire response will be used directly as the git commit message.
|
|
1545
|
-
Do not include any explanatory text before or after the commit message.
|
|
1546
|
-
Start your response immediately with the commit message text.
|
|
1547
|
-
</Output>`;
|
|
1548
|
-
}
|
|
1549
|
-
/**
|
|
1550
|
-
* Sanitize Claude output to remove meta-commentary and clean formatting
|
|
1551
|
-
* Handles cases where Claude includes explanatory text despite instructions
|
|
1552
|
-
*/
|
|
1553
|
-
sanitizeClaudeOutput(rawOutput) {
|
|
1554
|
-
let cleaned = rawOutput.trim();
|
|
1555
|
-
const metaPatterns = [
|
|
1556
|
-
/^.*?based on.*?changes.*?:/i,
|
|
1557
|
-
/^.*?looking at.*?files.*?:/i,
|
|
1558
|
-
/^.*?examining.*?:/i,
|
|
1559
|
-
/^.*?analyzing.*?:/i,
|
|
1560
|
-
/^.*?i'll.*?generate.*?:/i,
|
|
1561
|
-
/^.*?let me.*?:/i,
|
|
1562
|
-
/^.*?the commit message.*?should be.*?:/i,
|
|
1563
|
-
/^.*?here.*?is.*?commit.*?message.*?:/i
|
|
1564
|
-
];
|
|
1565
|
-
for (const pattern of metaPatterns) {
|
|
1566
|
-
cleaned = cleaned.replace(pattern, "").trim();
|
|
1567
|
-
}
|
|
1568
|
-
if (cleaned.includes(":")) {
|
|
1569
|
-
const colonIndex = cleaned.indexOf(":");
|
|
1570
|
-
const beforeColon = cleaned.substring(0, colonIndex).trim().toLowerCase();
|
|
1571
|
-
const metaIndicators = [
|
|
1572
|
-
"here is the commit message",
|
|
1573
|
-
"commit message",
|
|
1574
|
-
"here is",
|
|
1575
|
-
"the message should be",
|
|
1576
|
-
"i suggest",
|
|
1577
|
-
"my suggestion"
|
|
1578
|
-
];
|
|
1579
|
-
const isMetaCommentary = metaIndicators.some((indicator) => beforeColon.includes(indicator));
|
|
1580
|
-
if (isMetaCommentary) {
|
|
1581
|
-
const afterColon = cleaned.substring(colonIndex + 1).trim();
|
|
1582
|
-
if (afterColon && afterColon.length > 10) {
|
|
1583
|
-
cleaned = afterColon;
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1586
|
-
}
|
|
1587
|
-
if (cleaned.startsWith('"') && cleaned.endsWith('"') || cleaned.startsWith("'") && cleaned.endsWith("'")) {
|
|
1588
|
-
cleaned = cleaned.slice(1, -1).trim();
|
|
1589
|
-
}
|
|
1590
|
-
return cleaned;
|
|
1591
|
-
}
|
|
1592
|
-
};
|
|
1593
|
-
|
|
1594
|
-
// src/lib/BuildRunner.ts
|
|
1595
|
-
var BuildRunner = class {
|
|
1596
|
-
constructor(capabilityDetector) {
|
|
1597
|
-
this.capabilityDetector = capabilityDetector ?? new ProjectCapabilityDetector();
|
|
1598
|
-
}
|
|
1599
|
-
/**
|
|
1600
|
-
* Run build verification in the specified directory
|
|
1601
|
-
* @param buildPath - Path where build should run (typically main worktree path)
|
|
1602
|
-
* @param options - Build options
|
|
1603
|
-
*/
|
|
1604
|
-
async runBuild(buildPath, options = {}) {
|
|
1605
|
-
const startTime = Date.now();
|
|
1606
|
-
try {
|
|
1607
|
-
const pkgJson = await getPackageConfig(buildPath);
|
|
1608
|
-
const hasBuildScript = hasScript(pkgJson, "build");
|
|
1609
|
-
if (!hasBuildScript) {
|
|
1610
|
-
getLogger().debug("Skipping build - no build script found");
|
|
1611
|
-
return {
|
|
1612
|
-
success: true,
|
|
1613
|
-
skipped: true,
|
|
1614
|
-
reason: "No build script found in package configuration",
|
|
1615
|
-
duration: Date.now() - startTime
|
|
1616
|
-
};
|
|
1617
|
-
}
|
|
1618
|
-
} catch (error) {
|
|
1619
|
-
if (error instanceof Error && error.message.includes("package.json not found")) {
|
|
1620
|
-
getLogger().debug("Skipping build - no package configuration found");
|
|
1621
|
-
return {
|
|
1622
|
-
success: true,
|
|
1623
|
-
skipped: true,
|
|
1624
|
-
reason: "No package configuration found in project",
|
|
1625
|
-
duration: Date.now() - startTime
|
|
1626
|
-
};
|
|
1627
|
-
}
|
|
1628
|
-
throw error;
|
|
1629
|
-
}
|
|
1630
|
-
const capabilities = await this.capabilityDetector.detectCapabilities(buildPath);
|
|
1631
|
-
const isCLIProject = capabilities.capabilities.includes("cli");
|
|
1632
|
-
if (!isCLIProject) {
|
|
1633
|
-
getLogger().debug("Skipping build - not a CLI project (no bin field)");
|
|
1634
|
-
return {
|
|
1635
|
-
success: true,
|
|
1636
|
-
skipped: true,
|
|
1637
|
-
reason: "Project is not a CLI project (no bin field in package.json)",
|
|
1638
|
-
duration: Date.now() - startTime
|
|
1639
|
-
};
|
|
1640
|
-
}
|
|
1641
|
-
const packageManager = await detectPackageManager(buildPath);
|
|
1642
|
-
if (options.dryRun) {
|
|
1643
|
-
const command = packageManager === "npm" ? "npm run build" : `${packageManager} build`;
|
|
1644
|
-
getLogger().info(`[DRY RUN] Would run: ${command}`);
|
|
1645
|
-
return {
|
|
1646
|
-
success: true,
|
|
1647
|
-
skipped: false,
|
|
1648
|
-
duration: Date.now() - startTime
|
|
1649
|
-
};
|
|
1650
|
-
}
|
|
1651
|
-
getLogger().info("Running build...");
|
|
1652
|
-
try {
|
|
1653
|
-
await runScript("build", buildPath, [], { quiet: true });
|
|
1654
|
-
getLogger().success("Build completed successfully");
|
|
1655
|
-
return {
|
|
1656
|
-
success: true,
|
|
1657
|
-
skipped: false,
|
|
1658
|
-
duration: Date.now() - startTime
|
|
1659
|
-
};
|
|
1660
|
-
} catch {
|
|
1661
|
-
const runCommand = packageManager === "npm" ? "npm run build" : `${packageManager} build`;
|
|
1662
|
-
throw new Error(
|
|
1663
|
-
`Error: Build failed.
|
|
1664
|
-
Fix build errors before proceeding.
|
|
1665
|
-
|
|
1666
|
-
Run '${runCommand}' to see detailed errors.`
|
|
1667
|
-
);
|
|
1668
|
-
}
|
|
1669
|
-
}
|
|
1670
|
-
};
|
|
1671
|
-
|
|
1672
823
|
// src/commands/finish.ts
|
|
1673
824
|
import path3 from "path";
|
|
1674
825
|
var FinishCommand = class {
|
|
@@ -1709,7 +860,7 @@ var FinishCommand = class {
|
|
|
1709
860
|
const neonProvider = createNeonProviderFromSettings(settings);
|
|
1710
861
|
const databaseManager = new DatabaseManager(neonProvider, environmentManager, databaseUrlEnvVarName);
|
|
1711
862
|
const cliIsolationManager = new CLIIsolationManager();
|
|
1712
|
-
const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-
|
|
863
|
+
const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-FLPUUFOB.js");
|
|
1713
864
|
this.loomManager ??= new LoomManager(
|
|
1714
865
|
this.gitWorktreeManager,
|
|
1715
866
|
this.issueTracker,
|
|
@@ -1768,6 +919,7 @@ var FinishCommand = class {
|
|
|
1768
919
|
*/
|
|
1769
920
|
async execute(input) {
|
|
1770
921
|
var _a, _b, _c, _d;
|
|
922
|
+
process.env.ILOOM = "1";
|
|
1771
923
|
const isJsonMode = input.options.json === true;
|
|
1772
924
|
const result = {
|
|
1773
925
|
success: false,
|
|
@@ -2049,7 +1201,7 @@ var FinishCommand = class {
|
|
|
2049
1201
|
* This is the workflow: rebase → validate → commit → merge → cleanup
|
|
2050
1202
|
*/
|
|
2051
1203
|
async executeIssueWorkflow(parsed, options, worktree, result) {
|
|
2052
|
-
var _a, _b, _c;
|
|
1204
|
+
var _a, _b, _c, _d;
|
|
2053
1205
|
getLogger().info("Rebasing branch on main...");
|
|
2054
1206
|
const mergeOptions = {
|
|
2055
1207
|
dryRun: options.dryRun ?? false,
|
|
@@ -2094,9 +1246,12 @@ var FinishCommand = class {
|
|
|
2094
1246
|
getLogger().info("Validation passed, auto-committing uncommitted changes...");
|
|
2095
1247
|
const settings2 = await this.settingsManager.loadSettings(worktree.path);
|
|
2096
1248
|
const skipVerify = ((_b = (_a = settings2.workflows) == null ? void 0 : _a.issue) == null ? void 0 : _b.noVerify) ?? false;
|
|
1249
|
+
const providerType = ((_c = settings2.issueManagement) == null ? void 0 : _c.provider) ?? "github";
|
|
1250
|
+
const issuePrefix = IssueManagementProviderFactory.create(providerType).issuePrefix;
|
|
2097
1251
|
const commitOptions = {
|
|
2098
1252
|
dryRun: options.dryRun ?? false,
|
|
2099
|
-
skipVerify
|
|
1253
|
+
skipVerify,
|
|
1254
|
+
issuePrefix
|
|
2100
1255
|
};
|
|
2101
1256
|
if (parsed.type === "issue" && parsed.number) {
|
|
2102
1257
|
commitOptions.issueNumber = parsed.number;
|
|
@@ -2142,9 +1297,9 @@ var FinishCommand = class {
|
|
|
2142
1297
|
`The 'github-draft-pr' merge mode requires a GitHub-compatible issue tracker. Your provider (${this.issueTracker.providerName}) does not support pull requests.`
|
|
2143
1298
|
);
|
|
2144
1299
|
}
|
|
2145
|
-
const { MetadataManager:
|
|
2146
|
-
const
|
|
2147
|
-
const metadata = await
|
|
1300
|
+
const { MetadataManager: MetadataManager3 } = await import("./MetadataManager-XJ2YB762.js");
|
|
1301
|
+
const metadataManager2 = new MetadataManager3();
|
|
1302
|
+
const metadata = await metadataManager2.readMetadata(worktree.path);
|
|
2148
1303
|
getLogger().debug(`Draft PR mode: worktree=${worktree.path}, draftPrNumber=${(metadata == null ? void 0 : metadata.draftPrNumber) ?? "none"}`);
|
|
2149
1304
|
if (!(metadata == null ? void 0 : metadata.draftPrNumber)) {
|
|
2150
1305
|
getLogger().warn("No draft PR found in metadata, creating new PR...");
|
|
@@ -2209,7 +1364,7 @@ var FinishCommand = class {
|
|
|
2209
1364
|
} else {
|
|
2210
1365
|
getLogger().info(`[DRY RUN] Would mark PR #${metadata.draftPrNumber} as ready for review`);
|
|
2211
1366
|
}
|
|
2212
|
-
const prUrl = (
|
|
1367
|
+
const prUrl = (_d = metadata.prUrls) == null ? void 0 : _d[String(metadata.draftPrNumber)];
|
|
2213
1368
|
if (prUrl) {
|
|
2214
1369
|
result.prUrl = prUrl;
|
|
2215
1370
|
}
|
|
@@ -2243,7 +1398,17 @@ var FinishCommand = class {
|
|
|
2243
1398
|
getLogger().debug("Skipping build verification (--skip-build flag provided)");
|
|
2244
1399
|
}
|
|
2245
1400
|
await this.generateSessionSummaryIfConfigured(parsed, worktree, options);
|
|
2246
|
-
|
|
1401
|
+
const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-XJ2YB762.js");
|
|
1402
|
+
const metadataManager = new MetadataManager2();
|
|
1403
|
+
if (!options.dryRun) {
|
|
1404
|
+
await metadataManager.archiveMetadata(worktree.path);
|
|
1405
|
+
}
|
|
1406
|
+
if (options.cleanup === false) {
|
|
1407
|
+
getLogger().info("Worktree kept active (--no-cleanup flag)");
|
|
1408
|
+
getLogger().info(`To cleanup later: il cleanup ${parsed.originalInput}`);
|
|
1409
|
+
} else {
|
|
1410
|
+
await this.performPostMergeCleanup(parsed, options, worktree, result);
|
|
1411
|
+
}
|
|
2247
1412
|
}
|
|
2248
1413
|
/**
|
|
2249
1414
|
* Execute workflow for Pull Requests
|
|
@@ -2252,7 +1417,7 @@ var FinishCommand = class {
|
|
|
2252
1417
|
* - CLOSED/MERGED: Skip to cleanup
|
|
2253
1418
|
*/
|
|
2254
1419
|
async executePRWorkflow(parsed, options, worktree, pr, result) {
|
|
2255
|
-
var _a, _b;
|
|
1420
|
+
var _a, _b, _c;
|
|
2256
1421
|
if (pr.state === "closed" || pr.state === "merged") {
|
|
2257
1422
|
getLogger().info(`PR #${parsed.number} is ${pr.state.toUpperCase()} - skipping to cleanup`);
|
|
2258
1423
|
const gitStatus = await this.commitManager.detectUncommittedChanges(worktree.path);
|
|
@@ -2262,6 +1427,11 @@ var FinishCommand = class {
|
|
|
2262
1427
|
"Cannot cleanup PR with uncommitted changes. Commit or stash changes, then run again with --force to cleanup anyway."
|
|
2263
1428
|
);
|
|
2264
1429
|
}
|
|
1430
|
+
const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-XJ2YB762.js");
|
|
1431
|
+
const metadataManager = new MetadataManager2();
|
|
1432
|
+
if (!options.dryRun) {
|
|
1433
|
+
await metadataManager.archiveMetadata(worktree.path);
|
|
1434
|
+
}
|
|
2265
1435
|
await this.performPRCleanup(parsed, options, worktree, pr.state, result);
|
|
2266
1436
|
getLogger().success(`PR #${parsed.number} cleanup completed`);
|
|
2267
1437
|
result.operations.push({
|
|
@@ -2284,10 +1454,13 @@ var FinishCommand = class {
|
|
|
2284
1454
|
getLogger().info("Committing uncommitted changes...");
|
|
2285
1455
|
const settings = await this.settingsManager.loadSettings(worktree.path);
|
|
2286
1456
|
const skipVerify = ((_b = (_a = settings.workflows) == null ? void 0 : _a.pr) == null ? void 0 : _b.noVerify) ?? false;
|
|
1457
|
+
const providerType = ((_c = settings.issueManagement) == null ? void 0 : _c.provider) ?? "github";
|
|
1458
|
+
const issuePrefix = IssueManagementProviderFactory.create(providerType).issuePrefix;
|
|
2287
1459
|
try {
|
|
2288
1460
|
await this.commitManager.commitChanges(worktree.path, {
|
|
2289
1461
|
dryRun: false,
|
|
2290
|
-
skipVerify
|
|
1462
|
+
skipVerify,
|
|
1463
|
+
issuePrefix
|
|
2291
1464
|
// Do NOT pass issueNumber for PRs - no "Fixes #" trailer needed
|
|
2292
1465
|
});
|
|
2293
1466
|
getLogger().success("Changes committed");
|
|
@@ -2386,6 +1559,11 @@ var FinishCommand = class {
|
|
|
2386
1559
|
}
|
|
2387
1560
|
finishResult.prUrl = prResult.url;
|
|
2388
1561
|
await this.generateSessionSummaryIfConfigured(parsed, worktree, options, prResult.number);
|
|
1562
|
+
const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-XJ2YB762.js");
|
|
1563
|
+
const metadataManager = new MetadataManager2();
|
|
1564
|
+
if (!options.dryRun) {
|
|
1565
|
+
await metadataManager.archiveMetadata(worktree.path);
|
|
1566
|
+
}
|
|
2389
1567
|
await this.handlePRCleanupPrompt(parsed, options, worktree, finishResult);
|
|
2390
1568
|
}
|
|
2391
1569
|
}
|
|
@@ -2740,7 +1918,7 @@ var FinishCommand = class {
|
|
|
2740
1918
|
// src/utils/package-info.ts
|
|
2741
1919
|
import { readFileSync } from "fs";
|
|
2742
1920
|
import { fileURLToPath } from "url";
|
|
2743
|
-
import { dirname, join
|
|
1921
|
+
import { dirname, join } from "path";
|
|
2744
1922
|
function getPackageInfo(scriptPath) {
|
|
2745
1923
|
try {
|
|
2746
1924
|
let basePath;
|
|
@@ -2751,7 +1929,7 @@ function getPackageInfo(scriptPath) {
|
|
|
2751
1929
|
basePath = __filename2;
|
|
2752
1930
|
}
|
|
2753
1931
|
const __dirname = dirname(basePath);
|
|
2754
|
-
const packageJsonPath =
|
|
1932
|
+
const packageJsonPath = join(__dirname, "..", "package.json");
|
|
2755
1933
|
const packageJsonContent = readFileSync(packageJsonPath, "utf8");
|
|
2756
1934
|
const packageJson2 = JSON.parse(packageJsonContent);
|
|
2757
1935
|
return packageJson2;
|
|
@@ -2778,12 +1956,12 @@ function determineLoomType(worktree) {
|
|
|
2778
1956
|
}
|
|
2779
1957
|
return "branch";
|
|
2780
1958
|
}
|
|
2781
|
-
function extractPRNumbers(
|
|
2782
|
-
if (!
|
|
1959
|
+
function extractPRNumbers(path6) {
|
|
1960
|
+
if (!path6) {
|
|
2783
1961
|
return [];
|
|
2784
1962
|
}
|
|
2785
1963
|
const prPathPattern = /_pr_(\d+)$/;
|
|
2786
|
-
const match =
|
|
1964
|
+
const match = path6.match(prPathPattern);
|
|
2787
1965
|
if (match == null ? void 0 : match[1]) {
|
|
2788
1966
|
return [match[1]];
|
|
2789
1967
|
}
|
|
@@ -2830,12 +2008,199 @@ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
|
|
|
2830
2008
|
colorHex: (metadata == null ? void 0 : metadata.colorHex) ?? null,
|
|
2831
2009
|
projectPath: (metadata == null ? void 0 : metadata.projectPath) ?? null,
|
|
2832
2010
|
issueUrls: (metadata == null ? void 0 : metadata.issueUrls) ?? {},
|
|
2833
|
-
prUrls: (metadata == null ? void 0 : metadata.prUrls) ?? {}
|
|
2011
|
+
prUrls: (metadata == null ? void 0 : metadata.prUrls) ?? {},
|
|
2012
|
+
capabilities: (metadata == null ? void 0 : metadata.capabilities) ?? []
|
|
2834
2013
|
};
|
|
2835
2014
|
}
|
|
2836
2015
|
function formatLoomsForJson(worktrees, mainWorktreePath, metadata) {
|
|
2837
2016
|
return worktrees.map((wt) => formatLoomForJson(wt, mainWorktreePath, metadata == null ? void 0 : metadata.get(wt.path)));
|
|
2838
2017
|
}
|
|
2018
|
+
function formatFinishedLoomForJson(metadata) {
|
|
2019
|
+
const loomType = metadata.issueType ?? "branch";
|
|
2020
|
+
return {
|
|
2021
|
+
name: metadata.branchName ?? metadata.worktreePath ?? "unknown",
|
|
2022
|
+
worktreePath: null,
|
|
2023
|
+
// Finished looms no longer have a worktree
|
|
2024
|
+
branch: metadata.branchName,
|
|
2025
|
+
type: loomType,
|
|
2026
|
+
issue_numbers: metadata.issue_numbers,
|
|
2027
|
+
pr_numbers: metadata.pr_numbers,
|
|
2028
|
+
isMainWorktree: false,
|
|
2029
|
+
// Finished looms are never the main worktree
|
|
2030
|
+
description: metadata.description ?? null,
|
|
2031
|
+
created_at: metadata.created_at ?? null,
|
|
2032
|
+
issueTracker: metadata.issueTracker ?? null,
|
|
2033
|
+
colorHex: metadata.colorHex ?? null,
|
|
2034
|
+
projectPath: metadata.projectPath ?? null,
|
|
2035
|
+
issueUrls: metadata.issueUrls ?? {},
|
|
2036
|
+
prUrls: metadata.prUrls ?? {},
|
|
2037
|
+
capabilities: metadata.capabilities ?? [],
|
|
2038
|
+
status: metadata.status ?? "finished",
|
|
2039
|
+
finishedAt: metadata.finishedAt ?? null
|
|
2040
|
+
};
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
// src/cli.ts
|
|
2044
|
+
import fs3 from "fs-extra";
|
|
2045
|
+
|
|
2046
|
+
// src/lib/VersionMigrationManager.ts
|
|
2047
|
+
import fs2 from "fs-extra";
|
|
2048
|
+
import path5 from "path";
|
|
2049
|
+
import os2 from "os";
|
|
2050
|
+
|
|
2051
|
+
// src/migrations/index.ts
|
|
2052
|
+
import fs from "fs-extra";
|
|
2053
|
+
import path4 from "path";
|
|
2054
|
+
import os from "os";
|
|
2055
|
+
var migrations = [
|
|
2056
|
+
// v0.6.0 is the baseline - no migrations needed
|
|
2057
|
+
{
|
|
2058
|
+
version: "0.6.1",
|
|
2059
|
+
description: "Add global gitignore for .iloom/settings.local.json",
|
|
2060
|
+
migrate: async () => {
|
|
2061
|
+
const globalIgnorePath = path4.join(os.homedir(), ".config", "git", "ignore");
|
|
2062
|
+
const pattern = "**/.iloom/settings.local.json";
|
|
2063
|
+
await fs.ensureDir(path4.dirname(globalIgnorePath));
|
|
2064
|
+
let content = "";
|
|
2065
|
+
try {
|
|
2066
|
+
content = await fs.readFile(globalIgnorePath, "utf-8");
|
|
2067
|
+
} catch {
|
|
2068
|
+
}
|
|
2069
|
+
if (content.includes(pattern)) {
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
const separator = content.endsWith("\n") || content === "" ? "" : "\n";
|
|
2073
|
+
const newContent = content + separator + "\n# Added by iloom CLI\n" + pattern + "\n";
|
|
2074
|
+
await fs.writeFile(globalIgnorePath, newContent, "utf-8");
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
];
|
|
2078
|
+
|
|
2079
|
+
// src/lib/VersionMigrationManager.ts
|
|
2080
|
+
var VersionMigrationManager = class {
|
|
2081
|
+
constructor() {
|
|
2082
|
+
this.DEFAULT_VERSION = "0.6.0";
|
|
2083
|
+
this.VERSION_OVERRIDE_ENV = "ILOOM_VERSION_OVERRIDE";
|
|
2084
|
+
}
|
|
2085
|
+
// Return path to migration state file
|
|
2086
|
+
getMigrationStatePath() {
|
|
2087
|
+
return path5.join(os2.homedir(), ".config", "iloom-ai", "migration-state.json");
|
|
2088
|
+
}
|
|
2089
|
+
// Get effective version, respecting ILOOM_VERSION_OVERRIDE env var
|
|
2090
|
+
// packageVersion is the version from package.json passed by caller
|
|
2091
|
+
getEffectiveVersion(packageVersion) {
|
|
2092
|
+
const override = process.env[this.VERSION_OVERRIDE_ENV];
|
|
2093
|
+
if (override && override.trim() !== "") {
|
|
2094
|
+
logger.debug(`[VersionMigrationManager] Using version override: ${override} (package.json: ${packageVersion})`);
|
|
2095
|
+
return override.trim();
|
|
2096
|
+
}
|
|
2097
|
+
return packageVersion;
|
|
2098
|
+
}
|
|
2099
|
+
// Load full migration state from file
|
|
2100
|
+
// Returns state with DEFAULT_VERSION if file missing/invalid
|
|
2101
|
+
async loadFullMigrationState() {
|
|
2102
|
+
const statePath = this.getMigrationStatePath();
|
|
2103
|
+
try {
|
|
2104
|
+
const content = await fs2.readFile(statePath, "utf-8");
|
|
2105
|
+
const state = JSON.parse(content);
|
|
2106
|
+
if (typeof state.lastMigratedVersion === "string") {
|
|
2107
|
+
return state;
|
|
2108
|
+
}
|
|
2109
|
+
} catch {
|
|
2110
|
+
logger.debug(`[VersionMigrationManager] Migration state not found, using default version: ${this.DEFAULT_VERSION}`);
|
|
2111
|
+
}
|
|
2112
|
+
return {
|
|
2113
|
+
lastMigratedVersion: this.DEFAULT_VERSION,
|
|
2114
|
+
migratedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2115
|
+
};
|
|
2116
|
+
}
|
|
2117
|
+
// Load last migrated version from state file
|
|
2118
|
+
// Returns DEFAULT_VERSION if file missing/invalid
|
|
2119
|
+
async loadMigrationState() {
|
|
2120
|
+
const state = await this.loadFullMigrationState();
|
|
2121
|
+
return state.lastMigratedVersion;
|
|
2122
|
+
}
|
|
2123
|
+
// Save current version to state file, preserving and appending to existing failures
|
|
2124
|
+
async saveMigrationState(version, newFailures = []) {
|
|
2125
|
+
const statePath = this.getMigrationStatePath();
|
|
2126
|
+
try {
|
|
2127
|
+
await fs2.ensureDir(path5.dirname(statePath));
|
|
2128
|
+
const existingState = await this.loadFullMigrationState();
|
|
2129
|
+
const existingFailures = existingState.failedMigrations ?? [];
|
|
2130
|
+
const allFailures = [...existingFailures];
|
|
2131
|
+
for (const newFailure of newFailures) {
|
|
2132
|
+
const existingIndex = allFailures.findIndex((f) => f.version === newFailure.version);
|
|
2133
|
+
if (existingIndex >= 0) {
|
|
2134
|
+
allFailures[existingIndex] = newFailure;
|
|
2135
|
+
} else {
|
|
2136
|
+
allFailures.push(newFailure);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
const state = {
|
|
2140
|
+
lastMigratedVersion: version,
|
|
2141
|
+
migratedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2142
|
+
...allFailures.length > 0 && { failedMigrations: allFailures }
|
|
2143
|
+
};
|
|
2144
|
+
await fs2.writeFile(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
2145
|
+
} catch (error) {
|
|
2146
|
+
logger.warn(`[VersionMigrationManager] Failed to save migration state: ${error}`);
|
|
2147
|
+
}
|
|
2148
|
+
}
|
|
2149
|
+
// Compare semver versions: returns negative if v1 < v2, positive if v1 > v2, 0 if equal
|
|
2150
|
+
// Pattern from update-notifier.ts:190-221
|
|
2151
|
+
compareVersions(v1, v2) {
|
|
2152
|
+
try {
|
|
2153
|
+
const parts1 = v1.split(".").map((p) => parseInt(p, 10));
|
|
2154
|
+
const parts2 = v2.split(".").map((p) => parseInt(p, 10));
|
|
2155
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
2156
|
+
const p1 = parts1[i] ?? 0;
|
|
2157
|
+
const p2 = parts2[i] ?? 0;
|
|
2158
|
+
if (p1 !== p2) return p1 - p2;
|
|
2159
|
+
}
|
|
2160
|
+
return 0;
|
|
2161
|
+
} catch {
|
|
2162
|
+
return 0;
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
// Get migrations that need to run (version > lastMigrated, version <= current)
|
|
2166
|
+
getPendingMigrations(lastMigratedVersion, currentVersion) {
|
|
2167
|
+
return migrations.filter(
|
|
2168
|
+
(m) => this.compareVersions(m.version, lastMigratedVersion) > 0 && this.compareVersions(m.version, currentVersion) <= 0
|
|
2169
|
+
).sort((a, b) => this.compareVersions(a.version, b.version));
|
|
2170
|
+
}
|
|
2171
|
+
// Main entry point - run any pending migrations
|
|
2172
|
+
// packageVersion is the version from package.json; may be overridden by ILOOM_VERSION_OVERRIDE
|
|
2173
|
+
async runMigrationsIfNeeded(packageVersion) {
|
|
2174
|
+
const currentVersion = this.getEffectiveVersion(packageVersion);
|
|
2175
|
+
const lastMigratedVersion = await this.loadMigrationState();
|
|
2176
|
+
if (this.compareVersions(lastMigratedVersion, currentVersion) >= 0) {
|
|
2177
|
+
return;
|
|
2178
|
+
}
|
|
2179
|
+
const pending = this.getPendingMigrations(lastMigratedVersion, currentVersion);
|
|
2180
|
+
if (pending.length === 0) {
|
|
2181
|
+
logger.debug(`[VersionMigrationManager] No migrations to run, updating state to ${currentVersion}`);
|
|
2182
|
+
await this.saveMigrationState(currentVersion);
|
|
2183
|
+
return;
|
|
2184
|
+
}
|
|
2185
|
+
const failedMigrations = [];
|
|
2186
|
+
for (const migration of pending) {
|
|
2187
|
+
logger.debug(`[VersionMigrationManager] Running migration to ${migration.version}: ${migration.description}`);
|
|
2188
|
+
try {
|
|
2189
|
+
await migration.migrate();
|
|
2190
|
+
logger.debug(`[VersionMigrationManager] Migration to ${migration.version} completed`);
|
|
2191
|
+
} catch (error) {
|
|
2192
|
+
logger.warn(`[VersionMigrationManager] Migration to ${migration.version} failed: ${error}`);
|
|
2193
|
+
failedMigrations.push({
|
|
2194
|
+
version: migration.version,
|
|
2195
|
+
description: migration.description,
|
|
2196
|
+
failedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2197
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2198
|
+
});
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
await this.saveMigrationState(currentVersion, failedMigrations);
|
|
2202
|
+
}
|
|
2203
|
+
};
|
|
2839
2204
|
|
|
2840
2205
|
// src/cli.ts
|
|
2841
2206
|
var __filename = fileURLToPath2(import.meta.url);
|
|
@@ -2868,6 +2233,12 @@ program.name("iloom").description(packageJson.description).version(packageJson.v
|
|
|
2868
2233
|
} catch (error) {
|
|
2869
2234
|
logger.debug(`Settings migration failed: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
2870
2235
|
}
|
|
2236
|
+
try {
|
|
2237
|
+
const versionMigrationManager = new VersionMigrationManager();
|
|
2238
|
+
await versionMigrationManager.runMigrationsIfNeeded(packageJson.version);
|
|
2239
|
+
} catch (error) {
|
|
2240
|
+
logger.warn(`Version migration failed: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
2241
|
+
}
|
|
2871
2242
|
await validateSettingsForCommand(actionCommand);
|
|
2872
2243
|
await validateGhCliForCommand(actionCommand);
|
|
2873
2244
|
await validateIdeForStartCommand(thisCommand);
|
|
@@ -2997,14 +2368,14 @@ async function autoLaunchInitForMultipleRemotes() {
|
|
|
2997
2368
|
await waitForKeypress2("Press any key to start configuration...");
|
|
2998
2369
|
logger.info("");
|
|
2999
2370
|
try {
|
|
3000
|
-
const { InitCommand: InitCommand2 } = await import("./init-
|
|
2371
|
+
const { InitCommand: InitCommand2 } = await import("./init-XQQMFDM6.js");
|
|
3001
2372
|
const initCommand = new InitCommand2();
|
|
3002
2373
|
const customInitialMessage = "Help me configure which git remote iloom should use for GitHub operations. I have multiple remotes and need to select the correct one.";
|
|
3003
2374
|
await initCommand.execute(customInitialMessage);
|
|
3004
2375
|
logger.info("");
|
|
3005
2376
|
logger.info("Configuration complete! Continuing with your original command...");
|
|
3006
2377
|
logger.info("");
|
|
3007
|
-
const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-
|
|
2378
|
+
const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-YU4VYPTW.js");
|
|
3008
2379
|
const settingsManager = new SettingsManager2();
|
|
3009
2380
|
const settings = await settingsManager.loadSettings();
|
|
3010
2381
|
const { hasMultipleRemotes: hasMultipleRemotes2 } = await import("./remote-IJAMOEAP.js");
|
|
@@ -3098,7 +2469,7 @@ program.command("add-issue").alias("a").description("Create and enhance GitHub i
|
|
|
3098
2469
|
});
|
|
3099
2470
|
program.command("feedback").alias("f").description("Submit feedback/bug report to iloom-cli repository").argument("<description>", "Feedback title (>30 chars, >2 spaces; or any non-empty text when --body provided)").option("--body <text>", "Body text for feedback (added after diagnostics)").action(async (description, options) => {
|
|
3100
2471
|
try {
|
|
3101
|
-
const { FeedbackCommand } = await import("./feedback-
|
|
2472
|
+
const { FeedbackCommand } = await import("./feedback-G7G5QCY4.js");
|
|
3102
2473
|
const command = new FeedbackCommand();
|
|
3103
2474
|
const feedbackOptions = {};
|
|
3104
2475
|
if (options.body !== void 0) {
|
|
@@ -3148,7 +2519,7 @@ program.command("enhance").description("Apply enhancement agent to existing GitH
|
|
|
3148
2519
|
await executeAction();
|
|
3149
2520
|
}
|
|
3150
2521
|
});
|
|
3151
|
-
program.command("finish").alias("dn").description("Merge work and cleanup workspace").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("-f, --force", "Skip confirmation prompts").option("-n, --dry-run", "Preview actions without executing").option("--pr <number>", "Treat input as PR number", parseFloat).option("--skip-build", "Skip post-merge build verification").option("--no-browser", "Skip opening PR in browser (github-pr mode only)").option("--cleanup", "Clean up worktree after
|
|
2522
|
+
program.command("finish").alias("dn").description("Merge work and cleanup workspace").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("-f, --force", "Skip confirmation prompts").option("-n, --dry-run", "Preview actions without executing").option("--pr <number>", "Treat input as PR number", parseFloat).option("--skip-build", "Skip post-merge build verification").option("--no-browser", "Skip opening PR in browser (github-pr mode only)").option("--cleanup", "Clean up worktree after finishing (default in local mode)").option("--no-cleanup", "Keep worktree after finishing").option("--json", "Output result as JSON").action(async (identifier, options) => {
|
|
3152
2523
|
const executeAction = async () => {
|
|
3153
2524
|
try {
|
|
3154
2525
|
const settingsManager = new SettingsManager();
|
|
@@ -3179,9 +2550,45 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
|
|
|
3179
2550
|
await executeAction();
|
|
3180
2551
|
}
|
|
3181
2552
|
});
|
|
2553
|
+
program.command("commit").alias("c").description("Commit all uncommitted files with issue reference").option("-m, --message <text>", "Custom commit message (skip Claude generation)").option("--fixes", 'Use "Fixes #N" trailer instead of "Refs #N" (closes issue)').option("--no-review", "Skip commit message review prompt").option("--json", "Output result as JSON (implies --no-review)").option("--wip-commit", "Quick WIP commit: skip validations and pre-commit hooks").action(async (options) => {
|
|
2554
|
+
const executeAction = async () => {
|
|
2555
|
+
try {
|
|
2556
|
+
const { CommitCommand } = await import("./commit-6S2RIA2K.js");
|
|
2557
|
+
const command = new CommitCommand();
|
|
2558
|
+
const noReview = options.review === false || options.json === true;
|
|
2559
|
+
const result = await command.execute({
|
|
2560
|
+
message: options.message,
|
|
2561
|
+
fixes: options.fixes ?? false,
|
|
2562
|
+
noReview,
|
|
2563
|
+
json: options.json ?? false,
|
|
2564
|
+
wipCommit: options.wipCommit ?? false
|
|
2565
|
+
});
|
|
2566
|
+
if (options.json && result) {
|
|
2567
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2568
|
+
}
|
|
2569
|
+
process.exit(0);
|
|
2570
|
+
} catch (error) {
|
|
2571
|
+
if (error instanceof UserAbortedCommitError) {
|
|
2572
|
+
process.exit(130);
|
|
2573
|
+
}
|
|
2574
|
+
if (options.json) {
|
|
2575
|
+
console.log(JSON.stringify({ success: false, error: error instanceof Error ? error.message : "Unknown error" }, null, 2));
|
|
2576
|
+
} else {
|
|
2577
|
+
logger.error(`Commit failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2578
|
+
}
|
|
2579
|
+
process.exit(1);
|
|
2580
|
+
}
|
|
2581
|
+
};
|
|
2582
|
+
if (options.json) {
|
|
2583
|
+
const jsonLogger = createStderrLogger();
|
|
2584
|
+
await withLogger(jsonLogger, executeAction);
|
|
2585
|
+
} else {
|
|
2586
|
+
await executeAction();
|
|
2587
|
+
}
|
|
2588
|
+
});
|
|
3182
2589
|
program.command("rebase").description("Rebase current branch on main with Claude-assisted conflict resolution").option("-f, --force", "Skip confirmation prompts").option("-n, --dry-run", "Preview actions without executing").action(async (options) => {
|
|
3183
2590
|
try {
|
|
3184
|
-
const { RebaseCommand } = await import("./rebase-
|
|
2591
|
+
const { RebaseCommand } = await import("./rebase-RKQED567.js");
|
|
3185
2592
|
const command = new RebaseCommand();
|
|
3186
2593
|
await command.execute(options);
|
|
3187
2594
|
} catch (error) {
|
|
@@ -3193,7 +2600,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
|
|
|
3193
2600
|
new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
|
|
3194
2601
|
).action(async (options) => {
|
|
3195
2602
|
try {
|
|
3196
|
-
const { IgniteCommand } = await import("./ignite-
|
|
2603
|
+
const { IgniteCommand } = await import("./ignite-YUAOJ5PP.js");
|
|
3197
2604
|
const command = new IgniteCommand();
|
|
3198
2605
|
await command.execute(options.oneShot ?? "default");
|
|
3199
2606
|
} catch (error) {
|
|
@@ -3204,7 +2611,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
|
|
|
3204
2611
|
program.command("open").description("Open workspace in browser or run CLI tool").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").allowUnknownOption().action(async (identifier, _options, command) => {
|
|
3205
2612
|
try {
|
|
3206
2613
|
const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
|
|
3207
|
-
const { OpenCommand } = await import("./open-
|
|
2614
|
+
const { OpenCommand } = await import("./open-MCWQAPSZ.js");
|
|
3208
2615
|
const cmd = new OpenCommand();
|
|
3209
2616
|
const input = identifier ? { identifier, args } : { args };
|
|
3210
2617
|
await cmd.execute(input);
|
|
@@ -3216,7 +2623,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
|
|
|
3216
2623
|
program.command("run").description("Run CLI tool or open workspace in browser").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").allowUnknownOption().action(async (identifier, _options, command) => {
|
|
3217
2624
|
try {
|
|
3218
2625
|
const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
|
|
3219
|
-
const { RunCommand } = await import("./run-
|
|
2626
|
+
const { RunCommand } = await import("./run-CCG24PBC.js");
|
|
3220
2627
|
const cmd = new RunCommand();
|
|
3221
2628
|
const input = identifier ? { identifier, args } : { args };
|
|
3222
2629
|
await cmd.execute(input);
|
|
@@ -3227,7 +2634,7 @@ program.command("run").description("Run CLI tool or open workspace in browser").
|
|
|
3227
2634
|
});
|
|
3228
2635
|
program.command("dev-server").alias("dev").description("Start dev server for workspace (foreground)").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").option("--json", "Output as JSON").action(async (identifier, options) => {
|
|
3229
2636
|
try {
|
|
3230
|
-
const { DevServerCommand } = await import("./dev-server-
|
|
2637
|
+
const { DevServerCommand } = await import("./dev-server-GREJUEKW.js");
|
|
3231
2638
|
const cmd = new DevServerCommand();
|
|
3232
2639
|
await cmd.execute({ identifier, json: options == null ? void 0 : options.json });
|
|
3233
2640
|
} catch (error) {
|
|
@@ -3237,7 +2644,7 @@ program.command("dev-server").alias("dev").description("Start dev server for wor
|
|
|
3237
2644
|
});
|
|
3238
2645
|
program.command("shell").alias("terminal").description("Open interactive shell with workspace environment").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
|
|
3239
2646
|
try {
|
|
3240
|
-
const { ShellCommand } = await import("./shell-
|
|
2647
|
+
const { ShellCommand } = await import("./shell-2NNSIU34.js");
|
|
3241
2648
|
const cmd = new ShellCommand();
|
|
3242
2649
|
await cmd.execute({ identifier });
|
|
3243
2650
|
} catch (error) {
|
|
@@ -3247,7 +2654,7 @@ program.command("shell").alias("terminal").description("Open interactive shell w
|
|
|
3247
2654
|
});
|
|
3248
2655
|
program.command("build").description("Run the build script").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
|
|
3249
2656
|
try {
|
|
3250
|
-
const { BuildCommand } = await import("./build-
|
|
2657
|
+
const { BuildCommand } = await import("./build-O2EJHDEW.js");
|
|
3251
2658
|
const cmd = new BuildCommand();
|
|
3252
2659
|
await cmd.execute(identifier ? { identifier } : {});
|
|
3253
2660
|
} catch (error) {
|
|
@@ -3257,7 +2664,7 @@ program.command("build").description("Run the build script").argument("[identifi
|
|
|
3257
2664
|
});
|
|
3258
2665
|
program.command("lint").description("Run the lint script").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
|
|
3259
2666
|
try {
|
|
3260
|
-
const { LintCommand } = await import("./lint-
|
|
2667
|
+
const { LintCommand } = await import("./lint-OFVN7FT6.js");
|
|
3261
2668
|
const cmd = new LintCommand();
|
|
3262
2669
|
await cmd.execute(identifier ? { identifier } : {});
|
|
3263
2670
|
} catch (error) {
|
|
@@ -3267,7 +2674,7 @@ program.command("lint").description("Run the lint script").argument("[identifier
|
|
|
3267
2674
|
});
|
|
3268
2675
|
program.command("test").description("Run the test script").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
|
|
3269
2676
|
try {
|
|
3270
|
-
const { TestCommand } = await import("./test-
|
|
2677
|
+
const { TestCommand } = await import("./test-QZDOEUIO.js");
|
|
3271
2678
|
const cmd = new TestCommand();
|
|
3272
2679
|
await cmd.execute(identifier ? { identifier } : {});
|
|
3273
2680
|
} catch (error) {
|
|
@@ -3277,7 +2684,7 @@ program.command("test").description("Run the test script").argument("[identifier
|
|
|
3277
2684
|
});
|
|
3278
2685
|
program.command("compile").alias("typecheck").description("Run the compile or typecheck script (prefers compile if both exist)").argument("[identifier]", "Issue number, PR number, or branch name (auto-detected if omitted)").action(async (identifier) => {
|
|
3279
2686
|
try {
|
|
3280
|
-
const { CompileCommand } = await import("./compile-
|
|
2687
|
+
const { CompileCommand } = await import("./compile-LRMAADUT.js");
|
|
3281
2688
|
const cmd = new CompileCommand();
|
|
3282
2689
|
await cmd.execute(identifier ? { identifier } : {});
|
|
3283
2690
|
} catch (error) {
|
|
@@ -3285,10 +2692,10 @@ program.command("compile").alias("typecheck").description("Run the compile or ty
|
|
|
3285
2692
|
process.exit(1);
|
|
3286
2693
|
}
|
|
3287
2694
|
});
|
|
3288
|
-
program.command("cleanup").alias("remove").alias("clean").description("Remove workspaces").argument("[identifier]", "Branch name or issue number to cleanup (auto-detected)").option("-l, --list", "List all worktrees").option("-a, --all", "Remove all worktrees (interactive confirmation)").option("-i, --issue <number>", "Cleanup by issue number", parseInt).option("-f, --force", "Skip confirmations and force removal").option("--dry-run", "Show what would be done without doing it").option("--json", "Output result as JSON").action(async (identifier, options) => {
|
|
2695
|
+
program.command("cleanup").alias("remove").alias("clean").description("Remove workspaces").argument("[identifier]", "Branch name or issue number to cleanup (auto-detected)").option("-l, --list", "List all worktrees").option("-a, --all", "Remove all worktrees (interactive confirmation)").option("-i, --issue <number>", "Cleanup by issue number", parseInt).option("-f, --force", "Skip confirmations and force removal").option("--dry-run", "Show what would be done without doing it").option("--json", "Output result as JSON").option("--defer <ms>", "Wait specified milliseconds before cleanup", parseInt).action(async (identifier, options) => {
|
|
3289
2696
|
const executeAction = async () => {
|
|
3290
2697
|
try {
|
|
3291
|
-
const { CleanupCommand } = await import("./cleanup-
|
|
2698
|
+
const { CleanupCommand } = await import("./cleanup-ZPOMRSNN.js");
|
|
3292
2699
|
const command = new CleanupCommand();
|
|
3293
2700
|
const input = {
|
|
3294
2701
|
options: options ?? {}
|
|
@@ -3317,15 +2724,78 @@ program.command("cleanup").alias("remove").alias("clean").description("Remove wo
|
|
|
3317
2724
|
await executeAction();
|
|
3318
2725
|
}
|
|
3319
2726
|
});
|
|
3320
|
-
program.command("list").description("Show active workspaces").option("--json", "Output as JSON").action(async (options) => {
|
|
2727
|
+
program.command("list").description("Show active workspaces").option("--json", "Output as JSON").option("--finished", "Show only finished looms (sorted by finish time, latest first)").option("--all", "Show both active and finished looms").option("--global", "Show looms from all projects (default: current project only)").action(async (options) => {
|
|
3321
2728
|
try {
|
|
3322
2729
|
const manager = new GitWorktreeManager();
|
|
3323
2730
|
const metadataManager = new MetadataManager();
|
|
3324
|
-
|
|
2731
|
+
let currentProjectPath = null;
|
|
2732
|
+
if (!options.global) {
|
|
2733
|
+
try {
|
|
2734
|
+
currentProjectPath = await findMainWorktreePathWithSettings();
|
|
2735
|
+
} catch (error) {
|
|
2736
|
+
if (error instanceof GitCommandError && (error.exitCode === 128 || /fatal: not a git repository/i.test(error.stderr))) {
|
|
2737
|
+
currentProjectPath = null;
|
|
2738
|
+
} else if (error instanceof Error && error.message.includes("Invalid settings")) {
|
|
2739
|
+
currentProjectPath = null;
|
|
2740
|
+
} else {
|
|
2741
|
+
throw error;
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
const showActive = !options.finished;
|
|
2746
|
+
const showFinished = Boolean(options.finished) || Boolean(options.all);
|
|
2747
|
+
let worktrees = [];
|
|
3325
2748
|
const metadata = /* @__PURE__ */ new Map();
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
2749
|
+
let globalActiveLooms = [];
|
|
2750
|
+
if (showActive) {
|
|
2751
|
+
if (options.global) {
|
|
2752
|
+
const allMetadata = await metadataManager.listAllMetadata();
|
|
2753
|
+
for (const loom of allMetadata) {
|
|
2754
|
+
if (!loom.worktreePath) {
|
|
2755
|
+
continue;
|
|
2756
|
+
}
|
|
2757
|
+
const pathExists = await fs3.pathExists(loom.worktreePath);
|
|
2758
|
+
if (!pathExists) {
|
|
2759
|
+
continue;
|
|
2760
|
+
}
|
|
2761
|
+
const isValid = await isValidGitRepo(loom.worktreePath);
|
|
2762
|
+
if (!isValid) {
|
|
2763
|
+
continue;
|
|
2764
|
+
}
|
|
2765
|
+
globalActiveLooms.push(loom);
|
|
2766
|
+
metadata.set(loom.worktreePath, loom);
|
|
2767
|
+
}
|
|
2768
|
+
} else {
|
|
2769
|
+
try {
|
|
2770
|
+
worktrees = await manager.listWorktrees({ porcelain: true });
|
|
2771
|
+
for (const worktree of worktrees) {
|
|
2772
|
+
const loomMetadata = await metadataManager.readMetadata(worktree.path);
|
|
2773
|
+
metadata.set(worktree.path, loomMetadata);
|
|
2774
|
+
}
|
|
2775
|
+
} catch (error) {
|
|
2776
|
+
if (error instanceof GitCommandError && (error.exitCode === 128 || /fatal: not a git repository/i.test(error.stderr))) {
|
|
2777
|
+
worktrees = [];
|
|
2778
|
+
} else {
|
|
2779
|
+
throw error;
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
let finishedLooms = [];
|
|
2785
|
+
if (showFinished) {
|
|
2786
|
+
finishedLooms = await metadataManager.listFinishedMetadata();
|
|
2787
|
+
}
|
|
2788
|
+
let filteredWorktrees = worktrees;
|
|
2789
|
+
let filteredGlobalActiveLooms = globalActiveLooms;
|
|
2790
|
+
let filteredFinishedLooms = finishedLooms;
|
|
2791
|
+
if (currentProjectPath) {
|
|
2792
|
+
filteredWorktrees = worktrees.filter((wt) => {
|
|
2793
|
+
const loomMetadata = metadata.get(wt.path);
|
|
2794
|
+
return (loomMetadata == null ? void 0 : loomMetadata.projectPath) == null || (loomMetadata == null ? void 0 : loomMetadata.projectPath) === currentProjectPath;
|
|
2795
|
+
});
|
|
2796
|
+
filteredFinishedLooms = finishedLooms.filter(
|
|
2797
|
+
(loom) => loom.projectPath == null || loom.projectPath === currentProjectPath
|
|
2798
|
+
);
|
|
3329
2799
|
}
|
|
3330
2800
|
if (options.json) {
|
|
3331
2801
|
let mainWorktreePath;
|
|
@@ -3333,26 +2803,108 @@ program.command("list").description("Show active workspaces").option("--json", "
|
|
|
3333
2803
|
mainWorktreePath = await findMainWorktreePathWithSettings();
|
|
3334
2804
|
} catch {
|
|
3335
2805
|
}
|
|
3336
|
-
|
|
2806
|
+
let activeJson = [];
|
|
2807
|
+
if (showActive) {
|
|
2808
|
+
if (options.global) {
|
|
2809
|
+
activeJson = globalActiveLooms.map((loom) => ({
|
|
2810
|
+
name: loom.branchName ?? loom.worktreePath ?? "unknown",
|
|
2811
|
+
worktreePath: loom.worktreePath,
|
|
2812
|
+
branch: loom.branchName,
|
|
2813
|
+
type: loom.issueType ?? "branch",
|
|
2814
|
+
issue_numbers: loom.issue_numbers,
|
|
2815
|
+
pr_numbers: loom.pr_numbers,
|
|
2816
|
+
isMainWorktree: false,
|
|
2817
|
+
// Global looms from other projects are never the main worktree
|
|
2818
|
+
description: loom.description ?? null,
|
|
2819
|
+
created_at: loom.created_at ?? null,
|
|
2820
|
+
issueTracker: loom.issueTracker ?? null,
|
|
2821
|
+
colorHex: loom.colorHex ?? null,
|
|
2822
|
+
projectPath: loom.projectPath ?? null,
|
|
2823
|
+
issueUrls: loom.issueUrls ?? {},
|
|
2824
|
+
prUrls: loom.prUrls ?? {},
|
|
2825
|
+
status: "active",
|
|
2826
|
+
finishedAt: null
|
|
2827
|
+
}));
|
|
2828
|
+
} else {
|
|
2829
|
+
activeJson = formatLoomsForJson(worktrees, mainWorktreePath, metadata).map((loom) => ({
|
|
2830
|
+
...loom,
|
|
2831
|
+
status: "active",
|
|
2832
|
+
finishedAt: null
|
|
2833
|
+
}));
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
if (currentProjectPath && !options.global) {
|
|
2837
|
+
activeJson = activeJson.filter(
|
|
2838
|
+
(loom) => loom.projectPath == null || loom.projectPath === currentProjectPath
|
|
2839
|
+
);
|
|
2840
|
+
}
|
|
2841
|
+
let finishedJson = finishedLooms.map(formatFinishedLoomForJson);
|
|
2842
|
+
if (currentProjectPath) {
|
|
2843
|
+
finishedJson = finishedJson.filter(
|
|
2844
|
+
(loom) => loom.projectPath == null || loom.projectPath === currentProjectPath
|
|
2845
|
+
);
|
|
2846
|
+
}
|
|
2847
|
+
const allLooms = [...activeJson, ...finishedJson];
|
|
2848
|
+
console.log(JSON.stringify(allLooms, null, 2));
|
|
3337
2849
|
return;
|
|
3338
2850
|
}
|
|
3339
|
-
|
|
3340
|
-
|
|
2851
|
+
const hasActive = options.global ? filteredGlobalActiveLooms.length > 0 : filteredWorktrees.length > 0;
|
|
2852
|
+
const hasFinished = filteredFinishedLooms.length > 0;
|
|
2853
|
+
if (!hasActive && !hasFinished) {
|
|
2854
|
+
if (options.finished) {
|
|
2855
|
+
logger.info("No finished looms found");
|
|
2856
|
+
} else if (options.all) {
|
|
2857
|
+
logger.info("No looms found");
|
|
2858
|
+
} else {
|
|
2859
|
+
logger.info("No worktrees found");
|
|
2860
|
+
}
|
|
3341
2861
|
return;
|
|
3342
2862
|
}
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
2863
|
+
if (showActive && hasActive) {
|
|
2864
|
+
logger.info("Active workspaces:");
|
|
2865
|
+
if (options.global) {
|
|
2866
|
+
for (const loom of filteredGlobalActiveLooms) {
|
|
2867
|
+
logger.info(` ${loom.branchName ?? "unknown"}`);
|
|
2868
|
+
if (loom.description) {
|
|
2869
|
+
logger.info(` Description: ${loom.description}`);
|
|
2870
|
+
}
|
|
2871
|
+
if (loom.worktreePath) {
|
|
2872
|
+
logger.info(` Path: ${loom.worktreePath}`);
|
|
2873
|
+
}
|
|
2874
|
+
if (loom.projectPath) {
|
|
2875
|
+
logger.info(` Project: ${loom.projectPath}`);
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
} else {
|
|
2879
|
+
for (const worktree of filteredWorktrees) {
|
|
2880
|
+
const formatted = manager.formatWorktree(worktree);
|
|
2881
|
+
const loomMetadata = metadata.get(worktree.path);
|
|
2882
|
+
logger.info(` ${formatted.title}`);
|
|
2883
|
+
if (loomMetadata == null ? void 0 : loomMetadata.description) {
|
|
2884
|
+
logger.info(` Description: ${loomMetadata.description}`);
|
|
2885
|
+
}
|
|
2886
|
+
logger.info(` Path: ${formatted.path}`);
|
|
2887
|
+
logger.info(` Commit: ${formatted.commit}`);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
if (showFinished && hasFinished) {
|
|
2892
|
+
if (showActive && hasActive) {
|
|
2893
|
+
logger.info("");
|
|
2894
|
+
}
|
|
2895
|
+
logger.info("Finished looms:");
|
|
2896
|
+
for (const loom of filteredFinishedLooms) {
|
|
2897
|
+
logger.info(` ${loom.branchName ?? "unknown"}`);
|
|
2898
|
+
if (loom.description) {
|
|
2899
|
+
logger.info(` Description: ${loom.description}`);
|
|
2900
|
+
}
|
|
2901
|
+
if (loom.finishedAt) {
|
|
2902
|
+
logger.info(` Finished: ${new Date(loom.finishedAt).toLocaleString()}`);
|
|
2903
|
+
}
|
|
3350
2904
|
}
|
|
3351
|
-
logger.info(` Path: ${formatted.path}`);
|
|
3352
|
-
logger.info(` Commit: ${formatted.commit}`);
|
|
3353
2905
|
}
|
|
3354
2906
|
} catch (error) {
|
|
3355
|
-
if (error instanceof
|
|
2907
|
+
if (error instanceof GitCommandError && (error.exitCode === 128 || /fatal: not a git repository/i.test(error.stderr))) {
|
|
3356
2908
|
if (options.json) {
|
|
3357
2909
|
console.log("[]");
|
|
3358
2910
|
} else {
|
|
@@ -3366,7 +2918,7 @@ program.command("list").description("Show active workspaces").option("--json", "
|
|
|
3366
2918
|
});
|
|
3367
2919
|
program.command("projects").description("List configured iloom projects").option("--json", "Output as JSON (default behavior)").action(async (options) => {
|
|
3368
2920
|
try {
|
|
3369
|
-
const { ProjectsCommand } = await import("./projects-
|
|
2921
|
+
const { ProjectsCommand } = await import("./projects-PQOTWUII.js");
|
|
3370
2922
|
const command = new ProjectsCommand();
|
|
3371
2923
|
const result = await command.execute(options);
|
|
3372
2924
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -3377,7 +2929,7 @@ program.command("projects").description("List configured iloom projects").option
|
|
|
3377
2929
|
});
|
|
3378
2930
|
program.command("init").alias("config").description("Initialize iloom configuration").argument("[prompt]", 'Custom initial message to send to Claude (defaults to "Help me configure iloom settings.")').action(async (prompt) => {
|
|
3379
2931
|
try {
|
|
3380
|
-
const { InitCommand: InitCommand2 } = await import("./init-
|
|
2932
|
+
const { InitCommand: InitCommand2 } = await import("./init-XQQMFDM6.js");
|
|
3381
2933
|
const command = new InitCommand2();
|
|
3382
2934
|
const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
|
|
3383
2935
|
const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
|
|
@@ -3387,11 +2939,11 @@ program.command("init").alias("config").description("Initialize iloom configurat
|
|
|
3387
2939
|
process.exit(1);
|
|
3388
2940
|
}
|
|
3389
2941
|
});
|
|
3390
|
-
program.command("contribute").description("Set up local development environment for contributing to iloom").action(async () => {
|
|
2942
|
+
program.command("contribute").description("Set up local development environment for contributing to a GitHub project").argument("[repository]", "GitHub repository (owner/repo, github.com/owner/repo, or full URL). Defaults to iloom-ai/iloom-cli").action(async (repository) => {
|
|
3391
2943
|
try {
|
|
3392
|
-
const { ContributeCommand } = await import("./contribute-
|
|
2944
|
+
const { ContributeCommand } = await import("./contribute-GXKOIA42.js");
|
|
3393
2945
|
const command = new ContributeCommand();
|
|
3394
|
-
await command.execute();
|
|
2946
|
+
await command.execute(repository);
|
|
3395
2947
|
} catch (error) {
|
|
3396
2948
|
logger.error(`Failed to set up contributor environment: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3397
2949
|
process.exit(1);
|
|
@@ -3409,8 +2961,8 @@ program.command("update").description("Update iloom-cli to the latest version").
|
|
|
3409
2961
|
});
|
|
3410
2962
|
program.command("test-github").description("Test GitHub integration (Issue #3)").argument("<identifier>", "Issue number or PR number").option("--no-claude", "Skip Claude for branch name generation").action(async (identifier, options) => {
|
|
3411
2963
|
try {
|
|
3412
|
-
const { GitHubService: GitHubService2 } = await import("./GitHubService-
|
|
3413
|
-
const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-
|
|
2964
|
+
const { GitHubService: GitHubService2 } = await import("./GitHubService-O7U4UQ7N.js");
|
|
2965
|
+
const { DefaultBranchNamingService: DefaultBranchNamingService2 } = await import("./BranchNamingService-FLPUUFOB.js");
|
|
3414
2966
|
logger.info("Testing GitHub Integration\n");
|
|
3415
2967
|
const service = new GitHubService2();
|
|
3416
2968
|
const branchNaming = new DefaultBranchNamingService2({ useClaude: options.claude !== false });
|
|
@@ -3468,14 +3020,14 @@ program.command("test-github").description("Test GitHub integration (Issue #3)")
|
|
|
3468
3020
|
});
|
|
3469
3021
|
program.command("test-claude").description("Test Claude integration (Issue #10)").option("--detect", "Test Claude CLI detection").option("--version", "Get Claude CLI version").option("--branch <title>", "Test branch name generation with given title").option("--issue <number>", "Issue number for branch generation", "123").option("--launch <prompt>", "Launch Claude with a prompt (headless)").option("--interactive", "Launch Claude interactively (requires --launch)").option("--template <name>", "Test template loading").action(async (options) => {
|
|
3470
3022
|
try {
|
|
3471
|
-
const { detectClaudeCli
|
|
3472
|
-
const { PromptTemplateManager } = await import("./PromptTemplateManager-
|
|
3473
|
-
const { ClaudeService } = await import("./ClaudeService-
|
|
3474
|
-
const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-
|
|
3023
|
+
const { detectClaudeCli, getClaudeVersion, generateBranchName, launchClaude: launchClaude2 } = await import("./claude-6H36IBHO.js");
|
|
3024
|
+
const { PromptTemplateManager } = await import("./PromptTemplateManager-7L3HJQQU.js");
|
|
3025
|
+
const { ClaudeService } = await import("./ClaudeService-CRSETT3A.js");
|
|
3026
|
+
const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-KE5TBZVZ.js");
|
|
3475
3027
|
logger.info("Testing Claude Integration\n");
|
|
3476
3028
|
if (options.detect) {
|
|
3477
3029
|
logger.info("Detecting Claude CLI...");
|
|
3478
|
-
const isAvailable = await
|
|
3030
|
+
const isAvailable = await detectClaudeCli();
|
|
3479
3031
|
if (isAvailable) {
|
|
3480
3032
|
logger.success(" Claude CLI is available");
|
|
3481
3033
|
} else {
|
|
@@ -3531,7 +3083,7 @@ program.command("test-claude").description("Test Claude integration (Issue #10)"
|
|
|
3531
3083
|
if (!options.detect && !options.version && !options.branch && !options.launch && !options.template) {
|
|
3532
3084
|
logger.info("Running full Claude integration test suite...\n");
|
|
3533
3085
|
logger.info("1. Testing Claude CLI detection...");
|
|
3534
|
-
const isAvailable = await
|
|
3086
|
+
const isAvailable = await detectClaudeCli();
|
|
3535
3087
|
if (isAvailable) {
|
|
3536
3088
|
logger.success(" Claude CLI is available");
|
|
3537
3089
|
} else {
|
|
@@ -3606,7 +3158,7 @@ program.command("test-claude").description("Test Claude integration (Issue #10)"
|
|
|
3606
3158
|
});
|
|
3607
3159
|
program.command("test-webserver").description("Test if a web server is running on a workspace port").argument("<issue-number>", "Issue number (port will be calculated as 3000 + issue number)", parseInt).option("--kill", "Kill the web server if detected").action(async (issueNumber, options) => {
|
|
3608
3160
|
try {
|
|
3609
|
-
const { TestWebserverCommand } = await import("./test-webserver-
|
|
3161
|
+
const { TestWebserverCommand } = await import("./test-webserver-NRMGT2HB.js");
|
|
3610
3162
|
const command = new TestWebserverCommand();
|
|
3611
3163
|
await command.execute({ issueNumber, options });
|
|
3612
3164
|
} catch (error) {
|
|
@@ -3619,7 +3171,7 @@ program.command("test-webserver").description("Test if a web server is running o
|
|
|
3619
3171
|
});
|
|
3620
3172
|
program.command("test-git").description("Test Git integration - findMainWorktreePath() function (reads .iloom/settings.json)").action(async () => {
|
|
3621
3173
|
try {
|
|
3622
|
-
const { TestGitCommand } = await import("./test-git-
|
|
3174
|
+
const { TestGitCommand } = await import("./test-git-E2BLXR6M.js");
|
|
3623
3175
|
const command = new TestGitCommand();
|
|
3624
3176
|
await command.execute();
|
|
3625
3177
|
} catch (error) {
|
|
@@ -3645,7 +3197,7 @@ program.command("test-tabs").description("Test iTerm2 dual tab functionality - o
|
|
|
3645
3197
|
});
|
|
3646
3198
|
program.command("test-prefix").description("Test worktree prefix configuration - preview worktree paths (reads .iloom/settings.json)").action(async () => {
|
|
3647
3199
|
try {
|
|
3648
|
-
const { TestPrefixCommand } = await import("./test-prefix-
|
|
3200
|
+
const { TestPrefixCommand } = await import("./test-prefix-A7JGGYAA.js");
|
|
3649
3201
|
const command = new TestPrefixCommand();
|
|
3650
3202
|
await command.execute();
|
|
3651
3203
|
} catch (error) {
|
|
@@ -3659,7 +3211,7 @@ program.command("test-prefix").description("Test worktree prefix configuration -
|
|
|
3659
3211
|
program.command("summary").description("Generate Claude session summary for a loom").argument("[identifier]", "Issue number, PR number (pr/123), or branch name (auto-detected if omitted)").option("--with-comment", "Post summary as a comment to the issue/PR").option("--json", "Output result as JSON").action(async (identifier, options) => {
|
|
3660
3212
|
const executeAction = async () => {
|
|
3661
3213
|
try {
|
|
3662
|
-
const { SummaryCommand } = await import("./summary-
|
|
3214
|
+
const { SummaryCommand } = await import("./summary-G6L3VAKK.js");
|
|
3663
3215
|
const command = new SummaryCommand();
|
|
3664
3216
|
const result = await command.execute({ identifier, options });
|
|
3665
3217
|
if (options.json && result) {
|
|
@@ -3688,7 +3240,7 @@ program.command("summary").description("Generate Claude session summary for a lo
|
|
|
3688
3240
|
program.command("recap").description("Get recap for a loom (defaults to current directory)").argument("[identifier]", "Issue number, PR number (pr/123), or branch name (auto-detected if omitted)").option("--json", "Output as JSON with filePath for file watching").action(async (identifier, options) => {
|
|
3689
3241
|
const executeAction = async () => {
|
|
3690
3242
|
try {
|
|
3691
|
-
const { RecapCommand } = await import("./recap-
|
|
3243
|
+
const { RecapCommand } = await import("./recap-ZKGHZCX6.js");
|
|
3692
3244
|
const command = new RecapCommand();
|
|
3693
3245
|
const result = await command.execute({ identifier, json: options.json });
|
|
3694
3246
|
if (options.json && result) {
|
|
@@ -3717,7 +3269,7 @@ program.command("recap").description("Get recap for a loom (defaults to current
|
|
|
3717
3269
|
program.command("test-neon").description("Test Neon integration and debug configuration").action(async () => {
|
|
3718
3270
|
var _a;
|
|
3719
3271
|
try {
|
|
3720
|
-
const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-
|
|
3272
|
+
const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-YU4VYPTW.js");
|
|
3721
3273
|
const { createNeonProviderFromSettings: createNeonProviderFromSettings2 } = await import("./neon-helpers-3KBC4A3Y.js");
|
|
3722
3274
|
logger.info("Testing Neon Integration\n");
|
|
3723
3275
|
logger.info("1. Settings Configuration:");
|