@botiverse/raft-daemon 0.60.0 → 0.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-65UFKNJJ.js → chunk-XMSXOB5R.js} +904 -143
- package/dist/cli/index.js +28 -1
- package/dist/core.js +1 -1
- package/dist/{dist-JVLCJ2QO.js → dist-6YUWBDWX.js} +26 -1
- package/dist/index.js +1 -1
- 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
|
|
@@ -3341,6 +3367,7 @@ function routeFamilyForPath(pathname) {
|
|
|
3341
3367
|
function daemonUpstreamTargetHostClass(url) {
|
|
3342
3368
|
const hostname = url.hostname.toLowerCase();
|
|
3343
3369
|
if (hostname === "api.slock.ai") return "api.slock.ai";
|
|
3370
|
+
if (hostname === "api.raft.build") return "api.raft.build";
|
|
3344
3371
|
return "custom_server";
|
|
3345
3372
|
}
|
|
3346
3373
|
function upstreamLayerForProxyError(err) {
|
|
@@ -6206,11 +6233,455 @@ function detectKimiModels(home = os4.homedir()) {
|
|
|
6206
6233
|
return { models, default: defaultModel };
|
|
6207
6234
|
}
|
|
6208
6235
|
|
|
6236
|
+
// src/drivers/kimi-sdk.ts
|
|
6237
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
6238
|
+
import { EventEmitter } from "events";
|
|
6239
|
+
import { mkdirSync as mkdirSync3 } from "fs";
|
|
6240
|
+
import path9 from "path";
|
|
6241
|
+
import { createRequire as createRequire2 } from "module";
|
|
6242
|
+
import {
|
|
6243
|
+
createKimiHarness
|
|
6244
|
+
} from "@botiverse/kimi-code-sdk";
|
|
6245
|
+
var requireFromHere = createRequire2(import.meta.url);
|
|
6246
|
+
var KIMI_CODE_USER_AGENT_PRODUCT = "kimi-code-cli";
|
|
6247
|
+
var KIMI_CODE_HOST_VERSION = "0.14.3";
|
|
6248
|
+
function getDaemonVersion() {
|
|
6249
|
+
try {
|
|
6250
|
+
const pkg = requireFromHere("../../package.json");
|
|
6251
|
+
return pkg.version || "0.0.0";
|
|
6252
|
+
} catch {
|
|
6253
|
+
return "0.0.0";
|
|
6254
|
+
}
|
|
6255
|
+
}
|
|
6256
|
+
var KIMI_SESSION_DIR = ".kimi-sessions";
|
|
6257
|
+
function createKimiSdkEventMappingState(sessionId = null) {
|
|
6258
|
+
return {
|
|
6259
|
+
sessionId,
|
|
6260
|
+
sessionAnnounced: false
|
|
6261
|
+
};
|
|
6262
|
+
}
|
|
6263
|
+
function buildKimiSessionDir(workingDirectory) {
|
|
6264
|
+
return path9.join(workingDirectory, KIMI_SESSION_DIR);
|
|
6265
|
+
}
|
|
6266
|
+
function kimiErrorMessage(error) {
|
|
6267
|
+
if (typeof error === "string" && error.trim()) return error.trim();
|
|
6268
|
+
if (error && typeof error === "object") {
|
|
6269
|
+
const record = error;
|
|
6270
|
+
if (typeof record.message === "string" && record.message.trim()) return record.message.trim();
|
|
6271
|
+
try {
|
|
6272
|
+
return JSON.stringify(error);
|
|
6273
|
+
} catch {
|
|
6274
|
+
}
|
|
6275
|
+
}
|
|
6276
|
+
return "Unknown Kimi error";
|
|
6277
|
+
}
|
|
6278
|
+
function pushSessionInitIfNeeded(state, events) {
|
|
6279
|
+
if (!state.sessionAnnounced && state.sessionId) {
|
|
6280
|
+
events.push({ kind: "session_init", sessionId: state.sessionId });
|
|
6281
|
+
state.sessionAnnounced = true;
|
|
6282
|
+
}
|
|
6283
|
+
}
|
|
6284
|
+
function mapKimiSdkEventToParsedEvents(event, state) {
|
|
6285
|
+
const events = [];
|
|
6286
|
+
pushSessionInitIfNeeded(state, events);
|
|
6287
|
+
switch (event.type) {
|
|
6288
|
+
// ── content streaming → ParsedEvent ──
|
|
6289
|
+
case "thinking.delta":
|
|
6290
|
+
if (typeof event.delta === "string" && event.delta.length > 0) {
|
|
6291
|
+
events.push({ kind: "thinking", text: event.delta });
|
|
6292
|
+
}
|
|
6293
|
+
return events;
|
|
6294
|
+
case "assistant.delta":
|
|
6295
|
+
if (typeof event.delta === "string" && event.delta.length > 0) {
|
|
6296
|
+
events.push({ kind: "text", text: event.delta });
|
|
6297
|
+
}
|
|
6298
|
+
return events;
|
|
6299
|
+
case "tool.call.started":
|
|
6300
|
+
events.push({
|
|
6301
|
+
kind: "tool_call",
|
|
6302
|
+
name: event.name || "unknown_tool",
|
|
6303
|
+
input: event.args ?? {}
|
|
6304
|
+
});
|
|
6305
|
+
return events;
|
|
6306
|
+
case "tool.result":
|
|
6307
|
+
events.push({ kind: "tool_output", name: "" });
|
|
6308
|
+
return events;
|
|
6309
|
+
case "compaction.started":
|
|
6310
|
+
events.push({ kind: "compaction_started" });
|
|
6311
|
+
return events;
|
|
6312
|
+
case "compaction.completed":
|
|
6313
|
+
events.push({ kind: "compaction_finished" });
|
|
6314
|
+
return events;
|
|
6315
|
+
case "error":
|
|
6316
|
+
events.push({ kind: "error", message: kimiErrorMessage(event) });
|
|
6317
|
+
return events;
|
|
6318
|
+
// ── THE single turn-triggering source class ──
|
|
6319
|
+
case "turn.ended":
|
|
6320
|
+
events.push({ kind: "turn_end", sessionId: state.sessionId || void 0 });
|
|
6321
|
+
return events;
|
|
6322
|
+
// ── explicit drops (RS-004) ──
|
|
6323
|
+
// `warning` is non-fatal in the SDK's vocabulary; mapping it to
|
|
6324
|
+
// ParsedEvent.kind="error" would latch the agent into APM's error state
|
|
6325
|
+
// (lastRuntimeError set by `runtime.error`, then NOT cleared by the
|
|
6326
|
+
// following turn_end) — so a warning would brick the agent until
|
|
6327
|
+
// restart. Drop it here; the SDK's own log already records it.
|
|
6328
|
+
case "warning":
|
|
6329
|
+
// turn / step lifecycle (state-only, no parsed payload)
|
|
6330
|
+
case "turn.started":
|
|
6331
|
+
case "turn.step.started":
|
|
6332
|
+
case "turn.step.completed":
|
|
6333
|
+
case "turn.step.retrying":
|
|
6334
|
+
case "turn.step.interrupted":
|
|
6335
|
+
// tool-call progress / hooks (could elevate to internal_progress in future)
|
|
6336
|
+
case "tool.call.delta":
|
|
6337
|
+
case "tool.progress":
|
|
6338
|
+
case "hook.result":
|
|
6339
|
+
// status / meta updates
|
|
6340
|
+
case "agent.status.updated":
|
|
6341
|
+
case "session.meta.updated":
|
|
6342
|
+
case "goal.updated":
|
|
6343
|
+
case "skill.activated":
|
|
6344
|
+
// MCP infra
|
|
6345
|
+
case "tool.list.updated":
|
|
6346
|
+
case "mcp.server.status":
|
|
6347
|
+
// subagent lifecycle (v0: drop; could surface later)
|
|
6348
|
+
case "subagent.spawned":
|
|
6349
|
+
case "subagent.started":
|
|
6350
|
+
case "subagent.suspended":
|
|
6351
|
+
case "subagent.completed":
|
|
6352
|
+
case "subagent.failed":
|
|
6353
|
+
// compaction sub-cases
|
|
6354
|
+
case "compaction.blocked":
|
|
6355
|
+
case "compaction.cancelled":
|
|
6356
|
+
// out-of-band
|
|
6357
|
+
case "background.task.started":
|
|
6358
|
+
case "background.task.terminated":
|
|
6359
|
+
case "cron.fired":
|
|
6360
|
+
return events;
|
|
6361
|
+
default: {
|
|
6362
|
+
const _exhaustive = event;
|
|
6363
|
+
return _exhaustive;
|
|
6364
|
+
}
|
|
6365
|
+
}
|
|
6366
|
+
}
|
|
6367
|
+
var KIMI_SDK_RUNTIME_SESSION_DESCRIPTOR = {
|
|
6368
|
+
transport: "sdk",
|
|
6369
|
+
lifecycle: "sdk_session",
|
|
6370
|
+
input: {
|
|
6371
|
+
initial: "start",
|
|
6372
|
+
idle: "sdk_prompt",
|
|
6373
|
+
busy: "sdk_steer"
|
|
6374
|
+
},
|
|
6375
|
+
readiness: "sdk_ready",
|
|
6376
|
+
turnBoundary: "sdk_event",
|
|
6377
|
+
startPolicy: "immediate",
|
|
6378
|
+
inFlightWake: "steer",
|
|
6379
|
+
busyDelivery: "direct",
|
|
6380
|
+
postTurn: "keep_alive"
|
|
6381
|
+
};
|
|
6382
|
+
async function createKimiAgentSessionForContext(ctx, sessionId) {
|
|
6383
|
+
const sessionDir = buildKimiSessionDir(ctx.workingDirectory);
|
|
6384
|
+
mkdirSync3(sessionDir, { recursive: true });
|
|
6385
|
+
const cliTransport = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
6386
|
+
const spawnEnv = cliTransport.spawnEnv;
|
|
6387
|
+
const wrapperPath = cliTransport.wrapperPath;
|
|
6388
|
+
const homeDir = spawnEnv.KIMI_HOME || (process.env.HOME ? path9.join(process.env.HOME, ".kimi") : path9.join(ctx.workingDirectory, ".kimi"));
|
|
6389
|
+
mkdirSync3(homeDir, { recursive: true });
|
|
6390
|
+
const harness = createKimiHarness({
|
|
6391
|
+
homeDir,
|
|
6392
|
+
identity: {
|
|
6393
|
+
userAgentProduct: KIMI_CODE_USER_AGENT_PRODUCT,
|
|
6394
|
+
version: KIMI_CODE_HOST_VERSION,
|
|
6395
|
+
userAgentSuffix: `slock-daemon/${getDaemonVersion()}`
|
|
6396
|
+
}
|
|
6397
|
+
});
|
|
6398
|
+
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
6399
|
+
const sessionFields = {
|
|
6400
|
+
workDir: ctx.workingDirectory,
|
|
6401
|
+
...launchRuntimeFields.model && launchRuntimeFields.model !== "default" ? { model: launchRuntimeFields.model } : {}
|
|
6402
|
+
};
|
|
6403
|
+
let session;
|
|
6404
|
+
if (ctx.config.sessionId) {
|
|
6405
|
+
try {
|
|
6406
|
+
session = await harness.resumeSession({ ...sessionFields, id: ctx.config.sessionId });
|
|
6407
|
+
} catch (resumeError) {
|
|
6408
|
+
void resumeError;
|
|
6409
|
+
session = await harness.createSession(sessionFields);
|
|
6410
|
+
}
|
|
6411
|
+
} else {
|
|
6412
|
+
session = await harness.createSession(sessionFields);
|
|
6413
|
+
}
|
|
6414
|
+
return { harness, session, wrapperPath };
|
|
6415
|
+
}
|
|
6416
|
+
var KimiSdkRuntimeSession = class {
|
|
6417
|
+
constructor(ctx, setCurrentSessionId, sessionFactory = createKimiAgentSessionForContext) {
|
|
6418
|
+
this.ctx = ctx;
|
|
6419
|
+
this.setCurrentSessionId = setCurrentSessionId;
|
|
6420
|
+
this.sessionFactory = sessionFactory;
|
|
6421
|
+
this.mappingState = createKimiSdkEventMappingState(ctx.config.sessionId || null);
|
|
6422
|
+
}
|
|
6423
|
+
descriptor = KIMI_SDK_RUNTIME_SESSION_DESCRIPTOR;
|
|
6424
|
+
events = new EventEmitter();
|
|
6425
|
+
mappingState;
|
|
6426
|
+
harness = null;
|
|
6427
|
+
session = null;
|
|
6428
|
+
wrapperPath = null;
|
|
6429
|
+
unsubscribe = null;
|
|
6430
|
+
started = false;
|
|
6431
|
+
didClose = false;
|
|
6432
|
+
requestedStopReason;
|
|
6433
|
+
exitInfo = null;
|
|
6434
|
+
get pid() {
|
|
6435
|
+
return void 0;
|
|
6436
|
+
}
|
|
6437
|
+
get currentSessionId() {
|
|
6438
|
+
return this.mappingState.sessionId;
|
|
6439
|
+
}
|
|
6440
|
+
get exitCode() {
|
|
6441
|
+
return this.exitInfo?.code ?? null;
|
|
6442
|
+
}
|
|
6443
|
+
get signalCode() {
|
|
6444
|
+
return this.exitInfo?.signal ?? null;
|
|
6445
|
+
}
|
|
6446
|
+
get closed() {
|
|
6447
|
+
return this.didClose;
|
|
6448
|
+
}
|
|
6449
|
+
on(event, cb) {
|
|
6450
|
+
this.events.on(event, cb);
|
|
6451
|
+
}
|
|
6452
|
+
async start(input) {
|
|
6453
|
+
if (this.started) {
|
|
6454
|
+
return { ok: false, reason: "runtime_error", error: "runtime session already started" };
|
|
6455
|
+
}
|
|
6456
|
+
if (this.didClose) return { ok: false, reason: "closed" };
|
|
6457
|
+
this.started = true;
|
|
6458
|
+
const sessionId = input.sessionId || this.ctx.config.sessionId || randomUUID3();
|
|
6459
|
+
this.mappingState.sessionId = sessionId;
|
|
6460
|
+
this.setCurrentSessionId(sessionId);
|
|
6461
|
+
const { harness, session, wrapperPath } = await this.sessionFactory(
|
|
6462
|
+
{
|
|
6463
|
+
...this.ctx,
|
|
6464
|
+
config: {
|
|
6465
|
+
...this.ctx.config,
|
|
6466
|
+
sessionId
|
|
6467
|
+
}
|
|
6468
|
+
},
|
|
6469
|
+
sessionId
|
|
6470
|
+
);
|
|
6471
|
+
this.harness = harness;
|
|
6472
|
+
this.session = session;
|
|
6473
|
+
this.wrapperPath = wrapperPath;
|
|
6474
|
+
this.mappingState.sessionId = session.id;
|
|
6475
|
+
this.setCurrentSessionId(session.id);
|
|
6476
|
+
session.setApprovalHandler(() => ({ decision: "approved", scope: "session" }));
|
|
6477
|
+
this.unsubscribe = session.onEvent((event) => {
|
|
6478
|
+
for (const parsed of mapKimiSdkEventToParsedEvents(event, this.mappingState)) {
|
|
6479
|
+
this.events.emit("runtime_event", parsed);
|
|
6480
|
+
}
|
|
6481
|
+
});
|
|
6482
|
+
this.emitSessionInit();
|
|
6483
|
+
const firstTurnText = this.composeFirstTurnPreamble(input.text);
|
|
6484
|
+
this.launchPrompt(firstTurnText);
|
|
6485
|
+
return { ok: true, acceptedAs: "prompt" };
|
|
6486
|
+
}
|
|
6487
|
+
composeFirstTurnPreamble(turnText) {
|
|
6488
|
+
const sections = [];
|
|
6489
|
+
if (this.ctx.standingPrompt) {
|
|
6490
|
+
sections.push(this.ctx.standingPrompt);
|
|
6491
|
+
}
|
|
6492
|
+
if (this.wrapperPath) {
|
|
6493
|
+
sections.push(
|
|
6494
|
+
`## CLI invocation note (Kimi SDK in-process runtime)
|
|
6495
|
+
|
|
6496
|
+
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:
|
|
6497
|
+
|
|
6498
|
+
\`\`\`
|
|
6499
|
+
${this.wrapperPath}
|
|
6500
|
+
\`\`\`
|
|
6501
|
+
|
|
6502
|
+
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.`
|
|
6503
|
+
);
|
|
6504
|
+
}
|
|
6505
|
+
sections.push(turnText);
|
|
6506
|
+
return sections.join("\n\n---\n\n");
|
|
6507
|
+
}
|
|
6508
|
+
send(input) {
|
|
6509
|
+
if (this.didClose) return { ok: false, reason: "closed" };
|
|
6510
|
+
const session = this.session;
|
|
6511
|
+
if (!session) return { ok: false, reason: "closed" };
|
|
6512
|
+
if (input.mode === "busy") {
|
|
6513
|
+
this.deferSdkCall(() => session.steer(input.text));
|
|
6514
|
+
return { ok: true, acceptedAs: "steer" };
|
|
6515
|
+
}
|
|
6516
|
+
this.launchPrompt(input.text);
|
|
6517
|
+
return { ok: true, acceptedAs: "prompt" };
|
|
6518
|
+
}
|
|
6519
|
+
async stop(opts) {
|
|
6520
|
+
if (this.didClose) return;
|
|
6521
|
+
this.requestedStopReason = opts?.reason;
|
|
6522
|
+
const signal = opts?.signal ?? "SIGTERM";
|
|
6523
|
+
const session = this.session;
|
|
6524
|
+
if (session) {
|
|
6525
|
+
try {
|
|
6526
|
+
await session.cancel();
|
|
6527
|
+
} catch (error) {
|
|
6528
|
+
this.events.emit("stderr", kimiErrorMessage(error));
|
|
6529
|
+
}
|
|
6530
|
+
}
|
|
6531
|
+
await this.disposeSession();
|
|
6532
|
+
this.emitExitAndClose(null, signal);
|
|
6533
|
+
}
|
|
6534
|
+
async dispose() {
|
|
6535
|
+
if (this.didClose) return;
|
|
6536
|
+
await this.disposeSession();
|
|
6537
|
+
this.emitExitAndClose(0, null);
|
|
6538
|
+
}
|
|
6539
|
+
emitSessionInit() {
|
|
6540
|
+
const sessionId = this.mappingState.sessionId;
|
|
6541
|
+
if (!sessionId || this.mappingState.sessionAnnounced) return;
|
|
6542
|
+
this.mappingState.sessionAnnounced = true;
|
|
6543
|
+
this.events.emit("runtime_event", { kind: "session_init", sessionId });
|
|
6544
|
+
}
|
|
6545
|
+
launchPrompt(text) {
|
|
6546
|
+
const session = this.session;
|
|
6547
|
+
if (!session) {
|
|
6548
|
+
this.events.emit("runtime_event", {
|
|
6549
|
+
kind: "error",
|
|
6550
|
+
message: "Kimi SDK session is not started"
|
|
6551
|
+
});
|
|
6552
|
+
return;
|
|
6553
|
+
}
|
|
6554
|
+
this.deferSdkCall(() => session.prompt(text));
|
|
6555
|
+
}
|
|
6556
|
+
deferSdkCall(invoke) {
|
|
6557
|
+
setImmediate(() => {
|
|
6558
|
+
if (this.didClose) return;
|
|
6559
|
+
try {
|
|
6560
|
+
void invoke().catch((error) => {
|
|
6561
|
+
if (this.didClose) return;
|
|
6562
|
+
this.events.emit("runtime_event", {
|
|
6563
|
+
kind: "error",
|
|
6564
|
+
message: kimiErrorMessage(error)
|
|
6565
|
+
});
|
|
6566
|
+
});
|
|
6567
|
+
} catch (error) {
|
|
6568
|
+
if (this.didClose) return;
|
|
6569
|
+
this.events.emit("runtime_event", {
|
|
6570
|
+
kind: "error",
|
|
6571
|
+
message: kimiErrorMessage(error)
|
|
6572
|
+
});
|
|
6573
|
+
}
|
|
6574
|
+
});
|
|
6575
|
+
}
|
|
6576
|
+
async disposeSession() {
|
|
6577
|
+
const unsubscribe = this.unsubscribe;
|
|
6578
|
+
this.unsubscribe = null;
|
|
6579
|
+
try {
|
|
6580
|
+
unsubscribe?.();
|
|
6581
|
+
} catch {
|
|
6582
|
+
}
|
|
6583
|
+
const session = this.session;
|
|
6584
|
+
this.session = null;
|
|
6585
|
+
try {
|
|
6586
|
+
await session?.close();
|
|
6587
|
+
} catch (error) {
|
|
6588
|
+
this.events.emit("stderr", kimiErrorMessage(error));
|
|
6589
|
+
}
|
|
6590
|
+
const harness = this.harness;
|
|
6591
|
+
this.harness = null;
|
|
6592
|
+
try {
|
|
6593
|
+
await harness?.close();
|
|
6594
|
+
} catch (error) {
|
|
6595
|
+
this.events.emit("stderr", kimiErrorMessage(error));
|
|
6596
|
+
}
|
|
6597
|
+
}
|
|
6598
|
+
emitExitAndClose(code, signal) {
|
|
6599
|
+
if (this.didClose) return;
|
|
6600
|
+
this.didClose = true;
|
|
6601
|
+
const info = {
|
|
6602
|
+
code,
|
|
6603
|
+
signal,
|
|
6604
|
+
reason: this.requestedStopReason ? "requested" : "runtime_exit"
|
|
6605
|
+
};
|
|
6606
|
+
this.exitInfo = info;
|
|
6607
|
+
this.events.emit("exit", info);
|
|
6608
|
+
this.events.emit("close", info);
|
|
6609
|
+
}
|
|
6610
|
+
};
|
|
6611
|
+
var KIMI_SDK_DEFAULT_MODELS = [
|
|
6612
|
+
// Canonical Kimi Code SDK model (matches the `default_model` upstream
|
|
6613
|
+
// ships in `~/.kimi/config.toml` after `kimi login`). Mirrored as the first
|
|
6614
|
+
// entry in `RUNTIME_MODELS["kimi-sdk"]` (packages/shared/src/index.ts) so
|
|
6615
|
+
// both the daemon's launch resolution and the web's getDefaultModel agree.
|
|
6616
|
+
{ id: "kimi-code/kimi-for-coding", label: "Kimi-K2.6 (Kimi for Coding)", verified: "launchable" },
|
|
6617
|
+
{ id: "kimi-k2-0905-preview", label: "Kimi K2 (preview)", verified: "suggestion_only" }
|
|
6618
|
+
];
|
|
6619
|
+
function detectKimiSdkModels() {
|
|
6620
|
+
return { models: KIMI_SDK_DEFAULT_MODELS };
|
|
6621
|
+
}
|
|
6622
|
+
var KimiSdkDriver = class {
|
|
6623
|
+
id = "kimi-sdk";
|
|
6624
|
+
supportsNativeStandingPrompt = true;
|
|
6625
|
+
lifecycle = {
|
|
6626
|
+
kind: "persistent",
|
|
6627
|
+
stdin: "direct",
|
|
6628
|
+
inFlightWake: "steer"
|
|
6629
|
+
};
|
|
6630
|
+
communication = {
|
|
6631
|
+
chat: "slock_cli",
|
|
6632
|
+
runtimeControl: "none"
|
|
6633
|
+
};
|
|
6634
|
+
session = {
|
|
6635
|
+
recovery: "resume_or_fresh"
|
|
6636
|
+
};
|
|
6637
|
+
model = {
|
|
6638
|
+
detectedModelsVerifiedAs: "suggestion_only",
|
|
6639
|
+
toLaunchSpec: (modelId) => ({ params: { model: modelId } })
|
|
6640
|
+
};
|
|
6641
|
+
supportsStdinNotification = true;
|
|
6642
|
+
busyDeliveryMode = "direct";
|
|
6643
|
+
sessionId = null;
|
|
6644
|
+
get currentSessionId() {
|
|
6645
|
+
return this.sessionId;
|
|
6646
|
+
}
|
|
6647
|
+
probe() {
|
|
6648
|
+
return { available: true };
|
|
6649
|
+
}
|
|
6650
|
+
async detectModels() {
|
|
6651
|
+
return detectKimiSdkModels();
|
|
6652
|
+
}
|
|
6653
|
+
createSession(ctx) {
|
|
6654
|
+
this.sessionId = ctx.config.sessionId || null;
|
|
6655
|
+
return new KimiSdkRuntimeSession(ctx, (sessionId) => {
|
|
6656
|
+
this.sessionId = sessionId;
|
|
6657
|
+
});
|
|
6658
|
+
}
|
|
6659
|
+
async spawn(_ctx) {
|
|
6660
|
+
throw new Error("KimiSdkDriver uses a native RuntimeSession; child-process spawn is unsupported");
|
|
6661
|
+
}
|
|
6662
|
+
parseLine(_line) {
|
|
6663
|
+
return [];
|
|
6664
|
+
}
|
|
6665
|
+
encodeStdinMessage(_text, _sessionId, _opts) {
|
|
6666
|
+
return null;
|
|
6667
|
+
}
|
|
6668
|
+
buildSystemPrompt(config, _agentId) {
|
|
6669
|
+
return buildCliTransportSystemPrompt(config, {
|
|
6670
|
+
extraCriticalRules: [],
|
|
6671
|
+
postStartupNotes: [
|
|
6672
|
+
"**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."
|
|
6673
|
+
],
|
|
6674
|
+
includeStdinNotificationSection: true,
|
|
6675
|
+
messageNotificationStyle: "direct"
|
|
6676
|
+
});
|
|
6677
|
+
}
|
|
6678
|
+
};
|
|
6679
|
+
|
|
6209
6680
|
// src/drivers/opencode.ts
|
|
6210
6681
|
import { spawn as spawn8, spawnSync as spawnSync2 } from "child_process";
|
|
6211
6682
|
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
|
|
6212
6683
|
import os5 from "os";
|
|
6213
|
-
import
|
|
6684
|
+
import path10 from "path";
|
|
6214
6685
|
var SLOCK_AGENT_NAME = "slock";
|
|
6215
6686
|
var NO_MESSAGE_PROMPT = "No new messages are pending. Stop now.";
|
|
6216
6687
|
var FIRST_MESSAGE_TASK_PREFIX = "First message task (system-triggered):";
|
|
@@ -6239,7 +6710,7 @@ function parseUserOpenCodeConfig(ctx) {
|
|
|
6239
6710
|
return parseOpenCodeConfigContent(raw);
|
|
6240
6711
|
}
|
|
6241
6712
|
function readLocalOpenCodeConfig(home = os5.homedir()) {
|
|
6242
|
-
const configPath =
|
|
6713
|
+
const configPath = path10.join(home, ".config", "opencode", "opencode.json");
|
|
6243
6714
|
try {
|
|
6244
6715
|
return parseOpenCodeConfigContent(readFileSync4(configPath, "utf8"));
|
|
6245
6716
|
} catch {
|
|
@@ -6437,11 +6908,11 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
6437
6908
|
};
|
|
6438
6909
|
}
|
|
6439
6910
|
function isWindowsCommandShim(commandPath) {
|
|
6440
|
-
const ext =
|
|
6911
|
+
const ext = path10.win32.extname(commandPath).toLowerCase();
|
|
6441
6912
|
return ext === ".cmd" || ext === ".bat";
|
|
6442
6913
|
}
|
|
6443
6914
|
function opencodePackageEntryCandidates(packageRoot) {
|
|
6444
|
-
const winPath =
|
|
6915
|
+
const winPath = path10.win32;
|
|
6445
6916
|
return [
|
|
6446
6917
|
winPath.join(packageRoot, "bin", "opencode.exe"),
|
|
6447
6918
|
winPath.join(packageRoot, "bin", "opencode.js"),
|
|
@@ -6450,7 +6921,7 @@ function opencodePackageEntryCandidates(packageRoot) {
|
|
|
6450
6921
|
];
|
|
6451
6922
|
}
|
|
6452
6923
|
function openCodeSpecForEntry(entry, commandArgs) {
|
|
6453
|
-
if (
|
|
6924
|
+
if (path10.win32.extname(entry).toLowerCase() === ".exe") {
|
|
6454
6925
|
return { command: entry, args: commandArgs, shell: false };
|
|
6455
6926
|
}
|
|
6456
6927
|
return { command: process.execPath, args: [entry, ...commandArgs], shell: false };
|
|
@@ -6459,7 +6930,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
|
6459
6930
|
const existsSyncFn = deps.existsSyncFn ?? existsSync8;
|
|
6460
6931
|
const execFileSyncFn = deps.execFileSyncFn;
|
|
6461
6932
|
const env = deps.env ?? process.env;
|
|
6462
|
-
const winPath =
|
|
6933
|
+
const winPath = path10.win32;
|
|
6463
6934
|
const candidates = [];
|
|
6464
6935
|
if (execFileSyncFn) {
|
|
6465
6936
|
try {
|
|
@@ -6487,7 +6958,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
|
6487
6958
|
function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
6488
6959
|
if (!isWindowsCommandShim(commandPath)) return [];
|
|
6489
6960
|
const readFileSyncFn = deps.readFileSyncFn ?? readFileSync4;
|
|
6490
|
-
const commandDir =
|
|
6961
|
+
const commandDir = path10.win32.dirname(commandPath);
|
|
6491
6962
|
let raw;
|
|
6492
6963
|
try {
|
|
6493
6964
|
raw = String(readFileSyncFn(commandPath, "utf8"));
|
|
@@ -6498,7 +6969,7 @@ function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
|
6498
6969
|
const dp0Pattern = /%~dp0\\?([^"\r\n]*?opencode\.(?:exe|js|mjs|cjs))/gi;
|
|
6499
6970
|
for (const match of raw.matchAll(dp0Pattern)) {
|
|
6500
6971
|
const relative = match[1]?.replace(/^\\+/, "");
|
|
6501
|
-
if (relative) candidates.push(
|
|
6972
|
+
if (relative) candidates.push(path10.win32.normalize(path10.win32.join(commandDir, relative)));
|
|
6502
6973
|
}
|
|
6503
6974
|
return candidates;
|
|
6504
6975
|
}
|
|
@@ -6512,7 +6983,7 @@ function resolveOpenCodeSpawn(commandArgs, deps = {}) {
|
|
|
6512
6983
|
};
|
|
6513
6984
|
}
|
|
6514
6985
|
const command = resolveCommandOnPath("opencode", deps);
|
|
6515
|
-
if (command &&
|
|
6986
|
+
if (command && path10.win32.extname(command).toLowerCase() === ".exe") {
|
|
6516
6987
|
return { command, args: commandArgs, shell: false };
|
|
6517
6988
|
}
|
|
6518
6989
|
const packageEntry = resolveWindowsOpenCodePackageEntry(command, deps);
|
|
@@ -6682,17 +7153,16 @@ var OpenCodeDriver = class {
|
|
|
6682
7153
|
};
|
|
6683
7154
|
|
|
6684
7155
|
// src/drivers/pi.ts
|
|
6685
|
-
import { randomUUID as
|
|
6686
|
-
import { EventEmitter } from "events";
|
|
6687
|
-
import { mkdirSync as
|
|
6688
|
-
import
|
|
7156
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
7157
|
+
import { EventEmitter as EventEmitter2 } from "events";
|
|
7158
|
+
import { mkdirSync as mkdirSync4, readdirSync as readdirSync2 } from "fs";
|
|
7159
|
+
import path11 from "path";
|
|
6689
7160
|
import {
|
|
6690
7161
|
AuthStorage,
|
|
6691
7162
|
createBashTool,
|
|
6692
|
-
|
|
6693
|
-
|
|
7163
|
+
createAgentSessionFromServices,
|
|
7164
|
+
createAgentSessionServices,
|
|
6694
7165
|
getAgentDir,
|
|
6695
|
-
ModelRegistry,
|
|
6696
7166
|
SessionManager,
|
|
6697
7167
|
SettingsManager,
|
|
6698
7168
|
VERSION as PI_SDK_VERSION
|
|
@@ -6712,7 +7182,7 @@ function createPiSdkEventMappingState(sessionId = null) {
|
|
|
6712
7182
|
};
|
|
6713
7183
|
}
|
|
6714
7184
|
function buildPiSessionDir(workingDirectory) {
|
|
6715
|
-
return
|
|
7185
|
+
return path11.join(workingDirectory, PI_SESSION_DIR);
|
|
6716
7186
|
}
|
|
6717
7187
|
async function buildPiSpawnEnv(ctx) {
|
|
6718
7188
|
return (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
@@ -6734,7 +7204,7 @@ function findPiSessionFile(sessionDir, sessionId) {
|
|
|
6734
7204
|
}
|
|
6735
7205
|
const suffix = `_${sessionId}.jsonl`;
|
|
6736
7206
|
const match = entries.find((entry) => entry.endsWith(suffix));
|
|
6737
|
-
return match ?
|
|
7207
|
+
return match ? path11.join(sessionDir, match) : null;
|
|
6738
7208
|
}
|
|
6739
7209
|
function detectPiModelsFromRegistry(modelRegistry) {
|
|
6740
7210
|
const models = [];
|
|
@@ -6751,8 +7221,70 @@ function detectPiModelsFromRegistry(modelRegistry) {
|
|
|
6751
7221
|
}
|
|
6752
7222
|
return models.length > 0 ? { models } : null;
|
|
6753
7223
|
}
|
|
6754
|
-
function
|
|
6755
|
-
|
|
7224
|
+
function applyPiDaemonSettingsOverrides(settingsManager) {
|
|
7225
|
+
settingsManager.applyOverrides({ compaction: { enabled: PI_SDK_COMPACTION_ENABLED } });
|
|
7226
|
+
}
|
|
7227
|
+
function logPiServiceDiagnostics(context, services) {
|
|
7228
|
+
for (const diagnostic of services.diagnostics) {
|
|
7229
|
+
const message = `[pi-driver] ${context} diagnostic: ${diagnostic.message}`;
|
|
7230
|
+
if (diagnostic.type === "info") {
|
|
7231
|
+
console.info(message);
|
|
7232
|
+
} else {
|
|
7233
|
+
console.warn(message);
|
|
7234
|
+
}
|
|
7235
|
+
}
|
|
7236
|
+
}
|
|
7237
|
+
function formatPiModelLogId(model) {
|
|
7238
|
+
return model ? `${model.provider}/${model.id}` : "default";
|
|
7239
|
+
}
|
|
7240
|
+
function piServiceDiagnosticTraceAttrs(services) {
|
|
7241
|
+
let info = 0;
|
|
7242
|
+
let warning = 0;
|
|
7243
|
+
for (const diagnostic of services.diagnostics) {
|
|
7244
|
+
if (diagnostic.type === "info") {
|
|
7245
|
+
info++;
|
|
7246
|
+
} else {
|
|
7247
|
+
warning++;
|
|
7248
|
+
}
|
|
7249
|
+
}
|
|
7250
|
+
return {
|
|
7251
|
+
diagnostics_count: services.diagnostics.length,
|
|
7252
|
+
diagnostic_info_count: info,
|
|
7253
|
+
diagnostic_warning_count: warning
|
|
7254
|
+
};
|
|
7255
|
+
}
|
|
7256
|
+
function addPiServiceTraceEvent(span, name, services, attrs = {}) {
|
|
7257
|
+
span?.addEvent(name, {
|
|
7258
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7259
|
+
...piServiceDiagnosticTraceAttrs(services),
|
|
7260
|
+
...attrs
|
|
7261
|
+
});
|
|
7262
|
+
}
|
|
7263
|
+
async function detectPiModels(modelRegistry, traceContext = {}) {
|
|
7264
|
+
if (modelRegistry) {
|
|
7265
|
+
return detectPiModelsFromRegistry(modelRegistry);
|
|
7266
|
+
}
|
|
7267
|
+
const agentDir = getAgentDir();
|
|
7268
|
+
const services = await createAgentSessionServices({
|
|
7269
|
+
cwd: process.cwd(),
|
|
7270
|
+
agentDir
|
|
7271
|
+
});
|
|
7272
|
+
logPiServiceDiagnostics("detect_models", services);
|
|
7273
|
+
addPiServiceTraceEvent(traceContext.span, "daemon.pi.models.services_ready", services);
|
|
7274
|
+
const result = detectPiModelsFromRegistry(services.modelRegistry);
|
|
7275
|
+
traceContext.span?.addEvent("daemon.pi.models.result", {
|
|
7276
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7277
|
+
returned_models_count: result?.models?.length ?? 0,
|
|
7278
|
+
outcome: result ? "models_returned" : "no_models",
|
|
7279
|
+
...piServiceDiagnosticTraceAttrs(services)
|
|
7280
|
+
});
|
|
7281
|
+
console.info(
|
|
7282
|
+
"[pi-driver] detect_models agentDir=%s available=%d returned=%d",
|
|
7283
|
+
agentDir,
|
|
7284
|
+
services.modelRegistry.getAvailable().length,
|
|
7285
|
+
result?.models?.length ?? 0
|
|
7286
|
+
);
|
|
7287
|
+
return result;
|
|
6756
7288
|
}
|
|
6757
7289
|
function humanizePiSegment(value) {
|
|
6758
7290
|
return value.split(/[-_/]/).filter(Boolean).map(formatPiLabelToken).join(" ");
|
|
@@ -6785,7 +7317,7 @@ function piErrorMessage(error) {
|
|
|
6785
7317
|
}
|
|
6786
7318
|
return "Unknown Pi error";
|
|
6787
7319
|
}
|
|
6788
|
-
function
|
|
7320
|
+
function pushSessionInitIfNeeded2(state, events) {
|
|
6789
7321
|
if (!state.sessionAnnounced && state.sessionId) {
|
|
6790
7322
|
events.push({ kind: "session_init", sessionId: state.sessionId });
|
|
6791
7323
|
state.sessionAnnounced = true;
|
|
@@ -6822,7 +7354,7 @@ function mapPiAssistantMessageEvent(assistantEvent, state) {
|
|
|
6822
7354
|
}
|
|
6823
7355
|
function mapPiSdkEventToParsedEvents(event, state) {
|
|
6824
7356
|
const events = [];
|
|
6825
|
-
|
|
7357
|
+
pushSessionInitIfNeeded2(state, events);
|
|
6826
7358
|
switch (event.type) {
|
|
6827
7359
|
case "agent_start":
|
|
6828
7360
|
case "turn_start":
|
|
@@ -6887,49 +7419,127 @@ var PI_IDLE_PROMPT_RETRY_MS = 25;
|
|
|
6887
7419
|
var PI_IDLE_PROMPT_MAX_WAIT_MS = 1e3;
|
|
6888
7420
|
async function createPiAgentSessionForContext(ctx, sessionId) {
|
|
6889
7421
|
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"));
|
|
7422
|
+
mkdirSync4(sessionDir, { recursive: true });
|
|
6895
7423
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
6896
|
-
const
|
|
6897
|
-
|
|
6898
|
-
|
|
6899
|
-
|
|
6900
|
-
|
|
6901
|
-
|
|
6902
|
-
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
7424
|
+
const requestedModel = launchRuntimeFields.model || "default";
|
|
7425
|
+
const traceSpan = ctx.tracer?.startSpan("daemon.pi.session.create", {
|
|
7426
|
+
surface: "daemon",
|
|
7427
|
+
kind: "internal",
|
|
7428
|
+
attrs: {
|
|
7429
|
+
agentId: ctx.agentId,
|
|
7430
|
+
launchId: ctx.launchId || void 0,
|
|
7431
|
+
runtime: ctx.config.runtime,
|
|
7432
|
+
model: ctx.config.model,
|
|
7433
|
+
session_id_present: Boolean(sessionId),
|
|
7434
|
+
requested_model: requestedModel
|
|
7435
|
+
}
|
|
6906
7436
|
});
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
7437
|
+
try {
|
|
7438
|
+
const spawnEnv = await buildPiSpawnEnv(ctx);
|
|
7439
|
+
const agentDir = spawnEnv.PI_CODING_AGENT_DIR || getAgentDir();
|
|
7440
|
+
const authStorage = AuthStorage.create(path11.join(agentDir, "auth.json"));
|
|
7441
|
+
const settingsManager = SettingsManager.create(ctx.workingDirectory, agentDir);
|
|
7442
|
+
const services = await createAgentSessionServices({
|
|
7443
|
+
cwd: ctx.workingDirectory,
|
|
7444
|
+
agentDir,
|
|
7445
|
+
authStorage,
|
|
7446
|
+
settingsManager,
|
|
7447
|
+
resourceLoaderOptions: {
|
|
7448
|
+
systemPromptOverride: () => ctx.standingPrompt
|
|
7449
|
+
}
|
|
7450
|
+
});
|
|
7451
|
+
applyPiDaemonSettingsOverrides(services.settingsManager);
|
|
7452
|
+
logPiServiceDiagnostics("create_session", services);
|
|
7453
|
+
addPiServiceTraceEvent(traceSpan, "daemon.pi.session.services_ready", services, {
|
|
7454
|
+
agent_dir_source: spawnEnv.PI_CODING_AGENT_DIR ? "spawn_env" : "default"
|
|
7455
|
+
});
|
|
7456
|
+
const model = resolvePiModelFromRegistry(launchRuntimeFields.model, services.modelRegistry);
|
|
7457
|
+
const resolvedModel = formatPiModelLogId(model);
|
|
7458
|
+
traceSpan?.addEvent("daemon.pi.session.model_resolved", {
|
|
7459
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7460
|
+
requested_model: requestedModel,
|
|
7461
|
+
requested_model_explicit: requestedModel !== "default",
|
|
7462
|
+
resolved_model: resolvedModel,
|
|
7463
|
+
resolved_model_present: Boolean(model)
|
|
7464
|
+
});
|
|
7465
|
+
console.info(
|
|
7466
|
+
"[pi-driver] create_session services_ready agentDir=%s available=%d requested=%s resolved=%s",
|
|
7467
|
+
agentDir,
|
|
7468
|
+
services.modelRegistry.getAvailable().length,
|
|
7469
|
+
requestedModel,
|
|
7470
|
+
resolvedModel
|
|
7471
|
+
);
|
|
7472
|
+
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default" && !model) {
|
|
7473
|
+
console.warn(
|
|
7474
|
+
"[pi-driver] create_session missing_model requested=%s available=%d",
|
|
7475
|
+
requestedModel,
|
|
7476
|
+
services.modelRegistry.getAvailable().length
|
|
7477
|
+
);
|
|
7478
|
+
traceSpan?.addEvent("daemon.pi.session.missing_model", {
|
|
7479
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7480
|
+
requested_model: requestedModel
|
|
7481
|
+
});
|
|
7482
|
+
traceSpan?.end("error", {
|
|
7483
|
+
attrs: {
|
|
7484
|
+
outcome: "missing_model",
|
|
7485
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7486
|
+
requested_model: requestedModel,
|
|
7487
|
+
resolved_model_present: false,
|
|
7488
|
+
...piServiceDiagnosticTraceAttrs(services)
|
|
7489
|
+
}
|
|
7490
|
+
});
|
|
7491
|
+
throw new Error(`Pi model not found: ${launchRuntimeFields.model}`);
|
|
7492
|
+
}
|
|
7493
|
+
const existingSessionFile = ctx.config.sessionId ? findPiSessionFile(sessionDir, ctx.config.sessionId) : null;
|
|
7494
|
+
const sessionManager = existingSessionFile ? SessionManager.open(existingSessionFile, sessionDir, ctx.workingDirectory) : SessionManager.create(ctx.workingDirectory, sessionDir, { id: sessionId });
|
|
7495
|
+
const { session } = await createAgentSessionFromServices({
|
|
7496
|
+
services,
|
|
7497
|
+
sessionManager,
|
|
7498
|
+
model,
|
|
7499
|
+
thinkingLevel: launchRuntimeFields.reasoningEffort,
|
|
7500
|
+
customTools: [
|
|
7501
|
+
createBashTool(ctx.workingDirectory, {
|
|
7502
|
+
spawnHook: (spawnContext) => ({
|
|
7503
|
+
...spawnContext,
|
|
7504
|
+
env: {
|
|
7505
|
+
...spawnContext.env,
|
|
7506
|
+
...spawnEnv
|
|
7507
|
+
}
|
|
7508
|
+
})
|
|
6926
7509
|
})
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
7510
|
+
]
|
|
7511
|
+
});
|
|
7512
|
+
traceSpan?.addEvent("daemon.pi.session.started", {
|
|
7513
|
+
requested_model: requestedModel,
|
|
7514
|
+
resolved_model: resolvedModel,
|
|
7515
|
+
session_id_present: Boolean(session.sessionId)
|
|
7516
|
+
});
|
|
7517
|
+
traceSpan?.end("ok", {
|
|
7518
|
+
attrs: {
|
|
7519
|
+
outcome: "started",
|
|
7520
|
+
available_models_count: services.modelRegistry.getAvailable().length,
|
|
7521
|
+
requested_model: requestedModel,
|
|
7522
|
+
resolved_model: resolvedModel,
|
|
7523
|
+
resolved_model_present: Boolean(model),
|
|
7524
|
+
...piServiceDiagnosticTraceAttrs(services)
|
|
7525
|
+
}
|
|
7526
|
+
});
|
|
7527
|
+
console.info(
|
|
7528
|
+
"[pi-driver] create_session started sessionId=%s requested=%s resolved=%s",
|
|
7529
|
+
sessionId,
|
|
7530
|
+
requestedModel,
|
|
7531
|
+
resolvedModel
|
|
7532
|
+
);
|
|
7533
|
+
return session;
|
|
7534
|
+
} catch (error) {
|
|
7535
|
+
traceSpan?.end("error", {
|
|
7536
|
+
attrs: {
|
|
7537
|
+
outcome: "error",
|
|
7538
|
+
error_class: error instanceof Error ? error.name : typeof error
|
|
7539
|
+
}
|
|
7540
|
+
});
|
|
7541
|
+
throw error;
|
|
7542
|
+
}
|
|
6933
7543
|
}
|
|
6934
7544
|
var PiSdkRuntimeSession = class {
|
|
6935
7545
|
constructor(ctx, setCurrentSessionId, sessionFactory = createPiAgentSessionForContext) {
|
|
@@ -6939,7 +7549,7 @@ var PiSdkRuntimeSession = class {
|
|
|
6939
7549
|
this.mappingState = createPiSdkEventMappingState(ctx.config.sessionId || null);
|
|
6940
7550
|
}
|
|
6941
7551
|
descriptor = PI_RUNTIME_SESSION_DESCRIPTOR;
|
|
6942
|
-
events = new
|
|
7552
|
+
events = new EventEmitter2();
|
|
6943
7553
|
mappingState;
|
|
6944
7554
|
session = null;
|
|
6945
7555
|
unsubscribe = null;
|
|
@@ -6971,7 +7581,7 @@ var PiSdkRuntimeSession = class {
|
|
|
6971
7581
|
}
|
|
6972
7582
|
if (this.didClose) return { ok: false, reason: "closed" };
|
|
6973
7583
|
this.started = true;
|
|
6974
|
-
const sessionId = input.sessionId || this.ctx.config.sessionId ||
|
|
7584
|
+
const sessionId = input.sessionId || this.ctx.config.sessionId || randomUUID4();
|
|
6975
7585
|
this.mappingState.sessionId = sessionId;
|
|
6976
7586
|
this.setCurrentSessionId(sessionId);
|
|
6977
7587
|
const session = await this.sessionFactory({
|
|
@@ -7145,8 +7755,8 @@ var PiDriver = class {
|
|
|
7145
7755
|
version: PI_SDK_VERSION
|
|
7146
7756
|
};
|
|
7147
7757
|
}
|
|
7148
|
-
async detectModels() {
|
|
7149
|
-
return detectPiModels();
|
|
7758
|
+
async detectModels(ctx) {
|
|
7759
|
+
return detectPiModels(void 0, ctx);
|
|
7150
7760
|
}
|
|
7151
7761
|
createSession(ctx) {
|
|
7152
7762
|
this.sessionId = ctx.config.sessionId || null;
|
|
@@ -7182,7 +7792,7 @@ function delay(ms) {
|
|
|
7182
7792
|
}
|
|
7183
7793
|
|
|
7184
7794
|
// src/drivers/runtimeSession.ts
|
|
7185
|
-
import { EventEmitter as
|
|
7795
|
+
import { EventEmitter as EventEmitter3 } from "events";
|
|
7186
7796
|
function descriptorFromDriver(driver) {
|
|
7187
7797
|
const lifecycle = driver.lifecycle.kind === "per_turn" ? "turn_based" : "persistent_stream";
|
|
7188
7798
|
const idle = driver.supportsStdinNotification ? "stdin" : "unsupported";
|
|
@@ -7210,7 +7820,7 @@ var ChildProcessRuntimeSession = class {
|
|
|
7210
7820
|
this.descriptor = descriptorFromDriver(driver);
|
|
7211
7821
|
}
|
|
7212
7822
|
descriptor;
|
|
7213
|
-
events = new
|
|
7823
|
+
events = new EventEmitter3();
|
|
7214
7824
|
process = null;
|
|
7215
7825
|
started = false;
|
|
7216
7826
|
stdoutBuffer = "";
|
|
@@ -7323,7 +7933,13 @@ var driverFactories = {
|
|
|
7323
7933
|
copilot: () => new CopilotDriver(),
|
|
7324
7934
|
cursor: () => new CursorDriver(),
|
|
7325
7935
|
gemini: () => new GeminiDriver(),
|
|
7936
|
+
// Two separate Kimi runtimes (per #proj-runtime:cc818e65 6/16 consensus):
|
|
7937
|
+
// - `kimi` = legacy kimi-cli child-process driver. Backward-compat for
|
|
7938
|
+
// existing `runtime=kimi` agents. Frontend marks deprecated.
|
|
7939
|
+
// - `kimi-sdk` = canonical in-process SDK driver. Frontend label "Kimi Code".
|
|
7940
|
+
// No alias / no auto-migration; explicit pick at agent-create time.
|
|
7326
7941
|
kimi: () => new KimiDriver(),
|
|
7942
|
+
"kimi-sdk": () => new KimiSdkDriver(),
|
|
7327
7943
|
opencode: () => new OpenCodeDriver(),
|
|
7328
7944
|
pi: () => new PiDriver()
|
|
7329
7945
|
};
|
|
@@ -7338,7 +7954,7 @@ function getDriver(runtimeId) {
|
|
|
7338
7954
|
|
|
7339
7955
|
// src/workspaces.ts
|
|
7340
7956
|
import { readdir, rm, stat } from "fs/promises";
|
|
7341
|
-
import
|
|
7957
|
+
import path12 from "path";
|
|
7342
7958
|
function isValidWorkspaceDirectoryName(directoryName) {
|
|
7343
7959
|
return !directoryName.includes("/") && !directoryName.includes("\\") && !directoryName.includes("..");
|
|
7344
7960
|
}
|
|
@@ -7346,7 +7962,7 @@ function resolveWorkspaceDirectoryPath(dataDir, directoryName) {
|
|
|
7346
7962
|
if (!isValidWorkspaceDirectoryName(directoryName)) {
|
|
7347
7963
|
return null;
|
|
7348
7964
|
}
|
|
7349
|
-
return
|
|
7965
|
+
return path12.join(dataDir, directoryName);
|
|
7350
7966
|
}
|
|
7351
7967
|
function emptyWorkspaceDirectorySummary(latestMtime = /* @__PURE__ */ new Date(0)) {
|
|
7352
7968
|
return {
|
|
@@ -7395,7 +8011,7 @@ async function summarizeWorkspaceDirectory(dirPath) {
|
|
|
7395
8011
|
return summary;
|
|
7396
8012
|
}
|
|
7397
8013
|
const childSummaries = await Promise.all(
|
|
7398
|
-
entries.map((entry) => summarizeWorkspaceEntry(
|
|
8014
|
+
entries.map((entry) => summarizeWorkspaceEntry(path12.join(dirPath, entry.name), entry))
|
|
7399
8015
|
);
|
|
7400
8016
|
for (const childSummary of childSummaries) {
|
|
7401
8017
|
summary = mergeWorkspaceDirectorySummaries(summary, childSummary);
|
|
@@ -7414,7 +8030,7 @@ async function scanWorkspaceDirectories(dataDir) {
|
|
|
7414
8030
|
if (!entry.isDirectory()) {
|
|
7415
8031
|
return null;
|
|
7416
8032
|
}
|
|
7417
|
-
const dirPath =
|
|
8033
|
+
const dirPath = path12.join(dataDir, entry.name);
|
|
7418
8034
|
try {
|
|
7419
8035
|
const summary = await summarizeWorkspaceDirectory(dirPath);
|
|
7420
8036
|
return {
|
|
@@ -7965,12 +8581,12 @@ function findSessionJsonl(root, predicate) {
|
|
|
7965
8581
|
for (const entry of entries) {
|
|
7966
8582
|
if (++visited > maxEntries) return null;
|
|
7967
8583
|
if (!entry.isFile() || !predicate(entry.name)) continue;
|
|
7968
|
-
return
|
|
8584
|
+
return path13.join(dir, entry.name);
|
|
7969
8585
|
}
|
|
7970
8586
|
for (const entry of entries) {
|
|
7971
8587
|
if (++visited > maxEntries) return null;
|
|
7972
8588
|
if (!entry.isDirectory()) continue;
|
|
7973
|
-
const found = visit(
|
|
8589
|
+
const found = visit(path13.join(dir, entry.name), depth - 1);
|
|
7974
8590
|
if (found) return found;
|
|
7975
8591
|
}
|
|
7976
8592
|
return null;
|
|
@@ -7983,9 +8599,9 @@ function safeSessionFilename(value) {
|
|
|
7983
8599
|
}
|
|
7984
8600
|
function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
7985
8601
|
try {
|
|
7986
|
-
const dir =
|
|
7987
|
-
|
|
7988
|
-
const filePath =
|
|
8602
|
+
const dir = path13.join(fallbackDir, ".slock", "runtime-sessions");
|
|
8603
|
+
mkdirSync5(dir, { recursive: true });
|
|
8604
|
+
const filePath = path13.join(dir, `${runtime}-${safeSessionFilename(sessionId)}.jsonl`);
|
|
7989
8605
|
writeFileSync4(filePath, JSON.stringify({
|
|
7990
8606
|
type: "runtime_session_handoff",
|
|
7991
8607
|
runtime,
|
|
@@ -8017,7 +8633,7 @@ function ensureRuntimeHomeDir(config, defaultHomeDir, workspacePath) {
|
|
|
8017
8633
|
return defaultHomeDir;
|
|
8018
8634
|
}
|
|
8019
8635
|
function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os6.homedir(), fallbackDir) {
|
|
8020
|
-
const directPath =
|
|
8636
|
+
const directPath = path13.isAbsolute(sessionId) ? sessionId : null;
|
|
8021
8637
|
if (directPath) {
|
|
8022
8638
|
try {
|
|
8023
8639
|
if (statSync(directPath).isFile()) {
|
|
@@ -8026,7 +8642,7 @@ function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os6.homedir(), f
|
|
|
8026
8642
|
} catch {
|
|
8027
8643
|
}
|
|
8028
8644
|
}
|
|
8029
|
-
const resolvedPath = runtime === "claude" ? findSessionJsonl(
|
|
8645
|
+
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
8646
|
if (!resolvedPath && fallbackDir) {
|
|
8031
8647
|
const fallback = writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir);
|
|
8032
8648
|
if (fallback) return fallback;
|
|
@@ -8751,6 +9367,9 @@ function resumeSessionRecoveryReason(ap) {
|
|
|
8751
9367
|
if (candidates.some(isOpenCodeReplayRejectedByProvider)) return "provider_replay_rejected";
|
|
8752
9368
|
return null;
|
|
8753
9369
|
}
|
|
9370
|
+
if (ap.driver.id === "pi") {
|
|
9371
|
+
return candidates.some(isPiReplayRejectedByProvider) ? "provider_replay_rejected" : null;
|
|
9372
|
+
}
|
|
8754
9373
|
if (ap.driver.id === "gemini") {
|
|
8755
9374
|
return candidates.some(
|
|
8756
9375
|
(text) => /Error resuming session:\s*Invalid session identifier/i.test(text) && text.includes(ap.sessionId)
|
|
@@ -8761,9 +9380,13 @@ function resumeSessionRecoveryReason(ap) {
|
|
|
8761
9380
|
function isOpenCodeReplayRejectedByProvider(text) {
|
|
8762
9381
|
return /Invalid request:\s*the message at position \d+ with role ['"]?assistant['"]? must not be empty/i.test(text);
|
|
8763
9382
|
}
|
|
9383
|
+
function isPiReplayRejectedByProvider(text) {
|
|
9384
|
+
return /Cannot continue from message role:\s*assistant/i.test(text);
|
|
9385
|
+
}
|
|
8764
9386
|
function resumeSessionRuntimeLabel(runtimeId) {
|
|
8765
9387
|
if (runtimeId === "opencode") return "OpenCode";
|
|
8766
9388
|
if (runtimeId === "gemini") return "Gemini";
|
|
9389
|
+
if (runtimeId === "pi") return "Pi";
|
|
8767
9390
|
return "Claude";
|
|
8768
9391
|
}
|
|
8769
9392
|
function classifyActivityDetailForTrace(detail) {
|
|
@@ -9032,6 +9655,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9032
9655
|
maxConcurrentAgentStarts;
|
|
9033
9656
|
agentStartIntervalMs;
|
|
9034
9657
|
startingInboxes = /* @__PURE__ */ new Map();
|
|
9658
|
+
terminalRuntimeFailures = /* @__PURE__ */ new Map();
|
|
9035
9659
|
pendingStartRebinds = /* @__PURE__ */ new Map();
|
|
9036
9660
|
/** Cached configs for agents whose process exited normally — enables auto-restart on next message */
|
|
9037
9661
|
idleAgentConfigs = /* @__PURE__ */ new Map();
|
|
@@ -9969,7 +10593,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9969
10593
|
);
|
|
9970
10594
|
wakeMessage = void 0;
|
|
9971
10595
|
}
|
|
9972
|
-
const agentDataDir =
|
|
10596
|
+
const agentDataDir = path13.join(this.dataDir, agentId);
|
|
9973
10597
|
await mkdir(agentDataDir, { recursive: true });
|
|
9974
10598
|
let runtimeConfig = withLocalRuntimeContext(config, agentId, agentDataDir);
|
|
9975
10599
|
const legacyRuntimeProfileControl = runtimeConfig.runtimeProfileControl?.kind === "migration" ? runtimeConfig.runtimeProfileControl : null;
|
|
@@ -9983,23 +10607,23 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
9983
10607
|
);
|
|
9984
10608
|
runtimeConfig = { ...runtimeConfig, runtimeProfileControl: null };
|
|
9985
10609
|
}
|
|
9986
|
-
const memoryMdPath =
|
|
10610
|
+
const memoryMdPath = path13.join(agentDataDir, "MEMORY.md");
|
|
9987
10611
|
try {
|
|
9988
10612
|
await access(memoryMdPath);
|
|
9989
10613
|
} catch {
|
|
9990
10614
|
const initialMemoryMd = buildInitialMemoryMd(runtimeConfig);
|
|
9991
10615
|
await writeFile(memoryMdPath, initialMemoryMd);
|
|
9992
10616
|
}
|
|
9993
|
-
const notesDir =
|
|
10617
|
+
const notesDir = path13.join(agentDataDir, "notes");
|
|
9994
10618
|
await mkdir(notesDir, { recursive: true });
|
|
9995
10619
|
if (getOnboardingSeedMode(config) === FIRST_CINDY_SEED_MODE) {
|
|
9996
10620
|
const seedFiles = buildOnboardingSeedFiles();
|
|
9997
10621
|
for (const { relativePath, content } of seedFiles) {
|
|
9998
|
-
const fullPath =
|
|
10622
|
+
const fullPath = path13.join(agentDataDir, relativePath);
|
|
9999
10623
|
try {
|
|
10000
10624
|
await access(fullPath);
|
|
10001
10625
|
} catch {
|
|
10002
|
-
await mkdir(
|
|
10626
|
+
await mkdir(path13.dirname(fullPath), { recursive: true });
|
|
10003
10627
|
await writeFile(fullPath, content);
|
|
10004
10628
|
}
|
|
10005
10629
|
}
|
|
@@ -10116,7 +10740,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10116
10740
|
daemonApiKey: this.daemonApiKey,
|
|
10117
10741
|
launchId: effectiveLaunchId,
|
|
10118
10742
|
agentCredentialProxyInboxCoordinator: this.createAgentProxyInboxCoordinator(agentId),
|
|
10119
|
-
cliTransportTraceDir: this.cliTransportTraceDir
|
|
10743
|
+
cliTransportTraceDir: this.cliTransportTraceDir,
|
|
10744
|
+
tracer: this.tracer
|
|
10120
10745
|
};
|
|
10121
10746
|
const runtime = driver.createSession?.(runtimeContext) ?? createChildProcessRuntimeSession(driver, runtimeContext);
|
|
10122
10747
|
agentProcess = {
|
|
@@ -10395,10 +11020,24 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10395
11020
|
}
|
|
10396
11021
|
}
|
|
10397
11022
|
});
|
|
10398
|
-
|
|
11023
|
+
let startResult;
|
|
11024
|
+
try {
|
|
11025
|
+
startResult = await runtime.start({ text: prompt, sessionId: effectiveConfig.sessionId || null });
|
|
11026
|
+
} catch (error) {
|
|
11027
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11028
|
+
startResult = { ok: false, reason: "runtime_error", error: message };
|
|
11029
|
+
}
|
|
10399
11030
|
if (!startResult.ok) {
|
|
11031
|
+
const diagnostics = startResult.error ? buildRuntimeErrorDiagnosticEnvelope(startResult.error) : null;
|
|
11032
|
+
this.recordDaemonTrace("daemon.agent.runtime_start.failed", {
|
|
11033
|
+
...this.startQueueTraceAttrs(agentId, effectiveConfig, wakeMessage, unreadSummary, resumePrompt, agentProcess.launchId || void 0, wakeMessageTransient),
|
|
11034
|
+
runtime_start_reason: startResult.reason,
|
|
11035
|
+
error_present: Boolean(startResult.error),
|
|
11036
|
+
runtime_error_class: diagnostics?.spanAttrs.runtime_error_class
|
|
11037
|
+
}, "error");
|
|
10400
11038
|
throw new Error(`Runtime session failed to start: ${startResult.reason}${startResult.error ? ` (${startResult.error})` : ""}`);
|
|
10401
11039
|
}
|
|
11040
|
+
this.terminalRuntimeFailures.delete(agentId);
|
|
10402
11041
|
this.recordDaemonTrace("daemon.agent.spawn.created", {
|
|
10403
11042
|
...this.startQueueTraceAttrs(agentId, effectiveConfig, wakeMessage, unreadSummary, resumePrompt, agentProcess.launchId || void 0, wakeMessageTransient),
|
|
10404
11043
|
detached: false,
|
|
@@ -10452,6 +11091,52 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10452
11091
|
this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
|
|
10453
11092
|
this.agents.delete(agentId);
|
|
10454
11093
|
this.idleAgentConfigs.delete(agentId);
|
|
11094
|
+
this.terminalRuntimeFailures.delete(agentId);
|
|
11095
|
+
}
|
|
11096
|
+
cleanupTerminalRuntimeFailure(agentId, ap, detail) {
|
|
11097
|
+
if (this.agents.get(agentId) !== ap) return;
|
|
11098
|
+
ap.notifications.clear();
|
|
11099
|
+
this.clearRuntimeErrorDeliveryBackoff(ap);
|
|
11100
|
+
if (ap.pendingTrajectory?.timer) {
|
|
11101
|
+
clearTimeout(ap.pendingTrajectory.timer);
|
|
11102
|
+
ap.pendingTrajectory.timer = null;
|
|
11103
|
+
}
|
|
11104
|
+
if (ap.activityHeartbeat) {
|
|
11105
|
+
clearInterval(ap.activityHeartbeat);
|
|
11106
|
+
ap.activityHeartbeat = null;
|
|
11107
|
+
}
|
|
11108
|
+
this.clearCompactionWatchdog(ap);
|
|
11109
|
+
this.clearRuntimeStartupTimeout(ap);
|
|
11110
|
+
this.clearStalledRecoverySigtermWatchdog(ap);
|
|
11111
|
+
cleanupAgentCredentialProxy(agentId, ap.launchId);
|
|
11112
|
+
this.revokeManagedRunnerCredential(agentId, ap.config, ap.launchId);
|
|
11113
|
+
this.idleAgentConfigs.delete(agentId);
|
|
11114
|
+
const pending = this.startingInboxes.get(agentId) || [];
|
|
11115
|
+
if (ap.inbox.length > 0) {
|
|
11116
|
+
this.startingInboxes.set(agentId, [...pending, ...ap.inbox]);
|
|
11117
|
+
}
|
|
11118
|
+
this.terminalRuntimeFailures.set(agentId, { detail, launchId: ap.launchId });
|
|
11119
|
+
this.agents.delete(agentId);
|
|
11120
|
+
const diagnostics = buildRuntimeErrorDiagnosticEnvelope(detail);
|
|
11121
|
+
this.recordDaemonTrace("daemon.agent.terminal_runtime_error.cleanup", {
|
|
11122
|
+
agentId,
|
|
11123
|
+
launchId: ap.launchId || void 0,
|
|
11124
|
+
runtime: ap.config.runtime,
|
|
11125
|
+
model: ap.config.model,
|
|
11126
|
+
session_id_present: Boolean(ap.sessionId),
|
|
11127
|
+
process_pid_present: typeof ap.runtime.pid === "number",
|
|
11128
|
+
inbox_count: ap.inbox.length,
|
|
11129
|
+
pending_notification_count: ap.notifications.pendingCount,
|
|
11130
|
+
runtime_error_class: diagnostics.spanAttrs.runtime_error_class
|
|
11131
|
+
}, "error");
|
|
11132
|
+
this.runtimeExitTraceAttrs.set(ap.runtime, {
|
|
11133
|
+
stop_source: "terminal_runtime_error",
|
|
11134
|
+
runtime_error_class: diagnostics.spanAttrs.runtime_error_class
|
|
11135
|
+
});
|
|
11136
|
+
void ap.runtime.stop({ signal: "SIGTERM", reason: "terminal_runtime_error" }).catch((err) => {
|
|
11137
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
11138
|
+
logger.warn(`[Agent ${agentId}] Failed to terminate ${ap.driver.id} after terminal runtime error: ${reason}`);
|
|
11139
|
+
});
|
|
10455
11140
|
}
|
|
10456
11141
|
cacheStartupTimeoutRetryConfig(agentId, ap) {
|
|
10457
11142
|
const retryConfig = {
|
|
@@ -10690,6 +11375,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10690
11375
|
this.cancelQueuedAgentStart(agentId, "stop requested");
|
|
10691
11376
|
this.pendingStartRebinds.delete(agentId);
|
|
10692
11377
|
this.idleAgentConfigs.delete(agentId);
|
|
11378
|
+
this.terminalRuntimeFailures.delete(agentId);
|
|
10693
11379
|
const ap = this.agents.get(agentId);
|
|
10694
11380
|
if (!ap) {
|
|
10695
11381
|
if (!silent) {
|
|
@@ -10792,6 +11478,35 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
10792
11478
|
}));
|
|
10793
11479
|
return true;
|
|
10794
11480
|
}
|
|
11481
|
+
const terminalRuntimeFailure = this.terminalRuntimeFailures.get(agentId);
|
|
11482
|
+
if (terminalRuntimeFailure) {
|
|
11483
|
+
if (transientDelivery) {
|
|
11484
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
11485
|
+
outcome: "transient_dropped_terminal_runtime_error_no_process",
|
|
11486
|
+
accepted: true,
|
|
11487
|
+
process_present: false,
|
|
11488
|
+
cached_idle_config_present: false,
|
|
11489
|
+
terminal_runtime_failure: true,
|
|
11490
|
+
launchId: terminalRuntimeFailure.launchId || void 0
|
|
11491
|
+
}));
|
|
11492
|
+
return true;
|
|
11493
|
+
}
|
|
11494
|
+
const pending = this.startingInboxes.get(agentId) || [];
|
|
11495
|
+
pending.push(message);
|
|
11496
|
+
this.startingInboxes.set(agentId, pending);
|
|
11497
|
+
this.recordDaemonTrace("daemon.agent.delivery.routed", this.deliveryTraceAttrs(agentId, message, {
|
|
11498
|
+
outcome: "queued_terminal_runtime_error_no_process",
|
|
11499
|
+
accepted: true,
|
|
11500
|
+
process_present: false,
|
|
11501
|
+
cached_idle_config_present: false,
|
|
11502
|
+
terminal_runtime_failure: true,
|
|
11503
|
+
starting_inbox_count: pending.length,
|
|
11504
|
+
launchId: terminalRuntimeFailure.launchId || void 0
|
|
11505
|
+
}));
|
|
11506
|
+
this.sendAgentStatus(agentId, "inactive", terminalRuntimeFailure.launchId);
|
|
11507
|
+
this.broadcastActivity(agentId, "error", terminalRuntimeFailure.detail, [], terminalRuntimeFailure.launchId);
|
|
11508
|
+
return true;
|
|
11509
|
+
}
|
|
10795
11510
|
const cached = this.idleAgentConfigs.get(agentId);
|
|
10796
11511
|
if (cached) {
|
|
10797
11512
|
const driver = this.driverResolver(cached.config.runtime || "claude");
|
|
@@ -11135,7 +11850,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11135
11850
|
return true;
|
|
11136
11851
|
}
|
|
11137
11852
|
async resetWorkspace(agentId) {
|
|
11138
|
-
const agentDataDir =
|
|
11853
|
+
const agentDataDir = path13.join(this.dataDir, agentId);
|
|
11139
11854
|
try {
|
|
11140
11855
|
await rm2(agentDataDir, { recursive: true, force: true });
|
|
11141
11856
|
logger.info(`[Agent ${agentId}] Workspace reset complete (${agentDataDir})`);
|
|
@@ -11196,7 +11911,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11196
11911
|
return result;
|
|
11197
11912
|
}
|
|
11198
11913
|
buildRuntimeProfileReport(agentId, config, sessionId, launchId) {
|
|
11199
|
-
const workspacePath =
|
|
11914
|
+
const workspacePath = path13.join(this.dataDir, agentId);
|
|
11200
11915
|
const runtimeHomeDir = resolveRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspacePath);
|
|
11201
11916
|
return {
|
|
11202
11917
|
agentId,
|
|
@@ -11490,7 +12205,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11490
12205
|
}
|
|
11491
12206
|
// Workspace file browsing
|
|
11492
12207
|
async getFileTree(agentId, dirPath) {
|
|
11493
|
-
const agentDir =
|
|
12208
|
+
const agentDir = path13.join(this.dataDir, agentId);
|
|
11494
12209
|
try {
|
|
11495
12210
|
await stat2(agentDir);
|
|
11496
12211
|
} catch {
|
|
@@ -11498,8 +12213,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11498
12213
|
}
|
|
11499
12214
|
let targetDir = agentDir;
|
|
11500
12215
|
if (dirPath) {
|
|
11501
|
-
const resolved =
|
|
11502
|
-
if (!resolved.startsWith(agentDir +
|
|
12216
|
+
const resolved = path13.resolve(agentDir, dirPath);
|
|
12217
|
+
if (!resolved.startsWith(agentDir + path13.sep) && resolved !== agentDir) {
|
|
11503
12218
|
return [];
|
|
11504
12219
|
}
|
|
11505
12220
|
targetDir = resolved;
|
|
@@ -11507,14 +12222,14 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11507
12222
|
return this.listDirectoryChildren(targetDir, agentDir);
|
|
11508
12223
|
}
|
|
11509
12224
|
async readFile(agentId, filePath) {
|
|
11510
|
-
const agentDir =
|
|
11511
|
-
const resolved =
|
|
11512
|
-
if (!resolved.startsWith(agentDir +
|
|
12225
|
+
const agentDir = path13.join(this.dataDir, agentId);
|
|
12226
|
+
const resolved = path13.resolve(agentDir, filePath);
|
|
12227
|
+
if (!resolved.startsWith(agentDir + path13.sep) && resolved !== agentDir) {
|
|
11513
12228
|
throw new Error("Access denied");
|
|
11514
12229
|
}
|
|
11515
12230
|
const info = await stat2(resolved);
|
|
11516
12231
|
if (info.isDirectory()) throw new Error("Cannot read a directory");
|
|
11517
|
-
const ext =
|
|
12232
|
+
const ext = path13.extname(resolved).toLowerCase();
|
|
11518
12233
|
if (WORKSPACE_TEXT_EXTENSIONS.has(ext) || ext === "") {
|
|
11519
12234
|
if (info.size > WORKSPACE_TEXT_FILE_MAX_BYTES) throw new Error("File too large");
|
|
11520
12235
|
const content = await readFile(resolved, "utf-8");
|
|
@@ -11550,14 +12265,14 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11550
12265
|
const idle = this.idleAgentConfigs.get(agentId);
|
|
11551
12266
|
const config = agent?.config ?? idle?.config ?? null;
|
|
11552
12267
|
const runtime = runtimeHint || config?.runtime || "claude";
|
|
11553
|
-
const workspaceDir =
|
|
12268
|
+
const workspaceDir = path13.join(this.dataDir, agentId);
|
|
11554
12269
|
const home = config ? ensureRuntimeHomeDir(config, os6.homedir(), workspaceDir) : os6.homedir();
|
|
11555
12270
|
const paths = _AgentProcessManager.SKILL_PATHS[runtime] || _AgentProcessManager.SKILL_PATHS.claude;
|
|
11556
12271
|
const globalResults = await Promise.all(
|
|
11557
|
-
paths.global.map((p) => this.scanSkillsDir(
|
|
12272
|
+
paths.global.map((p) => this.scanSkillsDir(path13.join(home, p)))
|
|
11558
12273
|
);
|
|
11559
12274
|
const workspaceResults = await Promise.all(
|
|
11560
|
-
paths.workspace.map((p) => this.scanSkillsDir(
|
|
12275
|
+
paths.workspace.map((p) => this.scanSkillsDir(path13.join(workspaceDir, p)))
|
|
11561
12276
|
);
|
|
11562
12277
|
const dedup = (skills) => {
|
|
11563
12278
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -11586,7 +12301,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11586
12301
|
const skills = [];
|
|
11587
12302
|
for (const entry of entries) {
|
|
11588
12303
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
11589
|
-
const skillMd =
|
|
12304
|
+
const skillMd = path13.join(dir, entry.name, "SKILL.md");
|
|
11590
12305
|
try {
|
|
11591
12306
|
const content = await readFile(skillMd, "utf-8");
|
|
11592
12307
|
const skill = this.parseSkillMd(entry.name, content);
|
|
@@ -11597,7 +12312,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11597
12312
|
} else if (entry.name.endsWith(".md")) {
|
|
11598
12313
|
const cmdName = entry.name.replace(/\.md$/, "");
|
|
11599
12314
|
try {
|
|
11600
|
-
const content = await readFile(
|
|
12315
|
+
const content = await readFile(path13.join(dir, entry.name), "utf-8");
|
|
11601
12316
|
const skill = this.parseSkillMd(cmdName, content);
|
|
11602
12317
|
skill.sourcePath = dir;
|
|
11603
12318
|
skills.push(skill);
|
|
@@ -12574,8 +13289,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
12574
13289
|
logger.warn(`[Agent ${agentId}] Failed to terminate ${ap.driver.id} after auth error: ${reason}`);
|
|
12575
13290
|
}
|
|
12576
13291
|
} else if (stickyTerminalFailure) {
|
|
12577
|
-
ap.notifications.clear();
|
|
12578
13292
|
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
13293
|
+
this.cleanupTerminalRuntimeFailure(agentId, ap, stickyTerminalFailure.detail);
|
|
12579
13294
|
logger.warn(`[Agent ${agentId}] ${ap.driver.id} terminal runtime error requires explicit recovery`);
|
|
12580
13295
|
} else {
|
|
12581
13296
|
ap.notifications.clearPending();
|
|
@@ -13077,8 +13792,8 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
13077
13792
|
const nodes = [];
|
|
13078
13793
|
for (const entry of entries) {
|
|
13079
13794
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
13080
|
-
const fullPath =
|
|
13081
|
-
const relativePath =
|
|
13795
|
+
const fullPath = path13.join(dir, entry.name);
|
|
13796
|
+
const relativePath = path13.relative(rootDir, fullPath);
|
|
13082
13797
|
let info;
|
|
13083
13798
|
try {
|
|
13084
13799
|
info = await stat2(fullPath);
|
|
@@ -13451,10 +14166,10 @@ var ReminderCache = class {
|
|
|
13451
14166
|
};
|
|
13452
14167
|
|
|
13453
14168
|
// src/machineLock.ts
|
|
13454
|
-
import { createHash as createHash4, randomUUID as
|
|
13455
|
-
import { mkdirSync as
|
|
14169
|
+
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
14170
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
13456
14171
|
import os7 from "os";
|
|
13457
|
-
import
|
|
14172
|
+
import path14 from "path";
|
|
13458
14173
|
var INCOMPLETE_LOCK_STALE_MS = 3e4;
|
|
13459
14174
|
var DaemonMachineLockConflictError = class extends Error {
|
|
13460
14175
|
code = "DAEMON_MACHINE_LOCK_HELD";
|
|
@@ -13476,7 +14191,7 @@ function resolveDefaultMachineStateRoot() {
|
|
|
13476
14191
|
return resolveSlockHomePath("machines");
|
|
13477
14192
|
}
|
|
13478
14193
|
function ownerPath(lockDir) {
|
|
13479
|
-
return
|
|
14194
|
+
return path14.join(lockDir, "owner.json");
|
|
13480
14195
|
}
|
|
13481
14196
|
function readOwner(lockDir) {
|
|
13482
14197
|
try {
|
|
@@ -13506,13 +14221,13 @@ function acquireDaemonMachineLock(options) {
|
|
|
13506
14221
|
const rootDir = options.rootDir ?? resolveDefaultMachineStateRoot();
|
|
13507
14222
|
const fingerprint = apiKeyFingerprint(options.apiKey);
|
|
13508
14223
|
const lockId = getDaemonMachineLockId(options.apiKey);
|
|
13509
|
-
const machineDir =
|
|
13510
|
-
const lockDir =
|
|
13511
|
-
const token =
|
|
13512
|
-
|
|
14224
|
+
const machineDir = path14.join(rootDir, lockId);
|
|
14225
|
+
const lockDir = path14.join(machineDir, "daemon.lock");
|
|
14226
|
+
const token = randomUUID5();
|
|
14227
|
+
mkdirSync6(machineDir, { recursive: true });
|
|
13513
14228
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
13514
14229
|
try {
|
|
13515
|
-
|
|
14230
|
+
mkdirSync6(lockDir);
|
|
13516
14231
|
const owner = {
|
|
13517
14232
|
pid: process.pid,
|
|
13518
14233
|
token,
|
|
@@ -13567,8 +14282,8 @@ function acquireDaemonMachineLock(options) {
|
|
|
13567
14282
|
}
|
|
13568
14283
|
|
|
13569
14284
|
// src/localTraceSink.ts
|
|
13570
|
-
import { appendFileSync, mkdirSync as
|
|
13571
|
-
import
|
|
14285
|
+
import { appendFileSync, mkdirSync as mkdirSync7, readdirSync as readdirSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
14286
|
+
import path15 from "path";
|
|
13572
14287
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
13573
14288
|
var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
|
|
13574
14289
|
var DEFAULT_MAX_FILES = 8;
|
|
@@ -13605,7 +14320,7 @@ var LocalRotatingTraceSink = class {
|
|
|
13605
14320
|
currentSize = 0;
|
|
13606
14321
|
sequence = 0;
|
|
13607
14322
|
constructor(options) {
|
|
13608
|
-
this.traceDir =
|
|
14323
|
+
this.traceDir = path15.join(options.machineDir, "traces");
|
|
13609
14324
|
this.maxFileBytes = Math.max(1024, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES));
|
|
13610
14325
|
const baseAgeMs = Math.max(1e3, Math.floor(options.maxFileAgeMs ?? DEFAULT_MAX_FILE_AGE_MS));
|
|
13611
14326
|
const ageJitterMs = Math.max(0, Math.floor(options.maxFileAgeJitterMs ?? 0));
|
|
@@ -13631,11 +14346,11 @@ var LocalRotatingTraceSink = class {
|
|
|
13631
14346
|
return this.currentFile;
|
|
13632
14347
|
}
|
|
13633
14348
|
ensureFile(nextBytes) {
|
|
13634
|
-
|
|
14349
|
+
mkdirSync7(this.traceDir, { recursive: true, mode: 448 });
|
|
13635
14350
|
const nowMs = this.nowMsProvider();
|
|
13636
14351
|
const shouldRotateForAge = this.currentFileOpenedAtMs !== null && nowMs - this.currentFileOpenedAtMs >= this.maxFileAgeMs;
|
|
13637
14352
|
if (!this.currentFile || this.currentSize + nextBytes > this.maxFileBytes || shouldRotateForAge) {
|
|
13638
|
-
this.currentFile =
|
|
14353
|
+
this.currentFile = path15.join(
|
|
13639
14354
|
this.traceDir,
|
|
13640
14355
|
`daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
|
|
13641
14356
|
);
|
|
@@ -13650,7 +14365,7 @@ var LocalRotatingTraceSink = class {
|
|
|
13650
14365
|
const excess = files.length - this.maxFiles;
|
|
13651
14366
|
if (excess <= 0) return;
|
|
13652
14367
|
for (const file of files.slice(0, excess)) {
|
|
13653
|
-
rmSync4(
|
|
14368
|
+
rmSync4(path15.join(this.traceDir, file), { force: true });
|
|
13654
14369
|
}
|
|
13655
14370
|
}
|
|
13656
14371
|
};
|
|
@@ -13738,10 +14453,10 @@ function isDiagnosticErrorAttr(key) {
|
|
|
13738
14453
|
}
|
|
13739
14454
|
|
|
13740
14455
|
// src/traceBundleUpload.ts
|
|
13741
|
-
import { createHash as createHash6, randomUUID as
|
|
14456
|
+
import { createHash as createHash6, randomUUID as randomUUID6 } from "crypto";
|
|
13742
14457
|
import { gzipSync } from "zlib";
|
|
13743
14458
|
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
13744
|
-
import
|
|
14459
|
+
import path16 from "path";
|
|
13745
14460
|
|
|
13746
14461
|
// src/chatBridgeRequest.ts
|
|
13747
14462
|
var DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS = Number.parseInt(
|
|
@@ -13841,8 +14556,8 @@ async function executeResponseRequest(url, init, {
|
|
|
13841
14556
|
}
|
|
13842
14557
|
|
|
13843
14558
|
// src/directUploadCapability.ts
|
|
13844
|
-
function joinUrl(base,
|
|
13845
|
-
return `${base.replace(/\/+$/, "")}${
|
|
14559
|
+
function joinUrl(base, path18) {
|
|
14560
|
+
return `${base.replace(/\/+$/, "")}${path18}`;
|
|
13846
14561
|
}
|
|
13847
14562
|
function jsonHeaders(apiKey) {
|
|
13848
14563
|
return {
|
|
@@ -14061,7 +14776,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
14061
14776
|
}, nextMs);
|
|
14062
14777
|
}
|
|
14063
14778
|
async findUploadCandidates() {
|
|
14064
|
-
const traceDir =
|
|
14779
|
+
const traceDir = path16.join(this.options.machineDir, "traces");
|
|
14065
14780
|
let names;
|
|
14066
14781
|
try {
|
|
14067
14782
|
names = await readdir3(traceDir);
|
|
@@ -14073,8 +14788,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
14073
14788
|
const currentFile = this.options.currentFileProvider?.();
|
|
14074
14789
|
const candidates = [];
|
|
14075
14790
|
for (const name of names.filter((entry) => entry.startsWith("daemon-trace-") && entry.endsWith(".jsonl")).sort()) {
|
|
14076
|
-
const file =
|
|
14077
|
-
if (currentFile &&
|
|
14791
|
+
const file = path16.join(traceDir, name);
|
|
14792
|
+
if (currentFile && path16.resolve(file) === path16.resolve(currentFile)) continue;
|
|
14078
14793
|
if (await this.isUploaded(file)) continue;
|
|
14079
14794
|
try {
|
|
14080
14795
|
const info = await stat3(file);
|
|
@@ -14106,7 +14821,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
14106
14821
|
}
|
|
14107
14822
|
const gzipped = gzipSync(raw);
|
|
14108
14823
|
const bundleSha256 = sha256Hex(gzipped);
|
|
14109
|
-
const bundleId =
|
|
14824
|
+
const bundleId = randomUUID6();
|
|
14110
14825
|
await uploadWithSignedCapability({
|
|
14111
14826
|
serverUrl: this.options.serverUrl,
|
|
14112
14827
|
apiKey: this.options.apiKey,
|
|
@@ -14148,8 +14863,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
14148
14863
|
}
|
|
14149
14864
|
}
|
|
14150
14865
|
uploadStatePath(file) {
|
|
14151
|
-
const stateDir =
|
|
14152
|
-
return
|
|
14866
|
+
const stateDir = path16.join(this.options.machineDir, "trace-uploads");
|
|
14867
|
+
return path16.join(stateDir, `${path16.basename(file)}.uploaded.json`);
|
|
14153
14868
|
}
|
|
14154
14869
|
async isUploaded(file) {
|
|
14155
14870
|
try {
|
|
@@ -14161,9 +14876,9 @@ var DaemonTraceBundleUploader = class {
|
|
|
14161
14876
|
}
|
|
14162
14877
|
async markUploaded(file, metadata) {
|
|
14163
14878
|
const stateFile = this.uploadStatePath(file);
|
|
14164
|
-
await mkdir2(
|
|
14879
|
+
await mkdir2(path16.dirname(stateFile), { recursive: true, mode: 448 });
|
|
14165
14880
|
await writeFile2(stateFile, `${JSON.stringify({
|
|
14166
|
-
file:
|
|
14881
|
+
file: path16.basename(file),
|
|
14167
14882
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14168
14883
|
...metadata
|
|
14169
14884
|
}, null, 2)}
|
|
@@ -14226,6 +14941,24 @@ var DAEMON_CORE_TRACE_ATTR_CONTRACTS = {
|
|
|
14226
14941
|
"daemon.runtime_profile.report.sent": {
|
|
14227
14942
|
spanAttrs: ["agentId", "launchId", "runtime", "report_source", "model_present", "session_ref_present", "workspace_ref_present"]
|
|
14228
14943
|
},
|
|
14944
|
+
"daemon.runtime_models.detect": {
|
|
14945
|
+
spanAttrs: ["runtime", "requestId"],
|
|
14946
|
+
eventAttrs: {
|
|
14947
|
+
"daemon.pi.models.services_ready": ["available_models_count", "diagnostics_count", "diagnostic_info_count", "diagnostic_warning_count"],
|
|
14948
|
+
"daemon.pi.models.result": ["available_models_count", "returned_models_count", "diagnostics_count", "diagnostic_info_count", "diagnostic_warning_count", "outcome"]
|
|
14949
|
+
},
|
|
14950
|
+
endAttrs: ["outcome", "models_count", "default_model_present", "verified_as", "error_class"]
|
|
14951
|
+
},
|
|
14952
|
+
"daemon.pi.session.create": {
|
|
14953
|
+
spanAttrs: ["agentId", "launchId", "runtime", "model", "session_id_present", "requested_model"],
|
|
14954
|
+
eventAttrs: {
|
|
14955
|
+
"daemon.pi.session.services_ready": ["available_models_count", "diagnostics_count", "diagnostic_info_count", "diagnostic_warning_count", "agent_dir_source"],
|
|
14956
|
+
"daemon.pi.session.model_resolved": ["available_models_count", "requested_model", "requested_model_explicit", "resolved_model", "resolved_model_present"],
|
|
14957
|
+
"daemon.pi.session.missing_model": ["available_models_count", "requested_model"],
|
|
14958
|
+
"daemon.pi.session.started": ["requested_model", "resolved_model", "session_id_present"]
|
|
14959
|
+
},
|
|
14960
|
+
endAttrs: ["outcome", "available_models_count", "diagnostics_count", "diagnostic_info_count", "diagnostic_warning_count", "requested_model", "resolved_model", "resolved_model_present", "error_class"]
|
|
14961
|
+
},
|
|
14229
14962
|
"daemon.connection.local_disconnect_observed": {
|
|
14230
14963
|
spanAttrs: ["running_agents_count", "idle_agents_count"]
|
|
14231
14964
|
}
|
|
@@ -14278,20 +15011,20 @@ function parseDaemonCliArgs(args) {
|
|
|
14278
15011
|
}
|
|
14279
15012
|
function readDaemonVersion(moduleUrl = import.meta.url) {
|
|
14280
15013
|
try {
|
|
14281
|
-
const require2 =
|
|
15014
|
+
const require2 = createRequire3(moduleUrl);
|
|
14282
15015
|
return require2("../package.json").version;
|
|
14283
15016
|
} catch {
|
|
14284
15017
|
return "0.0.0-dev";
|
|
14285
15018
|
}
|
|
14286
15019
|
}
|
|
14287
15020
|
function resolveSlockCliPath(moduleUrl = import.meta.url) {
|
|
14288
|
-
const thisDir =
|
|
14289
|
-
const bundledDistPath =
|
|
15021
|
+
const thisDir = path17.dirname(fileURLToPath(moduleUrl));
|
|
15022
|
+
const bundledDistPath = path17.resolve(thisDir, "cli", "index.js");
|
|
14290
15023
|
try {
|
|
14291
15024
|
accessSync(bundledDistPath);
|
|
14292
15025
|
return bundledDistPath;
|
|
14293
15026
|
} catch {
|
|
14294
|
-
const workspaceDistPath =
|
|
15027
|
+
const workspaceDistPath = path17.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
|
|
14295
15028
|
accessSync(workspaceDistPath);
|
|
14296
15029
|
return workspaceDistPath;
|
|
14297
15030
|
}
|
|
@@ -14305,7 +15038,7 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
|
|
|
14305
15038
|
}
|
|
14306
15039
|
async function runBundledSlockCli(argv) {
|
|
14307
15040
|
process.argv = [process.execPath, "slock", ...argv];
|
|
14308
|
-
await import("./dist-
|
|
15041
|
+
await import("./dist-6YUWBDWX.js");
|
|
14309
15042
|
}
|
|
14310
15043
|
function detectRuntimes(tracer = noopTracer) {
|
|
14311
15044
|
const ids = [];
|
|
@@ -14497,7 +15230,7 @@ var DaemonCore = class {
|
|
|
14497
15230
|
}
|
|
14498
15231
|
resolveMachineStateRoot() {
|
|
14499
15232
|
if (this.options.machineStateDir) return this.options.machineStateDir;
|
|
14500
|
-
if (this.options.dataDir) return
|
|
15233
|
+
if (this.options.dataDir) return path17.join(path17.dirname(this.options.dataDir), "machines");
|
|
14501
15234
|
return resolveDefaultMachineStateRoot();
|
|
14502
15235
|
}
|
|
14503
15236
|
shouldEnableLocalTrace() {
|
|
@@ -14524,7 +15257,7 @@ var DaemonCore = class {
|
|
|
14524
15257
|
sink: this.localTraceSink
|
|
14525
15258
|
}));
|
|
14526
15259
|
this.agentManager.setTracer(this.tracer);
|
|
14527
|
-
this.agentManager.setCliTransportTraceDir(
|
|
15260
|
+
this.agentManager.setCliTransportTraceDir(path17.join(machineDir, "traces"));
|
|
14528
15261
|
}
|
|
14529
15262
|
installTraceBundleUploader(machineDir) {
|
|
14530
15263
|
if (!this.shouldEnableLocalTrace()) return;
|
|
@@ -14926,7 +15659,15 @@ var DaemonCore = class {
|
|
|
14926
15659
|
break;
|
|
14927
15660
|
case "machine:runtime_models:detect": {
|
|
14928
15661
|
const driver = getDriver(msg.runtime);
|
|
14929
|
-
const
|
|
15662
|
+
const span = this.tracer.startSpan("daemon.runtime_models.detect", {
|
|
15663
|
+
surface: "daemon",
|
|
15664
|
+
kind: "internal",
|
|
15665
|
+
attrs: {
|
|
15666
|
+
runtime: msg.runtime,
|
|
15667
|
+
requestId: msg.requestId
|
|
15668
|
+
}
|
|
15669
|
+
});
|
|
15670
|
+
const detect = typeof driver?.detectModels === "function" ? driver.detectModels({ tracer: this.tracer, span }) : Promise.resolve(null);
|
|
14930
15671
|
Promise.resolve(detect).then((result) => {
|
|
14931
15672
|
if (result) {
|
|
14932
15673
|
const verified = driver.model.detectedModelsVerifiedAs;
|
|
@@ -14935,12 +15676,32 @@ var DaemonCore = class {
|
|
|
14935
15676
|
verified: model.verified ?? verified
|
|
14936
15677
|
}));
|
|
14937
15678
|
this.connection.send({ type: "machine:runtime_models:result", requestId: msg.requestId, models, default: result.default });
|
|
15679
|
+
span.end("ok", {
|
|
15680
|
+
attrs: {
|
|
15681
|
+
outcome: "models_returned",
|
|
15682
|
+
models_count: models.length,
|
|
15683
|
+
default_model_present: Boolean(result.default),
|
|
15684
|
+
verified_as: verified
|
|
15685
|
+
}
|
|
15686
|
+
});
|
|
14938
15687
|
} else {
|
|
14939
15688
|
this.connection.send({ type: "machine:runtime_models:result", requestId: msg.requestId, error: "unsupported" });
|
|
15689
|
+
span.end("ok", {
|
|
15690
|
+
attrs: {
|
|
15691
|
+
outcome: "unsupported",
|
|
15692
|
+
models_count: 0
|
|
15693
|
+
}
|
|
15694
|
+
});
|
|
14940
15695
|
}
|
|
14941
15696
|
}).catch((err) => {
|
|
14942
15697
|
const reason = err instanceof Error ? err.message : String(err);
|
|
14943
15698
|
this.connection.send({ type: "machine:runtime_models:result", requestId: msg.requestId, error: reason });
|
|
15699
|
+
span.end("error", {
|
|
15700
|
+
attrs: {
|
|
15701
|
+
outcome: "error",
|
|
15702
|
+
error_class: err instanceof Error ? err.name : typeof err
|
|
15703
|
+
}
|
|
15704
|
+
});
|
|
14944
15705
|
});
|
|
14945
15706
|
break;
|
|
14946
15707
|
}
|