@iloom/cli 0.1.18 → 0.2.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/README.md +53 -6
- package/dist/ClaudeContextManager-LVCYRM6Q.js +13 -0
- package/dist/ClaudeService-WVTWB3DK.js +12 -0
- package/dist/{GitHubService-SH4H6VS5.js → GitHubService-7E2S5NNZ.js} +3 -3
- package/dist/{LoomLauncher-FB2MV2ZI.js → LoomLauncher-CTSWJL35.js} +7 -7
- package/dist/{PromptTemplateManager-WM5GIPEF.js → PromptTemplateManager-WII75TKH.js} +2 -2
- package/dist/README.md +771 -0
- package/dist/{SettingsManager-SKLUVE3K.js → SettingsManager-XOYCLH3D.js} +2 -2
- package/dist/{add-issue-L5HX6LEV.js → add-issue-OBI325W7.js} +7 -7
- package/dist/{chunk-SLIMABFA.js → chunk-2PLUQT6J.js} +2 -2
- package/dist/{chunk-VVH3ANF2.js → chunk-4IV6W4U5.js} +4 -4
- package/dist/{chunk-PV3GAXQO.js → chunk-6LEQW46Y.js} +2 -2
- package/dist/{chunk-6OTVPRXH.js → chunk-CVLAZRNB.js} +2 -2
- package/dist/{chunk-FXV24OYZ.js → chunk-DJUGYNQE.js} +9 -2
- package/dist/{chunk-FXV24OYZ.js.map → chunk-DJUGYNQE.js.map} +1 -1
- package/dist/{chunk-KOCQAD2E.js → chunk-HBVFXN7R.js} +3 -3
- package/dist/{chunk-HURVAQRK.js → chunk-LHP6ROUM.js} +4 -4
- package/dist/{chunk-PXZBAC2M.js → chunk-MFU53H6J.js} +2 -2
- package/dist/{chunk-L4QGC27H.js → chunk-PVAVNJKS.js} +13 -1
- package/dist/chunk-PVAVNJKS.js.map +1 -0
- package/dist/{chunk-PR7FKQBG.js → chunk-RF2YI2XJ.js} +2 -2
- package/dist/{chunk-DGEKUT7Q.js → chunk-SWCRXDZC.js} +34 -6
- package/dist/chunk-SWCRXDZC.js.map +1 -0
- package/dist/{chunk-Q2KYPAH2.js → chunk-SYOSCMIT.js} +6 -6
- package/dist/{chunk-VYQLLHZ7.js → chunk-T3KEIB4D.js} +6 -2
- package/dist/{chunk-VYQLLHZ7.js.map → chunk-T3KEIB4D.js.map} +1 -1
- package/dist/{chunk-IIPTBZQW.js → chunk-TS6DL67T.js} +2 -2
- package/dist/{chunk-IO4WFTL2.js → chunk-VETG35MF.js} +2 -2
- package/dist/{chunk-RSRO7564.js → chunk-ZE74H5BR.js} +28 -3
- package/dist/chunk-ZE74H5BR.js.map +1 -0
- package/dist/{claude-7LUVDZZ4.js → claude-ZIWDG4XG.js} +2 -2
- package/dist/{cleanup-ZHROIBSQ.js → cleanup-FEIVZSIV.js} +5 -5
- package/dist/cli.js +41 -31
- package/dist/cli.js.map +1 -1
- package/dist/contribute-EMZKCAC6.js +259 -0
- package/dist/contribute-EMZKCAC6.js.map +1 -0
- package/dist/{enhance-VVMAKMVZ.js → enhance-MNA4ZGXW.js} +7 -7
- package/dist/{feedback-AKHD7QIM.js → feedback-LFNMQBAZ.js} +6 -6
- package/dist/{finish-WGPISUEH.js → finish-TX5CJICB.js} +411 -17
- package/dist/finish-TX5CJICB.js.map +1 -0
- package/dist/{git-OUYMVYJX.js → git-WC6HZLOT.js} +2 -2
- package/dist/{ignite-JEN3K3OT.js → ignite-MQWVJEAB.js} +125 -10
- package/dist/ignite-MQWVJEAB.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +75 -7
- package/dist/index.js.map +1 -1
- package/dist/{init-EVUT4ZQJ.js → init-GJDYN2IK.js} +7 -7
- package/dist/mcp/{claude-YHHHLSXH.js → claude-NDFOCQQQ.js} +2 -2
- package/dist/mcp/github-comment-server.js.map +1 -1
- package/dist/mcp/{terminal-SDCMDVD7.js → terminal-OMNRFWB3.js} +28 -3
- package/dist/mcp/terminal-OMNRFWB3.js.map +1 -0
- package/dist/{open-ETZUFSE4.js → open-NXSN7XOC.js} +4 -4
- package/dist/prompts/init-prompt.txt +32 -1
- package/dist/prompts/issue-prompt.txt +141 -9
- package/dist/{rebase-KBWFDZCN.js → rebase-DUNFOJVS.js} +6 -6
- package/dist/{remote-GJEZWRCC.js → remote-ZCXJVVNW.js} +4 -2
- package/dist/{run-4SVQ3WEU.js → run-O7ZK7CKA.js} +4 -4
- package/dist/schema/settings.schema.json +18 -0
- package/dist/{start-2NEZU7SE.js → start-73I5W7WW.js} +16 -16
- package/dist/{terminal-3D6TUAKJ.js → terminal-BIRBZ4AZ.js} +2 -2
- package/dist/{test-git-MKZATGZN.js → test-git-T76HOTIA.js} +3 -3
- package/dist/{test-prefix-ZNLWDI3K.js → test-prefix-6HJUVQMH.js} +3 -3
- package/dist/{test-tabs-JRKY3QMM.js → test-tabs-RXDBZ6J7.js} +2 -2
- package/package.json +3 -2
- package/dist/ClaudeContextManager-LD3VB6EM.js +0 -13
- package/dist/ClaudeService-CFFI7DD5.js +0 -12
- package/dist/chunk-DGEKUT7Q.js.map +0 -1
- package/dist/chunk-L4QGC27H.js.map +0 -1
- package/dist/chunk-RSRO7564.js.map +0 -1
- package/dist/finish-WGPISUEH.js.map +0 -1
- package/dist/ignite-JEN3K3OT.js.map +0 -1
- package/dist/mcp/terminal-SDCMDVD7.js.map +0 -1
- /package/dist/{ClaudeContextManager-LD3VB6EM.js.map → ClaudeContextManager-LVCYRM6Q.js.map} +0 -0
- /package/dist/{ClaudeService-CFFI7DD5.js.map → ClaudeService-WVTWB3DK.js.map} +0 -0
- /package/dist/{GitHubService-SH4H6VS5.js.map → GitHubService-7E2S5NNZ.js.map} +0 -0
- /package/dist/{LoomLauncher-FB2MV2ZI.js.map → LoomLauncher-CTSWJL35.js.map} +0 -0
- /package/dist/{PromptTemplateManager-WM5GIPEF.js.map → PromptTemplateManager-WII75TKH.js.map} +0 -0
- /package/dist/{SettingsManager-SKLUVE3K.js.map → SettingsManager-XOYCLH3D.js.map} +0 -0
- /package/dist/{add-issue-L5HX6LEV.js.map → add-issue-OBI325W7.js.map} +0 -0
- /package/dist/{chunk-SLIMABFA.js.map → chunk-2PLUQT6J.js.map} +0 -0
- /package/dist/{chunk-VVH3ANF2.js.map → chunk-4IV6W4U5.js.map} +0 -0
- /package/dist/{chunk-PV3GAXQO.js.map → chunk-6LEQW46Y.js.map} +0 -0
- /package/dist/{chunk-6OTVPRXH.js.map → chunk-CVLAZRNB.js.map} +0 -0
- /package/dist/{chunk-KOCQAD2E.js.map → chunk-HBVFXN7R.js.map} +0 -0
- /package/dist/{chunk-HURVAQRK.js.map → chunk-LHP6ROUM.js.map} +0 -0
- /package/dist/{chunk-PXZBAC2M.js.map → chunk-MFU53H6J.js.map} +0 -0
- /package/dist/{chunk-PR7FKQBG.js.map → chunk-RF2YI2XJ.js.map} +0 -0
- /package/dist/{chunk-Q2KYPAH2.js.map → chunk-SYOSCMIT.js.map} +0 -0
- /package/dist/{chunk-IIPTBZQW.js.map → chunk-TS6DL67T.js.map} +0 -0
- /package/dist/{chunk-IO4WFTL2.js.map → chunk-VETG35MF.js.map} +0 -0
- /package/dist/{claude-7LUVDZZ4.js.map → claude-ZIWDG4XG.js.map} +0 -0
- /package/dist/{cleanup-ZHROIBSQ.js.map → cleanup-FEIVZSIV.js.map} +0 -0
- /package/dist/{enhance-VVMAKMVZ.js.map → enhance-MNA4ZGXW.js.map} +0 -0
- /package/dist/{feedback-AKHD7QIM.js.map → feedback-LFNMQBAZ.js.map} +0 -0
- /package/dist/{git-OUYMVYJX.js.map → git-WC6HZLOT.js.map} +0 -0
- /package/dist/{init-EVUT4ZQJ.js.map → init-GJDYN2IK.js.map} +0 -0
- /package/dist/mcp/{claude-YHHHLSXH.js.map → claude-NDFOCQQQ.js.map} +0 -0
- /package/dist/{open-ETZUFSE4.js.map → open-NXSN7XOC.js.map} +0 -0
- /package/dist/{rebase-KBWFDZCN.js.map → rebase-DUNFOJVS.js.map} +0 -0
- /package/dist/{remote-GJEZWRCC.js.map → remote-ZCXJVVNW.js.map} +0 -0
- /package/dist/{run-4SVQ3WEU.js.map → run-O7ZK7CKA.js.map} +0 -0
- /package/dist/{start-2NEZU7SE.js.map → start-73I5W7WW.js.map} +0 -0
- /package/dist/{terminal-3D6TUAKJ.js.map → terminal-BIRBZ4AZ.js.map} +0 -0
- /package/dist/{test-git-MKZATGZN.js.map → test-git-T76HOTIA.js.map} +0 -0
- /package/dist/{test-prefix-ZNLWDI3K.js.map → test-prefix-6HJUVQMH.js.map} +0 -0
- /package/dist/{test-tabs-JRKY3QMM.js.map → test-tabs-RXDBZ6J7.js.map} +0 -0
|
@@ -5,21 +5,21 @@ import {
|
|
|
5
5
|
import "./chunk-2ZPFJQ3B.js";
|
|
6
6
|
import {
|
|
7
7
|
IssueEnhancementService
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-RF2YI2XJ.js";
|
|
9
9
|
import {
|
|
10
10
|
AgentManager
|
|
11
11
|
} from "./chunk-OC4H6HJD.js";
|
|
12
12
|
import "./chunk-YETJNRQM.js";
|
|
13
13
|
import {
|
|
14
14
|
GitHubService
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-TS6DL67T.js";
|
|
16
|
+
import "./chunk-SWCRXDZC.js";
|
|
17
17
|
import {
|
|
18
18
|
getClaudeVersion
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-MFU53H6J.js";
|
|
20
20
|
import {
|
|
21
21
|
SettingsManager
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-T3KEIB4D.js";
|
|
23
23
|
import "./chunk-JNKJ7NJV.js";
|
|
24
24
|
import {
|
|
25
25
|
logger
|
|
@@ -155,4 +155,4 @@ ${description}`;
|
|
|
155
155
|
export {
|
|
156
156
|
FeedbackCommand
|
|
157
157
|
};
|
|
158
|
-
//# sourceMappingURL=feedback-
|
|
158
|
+
//# sourceMappingURL=feedback-LFNMQBAZ.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
MergeManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4IV6W4U5.js";
|
|
5
5
|
import {
|
|
6
6
|
ResourceCleanup
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SYOSCMIT.js";
|
|
8
8
|
import {
|
|
9
9
|
IdentifierParser
|
|
10
10
|
} from "./chunk-H4E4THUZ.js";
|
|
@@ -34,29 +34,39 @@ import {
|
|
|
34
34
|
hasScript,
|
|
35
35
|
readPackageJson
|
|
36
36
|
} from "./chunk-2ZPFJQ3B.js";
|
|
37
|
+
import {
|
|
38
|
+
openBrowser
|
|
39
|
+
} from "./chunk-YETJNRQM.js";
|
|
37
40
|
import {
|
|
38
41
|
getConfiguredRepoFromSettings,
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
getEffectivePRTargetRemote,
|
|
43
|
+
hasMultipleRemotes,
|
|
44
|
+
parseGitRemotes
|
|
45
|
+
} from "./chunk-DJUGYNQE.js";
|
|
41
46
|
import {
|
|
42
47
|
GitHubService
|
|
43
|
-
} from "./chunk-
|
|
44
|
-
import
|
|
48
|
+
} from "./chunk-TS6DL67T.js";
|
|
49
|
+
import {
|
|
50
|
+
executeGhCommand
|
|
51
|
+
} from "./chunk-SWCRXDZC.js";
|
|
45
52
|
import {
|
|
46
53
|
detectClaudeCli,
|
|
47
54
|
launchClaude
|
|
48
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-MFU53H6J.js";
|
|
49
56
|
import {
|
|
50
57
|
GitWorktreeManager
|
|
51
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-VETG35MF.js";
|
|
52
59
|
import {
|
|
53
60
|
SettingsManager
|
|
54
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-T3KEIB4D.js";
|
|
55
62
|
import {
|
|
56
63
|
executeGitCommand,
|
|
57
|
-
findMainWorktreePathWithSettings
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
findMainWorktreePathWithSettings,
|
|
65
|
+
pushBranchToRemote
|
|
66
|
+
} from "./chunk-HBVFXN7R.js";
|
|
67
|
+
import {
|
|
68
|
+
promptConfirmation
|
|
69
|
+
} from "./chunk-JNKJ7NJV.js";
|
|
60
70
|
import {
|
|
61
71
|
logger
|
|
62
72
|
} from "./chunk-GEHQXLEI.js";
|
|
@@ -781,6 +791,267 @@ Run '${runCommand}' to see detailed errors.`
|
|
|
781
791
|
}
|
|
782
792
|
};
|
|
783
793
|
|
|
794
|
+
// src/lib/PRManager.ts
|
|
795
|
+
var PRManager = class {
|
|
796
|
+
constructor(settings) {
|
|
797
|
+
this.settings = settings;
|
|
798
|
+
}
|
|
799
|
+
/**
|
|
800
|
+
* Check if a PR already exists for the given branch
|
|
801
|
+
* @param branchName - Branch to check
|
|
802
|
+
* @param cwd - Working directory
|
|
803
|
+
* @returns Existing PR info or null if none found
|
|
804
|
+
*/
|
|
805
|
+
async checkForExistingPR(branchName, cwd) {
|
|
806
|
+
try {
|
|
807
|
+
const prList = await executeGhCommand(
|
|
808
|
+
["pr", "list", "--head", branchName, "--state", "open", "--json", "number,url"],
|
|
809
|
+
cwd ? { cwd } : void 0
|
|
810
|
+
);
|
|
811
|
+
if (prList.length > 0) {
|
|
812
|
+
return prList[0] ?? null;
|
|
813
|
+
}
|
|
814
|
+
return null;
|
|
815
|
+
} catch (error) {
|
|
816
|
+
logger.debug("Error checking for existing PR", { error });
|
|
817
|
+
return null;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
/**
|
|
821
|
+
* Generate PR body using Claude if available, otherwise use simple template
|
|
822
|
+
* @param issueNumber - Issue number to include in body
|
|
823
|
+
* @param worktreePath - Path to worktree for context
|
|
824
|
+
* @returns PR body markdown
|
|
825
|
+
*/
|
|
826
|
+
async generatePRBody(issueNumber, worktreePath) {
|
|
827
|
+
const hasClaudeCli = await detectClaudeCli();
|
|
828
|
+
if (hasClaudeCli) {
|
|
829
|
+
try {
|
|
830
|
+
const prompt = this.buildPRBodyPrompt(issueNumber);
|
|
831
|
+
const body2 = await launchClaude(prompt, {
|
|
832
|
+
headless: true,
|
|
833
|
+
addDir: worktreePath,
|
|
834
|
+
timeout: 3e4
|
|
835
|
+
});
|
|
836
|
+
if (body2 && typeof body2 === "string" && body2.trim()) {
|
|
837
|
+
const sanitized = this.sanitizeClaudeOutput(body2);
|
|
838
|
+
if (sanitized) {
|
|
839
|
+
return sanitized;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
} catch (error) {
|
|
843
|
+
logger.debug("Claude PR body generation failed, using template", { error });
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
let body = "This PR contains changes from the iloom workflow.\n\n";
|
|
847
|
+
if (issueNumber) {
|
|
848
|
+
body += `Fixes #${issueNumber}`;
|
|
849
|
+
}
|
|
850
|
+
return body;
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Build structured XML prompt for PR body generation
|
|
854
|
+
* Uses XML format for clear task definition and output expectations
|
|
855
|
+
*/
|
|
856
|
+
buildPRBodyPrompt(issueNumber) {
|
|
857
|
+
const issueContext = issueNumber ? `
|
|
858
|
+
<IssueContext>
|
|
859
|
+
This PR is associated with GitHub issue #${issueNumber}.
|
|
860
|
+
Include "Fixes #${issueNumber}" at the end of the body on its own line.
|
|
861
|
+
</IssueContext>` : "";
|
|
862
|
+
return `<Task>
|
|
863
|
+
You are a software engineer writing a pull request body for this repository.
|
|
864
|
+
Examine the changes in the git repository and generate a concise, professional PR description.
|
|
865
|
+
</Task>
|
|
866
|
+
|
|
867
|
+
<Requirements>
|
|
868
|
+
<Format>Write 2-3 sentences summarizing what was changed and why.${issueNumber ? `
|
|
869
|
+
|
|
870
|
+
End with "Fixes #${issueNumber}" on its own line.` : ""}</Format>
|
|
871
|
+
<Tone>Professional and concise</Tone>
|
|
872
|
+
<Focus>Summarize the changes and their purpose</Focus>
|
|
873
|
+
<NoMeta>CRITICAL: Do NOT include ANY explanatory text, analysis, or meta-commentary. Output ONLY the raw PR body text.</NoMeta>
|
|
874
|
+
<Examples>
|
|
875
|
+
Good: "Add user authentication with JWT tokens to secure the API endpoints. This includes login and registration endpoints with proper password hashing.
|
|
876
|
+
|
|
877
|
+
Fixes #42"
|
|
878
|
+
Good: "Fix navigation bug in sidebar menu that caused incorrect highlighting on nested routes."
|
|
879
|
+
Bad: "Here's the PR body:
|
|
880
|
+
|
|
881
|
+
---
|
|
882
|
+
|
|
883
|
+
Add user authentication..."
|
|
884
|
+
Bad: "Based on the changes, I'll write: Fix navigation bug..."
|
|
885
|
+
</Examples>
|
|
886
|
+
${issueContext}
|
|
887
|
+
</Requirements>
|
|
888
|
+
|
|
889
|
+
<Output>
|
|
890
|
+
IMPORTANT: Your entire response will be used directly as the GitHub pull request body.
|
|
891
|
+
Do not include any explanatory text, headers, or separators before or after the body.
|
|
892
|
+
Start your response immediately with the PR body text.
|
|
893
|
+
</Output>`;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* Sanitize Claude output to remove meta-commentary and clean formatting
|
|
897
|
+
* Handles cases where Claude includes explanatory text despite instructions
|
|
898
|
+
*/
|
|
899
|
+
sanitizeClaudeOutput(rawOutput) {
|
|
900
|
+
let cleaned = rawOutput.trim();
|
|
901
|
+
const metaPatterns = [
|
|
902
|
+
/^.*?based on.*?changes.*?:/i,
|
|
903
|
+
/^.*?looking at.*?files.*?:/i,
|
|
904
|
+
/^.*?examining.*?:/i,
|
|
905
|
+
/^.*?analyzing.*?:/i,
|
|
906
|
+
/^.*?i'll.*?generate.*?:/i,
|
|
907
|
+
/^.*?let me.*?:/i,
|
|
908
|
+
/^.*?here.*?is.*?(?:the\s+)?(?:pr|pull request).*?body.*?:/i,
|
|
909
|
+
/^.*?here's.*?(?:the\s+)?(?:pr|pull request).*?body.*?:/i
|
|
910
|
+
];
|
|
911
|
+
for (const pattern of metaPatterns) {
|
|
912
|
+
cleaned = cleaned.replace(pattern, "").trim();
|
|
913
|
+
}
|
|
914
|
+
cleaned = cleaned.replace(/^[-=]{3,}\s*/m, "").trim();
|
|
915
|
+
if (cleaned.includes(":")) {
|
|
916
|
+
const colonIndex = cleaned.indexOf(":");
|
|
917
|
+
const beforeColon = cleaned.substring(0, colonIndex).trim().toLowerCase();
|
|
918
|
+
const metaIndicators = [
|
|
919
|
+
"here is the pr body",
|
|
920
|
+
"here is the pull request body",
|
|
921
|
+
"pr body",
|
|
922
|
+
"pull request body",
|
|
923
|
+
"here is",
|
|
924
|
+
"here's",
|
|
925
|
+
"the body should be",
|
|
926
|
+
"i suggest",
|
|
927
|
+
"my suggestion"
|
|
928
|
+
];
|
|
929
|
+
const isMetaCommentary = metaIndicators.some((indicator) => beforeColon.includes(indicator));
|
|
930
|
+
if (isMetaCommentary) {
|
|
931
|
+
const afterColon = cleaned.substring(colonIndex + 1).trim();
|
|
932
|
+
const afterSeparator = afterColon.replace(/^[-=]{3,}\s*/m, "").trim();
|
|
933
|
+
if (afterSeparator && afterSeparator.length > 10) {
|
|
934
|
+
cleaned = afterSeparator;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
if (cleaned.startsWith('"') && cleaned.endsWith('"') || cleaned.startsWith("'") && cleaned.endsWith("'")) {
|
|
939
|
+
cleaned = cleaned.slice(1, -1).trim();
|
|
940
|
+
}
|
|
941
|
+
return cleaned;
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Create a GitHub PR for the branch
|
|
945
|
+
* @param branchName - Branch to create PR from (used as --head)
|
|
946
|
+
* @param title - PR title
|
|
947
|
+
* @param body - PR body
|
|
948
|
+
* @param baseBranch - Base branch to target (usually main/master)
|
|
949
|
+
* @param cwd - Working directory
|
|
950
|
+
* @returns PR URL
|
|
951
|
+
*/
|
|
952
|
+
async createPR(branchName, title, body, baseBranch, cwd) {
|
|
953
|
+
try {
|
|
954
|
+
const targetRemote = await getEffectivePRTargetRemote(this.settings, cwd);
|
|
955
|
+
let headValue = branchName;
|
|
956
|
+
if (targetRemote !== "origin") {
|
|
957
|
+
const remotes = await parseGitRemotes(cwd);
|
|
958
|
+
const originRemote = remotes.find((r) => r.name === "origin");
|
|
959
|
+
if (originRemote) {
|
|
960
|
+
headValue = `${originRemote.owner}:${branchName}`;
|
|
961
|
+
logger.debug(`Fork workflow detected, using head: ${headValue}`);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
const args = ["pr", "create", "--head", headValue, "--title", title, "--body", body, "--base", baseBranch];
|
|
965
|
+
if (targetRemote !== "origin") {
|
|
966
|
+
const repo = await getConfiguredRepoFromSettings(this.settings, cwd);
|
|
967
|
+
args.push("--repo", repo);
|
|
968
|
+
}
|
|
969
|
+
const result = await executeGhCommand(args, cwd ? { cwd } : void 0);
|
|
970
|
+
const url = typeof result === "string" ? result.trim() : String(result).trim();
|
|
971
|
+
if (!url.includes("github.com") || !url.includes("/pull/")) {
|
|
972
|
+
throw new Error(`Unexpected response from gh pr create: ${url}`);
|
|
973
|
+
}
|
|
974
|
+
return url;
|
|
975
|
+
} catch (error) {
|
|
976
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
977
|
+
if (errorMessage.includes("Head sha can't be blank") || errorMessage.includes("No commits between")) {
|
|
978
|
+
throw new Error(
|
|
979
|
+
`Failed to create pull request: ${errorMessage}
|
|
980
|
+
|
|
981
|
+
This error typically occurs when:
|
|
982
|
+
- The branch was not fully pushed to the remote
|
|
983
|
+
- There's a race condition between push and PR creation
|
|
984
|
+
- The branch has no commits ahead of the base branch
|
|
985
|
+
|
|
986
|
+
Try running: git push -u origin ${branchName}
|
|
987
|
+
Then retry: il finish`
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
throw new Error(`Failed to create pull request: ${errorMessage}`);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Open PR URL in browser
|
|
995
|
+
* @param url - PR URL to open
|
|
996
|
+
*/
|
|
997
|
+
async openPRInBrowser(url) {
|
|
998
|
+
try {
|
|
999
|
+
await openBrowser(url);
|
|
1000
|
+
logger.debug("Opened PR in browser", { url });
|
|
1001
|
+
} catch (error) {
|
|
1002
|
+
logger.warn("Failed to open PR in browser", { error });
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Complete PR workflow: check for existing, create if needed, optionally open in browser
|
|
1007
|
+
* @param branchName - Branch to create PR from
|
|
1008
|
+
* @param title - PR title
|
|
1009
|
+
* @param issueNumber - Optional issue number for body generation
|
|
1010
|
+
* @param baseBranch - Base branch to target
|
|
1011
|
+
* @param worktreePath - Path to worktree
|
|
1012
|
+
* @param openInBrowser - Whether to open PR in browser
|
|
1013
|
+
* @returns PR creation result
|
|
1014
|
+
*/
|
|
1015
|
+
async createOrOpenPR(branchName, title, issueNumber, baseBranch, worktreePath, openInBrowser) {
|
|
1016
|
+
const existingPR = await this.checkForExistingPR(branchName, worktreePath);
|
|
1017
|
+
if (existingPR) {
|
|
1018
|
+
logger.info(`Pull request already exists: ${existingPR.url}`);
|
|
1019
|
+
if (openInBrowser) {
|
|
1020
|
+
await this.openPRInBrowser(existingPR.url);
|
|
1021
|
+
}
|
|
1022
|
+
return {
|
|
1023
|
+
url: existingPR.url,
|
|
1024
|
+
number: existingPR.number,
|
|
1025
|
+
wasExisting: true
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
const body = await this.generatePRBody(issueNumber, worktreePath);
|
|
1029
|
+
logger.info("Creating pull request...");
|
|
1030
|
+
const url = await this.createPR(branchName, title, body, baseBranch, worktreePath);
|
|
1031
|
+
const prNumber = this.extractPRNumberFromUrl(url);
|
|
1032
|
+
if (openInBrowser) {
|
|
1033
|
+
await this.openPRInBrowser(url);
|
|
1034
|
+
}
|
|
1035
|
+
return {
|
|
1036
|
+
url,
|
|
1037
|
+
number: prNumber,
|
|
1038
|
+
wasExisting: false
|
|
1039
|
+
};
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Extract PR number from GitHub PR URL
|
|
1043
|
+
* @param url - PR URL (e.g., https://github.com/owner/repo/pull/123)
|
|
1044
|
+
* @returns PR number
|
|
1045
|
+
*/
|
|
1046
|
+
extractPRNumberFromUrl(url) {
|
|
1047
|
+
const match = url.match(/\/pull\/(\d+)/);
|
|
1048
|
+
if (match == null ? void 0 : match[1]) {
|
|
1049
|
+
return parseInt(match[1], 10);
|
|
1050
|
+
}
|
|
1051
|
+
throw new Error(`Could not extract PR number from URL: ${url}`);
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
1054
|
+
|
|
784
1055
|
// src/commands/finish.ts
|
|
785
1056
|
import path from "path";
|
|
786
1057
|
var FinishCommand = class {
|
|
@@ -1107,8 +1378,8 @@ var FinishCommand = class {
|
|
|
1107
1378
|
logger.info("[DRY RUN] Would auto-commit uncommitted changes (validation passed)");
|
|
1108
1379
|
} else {
|
|
1109
1380
|
logger.info("Validation passed, auto-committing uncommitted changes...");
|
|
1110
|
-
const
|
|
1111
|
-
const skipVerify = ((_b = (_a =
|
|
1381
|
+
const settings2 = await this.settingsManager.loadSettings(worktree.path);
|
|
1382
|
+
const skipVerify = ((_b = (_a = settings2.workflows) == null ? void 0 : _a.issue) == null ? void 0 : _b.noVerify) ?? false;
|
|
1112
1383
|
const commitOptions = {
|
|
1113
1384
|
dryRun: options.dryRun ?? false,
|
|
1114
1385
|
skipVerify
|
|
@@ -1122,6 +1393,12 @@ var FinishCommand = class {
|
|
|
1122
1393
|
} else {
|
|
1123
1394
|
logger.debug("No uncommitted changes found");
|
|
1124
1395
|
}
|
|
1396
|
+
const settings = await this.settingsManager.loadSettings(worktree.path);
|
|
1397
|
+
const mergeBehavior = settings.mergeBehavior ?? { mode: "local" };
|
|
1398
|
+
if (mergeBehavior.mode === "github-pr") {
|
|
1399
|
+
await this.executeGitHubPRWorkflow(parsed, options, worktree, settings);
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1125
1402
|
logger.info("Rebasing branch on main...");
|
|
1126
1403
|
const mergeOptions = {
|
|
1127
1404
|
dryRun: options.dryRun ?? false,
|
|
@@ -1189,8 +1466,8 @@ var FinishCommand = class {
|
|
|
1189
1466
|
logger.info(`[DRY RUN] Would push changes to origin/${pr.branch}`);
|
|
1190
1467
|
} else {
|
|
1191
1468
|
logger.info("Pushing changes to remote...");
|
|
1192
|
-
const { pushBranchToRemote } = await import("./git-
|
|
1193
|
-
await
|
|
1469
|
+
const { pushBranchToRemote: pushBranchToRemote2 } = await import("./git-WC6HZLOT.js");
|
|
1470
|
+
await pushBranchToRemote2(pr.branch, worktree.path, {
|
|
1194
1471
|
dryRun: false
|
|
1195
1472
|
});
|
|
1196
1473
|
logger.success(`Changes pushed to PR #${parsed.number}`);
|
|
@@ -1200,6 +1477,123 @@ var FinishCommand = class {
|
|
|
1200
1477
|
logger.info(`To cleanup when done: il cleanup ${parsed.number}`);
|
|
1201
1478
|
}
|
|
1202
1479
|
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Execute workflow for GitHub PR creation (github-pr merge mode)
|
|
1482
|
+
* Validates → Commits → Pushes → Creates PR → Prompts for cleanup
|
|
1483
|
+
*/
|
|
1484
|
+
async executeGitHubPRWorkflow(parsed, options, worktree, settings) {
|
|
1485
|
+
if (options.dryRun) {
|
|
1486
|
+
logger.info("[DRY RUN] Would push branch to origin");
|
|
1487
|
+
} else {
|
|
1488
|
+
logger.info("Pushing branch to origin...");
|
|
1489
|
+
await pushBranchToRemote(worktree.branch, worktree.path, { dryRun: false });
|
|
1490
|
+
logger.success("Branch pushed successfully");
|
|
1491
|
+
}
|
|
1492
|
+
const prManager = new PRManager(settings);
|
|
1493
|
+
let prTitle = `Work from ${worktree.branch}`;
|
|
1494
|
+
if (parsed.type === "issue" && parsed.number) {
|
|
1495
|
+
try {
|
|
1496
|
+
const issue = await this.gitHubService.fetchIssue(parsed.number);
|
|
1497
|
+
prTitle = issue.title;
|
|
1498
|
+
} catch (error) {
|
|
1499
|
+
logger.debug("Could not fetch issue title, using branch name", { error });
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
if (options.dryRun) {
|
|
1503
|
+
logger.info("[DRY RUN] Would create GitHub PR");
|
|
1504
|
+
logger.info(` Title: ${prTitle}`);
|
|
1505
|
+
logger.info(` Base: ${settings.mainBranch ?? "main"}`);
|
|
1506
|
+
} else {
|
|
1507
|
+
const baseBranch = settings.mainBranch ?? "main";
|
|
1508
|
+
const openInBrowser = options.noBrowser !== true;
|
|
1509
|
+
const result = await prManager.createOrOpenPR(
|
|
1510
|
+
worktree.branch,
|
|
1511
|
+
prTitle,
|
|
1512
|
+
parsed.type === "issue" ? parsed.number : void 0,
|
|
1513
|
+
baseBranch,
|
|
1514
|
+
worktree.path,
|
|
1515
|
+
openInBrowser
|
|
1516
|
+
);
|
|
1517
|
+
if (result.wasExisting) {
|
|
1518
|
+
logger.success(`Existing pull request: ${result.url}`);
|
|
1519
|
+
} else {
|
|
1520
|
+
logger.success(`Pull request created: ${result.url}`);
|
|
1521
|
+
}
|
|
1522
|
+
await this.handlePRCleanupPrompt(parsed, options, worktree);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Handle cleanup prompt after PR creation
|
|
1527
|
+
* Respects --cleanup and --no-cleanup flags, otherwise prompts user
|
|
1528
|
+
*/
|
|
1529
|
+
async handlePRCleanupPrompt(parsed, options, worktree) {
|
|
1530
|
+
if (options.cleanup === true) {
|
|
1531
|
+
logger.info("Cleaning up worktree (--cleanup flag)...");
|
|
1532
|
+
await this.performWorktreeCleanup(parsed, options, worktree);
|
|
1533
|
+
} else if (options.cleanup === false) {
|
|
1534
|
+
logger.info("Worktree kept active for continued work (--no-cleanup flag)");
|
|
1535
|
+
logger.info(`To cleanup later: il cleanup ${parsed.originalInput}`);
|
|
1536
|
+
} else {
|
|
1537
|
+
logger.info("");
|
|
1538
|
+
logger.info("PR created successfully. Would you like to clean up the worktree?");
|
|
1539
|
+
logger.info(` Worktree: ${worktree.path}`);
|
|
1540
|
+
logger.info(` Branch: ${worktree.branch}`);
|
|
1541
|
+
logger.info("");
|
|
1542
|
+
const shouldCleanup = await promptConfirmation(
|
|
1543
|
+
"Clean up worktree now?",
|
|
1544
|
+
false
|
|
1545
|
+
// Default to keeping worktree (safer option)
|
|
1546
|
+
);
|
|
1547
|
+
if (shouldCleanup) {
|
|
1548
|
+
await this.performWorktreeCleanup(parsed, options, worktree);
|
|
1549
|
+
} else {
|
|
1550
|
+
logger.info("Worktree kept active. Run `il cleanup` when ready.");
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* Perform worktree cleanup (used by GitHub PR workflow)
|
|
1556
|
+
* Similar to performPostMergeCleanup but for PR workflow
|
|
1557
|
+
*/
|
|
1558
|
+
async performWorktreeCleanup(parsed, options, worktree) {
|
|
1559
|
+
const cleanupInput = {
|
|
1560
|
+
type: parsed.type,
|
|
1561
|
+
originalInput: parsed.originalInput,
|
|
1562
|
+
...parsed.number !== void 0 && { number: parsed.number },
|
|
1563
|
+
...parsed.branchName !== void 0 && { branchName: parsed.branchName }
|
|
1564
|
+
};
|
|
1565
|
+
const cleanupOptions = {
|
|
1566
|
+
dryRun: options.dryRun ?? false,
|
|
1567
|
+
deleteBranch: false,
|
|
1568
|
+
// Don't delete branch - PR still needs it
|
|
1569
|
+
keepDatabase: false,
|
|
1570
|
+
// Clean up database
|
|
1571
|
+
force: options.force ?? false
|
|
1572
|
+
};
|
|
1573
|
+
try {
|
|
1574
|
+
logger.info("Starting worktree cleanup...");
|
|
1575
|
+
await this.ensureResourceCleanup();
|
|
1576
|
+
if (!this.resourceCleanup) {
|
|
1577
|
+
throw new Error("Failed to initialize ResourceCleanup");
|
|
1578
|
+
}
|
|
1579
|
+
const result = await this.resourceCleanup.cleanupWorktree(cleanupInput, cleanupOptions);
|
|
1580
|
+
this.reportCleanupResults(result);
|
|
1581
|
+
if (!result.success) {
|
|
1582
|
+
logger.warn("Some cleanup operations failed - manual cleanup may be required");
|
|
1583
|
+
this.showManualCleanupInstructions(worktree);
|
|
1584
|
+
} else {
|
|
1585
|
+
logger.success("Worktree cleanup completed successfully");
|
|
1586
|
+
}
|
|
1587
|
+
if (this.isRunningFromWithinWorktree(worktree.path)) {
|
|
1588
|
+
this.showTerminalCloseWarning(worktree);
|
|
1589
|
+
}
|
|
1590
|
+
} catch (error) {
|
|
1591
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
1592
|
+
logger.warn(`Cleanup failed: ${errorMessage}`);
|
|
1593
|
+
logger.warn("Manual cleanup may be required");
|
|
1594
|
+
this.showManualCleanupInstructions(worktree);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1203
1597
|
/**
|
|
1204
1598
|
* Perform cleanup for closed/merged PRs
|
|
1205
1599
|
* Similar to performPostMergeCleanup but with different messaging
|
|
@@ -1352,4 +1746,4 @@ var FinishCommand = class {
|
|
|
1352
1746
|
export {
|
|
1353
1747
|
FinishCommand
|
|
1354
1748
|
};
|
|
1355
|
-
//# sourceMappingURL=finish-
|
|
1749
|
+
//# sourceMappingURL=finish-TX5CJICB.js.map
|