@botiverse/raft-daemon 0.60.0 → 0.61.0-play.20260616140732
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/{chunk-65UFKNJJ.js → chunk-GODOOMDN.js} +1034 -171
- package/dist/cli/index.js +28 -1
- package/dist/cli/package.json +1 -1
- package/dist/core.js +5 -1
- package/dist/{dist-JVLCJ2QO.js → dist-6YUWBDWX.js} +26 -1
- package/dist/index.js +5 -3
- package/package.json +2 -1
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
// src/core.ts
|
|
2
|
-
import
|
|
2
|
+
import path17 from "path";
|
|
3
3
|
import os8 from "os";
|
|
4
|
-
import { createRequire as
|
|
4
|
+
import { createRequire as createRequire3 } from "module";
|
|
5
5
|
import { accessSync } from "fs";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
8
|
+
// ../shared/src/typeGuards.ts
|
|
9
|
+
function makeIsMember(members) {
|
|
10
|
+
const set = new Set(members);
|
|
11
|
+
return (value) => typeof value === "string" && set.has(value);
|
|
12
|
+
}
|
|
13
|
+
|
|
8
14
|
// ../shared/src/slockRefs.ts
|
|
9
15
|
var SLOCK_REF_CHANNEL_NAME_PATTERN = String.raw`[\p{L}\p{N}_-]+`;
|
|
10
16
|
var SLOCK_REF_USER_NAME_PATTERN = SLOCK_REF_CHANNEL_NAME_PATTERN;
|
|
@@ -28,6 +34,10 @@ var CHANNEL_MESSAGE_RE = new RegExp(
|
|
|
28
34
|
String.raw`^#(${SLOCK_REF_CHANNEL_NAME_PATTERN})(?::(${SLOCK_REF_THREAD_SHORT_ID_PATTERN}))?\s+msg=(${SLOCK_REF_MESSAGE_ID_PATTERN})$`,
|
|
29
35
|
"iu"
|
|
30
36
|
);
|
|
37
|
+
var DM_MESSAGE_RE = new RegExp(
|
|
38
|
+
String.raw`^dm:@(${SLOCK_REF_DM_PEER_PATTERN})(?::(${SLOCK_REF_THREAD_SHORT_ID_PATTERN}))?\s+msg=(${SLOCK_REF_MESSAGE_ID_PATTERN})$`,
|
|
39
|
+
"iu"
|
|
40
|
+
);
|
|
31
41
|
|
|
32
42
|
// ../shared/src/producerFactLineage.ts
|
|
33
43
|
var PRODUCER_FACT_TEXT_LABEL = "producerFactId";
|
|
@@ -1278,6 +1288,9 @@ var SERVER_CAPABILITY_MATRIX = {
|
|
|
1278
1288
|
|
|
1279
1289
|
// ../shared/src/index.ts
|
|
1280
1290
|
var RUNTIME_CONFIG_VERSION = 1;
|
|
1291
|
+
var AGENT_ACTIVITIES = ["online", "thinking", "working", "error", "offline"];
|
|
1292
|
+
var isAgentActivity = makeIsMember(AGENT_ACTIVITIES);
|
|
1293
|
+
var VALID_ACTIVITIES = new Set(AGENT_ACTIVITIES);
|
|
1281
1294
|
var EXTERNAL_AGENT_RUNTIME_ID = "external";
|
|
1282
1295
|
var EXTERNAL_AGENT_RUNTIME_MODEL = "external";
|
|
1283
1296
|
var EXTERNAL_AGENT_RUNTIME_DISPLAY_NAME = "External agent";
|
|
@@ -1285,7 +1298,11 @@ var RUNTIMES = [
|
|
|
1285
1298
|
{ id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
|
|
1286
1299
|
{ id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
|
|
1287
1300
|
{ id: "antigravity", displayName: "Antigravity CLI", binary: "agy", supported: true },
|
|
1288
|
-
|
|
1301
|
+
// Kimi: prefer the in-process SDK (`kimi-sdk` → "Kimi Code") for new agents.
|
|
1302
|
+
// The legacy `kimi` (kimi-cli child-process) entry stays for backward compat
|
|
1303
|
+
// with existing `runtime=kimi` agents but is labelled deprecated.
|
|
1304
|
+
{ id: "kimi-sdk", displayName: "Kimi Code", binary: "", supported: true },
|
|
1305
|
+
{ id: "kimi", displayName: "Kimi CLI (deprecated)", binary: "kimi", supported: true },
|
|
1289
1306
|
{ id: "copilot", displayName: "Copilot CLI", binary: "copilot", supported: true },
|
|
1290
1307
|
{ id: "cursor", displayName: "Cursor CLI", binary: "cursor-agent", supported: true },
|
|
1291
1308
|
{ id: "gemini", displayName: "Gemini CLI", binary: "gemini", supported: true },
|
|
@@ -1353,6 +1370,15 @@ var RUNTIME_MODELS = {
|
|
|
1353
1370
|
// built-in option is to defer to whatever default model the CLI already uses.
|
|
1354
1371
|
kimi: [
|
|
1355
1372
|
{ id: "default", label: "Configured Default" }
|
|
1373
|
+
],
|
|
1374
|
+
// kimi-sdk runs the Kimi Code SDK in-process. Surface the canonical model
|
|
1375
|
+
// first so getDefaultModel("kimi-sdk") returns it (without a static entry,
|
|
1376
|
+
// useRuntimeModels falls back to Claude's list and getDefaultModel returns
|
|
1377
|
+
// "sonnet" — which the SDK driver would pass through to the Kimi session
|
|
1378
|
+
// and the LLM call would fail). Mirrors detectKimiSdkModels() in the daemon.
|
|
1379
|
+
"kimi-sdk": [
|
|
1380
|
+
{ id: "kimi-code/kimi-for-coding", label: "Kimi-K2.6 (Kimi for Coding)", verified: "launchable" },
|
|
1381
|
+
{ id: "kimi-k2-0905-preview", label: "Kimi K2 (preview)", verified: "suggestion_only" }
|
|
1356
1382
|
]
|
|
1357
1383
|
};
|
|
1358
1384
|
function getDefaultModel(runtimeId) {
|
|
@@ -1538,10 +1564,10 @@ var DISPLAY_PLAN_CONFIG = {
|
|
|
1538
1564
|
};
|
|
1539
1565
|
|
|
1540
1566
|
// src/agentProcessManager.ts
|
|
1541
|
-
import { mkdirSync as
|
|
1567
|
+
import { mkdirSync as mkdirSync5, readdirSync as readdirSync3, statSync, writeFileSync as writeFileSync4 } from "fs";
|
|
1542
1568
|
import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2 } from "fs/promises";
|
|
1543
1569
|
import { createHash as createHash3 } from "crypto";
|
|
1544
|
-
import
|
|
1570
|
+
import path13 from "path";
|
|
1545
1571
|
import os6 from "os";
|
|
1546
1572
|
|
|
1547
1573
|
// src/drivers/claude.ts
|
|
@@ -1579,7 +1605,7 @@ Use the \`raft\` CLI for chat / task / attachment operations (\`slock\` remains
|
|
|
1579
1605
|
11. **\`raft message react\`** \u2014 Add or remove your reaction on a message. Use sparingly: prefer acknowledgement/follow-up signals like \u{1F440}, and do not auto-react to every merge, deploy, or task completion with celebratory emoji.
|
|
1580
1606
|
12. **\`raft task list\`** \u2014 View a channel's task board.
|
|
1581
1607
|
13. **\`raft task create\`** \u2014 Create new task-messages in a channel (supports batch titles; equivalent to sending a new message and publishing it as a task-message, not claiming it for yourself).
|
|
1582
|
-
14. **\`raft task claim\`** \u2014 Claim tasks by number or message ID
|
|
1608
|
+
14. **\`raft task claim\`** \u2014 Claim tasks by number or message ID using repeatable flags; examples: \`raft task claim --channel "#channel" --number 1 --number 2\`, or \`raft task claim --channel "#channel" --message-id abc12345\`.
|
|
1583
1609
|
15. **\`raft task unclaim\`** \u2014 Release your claim on a task.
|
|
1584
1610
|
16. **\`raft task update\`** \u2014 Change a task's status (e.g. to in_review or done).
|
|
1585
1611
|
17. **\`raft attachment upload\`** \u2014 Upload a file to attach to a message. Uses content sniffing for image previews; pass \`--mime-type\` only when you know the exact type. Returns an attachment ID to pass to \`raft message send\`.
|
|
@@ -1711,7 +1737,7 @@ Only top-level channel / DM messages can become tasks. Messages inside threads a
|
|
|
1711
1737
|
**Assignee** is independent from status \u2014 a task can be claimed or unclaimed at any status except \`done\`.
|
|
1712
1738
|
|
|
1713
1739
|
**Workflow:**
|
|
1714
|
-
1. Receive a message that requires action \u2192 claim it first (by task number if already a task, or by message ID if it's a regular message)
|
|
1740
|
+
1. Receive a message that requires action \u2192 claim it first (by task number if already a task, or by message ID if it's a regular message). Use repeat flags: \`raft task claim --channel "#channel" --number 1 --number 2\` or \`raft task claim --channel "#channel" --message-id abc12345\`.
|
|
1715
1741
|
2. If the claim fails, someone else is working on it \u2014 move on to another task
|
|
1716
1742
|
3. Post updates in the task's thread: \`raft message send --target "#channel:msgShortId" <<'${D}'\` followed by the message body and \`${D}\`
|
|
1717
1743
|
4. When done, set status to \`in_review\` so a human can validate via \`raft task update\`
|
|
@@ -1723,7 +1749,7 @@ Only top-level channel / DM messages can become tasks. Messages inside threads a
|
|
|
1723
1749
|
- \`raft task create\` only creates the task \u2014 to own it, call \`raft task claim\` afterward.
|
|
1724
1750
|
- Typical uses for \`raft task create\` are breaking down a larger task into parallel subtasks, or batch-creating genuinely new work for others to claim.
|
|
1725
1751
|
- If someone already sent the work item as a message, just claim that existing message/task instead of creating a new one.
|
|
1726
|
-
- If the work already exists as a message, reuse it via \`raft task claim --message-id
|
|
1752
|
+
- If the work already exists as a message, reuse it via \`raft task claim --channel "#channel" --message-id abc12345\`.
|
|
1727
1753
|
|
|
1728
1754
|
**Creating new tasks:**
|
|
1729
1755
|
- The task system exists to prevent duplicate work. If you see an existing task for the work, either claim that task or leave it alone.
|
|
@@ -2130,6 +2156,19 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
|
|
|
2130
2156
|
return candidates.filter((candidate) => existsSync(candidate.path));
|
|
2131
2157
|
}
|
|
2132
2158
|
|
|
2159
|
+
// src/authEnv.ts
|
|
2160
|
+
var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
|
|
2161
|
+
var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
|
|
2162
|
+
function scrubDaemonAuthEnv(env) {
|
|
2163
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
2164
|
+
return env;
|
|
2165
|
+
}
|
|
2166
|
+
function scrubDaemonChildEnv(env) {
|
|
2167
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
2168
|
+
delete env[SLOCK_AGENT_TOKEN_ENV];
|
|
2169
|
+
return env;
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2133
2172
|
// src/agentCredentialProxy.ts
|
|
2134
2173
|
import { randomBytes } from "crypto";
|
|
2135
2174
|
import http from "http";
|
|
@@ -3341,6 +3380,7 @@ function routeFamilyForPath(pathname) {
|
|
|
3341
3380
|
function daemonUpstreamTargetHostClass(url) {
|
|
3342
3381
|
const hostname = url.hostname.toLowerCase();
|
|
3343
3382
|
if (hostname === "api.slock.ai") return "api.slock.ai";
|
|
3383
|
+
if (hostname === "api.raft.build") return "api.raft.build";
|
|
3344
3384
|
return "custom_server";
|
|
3345
3385
|
}
|
|
3346
3386
|
function upstreamLayerForProxyError(err) {
|
|
@@ -3617,7 +3657,9 @@ var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
|
|
|
3617
3657
|
var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
|
|
3618
3658
|
var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
3619
3659
|
var RAW_CREDENTIAL_ENV_DENYLIST = [
|
|
3620
|
-
"
|
|
3660
|
+
"SLOCK_AGENT_TOKEN",
|
|
3661
|
+
"SLOCK_AGENT_CREDENTIAL_KEY",
|
|
3662
|
+
"SLOCK_AGENT_CREDENTIAL_KEY_FILE"
|
|
3621
3663
|
];
|
|
3622
3664
|
function deriveCliFallbackCandidates(cliPath) {
|
|
3623
3665
|
if (!cliPath || cliPath === "__cli") return [];
|
|
@@ -3932,7 +3974,7 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
|
|
|
3932
3974
|
...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
|
|
3933
3975
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
3934
3976
|
};
|
|
3935
|
-
|
|
3977
|
+
scrubDaemonChildEnv(spawnEnv);
|
|
3936
3978
|
for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
|
|
3937
3979
|
delete spawnEnv[key];
|
|
3938
3980
|
}
|
|
@@ -4367,7 +4409,7 @@ function requiresWindowsShell(command, platform = process.platform) {
|
|
|
4367
4409
|
}
|
|
4368
4410
|
function resolveCommandOnPath(command, deps = {}) {
|
|
4369
4411
|
const platform = deps.platform ?? process.platform;
|
|
4370
|
-
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
4412
|
+
const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
|
|
4371
4413
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
4372
4414
|
const existsSyncFn = deps.existsSyncFn ?? existsSync3;
|
|
4373
4415
|
if (platform === "win32") {
|
|
@@ -4393,7 +4435,7 @@ function firstExistingPath(candidates, deps = {}) {
|
|
|
4393
4435
|
return null;
|
|
4394
4436
|
}
|
|
4395
4437
|
function readCommandVersion(command, args = [], deps = {}) {
|
|
4396
|
-
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
4438
|
+
const env = scrubDaemonChildEnv({ ...withWindowsUserEnvironment(deps.env ?? process.env, deps) });
|
|
4397
4439
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
4398
4440
|
try {
|
|
4399
4441
|
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
@@ -5787,11 +5829,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
|
|
|
5787
5829
|
return parseCursorModelsOutput(String(result.stdout || ""));
|
|
5788
5830
|
}
|
|
5789
5831
|
function buildCursorModelProbeEnv(deps = {}) {
|
|
5790
|
-
return withWindowsUserEnvironment({
|
|
5832
|
+
return scrubDaemonChildEnv(withWindowsUserEnvironment({
|
|
5791
5833
|
...deps.env ?? process.env,
|
|
5792
5834
|
FORCE_COLOR: "0",
|
|
5793
5835
|
NO_COLOR: "1"
|
|
5794
|
-
}, deps);
|
|
5836
|
+
}, deps));
|
|
5795
5837
|
}
|
|
5796
5838
|
function runCursorModelsCommand() {
|
|
5797
5839
|
return spawnSync("cursor-agent", ["models"], {
|
|
@@ -5847,7 +5889,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
5847
5889
|
}
|
|
5848
5890
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
5849
5891
|
const existsSyncFn = deps.existsSyncFn ?? existsSync6;
|
|
5850
|
-
const env = deps.env ?? process.env;
|
|
5892
|
+
const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
|
|
5851
5893
|
const winPath = path7.win32;
|
|
5852
5894
|
let geminiEntry = null;
|
|
5853
5895
|
try {
|
|
@@ -5984,12 +6026,15 @@ var GeminiDriver = class {
|
|
|
5984
6026
|
// src/drivers/kimi.ts
|
|
5985
6027
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
5986
6028
|
import { spawn as spawn7 } from "child_process";
|
|
5987
|
-
import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
6029
|
+
import { chmodSync, existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5988
6030
|
import os4 from "os";
|
|
5989
6031
|
import path8 from "path";
|
|
5990
6032
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
5991
6033
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
5992
6034
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
6035
|
+
var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
|
|
6036
|
+
var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
|
|
6037
|
+
var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
|
|
5993
6038
|
function parseToolArguments(raw) {
|
|
5994
6039
|
if (typeof raw !== "string") return raw;
|
|
5995
6040
|
try {
|
|
@@ -5998,6 +6043,73 @@ function parseToolArguments(raw) {
|
|
|
5998
6043
|
return raw;
|
|
5999
6044
|
}
|
|
6000
6045
|
}
|
|
6046
|
+
function readKimiConfigSource(home = os4.homedir(), env = process.env) {
|
|
6047
|
+
const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
6048
|
+
if (inlineConfig && inlineConfig.trim()) {
|
|
6049
|
+
return {
|
|
6050
|
+
raw: inlineConfig,
|
|
6051
|
+
explicitPath: null,
|
|
6052
|
+
sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
|
|
6053
|
+
};
|
|
6054
|
+
}
|
|
6055
|
+
const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
6056
|
+
const configPath = explicitPath && explicitPath.trim() ? explicitPath : path8.join(home, ".kimi", "config.toml");
|
|
6057
|
+
try {
|
|
6058
|
+
return {
|
|
6059
|
+
raw: readFileSync3(configPath, "utf8"),
|
|
6060
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
6061
|
+
sourcePath: configPath
|
|
6062
|
+
};
|
|
6063
|
+
} catch {
|
|
6064
|
+
return {
|
|
6065
|
+
raw: null,
|
|
6066
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
6067
|
+
sourcePath: configPath
|
|
6068
|
+
};
|
|
6069
|
+
}
|
|
6070
|
+
}
|
|
6071
|
+
function buildKimiSpawnEnv(env = process.env) {
|
|
6072
|
+
const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
6073
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
6074
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
6075
|
+
return scrubDaemonChildEnv(spawnEnv);
|
|
6076
|
+
}
|
|
6077
|
+
function buildKimiEffectiveEnv(ctx, overrideEnv) {
|
|
6078
|
+
return {
|
|
6079
|
+
...process.env,
|
|
6080
|
+
...ctx.config.envVars || {},
|
|
6081
|
+
...overrideEnv || {}
|
|
6082
|
+
};
|
|
6083
|
+
}
|
|
6084
|
+
function buildKimiLaunchOptions(ctx, opts = {}) {
|
|
6085
|
+
const env = buildKimiEffectiveEnv(ctx, opts.env);
|
|
6086
|
+
const source = readKimiConfigSource(opts.home ?? os4.homedir(), env);
|
|
6087
|
+
const args = [];
|
|
6088
|
+
let configFilePath = null;
|
|
6089
|
+
let configContent = null;
|
|
6090
|
+
if (source.explicitPath) {
|
|
6091
|
+
configFilePath = source.explicitPath;
|
|
6092
|
+
} else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
|
|
6093
|
+
configFilePath = path8.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
|
|
6094
|
+
configContent = source.raw;
|
|
6095
|
+
if (opts.writeGeneratedConfig !== false) {
|
|
6096
|
+
writeFileSync3(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
|
|
6097
|
+
chmodSync(configFilePath, 384);
|
|
6098
|
+
}
|
|
6099
|
+
}
|
|
6100
|
+
if (configFilePath) {
|
|
6101
|
+
args.push("--config-file", configFilePath);
|
|
6102
|
+
}
|
|
6103
|
+
if (ctx.config.model && ctx.config.model !== "default") {
|
|
6104
|
+
args.push("--model", ctx.config.model);
|
|
6105
|
+
}
|
|
6106
|
+
return {
|
|
6107
|
+
args,
|
|
6108
|
+
env: buildKimiSpawnEnv(env),
|
|
6109
|
+
configFilePath,
|
|
6110
|
+
configContent
|
|
6111
|
+
};
|
|
6112
|
+
}
|
|
6001
6113
|
function resolveKimiSpawn(commandArgs, deps = {}) {
|
|
6002
6114
|
return {
|
|
6003
6115
|
command: resolveCommandOnPath("kimi", deps) ?? "kimi",
|
|
@@ -6021,7 +6133,25 @@ var KimiDriver = class {
|
|
|
6021
6133
|
};
|
|
6022
6134
|
model = {
|
|
6023
6135
|
detectedModelsVerifiedAs: "launchable",
|
|
6024
|
-
toLaunchSpec: (modelId) =>
|
|
6136
|
+
toLaunchSpec: (modelId, ctx, opts) => {
|
|
6137
|
+
if (!ctx) return { args: ["--model", modelId] };
|
|
6138
|
+
const launchCtx = {
|
|
6139
|
+
...ctx,
|
|
6140
|
+
config: {
|
|
6141
|
+
...ctx.config,
|
|
6142
|
+
model: modelId
|
|
6143
|
+
}
|
|
6144
|
+
};
|
|
6145
|
+
const launch = buildKimiLaunchOptions(launchCtx, {
|
|
6146
|
+
home: opts?.home,
|
|
6147
|
+
writeGeneratedConfig: false
|
|
6148
|
+
});
|
|
6149
|
+
return {
|
|
6150
|
+
args: launch.args,
|
|
6151
|
+
env: launch.env,
|
|
6152
|
+
configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
|
|
6153
|
+
};
|
|
6154
|
+
}
|
|
6025
6155
|
};
|
|
6026
6156
|
supportsStdinNotification = true;
|
|
6027
6157
|
busyDeliveryMode = "direct";
|
|
@@ -6045,21 +6175,23 @@ var KimiDriver = class {
|
|
|
6045
6175
|
` system_prompt_path: ./${KIMI_SYSTEM_PROMPT_FILE}`,
|
|
6046
6176
|
""
|
|
6047
6177
|
].join("\n"), "utf8");
|
|
6178
|
+
const launch = buildKimiLaunchOptions(ctx);
|
|
6048
6179
|
const args = [
|
|
6049
6180
|
"--wire",
|
|
6050
6181
|
"--yolo",
|
|
6051
6182
|
"--agent-file",
|
|
6052
6183
|
agentFilePath,
|
|
6053
6184
|
"--session",
|
|
6054
|
-
this.sessionId
|
|
6185
|
+
this.sessionId,
|
|
6186
|
+
...launch.args
|
|
6055
6187
|
];
|
|
6056
6188
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
6057
6189
|
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
|
|
6058
6190
|
args.push("--model", launchRuntimeFields.model);
|
|
6059
6191
|
}
|
|
6060
6192
|
const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
6061
|
-
const
|
|
6062
|
-
const proc = spawn7(
|
|
6193
|
+
const spawnTarget = resolveKimiSpawn(args);
|
|
6194
|
+
const proc = spawn7(spawnTarget.command, spawnTarget.args, {
|
|
6063
6195
|
cwd: ctx.workingDirectory,
|
|
6064
6196
|
stdio: ["pipe", "pipe", "pipe"],
|
|
6065
6197
|
env: spawnEnv,
|
|
@@ -6067,7 +6199,7 @@ var KimiDriver = class {
|
|
|
6067
6199
|
// and has an 8191-character command-line limit. Kimi's official
|
|
6068
6200
|
// installer/uv entrypoint is an executable, so launch it directly and
|
|
6069
6201
|
// keep prompts on stdin / files instead of routing through cmd.exe.
|
|
6070
|
-
shell:
|
|
6202
|
+
shell: spawnTarget.shell
|
|
6071
6203
|
});
|
|
6072
6204
|
proc.stdin?.write(JSON.stringify({
|
|
6073
6205
|
jsonrpc: "2.0",
|
|
@@ -6180,14 +6312,9 @@ var KimiDriver = class {
|
|
|
6180
6312
|
return detectKimiModels();
|
|
6181
6313
|
}
|
|
6182
6314
|
};
|
|
6183
|
-
function detectKimiModels(home = os4.homedir()) {
|
|
6184
|
-
const
|
|
6185
|
-
|
|
6186
|
-
try {
|
|
6187
|
-
raw = readFileSync3(configPath, "utf8");
|
|
6188
|
-
} catch {
|
|
6189
|
-
return null;
|
|
6190
|
-
}
|
|
6315
|
+
function detectKimiModels(home = os4.homedir(), opts = {}) {
|
|
6316
|
+
const raw = readKimiConfigSource(home, opts.env).raw;
|
|
6317
|
+
if (raw === null) return null;
|
|
6191
6318
|
const models = [];
|
|
6192
6319
|
const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
|
|
6193
6320
|
const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
|
|
@@ -6206,11 +6333,455 @@ function detectKimiModels(home = os4.homedir()) {
|
|
|
6206
6333
|
return { models, default: defaultModel };
|
|
6207
6334
|
}
|
|
6208
6335
|
|
|
6336
|
+
// src/drivers/kimi-sdk.ts
|
|
6337
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
6338
|
+
import { EventEmitter } from "events";
|
|
6339
|
+
import { mkdirSync as mkdirSync3 } from "fs";
|
|
6340
|
+
import path9 from "path";
|
|
6341
|
+
import { createRequire as createRequire2 } from "module";
|
|
6342
|
+
import {
|
|
6343
|
+
createKimiHarness
|
|
6344
|
+
} from "@botiverse/kimi-code-sdk";
|
|
6345
|
+
var requireFromHere = createRequire2(import.meta.url);
|
|
6346
|
+
var KIMI_CODE_USER_AGENT_PRODUCT = "kimi-code-cli";
|
|
6347
|
+
var KIMI_CODE_HOST_VERSION = "0.14.3";
|
|
6348
|
+
function getDaemonVersion() {
|
|
6349
|
+
try {
|
|
6350
|
+
const pkg = requireFromHere("../../package.json");
|
|
6351
|
+
return pkg.version || "0.0.0";
|
|
6352
|
+
} catch {
|
|
6353
|
+
return "0.0.0";
|
|
6354
|
+
}
|
|
6355
|
+
}
|
|
6356
|
+
var KIMI_SESSION_DIR = ".kimi-sessions";
|
|
6357
|
+
function createKimiSdkEventMappingState(sessionId = null) {
|
|
6358
|
+
return {
|
|
6359
|
+
sessionId,
|
|
6360
|
+
sessionAnnounced: false
|
|
6361
|
+
};
|
|
6362
|
+
}
|
|
6363
|
+
function buildKimiSessionDir(workingDirectory) {
|
|
6364
|
+
return path9.join(workingDirectory, KIMI_SESSION_DIR);
|
|
6365
|
+
}
|
|
6366
|
+
function kimiErrorMessage(error) {
|
|
6367
|
+
if (typeof error === "string" && error.trim()) return error.trim();
|
|
6368
|
+
if (error && typeof error === "object") {
|
|
6369
|
+
const record = error;
|
|
6370
|
+
if (typeof record.message === "string" && record.message.trim()) return record.message.trim();
|
|
6371
|
+
try {
|
|
6372
|
+
return JSON.stringify(error);
|
|
6373
|
+
} catch {
|
|
6374
|
+
}
|
|
6375
|
+
}
|
|
6376
|
+
return "Unknown Kimi error";
|
|
6377
|
+
}
|
|
6378
|
+
function pushSessionInitIfNeeded(state, events) {
|
|
6379
|
+
if (!state.sessionAnnounced && state.sessionId) {
|
|
6380
|
+
events.push({ kind: "session_init", sessionId: state.sessionId });
|
|
6381
|
+
state.sessionAnnounced = true;
|
|
6382
|
+
}
|
|
6383
|
+
}
|
|
6384
|
+
function mapKimiSdkEventToParsedEvents(event, state) {
|
|
6385
|
+
const events = [];
|
|
6386
|
+
pushSessionInitIfNeeded(state, events);
|
|
6387
|
+
switch (event.type) {
|
|
6388
|
+
// ── content streaming → ParsedEvent ──
|
|
6389
|
+
case "thinking.delta":
|
|
6390
|
+
if (typeof event.delta === "string" && event.delta.length > 0) {
|
|
6391
|
+
events.push({ kind: "thinking", text: event.delta });
|
|
6392
|
+
}
|
|
6393
|
+
return events;
|
|
6394
|
+
case "assistant.delta":
|
|
6395
|
+
if (typeof event.delta === "string" && event.delta.length > 0) {
|
|
6396
|
+
events.push({ kind: "text", text: event.delta });
|
|
6397
|
+
}
|
|
6398
|
+
return events;
|
|
6399
|
+
case "tool.call.started":
|
|
6400
|
+
events.push({
|
|
6401
|
+
kind: "tool_call",
|
|
6402
|
+
name: event.name || "unknown_tool",
|
|
6403
|
+
input: event.args ?? {}
|
|
6404
|
+
});
|
|
6405
|
+
return events;
|
|
6406
|
+
case "tool.result":
|
|
6407
|
+
events.push({ kind: "tool_output", name: "" });
|
|
6408
|
+
return events;
|
|
6409
|
+
case "compaction.started":
|
|
6410
|
+
events.push({ kind: "compaction_started" });
|
|
6411
|
+
return events;
|
|
6412
|
+
case "compaction.completed":
|
|
6413
|
+
events.push({ kind: "compaction_finished" });
|
|
6414
|
+
return events;
|
|
6415
|
+
case "error":
|
|
6416
|
+
events.push({ kind: "error", message: kimiErrorMessage(event) });
|
|
6417
|
+
return events;
|
|
6418
|
+
// ── THE single turn-triggering source class ──
|
|
6419
|
+
case "turn.ended":
|
|
6420
|
+
events.push({ kind: "turn_end", sessionId: state.sessionId || void 0 });
|
|
6421
|
+
return events;
|
|
6422
|
+
// ── explicit drops (RS-004) ──
|
|
6423
|
+
// `warning` is non-fatal in the SDK's vocabulary; mapping it to
|
|
6424
|
+
// ParsedEvent.kind="error" would latch the agent into APM's error state
|
|
6425
|
+
// (lastRuntimeError set by `runtime.error`, then NOT cleared by the
|
|
6426
|
+
// following turn_end) — so a warning would brick the agent until
|
|
6427
|
+
// restart. Drop it here; the SDK's own log already records it.
|
|
6428
|
+
case "warning":
|
|
6429
|
+
// turn / step lifecycle (state-only, no parsed payload)
|
|
6430
|
+
case "turn.started":
|
|
6431
|
+
case "turn.step.started":
|
|
6432
|
+
case "turn.step.completed":
|
|
6433
|
+
case "turn.step.retrying":
|
|
6434
|
+
case "turn.step.interrupted":
|
|
6435
|
+
// tool-call progress / hooks (could elevate to internal_progress in future)
|
|
6436
|
+
case "tool.call.delta":
|
|
6437
|
+
case "tool.progress":
|
|
6438
|
+
case "hook.result":
|
|
6439
|
+
// status / meta updates
|
|
6440
|
+
case "agent.status.updated":
|
|
6441
|
+
case "session.meta.updated":
|
|
6442
|
+
case "goal.updated":
|
|
6443
|
+
case "skill.activated":
|
|
6444
|
+
// MCP infra
|
|
6445
|
+
case "tool.list.updated":
|
|
6446
|
+
case "mcp.server.status":
|
|
6447
|
+
// subagent lifecycle (v0: drop; could surface later)
|
|
6448
|
+
case "subagent.spawned":
|
|
6449
|
+
case "subagent.started":
|
|
6450
|
+
case "subagent.suspended":
|
|
6451
|
+
case "subagent.completed":
|
|
6452
|
+
case "subagent.failed":
|
|
6453
|
+
// compaction sub-cases
|
|
6454
|
+
case "compaction.blocked":
|
|
6455
|
+
case "compaction.cancelled":
|
|
6456
|
+
// out-of-band
|
|
6457
|
+
case "background.task.started":
|
|
6458
|
+
case "background.task.terminated":
|
|
6459
|
+
case "cron.fired":
|
|
6460
|
+
return events;
|
|
6461
|
+
default: {
|
|
6462
|
+
const _exhaustive = event;
|
|
6463
|
+
return _exhaustive;
|
|
6464
|
+
}
|
|
6465
|
+
}
|
|
6466
|
+
}
|
|
6467
|
+
var KIMI_SDK_RUNTIME_SESSION_DESCRIPTOR = {
|
|
6468
|
+
transport: "sdk",
|
|
6469
|
+
lifecycle: "sdk_session",
|
|
6470
|
+
input: {
|
|
6471
|
+
initial: "start",
|
|
6472
|
+
idle: "sdk_prompt",
|
|
6473
|
+
busy: "sdk_steer"
|
|
6474
|
+
},
|
|
6475
|
+
readiness: "sdk_ready",
|
|
6476
|
+
turnBoundary: "sdk_event",
|
|
6477
|
+
startPolicy: "immediate",
|
|
6478
|
+
inFlightWake: "steer",
|
|
6479
|
+
busyDelivery: "direct",
|
|
6480
|
+
postTurn: "keep_alive"
|
|
6481
|
+
};
|
|
6482
|
+
async function createKimiAgentSessionForContext(ctx, sessionId) {
|
|
6483
|
+
const sessionDir = buildKimiSessionDir(ctx.workingDirectory);
|
|
6484
|
+
mkdirSync3(sessionDir, { recursive: true });
|
|
6485
|
+
const cliTransport = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
6486
|
+
const spawnEnv = cliTransport.spawnEnv;
|
|
6487
|
+
const wrapperPath = cliTransport.wrapperPath;
|
|
6488
|
+
const homeDir = spawnEnv.KIMI_HOME || (process.env.HOME ? path9.join(process.env.HOME, ".kimi") : path9.join(ctx.workingDirectory, ".kimi"));
|
|
6489
|
+
mkdirSync3(homeDir, { recursive: true });
|
|
6490
|
+
const harness = createKimiHarness({
|
|
6491
|
+
homeDir,
|
|
6492
|
+
identity: {
|
|
6493
|
+
userAgentProduct: KIMI_CODE_USER_AGENT_PRODUCT,
|
|
6494
|
+
version: KIMI_CODE_HOST_VERSION,
|
|
6495
|
+
userAgentSuffix: `slock-daemon/${getDaemonVersion()}`
|
|
6496
|
+
}
|
|
6497
|
+
});
|
|
6498
|
+
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
6499
|
+
const sessionFields = {
|
|
6500
|
+
workDir: ctx.workingDirectory,
|
|
6501
|
+
...launchRuntimeFields.model && launchRuntimeFields.model !== "default" ? { model: launchRuntimeFields.model } : {}
|
|
6502
|
+
};
|
|
6503
|
+
let session;
|
|
6504
|
+
if (ctx.config.sessionId) {
|
|
6505
|
+
try {
|
|
6506
|
+
session = await harness.resumeSession({ ...sessionFields, id: ctx.config.sessionId });
|
|
6507
|
+
} catch (resumeError) {
|
|
6508
|
+
void resumeError;
|
|
6509
|
+
session = await harness.createSession(sessionFields);
|
|
6510
|
+
}
|
|
6511
|
+
} else {
|
|
6512
|
+
session = await harness.createSession(sessionFields);
|
|
6513
|
+
}
|
|
6514
|
+
return { harness, session, wrapperPath };
|
|
6515
|
+
}
|
|
6516
|
+
var KimiSdkRuntimeSession = class {
|
|
6517
|
+
constructor(ctx, setCurrentSessionId, sessionFactory = createKimiAgentSessionForContext) {
|
|
6518
|
+
this.ctx = ctx;
|
|
6519
|
+
this.setCurrentSessionId = setCurrentSessionId;
|
|
6520
|
+
this.sessionFactory = sessionFactory;
|
|
6521
|
+
this.mappingState = createKimiSdkEventMappingState(ctx.config.sessionId || null);
|
|
6522
|
+
}
|
|
6523
|
+
descriptor = KIMI_SDK_RUNTIME_SESSION_DESCRIPTOR;
|
|
6524
|
+
events = new EventEmitter();
|
|
6525
|
+
mappingState;
|
|
6526
|
+
harness = null;
|
|
6527
|
+
session = null;
|
|
6528
|
+
wrapperPath = null;
|
|
6529
|
+
unsubscribe = null;
|
|
6530
|
+
started = false;
|
|
6531
|
+
didClose = false;
|
|
6532
|
+
requestedStopReason;
|
|
6533
|
+
exitInfo = null;
|
|
6534
|
+
get pid() {
|
|
6535
|
+
return void 0;
|
|
6536
|
+
}
|
|
6537
|
+
get currentSessionId() {
|
|
6538
|
+
return this.mappingState.sessionId;
|
|
6539
|
+
}
|
|
6540
|
+
get exitCode() {
|
|
6541
|
+
return this.exitInfo?.code ?? null;
|
|
6542
|
+
}
|
|
6543
|
+
get signalCode() {
|
|
6544
|
+
return this.exitInfo?.signal ?? null;
|
|
6545
|
+
}
|
|
6546
|
+
get closed() {
|
|
6547
|
+
return this.didClose;
|
|
6548
|
+
}
|
|
6549
|
+
on(event, cb) {
|
|
6550
|
+
this.events.on(event, cb);
|
|
6551
|
+
}
|
|
6552
|
+
async start(input) {
|
|
6553
|
+
if (this.started) {
|
|
6554
|
+
return { ok: false, reason: "runtime_error", error: "runtime session already started" };
|
|
6555
|
+
}
|
|
6556
|
+
if (this.didClose) return { ok: false, reason: "closed" };
|
|
6557
|
+
this.started = true;
|
|
6558
|
+
const sessionId = input.sessionId || this.ctx.config.sessionId || randomUUID3();
|
|
6559
|
+
this.mappingState.sessionId = sessionId;
|
|
6560
|
+
this.setCurrentSessionId(sessionId);
|
|
6561
|
+
const { harness, session, wrapperPath } = await this.sessionFactory(
|
|
6562
|
+
{
|
|
6563
|
+
...this.ctx,
|
|
6564
|
+
config: {
|
|
6565
|
+
...this.ctx.config,
|
|
6566
|
+
sessionId
|
|
6567
|
+
}
|
|
6568
|
+
},
|
|
6569
|
+
sessionId
|
|
6570
|
+
);
|
|
6571
|
+
this.harness = harness;
|
|
6572
|
+
this.session = session;
|
|
6573
|
+
this.wrapperPath = wrapperPath;
|
|
6574
|
+
this.mappingState.sessionId = session.id;
|
|
6575
|
+
this.setCurrentSessionId(session.id);
|
|
6576
|
+
session.setApprovalHandler(() => ({ decision: "approved", scope: "session" }));
|
|
6577
|
+
this.unsubscribe = session.onEvent((event) => {
|
|
6578
|
+
for (const parsed of mapKimiSdkEventToParsedEvents(event, this.mappingState)) {
|
|
6579
|
+
this.events.emit("runtime_event", parsed);
|
|
6580
|
+
}
|
|
6581
|
+
});
|
|
6582
|
+
this.emitSessionInit();
|
|
6583
|
+
const firstTurnText = this.composeFirstTurnPreamble(input.text);
|
|
6584
|
+
this.launchPrompt(firstTurnText);
|
|
6585
|
+
return { ok: true, acceptedAs: "prompt" };
|
|
6586
|
+
}
|
|
6587
|
+
composeFirstTurnPreamble(turnText) {
|
|
6588
|
+
const sections = [];
|
|
6589
|
+
if (this.ctx.standingPrompt) {
|
|
6590
|
+
sections.push(this.ctx.standingPrompt);
|
|
6591
|
+
}
|
|
6592
|
+
if (this.wrapperPath) {
|
|
6593
|
+
sections.push(
|
|
6594
|
+
`## CLI invocation note (Kimi SDK in-process runtime)
|
|
6595
|
+
|
|
6596
|
+
When you run \`raft\` CLI commands from your bash tool, **use this absolute path** because PATH is not pre-injected for the in-process Kimi SDK:
|
|
6597
|
+
|
|
6598
|
+
\`\`\`
|
|
6599
|
+
${this.wrapperPath}
|
|
6600
|
+
\`\`\`
|
|
6601
|
+
|
|
6602
|
+
So instead of \`raft message send ...\`, run \`${this.wrapperPath} message send ...\` (every \`raft\` reference in the protocol above maps to this wrapper). The wrapper carries this agent's identity automatically; do not pass auth tokens explicitly.`
|
|
6603
|
+
);
|
|
6604
|
+
}
|
|
6605
|
+
sections.push(turnText);
|
|
6606
|
+
return sections.join("\n\n---\n\n");
|
|
6607
|
+
}
|
|
6608
|
+
send(input) {
|
|
6609
|
+
if (this.didClose) return { ok: false, reason: "closed" };
|
|
6610
|
+
const session = this.session;
|
|
6611
|
+
if (!session) return { ok: false, reason: "closed" };
|
|
6612
|
+
if (input.mode === "busy") {
|
|
6613
|
+
this.deferSdkCall(() => session.steer(input.text));
|
|
6614
|
+
return { ok: true, acceptedAs: "steer" };
|
|
6615
|
+
}
|
|
6616
|
+
this.launchPrompt(input.text);
|
|
6617
|
+
return { ok: true, acceptedAs: "prompt" };
|
|
6618
|
+
}
|
|
6619
|
+
async stop(opts) {
|
|
6620
|
+
if (this.didClose) return;
|
|
6621
|
+
this.requestedStopReason = opts?.reason;
|
|
6622
|
+
const signal = opts?.signal ?? "SIGTERM";
|
|
6623
|
+
const session = this.session;
|
|
6624
|
+
if (session) {
|
|
6625
|
+
try {
|
|
6626
|
+
await session.cancel();
|
|
6627
|
+
} catch (error) {
|
|
6628
|
+
this.events.emit("stderr", kimiErrorMessage(error));
|
|
6629
|
+
}
|
|
6630
|
+
}
|
|
6631
|
+
await this.disposeSession();
|
|
6632
|
+
this.emitExitAndClose(null, signal);
|
|
6633
|
+
}
|
|
6634
|
+
async dispose() {
|
|
6635
|
+
if (this.didClose) return;
|
|
6636
|
+
await this.disposeSession();
|
|
6637
|
+
this.emitExitAndClose(0, null);
|
|
6638
|
+
}
|
|
6639
|
+
emitSessionInit() {
|
|
6640
|
+
const sessionId = this.mappingState.sessionId;
|
|
6641
|
+
if (!sessionId || this.mappingState.sessionAnnounced) return;
|
|
6642
|
+
this.mappingState.sessionAnnounced = true;
|
|
6643
|
+
this.events.emit("runtime_event", { kind: "session_init", sessionId });
|
|
6644
|
+
}
|
|
6645
|
+
launchPrompt(text) {
|
|
6646
|
+
const session = this.session;
|
|
6647
|
+
if (!session) {
|
|
6648
|
+
this.events.emit("runtime_event", {
|
|
6649
|
+
kind: "error",
|
|
6650
|
+
message: "Kimi SDK session is not started"
|
|
6651
|
+
});
|
|
6652
|
+
return;
|
|
6653
|
+
}
|
|
6654
|
+
this.deferSdkCall(() => session.prompt(text));
|
|
6655
|
+
}
|
|
6656
|
+
deferSdkCall(invoke) {
|
|
6657
|
+
setImmediate(() => {
|
|
6658
|
+
if (this.didClose) return;
|
|
6659
|
+
try {
|
|
6660
|
+
void invoke().catch((error) => {
|
|
6661
|
+
if (this.didClose) return;
|
|
6662
|
+
this.events.emit("runtime_event", {
|
|
6663
|
+
kind: "error",
|
|
6664
|
+
message: kimiErrorMessage(error)
|
|
6665
|
+
});
|
|
6666
|
+
});
|
|
6667
|
+
} catch (error) {
|
|
6668
|
+
if (this.didClose) return;
|
|
6669
|
+
this.events.emit("runtime_event", {
|
|
6670
|
+
kind: "error",
|
|
6671
|
+
message: kimiErrorMessage(error)
|
|
6672
|
+
});
|
|
6673
|
+
}
|
|
6674
|
+
});
|
|
6675
|
+
}
|
|
6676
|
+
async disposeSession() {
|
|
6677
|
+
const unsubscribe = this.unsubscribe;
|
|
6678
|
+
this.unsubscribe = null;
|
|
6679
|
+
try {
|
|
6680
|
+
unsubscribe?.();
|
|
6681
|
+
} catch {
|
|
6682
|
+
}
|
|
6683
|
+
const session = this.session;
|
|
6684
|
+
this.session = null;
|
|
6685
|
+
try {
|
|
6686
|
+
await session?.close();
|
|
6687
|
+
} catch (error) {
|
|
6688
|
+
this.events.emit("stderr", kimiErrorMessage(error));
|
|
6689
|
+
}
|
|
6690
|
+
const harness = this.harness;
|
|
6691
|
+
this.harness = null;
|
|
6692
|
+
try {
|
|
6693
|
+
await harness?.close();
|
|
6694
|
+
} catch (error) {
|
|
6695
|
+
this.events.emit("stderr", kimiErrorMessage(error));
|
|
6696
|
+
}
|
|
6697
|
+
}
|
|
6698
|
+
emitExitAndClose(code, signal) {
|
|
6699
|
+
if (this.didClose) return;
|
|
6700
|
+
this.didClose = true;
|
|
6701
|
+
const info = {
|
|
6702
|
+
code,
|
|
6703
|
+
signal,
|
|
6704
|
+
reason: this.requestedStopReason ? "requested" : "runtime_exit"
|
|
6705
|
+
};
|
|
6706
|
+
this.exitInfo = info;
|
|
6707
|
+
this.events.emit("exit", info);
|
|
6708
|
+
this.events.emit("close", info);
|
|
6709
|
+
}
|
|
6710
|
+
};
|
|
6711
|
+
var KIMI_SDK_DEFAULT_MODELS = [
|
|
6712
|
+
// Canonical Kimi Code SDK model (matches the `default_model` upstream
|
|
6713
|
+
// ships in `~/.kimi/config.toml` after `kimi login`). Mirrored as the first
|
|
6714
|
+
// entry in `RUNTIME_MODELS["kimi-sdk"]` (packages/shared/src/index.ts) so
|
|
6715
|
+
// both the daemon's launch resolution and the web's getDefaultModel agree.
|
|
6716
|
+
{ id: "kimi-code/kimi-for-coding", label: "Kimi-K2.6 (Kimi for Coding)", verified: "launchable" },
|
|
6717
|
+
{ id: "kimi-k2-0905-preview", label: "Kimi K2 (preview)", verified: "suggestion_only" }
|
|
6718
|
+
];
|
|
6719
|
+
function detectKimiSdkModels() {
|
|
6720
|
+
return { models: KIMI_SDK_DEFAULT_MODELS };
|
|
6721
|
+
}
|
|
6722
|
+
var KimiSdkDriver = class {
|
|
6723
|
+
id = "kimi-sdk";
|
|
6724
|
+
supportsNativeStandingPrompt = true;
|
|
6725
|
+
lifecycle = {
|
|
6726
|
+
kind: "persistent",
|
|
6727
|
+
stdin: "direct",
|
|
6728
|
+
inFlightWake: "steer"
|
|
6729
|
+
};
|
|
6730
|
+
communication = {
|
|
6731
|
+
chat: "slock_cli",
|
|
6732
|
+
runtimeControl: "none"
|
|
6733
|
+
};
|
|
6734
|
+
session = {
|
|
6735
|
+
recovery: "resume_or_fresh"
|
|
6736
|
+
};
|
|
6737
|
+
model = {
|
|
6738
|
+
detectedModelsVerifiedAs: "suggestion_only",
|
|
6739
|
+
toLaunchSpec: (modelId) => ({ params: { model: modelId } })
|
|
6740
|
+
};
|
|
6741
|
+
supportsStdinNotification = true;
|
|
6742
|
+
busyDeliveryMode = "direct";
|
|
6743
|
+
sessionId = null;
|
|
6744
|
+
get currentSessionId() {
|
|
6745
|
+
return this.sessionId;
|
|
6746
|
+
}
|
|
6747
|
+
probe() {
|
|
6748
|
+
return { available: true };
|
|
6749
|
+
}
|
|
6750
|
+
async detectModels() {
|
|
6751
|
+
return detectKimiSdkModels();
|
|
6752
|
+
}
|
|
6753
|
+
createSession(ctx) {
|
|
6754
|
+
this.sessionId = ctx.config.sessionId || null;
|
|
6755
|
+
return new KimiSdkRuntimeSession(ctx, (sessionId) => {
|
|
6756
|
+
this.sessionId = sessionId;
|
|
6757
|
+
});
|
|
6758
|
+
}
|
|
6759
|
+
async spawn(_ctx) {
|
|
6760
|
+
throw new Error("KimiSdkDriver uses a native RuntimeSession; child-process spawn is unsupported");
|
|
6761
|
+
}
|
|
6762
|
+
parseLine(_line) {
|
|
6763
|
+
return [];
|
|
6764
|
+
}
|
|
6765
|
+
encodeStdinMessage(_text, _sessionId, _opts) {
|
|
6766
|
+
return null;
|
|
6767
|
+
}
|
|
6768
|
+
buildSystemPrompt(config, _agentId) {
|
|
6769
|
+
return buildCliTransportSystemPrompt(config, {
|
|
6770
|
+
extraCriticalRules: [],
|
|
6771
|
+
postStartupNotes: [
|
|
6772
|
+
"**Kimi SDK runtime note:** Slock keeps Kimi running as a persistent SDK session. While you are working, Slock may send inbox-count notifications into the current turn; call `raft message check` at natural breakpoints."
|
|
6773
|
+
],
|
|
6774
|
+
includeStdinNotificationSection: true,
|
|
6775
|
+
messageNotificationStyle: "direct"
|
|
6776
|
+
});
|
|
6777
|
+
}
|
|
6778
|
+
};
|
|
6779
|
+
|
|
6209
6780
|
// src/drivers/opencode.ts
|
|
6210
6781
|
import { spawn as spawn8, spawnSync as spawnSync2 } from "child_process";
|
|
6211
6782
|
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
|
|
6212
6783
|
import os5 from "os";
|
|
6213
|
-
import
|
|
6784
|
+
import path10 from "path";
|
|
6214
6785
|
var SLOCK_AGENT_NAME = "slock";
|
|
6215
6786
|
var NO_MESSAGE_PROMPT = "No new messages are pending. Stop now.";
|
|
6216
6787
|
var FIRST_MESSAGE_TASK_PREFIX = "First message task (system-triggered):";
|
|
@@ -6239,7 +6810,7 @@ function parseUserOpenCodeConfig(ctx) {
|
|
|
6239
6810
|
return parseOpenCodeConfigContent(raw);
|
|
6240
6811
|
}
|
|
6241
6812
|
function readLocalOpenCodeConfig(home = os5.homedir()) {
|
|
6242
|
-
const configPath =
|
|
6813
|
+
const configPath = path10.join(home, ".config", "opencode", "opencode.json");
|
|
6243
6814
|
try {
|
|
6244
6815
|
return parseOpenCodeConfigContent(readFileSync4(configPath, "utf8"));
|
|
6245
6816
|
} catch {
|
|
@@ -6425,7 +6996,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
6425
6996
|
const platform = deps.platform ?? process.platform;
|
|
6426
6997
|
const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
|
|
6427
6998
|
const result = spawnSyncFn("opencode", ["models"], {
|
|
6428
|
-
env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
6999
|
+
env: scrubDaemonChildEnv({ ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" }),
|
|
6429
7000
|
encoding: "utf8",
|
|
6430
7001
|
timeout: 5e3,
|
|
6431
7002
|
shell: platform === "win32"
|
|
@@ -6437,11 +7008,11 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
6437
7008
|
};
|
|
6438
7009
|
}
|
|
6439
7010
|
function isWindowsCommandShim(commandPath) {
|
|
6440
|
-
const ext =
|
|
7011
|
+
const ext = path10.win32.extname(commandPath).toLowerCase();
|
|
6441
7012
|
return ext === ".cmd" || ext === ".bat";
|
|
6442
7013
|
}
|
|
6443
7014
|
function opencodePackageEntryCandidates(packageRoot) {
|
|
6444
|
-
const winPath =
|
|
7015
|
+
const winPath = path10.win32;
|
|
6445
7016
|
return [
|
|
6446
7017
|
winPath.join(packageRoot, "bin", "opencode.exe"),
|
|
6447
7018
|
winPath.join(packageRoot, "bin", "opencode.js"),
|
|
@@ -6450,7 +7021,7 @@ function opencodePackageEntryCandidates(packageRoot) {
|
|
|
6450
7021
|
];
|
|
6451
7022
|
}
|
|
6452
7023
|
function openCodeSpecForEntry(entry, commandArgs) {
|
|
6453
|
-
if (
|
|
7024
|
+
if (path10.win32.extname(entry).toLowerCase() === ".exe") {
|
|
6454
7025
|
return { command: entry, args: commandArgs, shell: false };
|
|
6455
7026
|
}
|
|
6456
7027
|
return { command: process.execPath, args: [entry, ...commandArgs], shell: false };
|
|
@@ -6459,7 +7030,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
|
6459
7030
|
const existsSyncFn = deps.existsSyncFn ?? existsSync8;
|
|
6460
7031
|
const execFileSyncFn = deps.execFileSyncFn;
|
|
6461
7032
|
const env = deps.env ?? process.env;
|
|
6462
|
-
const winPath =
|
|
7033
|
+
const winPath = path10.win32;
|
|
6463
7034
|
const candidates = [];
|
|
6464
7035
|
if (execFileSyncFn) {
|
|
6465
7036
|
try {
|
|
@@ -6487,7 +7058,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
|
6487
7058
|
function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
6488
7059
|
if (!isWindowsCommandShim(commandPath)) return [];
|
|
6489
7060
|
const readFileSyncFn = deps.readFileSyncFn ?? readFileSync4;
|
|
6490
|
-
const commandDir =
|
|
7061
|
+
const commandDir = path10.win32.dirname(commandPath);
|
|
6491
7062
|
let raw;
|
|
6492
7063
|
try {
|
|
6493
7064
|
raw = String(readFileSyncFn(commandPath, "utf8"));
|
|
@@ -6498,7 +7069,7 @@ function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
|
6498
7069
|
const dp0Pattern = /%~dp0\\?([^"\r\n]*?opencode\.(?:exe|js|mjs|cjs))/gi;
|
|
6499
7070
|
for (const match of raw.matchAll(dp0Pattern)) {
|
|
6500
7071
|
const relative = match[1]?.replace(/^\\+/, "");
|
|
6501
|
-
if (relative) candidates.push(
|
|
7072
|
+
if (relative) candidates.push(path10.win32.normalize(path10.win32.join(commandDir, relative)));
|
|
6502
7073
|
}
|
|
6503
7074
|
return candidates;
|
|
6504
7075
|
}
|
|
@@ -6512,7 +7083,7 @@ function resolveOpenCodeSpawn(commandArgs, deps = {}) {
|
|
|
6512
7083
|
};
|
|
6513
7084
|
}
|
|
6514
7085
|
const command = resolveCommandOnPath("opencode", deps);
|
|
6515
|
-
if (command &&
|
|
7086
|
+
if (command && path10.win32.extname(command).toLowerCase() === ".exe") {
|
|
6516
7087
|
return { command, args: commandArgs, shell: false };
|
|
6517
7088
|
}
|
|
6518
7089
|
const packageEntry = resolveWindowsOpenCodePackageEntry(command, deps);
|
|
@@ -6682,17 +7253,16 @@ var OpenCodeDriver = class {
|
|
|
6682
7253
|
};
|
|
6683
7254
|
|
|
6684
7255
|
// src/drivers/pi.ts
|
|
6685
|
-
import { randomUUID as
|
|
6686
|
-
import { EventEmitter } from "events";
|
|
6687
|
-
import { mkdirSync as
|
|
6688
|
-
import
|
|
7256
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
7257
|
+
import { EventEmitter as EventEmitter2 } from "events";
|
|
7258
|
+
import { mkdirSync as mkdirSync4, readdirSync as readdirSync2 } from "fs";
|
|
7259
|
+
import path11 from "path";
|
|
6689
7260
|
import {
|
|
6690
7261
|
AuthStorage,
|
|
6691
7262
|
createBashTool,
|
|
6692
|
-
|
|
6693
|
-
|
|
7263
|
+
createAgentSessionFromServices,
|
|
7264
|
+
createAgentSessionServices,
|
|
6694
7265
|
getAgentDir,
|
|
6695
|
-
ModelRegistry,
|
|
6696
7266
|
SessionManager,
|
|
6697
7267
|
SettingsManager,
|
|
6698
7268
|
VERSION as PI_SDK_VERSION
|
|
@@ -6712,7 +7282,7 @@ function createPiSdkEventMappingState(sessionId = null) {
|
|
|
6712
7282
|
};
|
|
6713
7283
|
}
|
|
6714
7284
|
function buildPiSessionDir(workingDirectory) {
|
|
6715
|
-
return
|
|
7285
|
+
return path11.join(workingDirectory, PI_SESSION_DIR);
|
|
6716
7286
|
}
|
|
6717
7287
|
async function buildPiSpawnEnv(ctx) {
|
|
6718
7288
|
return (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
@@ -6734,7 +7304,7 @@ function findPiSessionFile(sessionDir, sessionId) {
|
|
|
6734
7304
|
}
|
|
6735
7305
|
const suffix = `_${sessionId}.jsonl`;
|
|
6736
7306
|
const match = entries.find((entry) => entry.endsWith(suffix));
|
|
6737
|
-
return match ?
|
|
7307
|
+
return match ? path11.join(sessionDir, match) : null;
|
|
6738
7308
|
}
|
|
6739
7309
|
function detectPiModelsFromRegistry(modelRegistry) {
|
|
6740
7310
|
const models = [];
|
|
@@ -6751,8 +7321,70 @@ function detectPiModelsFromRegistry(modelRegistry) {
|
|
|
6751
7321
|
}
|
|
6752
7322
|
return models.length > 0 ? { models } : null;
|
|
6753
7323
|
}
|
|
6754
|
-
function
|
|
6755
|
-
|
|
7324
|
+
function applyPiDaemonSettingsOverrides(settingsManager) {
|
|
7325
|
+
settingsManager.applyOverrides({ compaction: { enabled: PI_SDK_COMPACTION_ENABLED } });
|
|
7326
|
+
}
|
|
7327
|
+
function logPiServiceDiagnostics(context, services) {
|
|
7328
|
+
for (const diagnostic of services.diagnostics) {
|
|
7329
|
+
const message = `[pi-driver] ${context} diagnostic: ${diagnostic.message}`;
|
|
7330
|
+
if (diagnostic.type === "info") {
|
|
7331
|
+
console.info(message);
|
|
7332
|
+
} else {
|
|
7333
|
+
console.warn(message);
|
|
7334
|
+
}
|
|
7335
|
+
}
|
|
7336
|
+
}
|
|
7337
|
+
function formatPiModelLogId(model) {
|
|
7338
|
+
return model ? `${model.provider}/${model.id}` : "default";
|
|
7339
|
+
}
|
|
7340
|
+
function piServiceDiagnosticTraceAttrs(services) {
|
|
7341
|
+
let info = 0;
|
|
7342
|
+
let warning = 0;
|
|
7343
|
+
for (const diagnostic of services.diagnostics) {
|
|
7344
|
+
if (diagnostic.type === "info") {
|
|
7345
|
+
info++;
|
|
7346
|
+
} else {
|
|
7347
|
+
warning++;
|
|
7348
|
+
}
|
|
7349
|
+
}
|
|
7350
|
+
return {
|
|
7351
|
+
diagnostics_count: services.diagnostics.length,
|
|
7352
|
+
diagnostic_info_count: info,
|
|
7353
|
+
diagnostic_warning_count: warning
|
|
7354
|
+
};
|
|
7355
|
+
}
|
|
7356
|
+
function addPiServiceTraceEvent(span, name, services, attrs = {}) {
|
|
7357
|
+
span?.addEvent(name, {
|
|
7358
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7359
|
+
...piServiceDiagnosticTraceAttrs(services),
|
|
7360
|
+
...attrs
|
|
7361
|
+
});
|
|
7362
|
+
}
|
|
7363
|
+
async function detectPiModels(modelRegistry, traceContext = {}) {
|
|
7364
|
+
if (modelRegistry) {
|
|
7365
|
+
return detectPiModelsFromRegistry(modelRegistry);
|
|
7366
|
+
}
|
|
7367
|
+
const agentDir = getAgentDir();
|
|
7368
|
+
const services = await createAgentSessionServices({
|
|
7369
|
+
cwd: process.cwd(),
|
|
7370
|
+
agentDir
|
|
7371
|
+
});
|
|
7372
|
+
logPiServiceDiagnostics("detect_models", services);
|
|
7373
|
+
addPiServiceTraceEvent(traceContext.span, "daemon.pi.models.services_ready", services);
|
|
7374
|
+
const result = detectPiModelsFromRegistry(services.modelRegistry);
|
|
7375
|
+
traceContext.span?.addEvent("daemon.pi.models.result", {
|
|
7376
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7377
|
+
returned_models_count: result?.models?.length ?? 0,
|
|
7378
|
+
outcome: result ? "models_returned" : "no_models",
|
|
7379
|
+
...piServiceDiagnosticTraceAttrs(services)
|
|
7380
|
+
});
|
|
7381
|
+
console.info(
|
|
7382
|
+
"[pi-driver] detect_models agentDir=%s available=%d returned=%d",
|
|
7383
|
+
agentDir,
|
|
7384
|
+
services.modelRegistry.getAvailable().length,
|
|
7385
|
+
result?.models?.length ?? 0
|
|
7386
|
+
);
|
|
7387
|
+
return result;
|
|
6756
7388
|
}
|
|
6757
7389
|
function humanizePiSegment(value) {
|
|
6758
7390
|
return value.split(/[-_/]/).filter(Boolean).map(formatPiLabelToken).join(" ");
|
|
@@ -6785,7 +7417,7 @@ function piErrorMessage(error) {
|
|
|
6785
7417
|
}
|
|
6786
7418
|
return "Unknown Pi error";
|
|
6787
7419
|
}
|
|
6788
|
-
function
|
|
7420
|
+
function pushSessionInitIfNeeded2(state, events) {
|
|
6789
7421
|
if (!state.sessionAnnounced && state.sessionId) {
|
|
6790
7422
|
events.push({ kind: "session_init", sessionId: state.sessionId });
|
|
6791
7423
|
state.sessionAnnounced = true;
|
|
@@ -6822,7 +7454,7 @@ function mapPiAssistantMessageEvent(assistantEvent, state) {
|
|
|
6822
7454
|
}
|
|
6823
7455
|
function mapPiSdkEventToParsedEvents(event, state) {
|
|
6824
7456
|
const events = [];
|
|
6825
|
-
|
|
7457
|
+
pushSessionInitIfNeeded2(state, events);
|
|
6826
7458
|
switch (event.type) {
|
|
6827
7459
|
case "agent_start":
|
|
6828
7460
|
case "turn_start":
|
|
@@ -6887,49 +7519,127 @@ var PI_IDLE_PROMPT_RETRY_MS = 25;
|
|
|
6887
7519
|
var PI_IDLE_PROMPT_MAX_WAIT_MS = 1e3;
|
|
6888
7520
|
async function createPiAgentSessionForContext(ctx, sessionId) {
|
|
6889
7521
|
const sessionDir = buildPiSessionDir(ctx.workingDirectory);
|
|
6890
|
-
|
|
6891
|
-
const spawnEnv = await buildPiSpawnEnv(ctx);
|
|
6892
|
-
const agentDir = spawnEnv.PI_CODING_AGENT_DIR || getAgentDir();
|
|
6893
|
-
const authStorage = AuthStorage.create(path10.join(agentDir, "auth.json"));
|
|
6894
|
-
const modelRegistry = ModelRegistry.create(authStorage, path10.join(agentDir, "models.json"));
|
|
7522
|
+
mkdirSync4(sessionDir, { recursive: true });
|
|
6895
7523
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
6896
|
-
const
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
7524
|
+
const requestedModel = launchRuntimeFields.model || "default";
|
|
7525
|
+
const traceSpan = ctx.tracer?.startSpan("daemon.pi.session.create", {
|
|
7526
|
+
surface: "daemon",
|
|
7527
|
+
kind: "internal",
|
|
7528
|
+
attrs: {
|
|
7529
|
+
agentId: ctx.agentId,
|
|
7530
|
+
launchId: ctx.launchId || void 0,
|
|
7531
|
+
runtime: ctx.config.runtime,
|
|
7532
|
+
model: ctx.config.model,
|
|
7533
|
+
session_id_present: Boolean(sessionId),
|
|
7534
|
+
requested_model: requestedModel
|
|
7535
|
+
}
|
|
6906
7536
|
});
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
7537
|
+
try {
|
|
7538
|
+
const spawnEnv = await buildPiSpawnEnv(ctx);
|
|
7539
|
+
const agentDir = spawnEnv.PI_CODING_AGENT_DIR || getAgentDir();
|
|
7540
|
+
const authStorage = AuthStorage.create(path11.join(agentDir, "auth.json"));
|
|
7541
|
+
const settingsManager = SettingsManager.create(ctx.workingDirectory, agentDir);
|
|
7542
|
+
const services = await createAgentSessionServices({
|
|
7543
|
+
cwd: ctx.workingDirectory,
|
|
7544
|
+
agentDir,
|
|
7545
|
+
authStorage,
|
|
7546
|
+
settingsManager,
|
|
7547
|
+
resourceLoaderOptions: {
|
|
7548
|
+
systemPromptOverride: () => ctx.standingPrompt
|
|
7549
|
+
}
|
|
7550
|
+
});
|
|
7551
|
+
applyPiDaemonSettingsOverrides(services.settingsManager);
|
|
7552
|
+
logPiServiceDiagnostics("create_session", services);
|
|
7553
|
+
addPiServiceTraceEvent(traceSpan, "daemon.pi.session.services_ready", services, {
|
|
7554
|
+
agent_dir_source: spawnEnv.PI_CODING_AGENT_DIR ? "spawn_env" : "default"
|
|
7555
|
+
});
|
|
7556
|
+
const model = resolvePiModelFromRegistry(launchRuntimeFields.model, services.modelRegistry);
|
|
7557
|
+
const resolvedModel = formatPiModelLogId(model);
|
|
7558
|
+
traceSpan?.addEvent("daemon.pi.session.model_resolved", {
|
|
7559
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7560
|
+
requested_model: requestedModel,
|
|
7561
|
+
requested_model_explicit: requestedModel !== "default",
|
|
7562
|
+
resolved_model: resolvedModel,
|
|
7563
|
+
resolved_model_present: Boolean(model)
|
|
7564
|
+
});
|
|
7565
|
+
console.info(
|
|
7566
|
+
"[pi-driver] create_session services_ready agentDir=%s available=%d requested=%s resolved=%s",
|
|
7567
|
+
agentDir,
|
|
7568
|
+
services.modelRegistry.getAvailable().length,
|
|
7569
|
+
requestedModel,
|
|
7570
|
+
resolvedModel
|
|
7571
|
+
);
|
|
7572
|
+
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default" && !model) {
|
|
7573
|
+
console.warn(
|
|
7574
|
+
"[pi-driver] create_session missing_model requested=%s available=%d",
|
|
7575
|
+
requestedModel,
|
|
7576
|
+
services.modelRegistry.getAvailable().length
|
|
7577
|
+
);
|
|
7578
|
+
traceSpan?.addEvent("daemon.pi.session.missing_model", {
|
|
7579
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7580
|
+
requested_model: requestedModel
|
|
7581
|
+
});
|
|
7582
|
+
traceSpan?.end("error", {
|
|
7583
|
+
attrs: {
|
|
7584
|
+
outcome: "missing_model",
|
|
7585
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7586
|
+
requested_model: requestedModel,
|
|
7587
|
+
resolved_model_present: false,
|
|
7588
|
+
...piServiceDiagnosticTraceAttrs(services)
|
|
7589
|
+
}
|
|
7590
|
+
});
|
|
7591
|
+
throw new Error(`Pi model not found: ${launchRuntimeFields.model}`);
|
|
7592
|
+
}
|
|
7593
|
+
const existingSessionFile = ctx.config.sessionId ? findPiSessionFile(sessionDir, ctx.config.sessionId) : null;
|
|
7594
|
+
const sessionManager = existingSessionFile ? SessionManager.open(existingSessionFile, sessionDir, ctx.workingDirectory) : SessionManager.create(ctx.workingDirectory, sessionDir, { id: sessionId });
|
|
7595
|
+
const { session } = await createAgentSessionFromServices({
|
|
7596
|
+
services,
|
|
7597
|
+
sessionManager,
|
|
7598
|
+
model,
|
|
7599
|
+
thinkingLevel: launchRuntimeFields.reasoningEffort,
|
|
7600
|
+
customTools: [
|
|
7601
|
+
createBashTool(ctx.workingDirectory, {
|
|
7602
|
+
spawnHook: (spawnContext) => ({
|
|
7603
|
+
...spawnContext,
|
|
7604
|
+
env: {
|
|
7605
|
+
...spawnContext.env,
|
|
7606
|
+
...spawnEnv
|
|
7607
|
+
}
|
|
7608
|
+
})
|
|
6926
7609
|
})
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
7610
|
+
]
|
|
7611
|
+
});
|
|
7612
|
+
traceSpan?.addEvent("daemon.pi.session.started", {
|
|
7613
|
+
requested_model: requestedModel,
|
|
7614
|
+
resolved_model: resolvedModel,
|
|
7615
|
+
session_id_present: Boolean(session.sessionId)
|
|
7616
|
+
});
|
|
7617
|
+
traceSpan?.end("ok", {
|
|
7618
|
+
attrs: {
|
|
7619
|
+
outcome: "started",
|
|
7620
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7621
|
+
requested_model: requestedModel,
|
|
7622
|
+
resolved_model: resolvedModel,
|
|
7623
|
+
resolved_model_present: Boolean(model),
|
|
7624
|
+
...piServiceDiagnosticTraceAttrs(services)
|
|
7625
|
+
}
|
|
7626
|
+
});
|
|
7627
|
+
console.info(
|
|
7628
|
+
"[pi-driver] create_session started sessionId=%s requested=%s resolved=%s",
|
|
7629
|
+
sessionId,
|
|
7630
|
+
requestedModel,
|
|
7631
|
+
resolvedModel
|
|
7632
|
+
);
|
|
7633
|
+
return session;
|
|
7634
|
+
} catch (error) {
|
|
7635
|
+
traceSpan?.end("error", {
|
|
7636
|
+
attrs: {
|
|
7637
|
+
outcome: "error",
|
|
7638
|
+
error_class: error instanceof Error ? error.name : typeof error
|
|
7639
|
+
}
|
|
7640
|
+
});
|
|
7641
|
+
throw error;
|
|
7642
|
+
}
|
|
6933
7643
|
}
|
|
6934
7644
|
var PiSdkRuntimeSession = class {
|
|
6935
7645
|
constructor(ctx, setCurrentSessionId, sessionFactory = createPiAgentSessionForContext) {
|
|
@@ -6939,7 +7649,7 @@ var PiSdkRuntimeSession = class {
|
|
|
6939
7649
|
this.mappingState = createPiSdkEventMappingState(ctx.config.sessionId || null);
|
|
6940
7650
|
}
|
|
6941
7651
|
descriptor = PI_RUNTIME_SESSION_DESCRIPTOR;
|
|
6942
|
-
events = new
|
|
7652
|
+
events = new EventEmitter2();
|
|
6943
7653
|
mappingState;
|
|
6944
7654
|
session = null;
|
|
6945
7655
|
unsubscribe = null;
|
|
@@ -6971,7 +7681,7 @@ var PiSdkRuntimeSession = class {
|
|
|
6971
7681
|
}
|
|
6972
7682
|
if (this.didClose) return { ok: false, reason: "closed" };
|
|
6973
7683
|
this.started = true;
|
|
6974
|
-
const sessionId = input.sessionId || this.ctx.config.sessionId ||
|
|
7684
|
+
const sessionId = input.sessionId || this.ctx.config.sessionId || randomUUID4();
|
|
6975
7685
|
this.mappingState.sessionId = sessionId;
|
|
6976
7686
|
this.setCurrentSessionId(sessionId);
|
|
6977
7687
|
const session = await this.sessionFactory({
|
|
@@ -7145,8 +7855,8 @@ var PiDriver = class {
|
|
|
7145
7855
|
version: PI_SDK_VERSION
|
|
7146
7856
|
};
|
|
7147
7857
|
}
|
|
7148
|
-
async detectModels() {
|
|
7149
|
-
return detectPiModels();
|
|
7858
|
+
async detectModels(ctx) {
|
|
7859
|
+
return detectPiModels(void 0, ctx);
|
|
7150
7860
|
}
|
|
7151
7861
|
createSession(ctx) {
|
|
7152
7862
|
this.sessionId = ctx.config.sessionId || null;
|
|
@@ -7182,7 +7892,7 @@ function delay(ms) {
|
|
|
7182
7892
|
}
|
|
7183
7893
|
|
|
7184
7894
|
// src/drivers/runtimeSession.ts
|
|
7185
|
-
import { EventEmitter as
|
|
7895
|
+
import { EventEmitter as EventEmitter3 } from "events";
|
|
7186
7896
|
function descriptorFromDriver(driver) {
|
|
7187
7897
|
const lifecycle = driver.lifecycle.kind === "per_turn" ? "turn_based" : "persistent_stream";
|
|
7188
7898
|
const idle = driver.supportsStdinNotification ? "stdin" : "unsupported";
|
|
@@ -7210,7 +7920,7 @@ var ChildProcessRuntimeSession = class {
|
|
|
7210
7920
|
this.descriptor = descriptorFromDriver(driver);
|
|
7211
7921
|
}
|
|
7212
7922
|
descriptor;
|
|
7213
|
-
events = new
|
|
7923
|
+
events = new EventEmitter3();
|
|
7214
7924
|
process = null;
|
|
7215
7925
|
started = false;
|
|
7216
7926
|
stdoutBuffer = "";
|
|
@@ -7323,7 +8033,13 @@ var driverFactories = {
|
|
|
7323
8033
|
copilot: () => new CopilotDriver(),
|
|
7324
8034
|
cursor: () => new CursorDriver(),
|
|
7325
8035
|
gemini: () => new GeminiDriver(),
|
|
8036
|
+
// Two separate Kimi runtimes (per #proj-runtime:cc818e65 6/16 consensus):
|
|
8037
|
+
// - `kimi` = legacy kimi-cli child-process driver. Backward-compat for
|
|
8038
|
+
// existing `runtime=kimi` agents. Frontend marks deprecated.
|
|
8039
|
+
// - `kimi-sdk` = canonical in-process SDK driver. Frontend label "Kimi Code".
|
|
8040
|
+
// No alias / no auto-migration; explicit pick at agent-create time.
|
|
7326
8041
|
kimi: () => new KimiDriver(),
|
|
8042
|
+
"kimi-sdk": () => new KimiSdkDriver(),
|
|
7327
8043
|
opencode: () => new OpenCodeDriver(),
|
|
7328
8044
|
pi: () => new PiDriver()
|
|
7329
8045
|
};
|
|
@@ -7338,7 +8054,7 @@ function getDriver(runtimeId) {
|
|
|
7338
8054
|
|
|
7339
8055
|
// src/workspaces.ts
|
|
7340
8056
|
import { readdir, rm, stat } from "fs/promises";
|
|
7341
|
-
import
|
|
8057
|
+
import path12 from "path";
|
|
7342
8058
|
function isValidWorkspaceDirectoryName(directoryName) {
|
|
7343
8059
|
return !directoryName.includes("/") && !directoryName.includes("\\") && !directoryName.includes("..");
|
|
7344
8060
|
}
|
|
@@ -7346,7 +8062,7 @@ function resolveWorkspaceDirectoryPath(dataDir, directoryName) {
|
|
|
7346
8062
|
if (!isValidWorkspaceDirectoryName(directoryName)) {
|
|
7347
8063
|
return null;
|
|
7348
8064
|
}
|
|
7349
|
-
return
|
|
8065
|
+
return path12.join(dataDir, directoryName);
|
|
7350
8066
|
}
|
|
7351
8067
|
function emptyWorkspaceDirectorySummary(latestMtime = /* @__PURE__ */ new Date(0)) {
|
|
7352
8068
|
return {
|
|
@@ -7395,7 +8111,7 @@ async function summarizeWorkspaceDirectory(dirPath) {
|
|
|
7395
8111
|
return summary;
|
|
7396
8112
|
}
|
|
7397
8113
|
const childSummaries = await Promise.all(
|
|
7398
|
-
entries.map((entry) => summarizeWorkspaceEntry(
|
|
8114
|
+
entries.map((entry) => summarizeWorkspaceEntry(path12.join(dirPath, entry.name), entry))
|
|
7399
8115
|
);
|
|
7400
8116
|
for (const childSummary of childSummaries) {
|
|
7401
8117
|
summary = mergeWorkspaceDirectorySummaries(summary, childSummary);
|
|
@@ -7414,7 +8130,7 @@ async function scanWorkspaceDirectories(dataDir) {
|
|
|
7414
8130
|
if (!entry.isDirectory()) {
|
|
7415
8131
|
return null;
|
|
7416
8132
|
}
|
|
7417
|
-
const dirPath =
|
|
8133
|
+
const dirPath = path12.join(dataDir, entry.name);
|
|
7418
8134
|
try {
|
|
7419
8135
|
const summary = await summarizeWorkspaceDirectory(dirPath);
|
|
7420
8136
|
return {
|
|
@@ -7965,12 +8681,12 @@ function findSessionJsonl(root, predicate) {
|
|
|
7965
8681
|
for (const entry of entries) {
|
|
7966
8682
|
if (++visited > maxEntries) return null;
|
|
7967
8683
|
if (!entry.isFile() || !predicate(entry.name)) continue;
|
|
7968
|
-
return
|
|
8684
|
+
return path13.join(dir, entry.name);
|
|
7969
8685
|
}
|
|
7970
8686
|
for (const entry of entries) {
|
|
7971
8687
|
if (++visited > maxEntries) return null;
|
|
7972
8688
|
if (!entry.isDirectory()) continue;
|
|
7973
|
-
const found = visit(
|
|
8689
|
+
const found = visit(path13.join(dir, entry.name), depth - 1);
|
|
7974
8690
|
if (found) return found;
|
|
7975
8691
|
}
|
|
7976
8692
|
return null;
|
|
@@ -7983,9 +8699,9 @@ function safeSessionFilename(value) {
|
|
|
7983
8699
|
}
|
|
7984
8700
|
function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
7985
8701
|
try {
|
|
7986
|
-
const dir =
|
|
7987
|
-
|
|
7988
|
-
const filePath =
|
|
8702
|
+
const dir = path13.join(fallbackDir, ".slock", "runtime-sessions");
|
|
8703
|
+
mkdirSync5(dir, { recursive: true });
|
|
8704
|
+
const filePath = path13.join(dir, `${runtime}-${safeSessionFilename(sessionId)}.jsonl`);
|
|
7989
8705
|
writeFileSync4(filePath, JSON.stringify({
|
|
7990
8706
|
type: "runtime_session_handoff",
|
|
7991
8707
|
runtime,
|
|
@@ -8017,7 +8733,7 @@ function ensureRuntimeHomeDir(config, defaultHomeDir, workspacePath) {
|
|
|
8017
8733
|
return defaultHomeDir;
|
|
8018
8734
|
}
|
|
8019
8735
|
function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os6.homedir(), fallbackDir) {
|
|
8020
|
-
const directPath =
|
|
8736
|
+
const directPath = path13.isAbsolute(sessionId) ? sessionId : null;
|
|
8021
8737
|
if (directPath) {
|
|
8022
8738
|
try {
|
|
8023
8739
|
if (statSync(directPath).isFile()) {
|
|
@@ -8026,7 +8742,7 @@ function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os6.homedir(), f
|
|
|
8026
8742
|
} catch {
|
|
8027
8743
|
}
|
|
8028
8744
|
}
|
|
8029
|
-
const resolvedPath = runtime === "claude" ? findSessionJsonl(
|
|
8745
|
+
const resolvedPath = runtime === "claude" ? findSessionJsonl(path13.join(homeDir, ".claude", "projects"), (filename) => filename === `${sessionId}.jsonl`) : runtime === "codex" ? findSessionJsonl(path13.join(homeDir, ".codex", "sessions"), (filename) => filename.endsWith(".jsonl") && filename.includes(sessionId)) : null;
|
|
8030
8746
|
if (!resolvedPath && fallbackDir) {
|
|
8031
8747
|
const fallback = writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir);
|
|
8032
8748
|
if (fallback) return fallback;
|
|
@@ -8751,6 +9467,9 @@ function resumeSessionRecoveryReason(ap) {
|
|
|
8751
9467
|
if (candidates.some(isOpenCodeReplayRejectedByProvider)) return "provider_replay_rejected";
|
|
8752
9468
|
return null;
|
|
8753
9469
|
}
|
|
9470
|
+
if (ap.driver.id === "pi") {
|
|
9471
|
+
return candidates.some(isPiReplayRejectedByProvider) ? "provider_replay_rejected" : null;
|
|
9472
|
+
}
|
|
8754
9473
|
if (ap.driver.id === "gemini") {
|
|
8755
9474
|
return candidates.some(
|
|
8756
9475
|
(text) => /Error resuming session:\s*Invalid session identifier/i.test(text) && text.includes(ap.sessionId)
|
|
@@ -8761,9 +9480,13 @@ function resumeSessionRecoveryReason(ap) {
|
|
|
8761
9480
|
function isOpenCodeReplayRejectedByProvider(text) {
|
|
8762
9481
|
return /Invalid request:\s*the message at position \d+ with role ['"]?assistant['"]? must not be empty/i.test(text);
|
|
8763
9482
|
}
|
|
9483
|
+
function isPiReplayRejectedByProvider(text) {
|
|
9484
|
+
return /Cannot continue from message role:\s*assistant/i.test(text);
|
|
9485
|
+
}
|
|
8764
9486
|
function resumeSessionRuntimeLabel(runtimeId) {
|
|
8765
9487
|
if (runtimeId === "opencode") return "OpenCode";
|
|
8766
9488
|
if (runtimeId === "gemini") return "Gemini";
|
|
9489
|
+
if (runtimeId === "pi") return "Pi";
|
|
8767
9490
|
return "Claude";
|
|
8768
9491
|
}
|
|
8769
9492
|
function classifyActivityDetailForTrace(detail) {
|
|
@@ -9032,6 +9755,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9032
9755
|
maxConcurrentAgentStarts;
|
|
9033
9756
|
agentStartIntervalMs;
|
|
9034
9757
|
startingInboxes = /* @__PURE__ */ new Map();
|
|
9758
|
+
terminalRuntimeFailures = /* @__PURE__ */ new Map();
|
|
9035
9759
|
pendingStartRebinds = /* @__PURE__ */ new Map();
|
|
9036
9760
|
/** Cached configs for agents whose process exited normally — enables auto-restart on next message */
|
|
9037
9761
|
idleAgentConfigs = /* @__PURE__ */ new Map();
|
|
@@ -9969,7 +10693,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9969
10693
|
);
|
|
9970
10694
|
wakeMessage = void 0;
|
|
9971
10695
|
}
|
|
9972
|
-
const agentDataDir =
|
|
10696
|
+
const agentDataDir = path13.join(this.dataDir, agentId);
|
|
9973
10697
|
await mkdir(agentDataDir, { recursive: true });
|
|
9974
10698
|
let runtimeConfig = withLocalRuntimeContext(config, agentId, agentDataDir);
|
|
9975
10699
|
const legacyRuntimeProfileControl = runtimeConfig.runtimeProfileControl?.kind === "migration" ? runtimeConfig.runtimeProfileControl : null;
|
|
@@ -9983,23 +10707,23 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9983
10707
|
);
|
|
9984
10708
|
runtimeConfig = { ...runtimeConfig, runtimeProfileControl: null };
|
|
9985
10709
|
}
|
|
9986
|
-
const memoryMdPath =
|
|
10710
|
+
const memoryMdPath = path13.join(agentDataDir, "MEMORY.md");
|
|
9987
10711
|
try {
|
|
9988
10712
|
await access(memoryMdPath);
|
|
9989
10713
|
} catch {
|
|
9990
10714
|
const initialMemoryMd = buildInitialMemoryMd(runtimeConfig);
|
|
9991
10715
|
await writeFile(memoryMdPath, initialMemoryMd);
|
|
9992
10716
|
}
|
|
9993
|
-
const notesDir =
|
|
10717
|
+
const notesDir = path13.join(agentDataDir, "notes");
|
|
9994
10718
|
await mkdir(notesDir, { recursive: true });
|
|
9995
10719
|
if (getOnboardingSeedMode(config) === FIRST_CINDY_SEED_MODE) {
|
|
9996
10720
|
const seedFiles = buildOnboardingSeedFiles();
|
|
9997
10721
|
for (const { relativePath, content } of seedFiles) {
|
|
9998
|
-
const fullPath =
|
|
10722
|
+
const fullPath = path13.join(agentDataDir, relativePath);
|
|
9999
10723
|
try {
|
|
10000
10724
|
await access(fullPath);
|
|
10001
10725
|
} catch {
|
|
10002
|
-
await mkdir(
|
|
10726
|
+
await mkdir(path13.dirname(fullPath), { recursive: true });
|
|
10003
10727
|
await writeFile(fullPath, content);
|
|
10004
10728
|
}
|
|
10005
10729
|
}
|
|
@@ -10116,7 +10840,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10116
10840
|
daemonApiKey: this.daemonApiKey,
|
|
10117
10841
|
launchId: effectiveLaunchId,
|
|
10118
10842
|
agentCredentialProxyInboxCoordinator: this.createAgentProxyInboxCoordinator(agentId),
|
|
10119
|
-
cliTransportTraceDir: this.cliTransportTraceDir
|
|
10843
|
+
cliTransportTraceDir: this.cliTransportTraceDir,
|
|
10844
|
+
tracer: this.tracer
|
|
10120
10845
|
};
|
|
10121
10846
|
const runtime = driver.createSession?.(runtimeContext) ?? createChildProcessRuntimeSession(driver, runtimeContext);
|
|
10122
10847
|
agentProcess = {
|
|
@@ -10395,10 +11120,24 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10395
11120
|
}
|
|
10396
11121
|
}
|
|
10397
11122
|
});
|
|
10398
|
-
|
|
11123
|
+
let startResult;
|
|
11124
|
+
try {
|
|
11125
|
+
startResult = await runtime.start({ text: prompt, sessionId: effectiveConfig.sessionId || null });
|
|
11126
|
+
} catch (error) {
|
|
11127
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11128
|
+
startResult = { ok: false, reason: "runtime_error", error: message };
|
|
11129
|
+
}
|
|
10399
11130
|
if (!startResult.ok) {
|
|
11131
|
+
const diagnostics = startResult.error ? buildRuntimeErrorDiagnosticEnvelope(startResult.error) : null;
|
|
11132
|
+
this.recordDaemonTrace("daemon.agent.runtime_start.failed", {
|
|
11133
|
+
...this.startQueueTraceAttrs(agentId, effectiveConfig, wakeMessage, unreadSummary, resumePrompt, agentProcess.launchId || void 0, wakeMessageTransient),
|
|
11134
|
+
runtime_start_reason: startResult.reason,
|
|
11135
|
+
error_present: Boolean(startResult.error),
|
|
11136
|
+
runtime_error_class: diagnostics?.spanAttrs.runtime_error_class
|
|
11137
|
+
}, "error");
|
|
10400
11138
|
throw new Error(`Runtime session failed to start: ${startResult.reason}${startResult.error ? ` (${startResult.error})` : ""}`);
|
|
10401
11139
|
}
|
|
11140
|
+
this.terminalRuntimeFailures.delete(agentId);
|
|
10402
11141
|
this.recordDaemonTrace("daemon.agent.spawn.created", {
|
|
10403
11142
|
...this.startQueueTraceAttrs(agentId, effectiveConfig, wakeMessage, unreadSummary, resumePrompt, agentProcess.launchId || void 0, wakeMessageTransient),
|
|
10404
11143
|
detached: false,
|
|
@@ -10452,6 +11191,52 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10452
11191
|
this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
|
|
10453
11192
|
this.agents.delete(agentId);
|
|
10454
11193
|
this.idleAgentConfigs.delete(agentId);
|
|
11194
|
+
this.terminalRuntimeFailures.delete(agentId);
|
|
11195
|
+
}
|
|
11196
|
+
cleanupTerminalRuntimeFailure(agentId, ap, detail) {
|
|
11197
|
+
if (this.agents.get(agentId) !== ap) return;
|
|
11198
|
+
ap.notifications.clear();
|
|
11199
|
+
this.clearRuntimeErrorDeliveryBackoff(ap);
|
|
11200
|
+
if (ap.pendingTrajectory?.timer) {
|
|
11201
|
+
clearTimeout(ap.pendingTrajectory.timer);
|
|
11202
|
+
ap.pendingTrajectory.timer = null;
|
|
11203
|
+
}
|
|
11204
|
+
if (ap.activityHeartbeat) {
|
|
11205
|
+
clearInterval(ap.activityHeartbeat);
|
|
11206
|
+
ap.activityHeartbeat = null;
|
|
11207
|
+
}
|
|
11208
|
+
this.clearCompactionWatchdog(ap);
|
|
11209
|
+
this.clearRuntimeStartupTimeout(ap);
|
|
11210
|
+
this.clearStalledRecoverySigtermWatchdog(ap);
|
|
11211
|
+
cleanupAgentCredentialProxy(agentId, ap.launchId);
|
|
11212
|
+
this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
|
|
11213
|
+
this.idleAgentConfigs.delete(agentId);
|
|
11214
|
+
const pending = this.startingInboxes.get(agentId) || [];
|
|
11215
|
+
if (ap.inbox.length > 0) {
|
|
11216
|
+
this.startingInboxes.set(agentId, [...pending, ...ap.inbox]);
|
|
11217
|
+
}
|
|
11218
|
+
this.terminalRuntimeFailures.set(agentId, { detail, launchId: ap.launchId });
|
|
11219
|
+
this.agents.delete(agentId);
|
|
11220
|
+
const diagnostics = buildRuntimeErrorDiagnosticEnvelope(detail);
|
|
11221
|
+
this.recordDaemonTrace("daemon.agent.terminal_runtime_error.cleanup", {
|
|
11222
|
+
agentId,
|
|
11223
|
+
launchId: ap.launchId || void 0,
|
|
11224
|
+
runtime: ap.config.runtime,
|
|
11225
|
+
model: ap.config.model,
|
|
11226
|
+
session_id_present: Boolean(ap.sessionId),
|
|
11227
|
+
process_pid_present: typeof ap.runtime.pid === "number",
|
|
11228
|
+
inbox_count: ap.inbox.length,
|
|
11229
|
+
pending_notification_count: ap.notifications.pendingCount,
|
|
11230
|
+
runtime_error_class: diagnostics.spanAttrs.runtime_error_class
|
|
11231
|
+
}, "error");
|
|
11232
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
11233
|
+
stop_source: "terminal_runtime_error",
|
|
11234
|
+
runtime_error_class: diagnostics.spanAttrs.runtime_error_class
|
|
11235
|
+
});
|
|
11236
|
+
void ap.runtime.stop({ signal: "SIGTERM", reason: "terminal_runtime_error" }).catch((err) => {
|
|
11237
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11238
|
+
logger.warn(`[Agent ${agentId}] Failed to terminate ${ap.driver.id} after terminal runtime error: ${reason}`);
|
|
11239
|
+
});
|
|
10455
11240
|
}
|
|
10456
11241
|
cacheStartupTimeoutRetryConfig(agentId, ap) {
|
|
10457
11242
|
const retryConfig = {
|
|
@@ -10690,6 +11475,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10690
11475
|
this.cancelQueuedAgentStart(agentId, "stop requested");
|
|
10691
11476
|
this.pendingStartRebinds.delete(agentId);
|
|
10692
11477
|
this.idleAgentConfigs.delete(agentId);
|
|
11478
|
+
this.terminalRuntimeFailures.delete(agentId);
|
|
10693
11479
|
const ap = this.agents.get(agentId);
|
|
10694
11480
|
if (!ap) {
|
|
10695
11481
|
if (!silent) {
|
|
@@ -10792,6 +11578,35 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10792
11578
|
}));
|
|
10793
11579
|
return true;
|
|
10794
11580
|
}
|
|
11581
|
+
const terminalRuntimeFailure = this.terminalRuntimeFailures.get(agentId);
|
|
11582
|
+
if (terminalRuntimeFailure) {
|
|
11583
|
+
if (transientDelivery) {
|
|
11584
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
11585
|
+
outcome: "transient_dropped_terminal_runtime_error_no_process",
|
|
11586
|
+
accepted: true,
|
|
11587
|
+
process_present: false,
|
|
11588
|
+
cached_idle_config_present: false,
|
|
11589
|
+
terminal_runtime_failure: true,
|
|
11590
|
+
launchId: terminalRuntimeFailure.launchId || void 0
|
|
11591
|
+
}));
|
|
11592
|
+
return true;
|
|
11593
|
+
}
|
|
11594
|
+
const pending = this.startingInboxes.get(agentId) || [];
|
|
11595
|
+
pending.push(message);
|
|
11596
|
+
this.startingInboxes.set(agentId, pending);
|
|
11597
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
11598
|
+
outcome: "queued_terminal_runtime_error_no_process",
|
|
11599
|
+
accepted: true,
|
|
11600
|
+
process_present: false,
|
|
11601
|
+
cached_idle_config_present: false,
|
|
11602
|
+
terminal_runtime_failure: true,
|
|
11603
|
+
starting_inbox_count: pending.length,
|
|
11604
|
+
launchId: terminalRuntimeFailure.launchId || void 0
|
|
11605
|
+
}));
|
|
11606
|
+
this.sendAgentStatus(agentId, "inactive", terminalRuntimeFailure.launchId);
|
|
11607
|
+
this.broadcastActivity(agentId, "error", terminalRuntimeFailure.detail, [], terminalRuntimeFailure.launchId);
|
|
11608
|
+
return true;
|
|
11609
|
+
}
|
|
10795
11610
|
const cached = this.idleAgentConfigs.get(agentId);
|
|
10796
11611
|
if (cached) {
|
|
10797
11612
|
const driver = this.driverResolver(cached.config.runtime || "claude");
|
|
@@ -11135,7 +11950,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11135
11950
|
return true;
|
|
11136
11951
|
}
|
|
11137
11952
|
async resetWorkspace(agentId) {
|
|
11138
|
-
const agentDataDir =
|
|
11953
|
+
const agentDataDir = path13.join(this.dataDir, agentId);
|
|
11139
11954
|
try {
|
|
11140
11955
|
await rm2(agentDataDir, { recursive: true, force: true });
|
|
11141
11956
|
logger.info(`[Agent ${agentId}] Workspace reset complete (${agentDataDir})`);
|
|
@@ -11196,7 +12011,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11196
12011
|
return result;
|
|
11197
12012
|
}
|
|
11198
12013
|
buildRuntimeProfileReport(agentId, config, sessionId, launchId) {
|
|
11199
|
-
const workspacePath =
|
|
12014
|
+
const workspacePath = path13.join(this.dataDir, agentId);
|
|
11200
12015
|
const runtimeHomeDir = resolveRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspacePath);
|
|
11201
12016
|
return {
|
|
11202
12017
|
agentId,
|
|
@@ -11490,7 +12305,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11490
12305
|
}
|
|
11491
12306
|
// Workspace file browsing
|
|
11492
12307
|
async getFileTree(agentId, dirPath) {
|
|
11493
|
-
const agentDir =
|
|
12308
|
+
const agentDir = path13.join(this.dataDir, agentId);
|
|
11494
12309
|
try {
|
|
11495
12310
|
await stat2(agentDir);
|
|
11496
12311
|
} catch {
|
|
@@ -11498,8 +12313,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11498
12313
|
}
|
|
11499
12314
|
let targetDir = agentDir;
|
|
11500
12315
|
if (dirPath) {
|
|
11501
|
-
const resolved =
|
|
11502
|
-
if (!resolved.startsWith(agentDir +
|
|
12316
|
+
const resolved = path13.resolve(agentDir, dirPath);
|
|
12317
|
+
if (!resolved.startsWith(agentDir + path13.sep) && resolved !== agentDir) {
|
|
11503
12318
|
return [];
|
|
11504
12319
|
}
|
|
11505
12320
|
targetDir = resolved;
|
|
@@ -11507,14 +12322,14 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11507
12322
|
return this.listDirectoryChildren(targetDir, agentDir);
|
|
11508
12323
|
}
|
|
11509
12324
|
async readFile(agentId, filePath) {
|
|
11510
|
-
const agentDir =
|
|
11511
|
-
const resolved =
|
|
11512
|
-
if (!resolved.startsWith(agentDir +
|
|
12325
|
+
const agentDir = path13.join(this.dataDir, agentId);
|
|
12326
|
+
const resolved = path13.resolve(agentDir, filePath);
|
|
12327
|
+
if (!resolved.startsWith(agentDir + path13.sep) && resolved !== agentDir) {
|
|
11513
12328
|
throw new Error("Access denied");
|
|
11514
12329
|
}
|
|
11515
12330
|
const info = await stat2(resolved);
|
|
11516
12331
|
if (info.isDirectory()) throw new Error("Cannot read a directory");
|
|
11517
|
-
const ext =
|
|
12332
|
+
const ext = path13.extname(resolved).toLowerCase();
|
|
11518
12333
|
if (WORKSPACE_TEXT_EXTENSIONS.has(ext) || ext === "") {
|
|
11519
12334
|
if (info.size > WORKSPACE_TEXT_FILE_MAX_BYTES) throw new Error("File too large");
|
|
11520
12335
|
const content = await readFile(resolved, "utf-8");
|
|
@@ -11550,14 +12365,14 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11550
12365
|
const idle = this.idleAgentConfigs.get(agentId);
|
|
11551
12366
|
const config = agent?.config ?? idle?.config ?? null;
|
|
11552
12367
|
const runtime = runtimeHint || config?.runtime || "claude";
|
|
11553
|
-
const workspaceDir =
|
|
12368
|
+
const workspaceDir = path13.join(this.dataDir, agentId);
|
|
11554
12369
|
const home = config ? ensureRuntimeHomeDir(config, os6.homedir(), workspaceDir) : os6.homedir();
|
|
11555
12370
|
const paths = _AgentProcessManager.SKILL_PATHS[runtime] || _AgentProcessManager.SKILL_PATHS.claude;
|
|
11556
12371
|
const globalResults = await Promise.all(
|
|
11557
|
-
paths.global.map((p) => this.scanSkillsDir(
|
|
12372
|
+
paths.global.map((p) => this.scanSkillsDir(path13.join(home, p)))
|
|
11558
12373
|
);
|
|
11559
12374
|
const workspaceResults = await Promise.all(
|
|
11560
|
-
paths.workspace.map((p) => this.scanSkillsDir(
|
|
12375
|
+
paths.workspace.map((p) => this.scanSkillsDir(path13.join(workspaceDir, p)))
|
|
11561
12376
|
);
|
|
11562
12377
|
const dedup = (skills) => {
|
|
11563
12378
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -11586,7 +12401,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11586
12401
|
const skills = [];
|
|
11587
12402
|
for (const entry of entries) {
|
|
11588
12403
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
11589
|
-
const skillMd =
|
|
12404
|
+
const skillMd = path13.join(dir, entry.name, "SKILL.md");
|
|
11590
12405
|
try {
|
|
11591
12406
|
const content = await readFile(skillMd, "utf-8");
|
|
11592
12407
|
const skill = this.parseSkillMd(entry.name, content);
|
|
@@ -11597,7 +12412,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11597
12412
|
} else if (entry.name.endsWith(".md")) {
|
|
11598
12413
|
const cmdName = entry.name.replace(/\.md$/, "");
|
|
11599
12414
|
try {
|
|
11600
|
-
const content = await readFile(
|
|
12415
|
+
const content = await readFile(path13.join(dir, entry.name), "utf-8");
|
|
11601
12416
|
const skill = this.parseSkillMd(cmdName, content);
|
|
11602
12417
|
skill.sourcePath = dir;
|
|
11603
12418
|
skills.push(skill);
|
|
@@ -12574,8 +13389,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
12574
13389
|
logger.warn(`[Agent ${agentId}] Failed to terminate ${ap.driver.id} after auth error: ${reason}`);
|
|
12575
13390
|
}
|
|
12576
13391
|
} else if (stickyTerminalFailure) {
|
|
12577
|
-
ap.notifications.clear();
|
|
12578
13392
|
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
13393
|
+
this.cleanupTerminalRuntimeFailure(agentId, ap, stickyTerminalFailure.detail);
|
|
12579
13394
|
logger.warn(`[Agent ${agentId}] ${ap.driver.id} terminal runtime error requires explicit recovery`);
|
|
12580
13395
|
} else {
|
|
12581
13396
|
ap.notifications.clearPending();
|
|
@@ -13077,8 +13892,8 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
13077
13892
|
const nodes = [];
|
|
13078
13893
|
for (const entry of entries) {
|
|
13079
13894
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
13080
|
-
const fullPath =
|
|
13081
|
-
const relativePath =
|
|
13895
|
+
const fullPath = path13.join(dir, entry.name);
|
|
13896
|
+
const relativePath = path13.relative(rootDir, fullPath);
|
|
13082
13897
|
let info;
|
|
13083
13898
|
try {
|
|
13084
13899
|
info = await stat2(fullPath);
|
|
@@ -13451,10 +14266,10 @@ var ReminderCache = class {
|
|
|
13451
14266
|
};
|
|
13452
14267
|
|
|
13453
14268
|
// src/machineLock.ts
|
|
13454
|
-
import { createHash as createHash4, randomUUID as
|
|
13455
|
-
import { mkdirSync as
|
|
14269
|
+
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
14270
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
13456
14271
|
import os7 from "os";
|
|
13457
|
-
import
|
|
14272
|
+
import path14 from "path";
|
|
13458
14273
|
var INCOMPLETE_LOCK_STALE_MS = 3e4;
|
|
13459
14274
|
var DaemonMachineLockConflictError = class extends Error {
|
|
13460
14275
|
code = "DAEMON_MACHINE_LOCK_HELD";
|
|
@@ -13476,7 +14291,7 @@ function resolveDefaultMachineStateRoot() {
|
|
|
13476
14291
|
return resolveSlockHomePath("machines");
|
|
13477
14292
|
}
|
|
13478
14293
|
function ownerPath(lockDir) {
|
|
13479
|
-
return
|
|
14294
|
+
return path14.join(lockDir, "owner.json");
|
|
13480
14295
|
}
|
|
13481
14296
|
function readOwner(lockDir) {
|
|
13482
14297
|
try {
|
|
@@ -13506,13 +14321,13 @@ function acquireDaemonMachineLock(options) {
|
|
|
13506
14321
|
const rootDir = options.rootDir ?? resolveDefaultMachineStateRoot();
|
|
13507
14322
|
const fingerprint = apiKeyFingerprint(options.apiKey);
|
|
13508
14323
|
const lockId = getDaemonMachineLockId(options.apiKey);
|
|
13509
|
-
const machineDir =
|
|
13510
|
-
const lockDir =
|
|
13511
|
-
const token =
|
|
13512
|
-
|
|
14324
|
+
const machineDir = path14.join(rootDir, lockId);
|
|
14325
|
+
const lockDir = path14.join(machineDir, "daemon.lock");
|
|
14326
|
+
const token = randomUUID5();
|
|
14327
|
+
mkdirSync6(machineDir, { recursive: true });
|
|
13513
14328
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
13514
14329
|
try {
|
|
13515
|
-
|
|
14330
|
+
mkdirSync6(lockDir);
|
|
13516
14331
|
const owner = {
|
|
13517
14332
|
pid: process.pid,
|
|
13518
14333
|
token,
|
|
@@ -13567,8 +14382,8 @@ function acquireDaemonMachineLock(options) {
|
|
|
13567
14382
|
}
|
|
13568
14383
|
|
|
13569
14384
|
// src/localTraceSink.ts
|
|
13570
|
-
import { appendFileSync, mkdirSync as
|
|
13571
|
-
import
|
|
14385
|
+
import { appendFileSync, mkdirSync as mkdirSync7, readdirSync as readdirSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
14386
|
+
import path15 from "path";
|
|
13572
14387
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
13573
14388
|
var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
|
|
13574
14389
|
var DEFAULT_MAX_FILES = 8;
|
|
@@ -13605,7 +14420,7 @@ var LocalRotatingTraceSink = class {
|
|
|
13605
14420
|
currentSize = 0;
|
|
13606
14421
|
sequence = 0;
|
|
13607
14422
|
constructor(options) {
|
|
13608
|
-
this.traceDir =
|
|
14423
|
+
this.traceDir = path15.join(options.machineDir, "traces");
|
|
13609
14424
|
this.maxFileBytes = Math.max(1024, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES));
|
|
13610
14425
|
const baseAgeMs = Math.max(1e3, Math.floor(options.maxFileAgeMs ?? DEFAULT_MAX_FILE_AGE_MS));
|
|
13611
14426
|
const ageJitterMs = Math.max(0, Math.floor(options.maxFileAgeJitterMs ?? 0));
|
|
@@ -13631,11 +14446,11 @@ var LocalRotatingTraceSink = class {
|
|
|
13631
14446
|
return this.currentFile;
|
|
13632
14447
|
}
|
|
13633
14448
|
ensureFile(nextBytes) {
|
|
13634
|
-
|
|
14449
|
+
mkdirSync7(this.traceDir, { recursive: true, mode: 448 });
|
|
13635
14450
|
const nowMs = this.nowMsProvider();
|
|
13636
14451
|
const shouldRotateForAge = this.currentFileOpenedAtMs !== null && nowMs - this.currentFileOpenedAtMs >= this.maxFileAgeMs;
|
|
13637
14452
|
if (!this.currentFile || this.currentSize + nextBytes > this.maxFileBytes || shouldRotateForAge) {
|
|
13638
|
-
this.currentFile =
|
|
14453
|
+
this.currentFile = path15.join(
|
|
13639
14454
|
this.traceDir,
|
|
13640
14455
|
`daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
|
|
13641
14456
|
);
|
|
@@ -13650,7 +14465,7 @@ var LocalRotatingTraceSink = class {
|
|
|
13650
14465
|
const excess = files.length - this.maxFiles;
|
|
13651
14466
|
if (excess <= 0) return;
|
|
13652
14467
|
for (const file of files.slice(0, excess)) {
|
|
13653
|
-
rmSync4(
|
|
14468
|
+
rmSync4(path15.join(this.traceDir, file), { force: true });
|
|
13654
14469
|
}
|
|
13655
14470
|
}
|
|
13656
14471
|
};
|
|
@@ -13738,10 +14553,10 @@ function isDiagnosticErrorAttr(key) {
|
|
|
13738
14553
|
}
|
|
13739
14554
|
|
|
13740
14555
|
// src/traceBundleUpload.ts
|
|
13741
|
-
import { createHash as createHash6, randomUUID as
|
|
14556
|
+
import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
|
|
13742
14557
|
import { gzipSync } from "zlib";
|
|
13743
14558
|
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
13744
|
-
import
|
|
14559
|
+
import path16 from "path";
|
|
13745
14560
|
|
|
13746
14561
|
// src/chatBridgeRequest.ts
|
|
13747
14562
|
var DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS = Number.parseInt(
|
|
@@ -13841,8 +14656,8 @@ async function executeResponseRequest(url, init, {
|
|
|
13841
14656
|
}
|
|
13842
14657
|
|
|
13843
14658
|
// src/directUploadCapability.ts
|
|
13844
|
-
function joinUrl(base,
|
|
13845
|
-
return `${base.replace(/\/+$/, "")}${
|
|
14659
|
+
function joinUrl(base, path18) {
|
|
14660
|
+
return `${base.replace(/\/+$/, "")}${path18}`;
|
|
13846
14661
|
}
|
|
13847
14662
|
function jsonHeaders(apiKey) {
|
|
13848
14663
|
return {
|
|
@@ -14061,7 +14876,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
14061
14876
|
}, nextMs);
|
|
14062
14877
|
}
|
|
14063
14878
|
async findUploadCandidates() {
|
|
14064
|
-
const traceDir =
|
|
14879
|
+
const traceDir = path16.join(this.options.machineDir, "traces");
|
|
14065
14880
|
let names;
|
|
14066
14881
|
try {
|
|
14067
14882
|
names = await readdir3(traceDir);
|
|
@@ -14073,8 +14888,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
14073
14888
|
const currentFile = this.options.currentFileProvider?.();
|
|
14074
14889
|
const candidates = [];
|
|
14075
14890
|
for (const name of names.filter((entry) => entry.startsWith("daemon-trace-") && entry.endsWith(".jsonl")).sort()) {
|
|
14076
|
-
const file =
|
|
14077
|
-
if (currentFile &&
|
|
14891
|
+
const file = path16.join(traceDir, name);
|
|
14892
|
+
if (currentFile && path16.resolve(file) === path16.resolve(currentFile)) continue;
|
|
14078
14893
|
if (await this.isUploaded(file)) continue;
|
|
14079
14894
|
try {
|
|
14080
14895
|
const info = await stat3(file);
|
|
@@ -14106,7 +14921,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
14106
14921
|
}
|
|
14107
14922
|
const gzipped = gzipSync(raw);
|
|
14108
14923
|
const bundleSha256 = sha256Hex(gzipped);
|
|
14109
|
-
const bundleId =
|
|
14924
|
+
const bundleId = randomUUID6();
|
|
14110
14925
|
await uploadWithSignedCapability({
|
|
14111
14926
|
serverUrl: this.options.serverUrl,
|
|
14112
14927
|
apiKey: this.options.apiKey,
|
|
@@ -14148,8 +14963,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
14148
14963
|
}
|
|
14149
14964
|
}
|
|
14150
14965
|
uploadStatePath(file) {
|
|
14151
|
-
const stateDir =
|
|
14152
|
-
return
|
|
14966
|
+
const stateDir = path16.join(this.options.machineDir, "trace-uploads");
|
|
14967
|
+
return path16.join(stateDir, `${path16.basename(file)}.uploaded.json`);
|
|
14153
14968
|
}
|
|
14154
14969
|
async isUploaded(file) {
|
|
14155
14970
|
try {
|
|
@@ -14161,9 +14976,9 @@ var DaemonTraceBundleUploader = class {
|
|
|
14161
14976
|
}
|
|
14162
14977
|
async markUploaded(file, metadata) {
|
|
14163
14978
|
const stateFile = this.uploadStatePath(file);
|
|
14164
|
-
await mkdir2(
|
|
14979
|
+
await mkdir2(path16.dirname(stateFile), { recursive: true, mode: 448 });
|
|
14165
14980
|
await writeFile2(stateFile, `${JSON.stringify({
|
|
14166
|
-
file:
|
|
14981
|
+
file: path16.basename(file),
|
|
14167
14982
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14168
14983
|
...metadata
|
|
14169
14984
|
}, null, 2)}
|
|
@@ -14226,11 +15041,29 @@ var DAEMON_CORE_TRACE_ATTR_CONTRACTS = {
|
|
|
14226
15041
|
"daemon.runtime_profile.report.sent": {
|
|
14227
15042
|
spanAttrs: ["agentId", "launchId", "runtime", "report_source", "model_present", "session_ref_present", "workspace_ref_present"]
|
|
14228
15043
|
},
|
|
15044
|
+
"daemon.runtime_models.detect": {
|
|
15045
|
+
spanAttrs: ["runtime", "requestId"],
|
|
15046
|
+
eventAttrs: {
|
|
15047
|
+
"daemon.pi.models.services_ready": ["available_models_count", "diagnostics_count", "diagnostic_info_count", "diagnostic_warning_count"],
|
|
15048
|
+
"daemon.pi.models.result": ["available_models_count", "returned_models_count", "diagnostics_count", "diagnostic_info_count", "diagnostic_warning_count", "outcome"]
|
|
15049
|
+
},
|
|
15050
|
+
endAttrs: ["outcome", "models_count", "default_model_present", "verified_as", "error_class"]
|
|
15051
|
+
},
|
|
15052
|
+
"daemon.pi.session.create": {
|
|
15053
|
+
spanAttrs: ["agentId", "launchId", "runtime", "model", "session_id_present", "requested_model"],
|
|
15054
|
+
eventAttrs: {
|
|
15055
|
+
"daemon.pi.session.services_ready": ["available_models_count", "diagnostics_count", "diagnostic_info_count", "diagnostic_warning_count", "agent_dir_source"],
|
|
15056
|
+
"daemon.pi.session.model_resolved": ["available_models_count", "requested_model", "requested_model_explicit", "resolved_model", "resolved_model_present"],
|
|
15057
|
+
"daemon.pi.session.missing_model": ["available_models_count", "requested_model"],
|
|
15058
|
+
"daemon.pi.session.started": ["requested_model", "resolved_model", "session_id_present"]
|
|
15059
|
+
},
|
|
15060
|
+
endAttrs: ["outcome", "available_models_count", "diagnostics_count", "diagnostic_info_count", "diagnostic_warning_count", "requested_model", "resolved_model", "resolved_model_present", "error_class"]
|
|
15061
|
+
},
|
|
14229
15062
|
"daemon.connection.local_disconnect_observed": {
|
|
14230
15063
|
spanAttrs: ["running_agents_count", "idle_agents_count"]
|
|
14231
15064
|
}
|
|
14232
15065
|
};
|
|
14233
|
-
var DAEMON_CLI_USAGE =
|
|
15066
|
+
var DAEMON_CLI_USAGE = `Usage: slock-daemon --server-url <url> (--api-key <key> or ${DAEMON_API_KEY_ENV}=<key>)`;
|
|
14234
15067
|
var RunnerCredentialMintError2 = class extends Error {
|
|
14235
15068
|
code;
|
|
14236
15069
|
retryable;
|
|
@@ -14266,9 +15099,9 @@ function runnerCredentialErrorDetail2(error) {
|
|
|
14266
15099
|
async function waitForRunnerCredentialRetry2() {
|
|
14267
15100
|
await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
|
|
14268
15101
|
}
|
|
14269
|
-
function parseDaemonCliArgs(args) {
|
|
15102
|
+
function parseDaemonCliArgs(args, env = {}) {
|
|
14270
15103
|
let serverUrl = "";
|
|
14271
|
-
let apiKey = "";
|
|
15104
|
+
let apiKey = env[DAEMON_API_KEY_ENV] ?? "";
|
|
14272
15105
|
for (let i = 0; i < args.length; i++) {
|
|
14273
15106
|
if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
|
|
14274
15107
|
if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
|
|
@@ -14278,20 +15111,20 @@ function parseDaemonCliArgs(args) {
|
|
|
14278
15111
|
}
|
|
14279
15112
|
function readDaemonVersion(moduleUrl = import.meta.url) {
|
|
14280
15113
|
try {
|
|
14281
|
-
const require2 =
|
|
15114
|
+
const require2 = createRequire3(moduleUrl);
|
|
14282
15115
|
return require2("../package.json").version;
|
|
14283
15116
|
} catch {
|
|
14284
15117
|
return "0.0.0-dev";
|
|
14285
15118
|
}
|
|
14286
15119
|
}
|
|
14287
15120
|
function resolveSlockCliPath(moduleUrl = import.meta.url) {
|
|
14288
|
-
const thisDir =
|
|
14289
|
-
const bundledDistPath =
|
|
15121
|
+
const thisDir = path17.dirname(fileURLToPath(moduleUrl));
|
|
15122
|
+
const bundledDistPath = path17.resolve(thisDir, "cli", "index.js");
|
|
14290
15123
|
try {
|
|
14291
15124
|
accessSync(bundledDistPath);
|
|
14292
15125
|
return bundledDistPath;
|
|
14293
15126
|
} catch {
|
|
14294
|
-
const workspaceDistPath =
|
|
15127
|
+
const workspaceDistPath = path17.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
|
|
14295
15128
|
accessSync(workspaceDistPath);
|
|
14296
15129
|
return workspaceDistPath;
|
|
14297
15130
|
}
|
|
@@ -14305,7 +15138,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
|
|
|
14305
15138
|
}
|
|
14306
15139
|
async function runBundledSlockCli(argv) {
|
|
14307
15140
|
process.argv = [process.execPath, "slock", ...argv];
|
|
14308
|
-
await import("./dist-
|
|
15141
|
+
await import("./dist-6YUWBDWX.js");
|
|
14309
15142
|
}
|
|
14310
15143
|
function detectRuntimes(tracer = noopTracer) {
|
|
14311
15144
|
const ids = [];
|
|
@@ -14497,7 +15330,7 @@ var DaemonCore = class {
|
|
|
14497
15330
|
}
|
|
14498
15331
|
resolveMachineStateRoot() {
|
|
14499
15332
|
if (this.options.machineStateDir) return this.options.machineStateDir;
|
|
14500
|
-
if (this.options.dataDir) return
|
|
15333
|
+
if (this.options.dataDir) return path17.join(path17.dirname(this.options.dataDir), "machines");
|
|
14501
15334
|
return resolveDefaultMachineStateRoot();
|
|
14502
15335
|
}
|
|
14503
15336
|
shouldEnableLocalTrace() {
|
|
@@ -14524,7 +15357,7 @@ var DaemonCore = class {
|
|
|
14524
15357
|
sink: this.localTraceSink
|
|
14525
15358
|
}));
|
|
14526
15359
|
this.agentManager.setTracer(this.tracer);
|
|
14527
|
-
this.agentManager.setCliTransportTraceDir(
|
|
15360
|
+
this.agentManager.setCliTransportTraceDir(path17.join(machineDir, "traces"));
|
|
14528
15361
|
}
|
|
14529
15362
|
installTraceBundleUploader(machineDir) {
|
|
14530
15363
|
if (!this.shouldEnableLocalTrace()) return;
|
|
@@ -14926,7 +15759,15 @@ var DaemonCore = class {
|
|
|
14926
15759
|
break;
|
|
14927
15760
|
case "machine:runtime_models:detect": {
|
|
14928
15761
|
const driver = getDriver(msg.runtime);
|
|
14929
|
-
const
|
|
15762
|
+
const span = this.tracer.startSpan("daemon.runtime_models.detect", {
|
|
15763
|
+
surface: "daemon",
|
|
15764
|
+
kind: "internal",
|
|
15765
|
+
attrs: {
|
|
15766
|
+
runtime: msg.runtime,
|
|
15767
|
+
requestId: msg.requestId
|
|
15768
|
+
}
|
|
15769
|
+
});
|
|
15770
|
+
const detect = typeof driver?.detectModels === "function" ? driver.detectModels({ tracer: this.tracer, span }) : Promise.resolve(null);
|
|
14930
15771
|
Promise.resolve(detect).then((result) => {
|
|
14931
15772
|
if (result) {
|
|
14932
15773
|
const verified = driver.model.detectedModelsVerifiedAs;
|
|
@@ -14935,12 +15776,32 @@ var DaemonCore = class {
|
|
|
14935
15776
|
verified: model.verified ?? verified
|
|
14936
15777
|
}));
|
|
14937
15778
|
this.connection.send({ type: "machine:runtime_models:result", requestId: msg.requestId, models, default: result.default });
|
|
15779
|
+
span.end("ok", {
|
|
15780
|
+
attrs: {
|
|
15781
|
+
outcome: "models_returned",
|
|
15782
|
+
models_count: models.length,
|
|
15783
|
+
default_model_present: Boolean(result.default),
|
|
15784
|
+
verified_as: verified
|
|
15785
|
+
}
|
|
15786
|
+
});
|
|
14938
15787
|
} else {
|
|
14939
15788
|
this.connection.send({ type: "machine:runtime_models:result", requestId: msg.requestId, error: "unsupported" });
|
|
15789
|
+
span.end("ok", {
|
|
15790
|
+
attrs: {
|
|
15791
|
+
outcome: "unsupported",
|
|
15792
|
+
models_count: 0
|
|
15793
|
+
}
|
|
15794
|
+
});
|
|
14940
15795
|
}
|
|
14941
15796
|
}).catch((err) => {
|
|
14942
15797
|
const reason = err instanceof Error ? err.message : String(err);
|
|
14943
15798
|
this.connection.send({ type: "machine:runtime_models:result", requestId: msg.requestId, error: reason });
|
|
15799
|
+
span.end("error", {
|
|
15800
|
+
attrs: {
|
|
15801
|
+
outcome: "error",
|
|
15802
|
+
error_class: err instanceof Error ? err.name : typeof err
|
|
15803
|
+
}
|
|
15804
|
+
});
|
|
14944
15805
|
});
|
|
14945
15806
|
break;
|
|
14946
15807
|
}
|
|
@@ -15104,6 +15965,8 @@ var DaemonCore = class {
|
|
|
15104
15965
|
};
|
|
15105
15966
|
|
|
15106
15967
|
export {
|
|
15968
|
+
DAEMON_API_KEY_ENV,
|
|
15969
|
+
scrubDaemonAuthEnv,
|
|
15107
15970
|
subscribeDaemonLogs,
|
|
15108
15971
|
resolveWorkspaceDirectoryPath,
|
|
15109
15972
|
scanWorkspaceDirectories,
|