@iloom/cli 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +50 -4
- package/dist/{BranchNamingService-AO7BPIUJ.js → BranchNamingService-K6XNWQ6C.js} +2 -2
- package/dist/ClaudeContextManager-X2Y72GRL.js +14 -0
- package/dist/ClaudeService-7P32TTES.js +13 -0
- package/dist/{LoomLauncher-NHZMEVTQ.js → LoomLauncher-3I47SUPV.js} +6 -6
- package/dist/{ProjectCapabilityDetector-IA56AUE6.js → ProjectCapabilityDetector-N5L7T4IY.js} +3 -3
- package/dist/PromptTemplateManager-36YLQRHP.js +11 -0
- package/dist/README.md +50 -4
- package/dist/{SettingsManager-VCVLL32H.js → SettingsManager-QR7V2IW2.js} +2 -2
- package/dist/agents/iloom-artifact-reviewer.md +280 -0
- package/dist/agents/iloom-code-reviewer.md +9 -7
- package/dist/agents/iloom-issue-analyze-and-plan.md +21 -6
- package/dist/agents/iloom-issue-analyzer.md +21 -6
- package/dist/agents/iloom-issue-complexity-evaluator.md +21 -6
- package/dist/agents/iloom-issue-enhancer.md +21 -6
- package/dist/agents/iloom-issue-implementer.md +21 -6
- package/dist/agents/iloom-issue-planner.md +21 -6
- package/dist/{build-Z3WCIKPD.js → build-IC4CJRMP.js} +8 -8
- package/dist/{chunk-TVH67KEO.js → chunk-2HZX6AMR.js} +2 -2
- package/dist/{chunk-VZYSM7N7.js → chunk-2JPXGGP4.js} +20 -15
- package/dist/chunk-2JPXGGP4.js.map +1 -0
- package/dist/{chunk-HSGZW3ID.js → chunk-4GAJJUYS.js} +3 -3
- package/dist/chunk-4GAJJUYS.js.map +1 -0
- package/dist/{chunk-RD7I2Q2F.js → chunk-4LKGCFGG.js} +2 -2
- package/dist/{chunk-SSASIBDJ.js → chunk-5LVVQGB3.js} +5 -5
- package/dist/{chunk-GWONJE3X.js → chunk-6Y3FTRJL.js} +189 -48
- package/dist/chunk-6Y3FTRJL.js.map +1 -0
- package/dist/{chunk-4BSXZ5YZ.js → chunk-B7U6OKUR.js} +5 -24
- package/dist/chunk-B7U6OKUR.js.map +1 -0
- package/dist/{chunk-IGKPPACU.js → chunk-FO5GGFOV.js} +17 -8
- package/dist/chunk-FO5GGFOV.js.map +1 -0
- package/dist/{chunk-GDS2HXSW.js → chunk-H6ST2TGP.js} +20 -3
- package/dist/chunk-H6ST2TGP.js.map +1 -0
- package/dist/{chunk-A7XHHUEV.js → chunk-HZXBHMVM.js} +47 -22
- package/dist/chunk-HZXBHMVM.js.map +1 -0
- package/dist/{chunk-44Y5IF7P.js → chunk-I23OQB4Y.js} +5 -5
- package/dist/chunk-JT5LZRMI.js +302 -0
- package/dist/chunk-JT5LZRMI.js.map +1 -0
- package/dist/{chunk-Q457PKGH.js → chunk-KAYXR544.js} +2 -2
- package/dist/{chunk-XU5A6BWA.js → chunk-MZPRBNYC.js} +4 -4
- package/dist/{chunk-XHNACIHO.js → chunk-NTTSUAVM.js} +2 -2
- package/dist/{chunk-PLI3JQWT.js → chunk-OAVJR4PM.js} +2 -2
- package/dist/{chunk-4KGRPHM6.js → chunk-PL2FDYEK.js} +2 -2
- package/dist/chunk-QN47QVBX.js +131 -0
- package/dist/chunk-QN47QVBX.js.map +1 -0
- package/dist/{chunk-3FC3VNEX.js → chunk-RD7OPXZK.js} +34 -8
- package/dist/chunk-RD7OPXZK.js.map +1 -0
- package/dist/{chunk-O6LECMT6.js → chunk-TGRK3CHF.js} +8 -8
- package/dist/{chunk-7GLZVDPQ.js → chunk-TL72BGP6.js} +2 -2
- package/dist/{chunk-52MVUK5V.js → chunk-USSL2X4A.js} +2 -2
- package/dist/chunk-USSL2X4A.js.map +1 -0
- package/dist/{chunk-XPKN3QWY.js → chunk-VOGGLPG5.js} +1 -2
- package/dist/{chunk-IWIIOFEB.js → chunk-XFEK2X2D.js} +16 -6
- package/dist/chunk-XFEK2X2D.js.map +1 -0
- package/dist/{chunk-PBSHQVCT.js → chunk-Z6F5CUS6.js} +4 -4
- package/dist/{claude-V4HRPR4Z.js → claude-TP2QO3BU.js} +2 -2
- package/dist/{cleanup-NWNKWPUY.js → cleanup-M6N7KV7E.js} +20 -15
- package/dist/{cleanup-NWNKWPUY.js.map → cleanup-M6N7KV7E.js.map} +1 -1
- package/dist/cli.js +118 -84
- package/dist/cli.js.map +1 -1
- package/dist/{commit-534QIRHY.js → commit-ORHR53KW.js} +10 -10
- package/dist/{compile-UANHMNTS.js → compile-EOWJORKO.js} +8 -8
- package/dist/{contribute-7USRBWRM.js → contribute-4KCEOHSH.js} +3 -3
- package/dist/{dev-server-TO7RLYJI.js → dev-server-Q6M62ATG.js} +13 -13
- package/dist/{feedback-7ZZI6RC5.js → feedback-XRI7SGYX.js} +11 -11
- package/dist/{git-GUNOPP4Q.js → git-W3XUIFTR.js} +5 -3
- package/dist/hooks/iloom-hook.js +5 -3
- package/dist/{ignite-5SIGOW5V.js → ignite-3FHQY23X.js} +90 -26
- package/dist/ignite-3FHQY23X.js.map +1 -0
- package/dist/index.d.ts +37 -2
- package/dist/index.js +49 -13
- package/dist/index.js.map +1 -1
- package/dist/{chunk-FPNSFP6K.js → init-ALYWKNWG.js} +42 -329
- package/dist/init-ALYWKNWG.js.map +1 -0
- package/dist/{lint-XPODLDVA.js → lint-IHUH45OC.js} +8 -8
- package/dist/{open-M2SUR74Y.js → open-KWOV2OFO.js} +15 -15
- package/dist/{plan-FB4AOJ2Q.js → plan-P6MXL7AU.js} +54 -22
- package/dist/plan-P6MXL7AU.js.map +1 -0
- package/dist/{projects-325GEEGJ.js → projects-LH362JZQ.js} +3 -3
- package/dist/prompts/init-prompt.txt +9 -1
- package/dist/prompts/issue-prompt.txt +315 -5
- package/dist/prompts/plan-prompt.txt +4 -6
- package/dist/prompts/pr-prompt.txt +79 -0
- package/dist/prompts/regular-prompt.txt +210 -5
- package/dist/{rebase-4FNRBW3H.js → rebase-AJOJOZUG.js} +9 -9
- package/dist/{recap-GSXFEOD6.js → recap-GKJXMDXW.js} +5 -5
- package/dist/{run-GZNHRJB2.js → run-QEUVZF7J.js} +15 -15
- package/dist/schema/settings.schema.json +9 -1
- package/dist/{shell-2SPM3Z5O.js → shell-DAAVG4YN.js} +5 -5
- package/dist/{summary-Z4F7YFXE.js → summary-WNEYCO4S.js} +11 -11
- package/dist/{test-LBSPYIJW.js → test-5GPWWO3P.js} +8 -8
- package/dist/{test-git-ZPSPA2TP.js → test-git-EJUKDB7F.js} +3 -3
- package/dist/{test-prefix-6DLB2BHE.js → test-prefix-23TOBUXY.js} +3 -3
- package/dist/{test-webserver-XLJ2TZFP.js → test-webserver-CKROHFBQ.js} +5 -5
- package/dist/{vscode-LH3VSQ2W.js → vscode-6TOLFCI2.js} +5 -5
- package/package.json +2 -2
- package/dist/ClaudeContextManager-RDP6CLK6.js +0 -14
- package/dist/ClaudeService-FKPOQRA4.js +0 -13
- package/dist/PRManager-A63LT3NF.js +0 -16
- package/dist/PromptTemplateManager-OUYDHOPI.js +0 -9
- package/dist/chunk-3FC3VNEX.js.map +0 -1
- package/dist/chunk-4BSXZ5YZ.js.map +0 -1
- package/dist/chunk-52MVUK5V.js.map +0 -1
- package/dist/chunk-66QOCD5N.js +0 -79
- package/dist/chunk-66QOCD5N.js.map +0 -1
- package/dist/chunk-A7XHHUEV.js.map +0 -1
- package/dist/chunk-FPNSFP6K.js.map +0 -1
- package/dist/chunk-GDS2HXSW.js.map +0 -1
- package/dist/chunk-GWONJE3X.js.map +0 -1
- package/dist/chunk-HSGZW3ID.js.map +0 -1
- package/dist/chunk-IGKPPACU.js.map +0 -1
- package/dist/chunk-IWIIOFEB.js.map +0 -1
- package/dist/chunk-VZYSM7N7.js.map +0 -1
- package/dist/git-GUNOPP4Q.js.map +0 -1
- package/dist/ignite-5SIGOW5V.js.map +0 -1
- package/dist/init-XXDIB2UJ.js +0 -21
- package/dist/init-XXDIB2UJ.js.map +0 -1
- package/dist/plan-FB4AOJ2Q.js.map +0 -1
- /package/dist/{BranchNamingService-AO7BPIUJ.js.map → BranchNamingService-K6XNWQ6C.js.map} +0 -0
- /package/dist/{ClaudeContextManager-RDP6CLK6.js.map → ClaudeContextManager-X2Y72GRL.js.map} +0 -0
- /package/dist/{ClaudeService-FKPOQRA4.js.map → ClaudeService-7P32TTES.js.map} +0 -0
- /package/dist/{LoomLauncher-NHZMEVTQ.js.map → LoomLauncher-3I47SUPV.js.map} +0 -0
- /package/dist/{PRManager-A63LT3NF.js.map → ProjectCapabilityDetector-N5L7T4IY.js.map} +0 -0
- /package/dist/{ProjectCapabilityDetector-IA56AUE6.js.map → PromptTemplateManager-36YLQRHP.js.map} +0 -0
- /package/dist/{PromptTemplateManager-OUYDHOPI.js.map → SettingsManager-QR7V2IW2.js.map} +0 -0
- /package/dist/{build-Z3WCIKPD.js.map → build-IC4CJRMP.js.map} +0 -0
- /package/dist/{chunk-TVH67KEO.js.map → chunk-2HZX6AMR.js.map} +0 -0
- /package/dist/{chunk-RD7I2Q2F.js.map → chunk-4LKGCFGG.js.map} +0 -0
- /package/dist/{chunk-SSASIBDJ.js.map → chunk-5LVVQGB3.js.map} +0 -0
- /package/dist/{chunk-44Y5IF7P.js.map → chunk-I23OQB4Y.js.map} +0 -0
- /package/dist/{chunk-Q457PKGH.js.map → chunk-KAYXR544.js.map} +0 -0
- /package/dist/{chunk-XU5A6BWA.js.map → chunk-MZPRBNYC.js.map} +0 -0
- /package/dist/{chunk-XHNACIHO.js.map → chunk-NTTSUAVM.js.map} +0 -0
- /package/dist/{chunk-PLI3JQWT.js.map → chunk-OAVJR4PM.js.map} +0 -0
- /package/dist/{chunk-4KGRPHM6.js.map → chunk-PL2FDYEK.js.map} +0 -0
- /package/dist/{chunk-O6LECMT6.js.map → chunk-TGRK3CHF.js.map} +0 -0
- /package/dist/{chunk-7GLZVDPQ.js.map → chunk-TL72BGP6.js.map} +0 -0
- /package/dist/{chunk-XPKN3QWY.js.map → chunk-VOGGLPG5.js.map} +0 -0
- /package/dist/{chunk-PBSHQVCT.js.map → chunk-Z6F5CUS6.js.map} +0 -0
- /package/dist/{SettingsManager-VCVLL32H.js.map → claude-TP2QO3BU.js.map} +0 -0
- /package/dist/{commit-534QIRHY.js.map → commit-ORHR53KW.js.map} +0 -0
- /package/dist/{compile-UANHMNTS.js.map → compile-EOWJORKO.js.map} +0 -0
- /package/dist/{contribute-7USRBWRM.js.map → contribute-4KCEOHSH.js.map} +0 -0
- /package/dist/{dev-server-TO7RLYJI.js.map → dev-server-Q6M62ATG.js.map} +0 -0
- /package/dist/{feedback-7ZZI6RC5.js.map → feedback-XRI7SGYX.js.map} +0 -0
- /package/dist/{claude-V4HRPR4Z.js.map → git-W3XUIFTR.js.map} +0 -0
- /package/dist/{lint-XPODLDVA.js.map → lint-IHUH45OC.js.map} +0 -0
- /package/dist/{open-M2SUR74Y.js.map → open-KWOV2OFO.js.map} +0 -0
- /package/dist/{projects-325GEEGJ.js.map → projects-LH362JZQ.js.map} +0 -0
- /package/dist/{rebase-4FNRBW3H.js.map → rebase-AJOJOZUG.js.map} +0 -0
- /package/dist/{recap-GSXFEOD6.js.map → recap-GKJXMDXW.js.map} +0 -0
- /package/dist/{run-GZNHRJB2.js.map → run-QEUVZF7J.js.map} +0 -0
- /package/dist/{shell-2SPM3Z5O.js.map → shell-DAAVG4YN.js.map} +0 -0
- /package/dist/{summary-Z4F7YFXE.js.map → summary-WNEYCO4S.js.map} +0 -0
- /package/dist/{test-LBSPYIJW.js.map → test-5GPWWO3P.js.map} +0 -0
- /package/dist/{test-git-ZPSPA2TP.js.map → test-git-EJUKDB7F.js.map} +0 -0
- /package/dist/{test-prefix-6DLB2BHE.js.map → test-prefix-23TOBUXY.js.map} +0 -0
- /package/dist/{test-webserver-XLJ2TZFP.js.map → test-webserver-CKROHFBQ.js.map} +0 -0
- /package/dist/{vscode-LH3VSQ2W.js.map → vscode-6TOLFCI2.js.map} +0 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
GitWorktreeManager
|
|
4
|
+
} from "./chunk-4GAJJUYS.js";
|
|
5
|
+
import {
|
|
6
|
+
logger
|
|
7
|
+
} from "./chunk-VT4PDUYT.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/ShellCompletion.ts
|
|
10
|
+
import omelette from "omelette";
|
|
11
|
+
import { readFile } from "fs/promises";
|
|
12
|
+
import { existsSync } from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
import os from "os";
|
|
15
|
+
var ShellCompletion = class {
|
|
16
|
+
constructor(commandName) {
|
|
17
|
+
// omelette instance - no types available
|
|
18
|
+
this.COMPLETION_TIMEOUT = 1e3;
|
|
19
|
+
this.commandName = commandName ?? this.detectCommandName();
|
|
20
|
+
this.completion = omelette("iloom|il <command> <arg>");
|
|
21
|
+
this.setupHandlers();
|
|
22
|
+
}
|
|
23
|
+
detectCommandName() {
|
|
24
|
+
const scriptPath = process.argv[1] ?? "il";
|
|
25
|
+
const baseName = scriptPath.split("/").pop() ?? "il";
|
|
26
|
+
return baseName.replace(/\.js$/, "");
|
|
27
|
+
}
|
|
28
|
+
setupHandlers() {
|
|
29
|
+
this.completion.on("command", ({ reply }) => {
|
|
30
|
+
reply([
|
|
31
|
+
"start",
|
|
32
|
+
"finish",
|
|
33
|
+
"spin",
|
|
34
|
+
"ignite",
|
|
35
|
+
"open",
|
|
36
|
+
"run",
|
|
37
|
+
"cleanup",
|
|
38
|
+
"list",
|
|
39
|
+
"init"
|
|
40
|
+
// Intentionally exclude test-* commands from autocomplete
|
|
41
|
+
]);
|
|
42
|
+
});
|
|
43
|
+
this.completion.on("arg", async ({ line, reply }) => {
|
|
44
|
+
if (line.includes("cleanup")) {
|
|
45
|
+
const suggestions = await this.getBranchSuggestionsWithTimeout();
|
|
46
|
+
reply(suggestions);
|
|
47
|
+
} else {
|
|
48
|
+
reply([]);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get branch suggestions with timeout to prevent blocking
|
|
54
|
+
*/
|
|
55
|
+
async getBranchSuggestionsWithTimeout() {
|
|
56
|
+
try {
|
|
57
|
+
return await Promise.race([
|
|
58
|
+
this.getBranchSuggestions(),
|
|
59
|
+
this.timeout(this.COMPLETION_TIMEOUT, [])
|
|
60
|
+
]);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
logger.debug(`Autocomplete branch suggestions failed: ${error}`);
|
|
63
|
+
return [];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async timeout(ms, defaultValue) {
|
|
67
|
+
return new Promise((resolve) => {
|
|
68
|
+
setTimeout(() => resolve(defaultValue), ms);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
async getBranchSuggestions() {
|
|
72
|
+
try {
|
|
73
|
+
const manager = new GitWorktreeManager();
|
|
74
|
+
const worktrees = await manager.listWorktrees({ porcelain: true });
|
|
75
|
+
const repoInfo = await manager.getRepoInfo();
|
|
76
|
+
const repoRoot = repoInfo.root;
|
|
77
|
+
const currentBranch = repoInfo.currentBranch;
|
|
78
|
+
return worktrees.filter((wt) => wt.path !== repoRoot).filter((wt) => wt.branch !== currentBranch).map((wt) => wt.branch);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
logger.debug(`Failed to get branch suggestions: ${error}`);
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Initialize completion - must be called before program.parseAsync()
|
|
86
|
+
*/
|
|
87
|
+
init() {
|
|
88
|
+
this.completion.init();
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Detect user's current shell
|
|
92
|
+
*/
|
|
93
|
+
detectShell() {
|
|
94
|
+
const shell = process.env.SHELL ?? "";
|
|
95
|
+
if (shell.includes("bash")) return "bash";
|
|
96
|
+
if (shell.includes("zsh")) return "zsh";
|
|
97
|
+
if (shell.includes("fish")) return "fish";
|
|
98
|
+
return "unknown";
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get completion script for a specific shell
|
|
102
|
+
*/
|
|
103
|
+
getCompletionScript(shell) {
|
|
104
|
+
switch (shell) {
|
|
105
|
+
case "bash":
|
|
106
|
+
return this.completion.setupShellInitFile("bash");
|
|
107
|
+
case "zsh":
|
|
108
|
+
return this.completion.setupShellInitFile("zsh");
|
|
109
|
+
case "fish":
|
|
110
|
+
return this.completion.setupShellInitFile("fish");
|
|
111
|
+
default:
|
|
112
|
+
throw new Error(`Unsupported shell type: ${shell}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get setup instructions for manual installation
|
|
117
|
+
*/
|
|
118
|
+
getSetupInstructions(shell) {
|
|
119
|
+
const binaryName = this.commandName;
|
|
120
|
+
switch (shell) {
|
|
121
|
+
case "bash":
|
|
122
|
+
return `
|
|
123
|
+
Add the following to your ~/.bashrc or ~/.bash_profile:
|
|
124
|
+
|
|
125
|
+
eval "$(${binaryName} --completion)"
|
|
126
|
+
|
|
127
|
+
Then reload your shell:
|
|
128
|
+
|
|
129
|
+
source ~/.bashrc
|
|
130
|
+
`;
|
|
131
|
+
case "zsh":
|
|
132
|
+
return `
|
|
133
|
+
Add the following to your ~/.zshrc:
|
|
134
|
+
|
|
135
|
+
eval "$(${binaryName} --completion)"
|
|
136
|
+
|
|
137
|
+
Then reload your shell:
|
|
138
|
+
|
|
139
|
+
source ~/.zshrc
|
|
140
|
+
`;
|
|
141
|
+
case "fish":
|
|
142
|
+
return `
|
|
143
|
+
Add the following to your ~/.config/fish/config.fish:
|
|
144
|
+
|
|
145
|
+
${binaryName} --completion | source
|
|
146
|
+
|
|
147
|
+
Then reload your shell:
|
|
148
|
+
|
|
149
|
+
source ~/.config/fish/config.fish
|
|
150
|
+
`;
|
|
151
|
+
default:
|
|
152
|
+
return `
|
|
153
|
+
Shell autocomplete is supported for bash, zsh, and fish.
|
|
154
|
+
Your current shell (${shell}) may not be supported.
|
|
155
|
+
|
|
156
|
+
Please consult your shell's documentation for setting up custom completions.
|
|
157
|
+
`;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Generate completion script and print to stdout
|
|
162
|
+
* Used by: il --completion
|
|
163
|
+
*/
|
|
164
|
+
printCompletionScript(shell) {
|
|
165
|
+
const detectedShell = shell ?? this.detectShell();
|
|
166
|
+
if (detectedShell === "unknown") {
|
|
167
|
+
logger.error("Could not detect shell type. Please specify --shell bash|zsh|fish");
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
const script = this.getCompletionScript(detectedShell);
|
|
172
|
+
console.log(script);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
logger.error(`Failed to generate completion script: ${error}`);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get the shell configuration file path for the given shell type
|
|
180
|
+
*/
|
|
181
|
+
getShellConfigPath(shell) {
|
|
182
|
+
const homeDir = os.homedir();
|
|
183
|
+
switch (shell) {
|
|
184
|
+
case "bash": {
|
|
185
|
+
const bashrcPath = path.join(homeDir, ".bashrc");
|
|
186
|
+
const bashProfilePath = path.join(homeDir, ".bash_profile");
|
|
187
|
+
if (existsSync(bashrcPath)) {
|
|
188
|
+
return bashrcPath;
|
|
189
|
+
} else if (existsSync(bashProfilePath)) {
|
|
190
|
+
return bashProfilePath;
|
|
191
|
+
}
|
|
192
|
+
return bashrcPath;
|
|
193
|
+
}
|
|
194
|
+
case "zsh":
|
|
195
|
+
return path.join(homeDir, ".zshrc");
|
|
196
|
+
case "fish":
|
|
197
|
+
return path.join(homeDir, ".config", "fish", "config.fish");
|
|
198
|
+
default:
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Read the shell configuration file contents
|
|
204
|
+
*/
|
|
205
|
+
async readShellConfig(shell) {
|
|
206
|
+
const configPath = this.getShellConfigPath(shell);
|
|
207
|
+
if (!configPath) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
let content = "";
|
|
212
|
+
if (existsSync(configPath)) {
|
|
213
|
+
content = await readFile(configPath, "utf-8");
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
path: configPath,
|
|
217
|
+
content
|
|
218
|
+
};
|
|
219
|
+
} catch (error) {
|
|
220
|
+
logger.debug(`Failed to read shell config file ${configPath}: ${error}`);
|
|
221
|
+
return {
|
|
222
|
+
path: configPath,
|
|
223
|
+
content: ""
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Grep for completion-related content in shell configuration file
|
|
229
|
+
* Returns only lines containing '--completion' with 2 lines of context before and after
|
|
230
|
+
* Properly handles overlapping matches
|
|
231
|
+
*/
|
|
232
|
+
async grepCompletionConfig(shell) {
|
|
233
|
+
const configPath = this.getShellConfigPath(shell);
|
|
234
|
+
if (!configPath) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
let content = "";
|
|
239
|
+
if (existsSync(configPath)) {
|
|
240
|
+
const fullContent = await readFile(configPath, "utf-8");
|
|
241
|
+
const lines = fullContent.split(/\r?\n/);
|
|
242
|
+
const matchingIndices = [];
|
|
243
|
+
lines.forEach((line, index) => {
|
|
244
|
+
if (line.includes("--completion")) {
|
|
245
|
+
matchingIndices.push(index);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
if (matchingIndices.length === 0) {
|
|
249
|
+
content = "";
|
|
250
|
+
} else {
|
|
251
|
+
const ranges = [];
|
|
252
|
+
matchingIndices.forEach((matchIndex) => {
|
|
253
|
+
const start = Math.max(0, matchIndex - 2);
|
|
254
|
+
const end = Math.min(lines.length - 1, matchIndex + 2);
|
|
255
|
+
ranges.push({ start, end });
|
|
256
|
+
});
|
|
257
|
+
const mergedRanges = this.mergeOverlappingRanges(ranges);
|
|
258
|
+
const resultSections = mergedRanges.map(
|
|
259
|
+
(range) => lines.slice(range.start, range.end + 1).join("\n")
|
|
260
|
+
);
|
|
261
|
+
content = resultSections.join("\n--\n");
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
path: configPath,
|
|
266
|
+
content
|
|
267
|
+
};
|
|
268
|
+
} catch (error) {
|
|
269
|
+
logger.debug(`Failed to grep shell config file ${configPath}: ${error}`);
|
|
270
|
+
return {
|
|
271
|
+
path: configPath,
|
|
272
|
+
content: ""
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Merge overlapping ranges to avoid duplicate lines
|
|
278
|
+
*/
|
|
279
|
+
mergeOverlappingRanges(ranges) {
|
|
280
|
+
if (ranges.length === 0) return [];
|
|
281
|
+
const sorted = [...ranges].sort((a, b) => a.start - b.start);
|
|
282
|
+
const firstRange = sorted[0];
|
|
283
|
+
if (!firstRange) return [];
|
|
284
|
+
const merged = [firstRange];
|
|
285
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
286
|
+
const current = sorted[i];
|
|
287
|
+
const last = merged[merged.length - 1];
|
|
288
|
+
if (!current || !last) continue;
|
|
289
|
+
if (current.start <= last.end + 1) {
|
|
290
|
+
last.end = Math.max(last.end, current.end);
|
|
291
|
+
} else {
|
|
292
|
+
merged.push(current);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return merged;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
export {
|
|
300
|
+
ShellCompletion
|
|
301
|
+
};
|
|
302
|
+
//# sourceMappingURL=chunk-JT5LZRMI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/ShellCompletion.ts"],"sourcesContent":["import omelette from 'omelette'\nimport { GitWorktreeManager } from './GitWorktreeManager.js'\nimport { logger } from '../utils/logger.js'\nimport { readFile } from 'fs/promises'\nimport { existsSync } from 'fs'\nimport path from 'path'\nimport os from 'os'\n\nexport type ShellType = 'bash' | 'zsh' | 'fish' | 'unknown'\n\n/**\n * Manages shell autocomplete functionality for the iloom CLI\n * Uses omelette to provide tab-completion for commands in bash/zsh/fish\n */\nexport class ShellCompletion {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private completion: any // omelette instance - no types available\n private readonly COMPLETION_TIMEOUT = 1000 // ms - prevent blocking\n private readonly commandName: string\n\n constructor(commandName?: string) {\n // Detect command name from process.argv[1] if not provided\n this.commandName = commandName ?? this.detectCommandName()\n\n // Initialize omelette with both command names using pipe syntax\n // This registers completion for both 'iloom' and 'il' aliases\n // Template covers: <commandName> <command> <arg>\n // This allows for two-level completion: command completion + argument completion\n this.completion = omelette('iloom|il <command> <arg>')\n this.setupHandlers()\n }\n\n private detectCommandName(): string {\n // Get the actual command name used to invoke this script\n const scriptPath = process.argv[1] ?? 'il'\n const baseName = scriptPath.split('/').pop() ?? 'il'\n\n // Remove .js extension if present\n return baseName.replace(/\\.js$/, '')\n }\n\n private setupHandlers(): void {\n // Handler for command-level completion\n // When user types: il <TAB>\n this.completion.on('command', ({ reply }: { reply: (suggestions: string[]) => void }) => {\n reply([\n 'start',\n 'finish',\n 'spin',\n 'ignite',\n 'open',\n 'run',\n 'cleanup',\n 'list',\n 'init',\n // Intentionally exclude test-* commands from autocomplete\n ])\n })\n\n // Handler for argument-level completion\n // When user types: il <command> <TAB>\n this.completion.on('arg', async ({ line, reply }: { line: string; reply: (suggestions: string[]) => void }) => {\n // Check if the command is 'cleanup' to provide dynamic branch suggestions\n if (line.includes('cleanup')) {\n // Use timeout to prevent blocking if worktree listing is slow\n const suggestions = await this.getBranchSuggestionsWithTimeout()\n reply(suggestions)\n } else {\n // For other commands, no argument suggestions\n reply([])\n }\n })\n }\n\n /**\n * Get branch suggestions with timeout to prevent blocking\n */\n private async getBranchSuggestionsWithTimeout(): Promise<string[]> {\n try {\n return await Promise.race([\n this.getBranchSuggestions(),\n this.timeout(this.COMPLETION_TIMEOUT, []),\n ])\n } catch (error) {\n logger.debug(`Autocomplete branch suggestions failed: ${error}`)\n return []\n }\n }\n\n private async timeout<T>(ms: number, defaultValue: T): Promise<T> {\n return new Promise((resolve) => {\n // eslint-disable-next-line no-undef\n setTimeout(() => resolve(defaultValue), ms)\n })\n }\n\n async getBranchSuggestions(): Promise<string[]> {\n // Retrieve worktree branches for dynamic completion\n // Used by cleanup command autocomplete\n try {\n const manager = new GitWorktreeManager()\n const worktrees = await manager.listWorktrees({ porcelain: true })\n const repoInfo = await manager.getRepoInfo()\n\n // Filter out:\n // 1. Main worktree (at repo root) - can't be cleaned up\n // 2. Current worktree (where we're working) - shouldn't clean up current location\n const repoRoot = repoInfo.root\n const currentBranch = repoInfo.currentBranch\n\n return worktrees\n .filter((wt) => wt.path !== repoRoot) // Not the main worktree\n .filter((wt) => wt.branch !== currentBranch) // Not current worktree\n .map((wt) => wt.branch)\n } catch (error) {\n // Silently fail - autocomplete should never break the CLI\n logger.debug(`Failed to get branch suggestions: ${error}`)\n return []\n }\n }\n\n /**\n * Initialize completion - must be called before program.parseAsync()\n */\n init(): void {\n this.completion.init()\n }\n\n /**\n * Detect user's current shell\n */\n detectShell(): ShellType {\n const shell = process.env.SHELL ?? ''\n\n if (shell.includes('bash')) return 'bash'\n if (shell.includes('zsh')) return 'zsh'\n if (shell.includes('fish')) return 'fish'\n\n return 'unknown'\n }\n\n /**\n * Get completion script for a specific shell\n */\n getCompletionScript(shell: ShellType): string {\n switch (shell) {\n case 'bash':\n return this.completion.setupShellInitFile('bash')\n case 'zsh':\n return this.completion.setupShellInitFile('zsh')\n case 'fish':\n return this.completion.setupShellInitFile('fish')\n default:\n throw new Error(`Unsupported shell type: ${shell}`)\n }\n }\n\n /**\n * Get setup instructions for manual installation\n */\n getSetupInstructions(shell: ShellType): string {\n const binaryName = this.commandName\n\n switch (shell) {\n case 'bash':\n return `\nAdd the following to your ~/.bashrc or ~/.bash_profile:\n\n eval \"$(${binaryName} --completion)\"\n\nThen reload your shell:\n\n source ~/.bashrc\n`\n case 'zsh':\n return `\nAdd the following to your ~/.zshrc:\n\n eval \"$(${binaryName} --completion)\"\n\nThen reload your shell:\n\n source ~/.zshrc\n`\n case 'fish':\n return `\nAdd the following to your ~/.config/fish/config.fish:\n\n ${binaryName} --completion | source\n\nThen reload your shell:\n\n source ~/.config/fish/config.fish\n`\n default:\n return `\nShell autocomplete is supported for bash, zsh, and fish.\nYour current shell (${shell}) may not be supported.\n\nPlease consult your shell's documentation for setting up custom completions.\n`\n }\n }\n\n /**\n * Generate completion script and print to stdout\n * Used by: il --completion\n */\n printCompletionScript(shell?: ShellType): void {\n const detectedShell = shell ?? this.detectShell()\n\n if (detectedShell === 'unknown') {\n logger.error('Could not detect shell type. Please specify --shell bash|zsh|fish')\n process.exit(1)\n }\n\n try {\n const script = this.getCompletionScript(detectedShell)\n // eslint-disable-next-line no-console\n console.log(script)\n } catch (error) {\n logger.error(`Failed to generate completion script: ${error}`)\n process.exit(1)\n }\n }\n\n /**\n * Get the shell configuration file path for the given shell type\n */\n getShellConfigPath(shell: ShellType): string | null {\n const homeDir = os.homedir()\n\n switch (shell) {\n case 'bash': {\n // Prefer .bashrc, fall back to .bash_profile\n const bashrcPath = path.join(homeDir, '.bashrc')\n const bashProfilePath = path.join(homeDir, '.bash_profile')\n\n if (existsSync(bashrcPath)) {\n return bashrcPath\n } else if (existsSync(bashProfilePath)) {\n return bashProfilePath\n }\n // Return .bashrc path even if it doesn't exist (for creation)\n return bashrcPath\n }\n\n case 'zsh':\n return path.join(homeDir, '.zshrc')\n\n case 'fish':\n return path.join(homeDir, '.config', 'fish', 'config.fish')\n\n default:\n return null\n }\n }\n\n /**\n * Read the shell configuration file contents\n */\n async readShellConfig(shell: ShellType): Promise<{ path: string; content: string } | null> {\n const configPath = this.getShellConfigPath(shell)\n\n if (!configPath) {\n return null\n }\n\n try {\n let content = ''\n if (existsSync(configPath)) {\n content = await readFile(configPath, 'utf-8')\n }\n // Return the path and content (empty string if file doesn't exist)\n return {\n path: configPath,\n content\n }\n } catch (error) {\n logger.debug(`Failed to read shell config file ${configPath}: ${error}`)\n return {\n path: configPath,\n content: ''\n }\n }\n }\n\n /**\n * Grep for completion-related content in shell configuration file\n * Returns only lines containing '--completion' with 2 lines of context before and after\n * Properly handles overlapping matches\n */\n async grepCompletionConfig(shell: ShellType): Promise<{ path: string; content: string } | null> {\n const configPath = this.getShellConfigPath(shell)\n\n if (!configPath) {\n return null\n }\n\n try {\n let content = ''\n if (existsSync(configPath)) {\n const fullContent = await readFile(configPath, 'utf-8')\n const lines = fullContent.split(/\\r?\\n/)\n\n // Find all matching line indices\n const matchingIndices: number[] = []\n lines.forEach((line, index) => {\n if (line.includes('--completion')) {\n matchingIndices.push(index)\n }\n })\n\n if (matchingIndices.length === 0) {\n content = ''\n } else {\n // Create ranges with context, handling overlaps\n const ranges: { start: number; end: number }[] = []\n\n matchingIndices.forEach(matchIndex => {\n const start = Math.max(0, matchIndex - 2)\n const end = Math.min(lines.length - 1, matchIndex + 2)\n ranges.push({ start, end })\n })\n\n // Merge overlapping ranges\n const mergedRanges = this.mergeOverlappingRanges(ranges)\n\n // Extract lines for each merged range\n const resultSections = mergedRanges.map(range =>\n lines.slice(range.start, range.end + 1).join('\\n')\n )\n\n content = resultSections.join('\\n--\\n')\n }\n }\n\n return {\n path: configPath,\n content\n }\n } catch (error) {\n logger.debug(`Failed to grep shell config file ${configPath}: ${error}`)\n return {\n path: configPath,\n content: ''\n }\n }\n }\n\n /**\n * Merge overlapping ranges to avoid duplicate lines\n */\n private mergeOverlappingRanges(ranges: { start: number; end: number }[]): { start: number; end: number }[] {\n if (ranges.length === 0) return []\n\n // Sort ranges by start position\n const sorted = [...ranges].sort((a, b) => a.start - b.start)\n const firstRange = sorted[0]\n if (!firstRange) return []\n\n const merged: { start: number; end: number }[] = [firstRange]\n\n for (let i = 1; i < sorted.length; i++) {\n const current = sorted[i]\n const last = merged[merged.length - 1]\n\n // Both current and last should exist, but TypeScript needs explicit checks\n if (!current || !last) continue\n\n // If current range overlaps or is adjacent to the last merged range\n if (current.start <= last.end + 1) {\n // Merge ranges by extending the end\n last.end = Math.max(last.end, current.end)\n } else {\n // No overlap, add as new range\n merged.push(current)\n }\n }\n\n return merged\n }\n\n}\n"],"mappings":"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","names":[]}
|
|
@@ -15,7 +15,7 @@ var ClaudeBranchNameStrategy = class {
|
|
|
15
15
|
this.claudeModel = claudeModel;
|
|
16
16
|
}
|
|
17
17
|
async generate(issueNumber, title) {
|
|
18
|
-
const { generateBranchName } = await import("./claude-
|
|
18
|
+
const { generateBranchName } = await import("./claude-TP2QO3BU.js");
|
|
19
19
|
return generateBranchName(title, issueNumber, this.claudeModel);
|
|
20
20
|
}
|
|
21
21
|
};
|
|
@@ -52,4 +52,4 @@ export {
|
|
|
52
52
|
ClaudeBranchNameStrategy,
|
|
53
53
|
DefaultBranchNamingService
|
|
54
54
|
};
|
|
55
|
-
//# sourceMappingURL=chunk-
|
|
55
|
+
//# sourceMappingURL=chunk-KAYXR544.js.map
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
PromptTemplateManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QN47QVBX.js";
|
|
5
5
|
import {
|
|
6
6
|
SettingsManager
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XFEK2X2D.js";
|
|
8
8
|
import {
|
|
9
9
|
detectClaudeCli,
|
|
10
10
|
launchClaude,
|
|
11
11
|
launchClaudeInNewTerminalWindow
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-FO5GGFOV.js";
|
|
13
13
|
import {
|
|
14
14
|
logger
|
|
15
15
|
} from "./chunk-VT4PDUYT.js";
|
|
@@ -119,4 +119,4 @@ var ClaudeService = class {
|
|
|
119
119
|
export {
|
|
120
120
|
ClaudeService
|
|
121
121
|
};
|
|
122
|
-
//# sourceMappingURL=chunk-
|
|
122
|
+
//# sourceMappingURL=chunk-MZPRBNYC.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
calculatePortFromIdentifier
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-USSL2X4A.js";
|
|
5
5
|
|
|
6
6
|
// src/lib/process/ProcessManager.ts
|
|
7
7
|
import { execa } from "execa";
|
|
@@ -179,4 +179,4 @@ var ProcessManager = class {
|
|
|
179
179
|
export {
|
|
180
180
|
ProcessManager
|
|
181
181
|
};
|
|
182
|
-
//# sourceMappingURL=chunk-
|
|
182
|
+
//# sourceMappingURL=chunk-NTTSUAVM.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ClaudeService
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MZPRBNYC.js";
|
|
5
5
|
import {
|
|
6
6
|
logger
|
|
7
7
|
} from "./chunk-VT4PDUYT.js";
|
|
@@ -63,4 +63,4 @@ var ClaudeContextManager = class {
|
|
|
63
63
|
export {
|
|
64
64
|
ClaudeContextManager
|
|
65
65
|
};
|
|
66
|
-
//# sourceMappingURL=chunk-
|
|
66
|
+
//# sourceMappingURL=chunk-OAVJR4PM.js.map
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from "./chunk-7JDMYTFZ.js";
|
|
11
11
|
import {
|
|
12
12
|
launchClaude
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FO5GGFOV.js";
|
|
14
14
|
import {
|
|
15
15
|
getLogger
|
|
16
16
|
} from "./chunk-6MLEBAYZ.js";
|
|
@@ -244,4 +244,4 @@ export {
|
|
|
244
244
|
IssueEnhancementService,
|
|
245
245
|
capitalizeFirstLetter
|
|
246
246
|
};
|
|
247
|
-
//# sourceMappingURL=chunk-
|
|
247
|
+
//# sourceMappingURL=chunk-PL2FDYEK.js.map
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
logger
|
|
4
|
+
} from "./chunk-VT4PDUYT.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/PromptTemplateManager.ts
|
|
7
|
+
import { readFile } from "fs/promises";
|
|
8
|
+
import { accessSync } from "fs";
|
|
9
|
+
import path from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
import Handlebars from "handlebars";
|
|
12
|
+
Handlebars.registerHelper("raw", function(options) {
|
|
13
|
+
return options.fn(this);
|
|
14
|
+
});
|
|
15
|
+
function buildReviewTemplateVariables(agents) {
|
|
16
|
+
var _a, _b, _c, _d, _e, _f;
|
|
17
|
+
const variables = {};
|
|
18
|
+
const reviewerSettings = agents == null ? void 0 : agents["iloom-code-reviewer"];
|
|
19
|
+
const reviewEnabled = (reviewerSettings == null ? void 0 : reviewerSettings.enabled) !== false;
|
|
20
|
+
variables.REVIEW_ENABLED = reviewEnabled;
|
|
21
|
+
if (reviewEnabled) {
|
|
22
|
+
const providers = (reviewerSettings == null ? void 0 : reviewerSettings.providers) ?? {};
|
|
23
|
+
const hasAnyProvider = Object.keys(providers).length > 0;
|
|
24
|
+
const claudeModel = providers.claude ?? (hasAnyProvider ? void 0 : "sonnet");
|
|
25
|
+
if (claudeModel) {
|
|
26
|
+
variables.REVIEW_CLAUDE_MODEL = claudeModel;
|
|
27
|
+
}
|
|
28
|
+
if (providers.gemini) {
|
|
29
|
+
variables.REVIEW_GEMINI_MODEL = providers.gemini;
|
|
30
|
+
}
|
|
31
|
+
if (providers.codex) {
|
|
32
|
+
variables.REVIEW_CODEX_MODEL = providers.codex;
|
|
33
|
+
}
|
|
34
|
+
variables.HAS_REVIEW_CLAUDE = !!claudeModel;
|
|
35
|
+
variables.HAS_REVIEW_GEMINI = !!providers.gemini;
|
|
36
|
+
variables.HAS_REVIEW_CODEX = !!providers.codex;
|
|
37
|
+
}
|
|
38
|
+
const artifactReviewerSettings = agents == null ? void 0 : agents["iloom-artifact-reviewer"];
|
|
39
|
+
const artifactReviewEnabled = (artifactReviewerSettings == null ? void 0 : artifactReviewerSettings.enabled) !== false;
|
|
40
|
+
variables.ARTIFACT_REVIEW_ENABLED = artifactReviewEnabled;
|
|
41
|
+
if (artifactReviewEnabled) {
|
|
42
|
+
const artifactProviders = (artifactReviewerSettings == null ? void 0 : artifactReviewerSettings.providers) ?? {};
|
|
43
|
+
const hasAnyArtifactProvider = Object.keys(artifactProviders).length > 0;
|
|
44
|
+
const artifactClaudeModel = artifactProviders.claude ?? (hasAnyArtifactProvider ? void 0 : "sonnet");
|
|
45
|
+
if (artifactClaudeModel) {
|
|
46
|
+
variables.ARTIFACT_REVIEW_CLAUDE_MODEL = artifactClaudeModel;
|
|
47
|
+
}
|
|
48
|
+
if (artifactProviders.gemini) {
|
|
49
|
+
variables.ARTIFACT_REVIEW_GEMINI_MODEL = artifactProviders.gemini;
|
|
50
|
+
}
|
|
51
|
+
if (artifactProviders.codex) {
|
|
52
|
+
variables.ARTIFACT_REVIEW_CODEX_MODEL = artifactProviders.codex;
|
|
53
|
+
}
|
|
54
|
+
variables.HAS_ARTIFACT_REVIEW_CLAUDE = !!artifactClaudeModel;
|
|
55
|
+
variables.HAS_ARTIFACT_REVIEW_GEMINI = !!artifactProviders.gemini;
|
|
56
|
+
variables.HAS_ARTIFACT_REVIEW_CODEX = !!artifactProviders.codex;
|
|
57
|
+
}
|
|
58
|
+
variables.ENHANCER_REVIEW_ENABLED = ((_a = agents == null ? void 0 : agents["iloom-issue-enhancer"]) == null ? void 0 : _a.review) === true;
|
|
59
|
+
variables.ANALYZER_REVIEW_ENABLED = ((_b = agents == null ? void 0 : agents["iloom-issue-analyzer"]) == null ? void 0 : _b.review) === true;
|
|
60
|
+
variables.PLANNER_REVIEW_ENABLED = ((_c = agents == null ? void 0 : agents["iloom-issue-planner"]) == null ? void 0 : _c.review) === true;
|
|
61
|
+
variables.ANALYZE_AND_PLAN_REVIEW_ENABLED = ((_d = agents == null ? void 0 : agents["iloom-issue-analyze-and-plan"]) == null ? void 0 : _d.review) === true;
|
|
62
|
+
variables.IMPLEMENTER_REVIEW_ENABLED = ((_e = agents == null ? void 0 : agents["iloom-issue-implementer"]) == null ? void 0 : _e.review) === true;
|
|
63
|
+
variables.COMPLEXITY_REVIEW_ENABLED = ((_f = agents == null ? void 0 : agents["iloom-issue-complexity-evaluator"]) == null ? void 0 : _f.review) === true;
|
|
64
|
+
return variables;
|
|
65
|
+
}
|
|
66
|
+
var PromptTemplateManager = class {
|
|
67
|
+
constructor(templateDir) {
|
|
68
|
+
if (templateDir) {
|
|
69
|
+
this.templateDir = templateDir;
|
|
70
|
+
} else {
|
|
71
|
+
const currentFileUrl = import.meta.url;
|
|
72
|
+
const currentFilePath = fileURLToPath(currentFileUrl);
|
|
73
|
+
const distDir = path.dirname(currentFilePath);
|
|
74
|
+
let templateDir2 = path.join(distDir, "prompts");
|
|
75
|
+
let currentDir = distDir;
|
|
76
|
+
while (currentDir !== path.dirname(currentDir)) {
|
|
77
|
+
const candidatePath = path.join(currentDir, "prompts");
|
|
78
|
+
try {
|
|
79
|
+
accessSync(candidatePath);
|
|
80
|
+
templateDir2 = candidatePath;
|
|
81
|
+
break;
|
|
82
|
+
} catch {
|
|
83
|
+
currentDir = path.dirname(currentDir);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
this.templateDir = templateDir2;
|
|
87
|
+
logger.debug("PromptTemplateManager initialized", {
|
|
88
|
+
currentFilePath,
|
|
89
|
+
distDir,
|
|
90
|
+
templateDir: this.templateDir
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Load a template file by name
|
|
96
|
+
*/
|
|
97
|
+
async loadTemplate(templateName) {
|
|
98
|
+
const templatePath = path.join(this.templateDir, `${templateName}-prompt.txt`);
|
|
99
|
+
logger.debug("Loading template", {
|
|
100
|
+
templateName,
|
|
101
|
+
templateDir: this.templateDir,
|
|
102
|
+
templatePath
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
return await readFile(templatePath, "utf-8");
|
|
106
|
+
} catch (error) {
|
|
107
|
+
logger.error("Failed to load template", { templateName, templatePath, error });
|
|
108
|
+
throw new Error(`Template not found: ${templatePath}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Substitute variables in a template string using Handlebars
|
|
113
|
+
*/
|
|
114
|
+
substituteVariables(template, variables) {
|
|
115
|
+
const compiled = Handlebars.compile(template, { noEscape: true });
|
|
116
|
+
return compiled(variables);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get a fully processed prompt for a workflow type
|
|
120
|
+
*/
|
|
121
|
+
async getPrompt(type, variables) {
|
|
122
|
+
const template = await this.loadTemplate(type);
|
|
123
|
+
return this.substituteVariables(template, variables);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
buildReviewTemplateVariables,
|
|
129
|
+
PromptTemplateManager
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=chunk-QN47QVBX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/PromptTemplateManager.ts"],"sourcesContent":["import { readFile } from 'fs/promises'\nimport { accessSync } from 'fs'\nimport path from 'path'\nimport { fileURLToPath } from 'url'\nimport Handlebars from 'handlebars'\nimport { logger } from '../utils/logger.js'\nimport type { AgentSettings } from './SettingsManager.js'\n\n// Register raw helper to handle content with curly braces (e.g., JSON)\n// Usage: {{{{raw}}}}{{VARIABLE}}{{{{/raw}}}}\n// This outputs the variable content as-is without Handlebars parsing its curly braces\nHandlebars.registerHelper('raw', function (this: unknown, options: Handlebars.HelperOptions) {\n\treturn options.fn(this)\n})\n\nexport interface TemplateVariables {\n\tISSUE_NUMBER?: string | number\n\tPR_NUMBER?: number\n\tISSUE_TITLE?: string\n\tPR_TITLE?: string\n\tWORKSPACE_PATH?: string\n\tPORT?: number\n\tONE_SHOT_MODE?: boolean\n\tINTERACTIVE_MODE?: boolean\n\tSETTINGS_SCHEMA?: string\n\tSETTINGS_GLOBAL_JSON?: string\n\tSETTINGS_JSON?: string\n\tSETTINGS_LOCAL_JSON?: string\n\tSHELL_TYPE?: string\n\tSHELL_CONFIG_PATH?: string\n\tSHELL_CONFIG_CONTENT?: string\n\tREMOTES_INFO?: string\n\tMULTIPLE_REMOTES?: string\n\tSINGLE_REMOTE?: string\n\tSINGLE_REMOTE_NAME?: string\n\tSINGLE_REMOTE_URL?: string\n\tNO_REMOTES?: string\n\tREADME_CONTENT?: string\n\tSETTINGS_SCHEMA_CONTENT?: string\n\tFIRST_TIME_USER?: boolean\n\tVSCODE_SETTINGS_GITIGNORED?: string\n\t// Session summary template variables\n\tSESSION_CONTEXT?: string // Session ID for Claude to reference its conversation\n\tBRANCH_NAME?: string // Branch being finished\n\tLOOM_TYPE?: string // 'issue' or 'pr'\n\tCOMPACT_SUMMARIES?: string // Extracted compact summaries from session transcript\n\tRECAP_DATA?: string // Formatted recap data (goal, complexity, entries, artifacts)\n\t// Draft PR mode variables - mutually exclusive with standard issue mode\n\tDRAFT_PR_NUMBER?: number // PR number for draft PR workflow\n\tDRAFT_PR_URL?: string // Full URL of the draft PR (e.g., https://github.com/owner/repo/pull/123)\n\tDRAFT_PR_MODE?: boolean // True when using github-draft-pr merge mode\n\tAUTO_COMMIT_PUSH?: boolean // True when auto-commit/push is enabled for draft PR mode\n\tSTANDARD_ISSUE_MODE?: boolean // True when using standard issue commenting (not draft PR)\n\tSTANDARD_BRANCH_MODE?: boolean // True when using standard branch mode (not draft PR)\n\t// VS Code environment detection\n\tIS_VSCODE_MODE?: boolean // True when ILOOM_VSCODE=1 environment variable is set\n\t// Multi-language support variables - mutually exclusive\n\tHAS_PACKAGE_JSON?: boolean // True when project has package.json\n\tNO_PACKAGE_JSON?: boolean // True when project does not have package.json (non-Node.js projects)\n\t// Review agent configuration variables (code reviewer)\n\tREVIEW_ENABLED?: boolean // True if review is enabled (defaults to true)\n\tREVIEW_CLAUDE_MODEL?: string // Claude model if configured (defaults to 'sonnet')\n\tREVIEW_GEMINI_MODEL?: string // Gemini model if configured\n\tREVIEW_CODEX_MODEL?: string // Codex model if configured\n\tHAS_REVIEW_CLAUDE?: boolean // True if claude provider configured (defaults to true)\n\tHAS_REVIEW_GEMINI?: boolean // True if gemini provider configured\n\tHAS_REVIEW_CODEX?: boolean // True if codex provider configured\n\t// Artifact reviewer configuration variables\n\tARTIFACT_REVIEW_ENABLED?: boolean // True if artifact review is enabled (defaults to true)\n\tARTIFACT_REVIEW_CLAUDE_MODEL?: string // Claude model if configured (defaults to 'sonnet')\n\tARTIFACT_REVIEW_GEMINI_MODEL?: string // Gemini model if configured\n\tARTIFACT_REVIEW_CODEX_MODEL?: string // Codex model if configured\n\tHAS_ARTIFACT_REVIEW_CLAUDE?: boolean // True if claude provider configured (defaults to true)\n\tHAS_ARTIFACT_REVIEW_GEMINI?: boolean // True if gemini provider configured\n\tHAS_ARTIFACT_REVIEW_CODEX?: boolean // True if codex provider configured\n\t// Per-agent review flags (whether artifacts should be reviewed before posting)\n\tENHANCER_REVIEW_ENABLED?: boolean // True if enhancer artifacts should be reviewed\n\tANALYZER_REVIEW_ENABLED?: boolean // True if analyzer artifacts should be reviewed\n\tPLANNER_REVIEW_ENABLED?: boolean // True if planner artifacts should be reviewed\n\tANALYZE_AND_PLAN_REVIEW_ENABLED?: boolean // True if analyze-and-plan artifacts should be reviewed\n\tIMPLEMENTER_REVIEW_ENABLED?: boolean // True if implementer artifacts should be reviewed\n\tCOMPLEXITY_REVIEW_ENABLED?: boolean // True if complexity evaluator artifacts should be reviewed\n\t// Planning mode variables - mutually exclusive\n\tEXISTING_ISSUE_MODE?: boolean // True when decomposing an existing issue (il plan 42)\n\tFRESH_PLANNING_MODE?: boolean // True when starting fresh planning session (il plan \"feature idea\")\n\t// Issue context for decomposition mode\n\tPARENT_ISSUE_NUMBER?: string | undefined // Issue number being decomposed\n\tPARENT_ISSUE_TITLE?: string | undefined // Title of issue being decomposed\n\tPARENT_ISSUE_BODY?: string | undefined // Body of issue being decomposed\n\t// Existing children and dependencies context for decomposition mode\n\tPARENT_ISSUE_CHILDREN?: string | undefined // Formatted list of existing child issues (if any)\n\tPARENT_ISSUE_DEPENDENCIES?: string | undefined // Formatted list of existing dependencies (if any)\n\t// Multi-AI provider support for plan command\n\tPLANNER?: 'claude' | 'gemini' | 'codex'\n\tREVIEWER?: 'claude' | 'gemini' | 'codex' | 'none'\n\tUSE_CLAUDE_PLANNER?: boolean\n\tUSE_GEMINI_PLANNER?: boolean\n\tUSE_CODEX_PLANNER?: boolean\n\tUSE_CLAUDE_REVIEWER?: boolean\n\tUSE_GEMINI_REVIEWER?: boolean\n\tUSE_CODEX_REVIEWER?: boolean\n\tHAS_REVIEWER?: boolean\n\t// Git remote configuration\n\tGIT_REMOTE?: string // Remote name for push (defaults to 'origin')\n}\n\n/**\n * Build review-related template variables from settings.\n * Used by both the ignite command (for prompt templates) and AgentManager (for agent prompts).\n */\nexport function buildReviewTemplateVariables(agents?: Record<string, AgentSettings> | null): Partial<TemplateVariables> {\n\tconst variables: Partial<TemplateVariables> = {}\n\n\t// Code reviewer configuration\n\tconst reviewerSettings = agents?.['iloom-code-reviewer']\n\tconst reviewEnabled = reviewerSettings?.enabled !== false // Default to true\n\tvariables.REVIEW_ENABLED = reviewEnabled\n\n\tif (reviewEnabled) {\n\t\tconst providers = reviewerSettings?.providers ?? {}\n\t\tconst hasAnyProvider = Object.keys(providers).length > 0\n\n\t\tconst claudeModel = providers.claude ?? (hasAnyProvider ? undefined : 'sonnet')\n\t\tif (claudeModel) {\n\t\t\tvariables.REVIEW_CLAUDE_MODEL = claudeModel\n\t\t}\n\t\tif (providers.gemini) {\n\t\t\tvariables.REVIEW_GEMINI_MODEL = providers.gemini\n\t\t}\n\t\tif (providers.codex) {\n\t\t\tvariables.REVIEW_CODEX_MODEL = providers.codex\n\t\t}\n\t\tvariables.HAS_REVIEW_CLAUDE = !!claudeModel\n\t\tvariables.HAS_REVIEW_GEMINI = !!providers.gemini\n\t\tvariables.HAS_REVIEW_CODEX = !!providers.codex\n\t}\n\n\t// Artifact reviewer configuration\n\tconst artifactReviewerSettings = agents?.['iloom-artifact-reviewer']\n\tconst artifactReviewEnabled = artifactReviewerSettings?.enabled !== false // Default to true\n\tvariables.ARTIFACT_REVIEW_ENABLED = artifactReviewEnabled\n\n\tif (artifactReviewEnabled) {\n\t\tconst artifactProviders = artifactReviewerSettings?.providers ?? {}\n\t\tconst hasAnyArtifactProvider = Object.keys(artifactProviders).length > 0\n\n\t\tconst artifactClaudeModel = artifactProviders.claude ?? (hasAnyArtifactProvider ? undefined : 'sonnet')\n\t\tif (artifactClaudeModel) {\n\t\t\tvariables.ARTIFACT_REVIEW_CLAUDE_MODEL = artifactClaudeModel\n\t\t}\n\t\tif (artifactProviders.gemini) {\n\t\t\tvariables.ARTIFACT_REVIEW_GEMINI_MODEL = artifactProviders.gemini\n\t\t}\n\t\tif (artifactProviders.codex) {\n\t\t\tvariables.ARTIFACT_REVIEW_CODEX_MODEL = artifactProviders.codex\n\t\t}\n\t\tvariables.HAS_ARTIFACT_REVIEW_CLAUDE = !!artifactClaudeModel\n\t\tvariables.HAS_ARTIFACT_REVIEW_GEMINI = !!artifactProviders.gemini\n\t\tvariables.HAS_ARTIFACT_REVIEW_CODEX = !!artifactProviders.codex\n\t}\n\n\t// Per-agent review flags (defaults to false for each)\n\tvariables.ENHANCER_REVIEW_ENABLED = agents?.['iloom-issue-enhancer']?.review === true\n\tvariables.ANALYZER_REVIEW_ENABLED = agents?.['iloom-issue-analyzer']?.review === true\n\tvariables.PLANNER_REVIEW_ENABLED = agents?.['iloom-issue-planner']?.review === true\n\tvariables.ANALYZE_AND_PLAN_REVIEW_ENABLED = agents?.['iloom-issue-analyze-and-plan']?.review === true\n\tvariables.IMPLEMENTER_REVIEW_ENABLED = agents?.['iloom-issue-implementer']?.review === true\n\tvariables.COMPLEXITY_REVIEW_ENABLED = agents?.['iloom-issue-complexity-evaluator']?.review === true\n\n\treturn variables\n}\n\nexport class PromptTemplateManager {\n\tprivate templateDir: string\n\n\tconstructor(templateDir?: string) {\n\t\tif (templateDir) {\n\t\t\tthis.templateDir = templateDir\n\t\t} else {\n\t\t\t// Find templates relative to the package installation\n\t\t\t// When running from dist/, templates are copied to dist/prompts/\n\t\t\tconst currentFileUrl = import.meta.url\n\t\t\tconst currentFilePath = fileURLToPath(currentFileUrl)\n\t\t\tconst distDir = path.dirname(currentFilePath) // dist directory (may be chunked file location)\n\n\t\t\t// Walk up to find the dist directory (in case of chunked files)\n\t\t\tlet templateDir = path.join(distDir, 'prompts')\n\t\t\tlet currentDir = distDir\n\n\t\t\t// Try to find the prompts directory by walking up\n\t\t\twhile (currentDir !== path.dirname(currentDir)) {\n\t\t\t\tconst candidatePath = path.join(currentDir, 'prompts')\n\t\t\t\ttry {\n\t\t\t\t\t// Check if this directory exists (sync check for constructor)\n\t\t\t\t\taccessSync(candidatePath)\n\t\t\t\t\ttemplateDir = candidatePath\n\t\t\t\t\tbreak\n\t\t\t\t} catch {\n\t\t\t\t\tcurrentDir = path.dirname(currentDir)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.templateDir = templateDir\n\t\t\tlogger.debug('PromptTemplateManager initialized', {\n\t\t\t\tcurrentFilePath,\n\t\t\t\tdistDir,\n\t\t\t\ttemplateDir: this.templateDir\n\t\t\t})\n\t\t}\n\t}\n\n\t/**\n\t * Load a template file by name\n\t */\n\tasync loadTemplate(templateName: 'issue' | 'pr' | 'regular' | 'init' | 'session-summary' | 'plan'): Promise<string> {\n\t\tconst templatePath = path.join(this.templateDir, `${templateName}-prompt.txt`)\n\n\t\tlogger.debug('Loading template', {\n\t\t\ttemplateName,\n\t\t\ttemplateDir: this.templateDir,\n\t\t\ttemplatePath\n\t\t})\n\n\t\ttry {\n\t\t\treturn await readFile(templatePath, 'utf-8')\n\t\t} catch (error) {\n\t\t\tlogger.error('Failed to load template', { templateName, templatePath, error })\n\t\t\tthrow new Error(`Template not found: ${templatePath}`)\n\t\t}\n\t}\n\n\t/**\n\t * Substitute variables in a template string using Handlebars\n\t */\n\tsubstituteVariables(template: string, variables: TemplateVariables): string {\n\t\tconst compiled = Handlebars.compile(template, { noEscape: true })\n\t\treturn compiled(variables)\n\t}\n\n\t/**\n\t * Get a fully processed prompt for a workflow type\n\t */\n\tasync getPrompt(\n\t\ttype: 'issue' | 'pr' | 'regular' | 'init' | 'session-summary' | 'plan',\n\t\tvariables: TemplateVariables\n\t): Promise<string> {\n\t\tconst template = await this.loadTemplate(type)\n\t\treturn this.substituteVariables(template, variables)\n\t}\n}\n"],"mappings":"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","names":["templateDir"]}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
InitCommand
|
|
4
|
-
} from "./chunk-FPNSFP6K.js";
|
|
5
2
|
import {
|
|
6
3
|
FirstRunManager
|
|
7
4
|
} from "./chunk-Q7POFB5Q.js";
|
|
8
5
|
import {
|
|
9
6
|
getRepoRoot
|
|
10
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-H6ST2TGP.js";
|
|
8
|
+
import {
|
|
9
|
+
promptConfirmation,
|
|
10
|
+
waitForKeypress
|
|
11
|
+
} from "./chunk-7JDMYTFZ.js";
|
|
11
12
|
import {
|
|
12
13
|
logger
|
|
13
14
|
} from "./chunk-VT4PDUYT.js";
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
import { existsSync } from "fs";
|
|
17
18
|
import { readFile } from "fs/promises";
|
|
18
19
|
import path from "path";
|
|
20
|
+
import chalk from "chalk";
|
|
19
21
|
async function getProjectRoot() {
|
|
20
22
|
const repoRoot = await getRepoRoot();
|
|
21
23
|
if (repoRoot) {
|
|
@@ -54,13 +56,37 @@ async function hasNonEmptySettings(filePath) {
|
|
|
54
56
|
return false;
|
|
55
57
|
}
|
|
56
58
|
}
|
|
59
|
+
function displayDefaultsBox() {
|
|
60
|
+
logger.info(chalk.bold("Default Configuration:"));
|
|
61
|
+
logger.info("");
|
|
62
|
+
logger.info(` ${chalk.cyan("Main Branch:")} main`);
|
|
63
|
+
logger.info(` ${chalk.cyan("IDE:")} vscode`);
|
|
64
|
+
logger.info(` ${chalk.cyan("Issue Tracker:")} GitHub Issues`);
|
|
65
|
+
logger.info(` ${chalk.cyan("Merge Mode:")} local ${chalk.dim("(merge locally)")}`);
|
|
66
|
+
logger.info(` ${chalk.cyan("Base Port:")} 3000`);
|
|
67
|
+
}
|
|
57
68
|
async function launchFirstRunSetup() {
|
|
58
69
|
logger.info("First-time project setup detected.");
|
|
59
|
-
logger.info(
|
|
60
|
-
|
|
70
|
+
logger.info("");
|
|
71
|
+
displayDefaultsBox();
|
|
72
|
+
logger.info("");
|
|
73
|
+
const acceptDefaults = await promptConfirmation(
|
|
74
|
+
"Are these defaults OK?",
|
|
75
|
+
true
|
|
76
|
+
// default to true, so Enter accepts
|
|
61
77
|
);
|
|
62
|
-
|
|
78
|
+
if (acceptDefaults) {
|
|
79
|
+
const projectRoot = await getProjectRoot();
|
|
80
|
+
const firstRunManager = new FirstRunManager();
|
|
81
|
+
await firstRunManager.markProjectAsConfigured(projectRoot);
|
|
82
|
+
logger.info(chalk.green("Configuration complete! Using defaults."));
|
|
83
|
+
logger.info("You can run `il init` anytime to customize settings.");
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
logger.info("");
|
|
87
|
+
logger.info("iloom will now launch an interactive configuration session with Claude.");
|
|
63
88
|
await waitForKeypress("Press any key to start configuration...");
|
|
89
|
+
const { InitCommand } = await import("./init-ALYWKNWG.js");
|
|
64
90
|
const initCommand = new InitCommand();
|
|
65
91
|
await initCommand.execute(
|
|
66
92
|
"Help me configure iloom settings for this project. This is my first time using iloom here. Note: Your iloom command will execute once we are done with configuration changes."
|
|
@@ -72,4 +98,4 @@ export {
|
|
|
72
98
|
needsFirstRunSetup,
|
|
73
99
|
launchFirstRunSetup
|
|
74
100
|
};
|
|
75
|
-
//# sourceMappingURL=chunk-
|
|
101
|
+
//# sourceMappingURL=chunk-RD7OPXZK.js.map
|