@iloom/cli 0.9.2 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +160 -41
- package/dist/{BranchNamingService-K6XNWQ6C.js → BranchNamingService-25KSZAEM.js} +2 -2
- package/dist/ClaudeContextManager-66GR4BGM.js +14 -0
- package/dist/ClaudeService-7KM5NA5Z.js +13 -0
- package/dist/{GitHubService-TGWJN4V4.js → GitHubService-MEHKHUQP.js} +4 -4
- package/dist/IssueTrackerFactory-NG53YX5S.js +14 -0
- package/dist/{LoomLauncher-73NXL2CL.js → LoomLauncher-TDLZSYG2.js} +9 -9
- package/dist/{MetadataManager-W3C54UYT.js → MetadataManager-5QZSTKNN.js} +2 -2
- package/dist/{ProjectCapabilityDetector-N5L7T4IY.js → ProjectCapabilityDetector-5KSYUTBJ.js} +3 -3
- package/dist/{PromptTemplateManager-36YLQRHP.js → PromptTemplateManager-YOE2SIPG.js} +2 -2
- package/dist/README.md +160 -41
- package/dist/{SettingsManager-AW3JTJHD.js → SettingsManager-FNKCOZMQ.js} +4 -2
- package/dist/agents/iloom-artifact-reviewer.md +11 -0
- package/dist/agents/iloom-code-reviewer.md +14 -0
- package/dist/agents/iloom-issue-analyze-and-plan.md +55 -12
- package/dist/agents/iloom-issue-analyzer.md +49 -6
- package/dist/agents/iloom-issue-complexity-evaluator.md +47 -6
- package/dist/agents/iloom-issue-enhancer.md +86 -7
- package/dist/agents/iloom-issue-implementer.md +48 -7
- package/dist/agents/iloom-issue-planner.md +115 -62
- package/dist/{build-THZI572G.js → build-VHGEMXBA.js} +9 -9
- package/dist/chunk-4232AHNQ.js +35 -0
- package/dist/chunk-4232AHNQ.js.map +1 -0
- package/dist/chunk-4E7LCFUG.js +24 -0
- package/dist/chunk-4E7LCFUG.js.map +1 -0
- package/dist/{chunk-AR5QKYNE.js → chunk-4FGEGQW4.js} +4 -4
- package/dist/{chunk-R4YWBGY6.js → chunk-5FJWO4IT.js} +67 -22
- package/dist/chunk-5FJWO4IT.js.map +1 -0
- package/dist/{chunk-VPTAX5TR.js → chunk-5RPBYK5Q.js} +35 -30
- package/dist/chunk-5RPBYK5Q.js.map +1 -0
- package/dist/{chunk-YKFCCV6S.js → chunk-63QWFWH3.js} +7 -7
- package/dist/chunk-63QWFWH3.js.map +1 -0
- package/dist/{chunk-RI2YL6TK.js → chunk-7VHJNVLF.js} +80 -23
- package/dist/chunk-7VHJNVLF.js.map +1 -0
- package/dist/{chunk-B7U6OKUR.js → chunk-C6HNNJIV.js} +11 -3
- package/dist/chunk-C6HNNJIV.js.map +1 -0
- package/dist/{chunk-A7NJF73J.js → chunk-CVCTIDDK.js} +4 -4
- package/dist/{chunk-Z2TWEXR7.js → chunk-E6KOWMKA.js} +6 -6
- package/dist/chunk-E6KOWMKA.js.map +1 -0
- package/dist/{chunk-3I4ONZRT.js → chunk-EVPZFV3K.js} +10 -10
- package/dist/chunk-EVPZFV3K.js.map +1 -0
- package/dist/{chunk-IZIYLYPK.js → chunk-G5V75JD5.js} +2 -2
- package/dist/chunk-GRISNU6G.js +651 -0
- package/dist/chunk-GRISNU6G.js.map +1 -0
- package/dist/chunk-HEXKPKCK.js +1396 -0
- package/dist/chunk-HEXKPKCK.js.map +1 -0
- package/dist/{chunk-TC7APDKU.js → chunk-I5T677EA.js} +2 -2
- package/dist/{chunk-KBEIQP4G.js → chunk-KB64WNBZ.js} +43 -3
- package/dist/chunk-KB64WNBZ.js.map +1 -0
- package/dist/{chunk-NWMORW3U.js → chunk-KIK2ZFAL.js} +2 -2
- package/dist/{chunk-CWRI4JC3.js → chunk-KKV5WH5M.js} +30 -31
- package/dist/chunk-KKV5WH5M.js.map +1 -0
- package/dist/{chunk-DGG2VY7B.js → chunk-KVHIAWVT.js} +9 -9
- package/dist/chunk-KVHIAWVT.js.map +1 -0
- package/dist/{chunk-OFDN5NKS.js → chunk-KXDRI47U.js} +69 -12
- package/dist/chunk-KXDRI47U.js.map +1 -0
- package/dist/{chunk-NUACL52E.js → chunk-LLHXQS3C.js} +2 -2
- package/dist/chunk-LUKXJSRI.js +73 -0
- package/dist/chunk-LUKXJSRI.js.map +1 -0
- package/dist/{chunk-TL72BGP6.js → chunk-MORRVYPT.js} +2 -2
- package/dist/chunk-OTGH2HRS.js +1427 -0
- package/dist/chunk-OTGH2HRS.js.map +1 -0
- package/dist/{chunk-7ZEHSSUP.js → chunk-P4O6EH46.js} +4 -4
- package/dist/{chunk-KAYXR544.js → chunk-QVLPWNE3.js} +2 -2
- package/dist/chunk-QZWEJVWV.js +207 -0
- package/dist/chunk-QZWEJVWV.js.map +1 -0
- package/dist/chunk-RJ3VBUFK.js +781 -0
- package/dist/chunk-RJ3VBUFK.js.map +1 -0
- package/dist/chunk-RSYT7MVI.js +202 -0
- package/dist/chunk-RSYT7MVI.js.map +1 -0
- package/dist/{chunk-6IIL5M2L.js → chunk-S7PZA6IV.js} +10 -8
- package/dist/{chunk-6IIL5M2L.js.map → chunk-S7PZA6IV.js.map} +1 -1
- package/dist/chunk-SKSYYBCU.js +229 -0
- package/dist/chunk-SKSYYBCU.js.map +1 -0
- package/dist/{chunk-ULSWCPQG.js → chunk-SWSJWA2S.js} +476 -5
- package/dist/chunk-SWSJWA2S.js.map +1 -0
- package/dist/{chunk-KXGQYLFZ.js → chunk-UKBAJ2QQ.js} +61 -7
- package/dist/chunk-UKBAJ2QQ.js.map +1 -0
- package/dist/{chunk-FO5GGFOV.js → chunk-UR5DGNUO.js} +71 -9
- package/dist/chunk-UR5DGNUO.js.map +1 -0
- package/dist/{chunk-QN47QVBX.js → chunk-UUEW5KWB.js} +1 -1
- package/dist/chunk-UUEW5KWB.js.map +1 -0
- package/dist/{chunk-4CO6KG5S.js → chunk-VG45TUYK.js} +53 -7
- package/dist/{chunk-4CO6KG5S.js.map → chunk-VG45TUYK.js.map} +1 -1
- package/dist/{chunk-4LKGCFGG.js → chunk-WWKOVDWC.js} +2 -2
- package/dist/{chunk-KJTVU3HZ.js → chunk-WXIM2WS7.js} +8 -8
- package/dist/chunk-WXIM2WS7.js.map +1 -0
- package/dist/{chunk-VOGGLPG5.js → chunk-YQ57ORTV.js} +14 -1
- package/dist/chunk-YQ57ORTV.js.map +1 -0
- package/dist/{chunk-SOSQILHO.js → chunk-ZNMPGMHY.js} +44 -797
- package/dist/chunk-ZNMPGMHY.js.map +1 -0
- package/dist/{claude-TP2QO3BU.js → claude-7GGEWVEM.js} +2 -2
- package/dist/{cleanup-PJRIFFU4.js → cleanup-6PVAC4NI.js} +85 -34
- package/dist/cleanup-6PVAC4NI.js.map +1 -0
- package/dist/cli.js +630 -801
- package/dist/cli.js.map +1 -1
- package/dist/{commit-IVP3M4HG.js → commit-FZR5XDQG.js} +26 -23
- package/dist/commit-FZR5XDQG.js.map +1 -0
- package/dist/{compile-R2J65HBQ.js → compile-7ALJHZ4N.js} +9 -9
- package/dist/{contribute-VDZXHK5Y.js → contribute-5GKLK3BQ.js} +14 -6
- package/dist/contribute-5GKLK3BQ.js.map +1 -0
- package/dist/{dev-server-7F622OEO.js → dev-server-7SMIB7OF.js} +29 -15
- package/dist/dev-server-7SMIB7OF.js.map +1 -0
- package/dist/{feedback-E7VET7CL.js → feedback-G2GJFN2F.js} +18 -16
- package/dist/{feedback-E7VET7CL.js.map → feedback-G2GJFN2F.js.map} +1 -1
- package/dist/{git-2QDQ2X2S.js → git-GTLKAZRJ.js} +4 -4
- package/dist/hooks/iloom-hook.js +15 -0
- package/dist/ignite-H2O5Y5A2.js +34 -0
- package/dist/ignite-H2O5Y5A2.js.map +1 -0
- package/dist/index.d.ts +482 -58
- package/dist/index.js +1340 -44
- package/dist/index.js.map +1 -1
- package/dist/{init-676DHF6R.js → init-32YOKXRL.js} +57 -21
- package/dist/init-32YOKXRL.js.map +1 -0
- package/dist/{issues-PJSOLOBJ.js → issues-4UUAQ5K6.js} +61 -20
- package/dist/issues-4UUAQ5K6.js.map +1 -0
- package/dist/{lint-CJM7BAIM.js → lint-AAN2NZWG.js} +9 -9
- package/dist/mcp/harness-server.js +140 -0
- package/dist/mcp/harness-server.js.map +1 -0
- package/dist/mcp/issue-management-server.js +2599 -262
- package/dist/mcp/issue-management-server.js.map +1 -1
- package/dist/mcp/recap-server.js +144 -21
- package/dist/mcp/recap-server.js.map +1 -1
- package/dist/{neon-helpers-VVFFTLXE.js → neon-helpers-CQN2PB4S.js} +3 -3
- package/dist/neon-helpers-CQN2PB4S.js.map +1 -0
- package/dist/{open-544H7JF5.js → open-FXWW3VI4.js} +15 -15
- package/dist/open-FXWW3VI4.js.map +1 -0
- package/dist/{plan-Q7ELXDLC.js → plan-RQ5FPIGF.js} +358 -40
- package/dist/plan-RQ5FPIGF.js.map +1 -0
- package/dist/{projects-LH362JZQ.js → projects-2UOXFLNZ.js} +4 -4
- package/dist/prompts/CLAUDE.md +62 -0
- package/dist/prompts/init-prompt.txt +430 -34
- package/dist/prompts/issue-prompt.txt +473 -54
- package/dist/prompts/plan-prompt.txt +140 -19
- package/dist/prompts/pr-prompt.txt +44 -1
- package/dist/prompts/regular-prompt.txt +42 -1
- package/dist/prompts/session-summary-prompt.txt +14 -0
- package/dist/prompts/swarm-orchestrator-prompt.txt +464 -0
- package/dist/{rebase-YND35CIE.js → rebase-6NVLX5V7.js} +21 -12
- package/dist/rebase-6NVLX5V7.js.map +1 -0
- package/dist/{recap-3W7COH7D.js → recap-OMBOKJST.js} +47 -19
- package/dist/recap-OMBOKJST.js.map +1 -0
- package/dist/{run-QUXJKDQQ.js → run-BBXLRIZB.js} +15 -15
- package/dist/run-BBXLRIZB.js.map +1 -0
- package/dist/schema/package-iloom.schema.json +58 -0
- package/dist/schema/settings.schema.json +149 -15
- package/dist/{shell-QGECBLST.js → shell-RF7LTND5.js} +14 -7
- package/dist/shell-RF7LTND5.js.map +1 -0
- package/dist/{summary-G2T4452H.js → summary-WTQZ7XG2.js} +27 -25
- package/dist/summary-WTQZ7XG2.js.map +1 -0
- package/dist/{test-EA5NQFDC.js → test-SGO6I5Z7.js} +9 -9
- package/dist/{test-git-M7LSLEFL.js → test-git-XM4TM65W.js} +4 -4
- package/dist/test-jira-LDTOYFSD.js +96 -0
- package/dist/test-jira-LDTOYFSD.js.map +1 -0
- package/dist/{test-prefix-64NAAUON.js → test-prefix-GBO37XCN.js} +4 -4
- package/dist/{test-webserver-OK6Z5FJM.js → test-webserver-NZ3JTVLL.js} +6 -6
- package/dist/{vscode-AR5NNXXI.js → vscode-6XUGHJKL.js} +7 -7
- package/package.json +5 -1
- package/dist/ClaudeContextManager-HR5JQKAI.js +0 -14
- package/dist/ClaudeService-TK7FMC2X.js +0 -13
- package/dist/chunk-3I4ONZRT.js.map +0 -1
- package/dist/chunk-B7U6OKUR.js.map +0 -1
- package/dist/chunk-CWRI4JC3.js.map +0 -1
- package/dist/chunk-DGG2VY7B.js.map +0 -1
- package/dist/chunk-FJDRTVJX.js +0 -520
- package/dist/chunk-FJDRTVJX.js.map +0 -1
- package/dist/chunk-FO5GGFOV.js.map +0 -1
- package/dist/chunk-KBEIQP4G.js.map +0 -1
- package/dist/chunk-KJTVU3HZ.js.map +0 -1
- package/dist/chunk-KXGQYLFZ.js.map +0 -1
- package/dist/chunk-OFDN5NKS.js.map +0 -1
- package/dist/chunk-QN47QVBX.js.map +0 -1
- package/dist/chunk-R4YWBGY6.js.map +0 -1
- package/dist/chunk-RI2YL6TK.js.map +0 -1
- package/dist/chunk-SOSQILHO.js.map +0 -1
- package/dist/chunk-ULSWCPQG.js.map +0 -1
- package/dist/chunk-VOGGLPG5.js.map +0 -1
- package/dist/chunk-VPTAX5TR.js.map +0 -1
- package/dist/chunk-W6DP5RVR.js +0 -101
- package/dist/chunk-W6DP5RVR.js.map +0 -1
- package/dist/chunk-WHI5KEOX.js +0 -121
- package/dist/chunk-WHI5KEOX.js.map +0 -1
- package/dist/chunk-YKFCCV6S.js.map +0 -1
- package/dist/chunk-Z2TWEXR7.js.map +0 -1
- package/dist/cleanup-PJRIFFU4.js.map +0 -1
- package/dist/commit-IVP3M4HG.js.map +0 -1
- package/dist/contribute-VDZXHK5Y.js.map +0 -1
- package/dist/dev-server-7F622OEO.js.map +0 -1
- package/dist/ignite-IW35CDBD.js +0 -784
- package/dist/ignite-IW35CDBD.js.map +0 -1
- package/dist/init-676DHF6R.js.map +0 -1
- package/dist/issues-PJSOLOBJ.js.map +0 -1
- package/dist/open-544H7JF5.js.map +0 -1
- package/dist/plan-Q7ELXDLC.js.map +0 -1
- package/dist/rebase-YND35CIE.js.map +0 -1
- package/dist/recap-3W7COH7D.js.map +0 -1
- package/dist/run-QUXJKDQQ.js.map +0 -1
- package/dist/shell-QGECBLST.js.map +0 -1
- package/dist/summary-G2T4452H.js.map +0 -1
- /package/dist/{BranchNamingService-K6XNWQ6C.js.map → BranchNamingService-25KSZAEM.js.map} +0 -0
- /package/dist/{ClaudeContextManager-HR5JQKAI.js.map → ClaudeContextManager-66GR4BGM.js.map} +0 -0
- /package/dist/{ClaudeService-TK7FMC2X.js.map → ClaudeService-7KM5NA5Z.js.map} +0 -0
- /package/dist/{GitHubService-TGWJN4V4.js.map → GitHubService-MEHKHUQP.js.map} +0 -0
- /package/dist/{MetadataManager-W3C54UYT.js.map → IssueTrackerFactory-NG53YX5S.js.map} +0 -0
- /package/dist/{LoomLauncher-73NXL2CL.js.map → LoomLauncher-TDLZSYG2.js.map} +0 -0
- /package/dist/{ProjectCapabilityDetector-N5L7T4IY.js.map → MetadataManager-5QZSTKNN.js.map} +0 -0
- /package/dist/{PromptTemplateManager-36YLQRHP.js.map → ProjectCapabilityDetector-5KSYUTBJ.js.map} +0 -0
- /package/dist/{SettingsManager-AW3JTJHD.js.map → PromptTemplateManager-YOE2SIPG.js.map} +0 -0
- /package/dist/{claude-TP2QO3BU.js.map → SettingsManager-FNKCOZMQ.js.map} +0 -0
- /package/dist/{build-THZI572G.js.map → build-VHGEMXBA.js.map} +0 -0
- /package/dist/{chunk-AR5QKYNE.js.map → chunk-4FGEGQW4.js.map} +0 -0
- /package/dist/{chunk-A7NJF73J.js.map → chunk-CVCTIDDK.js.map} +0 -0
- /package/dist/{chunk-IZIYLYPK.js.map → chunk-G5V75JD5.js.map} +0 -0
- /package/dist/{chunk-TC7APDKU.js.map → chunk-I5T677EA.js.map} +0 -0
- /package/dist/{chunk-NWMORW3U.js.map → chunk-KIK2ZFAL.js.map} +0 -0
- /package/dist/{chunk-NUACL52E.js.map → chunk-LLHXQS3C.js.map} +0 -0
- /package/dist/{chunk-TL72BGP6.js.map → chunk-MORRVYPT.js.map} +0 -0
- /package/dist/{chunk-7ZEHSSUP.js.map → chunk-P4O6EH46.js.map} +0 -0
- /package/dist/{chunk-KAYXR544.js.map → chunk-QVLPWNE3.js.map} +0 -0
- /package/dist/{chunk-4LKGCFGG.js.map → chunk-WWKOVDWC.js.map} +0 -0
- /package/dist/{git-2QDQ2X2S.js.map → claude-7GGEWVEM.js.map} +0 -0
- /package/dist/{compile-R2J65HBQ.js.map → compile-7ALJHZ4N.js.map} +0 -0
- /package/dist/{neon-helpers-VVFFTLXE.js.map → git-GTLKAZRJ.js.map} +0 -0
- /package/dist/{lint-CJM7BAIM.js.map → lint-AAN2NZWG.js.map} +0 -0
- /package/dist/{projects-LH362JZQ.js.map → projects-2UOXFLNZ.js.map} +0 -0
- /package/dist/{test-EA5NQFDC.js.map → test-SGO6I5Z7.js.map} +0 -0
- /package/dist/{test-git-M7LSLEFL.js.map → test-git-XM4TM65W.js.map} +0 -0
- /package/dist/{test-prefix-64NAAUON.js.map → test-prefix-GBO37XCN.js.map} +0 -0
- /package/dist/{test-webserver-OK6Z5FJM.js.map → test-webserver-NZ3JTVLL.js.map} +0 -0
- /package/dist/{vscode-AR5NNXXI.js.map → vscode-6XUGHJKL.js.map} +0 -0
|
@@ -1,46 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
PRManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-KVHIAWVT.js";
|
|
5
5
|
import {
|
|
6
6
|
calculatePortForBranch,
|
|
7
7
|
calculatePortFromIdentifier
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-LLHXQS3C.js";
|
|
9
9
|
import {
|
|
10
10
|
installDependencies,
|
|
11
11
|
runScript
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-WWKOVDWC.js";
|
|
13
13
|
import {
|
|
14
14
|
getPackageConfig,
|
|
15
15
|
hasScript
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-YQ57ORTV.js";
|
|
17
|
+
import {
|
|
18
|
+
generateRandomSessionId
|
|
19
|
+
} from "./chunk-UR5DGNUO.js";
|
|
17
20
|
import {
|
|
18
21
|
GitCommandError,
|
|
19
22
|
PLACEHOLDER_COMMIT_PREFIX,
|
|
20
23
|
branchExists,
|
|
21
|
-
checkRemoteBranchStatus,
|
|
22
24
|
ensureRepositoryHasCommits,
|
|
23
25
|
executeGitCommand,
|
|
24
26
|
extractIssueNumber,
|
|
25
27
|
extractPRNumber,
|
|
26
28
|
fetchOrigin,
|
|
27
|
-
findMainWorktreePathWithSettings,
|
|
28
|
-
findWorktreeForBranch,
|
|
29
|
-
getMergeTargetBranch,
|
|
30
|
-
hasUncommittedChanges,
|
|
31
|
-
isBranchMergedIntoMain,
|
|
32
29
|
isFileTrackedByGit,
|
|
33
30
|
pushBranchToRemote
|
|
34
|
-
} from "./chunk-
|
|
35
|
-
import {
|
|
36
|
-
SettingsManager
|
|
37
|
-
} from "./chunk-RI2YL6TK.js";
|
|
31
|
+
} from "./chunk-4FGEGQW4.js";
|
|
38
32
|
import {
|
|
39
33
|
MetadataManager
|
|
40
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-KB64WNBZ.js";
|
|
41
35
|
import {
|
|
42
36
|
GitHubService
|
|
43
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-KXDRI47U.js";
|
|
38
|
+
import {
|
|
39
|
+
getLogger
|
|
40
|
+
} from "./chunk-6MLEBAYZ.js";
|
|
44
41
|
import {
|
|
45
42
|
calculateForegroundColor,
|
|
46
43
|
generateColorFromBranchName,
|
|
@@ -49,12 +46,6 @@ import {
|
|
|
49
46
|
rgbToHex,
|
|
50
47
|
selectDistinctColor
|
|
51
48
|
} from "./chunk-433MOLAU.js";
|
|
52
|
-
import {
|
|
53
|
-
generateRandomSessionId
|
|
54
|
-
} from "./chunk-FO5GGFOV.js";
|
|
55
|
-
import {
|
|
56
|
-
getLogger
|
|
57
|
-
} from "./chunk-6MLEBAYZ.js";
|
|
58
49
|
import {
|
|
59
50
|
detectDarkMode,
|
|
60
51
|
findEnvFileForDatabaseUrl,
|
|
@@ -244,10 +235,10 @@ var LoomManager = class {
|
|
|
244
235
|
* NEW: Checks for existing worktrees and reuses them if found
|
|
245
236
|
*/
|
|
246
237
|
async createIloom(input) {
|
|
247
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
|
|
238
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
|
|
248
239
|
getLogger().info("Fetching issue data...");
|
|
249
240
|
const issueData = await this.fetchIssueData(input);
|
|
250
|
-
if (input.type === "issue" || input.type === "pr" || input.type === "branch") {
|
|
241
|
+
if (input.type === "issue" || input.type === "epic" || input.type === "pr" || input.type === "branch") {
|
|
251
242
|
getLogger().info("Checking for existing worktree...");
|
|
252
243
|
const existing = await this.findExistingIloom(input, issueData);
|
|
253
244
|
if (existing) {
|
|
@@ -332,7 +323,7 @@ var LoomManager = class {
|
|
|
332
323
|
let draftPrNumber = void 0;
|
|
333
324
|
let draftPrUrl = void 0;
|
|
334
325
|
const mergeBehavior = settingsData.mergeBehavior ?? { mode: "local" };
|
|
335
|
-
if (mergeBehavior.mode === "github-draft-pr" && (input.type === "issue" || input.type === "branch")) {
|
|
326
|
+
if (mergeBehavior.mode === "github-draft-pr" && (input.type === "issue" || input.type === "epic" || input.type === "branch")) {
|
|
336
327
|
const prManager = new PRManager(settingsData);
|
|
337
328
|
getLogger().info("Fetching from origin...");
|
|
338
329
|
await executeGitCommand(["fetch", "origin"], { cwd: worktreePath });
|
|
@@ -367,6 +358,8 @@ var LoomManager = class {
|
|
|
367
358
|
getLogger().debug("Placeholder commit created");
|
|
368
359
|
getLogger().info("Pushing branch to remote for draft PR...");
|
|
369
360
|
await pushBranchToRemote(branchName, worktreePath, { dryRun: false });
|
|
361
|
+
await executeGitCommand(["reset", "--soft", "HEAD~1"], { cwd: worktreePath });
|
|
362
|
+
getLogger().debug("Placeholder commit removed from local branch (still on remote)");
|
|
370
363
|
}
|
|
371
364
|
const existingPR = await prManager.checkForExistingPR(branchName, worktreePath);
|
|
372
365
|
if (existingPR) {
|
|
@@ -376,7 +369,7 @@ var LoomManager = class {
|
|
|
376
369
|
} else {
|
|
377
370
|
const prTitle = (issueData == null ? void 0 : issueData.title) ?? `Work on ${branchName}`;
|
|
378
371
|
let prBody;
|
|
379
|
-
if (input.type === "issue") {
|
|
372
|
+
if (input.type === "issue" || input.type === "epic") {
|
|
380
373
|
const issueBody = (issueData == null ? void 0 : issueData.body) ? `
|
|
381
374
|
|
|
382
375
|
## ${issueData.title}
|
|
@@ -419,7 +412,7 @@ ${issueData.body}` : "";
|
|
|
419
412
|
error
|
|
420
413
|
);
|
|
421
414
|
}
|
|
422
|
-
if (input.type === "issue") {
|
|
415
|
+
if (input.type === "issue" || input.type === "epic") {
|
|
423
416
|
try {
|
|
424
417
|
getLogger().info("Moving issue to In Progress...");
|
|
425
418
|
if (this.issueTracker.moveIssueToInProgress) {
|
|
@@ -440,8 +433,8 @@ ${issueData.body}` : "";
|
|
|
440
433
|
const setArguments = (_k = input.options) == null ? void 0 : _k.setArguments;
|
|
441
434
|
const executablePath = (_l = input.options) == null ? void 0 : _l.executablePath;
|
|
442
435
|
if (enableClaude || enableCode || enableDevServer || enableTerminal) {
|
|
443
|
-
const { LoomLauncher } = await import("./LoomLauncher-
|
|
444
|
-
const { ClaudeContextManager } = await import("./ClaudeContextManager-
|
|
436
|
+
const { LoomLauncher } = await import("./LoomLauncher-TDLZSYG2.js");
|
|
437
|
+
const { ClaudeContextManager } = await import("./ClaudeContextManager-66GR4BGM.js");
|
|
445
438
|
const claudeContext = new ClaudeContextManager(void 0, void 0, this.settings);
|
|
446
439
|
const launcher = new LoomLauncher(claudeContext, this.settings);
|
|
447
440
|
await launcher.launchLoom({
|
|
@@ -453,7 +446,7 @@ ${issueData.body}` : "";
|
|
|
453
446
|
branchName,
|
|
454
447
|
port,
|
|
455
448
|
capabilities,
|
|
456
|
-
workflowType: input.type === "branch" ? "regular" : input.type,
|
|
449
|
+
workflowType: input.type === "branch" ? "regular" : input.type === "epic" ? "issue" : input.type,
|
|
457
450
|
identifier: input.identifier,
|
|
458
451
|
...(issueData == null ? void 0 : issueData.title) && { title: issueData.title },
|
|
459
452
|
oneShot,
|
|
@@ -467,7 +460,7 @@ ${issueData.body}` : "";
|
|
|
467
460
|
const description = (issueData == null ? void 0 : issueData.title) ?? branchName;
|
|
468
461
|
let issue_numbers = [];
|
|
469
462
|
let extractedIssueNum = null;
|
|
470
|
-
if (input.type === "issue") {
|
|
463
|
+
if (input.type === "issue" || input.type === "epic") {
|
|
471
464
|
issue_numbers = [String(input.identifier)];
|
|
472
465
|
} else if (input.type === "pr") {
|
|
473
466
|
extractedIssueNum = extractIssueNumber(branchName);
|
|
@@ -481,7 +474,7 @@ ${issueData.body}` : "";
|
|
|
481
474
|
}
|
|
482
475
|
const sessionId = generateRandomSessionId();
|
|
483
476
|
let issueUrls = {};
|
|
484
|
-
if (input.type === "issue" && (issueData == null ? void 0 : issueData.url)) {
|
|
477
|
+
if ((input.type === "issue" || input.type === "epic") && (issueData == null ? void 0 : issueData.url)) {
|
|
485
478
|
issueUrls = { [String(input.identifier)]: issueData.url };
|
|
486
479
|
} else if (input.type === "pr" && extractedIssueNum && (issueData == null ? void 0 : issueData.url)) {
|
|
487
480
|
const issueUrl = issueData.url.replace(`/pull/${input.identifier}`, `/issues/${extractedIssueNum}`);
|
|
@@ -493,6 +486,7 @@ ${issueData.body}` : "";
|
|
|
493
486
|
branchName,
|
|
494
487
|
worktreePath,
|
|
495
488
|
issueType: input.type,
|
|
489
|
+
...(input.type === "issue" || input.type === "epic") && { issueKey: this.issueTracker.normalizeIdentifier(input.identifier) },
|
|
496
490
|
issue_numbers,
|
|
497
491
|
pr_numbers,
|
|
498
492
|
issueTracker: this.issueTracker.providerName,
|
|
@@ -504,6 +498,9 @@ ${issueData.body}` : "";
|
|
|
504
498
|
capabilities,
|
|
505
499
|
...draftPrNumber && { draftPrNumber },
|
|
506
500
|
...((_o = input.options) == null ? void 0 : _o.oneShot) && { oneShot: input.options.oneShot },
|
|
501
|
+
...((_p = input.options) == null ? void 0 : _p.childIssueNumbers) && input.options.childIssueNumbers.length > 0 && { childIssueNumbers: input.options.childIssueNumbers },
|
|
502
|
+
...((_q = input.options) == null ? void 0 : _q.childIssues) && input.options.childIssues.length > 0 && { childIssues: input.options.childIssues },
|
|
503
|
+
...((_r = input.options) == null ? void 0 : _r.dependencyMap) && Object.keys(input.options.dependencyMap).length > 0 && { dependencyMap: input.options.dependencyMap },
|
|
507
504
|
...input.parentLoom && { parentLoom: input.parentLoom }
|
|
508
505
|
};
|
|
509
506
|
await this.metadataManager.writeMetadata(worktreePath, metadataInput);
|
|
@@ -592,7 +589,7 @@ ${issueData.body}` : "";
|
|
|
592
589
|
async checkAndWarnChildLooms(branchName) {
|
|
593
590
|
let targetBranch = branchName;
|
|
594
591
|
if (!targetBranch) {
|
|
595
|
-
const { getCurrentBranch } = await import("./git-
|
|
592
|
+
const { getCurrentBranch } = await import("./git-GTLKAZRJ.js");
|
|
596
593
|
targetBranch = await getCurrentBranch();
|
|
597
594
|
}
|
|
598
595
|
if (!targetBranch) {
|
|
@@ -621,7 +618,7 @@ ${issueData.body}` : "";
|
|
|
621
618
|
* Fetch issue/PR data based on input type
|
|
622
619
|
*/
|
|
623
620
|
async fetchIssueData(input) {
|
|
624
|
-
if (input.type === "issue") {
|
|
621
|
+
if (input.type === "issue" || input.type === "epic") {
|
|
625
622
|
return await this.issueTracker.fetchIssue(input.identifier);
|
|
626
623
|
} else if (input.type === "pr") {
|
|
627
624
|
if (this.issueTracker.supportsPullRequests && this.issueTracker.fetchPR) {
|
|
@@ -645,7 +642,7 @@ ${issueData.body}` : "";
|
|
|
645
642
|
if (input.type === "pr" && issueData && "branch" in issueData) {
|
|
646
643
|
return issueData.branch;
|
|
647
644
|
}
|
|
648
|
-
if (input.type === "issue" && issueData) {
|
|
645
|
+
if ((input.type === "issue" || input.type === "epic") && issueData) {
|
|
649
646
|
const branchName = await this.branchNaming.generateBranchName({
|
|
650
647
|
issueNumber: input.identifier,
|
|
651
648
|
title: issueData.title
|
|
@@ -918,7 +915,7 @@ ${issueData.body}` : "";
|
|
|
918
915
|
async setupPortForWeb(worktreePath, input, basePort) {
|
|
919
916
|
const envFilePath = path2.join(worktreePath, ".env.local");
|
|
920
917
|
const options = { basePort };
|
|
921
|
-
if (input.type === "issue") {
|
|
918
|
+
if (input.type === "issue" || input.type === "epic") {
|
|
922
919
|
options.issueNumber = input.identifier;
|
|
923
920
|
} else if (input.type === "pr") {
|
|
924
921
|
options.prNumber = input.identifier;
|
|
@@ -963,7 +960,7 @@ ${issueData.body}` : "";
|
|
|
963
960
|
var _a, _b;
|
|
964
961
|
const settingsData = await this.settings.loadSettings();
|
|
965
962
|
const basePort = ((_b = (_a = settingsData.capabilities) == null ? void 0 : _a.web) == null ? void 0 : _b.basePort) ?? 3e3;
|
|
966
|
-
if (input.type === "issue") {
|
|
963
|
+
if (input.type === "issue" || input.type === "epic") {
|
|
967
964
|
if (typeof input.identifier === "number") {
|
|
968
965
|
return this.environment.calculatePort({ basePort, issueNumber: input.identifier });
|
|
969
966
|
} else if (typeof input.identifier === "string") {
|
|
@@ -1017,8 +1014,8 @@ ${issueData.body}` : "";
|
|
|
1017
1014
|
let identifier = wt.branch;
|
|
1018
1015
|
if (loomMetadata == null ? void 0 : loomMetadata.issueType) {
|
|
1019
1016
|
type = loomMetadata.issueType;
|
|
1020
|
-
if (type === "issue" && ((_a = loomMetadata.issue_numbers) == null ? void 0 : _a[0])) {
|
|
1021
|
-
const issueId = loomMetadata.issue_numbers[0];
|
|
1017
|
+
if (type === "issue" && (loomMetadata.issueKey || ((_a = loomMetadata.issue_numbers) == null ? void 0 : _a[0]))) {
|
|
1018
|
+
const issueId = loomMetadata.issueKey ?? loomMetadata.issue_numbers[0] ?? "";
|
|
1022
1019
|
const numericId = parseInt(issueId, 10);
|
|
1023
1020
|
identifier = isNaN(numericId) ? issueId : numericId;
|
|
1024
1021
|
} else if (type === "pr" && ((_b = loomMetadata.pr_numbers) == null ? void 0 : _b[0])) {
|
|
@@ -1080,7 +1077,7 @@ ${issueData.body}` : "";
|
|
|
1080
1077
|
* Ports: handle_existing_worktree() from bash script lines 168-215
|
|
1081
1078
|
*/
|
|
1082
1079
|
async reuseIloom(worktree, input, issueData) {
|
|
1083
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
1080
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
1084
1081
|
const worktreePath = worktree.path;
|
|
1085
1082
|
const branchName = worktree.branch;
|
|
1086
1083
|
this.loadMainEnvFile();
|
|
@@ -1140,8 +1137,8 @@ ${issueData.body}` : "";
|
|
|
1140
1137
|
const executablePath = (_i = input.options) == null ? void 0 : _i.executablePath;
|
|
1141
1138
|
if (enableClaude || enableCode || enableDevServer || enableTerminal) {
|
|
1142
1139
|
getLogger().info("Launching workspace components...");
|
|
1143
|
-
const { LoomLauncher } = await import("./LoomLauncher-
|
|
1144
|
-
const { ClaudeContextManager } = await import("./ClaudeContextManager-
|
|
1140
|
+
const { LoomLauncher } = await import("./LoomLauncher-TDLZSYG2.js");
|
|
1141
|
+
const { ClaudeContextManager } = await import("./ClaudeContextManager-66GR4BGM.js");
|
|
1145
1142
|
const claudeContext = new ClaudeContextManager(void 0, void 0, this.settings);
|
|
1146
1143
|
const launcher = new LoomLauncher(claudeContext, this.settings);
|
|
1147
1144
|
await launcher.launchLoom({
|
|
@@ -1153,7 +1150,7 @@ ${issueData.body}` : "";
|
|
|
1153
1150
|
branchName,
|
|
1154
1151
|
port,
|
|
1155
1152
|
capabilities,
|
|
1156
|
-
workflowType: input.type === "branch" ? "regular" : input.type,
|
|
1153
|
+
workflowType: input.type === "branch" ? "regular" : input.type === "epic" ? "issue" : input.type,
|
|
1157
1154
|
identifier: input.identifier,
|
|
1158
1155
|
...(issueData == null ? void 0 : issueData.title) && { title: issueData.title },
|
|
1159
1156
|
oneShot,
|
|
@@ -1191,6 +1188,7 @@ ${issueData.body}` : "";
|
|
|
1191
1188
|
branchName,
|
|
1192
1189
|
worktreePath,
|
|
1193
1190
|
issueType: input.type,
|
|
1191
|
+
...input.type === "issue" && { issueKey: this.issueTracker.normalizeIdentifier(input.identifier) },
|
|
1194
1192
|
issue_numbers,
|
|
1195
1193
|
pr_numbers,
|
|
1196
1194
|
issueTracker: this.issueTracker.providerName,
|
|
@@ -1201,6 +1199,7 @@ ${issueData.body}` : "";
|
|
|
1201
1199
|
prUrls,
|
|
1202
1200
|
capabilities,
|
|
1203
1201
|
...((_l = input.options) == null ? void 0 : _l.oneShot) && { oneShot: input.options.oneShot },
|
|
1202
|
+
...((_m = input.options) == null ? void 0 : _m.childIssueNumbers) && input.options.childIssueNumbers.length > 0 && { childIssueNumbers: input.options.childIssueNumbers },
|
|
1204
1203
|
...input.parentLoom && { parentLoom: input.parentLoom }
|
|
1205
1204
|
};
|
|
1206
1205
|
await this.metadataManager.writeMetadata(worktreePath, metadataInput);
|
|
@@ -1875,762 +1874,10 @@ var DatabaseManager = class {
|
|
|
1875
1874
|
}
|
|
1876
1875
|
};
|
|
1877
1876
|
|
|
1878
|
-
// src/lib/ResourceCleanup.ts
|
|
1879
|
-
import path5 from "path";
|
|
1880
|
-
|
|
1881
|
-
// src/utils/recap-archiver.ts
|
|
1882
|
-
import path4 from "path";
|
|
1883
|
-
import os2 from "os";
|
|
1884
|
-
import fs6 from "fs-extra";
|
|
1885
|
-
var RECAPS_DIR = path4.join(os2.homedir(), ".config", "iloom-ai", "recaps");
|
|
1886
|
-
var ARCHIVED_DIR = path4.join(RECAPS_DIR, "archived");
|
|
1887
|
-
function slugifyPath(loomPath) {
|
|
1888
|
-
let slug = loomPath.replace(/[/\\]+$/, "");
|
|
1889
|
-
slug = slug.replace(/[/\\]/g, "___");
|
|
1890
|
-
slug = slug.replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
1891
|
-
return `${slug}.json`;
|
|
1892
|
-
}
|
|
1893
|
-
async function archiveRecap(worktreePath) {
|
|
1894
|
-
const filename = slugifyPath(worktreePath);
|
|
1895
|
-
const sourcePath = path4.join(RECAPS_DIR, filename);
|
|
1896
|
-
if (!await fs6.pathExists(sourcePath)) {
|
|
1897
|
-
getLogger().debug(`No recap file to archive for worktree: ${worktreePath}`);
|
|
1898
|
-
return;
|
|
1899
|
-
}
|
|
1900
|
-
const content = await fs6.readFile(sourcePath, "utf8");
|
|
1901
|
-
const data = JSON.parse(content);
|
|
1902
|
-
const archivedData = {
|
|
1903
|
-
...data,
|
|
1904
|
-
archivedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1905
|
-
};
|
|
1906
|
-
await fs6.ensureDir(ARCHIVED_DIR, { mode: 493 });
|
|
1907
|
-
const destPath = path4.join(ARCHIVED_DIR, filename);
|
|
1908
|
-
await fs6.writeFile(destPath, JSON.stringify(archivedData, null, 2), { mode: 420 });
|
|
1909
|
-
await fs6.unlink(sourcePath);
|
|
1910
|
-
getLogger().debug(`Recap archived for worktree: ${worktreePath}`);
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1913
|
-
// src/lib/ResourceCleanup.ts
|
|
1914
|
-
var ResourceCleanup = class {
|
|
1915
|
-
constructor(gitWorktree, processManager, database, cliIsolation, settingsManager) {
|
|
1916
|
-
this.gitWorktree = gitWorktree;
|
|
1917
|
-
this.processManager = processManager;
|
|
1918
|
-
this.database = database;
|
|
1919
|
-
this.cliIsolation = cliIsolation;
|
|
1920
|
-
this.settingsManager = settingsManager ?? new SettingsManager();
|
|
1921
|
-
this.metadataManager = new MetadataManager();
|
|
1922
|
-
}
|
|
1923
|
-
/**
|
|
1924
|
-
* Cleanup a worktree and associated resources
|
|
1925
|
-
* Main orchestration method
|
|
1926
|
-
*
|
|
1927
|
-
* @param parsed - ParsedInput from IdentifierParser with type information
|
|
1928
|
-
* @param options - Cleanup options
|
|
1929
|
-
*/
|
|
1930
|
-
async cleanupWorktree(parsed, options = {}) {
|
|
1931
|
-
var _a, _b, _c;
|
|
1932
|
-
const operations = [];
|
|
1933
|
-
const errors = [];
|
|
1934
|
-
const displayIdentifier = parsed.branchName ?? ((_a = parsed.number) == null ? void 0 : _a.toString()) ?? parsed.originalInput;
|
|
1935
|
-
getLogger().info(`Starting cleanup for: ${displayIdentifier}`);
|
|
1936
|
-
const number = parsed.number;
|
|
1937
|
-
if (number !== void 0) {
|
|
1938
|
-
const settings = await this.settingsManager.loadSettings();
|
|
1939
|
-
const basePort = ((_c = (_b = settings == null ? void 0 : settings.capabilities) == null ? void 0 : _b.web) == null ? void 0 : _c.basePort) ?? 3e3;
|
|
1940
|
-
const port = calculatePortFromIdentifier(number, basePort);
|
|
1941
|
-
if (options.dryRun) {
|
|
1942
|
-
operations.push({
|
|
1943
|
-
type: "dev-server",
|
|
1944
|
-
success: true,
|
|
1945
|
-
message: `[DRY RUN] Would check for dev server on port ${port}`
|
|
1946
|
-
});
|
|
1947
|
-
} else {
|
|
1948
|
-
try {
|
|
1949
|
-
const terminated = await this.terminateDevServer(port);
|
|
1950
|
-
operations.push({
|
|
1951
|
-
type: "dev-server",
|
|
1952
|
-
success: true,
|
|
1953
|
-
message: terminated ? `Dev server on port ${port} terminated` : `No dev server running on port ${port}`
|
|
1954
|
-
});
|
|
1955
|
-
} catch (error) {
|
|
1956
|
-
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
1957
|
-
errors.push(err);
|
|
1958
|
-
operations.push({
|
|
1959
|
-
type: "dev-server",
|
|
1960
|
-
success: false,
|
|
1961
|
-
message: `Failed to terminate dev server`,
|
|
1962
|
-
error: err.message
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
1965
|
-
}
|
|
1966
|
-
}
|
|
1967
|
-
let worktree = null;
|
|
1968
|
-
try {
|
|
1969
|
-
if (parsed.type === "pr" && parsed.number !== void 0) {
|
|
1970
|
-
const prNumber = typeof parsed.number === "number" ? parsed.number : Number(parsed.number);
|
|
1971
|
-
if (isNaN(prNumber) || !isFinite(prNumber)) {
|
|
1972
|
-
throw new Error(`Invalid PR number: ${parsed.number}. PR numbers must be numeric.`);
|
|
1973
|
-
}
|
|
1974
|
-
worktree = await this.gitWorktree.findWorktreeForPR(prNumber, "");
|
|
1975
|
-
} else if (parsed.type === "issue" && parsed.number !== void 0) {
|
|
1976
|
-
worktree = await this.gitWorktree.findWorktreeForIssue(parsed.number);
|
|
1977
|
-
} else if (parsed.type === "branch" && parsed.branchName) {
|
|
1978
|
-
worktree = await this.gitWorktree.findWorktreeForBranch(parsed.branchName);
|
|
1979
|
-
}
|
|
1980
|
-
if (!worktree) {
|
|
1981
|
-
throw new Error(`No worktree found for identifier: ${displayIdentifier}`);
|
|
1982
|
-
}
|
|
1983
|
-
getLogger().debug(`Found worktree: path="${worktree.path}", branch="${worktree.branch}"`);
|
|
1984
|
-
} catch (error) {
|
|
1985
|
-
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
1986
|
-
errors.push(err);
|
|
1987
|
-
return {
|
|
1988
|
-
identifier: displayIdentifier,
|
|
1989
|
-
success: false,
|
|
1990
|
-
operations,
|
|
1991
|
-
errors,
|
|
1992
|
-
rollbackRequired: false
|
|
1993
|
-
};
|
|
1994
|
-
}
|
|
1995
|
-
let safetyCheckPassed = false;
|
|
1996
|
-
if (!options.force) {
|
|
1997
|
-
const shouldCheckMergeSafety = options.checkMergeSafety ?? options.deleteBranch === true;
|
|
1998
|
-
const shouldCheckRemoteBranch = options.checkRemoteBranch ?? false;
|
|
1999
|
-
const safety = await this.validateWorktreeSafety(worktree, parsed.originalInput, shouldCheckMergeSafety, shouldCheckRemoteBranch);
|
|
2000
|
-
if (!safety.isSafe) {
|
|
2001
|
-
const blockerMessage = safety.blockers.join("\n\n");
|
|
2002
|
-
throw new Error(`Cannot cleanup:
|
|
2003
|
-
|
|
2004
|
-
${blockerMessage}`);
|
|
2005
|
-
}
|
|
2006
|
-
safetyCheckPassed = true;
|
|
2007
|
-
if (safety.warnings.length > 0) {
|
|
2008
|
-
safety.warnings.forEach((warning) => {
|
|
2009
|
-
getLogger().warn(warning);
|
|
2010
|
-
});
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
let databaseConfig = null;
|
|
2014
|
-
if (!options.keepDatabase && worktree) {
|
|
2015
|
-
const envFilePath = path5.join(worktree.path, ".env");
|
|
2016
|
-
try {
|
|
2017
|
-
const shouldCleanup = this.database ? await this.database.shouldUseDatabaseBranching(envFilePath) : false;
|
|
2018
|
-
databaseConfig = { shouldCleanup, envFilePath };
|
|
2019
|
-
} catch (error) {
|
|
2020
|
-
getLogger().warn(
|
|
2021
|
-
`Failed to read database config from ${envFilePath}, skipping database cleanup: ${error instanceof Error ? error.message : String(error)}`
|
|
2022
|
-
);
|
|
2023
|
-
databaseConfig = { shouldCleanup: false, envFilePath };
|
|
2024
|
-
}
|
|
2025
|
-
}
|
|
2026
|
-
let mainWorktreePath = null;
|
|
2027
|
-
if (!options.dryRun) {
|
|
2028
|
-
try {
|
|
2029
|
-
mainWorktreePath = await findMainWorktreePathWithSettings(worktree.path, this.settingsManager);
|
|
2030
|
-
} catch (error) {
|
|
2031
|
-
getLogger().warn(
|
|
2032
|
-
`Failed to find main worktree path: ${error instanceof Error ? error.message : String(error)}`
|
|
2033
|
-
);
|
|
2034
|
-
}
|
|
2035
|
-
}
|
|
2036
|
-
let mergeTargetBranch = null;
|
|
2037
|
-
if (options.deleteBranch && worktree && !options.dryRun) {
|
|
2038
|
-
try {
|
|
2039
|
-
mergeTargetBranch = await getMergeTargetBranch(worktree.path, {
|
|
2040
|
-
settingsManager: this.settingsManager,
|
|
2041
|
-
metadataManager: this.metadataManager
|
|
2042
|
-
});
|
|
2043
|
-
getLogger().debug(`Pre-fetched merge target branch: ${mergeTargetBranch}`);
|
|
2044
|
-
} catch (error) {
|
|
2045
|
-
getLogger().warn(
|
|
2046
|
-
`Failed to pre-fetch merge target branch: ${error instanceof Error ? error.message : String(error)}`
|
|
2047
|
-
);
|
|
2048
|
-
}
|
|
2049
|
-
}
|
|
2050
|
-
if (options.dryRun) {
|
|
2051
|
-
operations.push({
|
|
2052
|
-
type: "worktree",
|
|
2053
|
-
success: true,
|
|
2054
|
-
message: `[DRY RUN] Would remove worktree: ${worktree.path}`
|
|
2055
|
-
});
|
|
2056
|
-
} else {
|
|
2057
|
-
try {
|
|
2058
|
-
const worktreeOptions = {
|
|
2059
|
-
removeDirectory: true,
|
|
2060
|
-
removeBranch: false
|
|
2061
|
-
// Handle branch separately
|
|
2062
|
-
};
|
|
2063
|
-
if (options.force !== void 0) {
|
|
2064
|
-
worktreeOptions.force = options.force;
|
|
2065
|
-
}
|
|
2066
|
-
await this.gitWorktree.removeWorktree(worktree.path, worktreeOptions);
|
|
2067
|
-
operations.push({
|
|
2068
|
-
type: "worktree",
|
|
2069
|
-
success: true,
|
|
2070
|
-
message: `Worktree removed: ${worktree.path}`
|
|
2071
|
-
});
|
|
2072
|
-
} catch (error) {
|
|
2073
|
-
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
2074
|
-
errors.push(err);
|
|
2075
|
-
operations.push({
|
|
2076
|
-
type: "worktree",
|
|
2077
|
-
success: false,
|
|
2078
|
-
message: `Failed to remove worktree`,
|
|
2079
|
-
error: err.message
|
|
2080
|
-
});
|
|
2081
|
-
}
|
|
2082
|
-
}
|
|
2083
|
-
if (worktree) {
|
|
2084
|
-
if (options.dryRun) {
|
|
2085
|
-
operations.push({
|
|
2086
|
-
type: "recap",
|
|
2087
|
-
success: true,
|
|
2088
|
-
message: `[DRY RUN] Would archive recap file for: ${worktree.path}`
|
|
2089
|
-
});
|
|
2090
|
-
} else {
|
|
2091
|
-
try {
|
|
2092
|
-
await archiveRecap(worktree.path);
|
|
2093
|
-
operations.push({
|
|
2094
|
-
type: "recap",
|
|
2095
|
-
success: true,
|
|
2096
|
-
message: `Recap file archived`
|
|
2097
|
-
});
|
|
2098
|
-
} catch (error) {
|
|
2099
|
-
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
2100
|
-
getLogger().warn(`Recap archival failed: ${err.message}`);
|
|
2101
|
-
operations.push({
|
|
2102
|
-
type: "recap",
|
|
2103
|
-
success: false,
|
|
2104
|
-
message: "Recap archival failed (non-fatal)",
|
|
2105
|
-
error: err.message
|
|
2106
|
-
});
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
if (options.deleteBranch && worktree) {
|
|
2111
|
-
if (options.dryRun) {
|
|
2112
|
-
operations.push({
|
|
2113
|
-
type: "branch",
|
|
2114
|
-
success: true,
|
|
2115
|
-
message: `[DRY RUN] Would delete branch: ${worktree.branch}`
|
|
2116
|
-
});
|
|
2117
|
-
} else {
|
|
2118
|
-
try {
|
|
2119
|
-
const branchOptions = {
|
|
2120
|
-
dryRun: false,
|
|
2121
|
-
safetyVerified: safetyCheckPassed
|
|
2122
|
-
};
|
|
2123
|
-
if (mergeTargetBranch !== null) {
|
|
2124
|
-
branchOptions.mergeTargetBranch = mergeTargetBranch;
|
|
2125
|
-
}
|
|
2126
|
-
if (options.force !== void 0) {
|
|
2127
|
-
branchOptions.force = options.force;
|
|
2128
|
-
}
|
|
2129
|
-
await this.deleteBranch(worktree.branch, branchOptions, mainWorktreePath ?? void 0);
|
|
2130
|
-
operations.push({
|
|
2131
|
-
type: "branch",
|
|
2132
|
-
success: true,
|
|
2133
|
-
message: `Branch deleted: ${worktree.branch}`
|
|
2134
|
-
});
|
|
2135
|
-
} catch (error) {
|
|
2136
|
-
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
2137
|
-
errors.push(err);
|
|
2138
|
-
operations.push({
|
|
2139
|
-
type: "branch",
|
|
2140
|
-
success: false,
|
|
2141
|
-
message: `Failed to delete branch`,
|
|
2142
|
-
error: err.message
|
|
2143
|
-
});
|
|
2144
|
-
}
|
|
2145
|
-
}
|
|
2146
|
-
}
|
|
2147
|
-
const cliIdentifier = parsed.number ?? parsed.branchName;
|
|
2148
|
-
if (this.cliIsolation && cliIdentifier !== void 0) {
|
|
2149
|
-
if (options.dryRun) {
|
|
2150
|
-
operations.push({
|
|
2151
|
-
type: "cli-symlinks",
|
|
2152
|
-
success: true,
|
|
2153
|
-
message: `[DRY RUN] Would cleanup CLI symlinks for: ${cliIdentifier}`
|
|
2154
|
-
});
|
|
2155
|
-
} else {
|
|
2156
|
-
try {
|
|
2157
|
-
const removed = await this.cliIsolation.cleanupVersionedExecutables(cliIdentifier);
|
|
2158
|
-
operations.push({
|
|
2159
|
-
type: "cli-symlinks",
|
|
2160
|
-
success: true,
|
|
2161
|
-
message: removed.length > 0 ? `CLI symlinks removed: ${removed.length}` : "No CLI symlinks to cleanup"
|
|
2162
|
-
});
|
|
2163
|
-
} catch (error) {
|
|
2164
|
-
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
2165
|
-
errors.push(err);
|
|
2166
|
-
getLogger().warn(
|
|
2167
|
-
`CLI symlink cleanup failed: ${err.message}`
|
|
2168
|
-
);
|
|
2169
|
-
operations.push({
|
|
2170
|
-
type: "cli-symlinks",
|
|
2171
|
-
success: false,
|
|
2172
|
-
message: "CLI symlink cleanup failed (non-fatal)"
|
|
2173
|
-
});
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
}
|
|
2177
|
-
if (databaseConfig && worktree) {
|
|
2178
|
-
if (options.dryRun) {
|
|
2179
|
-
operations.push({
|
|
2180
|
-
type: "database",
|
|
2181
|
-
success: true,
|
|
2182
|
-
message: `[DRY RUN] Would cleanup database branch for: ${worktree.branch}`
|
|
2183
|
-
});
|
|
2184
|
-
} else {
|
|
2185
|
-
try {
|
|
2186
|
-
if (databaseConfig.shouldCleanup && this.database) {
|
|
2187
|
-
try {
|
|
2188
|
-
const deletionResult = await this.database.deleteBranchIfConfigured(
|
|
2189
|
-
worktree.branch,
|
|
2190
|
-
databaseConfig.shouldCleanup,
|
|
2191
|
-
false,
|
|
2192
|
-
// isPreview
|
|
2193
|
-
mainWorktreePath ?? void 0
|
|
2194
|
-
);
|
|
2195
|
-
if (deletionResult.deleted) {
|
|
2196
|
-
getLogger().info(`Database branch deleted: ${worktree.branch}`);
|
|
2197
|
-
operations.push({
|
|
2198
|
-
type: "database",
|
|
2199
|
-
success: true,
|
|
2200
|
-
message: `Database branch deleted`,
|
|
2201
|
-
deleted: true
|
|
2202
|
-
});
|
|
2203
|
-
} else if (deletionResult.notFound) {
|
|
2204
|
-
getLogger().debug(`No database branch found for: ${worktree.branch}`);
|
|
2205
|
-
operations.push({
|
|
2206
|
-
type: "database",
|
|
2207
|
-
success: true,
|
|
2208
|
-
message: `No database branch found (skipped)`,
|
|
2209
|
-
deleted: false
|
|
2210
|
-
});
|
|
2211
|
-
} else if (deletionResult.userDeclined) {
|
|
2212
|
-
getLogger().info("Preview database deletion declined by user");
|
|
2213
|
-
operations.push({
|
|
2214
|
-
type: "database",
|
|
2215
|
-
success: true,
|
|
2216
|
-
message: `Database cleanup skipped (user declined)`,
|
|
2217
|
-
deleted: false
|
|
2218
|
-
});
|
|
2219
|
-
} else if (!deletionResult.success) {
|
|
2220
|
-
const errorMsg = deletionResult.error ?? "Unknown error";
|
|
2221
|
-
errors.push(new Error(errorMsg));
|
|
2222
|
-
getLogger().warn(`Database cleanup failed: ${errorMsg}`);
|
|
2223
|
-
operations.push({
|
|
2224
|
-
type: "database",
|
|
2225
|
-
success: false,
|
|
2226
|
-
// Non-fatal, but report error
|
|
2227
|
-
message: `Database cleanup failed`,
|
|
2228
|
-
error: errorMsg,
|
|
2229
|
-
deleted: false
|
|
2230
|
-
});
|
|
2231
|
-
} else {
|
|
2232
|
-
errors.push(new Error("Database cleanup in an unknown state"));
|
|
2233
|
-
getLogger().warn("Database deletion returned unexpected result state");
|
|
2234
|
-
operations.push({
|
|
2235
|
-
type: "database",
|
|
2236
|
-
success: false,
|
|
2237
|
-
message: `Database cleanup in an unknown state`,
|
|
2238
|
-
deleted: false
|
|
2239
|
-
});
|
|
2240
|
-
}
|
|
2241
|
-
} catch (error) {
|
|
2242
|
-
errors.push(error instanceof Error ? error : new Error(String(error)));
|
|
2243
|
-
getLogger().warn(
|
|
2244
|
-
`Unexpected database cleanup exception: ${error instanceof Error ? error.message : String(error)}`
|
|
2245
|
-
);
|
|
2246
|
-
operations.push({
|
|
2247
|
-
type: "database",
|
|
2248
|
-
success: false,
|
|
2249
|
-
message: `Database cleanup failed`,
|
|
2250
|
-
error: error instanceof Error ? error.message : String(error),
|
|
2251
|
-
deleted: false
|
|
2252
|
-
});
|
|
2253
|
-
}
|
|
2254
|
-
} else {
|
|
2255
|
-
operations.push({
|
|
2256
|
-
type: "database",
|
|
2257
|
-
success: true,
|
|
2258
|
-
message: `Database cleanup skipped (not available)`,
|
|
2259
|
-
deleted: false
|
|
2260
|
-
});
|
|
2261
|
-
}
|
|
2262
|
-
} catch (error) {
|
|
2263
|
-
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
2264
|
-
errors.push(err);
|
|
2265
|
-
operations.push({
|
|
2266
|
-
type: "database",
|
|
2267
|
-
success: false,
|
|
2268
|
-
message: `Database cleanup failed`,
|
|
2269
|
-
error: err.message,
|
|
2270
|
-
deleted: false
|
|
2271
|
-
});
|
|
2272
|
-
}
|
|
2273
|
-
}
|
|
2274
|
-
}
|
|
2275
|
-
if (worktree) {
|
|
2276
|
-
if (options.dryRun) {
|
|
2277
|
-
operations.push({
|
|
2278
|
-
type: "metadata",
|
|
2279
|
-
success: true,
|
|
2280
|
-
message: `[DRY RUN] Would delete metadata for worktree: ${worktree.path}`
|
|
2281
|
-
});
|
|
2282
|
-
} else {
|
|
2283
|
-
try {
|
|
2284
|
-
await this.metadataManager.deleteMetadata(worktree.path);
|
|
2285
|
-
getLogger().info(`Metadata deleted for worktree: ${worktree.path}`);
|
|
2286
|
-
operations.push({
|
|
2287
|
-
type: "metadata",
|
|
2288
|
-
success: true,
|
|
2289
|
-
message: "Metadata deleted"
|
|
2290
|
-
});
|
|
2291
|
-
} catch (error) {
|
|
2292
|
-
const err = error instanceof Error ? error : new Error(String(error));
|
|
2293
|
-
errors.push(err);
|
|
2294
|
-
getLogger().warn(`Metadata deletion failed: ${err.message}`);
|
|
2295
|
-
operations.push({
|
|
2296
|
-
type: "metadata",
|
|
2297
|
-
success: false,
|
|
2298
|
-
message: "Metadata deletion failed (non-fatal)",
|
|
2299
|
-
error: err.message
|
|
2300
|
-
});
|
|
2301
|
-
}
|
|
2302
|
-
}
|
|
2303
|
-
}
|
|
2304
|
-
const success = errors.length === 0;
|
|
2305
|
-
return {
|
|
2306
|
-
identifier: displayIdentifier,
|
|
2307
|
-
branchName: worktree == null ? void 0 : worktree.branch,
|
|
2308
|
-
success,
|
|
2309
|
-
operations,
|
|
2310
|
-
errors,
|
|
2311
|
-
rollbackRequired: false
|
|
2312
|
-
// Cleanup operations are generally not reversible
|
|
2313
|
-
};
|
|
2314
|
-
}
|
|
2315
|
-
/**
|
|
2316
|
-
* Terminate dev server on specified port
|
|
2317
|
-
*/
|
|
2318
|
-
async terminateDevServer(port) {
|
|
2319
|
-
getLogger().debug(`Checking for dev server on port ${port}`);
|
|
2320
|
-
const processInfo = await this.processManager.detectDevServer(port);
|
|
2321
|
-
if (!processInfo) {
|
|
2322
|
-
getLogger().debug(`No process found on port ${port}`);
|
|
2323
|
-
return false;
|
|
2324
|
-
}
|
|
2325
|
-
if (!processInfo.isDevServer) {
|
|
2326
|
-
getLogger().warn(
|
|
2327
|
-
`Process on port ${port} (${processInfo.name}) doesn't appear to be a dev server, skipping`
|
|
2328
|
-
);
|
|
2329
|
-
return false;
|
|
2330
|
-
}
|
|
2331
|
-
getLogger().info(`Terminating dev server: ${processInfo.name} (PID: ${processInfo.pid})`);
|
|
2332
|
-
await this.processManager.terminateProcess(processInfo.pid);
|
|
2333
|
-
const isFree = await this.processManager.verifyPortFree(port);
|
|
2334
|
-
if (!isFree) {
|
|
2335
|
-
throw new Error(`Dev server may still be running on port ${port}`);
|
|
2336
|
-
}
|
|
2337
|
-
return true;
|
|
2338
|
-
}
|
|
2339
|
-
/**
|
|
2340
|
-
* Delete a Git branch with safety checks
|
|
2341
|
-
*
|
|
2342
|
-
* @param branchName - Name of the branch to delete
|
|
2343
|
-
* @param options - Delete options (force, dryRun)
|
|
2344
|
-
* @param cwd - Working directory to execute git command from (defaults to finding main worktree)
|
|
2345
|
-
*/
|
|
2346
|
-
async deleteBranch(branchName, options = {}, cwd) {
|
|
2347
|
-
const protectedBranches = await this.settingsManager.getProtectedBranches(cwd);
|
|
2348
|
-
if (protectedBranches.includes(branchName)) {
|
|
2349
|
-
throw new Error(`Cannot delete protected branch: ${branchName}`);
|
|
2350
|
-
}
|
|
2351
|
-
const workingDir = cwd ?? await findMainWorktreePathWithSettings(void 0, this.settingsManager);
|
|
2352
|
-
try {
|
|
2353
|
-
await executeGitCommand(["rev-parse", "--verify", `refs/heads/${branchName}`], {
|
|
2354
|
-
cwd: workingDir
|
|
2355
|
-
});
|
|
2356
|
-
} catch {
|
|
2357
|
-
getLogger().debug(`Branch ${branchName} does not exist, skipping deletion`);
|
|
2358
|
-
return true;
|
|
2359
|
-
}
|
|
2360
|
-
if (options.dryRun) {
|
|
2361
|
-
getLogger().info(`[DRY RUN] Would delete branch: ${branchName}`);
|
|
2362
|
-
return true;
|
|
2363
|
-
}
|
|
2364
|
-
let deleteCwd = workingDir;
|
|
2365
|
-
try {
|
|
2366
|
-
let deleteFlag = "-d";
|
|
2367
|
-
if (options.force) {
|
|
2368
|
-
deleteFlag = "-D";
|
|
2369
|
-
} else if (options.mergeTargetBranch) {
|
|
2370
|
-
const mergeTarget = options.mergeTargetBranch;
|
|
2371
|
-
try {
|
|
2372
|
-
const targetWorktreePath = await findWorktreeForBranch(mergeTarget, workingDir);
|
|
2373
|
-
getLogger().debug(`Running branch delete from worktree where '${mergeTarget}' is checked out: ${targetWorktreePath}`);
|
|
2374
|
-
deleteCwd = targetWorktreePath;
|
|
2375
|
-
} catch {
|
|
2376
|
-
getLogger().debug(`Could not find worktree for branch '${mergeTarget}', falling back to merge check`);
|
|
2377
|
-
const isMerged = await isBranchMergedIntoMain(branchName, mergeTarget, workingDir);
|
|
2378
|
-
if (isMerged) {
|
|
2379
|
-
getLogger().debug(`Branch '${branchName}' verified merged into '${mergeTarget}', using force delete`);
|
|
2380
|
-
deleteFlag = "-D";
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
} else if (options.worktreePath) {
|
|
2384
|
-
getLogger().warn("deleteBranch called with worktreePath but no mergeTargetBranch - this may fail if worktree was deleted");
|
|
2385
|
-
try {
|
|
2386
|
-
const mergeTarget = await getMergeTargetBranch(options.worktreePath, {
|
|
2387
|
-
settingsManager: this.settingsManager,
|
|
2388
|
-
metadataManager: this.metadataManager
|
|
2389
|
-
});
|
|
2390
|
-
try {
|
|
2391
|
-
const targetWorktreePath = await findWorktreeForBranch(mergeTarget, workingDir);
|
|
2392
|
-
getLogger().debug(`Running branch delete from worktree where '${mergeTarget}' is checked out: ${targetWorktreePath}`);
|
|
2393
|
-
deleteCwd = targetWorktreePath;
|
|
2394
|
-
} catch {
|
|
2395
|
-
getLogger().debug(`Could not find worktree for branch '${mergeTarget}', falling back to merge check`);
|
|
2396
|
-
const isMerged = await isBranchMergedIntoMain(branchName, mergeTarget, workingDir);
|
|
2397
|
-
if (isMerged) {
|
|
2398
|
-
getLogger().debug(`Branch '${branchName}' verified merged into '${mergeTarget}', using force delete`);
|
|
2399
|
-
deleteFlag = "-D";
|
|
2400
|
-
}
|
|
2401
|
-
}
|
|
2402
|
-
} catch (error) {
|
|
2403
|
-
getLogger().debug(`Could not read merge target from worktreePath: ${error instanceof Error ? error.message : String(error)}`);
|
|
2404
|
-
}
|
|
2405
|
-
}
|
|
2406
|
-
await executeGitCommand(["branch", deleteFlag, branchName], {
|
|
2407
|
-
cwd: deleteCwd
|
|
2408
|
-
});
|
|
2409
|
-
getLogger().info(`Branch deleted: ${branchName}`);
|
|
2410
|
-
return true;
|
|
2411
|
-
} catch (error) {
|
|
2412
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2413
|
-
if (errorMessage.includes("not found") || errorMessage.includes("does not exist")) {
|
|
2414
|
-
getLogger().debug(`Branch ${branchName} already deleted`);
|
|
2415
|
-
return true;
|
|
2416
|
-
}
|
|
2417
|
-
if (options.force) {
|
|
2418
|
-
throw error;
|
|
2419
|
-
}
|
|
2420
|
-
if (errorMessage.includes("not fully merged")) {
|
|
2421
|
-
if (options.safetyVerified) {
|
|
2422
|
-
getLogger().info(`Branch '${branchName}' not merged into HEAD but safety verified - using force delete`);
|
|
2423
|
-
await executeGitCommand(["branch", "-D", branchName], { cwd: deleteCwd });
|
|
2424
|
-
getLogger().info(`Branch deleted: ${branchName}`);
|
|
2425
|
-
return true;
|
|
2426
|
-
}
|
|
2427
|
-
throw new Error(
|
|
2428
|
-
`Cannot delete unmerged branch '${branchName}'. Use --force to delete anyway.`
|
|
2429
|
-
);
|
|
2430
|
-
}
|
|
2431
|
-
throw error;
|
|
2432
|
-
}
|
|
2433
|
-
}
|
|
2434
|
-
/**
|
|
2435
|
-
* Cleanup database branch
|
|
2436
|
-
* Gracefully handles missing DatabaseManager
|
|
2437
|
-
*
|
|
2438
|
-
* @deprecated This method is deprecated and should not be used for post-deletion cleanup.
|
|
2439
|
-
* Use the pre-fetch mechanism in cleanupWorktree() instead.
|
|
2440
|
-
* This method will fail if called after worktree deletion because
|
|
2441
|
-
* it attempts to read the .env file which has been deleted.
|
|
2442
|
-
*
|
|
2443
|
-
* @param branchName - Name of the branch to delete
|
|
2444
|
-
* @param worktreePath - Path to worktree (must still exist with .env file)
|
|
2445
|
-
*/
|
|
2446
|
-
async cleanupDatabase(branchName, worktreePath) {
|
|
2447
|
-
if (!this.database) {
|
|
2448
|
-
getLogger().debug("Database manager not available, skipping database cleanup");
|
|
2449
|
-
return false;
|
|
2450
|
-
}
|
|
2451
|
-
try {
|
|
2452
|
-
const envFilePath = path5.join(worktreePath, ".env");
|
|
2453
|
-
const shouldCleanup = await this.database.shouldUseDatabaseBranching(envFilePath);
|
|
2454
|
-
let cwd;
|
|
2455
|
-
try {
|
|
2456
|
-
cwd = await findMainWorktreePathWithSettings(worktreePath, this.settingsManager);
|
|
2457
|
-
} catch (error) {
|
|
2458
|
-
getLogger().debug(
|
|
2459
|
-
`Could not find main worktree path, using current directory: ${error instanceof Error ? error.message : String(error)}`
|
|
2460
|
-
);
|
|
2461
|
-
}
|
|
2462
|
-
const result = await this.database.deleteBranchIfConfigured(
|
|
2463
|
-
branchName,
|
|
2464
|
-
shouldCleanup,
|
|
2465
|
-
false,
|
|
2466
|
-
// isPreview
|
|
2467
|
-
cwd
|
|
2468
|
-
);
|
|
2469
|
-
if (result.deleted) {
|
|
2470
|
-
getLogger().info(`Database branch deleted: ${branchName}`);
|
|
2471
|
-
return true;
|
|
2472
|
-
} else if (result.notFound) {
|
|
2473
|
-
getLogger().debug(`No database branch found for: ${branchName}`);
|
|
2474
|
-
return false;
|
|
2475
|
-
} else if (result.userDeclined) {
|
|
2476
|
-
getLogger().info("Preview database deletion declined by user");
|
|
2477
|
-
return false;
|
|
2478
|
-
} else if (!result.success) {
|
|
2479
|
-
getLogger().warn(`Database cleanup failed: ${result.error ?? "Unknown error"}`);
|
|
2480
|
-
return false;
|
|
2481
|
-
} else {
|
|
2482
|
-
getLogger().debug("Database deletion returned unexpected result");
|
|
2483
|
-
return false;
|
|
2484
|
-
}
|
|
2485
|
-
} catch (error) {
|
|
2486
|
-
getLogger().warn(
|
|
2487
|
-
`Unexpected database cleanup error: ${error instanceof Error ? error.message : String(error)}`
|
|
2488
|
-
);
|
|
2489
|
-
return false;
|
|
2490
|
-
}
|
|
2491
|
-
}
|
|
2492
|
-
/**
|
|
2493
|
-
* Cleanup multiple worktrees
|
|
2494
|
-
*/
|
|
2495
|
-
async cleanupMultipleWorktrees(identifiers, options = {}) {
|
|
2496
|
-
const results = [];
|
|
2497
|
-
for (const identifier of identifiers) {
|
|
2498
|
-
const parsed = this.parseIdentifier(identifier);
|
|
2499
|
-
const result = await this.cleanupWorktree(parsed, options);
|
|
2500
|
-
results.push(result);
|
|
2501
|
-
}
|
|
2502
|
-
return results;
|
|
2503
|
-
}
|
|
2504
|
-
/**
|
|
2505
|
-
* Validate worktree safety given a worktree object
|
|
2506
|
-
* Private method used internally when worktree is already known
|
|
2507
|
-
*
|
|
2508
|
-
* @param worktree - The worktree to validate
|
|
2509
|
-
* @param identifier - The original identifier used (for error messages)
|
|
2510
|
-
* @param checkBranchMerge - Whether to check if branch is merged into main (for branch deletion)
|
|
2511
|
-
* @param checkRemoteBranch - Whether to check if branch exists on remote (for GitHub-PR mode)
|
|
2512
|
-
*/
|
|
2513
|
-
async validateWorktreeSafety(worktree, identifier, checkBranchMerge = false, checkRemoteBranch = false) {
|
|
2514
|
-
const warnings = [];
|
|
2515
|
-
const blockers = [];
|
|
2516
|
-
const isMain = await this.gitWorktree.isMainWorktree(worktree, this.settingsManager);
|
|
2517
|
-
if (isMain) {
|
|
2518
|
-
blockers.push(`Cannot cleanup main worktree: "${worktree.branch}" @ "${worktree.path}"`);
|
|
2519
|
-
}
|
|
2520
|
-
const hasChanges = await hasUncommittedChanges(worktree.path);
|
|
2521
|
-
if (hasChanges) {
|
|
2522
|
-
const blockerMessage = `Worktree has uncommitted changes.
|
|
2523
|
-
|
|
2524
|
-
Please resolve before cleanup - you have some options:
|
|
2525
|
-
\u2022 Commit changes: cd ${worktree.path} && git commit -am "message"
|
|
2526
|
-
\u2022 Stash changes: cd ${worktree.path} && git stash
|
|
2527
|
-
\u2022 Force cleanup: il cleanup ${identifier} --force (WARNING: will discard changes)`;
|
|
2528
|
-
blockers.push(blockerMessage);
|
|
2529
|
-
}
|
|
2530
|
-
if ((checkBranchMerge || checkRemoteBranch) && worktree.branch) {
|
|
2531
|
-
const mainBranch = await getMergeTargetBranch(worktree.path, {
|
|
2532
|
-
settingsManager: this.settingsManager,
|
|
2533
|
-
metadataManager: this.metadataManager
|
|
2534
|
-
});
|
|
2535
|
-
const remoteStatus = await checkRemoteBranchStatus(worktree.branch, worktree.path);
|
|
2536
|
-
if (remoteStatus.networkError) {
|
|
2537
|
-
const blockerMessage = `Cannot verify remote branch status due to network error.
|
|
2538
|
-
|
|
2539
|
-
Error: ${remoteStatus.errorMessage ?? "Unknown network error"}
|
|
2540
|
-
|
|
2541
|
-
Unable to determine if branch '${worktree.branch}' is safely backed up.
|
|
2542
|
-
Use --force to proceed without verification.`;
|
|
2543
|
-
blockers.push(blockerMessage);
|
|
2544
|
-
} else if (remoteStatus.exists && remoteStatus.localAhead) {
|
|
2545
|
-
const blockerMessage = `Branch '${worktree.branch}' has unpushed commits that would be lost.
|
|
2546
|
-
The remote branch exists but your local branch is ahead.
|
|
2547
|
-
|
|
2548
|
-
Please resolve before cleanup:
|
|
2549
|
-
\u2022 Push your commits: git push origin ${worktree.branch}
|
|
2550
|
-
\u2022 Force cleanup: il cleanup ${identifier} --force (WARNING: will lose commits)`;
|
|
2551
|
-
blockers.push(blockerMessage);
|
|
2552
|
-
} else if (remoteStatus.exists && !remoteStatus.localAhead) {
|
|
2553
|
-
} else if (!remoteStatus.exists) {
|
|
2554
|
-
const isMerged = await isBranchMergedIntoMain(worktree.branch, mainBranch, worktree.path);
|
|
2555
|
-
if (isMerged) {
|
|
2556
|
-
} else {
|
|
2557
|
-
const blockerMessage = `Branch '${worktree.branch}' has not been pushed to remote and is not merged into '${mainBranch}'.
|
|
2558
|
-
Deleting this branch would result in data loss.
|
|
2559
|
-
|
|
2560
|
-
Please resolve before cleanup - you have some options:
|
|
2561
|
-
\u2022 Push to remote: git push -u origin ${worktree.branch}
|
|
2562
|
-
\u2022 Merge to ${mainBranch}: git checkout ${mainBranch} && git merge ${worktree.branch}
|
|
2563
|
-
\u2022 Force cleanup: il cleanup ${identifier} --force (WARNING: will lose commits)`;
|
|
2564
|
-
blockers.push(blockerMessage);
|
|
2565
|
-
}
|
|
2566
|
-
}
|
|
2567
|
-
}
|
|
2568
|
-
return {
|
|
2569
|
-
isSafe: blockers.length === 0,
|
|
2570
|
-
warnings,
|
|
2571
|
-
blockers
|
|
2572
|
-
};
|
|
2573
|
-
}
|
|
2574
|
-
/**
|
|
2575
|
-
* Validate cleanup safety
|
|
2576
|
-
*/
|
|
2577
|
-
async validateCleanupSafety(identifier) {
|
|
2578
|
-
const warnings = [];
|
|
2579
|
-
const blockers = [];
|
|
2580
|
-
const worktrees = await this.gitWorktree.findWorktreesByIdentifier(identifier);
|
|
2581
|
-
if (worktrees.length === 0) {
|
|
2582
|
-
blockers.push(`No worktree found for: ${identifier}`);
|
|
2583
|
-
return { isSafe: false, warnings, blockers };
|
|
2584
|
-
}
|
|
2585
|
-
const worktree = worktrees[0];
|
|
2586
|
-
if (!worktree) {
|
|
2587
|
-
blockers.push(`No worktree found for: ${identifier}`);
|
|
2588
|
-
return { isSafe: false, warnings, blockers };
|
|
2589
|
-
}
|
|
2590
|
-
return await this.validateWorktreeSafety(worktree, identifier);
|
|
2591
|
-
}
|
|
2592
|
-
/**
|
|
2593
|
-
* Parse identifier to determine type and extract number
|
|
2594
|
-
* Helper method for port calculation
|
|
2595
|
-
*/
|
|
2596
|
-
parseIdentifier(identifier) {
|
|
2597
|
-
const issueId = extractIssueNumber(identifier);
|
|
2598
|
-
if (issueId !== null) {
|
|
2599
|
-
return {
|
|
2600
|
-
type: "issue",
|
|
2601
|
-
number: issueId,
|
|
2602
|
-
originalInput: identifier
|
|
2603
|
-
};
|
|
2604
|
-
}
|
|
2605
|
-
const prMatch = identifier.match(/(?:pr|PR)[/-](\d+)/);
|
|
2606
|
-
if (prMatch == null ? void 0 : prMatch[1]) {
|
|
2607
|
-
return {
|
|
2608
|
-
type: "pr",
|
|
2609
|
-
number: parseInt(prMatch[1], 10),
|
|
2610
|
-
originalInput: identifier
|
|
2611
|
-
};
|
|
2612
|
-
}
|
|
2613
|
-
const numericMatch = identifier.match(/^#?(\d+)$/);
|
|
2614
|
-
if (numericMatch == null ? void 0 : numericMatch[1]) {
|
|
2615
|
-
return {
|
|
2616
|
-
type: "issue",
|
|
2617
|
-
number: parseInt(numericMatch[1], 10),
|
|
2618
|
-
originalInput: identifier
|
|
2619
|
-
};
|
|
2620
|
-
}
|
|
2621
|
-
return {
|
|
2622
|
-
type: "branch",
|
|
2623
|
-
branchName: identifier,
|
|
2624
|
-
originalInput: identifier
|
|
2625
|
-
};
|
|
2626
|
-
}
|
|
2627
|
-
};
|
|
2628
|
-
|
|
2629
1877
|
export {
|
|
2630
1878
|
LoomManager,
|
|
2631
1879
|
EnvironmentManager,
|
|
2632
1880
|
CLIIsolationManager,
|
|
2633
|
-
DatabaseManager
|
|
2634
|
-
ResourceCleanup
|
|
1881
|
+
DatabaseManager
|
|
2635
1882
|
};
|
|
2636
|
-
//# sourceMappingURL=chunk-
|
|
1883
|
+
//# sourceMappingURL=chunk-ZNMPGMHY.js.map
|