@slock-ai/daemon 0.35.0 → 0.37.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/dist/chat-bridge.js +397 -93
- package/dist/{chunk-OSHFDFBV.js → chunk-7RQ2H2AM.js} +234 -114
- package/dist/{chunk-GX2DVINN.js → chunk-E6OOH3IC.js} +46 -1
- package/dist/core.js +4 -3
- package/dist/index.js +2 -2
- package/package.json +1 -1
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
import {
|
|
2
|
-
buildWebSocketOptions
|
|
3
|
-
|
|
2
|
+
buildWebSocketOptions,
|
|
3
|
+
logger
|
|
4
|
+
} from "./chunk-E6OOH3IC.js";
|
|
4
5
|
|
|
5
6
|
// src/core.ts
|
|
6
|
-
import
|
|
7
|
+
import path10 from "path";
|
|
7
8
|
import os4 from "os";
|
|
8
9
|
import { createRequire } from "module";
|
|
9
10
|
import { execSync as execSync2 } from "child_process";
|
|
10
11
|
import { accessSync } from "fs";
|
|
11
12
|
import { fileURLToPath } from "url";
|
|
12
13
|
|
|
14
|
+
// ../shared/src/testing/failpoints.ts
|
|
15
|
+
var NoopFailpointRegistry = class {
|
|
16
|
+
get enabled() {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
isEnabled() {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
configure() {
|
|
23
|
+
}
|
|
24
|
+
clear() {
|
|
25
|
+
}
|
|
26
|
+
getTrace() {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
hit(_key, _context, fallback) {
|
|
30
|
+
return fallback ? fallback() : void 0;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var noopFailpointRegistry = new NoopFailpointRegistry();
|
|
34
|
+
|
|
13
35
|
// ../shared/src/serverPermissions.ts
|
|
14
36
|
var EMPTY_SERVER_CAPABILITIES = Object.freeze({
|
|
15
37
|
manageServer: false,
|
|
@@ -99,13 +121,13 @@ var DISPLAY_PLAN_CONFIG = {
|
|
|
99
121
|
|
|
100
122
|
// src/agentProcessManager.ts
|
|
101
123
|
import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2 } from "fs/promises";
|
|
102
|
-
import
|
|
124
|
+
import path9 from "path";
|
|
103
125
|
import os3 from "os";
|
|
104
126
|
|
|
105
127
|
// src/drivers/claude.ts
|
|
106
128
|
import { spawn } from "child_process";
|
|
107
129
|
import { writeFileSync } from "fs";
|
|
108
|
-
import
|
|
130
|
+
import path2 from "path";
|
|
109
131
|
|
|
110
132
|
// src/drivers/systemPrompt.ts
|
|
111
133
|
function toolRef(prefix, name) {
|
|
@@ -297,6 +319,8 @@ Keep the user informed. They cannot see your internal reasoning, so:
|
|
|
297
319
|
|
|
298
320
|
Use plain-text @mentions (e.g. \`@alice\`) and #channel references (e.g. \`#general\`, \`#1\`) \u2014 no HTML tags.
|
|
299
321
|
|
|
322
|
+
When referring to a task in message content, use the explicit form \`task #123\`. Do not use bare \`#123\` for task references \u2014 bare \`#123\` is ambiguous with PR, issue, and release references.
|
|
323
|
+
|
|
300
324
|
When referencing a channel or mentioning someone, write them as plain text without backticks. Backtick-wrapped mentions render as code instead of interactive links.
|
|
301
325
|
|
|
302
326
|
### Formatting \u2014 URLs in non-English text
|
|
@@ -405,12 +429,83 @@ ${config.description}. This may evolve.`;
|
|
|
405
429
|
return prompt;
|
|
406
430
|
}
|
|
407
431
|
|
|
432
|
+
// src/drivers/probe.ts
|
|
433
|
+
import { execFileSync } from "child_process";
|
|
434
|
+
import { existsSync } from "fs";
|
|
435
|
+
import path from "path";
|
|
436
|
+
function normalizeExecOutput(raw) {
|
|
437
|
+
return Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw ?? "");
|
|
438
|
+
}
|
|
439
|
+
function resolveCommandOnPath(command, deps = {}) {
|
|
440
|
+
const platform = deps.platform ?? process.platform;
|
|
441
|
+
const env = deps.env ?? process.env;
|
|
442
|
+
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
443
|
+
const locator = platform === "win32" ? "where" : "which";
|
|
444
|
+
try {
|
|
445
|
+
const output = normalizeExecOutput(execFileSyncFn(locator, [command], {
|
|
446
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
447
|
+
env
|
|
448
|
+
}));
|
|
449
|
+
const resolved = output.trim().split(/\r?\n/)[0];
|
|
450
|
+
return resolved || null;
|
|
451
|
+
} catch {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
function firstExistingPath(candidates, deps = {}) {
|
|
456
|
+
const exists = deps.existsSyncFn ?? existsSync;
|
|
457
|
+
for (const candidate of candidates) {
|
|
458
|
+
if (exists(candidate)) return candidate;
|
|
459
|
+
}
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
function readCommandVersion(command, args = [], deps = {}) {
|
|
463
|
+
const env = deps.env ?? process.env;
|
|
464
|
+
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
465
|
+
try {
|
|
466
|
+
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
467
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
468
|
+
env,
|
|
469
|
+
timeout: 5e3
|
|
470
|
+
}));
|
|
471
|
+
return output.trim().split(/\r?\n/)[0] || null;
|
|
472
|
+
} catch {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
function resolveHomePath(relativePath, deps = {}) {
|
|
477
|
+
const homeDir = deps.homeDir ?? deps.env?.HOME ?? process.env.HOME ?? "";
|
|
478
|
+
return path.join(homeDir, relativePath);
|
|
479
|
+
}
|
|
480
|
+
|
|
408
481
|
// src/drivers/claude.ts
|
|
482
|
+
var CLAUDE_DESKTOP_CLI_RELATIVE_PATH = path2.join("Applications", "Claude Code URL Handler.app", "Contents", "MacOS", "claude");
|
|
483
|
+
var CLAUDE_DESKTOP_CLI_SYSTEM_PATH = "/Applications/Claude Code URL Handler.app/Contents/MacOS/claude";
|
|
484
|
+
function resolveClaudeCommand(deps = {}) {
|
|
485
|
+
const pathCommand = resolveCommandOnPath("claude", deps);
|
|
486
|
+
if (pathCommand) return pathCommand;
|
|
487
|
+
if ((deps.platform ?? process.platform) !== "darwin") return null;
|
|
488
|
+
return firstExistingPath([
|
|
489
|
+
resolveHomePath(CLAUDE_DESKTOP_CLI_RELATIVE_PATH, deps),
|
|
490
|
+
CLAUDE_DESKTOP_CLI_SYSTEM_PATH
|
|
491
|
+
], deps);
|
|
492
|
+
}
|
|
493
|
+
function probeClaude(deps = {}) {
|
|
494
|
+
const command = resolveClaudeCommand(deps);
|
|
495
|
+
if (!command) return { available: false };
|
|
496
|
+
return {
|
|
497
|
+
available: true,
|
|
498
|
+
version: readCommandVersion(command, [], deps) ?? void 0
|
|
499
|
+
};
|
|
500
|
+
}
|
|
409
501
|
var ClaudeDriver = class {
|
|
410
502
|
id = "claude";
|
|
411
503
|
supportsStdinNotification = true;
|
|
412
504
|
mcpToolPrefix = "mcp__chat__";
|
|
413
505
|
busyDeliveryMode = "notification";
|
|
506
|
+
probe() {
|
|
507
|
+
return probeClaude();
|
|
508
|
+
}
|
|
414
509
|
spawn(ctx) {
|
|
415
510
|
const mcpArgs = [
|
|
416
511
|
ctx.chatBridgePath,
|
|
@@ -432,7 +527,7 @@ var ClaudeDriver = class {
|
|
|
432
527
|
});
|
|
433
528
|
let mcpConfigArg;
|
|
434
529
|
if (process.platform === "win32") {
|
|
435
|
-
const mcpConfigPath =
|
|
530
|
+
const mcpConfigPath = path2.join(ctx.workingDirectory, ".slock-claude-mcp.json");
|
|
436
531
|
writeFileSync(mcpConfigPath, mcpConfig, "utf8");
|
|
437
532
|
mcpConfigArg = mcpConfigPath;
|
|
438
533
|
} else {
|
|
@@ -458,7 +553,7 @@ var ClaudeDriver = class {
|
|
|
458
553
|
}
|
|
459
554
|
const spawnEnv = { ...process.env, FORCE_COLOR: "0", ...ctx.config.envVars || {} };
|
|
460
555
|
delete spawnEnv.CLAUDECODE;
|
|
461
|
-
const proc = spawn("claude", args, {
|
|
556
|
+
const proc = spawn(resolveClaudeCommand() ?? "claude", args, {
|
|
462
557
|
cwd: ctx.workingDirectory,
|
|
463
558
|
stdio: ["pipe", "pipe", "pipe"],
|
|
464
559
|
env: spawnEnv,
|
|
@@ -633,9 +728,9 @@ var ClaudeDriver = class {
|
|
|
633
728
|
|
|
634
729
|
// src/drivers/codex.ts
|
|
635
730
|
import { spawn as spawn2, execSync } from "child_process";
|
|
636
|
-
import { existsSync, readFileSync } from "fs";
|
|
731
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
637
732
|
import os from "os";
|
|
638
|
-
import
|
|
733
|
+
import path3 from "path";
|
|
639
734
|
function getCodexNotificationErrorMessage(params) {
|
|
640
735
|
const topLevelMessage = params?.message;
|
|
641
736
|
if (typeof topLevelMessage === "string" && topLevelMessage.trim()) {
|
|
@@ -648,8 +743,8 @@ function getCodexNotificationErrorMessage(params) {
|
|
|
648
743
|
return null;
|
|
649
744
|
}
|
|
650
745
|
function ensureGitRepo(workingDirectory) {
|
|
651
|
-
const gitDir =
|
|
652
|
-
if (
|
|
746
|
+
const gitDir = path3.join(workingDirectory, ".git");
|
|
747
|
+
if (existsSync2(gitDir)) return;
|
|
653
748
|
execSync("git init", { cwd: workingDirectory, stdio: "pipe" });
|
|
654
749
|
execSync("git add -A && git commit --allow-empty -m 'init'", {
|
|
655
750
|
cwd: workingDirectory,
|
|
@@ -663,22 +758,48 @@ function ensureGitRepo(workingDirectory) {
|
|
|
663
758
|
}
|
|
664
759
|
});
|
|
665
760
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
761
|
+
var CODEX_DESKTOP_BUNDLE_PATH = "/Applications/Codex.app/Contents/Resources/codex";
|
|
762
|
+
function resolveCodexCommand(deps = {}) {
|
|
763
|
+
const pathCommand = resolveCommandOnPath("codex", deps);
|
|
764
|
+
if (pathCommand) return pathCommand;
|
|
765
|
+
if ((deps.platform ?? process.platform) !== "darwin") return null;
|
|
766
|
+
return firstExistingPath([CODEX_DESKTOP_BUNDLE_PATH], deps);
|
|
767
|
+
}
|
|
768
|
+
function probeCodex(deps = {}) {
|
|
769
|
+
if ((deps.platform ?? process.platform) === "win32") {
|
|
770
|
+
try {
|
|
771
|
+
const resolved = resolveCodexSpawn([], deps);
|
|
772
|
+
return {
|
|
773
|
+
available: true,
|
|
774
|
+
version: readCommandVersion(resolved.command, resolved.args, deps) ?? void 0
|
|
775
|
+
};
|
|
776
|
+
} catch {
|
|
777
|
+
return { available: false };
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
const command = resolveCodexCommand(deps);
|
|
781
|
+
if (!command) return { available: false };
|
|
782
|
+
return {
|
|
783
|
+
available: true,
|
|
784
|
+
version: readCommandVersion(command, [], deps) ?? void 0
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
function resolveCodexSpawn(commandArgs, deps = {}) {
|
|
788
|
+
if ((deps.platform ?? process.platform) !== "win32") {
|
|
789
|
+
return { command: resolveCodexCommand(deps) ?? "codex", args: commandArgs };
|
|
669
790
|
}
|
|
670
791
|
let codexEntry = null;
|
|
671
792
|
try {
|
|
672
793
|
const globalRoot = execSync("npm root -g", { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
|
|
673
|
-
const candidate =
|
|
674
|
-
if (
|
|
794
|
+
const candidate = path3.join(globalRoot, "@openai", "codex", "bin", "codex.js");
|
|
795
|
+
if (existsSync2(candidate)) codexEntry = candidate;
|
|
675
796
|
} catch {
|
|
676
797
|
}
|
|
677
798
|
if (!codexEntry) {
|
|
678
799
|
try {
|
|
679
800
|
const cmdPath = execSync("where codex", { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim().split(/\r?\n/)[0];
|
|
680
|
-
const candidate =
|
|
681
|
-
if (
|
|
801
|
+
const candidate = path3.join(path3.dirname(cmdPath), "node_modules", "@openai", "codex", "bin", "codex.js");
|
|
802
|
+
if (existsSync2(candidate)) codexEntry = candidate;
|
|
682
803
|
} catch {
|
|
683
804
|
}
|
|
684
805
|
}
|
|
@@ -708,6 +829,9 @@ var CodexDriver = class {
|
|
|
708
829
|
supportsStdinNotification = true;
|
|
709
830
|
mcpToolPrefix = "mcp_chat_";
|
|
710
831
|
busyDeliveryMode = "direct";
|
|
832
|
+
probe() {
|
|
833
|
+
return probeCodex();
|
|
834
|
+
}
|
|
711
835
|
process = null;
|
|
712
836
|
requestId = 0;
|
|
713
837
|
threadId = null;
|
|
@@ -1095,8 +1219,8 @@ var CodexDriver = class {
|
|
|
1095
1219
|
}
|
|
1096
1220
|
};
|
|
1097
1221
|
function detectCodexModels(home = os.homedir()) {
|
|
1098
|
-
const cachePath =
|
|
1099
|
-
const configPath =
|
|
1222
|
+
const cachePath = path3.join(home, ".codex", "models_cache.json");
|
|
1223
|
+
const configPath = path3.join(home, ".codex", "config.toml");
|
|
1100
1224
|
let models = [];
|
|
1101
1225
|
try {
|
|
1102
1226
|
const raw = readFileSync(cachePath, "utf8");
|
|
@@ -1126,7 +1250,7 @@ function detectCodexModels(home = os.homedir()) {
|
|
|
1126
1250
|
|
|
1127
1251
|
// src/drivers/copilot.ts
|
|
1128
1252
|
import { spawn as spawn3 } from "child_process";
|
|
1129
|
-
import
|
|
1253
|
+
import path4 from "path";
|
|
1130
1254
|
import { writeFileSync as writeFileSync2 } from "fs";
|
|
1131
1255
|
var CopilotDriver = class {
|
|
1132
1256
|
id = "copilot";
|
|
@@ -1141,7 +1265,7 @@ var CopilotDriver = class {
|
|
|
1141
1265
|
const isTsSource = ctx.chatBridgePath.endsWith(".ts");
|
|
1142
1266
|
const mcpCommand = isTsSource ? "npx" : "node";
|
|
1143
1267
|
const mcpArgs = isTsSource ? ["tsx", ctx.chatBridgePath, "--agent-id", ctx.agentId, "--server-url", ctx.config.serverUrl, "--auth-token", ctx.config.authToken || ctx.daemonApiKey] : [ctx.chatBridgePath, "--agent-id", ctx.agentId, "--server-url", ctx.config.serverUrl, "--auth-token", ctx.config.authToken || ctx.daemonApiKey];
|
|
1144
|
-
const mcpConfigPath =
|
|
1268
|
+
const mcpConfigPath = path4.join(ctx.workingDirectory, ".slock-copilot-mcp.json");
|
|
1145
1269
|
writeFileSync2(mcpConfigPath, JSON.stringify({
|
|
1146
1270
|
mcpServers: {
|
|
1147
1271
|
chat: {
|
|
@@ -1308,22 +1432,22 @@ var CopilotDriver = class {
|
|
|
1308
1432
|
|
|
1309
1433
|
// src/drivers/cursor.ts
|
|
1310
1434
|
import { spawn as spawn4 } from "child_process";
|
|
1311
|
-
import { writeFileSync as writeFileSync3, mkdirSync, existsSync as
|
|
1312
|
-
import
|
|
1435
|
+
import { writeFileSync as writeFileSync3, mkdirSync, existsSync as existsSync3 } from "fs";
|
|
1436
|
+
import path5 from "path";
|
|
1313
1437
|
var CursorDriver = class {
|
|
1314
1438
|
id = "cursor";
|
|
1315
1439
|
supportsStdinNotification = false;
|
|
1316
1440
|
mcpToolPrefix = "mcp__chat__";
|
|
1317
1441
|
busyDeliveryMode = "none";
|
|
1318
1442
|
spawn(ctx) {
|
|
1319
|
-
const cursorDir =
|
|
1320
|
-
if (!
|
|
1443
|
+
const cursorDir = path5.join(ctx.workingDirectory, ".cursor");
|
|
1444
|
+
if (!existsSync3(cursorDir)) {
|
|
1321
1445
|
mkdirSync(cursorDir, { recursive: true });
|
|
1322
1446
|
}
|
|
1323
1447
|
const isTsSource = ctx.chatBridgePath.endsWith(".ts");
|
|
1324
1448
|
const mcpCommand = isTsSource ? "npx" : "node";
|
|
1325
1449
|
const mcpArgs = isTsSource ? ["tsx", ctx.chatBridgePath, "--agent-id", ctx.agentId, "--server-url", ctx.config.serverUrl, "--auth-token", ctx.config.authToken || ctx.daemonApiKey] : [ctx.chatBridgePath, "--agent-id", ctx.agentId, "--server-url", ctx.config.serverUrl, "--auth-token", ctx.config.authToken || ctx.daemonApiKey];
|
|
1326
|
-
const mcpConfigPath =
|
|
1450
|
+
const mcpConfigPath = path5.join(cursorDir, "mcp.json");
|
|
1327
1451
|
writeFileSync3(mcpConfigPath, JSON.stringify({
|
|
1328
1452
|
mcpServers: {
|
|
1329
1453
|
chat: {
|
|
@@ -1485,8 +1609,8 @@ var CursorDriver = class {
|
|
|
1485
1609
|
|
|
1486
1610
|
// src/drivers/gemini.ts
|
|
1487
1611
|
import { spawn as spawn5 } from "child_process";
|
|
1488
|
-
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync2, existsSync as
|
|
1489
|
-
import
|
|
1612
|
+
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
|
|
1613
|
+
import path6 from "path";
|
|
1490
1614
|
var GeminiDriver = class {
|
|
1491
1615
|
id = "gemini";
|
|
1492
1616
|
supportsStdinNotification = false;
|
|
@@ -1497,14 +1621,14 @@ var GeminiDriver = class {
|
|
|
1497
1621
|
spawn(ctx) {
|
|
1498
1622
|
this.sessionId = ctx.config.sessionId || null;
|
|
1499
1623
|
this.sessionAnnounced = false;
|
|
1500
|
-
const geminiDir =
|
|
1501
|
-
if (!
|
|
1624
|
+
const geminiDir = path6.join(ctx.workingDirectory, ".gemini");
|
|
1625
|
+
if (!existsSync4(geminiDir)) {
|
|
1502
1626
|
mkdirSync2(geminiDir, { recursive: true });
|
|
1503
1627
|
}
|
|
1504
1628
|
const isTsSource = ctx.chatBridgePath.endsWith(".ts");
|
|
1505
1629
|
const mcpCommand = isTsSource ? "npx" : "node";
|
|
1506
1630
|
const mcpArgs = isTsSource ? ["tsx", ctx.chatBridgePath, "--agent-id", ctx.agentId, "--server-url", ctx.config.serverUrl, "--auth-token", ctx.config.authToken || ctx.daemonApiKey] : [ctx.chatBridgePath, "--agent-id", ctx.agentId, "--server-url", ctx.config.serverUrl, "--auth-token", ctx.config.authToken || ctx.daemonApiKey];
|
|
1507
|
-
const settingsPath =
|
|
1631
|
+
const settingsPath = path6.join(geminiDir, "settings.json");
|
|
1508
1632
|
writeFileSync4(settingsPath, JSON.stringify({
|
|
1509
1633
|
mcpServers: {
|
|
1510
1634
|
chat: {
|
|
@@ -1645,9 +1769,9 @@ var GeminiDriver = class {
|
|
|
1645
1769
|
// src/drivers/kimi.ts
|
|
1646
1770
|
import { randomUUID } from "crypto";
|
|
1647
1771
|
import { spawn as spawn6 } from "child_process";
|
|
1648
|
-
import { existsSync as
|
|
1772
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
1649
1773
|
import os2 from "os";
|
|
1650
|
-
import
|
|
1774
|
+
import path7 from "path";
|
|
1651
1775
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
1652
1776
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
1653
1777
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
@@ -1676,10 +1800,10 @@ var KimiDriver = class {
|
|
|
1676
1800
|
const isTsSource = ctx.chatBridgePath.endsWith(".ts");
|
|
1677
1801
|
const command = isTsSource ? "npx" : "node";
|
|
1678
1802
|
const bridgeArgs = isTsSource ? ["tsx", ctx.chatBridgePath, "--agent-id", ctx.agentId, "--server-url", ctx.config.serverUrl, "--auth-token", ctx.config.authToken || ctx.daemonApiKey] : [ctx.chatBridgePath, "--agent-id", ctx.agentId, "--server-url", ctx.config.serverUrl, "--auth-token", ctx.config.authToken || ctx.daemonApiKey];
|
|
1679
|
-
const systemPromptPath =
|
|
1680
|
-
const agentFilePath =
|
|
1681
|
-
const mcpConfigPath =
|
|
1682
|
-
if (!isResume || !
|
|
1803
|
+
const systemPromptPath = path7.join(ctx.workingDirectory, KIMI_SYSTEM_PROMPT_FILE);
|
|
1804
|
+
const agentFilePath = path7.join(ctx.workingDirectory, KIMI_AGENT_FILE);
|
|
1805
|
+
const mcpConfigPath = path7.join(ctx.workingDirectory, KIMI_MCP_FILE);
|
|
1806
|
+
if (!isResume || !existsSync5(systemPromptPath)) {
|
|
1683
1807
|
writeFileSync5(systemPromptPath, ctx.prompt, "utf8");
|
|
1684
1808
|
}
|
|
1685
1809
|
writeFileSync5(agentFilePath, [
|
|
@@ -1871,7 +1995,7 @@ var KimiDriver = class {
|
|
|
1871
1995
|
}
|
|
1872
1996
|
};
|
|
1873
1997
|
function detectKimiModels(home = os2.homedir()) {
|
|
1874
|
-
const configPath =
|
|
1998
|
+
const configPath = path7.join(home, ".kimi", "config.toml");
|
|
1875
1999
|
let raw;
|
|
1876
2000
|
try {
|
|
1877
2001
|
raw = readFileSync2(configPath, "utf8");
|
|
@@ -1914,52 +2038,9 @@ function getDriver(runtimeId) {
|
|
|
1914
2038
|
return driver;
|
|
1915
2039
|
}
|
|
1916
2040
|
|
|
1917
|
-
// src/logger.ts
|
|
1918
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
1919
|
-
function timestamp() {
|
|
1920
|
-
const d = /* @__PURE__ */ new Date();
|
|
1921
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
1922
|
-
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
|
|
1923
|
-
}
|
|
1924
|
-
function format(level, msg) {
|
|
1925
|
-
return `${timestamp()} [${level}] ${msg}`;
|
|
1926
|
-
}
|
|
1927
|
-
function emit(event) {
|
|
1928
|
-
for (const listener of listeners) {
|
|
1929
|
-
listener(event);
|
|
1930
|
-
}
|
|
1931
|
-
}
|
|
1932
|
-
function subscribeDaemonLogs(listener) {
|
|
1933
|
-
listeners.add(listener);
|
|
1934
|
-
return () => {
|
|
1935
|
-
listeners.delete(listener);
|
|
1936
|
-
};
|
|
1937
|
-
}
|
|
1938
|
-
var logger = {
|
|
1939
|
-
info(msg) {
|
|
1940
|
-
const line = format("INFO", msg);
|
|
1941
|
-
console.log(line);
|
|
1942
|
-
emit({ level: "INFO", line, message: msg });
|
|
1943
|
-
},
|
|
1944
|
-
warn(msg) {
|
|
1945
|
-
const line = format("WARN", msg);
|
|
1946
|
-
console.warn(line);
|
|
1947
|
-
emit({ level: "WARN", line, message: msg });
|
|
1948
|
-
},
|
|
1949
|
-
error(msg, err) {
|
|
1950
|
-
const line = format("ERROR", msg);
|
|
1951
|
-
if (err) {
|
|
1952
|
-
console.error(line, err);
|
|
1953
|
-
} else {
|
|
1954
|
-
console.error(line);
|
|
1955
|
-
}
|
|
1956
|
-
emit({ level: "ERROR", line, message: msg, error: err });
|
|
1957
|
-
}
|
|
1958
|
-
};
|
|
1959
|
-
|
|
1960
2041
|
// src/workspaces.ts
|
|
1961
2042
|
import { readdir, rm, stat } from "fs/promises";
|
|
1962
|
-
import
|
|
2043
|
+
import path8 from "path";
|
|
1963
2044
|
function isValidWorkspaceDirectoryName(directoryName) {
|
|
1964
2045
|
return !directoryName.includes("/") && !directoryName.includes("\\") && !directoryName.includes("..");
|
|
1965
2046
|
}
|
|
@@ -1967,7 +2048,7 @@ function resolveWorkspaceDirectoryPath(dataDir, directoryName) {
|
|
|
1967
2048
|
if (!isValidWorkspaceDirectoryName(directoryName)) {
|
|
1968
2049
|
return null;
|
|
1969
2050
|
}
|
|
1970
|
-
return
|
|
2051
|
+
return path8.join(dataDir, directoryName);
|
|
1971
2052
|
}
|
|
1972
2053
|
function emptyWorkspaceDirectorySummary(latestMtime = /* @__PURE__ */ new Date(0)) {
|
|
1973
2054
|
return {
|
|
@@ -2016,7 +2097,7 @@ async function summarizeWorkspaceDirectory(dirPath) {
|
|
|
2016
2097
|
return summary;
|
|
2017
2098
|
}
|
|
2018
2099
|
const childSummaries = await Promise.all(
|
|
2019
|
-
entries.map((entry) => summarizeWorkspaceEntry(
|
|
2100
|
+
entries.map((entry) => summarizeWorkspaceEntry(path8.join(dirPath, entry.name), entry))
|
|
2020
2101
|
);
|
|
2021
2102
|
for (const childSummary of childSummaries) {
|
|
2022
2103
|
summary = mergeWorkspaceDirectorySummaries(summary, childSummary);
|
|
@@ -2035,7 +2116,7 @@ async function scanWorkspaceDirectories(dataDir) {
|
|
|
2035
2116
|
if (!entry.isDirectory()) {
|
|
2036
2117
|
return null;
|
|
2037
2118
|
}
|
|
2038
|
-
const dirPath =
|
|
2119
|
+
const dirPath = path8.join(dataDir, entry.name);
|
|
2039
2120
|
try {
|
|
2040
2121
|
const summary = await summarizeWorkspaceDirectory(dirPath);
|
|
2041
2122
|
return {
|
|
@@ -2067,7 +2148,7 @@ async function deleteWorkspaceDirectory(dataDir, directoryName) {
|
|
|
2067
2148
|
}
|
|
2068
2149
|
|
|
2069
2150
|
// src/agentProcessManager.ts
|
|
2070
|
-
var DATA_DIR =
|
|
2151
|
+
var DATA_DIR = path9.join(os3.homedir(), ".slock", "agents");
|
|
2071
2152
|
function toLocalTime(iso) {
|
|
2072
2153
|
const d = new Date(iso);
|
|
2073
2154
|
if (isNaN(d.getTime())) return iso;
|
|
@@ -2193,6 +2274,19 @@ function summarizeCrash(code, signal) {
|
|
|
2193
2274
|
if (typeof code === "number") return `exit code ${code}`;
|
|
2194
2275
|
return "unknown exit";
|
|
2195
2276
|
}
|
|
2277
|
+
function classifyTerminalFailure(ap) {
|
|
2278
|
+
const candidates = [
|
|
2279
|
+
ap.lastRuntimeError,
|
|
2280
|
+
...ap.recentStderr
|
|
2281
|
+
].filter((value) => !!value);
|
|
2282
|
+
for (const text of candidates) {
|
|
2283
|
+
const lower = text.toLowerCase();
|
|
2284
|
+
if (lower.includes("usage limit") || lower.includes("quota exceeded") || lower.includes("quota limit") || lower.includes("budget limit exceeded") || lower.includes("usage not included in your plan") || lower.includes("modelnotfounderror") || lower.includes("requested entity was not found") || lower.includes("model deprecated") || lower.includes("model not found")) {
|
|
2285
|
+
return text;
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
return null;
|
|
2289
|
+
}
|
|
2196
2290
|
function isMissingResumeSession(ap) {
|
|
2197
2291
|
if (ap.driver.id !== "claude") return false;
|
|
2198
2292
|
if (!ap.sessionId) return false;
|
|
@@ -2241,9 +2335,9 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
2241
2335
|
this.agentsStarting.add(agentId);
|
|
2242
2336
|
try {
|
|
2243
2337
|
const driver = this.driverResolver(config.runtime || "claude");
|
|
2244
|
-
const agentDataDir =
|
|
2338
|
+
const agentDataDir = path9.join(this.dataDir, agentId);
|
|
2245
2339
|
await mkdir(agentDataDir, { recursive: true });
|
|
2246
|
-
const memoryMdPath =
|
|
2340
|
+
const memoryMdPath = path9.join(agentDataDir, "MEMORY.md");
|
|
2247
2341
|
try {
|
|
2248
2342
|
await access(memoryMdPath);
|
|
2249
2343
|
} catch {
|
|
@@ -2261,7 +2355,7 @@ ${config.description || "No role defined yet."}
|
|
|
2261
2355
|
`;
|
|
2262
2356
|
await writeFile(memoryMdPath, initialMemoryMd);
|
|
2263
2357
|
}
|
|
2264
|
-
await mkdir(
|
|
2358
|
+
await mkdir(path9.join(agentDataDir, "notes"), { recursive: true });
|
|
2265
2359
|
const isResume = !!config.sessionId;
|
|
2266
2360
|
let prompt;
|
|
2267
2361
|
if (isResume && resumePrompt) {
|
|
@@ -2398,6 +2492,7 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2398
2492
|
this.agents.delete(agentId);
|
|
2399
2493
|
const finalCode = ap.exitCode ?? code;
|
|
2400
2494
|
const finalSignal = ap.exitSignal ?? signal;
|
|
2495
|
+
const terminalFailureDetail = classifyTerminalFailure(ap);
|
|
2401
2496
|
if (finalCode === 0) {
|
|
2402
2497
|
const queuedWakeMessage = !ap.driver.supportsStdinNotification ? ap.inbox.shift() : void 0;
|
|
2403
2498
|
const unreadSummary2 = queuedWakeMessage ? buildUnreadSummary(ap.inbox, formatChannelLabel(queuedWakeMessage)) : void 0;
|
|
@@ -2450,13 +2545,23 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2450
2545
|
this.startAgent(agentId, restartConfig, void 0, void 0, void 0, ap.launchId || void 0).catch((err) => {
|
|
2451
2546
|
logger.error(`[Agent ${agentId}] Cold start recovery failed`, err);
|
|
2452
2547
|
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
2453
|
-
this.broadcastActivity(agentId, "offline", `Crashed (${summary})
|
|
2548
|
+
this.broadcastActivity(agentId, "offline", `Crashed (${summary})`, [], ap.launchId);
|
|
2454
2549
|
});
|
|
2455
2550
|
return;
|
|
2456
2551
|
}
|
|
2457
2552
|
logger.error(`[Agent ${agentId}] Process crashed (${reason}) \u2014 marking inactive`);
|
|
2458
2553
|
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
2459
|
-
|
|
2554
|
+
if (terminalFailureDetail) {
|
|
2555
|
+
this.broadcastActivity(
|
|
2556
|
+
agentId,
|
|
2557
|
+
"error",
|
|
2558
|
+
terminalFailureDetail,
|
|
2559
|
+
[{ kind: "text", text: `Error: ${terminalFailureDetail}` }],
|
|
2560
|
+
ap.launchId
|
|
2561
|
+
);
|
|
2562
|
+
} else {
|
|
2563
|
+
this.broadcastActivity(agentId, "offline", `Crashed (${summary})`, [], ap.launchId);
|
|
2564
|
+
}
|
|
2460
2565
|
}
|
|
2461
2566
|
}
|
|
2462
2567
|
});
|
|
@@ -2590,7 +2695,7 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2590
2695
|
}
|
|
2591
2696
|
}
|
|
2592
2697
|
async resetWorkspace(agentId) {
|
|
2593
|
-
const agentDataDir =
|
|
2698
|
+
const agentDataDir = path9.join(this.dataDir, agentId);
|
|
2594
2699
|
try {
|
|
2595
2700
|
await rm2(agentDataDir, { recursive: true, force: true });
|
|
2596
2701
|
logger.info(`[Agent ${agentId}] Workspace reset complete (${agentDataDir})`);
|
|
@@ -2628,7 +2733,7 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2628
2733
|
}
|
|
2629
2734
|
// Workspace file browsing
|
|
2630
2735
|
async getFileTree(agentId, dirPath) {
|
|
2631
|
-
const agentDir =
|
|
2736
|
+
const agentDir = path9.join(this.dataDir, agentId);
|
|
2632
2737
|
try {
|
|
2633
2738
|
await stat2(agentDir);
|
|
2634
2739
|
} catch {
|
|
@@ -2636,8 +2741,8 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2636
2741
|
}
|
|
2637
2742
|
let targetDir = agentDir;
|
|
2638
2743
|
if (dirPath) {
|
|
2639
|
-
const resolved =
|
|
2640
|
-
if (!resolved.startsWith(agentDir +
|
|
2744
|
+
const resolved = path9.resolve(agentDir, dirPath);
|
|
2745
|
+
if (!resolved.startsWith(agentDir + path9.sep) && resolved !== agentDir) {
|
|
2641
2746
|
return [];
|
|
2642
2747
|
}
|
|
2643
2748
|
targetDir = resolved;
|
|
@@ -2645,9 +2750,9 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2645
2750
|
return this.listDirectoryChildren(targetDir, agentDir);
|
|
2646
2751
|
}
|
|
2647
2752
|
async readFile(agentId, filePath) {
|
|
2648
|
-
const agentDir =
|
|
2649
|
-
const resolved =
|
|
2650
|
-
if (!resolved.startsWith(agentDir +
|
|
2753
|
+
const agentDir = path9.join(this.dataDir, agentId);
|
|
2754
|
+
const resolved = path9.resolve(agentDir, filePath);
|
|
2755
|
+
if (!resolved.startsWith(agentDir + path9.sep) && resolved !== agentDir) {
|
|
2651
2756
|
throw new Error("Access denied");
|
|
2652
2757
|
}
|
|
2653
2758
|
const info = await stat2(resolved);
|
|
@@ -2671,7 +2776,7 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2671
2776
|
".sh",
|
|
2672
2777
|
".py"
|
|
2673
2778
|
]);
|
|
2674
|
-
const ext =
|
|
2779
|
+
const ext = path9.extname(resolved).toLowerCase();
|
|
2675
2780
|
if (!TEXT_EXTENSIONS.has(ext) && ext !== "") {
|
|
2676
2781
|
return { content: null, binary: true };
|
|
2677
2782
|
}
|
|
@@ -2698,13 +2803,13 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2698
2803
|
const agent = this.agents.get(agentId);
|
|
2699
2804
|
const runtime = runtimeHint || agent?.config.runtime || "claude";
|
|
2700
2805
|
const home = os3.homedir();
|
|
2701
|
-
const workspaceDir =
|
|
2806
|
+
const workspaceDir = path9.join(this.dataDir, agentId);
|
|
2702
2807
|
const paths = _AgentProcessManager.SKILL_PATHS[runtime] || _AgentProcessManager.SKILL_PATHS.claude;
|
|
2703
2808
|
const globalResults = await Promise.all(
|
|
2704
|
-
paths.global.map((p) => this.scanSkillsDir(
|
|
2809
|
+
paths.global.map((p) => this.scanSkillsDir(path9.join(home, p)))
|
|
2705
2810
|
);
|
|
2706
2811
|
const workspaceResults = await Promise.all(
|
|
2707
|
-
paths.workspace.map((p) => this.scanSkillsDir(
|
|
2812
|
+
paths.workspace.map((p) => this.scanSkillsDir(path9.join(workspaceDir, p)))
|
|
2708
2813
|
);
|
|
2709
2814
|
const dedup = (skills) => {
|
|
2710
2815
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2733,7 +2838,7 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2733
2838
|
const skills = [];
|
|
2734
2839
|
for (const entry of entries) {
|
|
2735
2840
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
2736
|
-
const skillMd =
|
|
2841
|
+
const skillMd = path9.join(dir, entry.name, "SKILL.md");
|
|
2737
2842
|
try {
|
|
2738
2843
|
const content = await readFile(skillMd, "utf-8");
|
|
2739
2844
|
const skill = this.parseSkillMd(entry.name, content);
|
|
@@ -2744,7 +2849,7 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2744
2849
|
} else if (entry.name.endsWith(".md")) {
|
|
2745
2850
|
const cmdName = entry.name.replace(/\.md$/, "");
|
|
2746
2851
|
try {
|
|
2747
|
-
const content = await readFile(
|
|
2852
|
+
const content = await readFile(path9.join(dir, entry.name), "utf-8");
|
|
2748
2853
|
const skill = this.parseSkillMd(cmdName, content);
|
|
2749
2854
|
skill.sourcePath = dir;
|
|
2750
2855
|
skills.push(skill);
|
|
@@ -2780,14 +2885,21 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2780
2885
|
* Broadcast an activity change — emits a single agent:activity event that carries
|
|
2781
2886
|
* both the status (for the dot indicator) and trajectory entries (for the activity log).
|
|
2782
2887
|
*/
|
|
2783
|
-
broadcastActivity(agentId, activity, detail, extraTrajectory = []) {
|
|
2888
|
+
broadcastActivity(agentId, activity, detail, extraTrajectory = [], launchIdOverride) {
|
|
2784
2889
|
const ap = this.agents.get(agentId);
|
|
2785
2890
|
const entries = [...extraTrajectory];
|
|
2786
2891
|
const hasToolStart = entries.some((e) => e.kind === "tool_start");
|
|
2787
2892
|
if (!hasToolStart) {
|
|
2788
2893
|
entries.push({ kind: "status", activity, detail });
|
|
2789
2894
|
}
|
|
2790
|
-
this.sendToServer({
|
|
2895
|
+
this.sendToServer({
|
|
2896
|
+
type: "agent:activity",
|
|
2897
|
+
agentId,
|
|
2898
|
+
activity,
|
|
2899
|
+
detail,
|
|
2900
|
+
entries,
|
|
2901
|
+
launchId: launchIdOverride || ap?.launchId || void 0
|
|
2902
|
+
});
|
|
2791
2903
|
if (ap) {
|
|
2792
2904
|
ap.lastActivity = activity;
|
|
2793
2905
|
ap.lastActivityDetail = detail;
|
|
@@ -2799,7 +2911,7 @@ Use read_history to catch up on the channels listed above, then stop. Read each
|
|
|
2799
2911
|
agentId,
|
|
2800
2912
|
activity: ap.lastActivity,
|
|
2801
2913
|
detail: ap.lastActivityDetail,
|
|
2802
|
-
launchId: ap.launchId || void 0
|
|
2914
|
+
launchId: launchIdOverride || ap.launchId || void 0
|
|
2803
2915
|
});
|
|
2804
2916
|
}, ACTIVITY_HEARTBEAT_MS);
|
|
2805
2917
|
}
|
|
@@ -2982,8 +3094,8 @@ Respond as appropriate. Complete all your work before stopping.`;
|
|
|
2982
3094
|
const nodes = [];
|
|
2983
3095
|
for (const entry of entries) {
|
|
2984
3096
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
2985
|
-
const fullPath =
|
|
2986
|
-
const relativePath =
|
|
3097
|
+
const fullPath = path9.join(dir, entry.name);
|
|
3098
|
+
const relativePath = path9.relative(rootDir, fullPath);
|
|
2987
3099
|
let info;
|
|
2988
3100
|
try {
|
|
2989
3101
|
info = await stat2(fullPath);
|
|
@@ -3154,13 +3266,13 @@ function readDaemonVersion(moduleUrl = import.meta.url) {
|
|
|
3154
3266
|
}
|
|
3155
3267
|
}
|
|
3156
3268
|
function resolveChatBridgePath(moduleUrl = import.meta.url) {
|
|
3157
|
-
const dirname =
|
|
3158
|
-
const jsPath =
|
|
3269
|
+
const dirname = path10.dirname(fileURLToPath(moduleUrl));
|
|
3270
|
+
const jsPath = path10.resolve(dirname, "chat-bridge.js");
|
|
3159
3271
|
try {
|
|
3160
3272
|
accessSync(jsPath);
|
|
3161
3273
|
return jsPath;
|
|
3162
3274
|
} catch {
|
|
3163
|
-
return
|
|
3275
|
+
return path10.resolve(dirname, "chat-bridge.ts");
|
|
3164
3276
|
}
|
|
3165
3277
|
}
|
|
3166
3278
|
function detectRuntimes() {
|
|
@@ -3168,6 +3280,15 @@ function detectRuntimes() {
|
|
|
3168
3280
|
const versions = {};
|
|
3169
3281
|
const cmd = process.platform === "win32" ? "where" : "which";
|
|
3170
3282
|
for (const runtime of RUNTIMES) {
|
|
3283
|
+
try {
|
|
3284
|
+
const probe = getDriver(runtime.id).probe?.();
|
|
3285
|
+
if (probe?.available) {
|
|
3286
|
+
ids.push(runtime.id);
|
|
3287
|
+
if (probe.version) versions[runtime.id] = probe.version;
|
|
3288
|
+
continue;
|
|
3289
|
+
}
|
|
3290
|
+
} catch {
|
|
3291
|
+
}
|
|
3171
3292
|
try {
|
|
3172
3293
|
execSync2(`${cmd} ${runtime.binary}`, { stdio: "pipe" });
|
|
3173
3294
|
ids.push(runtime.id);
|
|
@@ -3374,7 +3495,6 @@ var DaemonCore = class {
|
|
|
3374
3495
|
};
|
|
3375
3496
|
|
|
3376
3497
|
export {
|
|
3377
|
-
subscribeDaemonLogs,
|
|
3378
3498
|
resolveWorkspaceDirectoryPath,
|
|
3379
3499
|
scanWorkspaceDirectories,
|
|
3380
3500
|
deleteWorkspaceDirectory,
|