@iloom/cli 0.1.14
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 +33 -0
- package/README.md +711 -0
- package/dist/ClaudeContextManager-XOSXQ67R.js +13 -0
- package/dist/ClaudeContextManager-XOSXQ67R.js.map +1 -0
- package/dist/ClaudeService-YSZ6EXWP.js +12 -0
- package/dist/ClaudeService-YSZ6EXWP.js.map +1 -0
- package/dist/GitHubService-F7Z3XJOS.js +11 -0
- package/dist/GitHubService-F7Z3XJOS.js.map +1 -0
- package/dist/LoomLauncher-MODG2SEM.js +263 -0
- package/dist/LoomLauncher-MODG2SEM.js.map +1 -0
- package/dist/NeonProvider-PAGPUH7F.js +12 -0
- package/dist/NeonProvider-PAGPUH7F.js.map +1 -0
- package/dist/PromptTemplateManager-7FINLRDE.js +9 -0
- package/dist/PromptTemplateManager-7FINLRDE.js.map +1 -0
- package/dist/SettingsManager-VAZF26S2.js +19 -0
- package/dist/SettingsManager-VAZF26S2.js.map +1 -0
- package/dist/SettingsMigrationManager-MTQIMI54.js +146 -0
- package/dist/SettingsMigrationManager-MTQIMI54.js.map +1 -0
- package/dist/add-issue-22JBNOML.js +54 -0
- package/dist/add-issue-22JBNOML.js.map +1 -0
- package/dist/agents/iloom-issue-analyze-and-plan.md +580 -0
- package/dist/agents/iloom-issue-analyzer.md +290 -0
- package/dist/agents/iloom-issue-complexity-evaluator.md +224 -0
- package/dist/agents/iloom-issue-enhancer.md +266 -0
- package/dist/agents/iloom-issue-implementer.md +262 -0
- package/dist/agents/iloom-issue-planner.md +358 -0
- package/dist/agents/iloom-issue-reviewer.md +63 -0
- package/dist/chunk-2ZPFJQ3B.js +63 -0
- package/dist/chunk-2ZPFJQ3B.js.map +1 -0
- package/dist/chunk-37DYYFVK.js +29 -0
- package/dist/chunk-37DYYFVK.js.map +1 -0
- package/dist/chunk-BLCTGFZN.js +121 -0
- package/dist/chunk-BLCTGFZN.js.map +1 -0
- package/dist/chunk-CP2NU2JC.js +545 -0
- package/dist/chunk-CP2NU2JC.js.map +1 -0
- package/dist/chunk-CWR2SANQ.js +39 -0
- package/dist/chunk-CWR2SANQ.js.map +1 -0
- package/dist/chunk-F3XBU2R7.js +110 -0
- package/dist/chunk-F3XBU2R7.js.map +1 -0
- package/dist/chunk-GEHQXLEI.js +130 -0
- package/dist/chunk-GEHQXLEI.js.map +1 -0
- package/dist/chunk-GYCR2LOU.js +143 -0
- package/dist/chunk-GYCR2LOU.js.map +1 -0
- package/dist/chunk-GZP4UGGM.js +48 -0
- package/dist/chunk-GZP4UGGM.js.map +1 -0
- package/dist/chunk-H4E4THUZ.js +55 -0
- package/dist/chunk-H4E4THUZ.js.map +1 -0
- package/dist/chunk-HPJJSYNS.js +644 -0
- package/dist/chunk-HPJJSYNS.js.map +1 -0
- package/dist/chunk-JBH2ZYYZ.js +220 -0
- package/dist/chunk-JBH2ZYYZ.js.map +1 -0
- package/dist/chunk-JNKJ7NJV.js +78 -0
- package/dist/chunk-JNKJ7NJV.js.map +1 -0
- package/dist/chunk-JQ7VOSTC.js +437 -0
- package/dist/chunk-JQ7VOSTC.js.map +1 -0
- package/dist/chunk-KQDEK2ZW.js +199 -0
- package/dist/chunk-KQDEK2ZW.js.map +1 -0
- package/dist/chunk-O2QWO64Z.js +179 -0
- package/dist/chunk-O2QWO64Z.js.map +1 -0
- package/dist/chunk-OC4H6HJD.js +248 -0
- package/dist/chunk-OC4H6HJD.js.map +1 -0
- package/dist/chunk-PR7FKQBG.js +120 -0
- package/dist/chunk-PR7FKQBG.js.map +1 -0
- package/dist/chunk-PXZBAC2M.js +250 -0
- package/dist/chunk-PXZBAC2M.js.map +1 -0
- package/dist/chunk-QEPVTTHD.js +383 -0
- package/dist/chunk-QEPVTTHD.js.map +1 -0
- package/dist/chunk-RSRO7564.js +203 -0
- package/dist/chunk-RSRO7564.js.map +1 -0
- package/dist/chunk-SJUQ2NDR.js +146 -0
- package/dist/chunk-SJUQ2NDR.js.map +1 -0
- package/dist/chunk-SPYPLHMK.js +177 -0
- package/dist/chunk-SPYPLHMK.js.map +1 -0
- package/dist/chunk-SSCQCCJ7.js +75 -0
- package/dist/chunk-SSCQCCJ7.js.map +1 -0
- package/dist/chunk-SSR5AVRJ.js +41 -0
- package/dist/chunk-SSR5AVRJ.js.map +1 -0
- package/dist/chunk-T7QPXANZ.js +315 -0
- package/dist/chunk-T7QPXANZ.js.map +1 -0
- package/dist/chunk-U3WU5OWO.js +203 -0
- package/dist/chunk-U3WU5OWO.js.map +1 -0
- package/dist/chunk-W3DQTW63.js +124 -0
- package/dist/chunk-W3DQTW63.js.map +1 -0
- package/dist/chunk-WKEWRSDB.js +151 -0
- package/dist/chunk-WKEWRSDB.js.map +1 -0
- package/dist/chunk-Y7SAGNUT.js +66 -0
- package/dist/chunk-Y7SAGNUT.js.map +1 -0
- package/dist/chunk-YETJNRQM.js +39 -0
- package/dist/chunk-YETJNRQM.js.map +1 -0
- package/dist/chunk-YYSKGAZT.js +384 -0
- package/dist/chunk-YYSKGAZT.js.map +1 -0
- package/dist/chunk-ZZZWQGTS.js +169 -0
- package/dist/chunk-ZZZWQGTS.js.map +1 -0
- package/dist/claude-7LUVDZZ4.js +17 -0
- package/dist/claude-7LUVDZZ4.js.map +1 -0
- package/dist/cleanup-3LUWPSM7.js +412 -0
- package/dist/cleanup-3LUWPSM7.js.map +1 -0
- package/dist/cli-overrides-XFZWY7CM.js +16 -0
- package/dist/cli-overrides-XFZWY7CM.js.map +1 -0
- package/dist/cli.js +603 -0
- package/dist/cli.js.map +1 -0
- package/dist/color-ZVALX37U.js +21 -0
- package/dist/color-ZVALX37U.js.map +1 -0
- package/dist/enhance-XJIQHVPD.js +166 -0
- package/dist/enhance-XJIQHVPD.js.map +1 -0
- package/dist/env-MDFL4ZXL.js +23 -0
- package/dist/env-MDFL4ZXL.js.map +1 -0
- package/dist/feedback-23CLXKFT.js +158 -0
- package/dist/feedback-23CLXKFT.js.map +1 -0
- package/dist/finish-CY4CIH6O.js +1608 -0
- package/dist/finish-CY4CIH6O.js.map +1 -0
- package/dist/git-LVRZ57GJ.js +43 -0
- package/dist/git-LVRZ57GJ.js.map +1 -0
- package/dist/ignite-WXEF2ID5.js +359 -0
- package/dist/ignite-WXEF2ID5.js.map +1 -0
- package/dist/index.d.ts +1341 -0
- package/dist/index.js +3058 -0
- package/dist/index.js.map +1 -0
- package/dist/init-RHACUR4E.js +123 -0
- package/dist/init-RHACUR4E.js.map +1 -0
- package/dist/installation-detector-VARGFFRZ.js +11 -0
- package/dist/installation-detector-VARGFFRZ.js.map +1 -0
- package/dist/logger-MKYH4UDV.js +12 -0
- package/dist/logger-MKYH4UDV.js.map +1 -0
- package/dist/mcp/chunk-6SDFJ42P.js +62 -0
- package/dist/mcp/chunk-6SDFJ42P.js.map +1 -0
- package/dist/mcp/claude-YHHHLSXH.js +249 -0
- package/dist/mcp/claude-YHHHLSXH.js.map +1 -0
- package/dist/mcp/color-QS5BFCNN.js +168 -0
- package/dist/mcp/color-QS5BFCNN.js.map +1 -0
- package/dist/mcp/github-comment-server.js +165 -0
- package/dist/mcp/github-comment-server.js.map +1 -0
- package/dist/mcp/terminal-SDCMDVD7.js +202 -0
- package/dist/mcp/terminal-SDCMDVD7.js.map +1 -0
- package/dist/open-X6BTENPV.js +278 -0
- package/dist/open-X6BTENPV.js.map +1 -0
- package/dist/prompt-ANTQWHUF.js +13 -0
- package/dist/prompt-ANTQWHUF.js.map +1 -0
- package/dist/prompts/issue-prompt.txt +230 -0
- package/dist/prompts/pr-prompt.txt +35 -0
- package/dist/prompts/regular-prompt.txt +14 -0
- package/dist/run-2JCPQAX3.js +278 -0
- package/dist/run-2JCPQAX3.js.map +1 -0
- package/dist/schema/settings.schema.json +221 -0
- package/dist/start-LWVRBJ6S.js +982 -0
- package/dist/start-LWVRBJ6S.js.map +1 -0
- package/dist/terminal-3D6TUAKJ.js +16 -0
- package/dist/terminal-3D6TUAKJ.js.map +1 -0
- package/dist/test-git-XPF4SZXJ.js +52 -0
- package/dist/test-git-XPF4SZXJ.js.map +1 -0
- package/dist/test-prefix-XGFXFAYN.js +68 -0
- package/dist/test-prefix-XGFXFAYN.js.map +1 -0
- package/dist/test-tabs-JRKY3QMM.js +69 -0
- package/dist/test-tabs-JRKY3QMM.js.map +1 -0
- package/dist/test-webserver-M2I3EV4J.js +62 -0
- package/dist/test-webserver-M2I3EV4J.js.map +1 -0
- package/dist/update-3ZT2XX2G.js +79 -0
- package/dist/update-3ZT2XX2G.js.map +1 -0
- package/dist/update-notifier-QSSEB5KC.js +11 -0
- package/dist/update-notifier-QSSEB5KC.js.map +1 -0
- package/package.json +113 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
buildDevServerCommand
|
|
4
|
+
} from "./chunk-GZP4UGGM.js";
|
|
5
|
+
import {
|
|
6
|
+
ProcessManager
|
|
7
|
+
} from "./chunk-SPYPLHMK.js";
|
|
8
|
+
import {
|
|
9
|
+
logger
|
|
10
|
+
} from "./chunk-GEHQXLEI.js";
|
|
11
|
+
|
|
12
|
+
// src/lib/DevServerManager.ts
|
|
13
|
+
import { execa } from "execa";
|
|
14
|
+
import { setTimeout } from "timers/promises";
|
|
15
|
+
var DevServerManager = class {
|
|
16
|
+
constructor(processManager, options = {}) {
|
|
17
|
+
this.runningServers = /* @__PURE__ */ new Map();
|
|
18
|
+
this.processManager = processManager ?? new ProcessManager();
|
|
19
|
+
this.options = {
|
|
20
|
+
startupTimeout: options.startupTimeout ?? 3e4,
|
|
21
|
+
checkInterval: options.checkInterval ?? 1e3
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Ensure dev server is running on the specified port
|
|
26
|
+
* If not running, start it and wait for it to be ready
|
|
27
|
+
*
|
|
28
|
+
* @param worktreePath - Path to the worktree
|
|
29
|
+
* @param port - Port the server should run on
|
|
30
|
+
* @returns true if server is ready, false if startup failed/timed out
|
|
31
|
+
*/
|
|
32
|
+
async ensureServerRunning(worktreePath, port) {
|
|
33
|
+
logger.debug(`Checking if dev server is running on port ${port}...`);
|
|
34
|
+
const existingProcess = await this.processManager.detectDevServer(port);
|
|
35
|
+
if (existingProcess) {
|
|
36
|
+
logger.debug(
|
|
37
|
+
`Dev server already running on port ${port} (PID: ${existingProcess.pid})`
|
|
38
|
+
);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
logger.info(`Dev server not running on port ${port}, starting...`);
|
|
42
|
+
try {
|
|
43
|
+
await this.startDevServer(worktreePath, port);
|
|
44
|
+
return true;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
logger.error(
|
|
47
|
+
`Failed to start dev server: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
48
|
+
);
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Start dev server in background and wait for it to be ready
|
|
54
|
+
*/
|
|
55
|
+
async startDevServer(worktreePath, port) {
|
|
56
|
+
const devCommand = await buildDevServerCommand(worktreePath);
|
|
57
|
+
logger.debug(`Starting dev server with command: ${devCommand}`);
|
|
58
|
+
const serverProcess = execa("sh", ["-c", devCommand], {
|
|
59
|
+
cwd: worktreePath,
|
|
60
|
+
env: {
|
|
61
|
+
...process.env,
|
|
62
|
+
PORT: port.toString()
|
|
63
|
+
},
|
|
64
|
+
// Important: Don't inherit stdio - server runs in background
|
|
65
|
+
stdio: "ignore",
|
|
66
|
+
// Detach from parent process so it continues running
|
|
67
|
+
detached: true
|
|
68
|
+
});
|
|
69
|
+
this.runningServers.set(port, serverProcess);
|
|
70
|
+
serverProcess.unref();
|
|
71
|
+
logger.info(`Waiting for dev server to start on port ${port}...`);
|
|
72
|
+
const ready = await this.waitForServerReady(port);
|
|
73
|
+
if (!ready) {
|
|
74
|
+
throw new Error(
|
|
75
|
+
`Dev server failed to start within ${this.options.startupTimeout}ms timeout`
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
logger.success(`Dev server started successfully on port ${port}`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Wait for server to be ready by polling the port
|
|
82
|
+
*/
|
|
83
|
+
async waitForServerReady(port) {
|
|
84
|
+
const startTime = Date.now();
|
|
85
|
+
let attempts = 0;
|
|
86
|
+
while (Date.now() - startTime < this.options.startupTimeout) {
|
|
87
|
+
attempts++;
|
|
88
|
+
const processInfo = await this.processManager.detectDevServer(port);
|
|
89
|
+
if (processInfo) {
|
|
90
|
+
logger.debug(
|
|
91
|
+
`Server detected on port ${port} after ${attempts} attempts (${Date.now() - startTime}ms)`
|
|
92
|
+
);
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
await setTimeout(this.options.checkInterval);
|
|
96
|
+
}
|
|
97
|
+
logger.warn(
|
|
98
|
+
`Server did not start on port ${port} after ${this.options.startupTimeout}ms (${attempts} attempts)`
|
|
99
|
+
);
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Clean up all running server processes
|
|
104
|
+
* This should be called when the manager is being disposed
|
|
105
|
+
*/
|
|
106
|
+
async cleanup() {
|
|
107
|
+
for (const [port, serverProcess] of this.runningServers.entries()) {
|
|
108
|
+
try {
|
|
109
|
+
logger.debug(`Cleaning up server process on port ${port}`);
|
|
110
|
+
serverProcess.kill();
|
|
111
|
+
} catch (error) {
|
|
112
|
+
logger.warn(
|
|
113
|
+
`Failed to kill server process on port ${port}: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
this.runningServers.clear();
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export {
|
|
122
|
+
DevServerManager
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=chunk-W3DQTW63.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/DevServerManager.ts"],"sourcesContent":["import { execa, type ExecaChildProcess } from 'execa'\nimport { setTimeout } from 'timers/promises'\nimport { ProcessManager } from './process/ProcessManager.js'\nimport { buildDevServerCommand } from '../utils/dev-server.js'\nimport { logger } from '../utils/logger.js'\n\nexport interface DevServerManagerOptions {\n\t/**\n\t * Maximum time to wait for server to start (in milliseconds)\n\t * Default: 30000 (30 seconds)\n\t */\n\tstartupTimeout?: number\n\n\t/**\n\t * Interval between port checks (in milliseconds)\n\t * Default: 1000 (1 second)\n\t */\n\tcheckInterval?: number\n}\n\n/**\n * DevServerManager handles auto-starting and monitoring dev servers\n * Used by open/run commands to ensure dev server is running before opening browser\n */\nexport class DevServerManager {\n\tprivate readonly processManager: ProcessManager\n\tprivate readonly options: Required<DevServerManagerOptions>\n\tprivate runningServers: Map<number, ExecaChildProcess> = new Map()\n\n\tconstructor(\n\t\tprocessManager?: ProcessManager,\n\t\toptions: DevServerManagerOptions = {}\n\t) {\n\t\tthis.processManager = processManager ?? new ProcessManager()\n\t\tthis.options = {\n\t\t\tstartupTimeout: options.startupTimeout ?? 30000,\n\t\t\tcheckInterval: options.checkInterval ?? 1000,\n\t\t}\n\t}\n\n\t/**\n\t * Ensure dev server is running on the specified port\n\t * If not running, start it and wait for it to be ready\n\t *\n\t * @param worktreePath - Path to the worktree\n\t * @param port - Port the server should run on\n\t * @returns true if server is ready, false if startup failed/timed out\n\t */\n\tasync ensureServerRunning(worktreePath: string, port: number): Promise<boolean> {\n\t\tlogger.debug(`Checking if dev server is running on port ${port}...`)\n\n\t\t// Check if already running\n\t\tconst existingProcess = await this.processManager.detectDevServer(port)\n\t\tif (existingProcess) {\n\t\t\tlogger.debug(\n\t\t\t\t`Dev server already running on port ${port} (PID: ${existingProcess.pid})`\n\t\t\t)\n\t\t\treturn true\n\t\t}\n\n\t\t// Not running - start it\n\t\tlogger.info(`Dev server not running on port ${port}, starting...`)\n\n\t\ttry {\n\t\t\tawait this.startDevServer(worktreePath, port)\n\t\t\treturn true\n\t\t} catch (error) {\n\t\t\tlogger.error(\n\t\t\t\t`Failed to start dev server: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t)\n\t\t\treturn false\n\t\t}\n\t}\n\n\t/**\n\t * Start dev server in background and wait for it to be ready\n\t */\n\tprivate async startDevServer(worktreePath: string, port: number): Promise<void> {\n\t\t// Build dev server command\n\t\tconst devCommand = await buildDevServerCommand(worktreePath)\n\t\tlogger.debug(`Starting dev server with command: ${devCommand}`)\n\n\t\t// Start server in background\n\t\tconst serverProcess = execa('sh', ['-c', devCommand], {\n\t\t\tcwd: worktreePath,\n\t\t\tenv: {\n\t\t\t\t...process.env,\n\t\t\t\tPORT: port.toString(),\n\t\t\t},\n\t\t\t// Important: Don't inherit stdio - server runs in background\n\t\t\tstdio: 'ignore',\n\t\t\t// Detach from parent process so it continues running\n\t\t\tdetached: true,\n\t\t})\n\n\t\t// Store reference to prevent cleanup\n\t\tthis.runningServers.set(port, serverProcess)\n\n\t\t// Unref so parent can exit\n\t\tserverProcess.unref()\n\n\t\t// Wait for server to be ready\n\t\tlogger.info(`Waiting for dev server to start on port ${port}...`)\n\t\tconst ready = await this.waitForServerReady(port)\n\n\t\tif (!ready) {\n\t\t\tthrow new Error(\n\t\t\t\t`Dev server failed to start within ${this.options.startupTimeout}ms timeout`\n\t\t\t)\n\t\t}\n\n\t\tlogger.success(`Dev server started successfully on port ${port}`)\n\t}\n\n\t/**\n\t * Wait for server to be ready by polling the port\n\t */\n\tprivate async waitForServerReady(port: number): Promise<boolean> {\n\t\tconst startTime = Date.now()\n\t\tlet attempts = 0\n\n\t\twhile (Date.now() - startTime < this.options.startupTimeout) {\n\t\t\tattempts++\n\n\t\t\t// Check if server is listening\n\t\t\tconst processInfo = await this.processManager.detectDevServer(port)\n\n\t\t\tif (processInfo) {\n\t\t\t\tlogger.debug(\n\t\t\t\t\t`Server detected on port ${port} after ${attempts} attempts (${Date.now() - startTime}ms)`\n\t\t\t\t)\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// Wait before next check\n\t\t\tawait setTimeout(this.options.checkInterval)\n\t\t}\n\n\t\t// Timeout\n\t\tlogger.warn(\n\t\t\t`Server did not start on port ${port} after ${this.options.startupTimeout}ms (${attempts} attempts)`\n\t\t)\n\t\treturn false\n\t}\n\n\t/**\n\t * Clean up all running server processes\n\t * This should be called when the manager is being disposed\n\t */\n\tasync cleanup(): Promise<void> {\n\t\tfor (const [port, serverProcess] of this.runningServers.entries()) {\n\t\t\ttry {\n\t\t\t\tlogger.debug(`Cleaning up server process on port ${port}`)\n\t\t\t\tserverProcess.kill()\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t`Failed to kill server process on port ${port}: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\tthis.runningServers.clear()\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
detectClaudeCli,
|
|
4
|
+
generateBranchName,
|
|
5
|
+
launchClaude,
|
|
6
|
+
launchClaudeInNewTerminalWindow
|
|
7
|
+
} from "./chunk-PXZBAC2M.js";
|
|
8
|
+
import {
|
|
9
|
+
PromptTemplateManager
|
|
10
|
+
} from "./chunk-F3XBU2R7.js";
|
|
11
|
+
import {
|
|
12
|
+
SettingsManager
|
|
13
|
+
} from "./chunk-JBH2ZYYZ.js";
|
|
14
|
+
import {
|
|
15
|
+
logger
|
|
16
|
+
} from "./chunk-GEHQXLEI.js";
|
|
17
|
+
|
|
18
|
+
// src/lib/ClaudeService.ts
|
|
19
|
+
var ClaudeService = class {
|
|
20
|
+
constructor(templateManager, settingsManager) {
|
|
21
|
+
this.templateManager = templateManager ?? new PromptTemplateManager();
|
|
22
|
+
this.settingsManager = settingsManager ?? new SettingsManager();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Check if Claude CLI is available
|
|
26
|
+
*/
|
|
27
|
+
async isAvailable() {
|
|
28
|
+
return detectClaudeCli();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get the appropriate model for a workflow type
|
|
32
|
+
*/
|
|
33
|
+
getModelForWorkflow(type) {
|
|
34
|
+
if (type === "issue") {
|
|
35
|
+
return "claude-sonnet-4-20250514";
|
|
36
|
+
}
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the appropriate permission mode for a workflow type
|
|
41
|
+
*/
|
|
42
|
+
getPermissionModeForWorkflow(type) {
|
|
43
|
+
var _a;
|
|
44
|
+
if ((_a = this.settings) == null ? void 0 : _a.workflows) {
|
|
45
|
+
const workflowConfig = type === "issue" ? this.settings.workflows.issue : type === "pr" ? this.settings.workflows.pr : this.settings.workflows.regular;
|
|
46
|
+
if (workflowConfig == null ? void 0 : workflowConfig.permissionMode) {
|
|
47
|
+
return workflowConfig.permissionMode;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (type === "issue") {
|
|
51
|
+
return "acceptEdits";
|
|
52
|
+
}
|
|
53
|
+
return "default";
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Launch Claude for a specific workflow
|
|
57
|
+
*/
|
|
58
|
+
async launchForWorkflow(options) {
|
|
59
|
+
const { type, issueNumber, prNumber, title, workspacePath, port, headless = false, branchName, oneShot = "default", setArguments, executablePath } = options;
|
|
60
|
+
try {
|
|
61
|
+
this.settings ??= await this.settingsManager.loadSettings();
|
|
62
|
+
const variables = {
|
|
63
|
+
WORKSPACE_PATH: workspacePath
|
|
64
|
+
};
|
|
65
|
+
if (issueNumber !== void 0) {
|
|
66
|
+
variables.ISSUE_NUMBER = issueNumber;
|
|
67
|
+
}
|
|
68
|
+
if (prNumber !== void 0) {
|
|
69
|
+
variables.PR_NUMBER = prNumber;
|
|
70
|
+
}
|
|
71
|
+
if (title !== void 0) {
|
|
72
|
+
if (type === "issue") {
|
|
73
|
+
variables.ISSUE_TITLE = title;
|
|
74
|
+
} else if (type === "pr") {
|
|
75
|
+
variables.PR_TITLE = title;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (port !== void 0) {
|
|
79
|
+
variables.PORT = port;
|
|
80
|
+
}
|
|
81
|
+
const prompt = await this.templateManager.getPrompt(type, variables);
|
|
82
|
+
const model = this.getModelForWorkflow(type);
|
|
83
|
+
const permissionMode = this.getPermissionModeForWorkflow(type);
|
|
84
|
+
if (permissionMode === "bypassPermissions") {
|
|
85
|
+
logger.warn(
|
|
86
|
+
"\u26A0\uFE0F WARNING: Using bypassPermissions mode - Claude will execute all tool calls without confirmation. This can be dangerous. Use with caution."
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const claudeOptions = {
|
|
90
|
+
addDir: workspacePath,
|
|
91
|
+
headless
|
|
92
|
+
};
|
|
93
|
+
if (model !== void 0) {
|
|
94
|
+
claudeOptions.model = model;
|
|
95
|
+
}
|
|
96
|
+
if (permissionMode !== void 0 && permissionMode !== "default") {
|
|
97
|
+
claudeOptions.permissionMode = permissionMode;
|
|
98
|
+
}
|
|
99
|
+
if (branchName !== void 0) {
|
|
100
|
+
claudeOptions.branchName = branchName;
|
|
101
|
+
}
|
|
102
|
+
if (port !== void 0) {
|
|
103
|
+
claudeOptions.port = port;
|
|
104
|
+
}
|
|
105
|
+
if (setArguments !== void 0) {
|
|
106
|
+
claudeOptions.setArguments = setArguments;
|
|
107
|
+
}
|
|
108
|
+
if (executablePath !== void 0) {
|
|
109
|
+
claudeOptions.executablePath = executablePath;
|
|
110
|
+
}
|
|
111
|
+
logger.debug("Launching Claude for workflow", {
|
|
112
|
+
type,
|
|
113
|
+
model,
|
|
114
|
+
permissionMode,
|
|
115
|
+
headless,
|
|
116
|
+
workspacePath
|
|
117
|
+
});
|
|
118
|
+
if (headless) {
|
|
119
|
+
return await launchClaude(prompt, claudeOptions);
|
|
120
|
+
} else {
|
|
121
|
+
if (!claudeOptions.addDir) {
|
|
122
|
+
throw new Error("workspacePath required for interactive workflow launch");
|
|
123
|
+
}
|
|
124
|
+
return await launchClaudeInNewTerminalWindow(prompt, {
|
|
125
|
+
...claudeOptions,
|
|
126
|
+
workspacePath: claudeOptions.addDir,
|
|
127
|
+
oneShot
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
} catch (error) {
|
|
131
|
+
logger.error("Failed to launch Claude for workflow", { error, options });
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Generate branch name with Claude, with fallback on failure
|
|
137
|
+
*/
|
|
138
|
+
async generateBranchNameWithFallback(issueTitle, issueNumber) {
|
|
139
|
+
try {
|
|
140
|
+
return await generateBranchName(issueTitle, issueNumber);
|
|
141
|
+
} catch (error) {
|
|
142
|
+
logger.warn("Claude branch name generation failed, using fallback", { error });
|
|
143
|
+
return `feat/issue-${issueNumber}`;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export {
|
|
149
|
+
ClaudeService
|
|
150
|
+
};
|
|
151
|
+
//# sourceMappingURL=chunk-WKEWRSDB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/ClaudeService.ts"],"sourcesContent":["import { detectClaudeCli, launchClaude, launchClaudeInNewTerminalWindow, ClaudeCliOptions, generateBranchName } from '../utils/claude.js'\nimport { PromptTemplateManager, TemplateVariables } from './PromptTemplateManager.js'\nimport { SettingsManager, IloomSettings } from './SettingsManager.js'\nimport { logger } from '../utils/logger.js'\n\nexport interface ClaudeWorkflowOptions {\n\ttype: 'issue' | 'pr' | 'regular'\n\tissueNumber?: number\n\tprNumber?: number\n\ttitle?: string\n\tworkspacePath: string\n\tport?: number\n\theadless?: boolean\n\tbranchName?: string\n\toneShot?: import('../types/index.js').OneShotMode\n\tsetArguments?: string[] // Raw --set arguments to forward\n\texecutablePath?: string // Executable path to use for spin command\n}\n\nexport class ClaudeService {\n\tprivate templateManager: PromptTemplateManager\n\tprivate settingsManager: SettingsManager\n\tprivate settings?: IloomSettings\n\n\tconstructor(templateManager?: PromptTemplateManager, settingsManager?: SettingsManager) {\n\t\tthis.templateManager = templateManager ?? new PromptTemplateManager()\n\t\tthis.settingsManager = settingsManager ?? new SettingsManager()\n\t}\n\n\t/**\n\t * Check if Claude CLI is available\n\t */\n\tasync isAvailable(): Promise<boolean> {\n\t\treturn detectClaudeCli()\n\t}\n\n\t/**\n\t * Get the appropriate model for a workflow type\n\t */\n\tprivate getModelForWorkflow(type: 'issue' | 'pr' | 'regular'): string | undefined {\n\t\t// Issue workflows use claude-sonnet-4-20250514\n\t\tif (type === 'issue') {\n\t\t\treturn 'claude-sonnet-4-20250514'\n\t\t}\n\t\t// For PR and regular workflows, use Claude's default model\n\t\treturn undefined\n\t}\n\n\t/**\n\t * Get the appropriate permission mode for a workflow type\n\t */\n\tprivate getPermissionModeForWorkflow(\n\t\ttype: 'issue' | 'pr' | 'regular'\n\t): ClaudeCliOptions['permissionMode'] {\n\t\t// Check settings for configured permission mode\n\t\tif (this.settings?.workflows) {\n\t\t\tconst workflowConfig =\n\t\t\t\ttype === 'issue'\n\t\t\t\t\t? this.settings.workflows.issue\n\t\t\t\t\t: type === 'pr'\n\t\t\t\t\t\t? this.settings.workflows.pr\n\t\t\t\t\t\t: this.settings.workflows.regular\n\n\t\t\tif (workflowConfig?.permissionMode) {\n\t\t\t\treturn workflowConfig.permissionMode\n\t\t\t}\n\t\t}\n\n\t\t// Fall back to current defaults\n\t\tif (type === 'issue') {\n\t\t\treturn 'acceptEdits'\n\t\t}\n\t\t// For PR and regular workflows, use default permissions\n\t\treturn 'default'\n\t}\n\n\t/**\n\t * Launch Claude for a specific workflow\n\t */\n\tasync launchForWorkflow(options: ClaudeWorkflowOptions): Promise<string | void> {\n\t\tconst { type, issueNumber, prNumber, title, workspacePath, port, headless = false, branchName, oneShot = 'default', setArguments, executablePath } = options\n\n\t\ttry {\n\t\t\t// Load settings if not already cached\n\t\t\t// Settings are pre-validated at CLI startup, so no error handling needed here\n\t\t\tthis.settings ??= await this.settingsManager.loadSettings()\n\n\t\t\t// Build template variables\n\t\t\tconst variables: TemplateVariables = {\n\t\t\t\tWORKSPACE_PATH: workspacePath,\n\t\t\t}\n\n\t\t\tif (issueNumber !== undefined) {\n\t\t\t\tvariables.ISSUE_NUMBER = issueNumber\n\t\t\t}\n\n\t\t\tif (prNumber !== undefined) {\n\t\t\t\tvariables.PR_NUMBER = prNumber\n\t\t\t}\n\n\t\t\tif (title !== undefined) {\n\t\t\t\tif (type === 'issue') {\n\t\t\t\t\tvariables.ISSUE_TITLE = title\n\t\t\t\t} else if (type === 'pr') {\n\t\t\t\t\tvariables.PR_TITLE = title\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (port !== undefined) {\n\t\t\t\tvariables.PORT = port\n\t\t\t}\n\n\t\t\t// Get the prompt from template manager\n\t\t\tconst prompt = await this.templateManager.getPrompt(type, variables)\n\n\t\t\t// Determine model and permission mode\n\t\t\tconst model = this.getModelForWorkflow(type)\n\t\t\tconst permissionMode = this.getPermissionModeForWorkflow(type)\n\n\t\t\t// Display warning if bypassPermissions mode is used\n\t\t\tif (permissionMode === 'bypassPermissions') {\n\t\t\t\tlogger.warn(\n\t\t\t\t\t'⚠️ WARNING: Using bypassPermissions mode - Claude will execute all tool calls without confirmation. ' +\n\t\t\t\t\t\t'This can be dangerous. Use with caution.'\n\t\t\t\t)\n\t\t\t}\n\n\t\t\t// Build Claude CLI options\n\t\t\tconst claudeOptions: ClaudeCliOptions = {\n\t\t\t\taddDir: workspacePath,\n\t\t\t\theadless,\n\t\t\t}\n\n\t\t\t// Add optional model if present\n\t\t\tif (model !== undefined) {\n\t\t\t\tclaudeOptions.model = model\n\t\t\t}\n\n\t\t\t// Add permission mode if not default\n\t\t\tif (permissionMode !== undefined && permissionMode !== 'default') {\n\t\t\t\tclaudeOptions.permissionMode = permissionMode\n\t\t\t}\n\n\t\t\t// Add optional branch name for terminal coloring\n\t\t\tif (branchName !== undefined) {\n\t\t\t\tclaudeOptions.branchName = branchName\n\t\t\t}\n\n\t\t\t// Add optional port for terminal window export\n\t\t\tif (port !== undefined) {\n\t\t\t\tclaudeOptions.port = port\n\t\t\t}\n\n\t\t\t// Add optional setArguments for forwarding\n\t\t\tif (setArguments !== undefined) {\n\t\t\t\tclaudeOptions.setArguments = setArguments\n\t\t\t}\n\n\t\t\t// Add optional executablePath for spin command\n\t\t\tif (executablePath !== undefined) {\n\t\t\t\tclaudeOptions.executablePath = executablePath\n\t\t\t}\n\n\t\t\tlogger.debug('Launching Claude for workflow', {\n\t\t\t\ttype,\n\t\t\t\tmodel,\n\t\t\t\tpermissionMode,\n\t\t\t\theadless,\n\t\t\t\tworkspacePath,\n\t\t\t})\n\n\t\t\t// Launch Claude\n\t\t\tif (headless) {\n\t\t\t\t// Headless mode: use simple launchClaude\n\t\t\t\treturn await launchClaude(prompt, claudeOptions)\n\t\t\t} else {\n\t\t\t\t// Interactive workflow mode: use terminal window launcher\n\t\t\t\t// This is the \"end of il start\" behavior\n\t\t\t\tif (!claudeOptions.addDir) {\n\t\t\t\t\tthrow new Error('workspacePath required for interactive workflow launch')\n\t\t\t\t}\n\n\t\t\t\treturn await launchClaudeInNewTerminalWindow(prompt, {\n\t\t\t\t\t...claudeOptions,\n\t\t\t\t\tworkspacePath: claudeOptions.addDir,\n\t\t\t\t\toneShot,\n\t\t\t\t})\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger.error('Failed to launch Claude for workflow', { error, options })\n\t\t\tthrow error\n\t\t}\n\t}\n\n\t/**\n\t * Generate branch name with Claude, with fallback on failure\n\t */\n\tasync generateBranchNameWithFallback(issueTitle: string, issueNumber: number): Promise<string> {\n\t\ttry {\n\t\t\treturn await generateBranchName(issueTitle, issueNumber)\n\t\t} catch (error) {\n\t\t\tlogger.warn('Claude branch name generation failed, using fallback', { error })\n\t\t\treturn `feat/issue-${issueNumber}`\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ClaudeService
|
|
4
|
+
} from "./chunk-WKEWRSDB.js";
|
|
5
|
+
import {
|
|
6
|
+
logger
|
|
7
|
+
} from "./chunk-GEHQXLEI.js";
|
|
8
|
+
|
|
9
|
+
// src/lib/ClaudeContextManager.ts
|
|
10
|
+
var ClaudeContextManager = class {
|
|
11
|
+
constructor(claudeService, _promptTemplateManager, settingsManager) {
|
|
12
|
+
this.claudeService = claudeService ?? new ClaudeService(void 0, settingsManager);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Prepare context for Claude launch
|
|
16
|
+
* Placeholder for future .claude-context.md generation (Issue #11)
|
|
17
|
+
*/
|
|
18
|
+
async prepareContext(context) {
|
|
19
|
+
if (!context.workspacePath) {
|
|
20
|
+
throw new Error("Workspace path is required");
|
|
21
|
+
}
|
|
22
|
+
if (context.type === "issue" && typeof context.identifier !== "number") {
|
|
23
|
+
throw new Error("Issue identifier must be a number");
|
|
24
|
+
}
|
|
25
|
+
if (context.type === "pr" && typeof context.identifier !== "number") {
|
|
26
|
+
throw new Error("PR identifier must be a number");
|
|
27
|
+
}
|
|
28
|
+
logger.debug("Context prepared", { context });
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Launch Claude with the prepared context
|
|
32
|
+
*/
|
|
33
|
+
async launchWithContext(context, headless = false) {
|
|
34
|
+
await this.prepareContext(context);
|
|
35
|
+
const workflowOptions = {
|
|
36
|
+
type: context.type,
|
|
37
|
+
workspacePath: context.workspacePath,
|
|
38
|
+
...context.port !== void 0 && { port: context.port },
|
|
39
|
+
headless,
|
|
40
|
+
oneShot: context.oneShot ?? "default"
|
|
41
|
+
};
|
|
42
|
+
if (context.title !== void 0) {
|
|
43
|
+
workflowOptions.title = context.title;
|
|
44
|
+
}
|
|
45
|
+
if (context.branchName !== void 0) {
|
|
46
|
+
workflowOptions.branchName = context.branchName;
|
|
47
|
+
}
|
|
48
|
+
if (context.setArguments !== void 0) {
|
|
49
|
+
workflowOptions.setArguments = context.setArguments;
|
|
50
|
+
}
|
|
51
|
+
if (context.executablePath !== void 0) {
|
|
52
|
+
workflowOptions.executablePath = context.executablePath;
|
|
53
|
+
}
|
|
54
|
+
if (context.type === "issue") {
|
|
55
|
+
workflowOptions.issueNumber = context.identifier;
|
|
56
|
+
} else if (context.type === "pr") {
|
|
57
|
+
workflowOptions.prNumber = context.identifier;
|
|
58
|
+
}
|
|
59
|
+
return this.claudeService.launchForWorkflow(workflowOptions);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export {
|
|
64
|
+
ClaudeContextManager
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=chunk-Y7SAGNUT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/ClaudeContextManager.ts"],"sourcesContent":["import { ClaudeService, ClaudeWorkflowOptions } from './ClaudeService.js'\nimport { PromptTemplateManager } from './PromptTemplateManager.js'\nimport { logger } from '../utils/logger.js'\n\nexport interface ClaudeContext {\n\ttype: 'issue' | 'pr' | 'regular'\n\tidentifier: number | string\n\ttitle?: string\n\tworkspacePath: string\n\tport?: number\n\tbranchName?: string\n\toneShot?: import('../types/index.js').OneShotMode\n\tsetArguments?: string[] // Raw --set arguments to forward\n\texecutablePath?: string // Executable path to use for spin command\n}\n\nexport class ClaudeContextManager {\n\tprivate claudeService: ClaudeService\n\n\tconstructor(claudeService?: ClaudeService, _promptTemplateManager?: PromptTemplateManager, settingsManager?: import('./SettingsManager.js').SettingsManager) {\n\t\tthis.claudeService = claudeService ?? new ClaudeService(undefined, settingsManager)\n\t\t// promptTemplateManager is accepted for dependency injection but not used yet\n\t\t// Will be used in Issue #11 for .claude-context.md generation\n\t}\n\n\t/**\n\t * Prepare context for Claude launch\n\t * Placeholder for future .claude-context.md generation (Issue #11)\n\t */\n\tasync prepareContext(context: ClaudeContext): Promise<void> {\n\t\t// Validate context object\n\t\tif (!context.workspacePath) {\n\t\t\tthrow new Error('Workspace path is required')\n\t\t}\n\n\t\tif (context.type === 'issue' && typeof context.identifier !== 'number') {\n\t\t\tthrow new Error('Issue identifier must be a number')\n\t\t}\n\n\t\tif (context.type === 'pr' && typeof context.identifier !== 'number') {\n\t\t\tthrow new Error('PR identifier must be a number')\n\t\t}\n\n\t\tlogger.debug('Context prepared', { context })\n\t\t// Future: Generate .claude-context.md file in workspace\n\t}\n\n\t/**\n\t * Launch Claude with the prepared context\n\t */\n\tasync launchWithContext(context: ClaudeContext, headless: boolean = false): Promise<string | void> {\n\t\t// Prepare context first\n\t\tawait this.prepareContext(context)\n\n\t\t// Convert ClaudeContext to ClaudeWorkflowOptions\n\t\tconst workflowOptions: ClaudeWorkflowOptions = {\n\t\t\ttype: context.type,\n\t\t\tworkspacePath: context.workspacePath,\n\t\t\t...(context.port !== undefined && { port: context.port }),\n\t\t\theadless,\n\t\t\toneShot: context.oneShot ?? 'default',\n\t\t}\n\n\t\t// Add optional title if present\n\t\tif (context.title !== undefined) {\n\t\t\tworkflowOptions.title = context.title\n\t\t}\n\n\t\t// Add optional branch name if present\n\t\tif (context.branchName !== undefined) {\n\t\t\tworkflowOptions.branchName = context.branchName\n\t\t}\n\n\t\t// Add optional setArguments if present\n\t\tif (context.setArguments !== undefined) {\n\t\t\tworkflowOptions.setArguments = context.setArguments\n\t\t}\n\n\t\t// Add optional executablePath if present\n\t\tif (context.executablePath !== undefined) {\n\t\t\tworkflowOptions.executablePath = context.executablePath\n\t\t}\n\n\t\t// Set issue or PR number based on type\n\t\tif (context.type === 'issue') {\n\t\t\tworkflowOptions.issueNumber = context.identifier as number\n\t\t} else if (context.type === 'pr') {\n\t\t\tworkflowOptions.prNumber = context.identifier as number\n\t\t}\n\n\t\t// Delegate to Claude service\n\t\treturn this.claudeService.launchForWorkflow(workflowOptions)\n\t}\n}\n"],"mappings":";;;;;;;;;AAgBO,IAAM,uBAAN,MAA2B;AAAA,EAGjC,YAAY,eAA+B,wBAAgD,iBAAkE;AAC5J,SAAK,gBAAgB,iBAAiB,IAAI,cAAc,QAAW,eAAe;AAAA,EAGnF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,SAAuC;AAE3D,QAAI,CAAC,QAAQ,eAAe;AAC3B,YAAM,IAAI,MAAM,4BAA4B;AAAA,IAC7C;AAEA,QAAI,QAAQ,SAAS,WAAW,OAAO,QAAQ,eAAe,UAAU;AACvE,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACpD;AAEA,QAAI,QAAQ,SAAS,QAAQ,OAAO,QAAQ,eAAe,UAAU;AACpE,YAAM,IAAI,MAAM,gCAAgC;AAAA,IACjD;AAEA,WAAO,MAAM,oBAAoB,EAAE,QAAQ,CAAC;AAAA,EAE7C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,SAAwB,WAAoB,OAA+B;AAElG,UAAM,KAAK,eAAe,OAAO;AAGjC,UAAM,kBAAyC;AAAA,MAC9C,MAAM,QAAQ;AAAA,MACd,eAAe,QAAQ;AAAA,MACvB,GAAI,QAAQ,SAAS,UAAa,EAAE,MAAM,QAAQ,KAAK;AAAA,MACvD;AAAA,MACA,SAAS,QAAQ,WAAW;AAAA,IAC7B;AAGA,QAAI,QAAQ,UAAU,QAAW;AAChC,sBAAgB,QAAQ,QAAQ;AAAA,IACjC;AAGA,QAAI,QAAQ,eAAe,QAAW;AACrC,sBAAgB,aAAa,QAAQ;AAAA,IACtC;AAGA,QAAI,QAAQ,iBAAiB,QAAW;AACvC,sBAAgB,eAAe,QAAQ;AAAA,IACxC;AAGA,QAAI,QAAQ,mBAAmB,QAAW;AACzC,sBAAgB,iBAAiB,QAAQ;AAAA,IAC1C;AAGA,QAAI,QAAQ,SAAS,SAAS;AAC7B,sBAAgB,cAAc,QAAQ;AAAA,IACvC,WAAW,QAAQ,SAAS,MAAM;AACjC,sBAAgB,WAAW,QAAQ;AAAA,IACpC;AAGA,WAAO,KAAK,cAAc,kBAAkB,eAAe;AAAA,EAC5D;AACD;","names":[]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/utils/browser.ts
|
|
4
|
+
import { execa } from "execa";
|
|
5
|
+
function detectPlatform() {
|
|
6
|
+
const platform = process.platform;
|
|
7
|
+
if (platform === "darwin" || platform === "linux" || platform === "win32") {
|
|
8
|
+
return platform;
|
|
9
|
+
}
|
|
10
|
+
throw new Error(
|
|
11
|
+
`Unsupported platform: ${platform}. Browser opening is only supported on macOS, Linux, and Windows.`
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
function getBrowserCommand(platform) {
|
|
15
|
+
switch (platform) {
|
|
16
|
+
case "darwin":
|
|
17
|
+
return { command: "open", args: (url) => [url] };
|
|
18
|
+
case "linux":
|
|
19
|
+
return { command: "xdg-open", args: (url) => [url] };
|
|
20
|
+
case "win32":
|
|
21
|
+
return { command: "cmd", args: (url) => ["/c", "start", url] };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async function openBrowser(url) {
|
|
25
|
+
try {
|
|
26
|
+
const platform = detectPlatform();
|
|
27
|
+
const { command, args } = getBrowserCommand(platform);
|
|
28
|
+
await execa(command, args(url));
|
|
29
|
+
} catch (error) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`Failed to open browser: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
openBrowser
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=chunk-YETJNRQM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/browser.ts"],"sourcesContent":["import { execa } from 'execa'\n\nexport type Platform = 'darwin' | 'linux' | 'win32'\n\n/**\n * Detect the current platform\n * @returns Platform type\n * @throws Error if platform is unsupported\n */\nexport function detectPlatform(): Platform {\n\tconst platform = process.platform\n\n\tif (platform === 'darwin' || platform === 'linux' || platform === 'win32') {\n\t\treturn platform\n\t}\n\n\tthrow new Error(\n\t\t`Unsupported platform: ${platform}. Browser opening is only supported on macOS, Linux, and Windows.`\n\t)\n}\n\n/**\n * Get the browser command for the given platform\n * @param platform - The platform type\n * @returns Command to open browser\n */\nfunction getBrowserCommand(platform: Platform): { command: string; args: (url: string) => string[] } {\n\tswitch (platform) {\n\t\tcase 'darwin':\n\t\t\treturn { command: 'open', args: (url) => [url] }\n\t\tcase 'linux':\n\t\t\treturn { command: 'xdg-open', args: (url) => [url] }\n\t\tcase 'win32':\n\t\t\treturn { command: 'cmd', args: (url) => ['/c', 'start', url] }\n\t}\n}\n\n/**\n * Open a URL in the default browser\n * @param url - The URL to open\n * @throws Error if browser fails to open\n */\nexport async function openBrowser(url: string): Promise<void> {\n\ttry {\n\t\tconst platform = detectPlatform()\n\t\tconst { command, args } = getBrowserCommand(platform)\n\t\tawait execa(command, args(url))\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to open browser: ${error instanceof Error ? error.message : 'Unknown error'}`\n\t\t)\n\t}\n}\n"],"mappings":";;;AAAA,SAAS,aAAa;AASf,SAAS,iBAA2B;AAC1C,QAAM,WAAW,QAAQ;AAEzB,MAAI,aAAa,YAAY,aAAa,WAAW,aAAa,SAAS;AAC1E,WAAO;AAAA,EACR;AAEA,QAAM,IAAI;AAAA,IACT,yBAAyB,QAAQ;AAAA,EAClC;AACD;AAOA,SAAS,kBAAkB,UAA0E;AACpG,UAAQ,UAAU;AAAA,IACjB,KAAK;AACJ,aAAO,EAAE,SAAS,QAAQ,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE;AAAA,IAChD,KAAK;AACJ,aAAO,EAAE,SAAS,YAAY,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE;AAAA,IACpD,KAAK;AACJ,aAAO,EAAE,SAAS,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,SAAS,GAAG,EAAE;AAAA,EAC/D;AACD;AAOA,eAAsB,YAAY,KAA4B;AAC7D,MAAI;AACH,UAAM,WAAW,eAAe;AAChC,UAAM,EAAE,SAAS,KAAK,IAAI,kBAAkB,QAAQ;AACpD,UAAM,MAAM,SAAS,KAAK,GAAG,CAAC;AAAA,EAC/B,SAAS,OAAO;AACf,UAAM,IAAI;AAAA,MACT,2BAA2B,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IACpF;AAAA,EACD;AACD;","names":[]}
|