@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.
@@ -1,10 +1,16 @@
1
1
  // src/core.ts
2
- import path16 from "path";
2
+ import path17 from "path";
3
3
  import os8 from "os";
4
- import { createRequire as createRequire2 } from "module";
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
- { id: "kimi", displayName: "Kimi CLI", binary: "kimi", supported: true },
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 mkdirSync4, readdirSync as readdirSync3, statSync, writeFileSync as writeFileSync4 } from "fs";
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 path12 from "path";
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 (supports batch, handles conflicts).
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
- "SLOCK_AGENT_CREDENTIAL_KEY"
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
- delete spawnEnv.SLOCK_AGENT_TOKEN;
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) => ({ args: ["--model", 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 launch = resolveKimiSpawn(args);
6062
- const proc = spawn7(launch.command, launch.args, {
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: launch.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 configPath = path8.join(home, ".kimi", "config.toml");
6185
- let raw;
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 path9 from "path";
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 = path9.join(home, ".config", "opencode", "opencode.json");
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 = path9.win32.extname(commandPath).toLowerCase();
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 = path9.win32;
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 (path9.win32.extname(entry).toLowerCase() === ".exe") {
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 = path9.win32;
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 = path9.win32.dirname(commandPath);
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(path9.win32.normalize(path9.win32.join(commandDir, relative)));
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 && path9.win32.extname(command).toLowerCase() === ".exe") {
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 randomUUID3 } from "crypto";
6686
- import { EventEmitter } from "events";
6687
- import { mkdirSync as mkdirSync3, readdirSync as readdirSync2 } from "fs";
6688
- import path10 from "path";
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
- createAgentSession,
6693
- DefaultResourceLoader,
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 path10.join(workingDirectory, PI_SESSION_DIR);
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 ? path10.join(sessionDir, match) : null;
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 detectPiModels(modelRegistry = ModelRegistry.create(AuthStorage.create())) {
6755
- return detectPiModelsFromRegistry(modelRegistry);
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 pushSessionInitIfNeeded(state, events) {
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
- pushSessionInitIfNeeded(state, events);
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
- mkdirSync3(sessionDir, { recursive: true });
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 model = resolvePiModelFromRegistry(launchRuntimeFields.model, modelRegistry);
6897
- if (launchRuntimeFields.model && launchRuntimeFields.model !== "default" && !model) {
6898
- throw new Error(`Pi model not found: ${launchRuntimeFields.model}`);
6899
- }
6900
- const settingsManager = SettingsManager.inMemory({ compaction: { enabled: PI_SDK_COMPACTION_ENABLED } });
6901
- const resourceLoader = new DefaultResourceLoader({
6902
- cwd: ctx.workingDirectory,
6903
- agentDir,
6904
- settingsManager,
6905
- systemPromptOverride: () => ctx.standingPrompt
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
- await resourceLoader.reload();
6908
- const existingSessionFile = ctx.config.sessionId ? findPiSessionFile(sessionDir, ctx.config.sessionId) : null;
6909
- const sessionManager = existingSessionFile ? SessionManager.open(existingSessionFile, sessionDir, ctx.workingDirectory) : SessionManager.create(ctx.workingDirectory, sessionDir, { id: sessionId });
6910
- const { session } = await createAgentSession({
6911
- cwd: ctx.workingDirectory,
6912
- agentDir,
6913
- model,
6914
- thinkingLevel: launchRuntimeFields.reasoningEffort,
6915
- authStorage,
6916
- modelRegistry,
6917
- resourceLoader,
6918
- customTools: [
6919
- createBashTool(ctx.workingDirectory, {
6920
- spawnHook: (spawnContext) => ({
6921
- ...spawnContext,
6922
- env: {
6923
- ...spawnContext.env,
6924
- ...spawnEnv
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
- sessionManager,
6930
- settingsManager
6931
- });
6932
- return session;
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 EventEmitter();
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 || randomUUID3();
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 EventEmitter2 } from "events";
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 EventEmitter2();
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 path11 from "path";
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 path11.join(dataDir, directoryName);
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(path11.join(dirPath, entry.name), entry))
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 = path11.join(dataDir, entry.name);
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 path12.join(dir, entry.name);
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(path12.join(dir, entry.name), depth - 1);
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 = path12.join(fallbackDir, ".slock", "runtime-sessions");
7987
- mkdirSync4(dir, { recursive: true });
7988
- const filePath = path12.join(dir, `${runtime}-${safeSessionFilename(sessionId)}.jsonl`);
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 = path12.isAbsolute(sessionId) ? sessionId : null;
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(path12.join(homeDir, ".claude", "projects"), (filename) => filename === `${sessionId}.jsonl`) : runtime === "codex" ? findSessionJsonl(path12.join(homeDir, ".codex", "sessions"), (filename) => filename.endsWith(".jsonl") && filename.includes(sessionId)) : null;
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 = path12.join(this.dataDir, agentId);
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 = path12.join(agentDataDir, "MEMORY.md");
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 = path12.join(agentDataDir, "notes");
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 = path12.join(agentDataDir, relativePath);
10722
+ const fullPath = path13.join(agentDataDir, relativePath);
9999
10723
  try {
10000
10724
  await access(fullPath);
10001
10725
  } catch {
10002
- await mkdir(path12.dirname(fullPath), { recursive: true });
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
- const startResult = await runtime.start({ text: prompt, sessionId: effectiveConfig.sessionId || null });
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 = path12.join(this.dataDir, agentId);
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 = path12.join(this.dataDir, agentId);
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 = path12.join(this.dataDir, agentId);
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 = path12.resolve(agentDir, dirPath);
11502
- if (!resolved.startsWith(agentDir + path12.sep) && resolved !== 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 = path12.join(this.dataDir, agentId);
11511
- const resolved = path12.resolve(agentDir, filePath);
11512
- if (!resolved.startsWith(agentDir + path12.sep) && resolved !== 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 = path12.extname(resolved).toLowerCase();
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 = path12.join(this.dataDir, agentId);
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(path12.join(home, p)))
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(path12.join(workspaceDir, p)))
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 = path12.join(dir, entry.name, "SKILL.md");
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(path12.join(dir, entry.name), "utf-8");
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 = path12.join(dir, entry.name);
13081
- const relativePath = path12.relative(rootDir, fullPath);
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 randomUUID4 } from "crypto";
13455
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
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 path13 from "path";
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 path13.join(lockDir, "owner.json");
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 = path13.join(rootDir, lockId);
13510
- const lockDir = path13.join(machineDir, "daemon.lock");
13511
- const token = randomUUID4();
13512
- mkdirSync5(machineDir, { recursive: true });
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
- mkdirSync5(lockDir);
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 mkdirSync6, readdirSync as readdirSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
13571
- import path14 from "path";
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 = path14.join(options.machineDir, "traces");
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
- mkdirSync6(this.traceDir, { recursive: true, mode: 448 });
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 = path14.join(
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(path14.join(this.traceDir, file), { force: true });
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 randomUUID5 } from "crypto";
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 path15 from "path";
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, path17) {
13845
- return `${base.replace(/\/+$/, "")}${path17}`;
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 = path15.join(this.options.machineDir, "traces");
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 = path15.join(traceDir, name);
14077
- if (currentFile && path15.resolve(file) === path15.resolve(currentFile)) continue;
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 = randomUUID5();
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 = path15.join(this.options.machineDir, "trace-uploads");
14152
- return path15.join(stateDir, `${path15.basename(file)}.uploaded.json`);
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(path15.dirname(stateFile), { recursive: true, mode: 448 });
14979
+ await mkdir2(path16.dirname(stateFile), { recursive: true, mode: 448 });
14165
14980
  await writeFile2(stateFile, `${JSON.stringify({
14166
- file: path15.basename(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 = "Usage: slock-daemon --server-url <url> --api-key <key>";
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 = createRequire2(moduleUrl);
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 = path16.dirname(fileURLToPath(moduleUrl));
14289
- const bundledDistPath = path16.resolve(thisDir, "cli", "index.js");
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 = path16.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
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-JVLCJ2QO.js");
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 path16.join(path16.dirname(this.options.dataDir), "machines");
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(path16.join(machineDir, "traces"));
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 detect = typeof driver?.detectModels === "function" ? driver.detectModels() : Promise.resolve(null);
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,