@trops/dash-core 0.1.48 → 0.1.49
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/dist/electron/index.js +440 -20
- package/dist/electron/index.js.map +1 -1
- package/package.json +1 -1
package/dist/electron/index.js
CHANGED
|
@@ -22,7 +22,8 @@ var require$$2$4 = require('algoliasearch');
|
|
|
22
22
|
var require$$3$2 = require('node:path');
|
|
23
23
|
var require$$0$3 = require('openai');
|
|
24
24
|
require('live-plugin-manager');
|
|
25
|
-
var require$$0$
|
|
25
|
+
var require$$0$5 = require('@anthropic-ai/sdk');
|
|
26
|
+
var require$$0$4 = require('child_process');
|
|
26
27
|
var require$$2$6 = require('os');
|
|
27
28
|
var require$$3$3 = require('adm-zip');
|
|
28
29
|
var require$$4$1 = require('url');
|
|
@@ -525,23 +526,27 @@ var openaiEvents$1 = {
|
|
|
525
526
|
const LLM_SEND_MESSAGE$1 = "llm-send-message";
|
|
526
527
|
const LLM_ABORT_REQUEST$1 = "llm-abort-request";
|
|
527
528
|
const LLM_LIST_CONNECTED_TOOLS$1 = "llm-list-connected-tools";
|
|
529
|
+
const LLM_CHECK_CLI_AVAILABLE$1 = "llm-check-cli-available";
|
|
530
|
+
const LLM_CLEAR_CLI_SESSION$1 = "llm-clear-cli-session";
|
|
528
531
|
|
|
529
532
|
// --- Main → Renderer (send) ---
|
|
530
|
-
const LLM_STREAM_DELTA$
|
|
531
|
-
const LLM_STREAM_TOOL_CALL$
|
|
532
|
-
const LLM_STREAM_TOOL_RESULT$
|
|
533
|
-
const LLM_STREAM_COMPLETE$
|
|
534
|
-
const LLM_STREAM_ERROR$
|
|
533
|
+
const LLM_STREAM_DELTA$3 = "llm-stream-delta";
|
|
534
|
+
const LLM_STREAM_TOOL_CALL$3 = "llm-stream-tool-call";
|
|
535
|
+
const LLM_STREAM_TOOL_RESULT$3 = "llm-stream-tool-result";
|
|
536
|
+
const LLM_STREAM_COMPLETE$3 = "llm-stream-complete";
|
|
537
|
+
const LLM_STREAM_ERROR$3 = "llm-stream-error";
|
|
535
538
|
|
|
536
539
|
var llmEvents$1 = {
|
|
537
540
|
LLM_SEND_MESSAGE: LLM_SEND_MESSAGE$1,
|
|
538
541
|
LLM_ABORT_REQUEST: LLM_ABORT_REQUEST$1,
|
|
539
542
|
LLM_LIST_CONNECTED_TOOLS: LLM_LIST_CONNECTED_TOOLS$1,
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
543
|
+
LLM_CHECK_CLI_AVAILABLE: LLM_CHECK_CLI_AVAILABLE$1,
|
|
544
|
+
LLM_CLEAR_CLI_SESSION: LLM_CLEAR_CLI_SESSION$1,
|
|
545
|
+
LLM_STREAM_DELTA: LLM_STREAM_DELTA$3,
|
|
546
|
+
LLM_STREAM_TOOL_CALL: LLM_STREAM_TOOL_CALL$3,
|
|
547
|
+
LLM_STREAM_TOOL_RESULT: LLM_STREAM_TOOL_RESULT$3,
|
|
548
|
+
LLM_STREAM_COMPLETE: LLM_STREAM_COMPLETE$3,
|
|
549
|
+
LLM_STREAM_ERROR: LLM_STREAM_ERROR$3,
|
|
545
550
|
};
|
|
546
551
|
|
|
547
552
|
/**
|
|
@@ -4809,28 +4814,28 @@ const fs$5 = require$$2;
|
|
|
4809
4814
|
/**
|
|
4810
4815
|
* Cached shell PATH result (resolved once, reused for all spawns).
|
|
4811
4816
|
*/
|
|
4812
|
-
let _shellPath = null;
|
|
4817
|
+
let _shellPath$1 = null;
|
|
4813
4818
|
|
|
4814
4819
|
/**
|
|
4815
4820
|
* Get the user's full shell PATH (including nvm, homebrew, volta, etc.).
|
|
4816
4821
|
* Electron GUI apps on macOS don't inherit the shell PATH, so we
|
|
4817
4822
|
* resolve it once by invoking a login shell.
|
|
4818
4823
|
*/
|
|
4819
|
-
function getShellPath() {
|
|
4820
|
-
if (_shellPath !== null) return _shellPath;
|
|
4824
|
+
function getShellPath$1() {
|
|
4825
|
+
if (_shellPath$1 !== null) return _shellPath$1;
|
|
4821
4826
|
|
|
4822
4827
|
try {
|
|
4823
4828
|
const { execSync } = require("child_process");
|
|
4824
4829
|
const shell = process.env.SHELL || "/bin/bash";
|
|
4825
|
-
_shellPath = execSync(`${shell} -ilc 'echo -n "$PATH"'`, {
|
|
4830
|
+
_shellPath$1 = execSync(`${shell} -ilc 'echo -n "$PATH"'`, {
|
|
4826
4831
|
encoding: "utf8",
|
|
4827
4832
|
timeout: 5000,
|
|
4828
4833
|
});
|
|
4829
4834
|
} catch {
|
|
4830
|
-
_shellPath = process.env.PATH || "";
|
|
4835
|
+
_shellPath$1 = process.env.PATH || "";
|
|
4831
4836
|
}
|
|
4832
4837
|
|
|
4833
|
-
return _shellPath;
|
|
4838
|
+
return _shellPath$1;
|
|
4834
4839
|
}
|
|
4835
4840
|
|
|
4836
4841
|
/**
|
|
@@ -4948,7 +4953,7 @@ const mcpController$2 = {
|
|
|
4948
4953
|
const env = { ...process.env };
|
|
4949
4954
|
// Ensure full shell PATH is available (Electron GUI apps
|
|
4950
4955
|
// on macOS don't inherit nvm/homebrew paths)
|
|
4951
|
-
env.PATH = getShellPath();
|
|
4956
|
+
env.PATH = getShellPath$1();
|
|
4952
4957
|
if (mcpConfig.envMapping && credentials) {
|
|
4953
4958
|
Object.entries(mcpConfig.envMapping).forEach(
|
|
4954
4959
|
([envVar, credentialKey]) => {
|
|
@@ -6317,6 +6322,392 @@ const pluginController$1 = {
|
|
|
6317
6322
|
|
|
6318
6323
|
var pluginController_1 = pluginController$1;
|
|
6319
6324
|
|
|
6325
|
+
/**
|
|
6326
|
+
* cliController.js
|
|
6327
|
+
*
|
|
6328
|
+
* Manages Claude Code CLI (`claude -p`) as an alternative LLM backend.
|
|
6329
|
+
* Spawns the CLI subprocess, parses stream-json NDJSON output, and emits
|
|
6330
|
+
* the same LLM_STREAM_* events as the Anthropic SDK path.
|
|
6331
|
+
*
|
|
6332
|
+
* Users with a Claude Pro/Max subscription and Claude Code installed
|
|
6333
|
+
* can use the Chat widget without a separate API key.
|
|
6334
|
+
*/
|
|
6335
|
+
|
|
6336
|
+
const { spawn, execSync } = require$$0$4;
|
|
6337
|
+
const {
|
|
6338
|
+
LLM_STREAM_DELTA: LLM_STREAM_DELTA$2,
|
|
6339
|
+
LLM_STREAM_TOOL_CALL: LLM_STREAM_TOOL_CALL$2,
|
|
6340
|
+
LLM_STREAM_TOOL_RESULT: LLM_STREAM_TOOL_RESULT$2,
|
|
6341
|
+
LLM_STREAM_COMPLETE: LLM_STREAM_COMPLETE$2,
|
|
6342
|
+
LLM_STREAM_ERROR: LLM_STREAM_ERROR$2,
|
|
6343
|
+
} = llmEvents$1;
|
|
6344
|
+
|
|
6345
|
+
/**
|
|
6346
|
+
* Cached shell PATH result (resolved once, reused for all spawns).
|
|
6347
|
+
* Same pattern as mcpController.js.
|
|
6348
|
+
*/
|
|
6349
|
+
let _shellPath = null;
|
|
6350
|
+
|
|
6351
|
+
function getShellPath() {
|
|
6352
|
+
if (_shellPath !== null) return _shellPath;
|
|
6353
|
+
|
|
6354
|
+
try {
|
|
6355
|
+
const shell = process.env.SHELL || "/bin/bash";
|
|
6356
|
+
_shellPath = execSync(`${shell} -ilc 'echo -n "$PATH"'`, {
|
|
6357
|
+
encoding: "utf8",
|
|
6358
|
+
timeout: 5000,
|
|
6359
|
+
});
|
|
6360
|
+
} catch {
|
|
6361
|
+
_shellPath = process.env.PATH || "";
|
|
6362
|
+
}
|
|
6363
|
+
|
|
6364
|
+
return _shellPath;
|
|
6365
|
+
}
|
|
6366
|
+
|
|
6367
|
+
/**
|
|
6368
|
+
* Cached CLI binary path (resolved once via `which claude`).
|
|
6369
|
+
*/
|
|
6370
|
+
let _cliBinaryPath = undefined; // undefined = not yet checked
|
|
6371
|
+
|
|
6372
|
+
function resolveCliBinary() {
|
|
6373
|
+
if (_cliBinaryPath !== undefined) return _cliBinaryPath;
|
|
6374
|
+
|
|
6375
|
+
try {
|
|
6376
|
+
const fullPath = getShellPath();
|
|
6377
|
+
_cliBinaryPath = execSync("which claude", {
|
|
6378
|
+
encoding: "utf8",
|
|
6379
|
+
timeout: 5000,
|
|
6380
|
+
env: { ...process.env, PATH: fullPath },
|
|
6381
|
+
}).trim();
|
|
6382
|
+
} catch {
|
|
6383
|
+
_cliBinaryPath = null;
|
|
6384
|
+
}
|
|
6385
|
+
|
|
6386
|
+
return _cliBinaryPath;
|
|
6387
|
+
}
|
|
6388
|
+
|
|
6389
|
+
/**
|
|
6390
|
+
* Active CLI processes for abort support.
|
|
6391
|
+
* Map<requestId, ChildProcess>
|
|
6392
|
+
*/
|
|
6393
|
+
const activeProcesses = new Map();
|
|
6394
|
+
|
|
6395
|
+
/**
|
|
6396
|
+
* Session IDs for conversation continuity.
|
|
6397
|
+
* Map<widgetUuid, sessionId>
|
|
6398
|
+
*/
|
|
6399
|
+
const sessions = new Map();
|
|
6400
|
+
|
|
6401
|
+
/**
|
|
6402
|
+
* Send events safely to a window.
|
|
6403
|
+
*/
|
|
6404
|
+
function safeSend(win, channel, data) {
|
|
6405
|
+
if (win && !win.isDestroyed()) {
|
|
6406
|
+
win.webContents.send(channel, data);
|
|
6407
|
+
}
|
|
6408
|
+
}
|
|
6409
|
+
|
|
6410
|
+
const cliController$2 = {
|
|
6411
|
+
/**
|
|
6412
|
+
* isAvailable
|
|
6413
|
+
* Check if the Claude Code CLI is installed and accessible.
|
|
6414
|
+
*
|
|
6415
|
+
* @returns {{ available: boolean, path?: string }}
|
|
6416
|
+
*/
|
|
6417
|
+
isAvailable: () => {
|
|
6418
|
+
const binaryPath = resolveCliBinary();
|
|
6419
|
+
if (binaryPath) {
|
|
6420
|
+
return { available: true, path: binaryPath };
|
|
6421
|
+
}
|
|
6422
|
+
return { available: false };
|
|
6423
|
+
},
|
|
6424
|
+
|
|
6425
|
+
/**
|
|
6426
|
+
* sendMessage
|
|
6427
|
+
* Stream a response from the Claude Code CLI with NDJSON parsing.
|
|
6428
|
+
*
|
|
6429
|
+
* @param {BrowserWindow} win - the window to send stream events to
|
|
6430
|
+
* @param {string} requestId - unique ID for this request
|
|
6431
|
+
* @param {object} params - { model, messages, systemPrompt, maxToolRounds, widgetUuid }
|
|
6432
|
+
*/
|
|
6433
|
+
sendMessage: async (win, requestId, params) => {
|
|
6434
|
+
const { model, messages, systemPrompt, widgetUuid } = params;
|
|
6435
|
+
|
|
6436
|
+
const binaryPath = resolveCliBinary();
|
|
6437
|
+
if (!binaryPath) {
|
|
6438
|
+
safeSend(win, LLM_STREAM_ERROR$2, {
|
|
6439
|
+
requestId,
|
|
6440
|
+
error:
|
|
6441
|
+
"Claude Code CLI not found. Install from https://claude.ai/download",
|
|
6442
|
+
code: "CLI_NOT_FOUND",
|
|
6443
|
+
});
|
|
6444
|
+
return;
|
|
6445
|
+
}
|
|
6446
|
+
|
|
6447
|
+
// Build CLI args
|
|
6448
|
+
const args = ["-p", "--output-format", "stream-json", "--verbose"];
|
|
6449
|
+
|
|
6450
|
+
if (model) {
|
|
6451
|
+
args.push("--model", model);
|
|
6452
|
+
}
|
|
6453
|
+
|
|
6454
|
+
if (systemPrompt) {
|
|
6455
|
+
args.push("--append-system-prompt", systemPrompt);
|
|
6456
|
+
}
|
|
6457
|
+
|
|
6458
|
+
// Resume existing session for conversation continuity
|
|
6459
|
+
const sessionId = widgetUuid ? sessions.get(widgetUuid) : null;
|
|
6460
|
+
if (sessionId) {
|
|
6461
|
+
args.push("--resume", sessionId);
|
|
6462
|
+
}
|
|
6463
|
+
|
|
6464
|
+
// Extract the user message (last user message in the array)
|
|
6465
|
+
const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
|
|
6466
|
+
const userText =
|
|
6467
|
+
typeof lastUserMsg?.content === "string"
|
|
6468
|
+
? lastUserMsg.content
|
|
6469
|
+
: Array.isArray(lastUserMsg?.content)
|
|
6470
|
+
? lastUserMsg.content
|
|
6471
|
+
.filter((b) => b.type === "text")
|
|
6472
|
+
.map((b) => b.text)
|
|
6473
|
+
.join("\n")
|
|
6474
|
+
: "";
|
|
6475
|
+
|
|
6476
|
+
if (!userText) {
|
|
6477
|
+
safeSend(win, LLM_STREAM_ERROR$2, {
|
|
6478
|
+
requestId,
|
|
6479
|
+
error: "No user message to send.",
|
|
6480
|
+
code: "CLI_ERROR",
|
|
6481
|
+
});
|
|
6482
|
+
return;
|
|
6483
|
+
}
|
|
6484
|
+
|
|
6485
|
+
try {
|
|
6486
|
+
const fullPath = getShellPath();
|
|
6487
|
+
const child = spawn(binaryPath, args, {
|
|
6488
|
+
env: { ...process.env, PATH: fullPath },
|
|
6489
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
6490
|
+
});
|
|
6491
|
+
|
|
6492
|
+
activeProcesses.set(requestId, child);
|
|
6493
|
+
|
|
6494
|
+
// Pipe user message via stdin (not visible in ps)
|
|
6495
|
+
child.stdin.write(userText);
|
|
6496
|
+
child.stdin.end();
|
|
6497
|
+
|
|
6498
|
+
let stdoutBuffer = "";
|
|
6499
|
+
let stderrBuffer = "";
|
|
6500
|
+
let capturedSessionId = null;
|
|
6501
|
+
let retried = false;
|
|
6502
|
+
|
|
6503
|
+
// Track active tool calls for mapping results
|
|
6504
|
+
const activeToolCalls = new Map();
|
|
6505
|
+
|
|
6506
|
+
child.stdout.on("data", (chunk) => {
|
|
6507
|
+
stdoutBuffer += chunk.toString();
|
|
6508
|
+
|
|
6509
|
+
// Process complete lines
|
|
6510
|
+
const lines = stdoutBuffer.split("\n");
|
|
6511
|
+
stdoutBuffer = lines.pop(); // keep incomplete line in buffer
|
|
6512
|
+
|
|
6513
|
+
for (const line of lines) {
|
|
6514
|
+
if (!line.trim()) continue;
|
|
6515
|
+
|
|
6516
|
+
let parsed;
|
|
6517
|
+
try {
|
|
6518
|
+
parsed = JSON.parse(line);
|
|
6519
|
+
} catch {
|
|
6520
|
+
console.warn("[cliController] Skipping invalid JSON line:", line);
|
|
6521
|
+
continue;
|
|
6522
|
+
}
|
|
6523
|
+
|
|
6524
|
+
// Capture session ID from any message that has it
|
|
6525
|
+
if (parsed.session_id && widgetUuid) {
|
|
6526
|
+
capturedSessionId = parsed.session_id;
|
|
6527
|
+
sessions.set(widgetUuid, capturedSessionId);
|
|
6528
|
+
}
|
|
6529
|
+
|
|
6530
|
+
// Map CLI stream-json events to IPC events
|
|
6531
|
+
if (parsed.type === "content_block_delta") {
|
|
6532
|
+
if (parsed.delta?.type === "text_delta" && parsed.delta.text) {
|
|
6533
|
+
safeSend(win, LLM_STREAM_DELTA$2, {
|
|
6534
|
+
requestId,
|
|
6535
|
+
text: parsed.delta.text,
|
|
6536
|
+
});
|
|
6537
|
+
} else if (parsed.delta?.type === "input_json_delta") {
|
|
6538
|
+
// Update tool input incrementally
|
|
6539
|
+
const tc = activeToolCalls.get(parsed.index);
|
|
6540
|
+
if (tc) {
|
|
6541
|
+
tc.partialInput =
|
|
6542
|
+
(tc.partialInput || "") + (parsed.delta.partial_json || "");
|
|
6543
|
+
}
|
|
6544
|
+
}
|
|
6545
|
+
} else if (parsed.type === "content_block_start") {
|
|
6546
|
+
if (parsed.content_block?.type === "tool_use") {
|
|
6547
|
+
const toolBlock = parsed.content_block;
|
|
6548
|
+
activeToolCalls.set(parsed.index, {
|
|
6549
|
+
toolUseId: toolBlock.id,
|
|
6550
|
+
toolName: toolBlock.name,
|
|
6551
|
+
partialInput: "",
|
|
6552
|
+
});
|
|
6553
|
+
safeSend(win, LLM_STREAM_TOOL_CALL$2, {
|
|
6554
|
+
requestId,
|
|
6555
|
+
toolUseId: toolBlock.id,
|
|
6556
|
+
toolName: toolBlock.name,
|
|
6557
|
+
serverName: "Claude Code",
|
|
6558
|
+
input: toolBlock.input || {},
|
|
6559
|
+
});
|
|
6560
|
+
}
|
|
6561
|
+
} else if (parsed.type === "content_block_stop") {
|
|
6562
|
+
// Tool call completed — try to parse the accumulated input
|
|
6563
|
+
const tc = activeToolCalls.get(parsed.index);
|
|
6564
|
+
if (tc && tc.partialInput) {
|
|
6565
|
+
try {
|
|
6566
|
+
tc.finalInput = JSON.parse(tc.partialInput);
|
|
6567
|
+
} catch {
|
|
6568
|
+
tc.finalInput = tc.partialInput;
|
|
6569
|
+
}
|
|
6570
|
+
}
|
|
6571
|
+
} else if (parsed.type === "message_stop") {
|
|
6572
|
+
// Individual message completed (may be followed by more in tool-use loops)
|
|
6573
|
+
} else if (parsed.type === "result") {
|
|
6574
|
+
// Final result — conversation complete
|
|
6575
|
+
const content = [];
|
|
6576
|
+
if (parsed.result) {
|
|
6577
|
+
content.push({ type: "text", text: parsed.result });
|
|
6578
|
+
}
|
|
6579
|
+
|
|
6580
|
+
safeSend(win, LLM_STREAM_COMPLETE$2, {
|
|
6581
|
+
requestId,
|
|
6582
|
+
content,
|
|
6583
|
+
stopReason: parsed.stop_reason || "end_turn",
|
|
6584
|
+
usage: parsed.usage || {},
|
|
6585
|
+
});
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6588
|
+
});
|
|
6589
|
+
|
|
6590
|
+
child.stderr.on("data", (chunk) => {
|
|
6591
|
+
stderrBuffer += chunk.toString();
|
|
6592
|
+
});
|
|
6593
|
+
|
|
6594
|
+
child.on("error", (err) => {
|
|
6595
|
+
activeProcesses.delete(requestId);
|
|
6596
|
+
safeSend(win, LLM_STREAM_ERROR$2, {
|
|
6597
|
+
requestId,
|
|
6598
|
+
error: `Failed to start Claude CLI: ${err.message}`,
|
|
6599
|
+
code: "CLI_SPAWN_ERROR",
|
|
6600
|
+
});
|
|
6601
|
+
});
|
|
6602
|
+
|
|
6603
|
+
child.on("close", (code) => {
|
|
6604
|
+
activeProcesses.delete(requestId);
|
|
6605
|
+
|
|
6606
|
+
// Process any remaining buffer
|
|
6607
|
+
if (stdoutBuffer.trim()) {
|
|
6608
|
+
try {
|
|
6609
|
+
const parsed = JSON.parse(stdoutBuffer);
|
|
6610
|
+
if (parsed.session_id && widgetUuid) {
|
|
6611
|
+
sessions.set(widgetUuid, parsed.session_id);
|
|
6612
|
+
}
|
|
6613
|
+
if (parsed.type === "result") {
|
|
6614
|
+
const content = [];
|
|
6615
|
+
if (parsed.result) {
|
|
6616
|
+
content.push({ type: "text", text: parsed.result });
|
|
6617
|
+
}
|
|
6618
|
+
safeSend(win, LLM_STREAM_COMPLETE$2, {
|
|
6619
|
+
requestId,
|
|
6620
|
+
content,
|
|
6621
|
+
stopReason: parsed.stop_reason || "end_turn",
|
|
6622
|
+
usage: parsed.usage || {},
|
|
6623
|
+
});
|
|
6624
|
+
return;
|
|
6625
|
+
}
|
|
6626
|
+
} catch {
|
|
6627
|
+
// ignore
|
|
6628
|
+
}
|
|
6629
|
+
}
|
|
6630
|
+
|
|
6631
|
+
if (code !== 0 && code !== null) {
|
|
6632
|
+
// Check if resume failed and retry without it
|
|
6633
|
+
if (sessionId && !retried && stderrBuffer.includes("session")) {
|
|
6634
|
+
retried = true;
|
|
6635
|
+
if (widgetUuid) sessions.delete(widgetUuid);
|
|
6636
|
+
// Retry without --resume
|
|
6637
|
+
cliController$2.sendMessage(win, requestId, {
|
|
6638
|
+
...params,
|
|
6639
|
+
_retryWithoutResume: true,
|
|
6640
|
+
});
|
|
6641
|
+
return;
|
|
6642
|
+
}
|
|
6643
|
+
|
|
6644
|
+
// Check for auth errors
|
|
6645
|
+
if (
|
|
6646
|
+
stderrBuffer.includes("auth") ||
|
|
6647
|
+
stderrBuffer.includes("login") ||
|
|
6648
|
+
stderrBuffer.includes("not authenticated")
|
|
6649
|
+
) {
|
|
6650
|
+
safeSend(win, LLM_STREAM_ERROR$2, {
|
|
6651
|
+
requestId,
|
|
6652
|
+
error:
|
|
6653
|
+
"Claude Code CLI is not authenticated. Run `claude auth login` in your terminal.",
|
|
6654
|
+
code: "CLI_AUTH_ERROR",
|
|
6655
|
+
});
|
|
6656
|
+
return;
|
|
6657
|
+
}
|
|
6658
|
+
|
|
6659
|
+
safeSend(win, LLM_STREAM_ERROR$2, {
|
|
6660
|
+
requestId,
|
|
6661
|
+
error: `Claude CLI exited with code ${code}${stderrBuffer ? ": " + stderrBuffer.slice(0, 500) : ""}`,
|
|
6662
|
+
code: "CLI_ERROR",
|
|
6663
|
+
});
|
|
6664
|
+
}
|
|
6665
|
+
});
|
|
6666
|
+
} catch (err) {
|
|
6667
|
+
activeProcesses.delete(requestId);
|
|
6668
|
+
safeSend(win, LLM_STREAM_ERROR$2, {
|
|
6669
|
+
requestId,
|
|
6670
|
+
error: `Failed to start Claude CLI: ${err.message}`,
|
|
6671
|
+
code: "CLI_SPAWN_ERROR",
|
|
6672
|
+
});
|
|
6673
|
+
}
|
|
6674
|
+
},
|
|
6675
|
+
|
|
6676
|
+
/**
|
|
6677
|
+
* abortRequest
|
|
6678
|
+
* Kill an in-flight CLI process.
|
|
6679
|
+
*
|
|
6680
|
+
* @param {string} requestId - the request to cancel
|
|
6681
|
+
* @returns {{ success: boolean }}
|
|
6682
|
+
*/
|
|
6683
|
+
abortRequest: (requestId) => {
|
|
6684
|
+
const child = activeProcesses.get(requestId);
|
|
6685
|
+
if (child) {
|
|
6686
|
+
child.kill("SIGTERM");
|
|
6687
|
+
activeProcesses.delete(requestId);
|
|
6688
|
+
return { success: true };
|
|
6689
|
+
}
|
|
6690
|
+
return { success: false, message: "Request not found" };
|
|
6691
|
+
},
|
|
6692
|
+
|
|
6693
|
+
/**
|
|
6694
|
+
* clearSession
|
|
6695
|
+
* Remove the stored session ID for a widget (called on "New Chat").
|
|
6696
|
+
*
|
|
6697
|
+
* @param {string} widgetUuid - the widget whose session to clear
|
|
6698
|
+
* @returns {{ success: boolean }}
|
|
6699
|
+
*/
|
|
6700
|
+
clearSession: (widgetUuid) => {
|
|
6701
|
+
if (widgetUuid && sessions.has(widgetUuid)) {
|
|
6702
|
+
sessions.delete(widgetUuid);
|
|
6703
|
+
return { success: true };
|
|
6704
|
+
}
|
|
6705
|
+
return { success: false };
|
|
6706
|
+
},
|
|
6707
|
+
};
|
|
6708
|
+
|
|
6709
|
+
var cliController_1 = cliController$2;
|
|
6710
|
+
|
|
6320
6711
|
/**
|
|
6321
6712
|
* llmController.js
|
|
6322
6713
|
*
|
|
@@ -6328,8 +6719,9 @@ var pluginController_1 = pluginController$1;
|
|
|
6328
6719
|
* per-request, receiving the full messages array each time.
|
|
6329
6720
|
*/
|
|
6330
6721
|
|
|
6331
|
-
const Anthropic = require$$0$
|
|
6722
|
+
const Anthropic = require$$0$5;
|
|
6332
6723
|
const mcpController$1 = mcpController_1;
|
|
6724
|
+
const cliController$1 = cliController_1;
|
|
6333
6725
|
const {
|
|
6334
6726
|
LLM_STREAM_DELTA: LLM_STREAM_DELTA$1,
|
|
6335
6727
|
LLM_STREAM_TOOL_CALL: LLM_STREAM_TOOL_CALL$1,
|
|
@@ -6398,6 +6790,11 @@ const llmController$1 = {
|
|
|
6398
6790
|
* @param {object} params - { apiKey, model, messages, tools, toolServerMap, systemPrompt, maxToolRounds }
|
|
6399
6791
|
*/
|
|
6400
6792
|
sendMessage: async (win, requestId, params) => {
|
|
6793
|
+
// Route to CLI backend if specified
|
|
6794
|
+
if (params.backend === "claude-code") {
|
|
6795
|
+
return cliController$1.sendMessage(win, requestId, params);
|
|
6796
|
+
}
|
|
6797
|
+
|
|
6401
6798
|
const {
|
|
6402
6799
|
apiKey,
|
|
6403
6800
|
model = "claude-sonnet-4-20250514",
|
|
@@ -6621,7 +7018,8 @@ const llmController$1 = {
|
|
|
6621
7018
|
activeRequests.delete(requestId);
|
|
6622
7019
|
return { success: true };
|
|
6623
7020
|
}
|
|
6624
|
-
|
|
7021
|
+
// Fallback to CLI controller
|
|
7022
|
+
return cliController$1.abortRequest(requestId);
|
|
6625
7023
|
},
|
|
6626
7024
|
};
|
|
6627
7025
|
|
|
@@ -7889,6 +8287,8 @@ const {
|
|
|
7889
8287
|
LLM_SEND_MESSAGE,
|
|
7890
8288
|
LLM_ABORT_REQUEST,
|
|
7891
8289
|
LLM_LIST_CONNECTED_TOOLS,
|
|
8290
|
+
LLM_CHECK_CLI_AVAILABLE,
|
|
8291
|
+
LLM_CLEAR_CLI_SESSION,
|
|
7892
8292
|
LLM_STREAM_DELTA,
|
|
7893
8293
|
LLM_STREAM_TOOL_CALL,
|
|
7894
8294
|
LLM_STREAM_TOOL_RESULT,
|
|
@@ -7926,6 +8326,24 @@ const llmApi$2 = {
|
|
|
7926
8326
|
*/
|
|
7927
8327
|
listConnectedTools: () => ipcRenderer$2.invoke(LLM_LIST_CONNECTED_TOOLS),
|
|
7928
8328
|
|
|
8329
|
+
/**
|
|
8330
|
+
* checkCliAvailable
|
|
8331
|
+
* Check if the Claude Code CLI is installed and accessible.
|
|
8332
|
+
*
|
|
8333
|
+
* @returns {Promise<{ available: boolean, path?: string }>}
|
|
8334
|
+
*/
|
|
8335
|
+
checkCliAvailable: () => ipcRenderer$2.invoke(LLM_CHECK_CLI_AVAILABLE),
|
|
8336
|
+
|
|
8337
|
+
/**
|
|
8338
|
+
* clearCliSession
|
|
8339
|
+
* Clear the CLI conversation session for a widget (for "New Chat").
|
|
8340
|
+
*
|
|
8341
|
+
* @param {string} widgetUuid - the widget whose session to clear
|
|
8342
|
+
* @returns {Promise<{ success: boolean }>}
|
|
8343
|
+
*/
|
|
8344
|
+
clearCliSession: (widgetUuid) =>
|
|
8345
|
+
ipcRenderer$2.invoke(LLM_CLEAR_CLI_SESSION, { widgetUuid }),
|
|
8346
|
+
|
|
7929
8347
|
// --- Stream event listeners ---
|
|
7930
8348
|
|
|
7931
8349
|
/**
|
|
@@ -9553,6 +9971,7 @@ const openaiController = openaiController_1;
|
|
|
9553
9971
|
const menuItemsController = menuItemsController_1;
|
|
9554
9972
|
const pluginController = pluginController_1;
|
|
9555
9973
|
const llmController = llmController_1;
|
|
9974
|
+
const cliController = cliController_1;
|
|
9556
9975
|
|
|
9557
9976
|
// --- Utils ---
|
|
9558
9977
|
const clientCache = requireClientCache();
|
|
@@ -9609,6 +10028,7 @@ var electron = {
|
|
|
9609
10028
|
menuItemsController,
|
|
9610
10029
|
pluginController,
|
|
9611
10030
|
llmController,
|
|
10031
|
+
cliController,
|
|
9612
10032
|
|
|
9613
10033
|
// Controller functions (flat) — spread for convenient destructuring
|
|
9614
10034
|
...controllers,
|