@iloom/cli 0.4.1 → 0.5.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/README.md +24 -0
- package/dist/{ClaudeContextManager-DK77227F.js → ClaudeContextManager-DQFKIMEP.js} +5 -5
- package/dist/{ClaudeService-W3SA7HVG.js → ClaudeService-CJS32WG2.js} +4 -4
- package/dist/{LoomLauncher-S3YGJRJQ.js → LoomLauncher-JNWBMHES.js} +22 -88
- package/dist/LoomLauncher-JNWBMHES.js.map +1 -0
- package/dist/MetadataManager-WXUVXKUS.js +10 -0
- package/dist/PRManager-7DSIMCAD.js +16 -0
- package/dist/{PromptTemplateManager-2TDZAUC6.js → PromptTemplateManager-72FEOGT6.js} +2 -2
- package/dist/README.md +24 -0
- package/dist/{SettingsManager-FJFU6JJD.js → SettingsManager-XPR4TEQL.js} +2 -2
- package/dist/agents/iloom-issue-analyze-and-plan.md +41 -7
- package/dist/agents/iloom-issue-analyzer.md +38 -8
- package/dist/agents/iloom-issue-complexity-evaluator.md +45 -15
- package/dist/agents/iloom-issue-enhancer.md +60 -18
- package/dist/agents/iloom-issue-implementer.md +29 -7
- package/dist/agents/iloom-issue-planner.md +36 -7
- package/dist/agents/iloom-issue-reviewer.md +30 -7
- package/dist/{chunk-JC5HXN75.js → chunk-3CMGCRB5.js} +2 -2
- package/dist/{chunk-G6CIIJLT.js → chunk-4YTILIIH.js} +7 -8
- package/dist/chunk-4YTILIIH.js.map +1 -0
- package/dist/{chunk-IARWMDAX.js → chunk-6KB7R22U.js} +98 -16
- package/dist/chunk-6KB7R22U.js.map +1 -0
- package/dist/{chunk-55TB3FSG.js → chunk-AS2IRKLU.js} +2 -2
- package/dist/{chunk-VTXCGKV5.js → chunk-BVIK2P6P.js} +11 -3
- package/dist/chunk-BVIK2P6P.js.map +1 -0
- package/dist/chunk-CDF7ZX2B.js +72 -0
- package/dist/chunk-CDF7ZX2B.js.map +1 -0
- package/dist/{chunk-POI7KLBH.js → chunk-CDQEK2WD.js} +5 -5
- package/dist/{chunk-74VMN2KC.js → chunk-DKQ4SUII.js} +16 -1
- package/dist/chunk-DKQ4SUII.js.map +1 -0
- package/dist/{chunk-BIIQHEXJ.js → chunk-GVRO4PWE.js} +12 -8
- package/dist/chunk-GVRO4PWE.js.map +1 -0
- package/dist/{chunk-TMZAVPGF.js → chunk-HABINPX2.js} +71 -15
- package/dist/{chunk-TMZAVPGF.js.map → chunk-HABINPX2.js.map} +1 -1
- package/dist/{chunk-2W2FBL5G.js → chunk-LN4H3A6A.js} +66 -7
- package/dist/chunk-LN4H3A6A.js.map +1 -0
- package/dist/{chunk-VWNS6DH5.js → chunk-OOU3DKNT.js} +13 -7
- package/dist/chunk-OOU3DKNT.js.map +1 -0
- package/dist/chunk-P2ZQ5LKB.js +347 -0
- package/dist/chunk-P2ZQ5LKB.js.map +1 -0
- package/dist/{chunk-OF7BNW4D.js → chunk-RJKMF6BC.js} +30 -4
- package/dist/chunk-RJKMF6BC.js.map +1 -0
- package/dist/{chunk-O7WHXLCB.js → chunk-RNZMHJK7.js} +18 -4
- package/dist/chunk-RNZMHJK7.js.map +1 -0
- package/dist/{chunk-UPUAQYAW.js → chunk-S65T4O6I.js} +2 -2
- package/dist/{chunk-HD5SUKI2.js → chunk-TSLKDFAF.js} +55 -6
- package/dist/chunk-TSLKDFAF.js.map +1 -0
- package/dist/{chunk-IJ7IGJT3.js → chunk-YZTDGPFB.js} +18 -1
- package/dist/chunk-YZTDGPFB.js.map +1 -0
- package/dist/{cleanup-KDLVTT7M.js → cleanup-LU6NU2NZ.js} +14 -14
- package/dist/cli.js +283 -363
- package/dist/cli.js.map +1 -1
- package/dist/{contribute-HY372S6F.js → contribute-RS3DO3WP.js} +4 -4
- package/dist/{dev-server-JCJGQ3PV.js → dev-server-ASH7HJVI.js} +30 -16
- package/dist/dev-server-ASH7HJVI.js.map +1 -0
- package/dist/{feedback-7PVBQNLJ.js → feedback-OFVW22UW.js} +11 -6
- package/dist/{feedback-7PVBQNLJ.js.map → feedback-OFVW22UW.js.map} +1 -1
- package/dist/{git-4BVOOOOV.js → git-OQAPUPLP.js} +16 -6
- package/dist/git-OQAPUPLP.js.map +1 -0
- package/dist/{ignite-3B264M7K.js → ignite-NREQ3JRM.js} +57 -22
- package/dist/ignite-NREQ3JRM.js.map +1 -0
- package/dist/index.d.ts +58 -7
- package/dist/index.js +110 -7
- package/dist/index.js.map +1 -1
- package/dist/{init-LBA6NUK2.js → init-F6PFMSU5.js} +7 -7
- package/dist/init-F6PFMSU5.js.map +1 -0
- package/dist/mcp/recap-server.js +264 -0
- package/dist/mcp/recap-server.js.map +1 -0
- package/dist/{open-OGCV32Z4.js → open-KW4NTLXH.js} +16 -17
- package/dist/{open-OGCV32Z4.js.map → open-KW4NTLXH.js.map} +1 -1
- package/dist/{projects-P55273AB.js → projects-QEAEBAT2.js} +2 -2
- package/dist/prompts/init-prompt.txt +31 -72
- package/dist/prompts/issue-prompt.txt +115 -15
- package/dist/prompts/pr-prompt.txt +49 -1
- package/dist/prompts/regular-prompt.txt +80 -20
- package/dist/{rebase-4T5FQHNH.js → rebase-WZHHE5LU.js} +6 -6
- package/dist/recap-33NPZ3ZO.js +117 -0
- package/dist/recap-33NPZ3ZO.js.map +1 -0
- package/dist/{run-HNOP6WE2.js → run-HRYQ7TR7.js} +16 -17
- package/dist/{run-HNOP6WE2.js.map → run-HRYQ7TR7.js.map} +1 -1
- package/dist/schema/settings.schema.json +13 -2
- package/dist/{shell-DE3HKJSM.js → shell-JMU5XTHW.js} +6 -6
- package/dist/{summary-GDT7DTRI.js → summary-4SSGGH7N.js} +17 -9
- package/dist/summary-4SSGGH7N.js.map +1 -0
- package/dist/{test-git-YMAE57UP.js → test-git-6SAIRBUD.js} +4 -4
- package/dist/{test-prefix-YCKL6CMT.js → test-prefix-RLVRK5ZD.js} +4 -4
- package/package.json +1 -1
- package/dist/LoomLauncher-S3YGJRJQ.js.map +0 -1
- package/dist/chunk-2W2FBL5G.js.map +0 -1
- package/dist/chunk-74VMN2KC.js.map +0 -1
- package/dist/chunk-BIIQHEXJ.js.map +0 -1
- package/dist/chunk-G6CIIJLT.js.map +0 -1
- package/dist/chunk-HD5SUKI2.js.map +0 -1
- package/dist/chunk-IARWMDAX.js.map +0 -1
- package/dist/chunk-IJ7IGJT3.js.map +0 -1
- package/dist/chunk-O7WHXLCB.js.map +0 -1
- package/dist/chunk-OF7BNW4D.js.map +0 -1
- package/dist/chunk-QRBOPFAA.js +0 -48
- package/dist/chunk-QRBOPFAA.js.map +0 -1
- package/dist/chunk-VTXCGKV5.js.map +0 -1
- package/dist/chunk-VWNS6DH5.js.map +0 -1
- package/dist/dev-server-JCJGQ3PV.js.map +0 -1
- package/dist/ignite-3B264M7K.js.map +0 -1
- package/dist/summary-GDT7DTRI.js.map +0 -1
- /package/dist/{ClaudeContextManager-DK77227F.js.map → ClaudeContextManager-DQFKIMEP.js.map} +0 -0
- /package/dist/{ClaudeService-W3SA7HVG.js.map → ClaudeService-CJS32WG2.js.map} +0 -0
- /package/dist/{PromptTemplateManager-2TDZAUC6.js.map → MetadataManager-WXUVXKUS.js.map} +0 -0
- /package/dist/{SettingsManager-FJFU6JJD.js.map → PRManager-7DSIMCAD.js.map} +0 -0
- /package/dist/{git-4BVOOOOV.js.map → PromptTemplateManager-72FEOGT6.js.map} +0 -0
- /package/dist/{init-LBA6NUK2.js.map → SettingsManager-XPR4TEQL.js.map} +0 -0
- /package/dist/{chunk-JC5HXN75.js.map → chunk-3CMGCRB5.js.map} +0 -0
- /package/dist/{chunk-55TB3FSG.js.map → chunk-AS2IRKLU.js.map} +0 -0
- /package/dist/{chunk-POI7KLBH.js.map → chunk-CDQEK2WD.js.map} +0 -0
- /package/dist/{chunk-UPUAQYAW.js.map → chunk-S65T4O6I.js.map} +0 -0
- /package/dist/{cleanup-KDLVTT7M.js.map → cleanup-LU6NU2NZ.js.map} +0 -0
- /package/dist/{contribute-HY372S6F.js.map → contribute-RS3DO3WP.js.map} +0 -0
- /package/dist/{projects-P55273AB.js.map → projects-QEAEBAT2.js.map} +0 -0
- /package/dist/{rebase-4T5FQHNH.js.map → rebase-WZHHE5LU.js.map} +0 -0
- /package/dist/{shell-DE3HKJSM.js.map → shell-JMU5XTHW.js.map} +0 -0
- /package/dist/{test-git-YMAE57UP.js.map → test-git-6SAIRBUD.js.map} +0 -0
- /package/dist/{test-prefix-YCKL6CMT.js.map → test-prefix-RLVRK5ZD.js.map} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,98 +1,107 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SessionSummaryService
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-HABINPX2.js";
|
|
5
|
+
import {
|
|
6
|
+
FirstRunManager,
|
|
7
|
+
IssueTrackerFactory,
|
|
8
|
+
generateIssueManagementMcpConfig
|
|
9
|
+
} from "./chunk-TSLKDFAF.js";
|
|
10
|
+
import "./chunk-QHA67Q7A.js";
|
|
5
11
|
import {
|
|
6
12
|
CLIIsolationManager,
|
|
7
13
|
DatabaseManager,
|
|
8
14
|
EnvironmentManager,
|
|
9
15
|
LoomManager,
|
|
10
16
|
ResourceCleanup
|
|
11
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-6KB7R22U.js";
|
|
18
|
+
import {
|
|
19
|
+
detectPackageManager,
|
|
20
|
+
installDependencies,
|
|
21
|
+
runScript
|
|
22
|
+
} from "./chunk-VBFDVGAE.js";
|
|
23
|
+
import {
|
|
24
|
+
ProcessManager
|
|
25
|
+
} from "./chunk-VU3QMIP2.js";
|
|
26
|
+
import {
|
|
27
|
+
IdentifierParser
|
|
28
|
+
} from "./chunk-AS2IRKLU.js";
|
|
29
|
+
import {
|
|
30
|
+
createNeonProviderFromSettings
|
|
31
|
+
} from "./chunk-UNXRACJ7.js";
|
|
12
32
|
import {
|
|
13
33
|
InitCommand,
|
|
14
34
|
ShellCompletion
|
|
15
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-4YTILIIH.js";
|
|
16
36
|
import "./chunk-UYWAESOT.js";
|
|
17
37
|
import {
|
|
18
38
|
IssueEnhancementService,
|
|
19
39
|
capitalizeFirstLetter
|
|
20
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-BVIK2P6P.js";
|
|
21
41
|
import {
|
|
22
|
-
|
|
23
|
-
} from "./chunk-
|
|
42
|
+
AgentManager
|
|
43
|
+
} from "./chunk-RNZMHJK7.js";
|
|
24
44
|
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
generateIssueManagementMcpConfig
|
|
28
|
-
} from "./chunk-HD5SUKI2.js";
|
|
29
|
-
import "./chunk-QHA67Q7A.js";
|
|
45
|
+
ProjectCapabilityDetector
|
|
46
|
+
} from "./chunk-EBISESAP.js";
|
|
30
47
|
import {
|
|
31
|
-
|
|
32
|
-
|
|
48
|
+
hasScript,
|
|
49
|
+
readPackageJson
|
|
50
|
+
} from "./chunk-2ZPFJQ3B.js";
|
|
33
51
|
import {
|
|
34
|
-
|
|
35
|
-
} from "./chunk-
|
|
52
|
+
MergeManager
|
|
53
|
+
} from "./chunk-GVRO4PWE.js";
|
|
36
54
|
import {
|
|
37
|
-
|
|
38
|
-
} from "./chunk-
|
|
55
|
+
GitWorktreeManager
|
|
56
|
+
} from "./chunk-3CMGCRB5.js";
|
|
57
|
+
import {
|
|
58
|
+
PRManager
|
|
59
|
+
} from "./chunk-P2ZQ5LKB.js";
|
|
39
60
|
import {
|
|
40
61
|
openBrowser
|
|
41
62
|
} from "./chunk-YETJNRQM.js";
|
|
42
63
|
import {
|
|
43
|
-
|
|
44
|
-
|
|
64
|
+
getConfiguredRepoFromSettings,
|
|
65
|
+
hasMultipleRemotes
|
|
66
|
+
} from "./chunk-PSFVTBM7.js";
|
|
45
67
|
import {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
} from "./chunk-
|
|
68
|
+
getIdeConfig,
|
|
69
|
+
getInstallHint,
|
|
70
|
+
isIdeAvailable
|
|
71
|
+
} from "./chunk-CDF7ZX2B.js";
|
|
50
72
|
import {
|
|
51
73
|
ClaudeContextManager
|
|
52
|
-
} from "./chunk-
|
|
53
|
-
import "./chunk-
|
|
74
|
+
} from "./chunk-S65T4O6I.js";
|
|
75
|
+
import "./chunk-CDQEK2WD.js";
|
|
76
|
+
import "./chunk-DKQ4SUII.js";
|
|
54
77
|
import {
|
|
55
78
|
extractSettingsOverrides
|
|
56
79
|
} from "./chunk-GYCR2LOU.js";
|
|
57
80
|
import {
|
|
58
81
|
DefaultBranchNamingService
|
|
59
82
|
} from "./chunk-QIUJPPJQ.js";
|
|
60
|
-
import {
|
|
61
|
-
ProjectCapabilityDetector
|
|
62
|
-
} from "./chunk-EBISESAP.js";
|
|
63
|
-
import {
|
|
64
|
-
hasScript,
|
|
65
|
-
readPackageJson
|
|
66
|
-
} from "./chunk-2ZPFJQ3B.js";
|
|
67
|
-
import {
|
|
68
|
-
createNeonProviderFromSettings
|
|
69
|
-
} from "./chunk-UNXRACJ7.js";
|
|
70
|
-
import {
|
|
71
|
-
getConfiguredRepoFromSettings,
|
|
72
|
-
getEffectivePRTargetRemote,
|
|
73
|
-
hasMultipleRemotes,
|
|
74
|
-
parseGitRemotes
|
|
75
|
-
} from "./chunk-PSFVTBM7.js";
|
|
76
83
|
import {
|
|
77
84
|
executeGitCommand,
|
|
78
85
|
extractIssueNumber,
|
|
79
86
|
findMainWorktreePathWithSettings,
|
|
87
|
+
findPlaceholderCommitSha,
|
|
80
88
|
getMergeTargetBranch,
|
|
81
89
|
getRepoRoot,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
} from "./chunk-
|
|
90
|
+
isPlaceholderCommit,
|
|
91
|
+
pushBranchToRemote,
|
|
92
|
+
removePlaceholderCommitFromHead,
|
|
93
|
+
removePlaceholderCommitFromHistory
|
|
94
|
+
} from "./chunk-LN4H3A6A.js";
|
|
87
95
|
import {
|
|
88
96
|
SettingsManager
|
|
89
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-OOU3DKNT.js";
|
|
98
|
+
import {
|
|
99
|
+
MetadataManager
|
|
100
|
+
} from "./chunk-YZTDGPFB.js";
|
|
90
101
|
import {
|
|
91
102
|
GitHubService
|
|
92
103
|
} from "./chunk-OEGECBFS.js";
|
|
93
|
-
import
|
|
94
|
-
executeGhCommand
|
|
95
|
-
} from "./chunk-KO2FOMHL.js";
|
|
104
|
+
import "./chunk-KO2FOMHL.js";
|
|
96
105
|
import {
|
|
97
106
|
promptCommitAction,
|
|
98
107
|
promptConfirmation,
|
|
@@ -111,7 +120,6 @@ import {
|
|
|
111
120
|
getLogger,
|
|
112
121
|
withLogger
|
|
113
122
|
} from "./chunk-6UIGZD2N.js";
|
|
114
|
-
import "./chunk-74VMN2KC.js";
|
|
115
123
|
import {
|
|
116
124
|
createStderrLogger,
|
|
117
125
|
logger
|
|
@@ -605,7 +613,11 @@ var AddIssueCommand = class {
|
|
|
605
613
|
getLogger().info(`Using GitHub repository: ${repo}`);
|
|
606
614
|
}
|
|
607
615
|
}
|
|
608
|
-
|
|
616
|
+
const hasBody = !!body;
|
|
617
|
+
if (!description || !this.enhancementService.validateDescription(description, hasBody)) {
|
|
618
|
+
if (hasBody) {
|
|
619
|
+
throw new Error("Description is required and cannot be empty");
|
|
620
|
+
}
|
|
609
621
|
throw new Error("Description is required and must be more than 30 characters with at least 3 words");
|
|
610
622
|
}
|
|
611
623
|
const issueBody = body ?? await this.enhancementService.enhanceDescription(description);
|
|
@@ -1664,267 +1676,6 @@ Run '${runCommand}' to see detailed errors.`
|
|
|
1664
1676
|
}
|
|
1665
1677
|
};
|
|
1666
1678
|
|
|
1667
|
-
// src/lib/PRManager.ts
|
|
1668
|
-
var PRManager = class {
|
|
1669
|
-
constructor(settings) {
|
|
1670
|
-
this.settings = settings;
|
|
1671
|
-
}
|
|
1672
|
-
/**
|
|
1673
|
-
* Check if a PR already exists for the given branch
|
|
1674
|
-
* @param branchName - Branch to check
|
|
1675
|
-
* @param cwd - Working directory
|
|
1676
|
-
* @returns Existing PR info or null if none found
|
|
1677
|
-
*/
|
|
1678
|
-
async checkForExistingPR(branchName, cwd) {
|
|
1679
|
-
try {
|
|
1680
|
-
const prList = await executeGhCommand(
|
|
1681
|
-
["pr", "list", "--head", branchName, "--state", "open", "--json", "number,url"],
|
|
1682
|
-
cwd ? { cwd } : void 0
|
|
1683
|
-
);
|
|
1684
|
-
if (prList.length > 0) {
|
|
1685
|
-
return prList[0] ?? null;
|
|
1686
|
-
}
|
|
1687
|
-
return null;
|
|
1688
|
-
} catch (error) {
|
|
1689
|
-
getLogger().debug("Error checking for existing PR", { error });
|
|
1690
|
-
return null;
|
|
1691
|
-
}
|
|
1692
|
-
}
|
|
1693
|
-
/**
|
|
1694
|
-
* Generate PR body using Claude if available, otherwise use simple template
|
|
1695
|
-
* @param issueNumber - Issue number to include in body
|
|
1696
|
-
* @param worktreePath - Path to worktree for context
|
|
1697
|
-
* @returns PR body markdown
|
|
1698
|
-
*/
|
|
1699
|
-
async generatePRBody(issueNumber, worktreePath) {
|
|
1700
|
-
const hasClaudeCli = await detectClaudeCli();
|
|
1701
|
-
if (hasClaudeCli) {
|
|
1702
|
-
try {
|
|
1703
|
-
const prompt = this.buildPRBodyPrompt(issueNumber);
|
|
1704
|
-
const body2 = await launchClaude(prompt, {
|
|
1705
|
-
headless: true,
|
|
1706
|
-
addDir: worktreePath,
|
|
1707
|
-
timeout: 3e4
|
|
1708
|
-
});
|
|
1709
|
-
if (body2 && typeof body2 === "string" && body2.trim()) {
|
|
1710
|
-
const sanitized = this.sanitizeClaudeOutput(body2);
|
|
1711
|
-
if (sanitized) {
|
|
1712
|
-
return sanitized;
|
|
1713
|
-
}
|
|
1714
|
-
}
|
|
1715
|
-
} catch (error) {
|
|
1716
|
-
getLogger().debug("Claude PR body generation failed, using template", { error });
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
let body = "This PR contains changes from the iloom workflow.\n\n";
|
|
1720
|
-
if (issueNumber) {
|
|
1721
|
-
body += `Fixes #${issueNumber}`;
|
|
1722
|
-
}
|
|
1723
|
-
return body;
|
|
1724
|
-
}
|
|
1725
|
-
/**
|
|
1726
|
-
* Build structured XML prompt for PR body generation
|
|
1727
|
-
* Uses XML format for clear task definition and output expectations
|
|
1728
|
-
*/
|
|
1729
|
-
buildPRBodyPrompt(issueNumber) {
|
|
1730
|
-
const issueContext = issueNumber ? `
|
|
1731
|
-
<IssueContext>
|
|
1732
|
-
This PR is associated with GitHub issue #${issueNumber}.
|
|
1733
|
-
Include "Fixes #${issueNumber}" at the end of the body on its own line.
|
|
1734
|
-
</IssueContext>` : "";
|
|
1735
|
-
return `<Task>
|
|
1736
|
-
You are a software engineer writing a pull request body for this repository.
|
|
1737
|
-
Examine the changes in the git repository and generate a concise, professional PR description.
|
|
1738
|
-
</Task>
|
|
1739
|
-
|
|
1740
|
-
<Requirements>
|
|
1741
|
-
<Format>Write 2-3 sentences summarizing what was changed and why.${issueNumber ? `
|
|
1742
|
-
|
|
1743
|
-
End with "Fixes #${issueNumber}" on its own line.` : ""}</Format>
|
|
1744
|
-
<Tone>Professional and concise</Tone>
|
|
1745
|
-
<Focus>Summarize the changes and their purpose</Focus>
|
|
1746
|
-
<NoMeta>CRITICAL: Do NOT include ANY explanatory text, analysis, or meta-commentary. Output ONLY the raw PR body text.</NoMeta>
|
|
1747
|
-
<Examples>
|
|
1748
|
-
Good: "Add user authentication with JWT tokens to secure the API endpoints. This includes login and registration endpoints with proper password hashing.
|
|
1749
|
-
|
|
1750
|
-
Fixes #42"
|
|
1751
|
-
Good: "Fix navigation bug in sidebar menu that caused incorrect highlighting on nested routes."
|
|
1752
|
-
Bad: "Here's the PR body:
|
|
1753
|
-
|
|
1754
|
-
---
|
|
1755
|
-
|
|
1756
|
-
Add user authentication..."
|
|
1757
|
-
Bad: "Based on the changes, I'll write: Fix navigation bug..."
|
|
1758
|
-
</Examples>
|
|
1759
|
-
${issueContext}
|
|
1760
|
-
</Requirements>
|
|
1761
|
-
|
|
1762
|
-
<Output>
|
|
1763
|
-
IMPORTANT: Your entire response will be used directly as the GitHub pull request body.
|
|
1764
|
-
Do not include any explanatory text, headers, or separators before or after the body.
|
|
1765
|
-
Start your response immediately with the PR body text.
|
|
1766
|
-
</Output>`;
|
|
1767
|
-
}
|
|
1768
|
-
/**
|
|
1769
|
-
* Sanitize Claude output to remove meta-commentary and clean formatting
|
|
1770
|
-
* Handles cases where Claude includes explanatory text despite instructions
|
|
1771
|
-
*/
|
|
1772
|
-
sanitizeClaudeOutput(rawOutput) {
|
|
1773
|
-
let cleaned = rawOutput.trim();
|
|
1774
|
-
const metaPatterns = [
|
|
1775
|
-
/^.*?based on.*?changes.*?:/i,
|
|
1776
|
-
/^.*?looking at.*?files.*?:/i,
|
|
1777
|
-
/^.*?examining.*?:/i,
|
|
1778
|
-
/^.*?analyzing.*?:/i,
|
|
1779
|
-
/^.*?i'll.*?generate.*?:/i,
|
|
1780
|
-
/^.*?let me.*?:/i,
|
|
1781
|
-
/^.*?here.*?is.*?(?:the\s+)?(?:pr|pull request).*?body.*?:/i,
|
|
1782
|
-
/^.*?here's.*?(?:the\s+)?(?:pr|pull request).*?body.*?:/i
|
|
1783
|
-
];
|
|
1784
|
-
for (const pattern of metaPatterns) {
|
|
1785
|
-
cleaned = cleaned.replace(pattern, "").trim();
|
|
1786
|
-
}
|
|
1787
|
-
cleaned = cleaned.replace(/^[-=]{3,}\s*/m, "").trim();
|
|
1788
|
-
if (cleaned.includes(":")) {
|
|
1789
|
-
const colonIndex = cleaned.indexOf(":");
|
|
1790
|
-
const beforeColon = cleaned.substring(0, colonIndex).trim().toLowerCase();
|
|
1791
|
-
const metaIndicators = [
|
|
1792
|
-
"here is the pr body",
|
|
1793
|
-
"here is the pull request body",
|
|
1794
|
-
"pr body",
|
|
1795
|
-
"pull request body",
|
|
1796
|
-
"here is",
|
|
1797
|
-
"here's",
|
|
1798
|
-
"the body should be",
|
|
1799
|
-
"i suggest",
|
|
1800
|
-
"my suggestion"
|
|
1801
|
-
];
|
|
1802
|
-
const isMetaCommentary = metaIndicators.some((indicator) => beforeColon.includes(indicator));
|
|
1803
|
-
if (isMetaCommentary) {
|
|
1804
|
-
const afterColon = cleaned.substring(colonIndex + 1).trim();
|
|
1805
|
-
const afterSeparator = afterColon.replace(/^[-=]{3,}\s*/m, "").trim();
|
|
1806
|
-
if (afterSeparator && afterSeparator.length > 10) {
|
|
1807
|
-
cleaned = afterSeparator;
|
|
1808
|
-
}
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
if (cleaned.startsWith('"') && cleaned.endsWith('"') || cleaned.startsWith("'") && cleaned.endsWith("'")) {
|
|
1812
|
-
cleaned = cleaned.slice(1, -1).trim();
|
|
1813
|
-
}
|
|
1814
|
-
return cleaned;
|
|
1815
|
-
}
|
|
1816
|
-
/**
|
|
1817
|
-
* Create a GitHub PR for the branch
|
|
1818
|
-
* @param branchName - Branch to create PR from (used as --head)
|
|
1819
|
-
* @param title - PR title
|
|
1820
|
-
* @param body - PR body
|
|
1821
|
-
* @param baseBranch - Base branch to target (usually main/master)
|
|
1822
|
-
* @param cwd - Working directory
|
|
1823
|
-
* @returns PR URL
|
|
1824
|
-
*/
|
|
1825
|
-
async createPR(branchName, title, body, baseBranch, cwd) {
|
|
1826
|
-
try {
|
|
1827
|
-
const targetRemote = await getEffectivePRTargetRemote(this.settings, cwd);
|
|
1828
|
-
let headValue = branchName;
|
|
1829
|
-
if (targetRemote !== "origin") {
|
|
1830
|
-
const remotes = await parseGitRemotes(cwd);
|
|
1831
|
-
const originRemote = remotes.find((r) => r.name === "origin");
|
|
1832
|
-
if (originRemote) {
|
|
1833
|
-
headValue = `${originRemote.owner}:${branchName}`;
|
|
1834
|
-
getLogger().debug(`Fork workflow detected, using head: ${headValue}`);
|
|
1835
|
-
}
|
|
1836
|
-
}
|
|
1837
|
-
const args = ["pr", "create", "--head", headValue, "--title", title, "--body", body, "--base", baseBranch];
|
|
1838
|
-
if (targetRemote !== "origin") {
|
|
1839
|
-
const repo = await getConfiguredRepoFromSettings(this.settings, cwd);
|
|
1840
|
-
args.push("--repo", repo);
|
|
1841
|
-
}
|
|
1842
|
-
const result = await executeGhCommand(args, cwd ? { cwd } : void 0);
|
|
1843
|
-
const url = typeof result === "string" ? result.trim() : String(result).trim();
|
|
1844
|
-
if (!url.includes("github.com") || !url.includes("/pull/")) {
|
|
1845
|
-
throw new Error(`Unexpected response from gh pr create: ${url}`);
|
|
1846
|
-
}
|
|
1847
|
-
return url;
|
|
1848
|
-
} catch (error) {
|
|
1849
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1850
|
-
if (errorMessage.includes("Head sha can't be blank") || errorMessage.includes("No commits between")) {
|
|
1851
|
-
throw new Error(
|
|
1852
|
-
`Failed to create pull request: ${errorMessage}
|
|
1853
|
-
|
|
1854
|
-
This error typically occurs when:
|
|
1855
|
-
- The branch was not fully pushed to the remote
|
|
1856
|
-
- There's a race condition between push and PR creation
|
|
1857
|
-
- The branch has no commits ahead of the base branch
|
|
1858
|
-
|
|
1859
|
-
Try running: git push -u origin ${branchName}
|
|
1860
|
-
Then retry: il finish`
|
|
1861
|
-
);
|
|
1862
|
-
}
|
|
1863
|
-
throw new Error(`Failed to create pull request: ${errorMessage}`);
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
/**
|
|
1867
|
-
* Open PR URL in browser
|
|
1868
|
-
* @param url - PR URL to open
|
|
1869
|
-
*/
|
|
1870
|
-
async openPRInBrowser(url) {
|
|
1871
|
-
try {
|
|
1872
|
-
await openBrowser(url);
|
|
1873
|
-
getLogger().debug("Opened PR in browser", { url });
|
|
1874
|
-
} catch (error) {
|
|
1875
|
-
getLogger().warn("Failed to open PR in browser", { error });
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1878
|
-
/**
|
|
1879
|
-
* Complete PR workflow: check for existing, create if needed, optionally open in browser
|
|
1880
|
-
* @param branchName - Branch to create PR from
|
|
1881
|
-
* @param title - PR title
|
|
1882
|
-
* @param issueNumber - Optional issue number for body generation
|
|
1883
|
-
* @param baseBranch - Base branch to target
|
|
1884
|
-
* @param worktreePath - Path to worktree
|
|
1885
|
-
* @param openInBrowser - Whether to open PR in browser
|
|
1886
|
-
* @returns PR creation result
|
|
1887
|
-
*/
|
|
1888
|
-
async createOrOpenPR(branchName, title, issueNumber, baseBranch, worktreePath, openInBrowser) {
|
|
1889
|
-
const existingPR = await this.checkForExistingPR(branchName, worktreePath);
|
|
1890
|
-
if (existingPR) {
|
|
1891
|
-
getLogger().info(`Pull request already exists: ${existingPR.url}`);
|
|
1892
|
-
if (openInBrowser) {
|
|
1893
|
-
await this.openPRInBrowser(existingPR.url);
|
|
1894
|
-
}
|
|
1895
|
-
return {
|
|
1896
|
-
url: existingPR.url,
|
|
1897
|
-
number: existingPR.number,
|
|
1898
|
-
wasExisting: true
|
|
1899
|
-
};
|
|
1900
|
-
}
|
|
1901
|
-
const body = await this.generatePRBody(issueNumber, worktreePath);
|
|
1902
|
-
getLogger().info("Creating pull request...");
|
|
1903
|
-
const url = await this.createPR(branchName, title, body, baseBranch, worktreePath);
|
|
1904
|
-
const prNumber = this.extractPRNumberFromUrl(url);
|
|
1905
|
-
if (openInBrowser) {
|
|
1906
|
-
await this.openPRInBrowser(url);
|
|
1907
|
-
}
|
|
1908
|
-
return {
|
|
1909
|
-
url,
|
|
1910
|
-
number: prNumber,
|
|
1911
|
-
wasExisting: false
|
|
1912
|
-
};
|
|
1913
|
-
}
|
|
1914
|
-
/**
|
|
1915
|
-
* Extract PR number from GitHub PR URL
|
|
1916
|
-
* @param url - PR URL (e.g., https://github.com/owner/repo/pull/123)
|
|
1917
|
-
* @returns PR number
|
|
1918
|
-
*/
|
|
1919
|
-
extractPRNumberFromUrl(url) {
|
|
1920
|
-
const match = url.match(/\/pull\/(\d+)/);
|
|
1921
|
-
if (match == null ? void 0 : match[1]) {
|
|
1922
|
-
return parseInt(match[1], 10);
|
|
1923
|
-
}
|
|
1924
|
-
throw new Error(`Could not extract PR number from URL: ${url}`);
|
|
1925
|
-
}
|
|
1926
|
-
};
|
|
1927
|
-
|
|
1928
1679
|
// src/commands/finish.ts
|
|
1929
1680
|
import path3 from "path";
|
|
1930
1681
|
var FinishCommand = class {
|
|
@@ -2302,10 +2053,22 @@ var FinishCommand = class {
|
|
|
2302
2053
|
}
|
|
2303
2054
|
/**
|
|
2304
2055
|
* Execute workflow for issues and branches (merge into main)
|
|
2305
|
-
* This is the
|
|
2056
|
+
* This is the workflow: rebase → validate → commit → merge → cleanup
|
|
2306
2057
|
*/
|
|
2307
2058
|
async executeIssueWorkflow(parsed, options, worktree, result) {
|
|
2308
|
-
var _a, _b;
|
|
2059
|
+
var _a, _b, _c;
|
|
2060
|
+
getLogger().info("Rebasing branch on main...");
|
|
2061
|
+
const mergeOptions = {
|
|
2062
|
+
dryRun: options.dryRun ?? false,
|
|
2063
|
+
force: options.force ?? false
|
|
2064
|
+
};
|
|
2065
|
+
await this.mergeManager.rebaseOnMain(worktree.path, mergeOptions);
|
|
2066
|
+
getLogger().success("Branch rebased successfully");
|
|
2067
|
+
result.operations.push({
|
|
2068
|
+
type: "rebase",
|
|
2069
|
+
message: "Branch rebased on main",
|
|
2070
|
+
success: true
|
|
2071
|
+
});
|
|
2309
2072
|
if (!options.dryRun) {
|
|
2310
2073
|
getLogger().info("Running pre-merge validations...");
|
|
2311
2074
|
await this.validationRunner.runValidations(worktree.path, {
|
|
@@ -2380,18 +2143,92 @@ var FinishCommand = class {
|
|
|
2380
2143
|
await this.executeGitHubPRWorkflow(parsed, options, worktree, settings, result);
|
|
2381
2144
|
return;
|
|
2382
2145
|
}
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2146
|
+
if (mergeBehavior.mode === "github-draft-pr") {
|
|
2147
|
+
if (!this.issueTracker.supportsPullRequests) {
|
|
2148
|
+
throw new Error(
|
|
2149
|
+
`The 'github-draft-pr' merge mode requires a GitHub-compatible issue tracker. Your provider (${this.issueTracker.providerName}) does not support pull requests.`
|
|
2150
|
+
);
|
|
2151
|
+
}
|
|
2152
|
+
const { MetadataManager: MetadataManager2 } = await import("./MetadataManager-WXUVXKUS.js");
|
|
2153
|
+
const metadataManager = new MetadataManager2();
|
|
2154
|
+
const metadata = await metadataManager.readMetadata(worktree.path);
|
|
2155
|
+
getLogger().debug(`Draft PR mode: worktree=${worktree.path}, draftPrNumber=${(metadata == null ? void 0 : metadata.draftPrNumber) ?? "none"}`);
|
|
2156
|
+
if (!(metadata == null ? void 0 : metadata.draftPrNumber)) {
|
|
2157
|
+
getLogger().warn("No draft PR found in metadata, creating new PR...");
|
|
2158
|
+
await this.executeGitHubPRWorkflow(parsed, options, worktree, settings, result);
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
const isHeadPlaceholder = await isPlaceholderCommit(worktree.path);
|
|
2162
|
+
const placeholderSha = await findPlaceholderCommitSha(worktree.path);
|
|
2163
|
+
getLogger().debug(`Placeholder detection: isHead=${isHeadPlaceholder}, sha=${placeholderSha ?? "none"}`);
|
|
2164
|
+
if (isHeadPlaceholder) {
|
|
2165
|
+
const commitCount = await executeGitCommand(
|
|
2166
|
+
["rev-list", "--count", "HEAD"],
|
|
2167
|
+
{ cwd: worktree.path }
|
|
2168
|
+
);
|
|
2169
|
+
if (parseInt(commitCount.trim(), 10) <= 1) {
|
|
2170
|
+
throw new Error(
|
|
2171
|
+
"Cannot finish draft PR: no changes have been committed.\nPlease make at least one commit before finishing."
|
|
2172
|
+
);
|
|
2173
|
+
}
|
|
2174
|
+
if (!options.dryRun) {
|
|
2175
|
+
getLogger().info("Removing placeholder commit from HEAD...");
|
|
2176
|
+
await removePlaceholderCommitFromHead(worktree.path);
|
|
2177
|
+
} else {
|
|
2178
|
+
getLogger().info("[DRY RUN] Would remove placeholder commit from HEAD");
|
|
2179
|
+
}
|
|
2180
|
+
} else if (placeholderSha) {
|
|
2181
|
+
const commitsAfterPlaceholder = await executeGitCommand(
|
|
2182
|
+
["rev-list", "--count", `${placeholderSha}..HEAD`],
|
|
2183
|
+
{ cwd: worktree.path }
|
|
2184
|
+
);
|
|
2185
|
+
if (parseInt(commitsAfterPlaceholder.trim(), 10) === 0) {
|
|
2186
|
+
throw new Error(
|
|
2187
|
+
"Cannot finish draft PR: no changes have been committed after the placeholder.\nPlease make at least one commit before finishing."
|
|
2188
|
+
);
|
|
2189
|
+
}
|
|
2190
|
+
if (!options.dryRun) {
|
|
2191
|
+
getLogger().info("Removing placeholder commit from history...");
|
|
2192
|
+
await removePlaceholderCommitFromHistory(worktree.path, placeholderSha);
|
|
2193
|
+
} else {
|
|
2194
|
+
getLogger().info("[DRY RUN] Would remove placeholder commit from history");
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
const needsForceWithLease = isHeadPlaceholder || placeholderSha;
|
|
2198
|
+
if (!options.dryRun) {
|
|
2199
|
+
getLogger().info("Pushing final commits to remote...");
|
|
2200
|
+
if (needsForceWithLease) {
|
|
2201
|
+
await executeGitCommand(["push", "--force-with-lease", "origin", worktree.branch], { cwd: worktree.path });
|
|
2202
|
+
} else {
|
|
2203
|
+
await pushBranchToRemote(worktree.branch, worktree.path, { dryRun: false });
|
|
2204
|
+
}
|
|
2205
|
+
} else {
|
|
2206
|
+
if (needsForceWithLease) {
|
|
2207
|
+
getLogger().info("[DRY RUN] Would force push final commits to remote (history rewritten)");
|
|
2208
|
+
} else {
|
|
2209
|
+
getLogger().info("[DRY RUN] Would push final commits to remote");
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
const prManager = new PRManager(settings);
|
|
2213
|
+
if (!options.dryRun) {
|
|
2214
|
+
await prManager.markPRReady(metadata.draftPrNumber, worktree.path);
|
|
2215
|
+
getLogger().success(`PR #${metadata.draftPrNumber} marked as ready for review`);
|
|
2216
|
+
} else {
|
|
2217
|
+
getLogger().info(`[DRY RUN] Would mark PR #${metadata.draftPrNumber} as ready for review`);
|
|
2218
|
+
}
|
|
2219
|
+
const prUrl = (_c = metadata.prUrls) == null ? void 0 : _c[String(metadata.draftPrNumber)];
|
|
2220
|
+
if (prUrl) {
|
|
2221
|
+
result.prUrl = prUrl;
|
|
2222
|
+
}
|
|
2223
|
+
result.operations.push({
|
|
2224
|
+
type: "pr-ready",
|
|
2225
|
+
message: `PR #${metadata.draftPrNumber} marked as ready for review`,
|
|
2226
|
+
success: true
|
|
2227
|
+
});
|
|
2228
|
+
await this.generateSessionSummaryIfConfigured(parsed, worktree, options, metadata.draftPrNumber);
|
|
2229
|
+
await this.handlePRCleanupPrompt(parsed, options, worktree, result);
|
|
2230
|
+
return;
|
|
2231
|
+
}
|
|
2395
2232
|
getLogger().info("Performing fast-forward merge...");
|
|
2396
2233
|
await this.mergeManager.performFastForwardMerge(worktree.branch, worktree.path, mergeOptions);
|
|
2397
2234
|
getLogger().success("Fast-forward merge completed successfully");
|
|
@@ -2555,7 +2392,7 @@ var FinishCommand = class {
|
|
|
2555
2392
|
});
|
|
2556
2393
|
}
|
|
2557
2394
|
finishResult.prUrl = prResult.url;
|
|
2558
|
-
await this.generateSessionSummaryIfConfigured(parsed, worktree, options);
|
|
2395
|
+
await this.generateSessionSummaryIfConfigured(parsed, worktree, options, prResult.number);
|
|
2559
2396
|
await this.handlePRCleanupPrompt(parsed, options, worktree, finishResult);
|
|
2560
2397
|
}
|
|
2561
2398
|
}
|
|
@@ -2578,8 +2415,8 @@ var FinishCommand = class {
|
|
|
2578
2415
|
getLogger().info("");
|
|
2579
2416
|
const shouldCleanup = await promptConfirmation(
|
|
2580
2417
|
"Clean up worktree now?",
|
|
2581
|
-
|
|
2582
|
-
// Default to keeping worktree
|
|
2418
|
+
true
|
|
2419
|
+
// Default to keeping worktree - won't delete if unmerged changes
|
|
2583
2420
|
);
|
|
2584
2421
|
if (shouldCleanup) {
|
|
2585
2422
|
await this.performWorktreeCleanup(parsed, options, worktree, finishResult);
|
|
@@ -2720,8 +2557,13 @@ var FinishCommand = class {
|
|
|
2720
2557
|
* This ensures the finish workflow continues even if summary generation fails
|
|
2721
2558
|
*
|
|
2722
2559
|
* In dry-run mode: generates summary and shows preview, but doesn't post
|
|
2560
|
+
*
|
|
2561
|
+
* @param parsed - The parsed input identifying the issue/PR being finished
|
|
2562
|
+
* @param worktree - The worktree being finished
|
|
2563
|
+
* @param options - Finish options (including dryRun flag)
|
|
2564
|
+
* @param prNumber - Optional PR number - when provided, summary is posted to the PR instead of the issue
|
|
2723
2565
|
*/
|
|
2724
|
-
async generateSessionSummaryIfConfigured(parsed, worktree, options) {
|
|
2566
|
+
async generateSessionSummaryIfConfigured(parsed, worktree, options, prNumber) {
|
|
2725
2567
|
if (parsed.type === "branch") {
|
|
2726
2568
|
return;
|
|
2727
2569
|
}
|
|
@@ -2752,7 +2594,8 @@ var FinishCommand = class {
|
|
|
2752
2594
|
worktreePath: worktree.path,
|
|
2753
2595
|
issueNumber: parsed.number ?? 0,
|
|
2754
2596
|
branchName: worktree.branch,
|
|
2755
|
-
loomType: parsed.type
|
|
2597
|
+
loomType: parsed.type,
|
|
2598
|
+
...prNumber !== void 0 && { prNumber }
|
|
2756
2599
|
});
|
|
2757
2600
|
}
|
|
2758
2601
|
/**
|
|
@@ -2992,7 +2835,9 @@ function formatLoomForJson(worktree, mainWorktreePath, metadata) {
|
|
|
2992
2835
|
created_at: (metadata == null ? void 0 : metadata.created_at) ?? null,
|
|
2993
2836
|
issueTracker: (metadata == null ? void 0 : metadata.issueTracker) ?? null,
|
|
2994
2837
|
colorHex: (metadata == null ? void 0 : metadata.colorHex) ?? null,
|
|
2995
|
-
projectPath: (metadata == null ? void 0 : metadata.projectPath) ?? null
|
|
2838
|
+
projectPath: (metadata == null ? void 0 : metadata.projectPath) ?? null,
|
|
2839
|
+
issueUrls: (metadata == null ? void 0 : metadata.issueUrls) ?? {},
|
|
2840
|
+
prUrls: (metadata == null ? void 0 : metadata.prUrls) ?? {}
|
|
2996
2841
|
};
|
|
2997
2842
|
}
|
|
2998
2843
|
function formatLoomsForJson(worktrees, mainWorktreePath, metadata) {
|
|
@@ -3006,7 +2851,7 @@ function parseIssueIdentifier(value) {
|
|
|
3006
2851
|
const parsed = parseInt(value, 10);
|
|
3007
2852
|
return !isNaN(parsed) && String(parsed) === value ? parsed : value;
|
|
3008
2853
|
}
|
|
3009
|
-
program.name("iloom").description(packageJson.description).version(packageJson.version).option("--debug", "Enable debug output (default: based on ILOOM_DEBUG env var)").option("--completion", "Output shell completion script for current shell").option("--set <key=value>", "Override any setting using dot notation (repeatable, e.g., --set workflows.issue.startIde=false)").allowUnknownOption().hook("preAction", async (thisCommand) => {
|
|
2854
|
+
program.name("iloom").description(packageJson.description).version(packageJson.version).option("--debug", "Enable debug output (default: based on ILOOM_DEBUG env var)").option("--completion", "Output shell completion script for current shell").option("--set <key=value>", "Override any setting using dot notation (repeatable, e.g., --set workflows.issue.startIde=false)").allowUnknownOption().hook("preAction", async (thisCommand, actionCommand) => {
|
|
3010
2855
|
const options = thisCommand.opts();
|
|
3011
2856
|
const envDebug = process.env.ILOOM_DEBUG === "true";
|
|
3012
2857
|
const debugEnabled = options.debug !== void 0 ? options.debug : envDebug;
|
|
@@ -3030,16 +2875,18 @@ program.name("iloom").description(packageJson.description).version(packageJson.v
|
|
|
3030
2875
|
} catch (error) {
|
|
3031
2876
|
logger.debug(`Settings migration failed: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
3032
2877
|
}
|
|
3033
|
-
await validateSettingsForCommand(
|
|
3034
|
-
await validateGhCliForCommand(
|
|
2878
|
+
await validateSettingsForCommand(actionCommand);
|
|
2879
|
+
await validateGhCliForCommand(actionCommand);
|
|
2880
|
+
await validateIdeForStartCommand(thisCommand);
|
|
3035
2881
|
});
|
|
3036
2882
|
async function validateSettingsForCommand(command) {
|
|
3037
2883
|
var _a, _b;
|
|
3038
|
-
const commandName = command.
|
|
2884
|
+
const commandName = command.name();
|
|
3039
2885
|
const bypassCommands = ["help", "init", "update", "contribute"];
|
|
3040
2886
|
if (bypassCommands.includes(commandName)) {
|
|
3041
2887
|
return;
|
|
3042
2888
|
}
|
|
2889
|
+
const warnOnlyCommands = ["list", "projects"];
|
|
3043
2890
|
try {
|
|
3044
2891
|
const settingsManager = new SettingsManager();
|
|
3045
2892
|
const settings = await settingsManager.loadSettings();
|
|
@@ -3049,6 +2896,10 @@ async function validateSettingsForCommand(command) {
|
|
|
3049
2896
|
return;
|
|
3050
2897
|
}
|
|
3051
2898
|
} catch (error) {
|
|
2899
|
+
if (warnOnlyCommands.includes(commandName)) {
|
|
2900
|
+
logger.warn(`Configuration warning: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
2901
|
+
return;
|
|
2902
|
+
}
|
|
3052
2903
|
logger.error(`Configuration error: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3053
2904
|
logger.info("Please fix your .iloom/settings.json file and try again.");
|
|
3054
2905
|
process.exit(1);
|
|
@@ -3056,7 +2907,7 @@ async function validateSettingsForCommand(command) {
|
|
|
3056
2907
|
}
|
|
3057
2908
|
async function validateGhCliForCommand(command) {
|
|
3058
2909
|
var _a, _b;
|
|
3059
|
-
const commandName = command.
|
|
2910
|
+
const commandName = command.name();
|
|
3060
2911
|
const alwaysRequireGh = ["feedback", "contribute"];
|
|
3061
2912
|
const conditionallyRequireGh = ["start", "finish", "enhance", "add-issue", "ignite", "spin"];
|
|
3062
2913
|
const warnOnly = ["init", "list", "rebase", "cleanup", "run", "update", "open"];
|
|
@@ -3107,6 +2958,41 @@ async function validateGhCliForCommand(command) {
|
|
|
3107
2958
|
}
|
|
3108
2959
|
}
|
|
3109
2960
|
}
|
|
2961
|
+
async function validateIdeForStartCommand(command) {
|
|
2962
|
+
var _a, _b;
|
|
2963
|
+
const commandName = command.args[0] ?? "";
|
|
2964
|
+
if (commandName !== "start") {
|
|
2965
|
+
return;
|
|
2966
|
+
}
|
|
2967
|
+
const codeOption = command.opts()["code"];
|
|
2968
|
+
if (codeOption === false) {
|
|
2969
|
+
return;
|
|
2970
|
+
}
|
|
2971
|
+
const settingsManager = new SettingsManager();
|
|
2972
|
+
let settings;
|
|
2973
|
+
try {
|
|
2974
|
+
settings = await settingsManager.loadSettings();
|
|
2975
|
+
} catch {
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2978
|
+
const workflowConfig = (_a = settings.workflows) == null ? void 0 : _a.issue;
|
|
2979
|
+
if ((workflowConfig == null ? void 0 : workflowConfig.startIde) === false && codeOption !== true) {
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2982
|
+
const ideConfig = getIdeConfig(settings.ide);
|
|
2983
|
+
const available = await isIdeAvailable(ideConfig.command);
|
|
2984
|
+
if (!available) {
|
|
2985
|
+
const hint = getInstallHint(((_b = settings.ide) == null ? void 0 : _b.type) ?? "vscode");
|
|
2986
|
+
logger.error(
|
|
2987
|
+
`${ideConfig.name} is configured as your IDE but "${ideConfig.command}" command was not found.`
|
|
2988
|
+
);
|
|
2989
|
+
logger.info("");
|
|
2990
|
+
logger.info(hint);
|
|
2991
|
+
logger.info("");
|
|
2992
|
+
logger.info("Alternatively, use --no-code to skip IDE launch or configure a different IDE in settings.");
|
|
2993
|
+
process.exit(1);
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
3110
2996
|
async function autoLaunchInitForMultipleRemotes() {
|
|
3111
2997
|
var _a, _b;
|
|
3112
2998
|
logger.info("Multiple git remotes detected, but no GitHub remote is configured.");
|
|
@@ -3118,14 +3004,14 @@ async function autoLaunchInitForMultipleRemotes() {
|
|
|
3118
3004
|
await waitForKeypress2("Press any key to start configuration...");
|
|
3119
3005
|
logger.info("");
|
|
3120
3006
|
try {
|
|
3121
|
-
const { InitCommand: InitCommand2 } = await import("./init-
|
|
3007
|
+
const { InitCommand: InitCommand2 } = await import("./init-F6PFMSU5.js");
|
|
3122
3008
|
const initCommand = new InitCommand2();
|
|
3123
3009
|
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.";
|
|
3124
3010
|
await initCommand.execute(customInitialMessage);
|
|
3125
3011
|
logger.info("");
|
|
3126
3012
|
logger.info("Configuration complete! Continuing with your original command...");
|
|
3127
3013
|
logger.info("");
|
|
3128
|
-
const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-
|
|
3014
|
+
const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-XPR4TEQL.js");
|
|
3129
3015
|
const settingsManager = new SettingsManager2();
|
|
3130
3016
|
const settings = await settingsManager.loadSettings();
|
|
3131
3017
|
const { hasMultipleRemotes: hasMultipleRemotes2 } = await import("./remote-73TZ2ADI.js");
|
|
@@ -3183,7 +3069,7 @@ program.command("start").alias("new").alias("create").alias("up").description("C
|
|
|
3183
3069
|
await executeAction();
|
|
3184
3070
|
}
|
|
3185
3071
|
});
|
|
3186
|
-
program.command("add-issue").alias("a").description("Create and enhance GitHub issue without starting workspace").argument("<description>", "
|
|
3072
|
+
program.command("add-issue").alias("a").description("Create and enhance GitHub issue without starting workspace").argument("<description>", "Issue title (>30 chars, >2 spaces; or any non-empty text when --body provided)").option("--body <text>", "Body text for issue (skips AI enhancement)").option("--json", "Output result as JSON").action(async (description, options) => {
|
|
3187
3073
|
const executeAction = async () => {
|
|
3188
3074
|
try {
|
|
3189
3075
|
const settingsManager = new SettingsManager();
|
|
@@ -3217,9 +3103,9 @@ program.command("add-issue").alias("a").description("Create and enhance GitHub i
|
|
|
3217
3103
|
await executeAction();
|
|
3218
3104
|
}
|
|
3219
3105
|
});
|
|
3220
|
-
program.command("feedback").alias("f").description("Submit feedback/bug report to iloom-cli repository").argument("<description>", "
|
|
3106
|
+
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) => {
|
|
3221
3107
|
try {
|
|
3222
|
-
const { FeedbackCommand } = await import("./feedback-
|
|
3108
|
+
const { FeedbackCommand } = await import("./feedback-OFVW22UW.js");
|
|
3223
3109
|
const command = new FeedbackCommand();
|
|
3224
3110
|
const feedbackOptions = {};
|
|
3225
3111
|
if (options.body !== void 0) {
|
|
@@ -3299,7 +3185,7 @@ program.command("finish").alias("dn").description("Merge work and cleanup worksp
|
|
|
3299
3185
|
});
|
|
3300
3186
|
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) => {
|
|
3301
3187
|
try {
|
|
3302
|
-
const { RebaseCommand } = await import("./rebase-
|
|
3188
|
+
const { RebaseCommand } = await import("./rebase-WZHHE5LU.js");
|
|
3303
3189
|
const command = new RebaseCommand();
|
|
3304
3190
|
await command.execute(options);
|
|
3305
3191
|
} catch (error) {
|
|
@@ -3311,7 +3197,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
|
|
|
3311
3197
|
new Option("--one-shot <mode>", "One-shot automation mode").choices(["default", "noReview", "bypassPermissions"]).default("default")
|
|
3312
3198
|
).action(async (options) => {
|
|
3313
3199
|
try {
|
|
3314
|
-
const { IgniteCommand } = await import("./ignite-
|
|
3200
|
+
const { IgniteCommand } = await import("./ignite-NREQ3JRM.js");
|
|
3315
3201
|
const command = new IgniteCommand();
|
|
3316
3202
|
await command.execute(options.oneShot ?? "default");
|
|
3317
3203
|
} catch (error) {
|
|
@@ -3322,7 +3208,7 @@ program.command("spin").alias("ignite").description("Launch Claude with auto-det
|
|
|
3322
3208
|
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) => {
|
|
3323
3209
|
try {
|
|
3324
3210
|
const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
|
|
3325
|
-
const { OpenCommand } = await import("./open-
|
|
3211
|
+
const { OpenCommand } = await import("./open-KW4NTLXH.js");
|
|
3326
3212
|
const cmd = new OpenCommand();
|
|
3327
3213
|
const input = identifier ? { identifier, args } : { args };
|
|
3328
3214
|
await cmd.execute(input);
|
|
@@ -3334,7 +3220,7 @@ program.command("open").description("Open workspace in browser or run CLI tool")
|
|
|
3334
3220
|
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) => {
|
|
3335
3221
|
try {
|
|
3336
3222
|
const args = (command == null ? void 0 : command.args) ? command.args.slice(identifier ? 1 : 0) : [];
|
|
3337
|
-
const { RunCommand } = await import("./run-
|
|
3223
|
+
const { RunCommand } = await import("./run-HRYQ7TR7.js");
|
|
3338
3224
|
const cmd = new RunCommand();
|
|
3339
3225
|
const input = identifier ? { identifier, args } : { args };
|
|
3340
3226
|
await cmd.execute(input);
|
|
@@ -3345,7 +3231,7 @@ program.command("run").description("Run CLI tool or open workspace in browser").
|
|
|
3345
3231
|
});
|
|
3346
3232
|
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) => {
|
|
3347
3233
|
try {
|
|
3348
|
-
const { DevServerCommand } = await import("./dev-server-
|
|
3234
|
+
const { DevServerCommand } = await import("./dev-server-ASH7HJVI.js");
|
|
3349
3235
|
const cmd = new DevServerCommand();
|
|
3350
3236
|
await cmd.execute({ identifier, json: options == null ? void 0 : options.json });
|
|
3351
3237
|
} catch (error) {
|
|
@@ -3355,7 +3241,7 @@ program.command("dev-server").alias("dev").description("Start dev server for wor
|
|
|
3355
3241
|
});
|
|
3356
3242
|
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) => {
|
|
3357
3243
|
try {
|
|
3358
|
-
const { ShellCommand } = await import("./shell-
|
|
3244
|
+
const { ShellCommand } = await import("./shell-JMU5XTHW.js");
|
|
3359
3245
|
const cmd = new ShellCommand();
|
|
3360
3246
|
await cmd.execute({ identifier });
|
|
3361
3247
|
} catch (error) {
|
|
@@ -3366,7 +3252,7 @@ program.command("shell").alias("terminal").description("Open interactive shell w
|
|
|
3366
3252
|
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) => {
|
|
3367
3253
|
const executeAction = async () => {
|
|
3368
3254
|
try {
|
|
3369
|
-
const { CleanupCommand } = await import("./cleanup-
|
|
3255
|
+
const { CleanupCommand } = await import("./cleanup-LU6NU2NZ.js");
|
|
3370
3256
|
const command = new CleanupCommand();
|
|
3371
3257
|
const input = {
|
|
3372
3258
|
options: options ?? {}
|
|
@@ -3406,7 +3292,11 @@ program.command("list").description("Show active workspaces").option("--json", "
|
|
|
3406
3292
|
metadata.set(worktree.path, loomMetadata);
|
|
3407
3293
|
}
|
|
3408
3294
|
if (options.json) {
|
|
3409
|
-
|
|
3295
|
+
let mainWorktreePath;
|
|
3296
|
+
try {
|
|
3297
|
+
mainWorktreePath = await findMainWorktreePathWithSettings();
|
|
3298
|
+
} catch {
|
|
3299
|
+
}
|
|
3410
3300
|
console.log(JSON.stringify(formatLoomsForJson(worktrees, mainWorktreePath, metadata), null, 2));
|
|
3411
3301
|
return;
|
|
3412
3302
|
}
|
|
@@ -3440,7 +3330,7 @@ program.command("list").description("Show active workspaces").option("--json", "
|
|
|
3440
3330
|
});
|
|
3441
3331
|
program.command("projects").description("List configured iloom projects").option("--json", "Output as JSON (default behavior)").action(async (options) => {
|
|
3442
3332
|
try {
|
|
3443
|
-
const { ProjectsCommand } = await import("./projects-
|
|
3333
|
+
const { ProjectsCommand } = await import("./projects-QEAEBAT2.js");
|
|
3444
3334
|
const command = new ProjectsCommand();
|
|
3445
3335
|
const result = await command.execute(options);
|
|
3446
3336
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -3449,9 +3339,9 @@ program.command("projects").description("List configured iloom projects").option
|
|
|
3449
3339
|
process.exit(1);
|
|
3450
3340
|
}
|
|
3451
3341
|
});
|
|
3452
|
-
program.command("init").alias("config").description("Initialize iloom configuration
|
|
3342
|
+
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) => {
|
|
3453
3343
|
try {
|
|
3454
|
-
const { InitCommand: InitCommand2 } = await import("./init-
|
|
3344
|
+
const { InitCommand: InitCommand2 } = await import("./init-F6PFMSU5.js");
|
|
3455
3345
|
const command = new InitCommand2();
|
|
3456
3346
|
const trimmedPrompt = prompt == null ? void 0 : prompt.trim();
|
|
3457
3347
|
const customPrompt = trimmedPrompt && trimmedPrompt.length > 0 ? trimmedPrompt : void 0;
|
|
@@ -3463,7 +3353,7 @@ program.command("init").alias("config").description("Initialize iloom configurat
|
|
|
3463
3353
|
});
|
|
3464
3354
|
program.command("contribute").description("Set up local development environment for contributing to iloom").action(async () => {
|
|
3465
3355
|
try {
|
|
3466
|
-
const { ContributeCommand } = await import("./contribute-
|
|
3356
|
+
const { ContributeCommand } = await import("./contribute-RS3DO3WP.js");
|
|
3467
3357
|
const command = new ContributeCommand();
|
|
3468
3358
|
await command.execute();
|
|
3469
3359
|
} catch (error) {
|
|
@@ -3543,9 +3433,9 @@ program.command("test-github").description("Test GitHub integration (Issue #3)")
|
|
|
3543
3433
|
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) => {
|
|
3544
3434
|
try {
|
|
3545
3435
|
const { detectClaudeCli: detectClaudeCli2, getClaudeVersion, generateBranchName, launchClaude: launchClaude2 } = await import("./claude-ACVXNB6N.js");
|
|
3546
|
-
const { PromptTemplateManager } = await import("./PromptTemplateManager-
|
|
3547
|
-
const { ClaudeService } = await import("./ClaudeService-
|
|
3548
|
-
const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-
|
|
3436
|
+
const { PromptTemplateManager } = await import("./PromptTemplateManager-72FEOGT6.js");
|
|
3437
|
+
const { ClaudeService } = await import("./ClaudeService-CJS32WG2.js");
|
|
3438
|
+
const { ClaudeContextManager: ClaudeContextManager2 } = await import("./ClaudeContextManager-DQFKIMEP.js");
|
|
3549
3439
|
logger.info("Testing Claude Integration\n");
|
|
3550
3440
|
if (options.detect) {
|
|
3551
3441
|
logger.info("Detecting Claude CLI...");
|
|
@@ -3693,7 +3583,7 @@ program.command("test-webserver").description("Test if a web server is running o
|
|
|
3693
3583
|
});
|
|
3694
3584
|
program.command("test-git").description("Test Git integration - findMainWorktreePath() function (reads .iloom/settings.json)").action(async () => {
|
|
3695
3585
|
try {
|
|
3696
|
-
const { TestGitCommand } = await import("./test-git-
|
|
3586
|
+
const { TestGitCommand } = await import("./test-git-6SAIRBUD.js");
|
|
3697
3587
|
const command = new TestGitCommand();
|
|
3698
3588
|
await command.execute();
|
|
3699
3589
|
} catch (error) {
|
|
@@ -3719,7 +3609,7 @@ program.command("test-tabs").description("Test iTerm2 dual tab functionality - o
|
|
|
3719
3609
|
});
|
|
3720
3610
|
program.command("test-prefix").description("Test worktree prefix configuration - preview worktree paths (reads .iloom/settings.json)").action(async () => {
|
|
3721
3611
|
try {
|
|
3722
|
-
const { TestPrefixCommand } = await import("./test-prefix-
|
|
3612
|
+
const { TestPrefixCommand } = await import("./test-prefix-RLVRK5ZD.js");
|
|
3723
3613
|
const command = new TestPrefixCommand();
|
|
3724
3614
|
await command.execute();
|
|
3725
3615
|
} catch (error) {
|
|
@@ -3733,7 +3623,7 @@ program.command("test-prefix").description("Test worktree prefix configuration -
|
|
|
3733
3623
|
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) => {
|
|
3734
3624
|
const executeAction = async () => {
|
|
3735
3625
|
try {
|
|
3736
|
-
const { SummaryCommand } = await import("./summary-
|
|
3626
|
+
const { SummaryCommand } = await import("./summary-4SSGGH7N.js");
|
|
3737
3627
|
const command = new SummaryCommand();
|
|
3738
3628
|
const result = await command.execute({ identifier, options });
|
|
3739
3629
|
if (options.json && result) {
|
|
@@ -3759,10 +3649,39 @@ program.command("summary").description("Generate Claude session summary for a lo
|
|
|
3759
3649
|
await executeAction();
|
|
3760
3650
|
}
|
|
3761
3651
|
});
|
|
3652
|
+
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) => {
|
|
3653
|
+
const executeAction = async () => {
|
|
3654
|
+
try {
|
|
3655
|
+
const { RecapCommand } = await import("./recap-33NPZ3ZO.js");
|
|
3656
|
+
const command = new RecapCommand();
|
|
3657
|
+
const result = await command.execute({ identifier, json: options.json });
|
|
3658
|
+
if (options.json && result) {
|
|
3659
|
+
console.log(JSON.stringify(result, null, 2));
|
|
3660
|
+
}
|
|
3661
|
+
process.exit(0);
|
|
3662
|
+
} catch (error) {
|
|
3663
|
+
if (options.json) {
|
|
3664
|
+
console.log(JSON.stringify({ error: error instanceof Error ? error.message : "Unknown error" }, null, 2));
|
|
3665
|
+
} else {
|
|
3666
|
+
logger.error(`Recap failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3667
|
+
if (error instanceof Error && error.stack) {
|
|
3668
|
+
logger.debug(error.stack);
|
|
3669
|
+
}
|
|
3670
|
+
}
|
|
3671
|
+
process.exit(1);
|
|
3672
|
+
}
|
|
3673
|
+
};
|
|
3674
|
+
if (options.json) {
|
|
3675
|
+
const jsonLogger = createStderrLogger();
|
|
3676
|
+
await withLogger(jsonLogger, executeAction);
|
|
3677
|
+
} else {
|
|
3678
|
+
await executeAction();
|
|
3679
|
+
}
|
|
3680
|
+
});
|
|
3762
3681
|
program.command("test-neon").description("Test Neon integration and debug configuration").action(async () => {
|
|
3763
3682
|
var _a;
|
|
3764
3683
|
try {
|
|
3765
|
-
const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-
|
|
3684
|
+
const { SettingsManager: SettingsManager2 } = await import("./SettingsManager-XPR4TEQL.js");
|
|
3766
3685
|
const { createNeonProviderFromSettings: createNeonProviderFromSettings2 } = await import("./neon-helpers-L5CXQ5CT.js");
|
|
3767
3686
|
logger.info("Testing Neon Integration\n");
|
|
3768
3687
|
logger.info("1. Settings Configuration:");
|
|
@@ -3861,6 +3780,7 @@ if (isRunDirectly) {
|
|
|
3861
3780
|
}
|
|
3862
3781
|
}
|
|
3863
3782
|
export {
|
|
3864
|
-
validateGhCliForCommand
|
|
3783
|
+
validateGhCliForCommand,
|
|
3784
|
+
validateIdeForStartCommand
|
|
3865
3785
|
};
|
|
3866
3786
|
//# sourceMappingURL=cli.js.map
|