@slock-ai/daemon 0.54.2 → 0.55.1

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.
@@ -9,11 +9,35 @@ import {
9
9
 
10
10
  // src/core.ts
11
11
  import path16 from "path";
12
- import os8 from "os";
12
+ import os7 from "os";
13
13
  import { createRequire as createRequire2 } from "module";
14
14
  import { accessSync } from "fs";
15
15
  import { fileURLToPath } from "url";
16
16
 
17
+ // ../shared/src/slockRefs.ts
18
+ var SLOCK_REF_CHANNEL_NAME_PATTERN = String.raw`[\p{L}\p{N}_-]+`;
19
+ var SLOCK_REF_USER_NAME_PATTERN = SLOCK_REF_CHANNEL_NAME_PATTERN;
20
+ var SLOCK_REF_DM_PEER_PATTERN = String.raw`[\w-]+`;
21
+ var SLOCK_REF_THREAD_SHORT_ID_PATTERN = String.raw`[\da-f]{6,8}`;
22
+ var SLOCK_REF_MESSAGE_ID_PATTERN = String.raw`[A-Za-z0-9][A-Za-z0-9-]{1,63}`;
23
+ var SLOCK_REF_TASK_NUMBER_PATTERN = String.raw`[1-9]\d*`;
24
+ var USER_RE = new RegExp(String.raw`^@(${SLOCK_REF_USER_NAME_PATTERN})$`, "u");
25
+ var CHANNEL_RE = new RegExp(String.raw`^#(${SLOCK_REF_CHANNEL_NAME_PATTERN})$`, "u");
26
+ var CHANNEL_THREAD_RE = new RegExp(
27
+ String.raw`^#(${SLOCK_REF_CHANNEL_NAME_PATTERN}):(${SLOCK_REF_THREAD_SHORT_ID_PATTERN})$`,
28
+ "iu"
29
+ );
30
+ var DM_RE = new RegExp(String.raw`^dm:@(${SLOCK_REF_DM_PEER_PATTERN})$`, "iu");
31
+ var DM_THREAD_RE = new RegExp(
32
+ String.raw`^dm:@(${SLOCK_REF_DM_PEER_PATTERN}):(${SLOCK_REF_THREAD_SHORT_ID_PATTERN})$`,
33
+ "iu"
34
+ );
35
+ var TASK_RE = new RegExp(String.raw`^task\s+#(${SLOCK_REF_TASK_NUMBER_PATTERN})$`, "iu");
36
+ var CHANNEL_MESSAGE_RE = new RegExp(
37
+ String.raw`^#(${SLOCK_REF_CHANNEL_NAME_PATTERN})(?::(${SLOCK_REF_THREAD_SHORT_ID_PATTERN}))?\s+msg=(${SLOCK_REF_MESSAGE_ID_PATTERN})$`,
38
+ "iu"
39
+ );
40
+
17
41
  // ../shared/src/tracing/index.ts
18
42
  var DEFAULT_TRACE_FLAGS = "00";
19
43
  var TRACEPARENT_VERSION = "00";
@@ -724,6 +748,7 @@ var SERVER_CAPABILITY_MATRIX = {
724
748
  };
725
749
 
726
750
  // ../shared/src/index.ts
751
+ var RUNTIME_CONFIG_VERSION = 1;
727
752
  var RUNTIMES = [
728
753
  { id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
729
754
  { id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
@@ -734,6 +759,164 @@ var RUNTIMES = [
734
759
  { id: "gemini", displayName: "Gemini CLI", binary: "gemini", supported: true },
735
760
  { id: "opencode", displayName: "OpenCode", binary: "opencode", supported: true }
736
761
  ];
762
+ var RUNTIME_MODELS = {
763
+ claude: [
764
+ { id: "opus", label: "Opus" },
765
+ { id: "sonnet", label: "Sonnet" },
766
+ { id: "haiku", label: "Haiku" }
767
+ ],
768
+ codex: [
769
+ { id: "gpt-5.5", label: "GPT-5.5" },
770
+ { id: "gpt-5.4", label: "GPT-5.4" },
771
+ { id: "gpt-5.3-codex", label: "GPT-5.3 Codex" },
772
+ { id: "gpt-5.3-codex-spark", label: "GPT-5.3 Codex Spark" },
773
+ { id: "gpt-5.2-codex", label: "GPT-5.2 Codex" },
774
+ { id: "gpt-5.2", label: "GPT-5.2" },
775
+ { id: "gpt-5.1-codex-max", label: "GPT-5.1 Codex Max" },
776
+ { id: "gpt-5.1-codex", label: "GPT-5.1 Codex" },
777
+ { id: "gpt-5-codex", label: "GPT-5 Codex" },
778
+ { id: "gpt-5", label: "GPT-5" }
779
+ ],
780
+ antigravity: [
781
+ { id: "default", label: "AGY configured default", verified: "suggestion_only" }
782
+ ],
783
+ copilot: [
784
+ { id: "gpt-5.4", label: "GPT-5.4" },
785
+ { id: "gpt-5.2", label: "GPT-5.2" },
786
+ { id: "claude-4-sonnet", label: "Claude 4 Sonnet" },
787
+ { id: "claude-4.5-sonnet", label: "Claude 4.5 Sonnet" }
788
+ ],
789
+ cursor: [
790
+ { id: "composer-2-fast", label: "Composer 2 Fast" },
791
+ { id: "composer-2", label: "Composer 2" },
792
+ { id: "auto", label: "Auto" }
793
+ ],
794
+ gemini: [
795
+ { id: "default", label: "Configured Default / Auto", verified: "suggestion_only" },
796
+ { id: "gemini-3.1-pro-preview", label: "Gemini 3.1 Pro (Preview)" },
797
+ { id: "gemini-3-flash-preview", label: "Gemini 3 Flash (Preview)" },
798
+ { id: "gemini-2.5-pro", label: "Gemini 2.5 Pro" },
799
+ { id: "gemini-2.5-flash", label: "Gemini 2.5 Flash" }
800
+ ],
801
+ opencode: [
802
+ { id: "default", label: "Configured Default / Auto", verified: "suggestion_only" },
803
+ { id: "deepseek/deepseek-v4-pro", label: "DeepSeek V4 Pro (OpenCode)", verified: "suggestion_only" },
804
+ { id: "openrouter/anthropic/claude-opus-4.5", label: "Claude Opus 4.5 via OpenRouter", verified: "suggestion_only" },
805
+ { id: "fusecode/opus[1m]", label: "Opus 1M via FuseCode", verified: "suggestion_only" }
806
+ ],
807
+ // Kimi CLI resolves model keys from each user's local config, so the safest
808
+ // built-in option is to defer to whatever default model the CLI already uses.
809
+ kimi: [
810
+ { id: "default", label: "Configured Default" }
811
+ ]
812
+ };
813
+ function getDefaultModel(runtimeId) {
814
+ const models = RUNTIME_MODELS[runtimeId];
815
+ return models?.[0]?.id ?? "sonnet";
816
+ }
817
+ var CONTROLLED_RUNTIME_ENV_KEYS = {
818
+ claude: ["ANTHROPIC_BASE_URL", "ANTHROPIC_API_KEY", "ANTHROPIC_CUSTOM_MODEL_OPTION"]
819
+ };
820
+ function isPlainRecord(value) {
821
+ return value !== null && typeof value === "object" && !Array.isArray(value);
822
+ }
823
+ function normalizeEnvVars(envVars) {
824
+ if (!isPlainRecord(envVars)) return null;
825
+ const normalized = {};
826
+ for (const [key, value] of Object.entries(envVars)) {
827
+ if (typeof key === "string" && typeof value === "string") {
828
+ normalized[key] = value;
829
+ }
830
+ }
831
+ return Object.keys(normalized).length > 0 ? normalized : null;
832
+ }
833
+ function getControlledRuntimeEnvKeys(runtime) {
834
+ return CONTROLLED_RUNTIME_ENV_KEYS[runtime] ?? [];
835
+ }
836
+ function stripControlledRuntimeEnvVars(runtime, envVars) {
837
+ const normalized = normalizeEnvVars(envVars);
838
+ if (!normalized) return null;
839
+ const controlled = new Set(getControlledRuntimeEnvKeys(runtime));
840
+ for (const key of controlled) {
841
+ delete normalized[key];
842
+ }
843
+ return Object.keys(normalized).length > 0 ? normalized : null;
844
+ }
845
+ function isPresetRuntimeModel(runtime, model) {
846
+ return (RUNTIME_MODELS[runtime] ?? []).some((candidate) => candidate.id === model);
847
+ }
848
+ function modelConfigFromLegacy(runtime, model) {
849
+ return isPresetRuntimeModel(runtime, model) ? { kind: "preset", id: model } : { kind: "custom", name: model };
850
+ }
851
+ function parseProviderConfig(runtime, value) {
852
+ if (runtime !== "claude") return void 0;
853
+ if (!isPlainRecord(value)) return { kind: "default" };
854
+ if (value.kind === "custom" && typeof value.apiUrl === "string" && value.apiUrl.trim() && typeof value.apiKey === "string" && value.apiKey.trim()) {
855
+ return { kind: "custom", apiUrl: value.apiUrl.trim(), apiKey: value.apiKey.trim() };
856
+ }
857
+ return { kind: "default" };
858
+ }
859
+ function parseModelConfig(runtime, value, fallback) {
860
+ if (!isPlainRecord(value)) return modelConfigFromLegacy(runtime, fallback);
861
+ if (value.kind === "custom" && typeof value.name === "string" && value.name.trim()) {
862
+ return { kind: "custom", name: value.name.trim() };
863
+ }
864
+ if (value.kind === "preset" && typeof value.id === "string" && value.id.trim()) {
865
+ return { kind: "preset", id: value.id.trim() };
866
+ }
867
+ return modelConfigFromLegacy(runtime, fallback);
868
+ }
869
+ function parseModeConfig(value) {
870
+ if (!isPlainRecord(value)) return { kind: "default" };
871
+ if (value.kind === "fast") return { kind: "fast" };
872
+ return { kind: "default" };
873
+ }
874
+ function hydrateRuntimeConfig(input) {
875
+ const stored = isPlainRecord(input.runtimeConfig) && input.runtimeConfig.version === RUNTIME_CONFIG_VERSION ? input.runtimeConfig : null;
876
+ const runtime = typeof stored?.runtime === "string" && stored.runtime.trim() || typeof input.runtime === "string" && input.runtime.trim() || "claude";
877
+ const fallbackModel = typeof input.model === "string" && input.model.trim() || getDefaultModel(runtime);
878
+ const legacyEnvVars = normalizeEnvVars(input.envVars);
879
+ const storedEnvVars = normalizeEnvVars(stored?.envVars);
880
+ const legacyClaudeApiUrl = runtime === "claude" ? legacyEnvVars?.ANTHROPIC_BASE_URL : void 0;
881
+ const legacyClaudeApiKey = runtime === "claude" ? legacyEnvVars?.ANTHROPIC_API_KEY : void 0;
882
+ const provider = stored ? parseProviderConfig(runtime, stored.provider) : runtime === "claude" && legacyClaudeApiUrl && legacyClaudeApiKey ? { kind: "custom", apiUrl: legacyClaudeApiUrl, apiKey: legacyClaudeApiKey } : runtime === "claude" ? { kind: "default" } : void 0;
883
+ return {
884
+ version: RUNTIME_CONFIG_VERSION,
885
+ runtime,
886
+ ...provider ? { provider } : {},
887
+ model: stored ? parseModelConfig(runtime, stored.model, fallbackModel) : modelConfigFromLegacy(runtime, fallbackModel),
888
+ mode: stored ? parseModeConfig(stored.mode) : { kind: "default" },
889
+ reasoningEffort: stored?.reasoningEffort ?? input.reasoningEffort ?? null,
890
+ envVars: stripControlledRuntimeEnvVars(runtime, stored ? storedEnvVars : legacyEnvVars)
891
+ };
892
+ }
893
+ function runtimeConfigModelValue(config) {
894
+ return config.model.kind === "custom" ? config.model.name : config.model.id;
895
+ }
896
+ function runtimeConfigToLaunchFields(config) {
897
+ const normalized = isPlainRecord(config) && config.version === RUNTIME_CONFIG_VERSION ? hydrateRuntimeConfig({ runtimeConfig: config }) : hydrateRuntimeConfig(config);
898
+ const generatedEnvVars = {};
899
+ if (normalized.runtime === "claude") {
900
+ if (normalized.provider?.kind === "custom") {
901
+ generatedEnvVars.ANTHROPIC_BASE_URL = normalized.provider.apiUrl;
902
+ generatedEnvVars.ANTHROPIC_API_KEY = normalized.provider.apiKey;
903
+ }
904
+ if (normalized.model.kind === "custom") {
905
+ generatedEnvVars.ANTHROPIC_CUSTOM_MODEL_OPTION = normalized.model.name;
906
+ }
907
+ }
908
+ const envVars = {
909
+ ...normalized.envVars ?? {},
910
+ ...generatedEnvVars
911
+ };
912
+ return {
913
+ runtime: normalized.runtime,
914
+ model: runtimeConfigModelValue(normalized),
915
+ mode: normalized.mode,
916
+ reasoningEffort: normalized.reasoningEffort ?? null,
917
+ envVars: Object.keys(envVars).length > 0 ? envVars : null
918
+ };
919
+ }
737
920
  var PLAN_CONFIG = {
738
921
  free: {
739
922
  displayName: "Hobby",
@@ -769,17 +952,14 @@ var DISPLAY_PLAN_CONFIG = {
769
952
  };
770
953
 
771
954
  // src/agentProcessManager.ts
772
- import { mkdirSync as mkdirSync4, readdirSync as readdirSync2, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
955
+ import { mkdirSync as mkdirSync4, readdirSync, statSync, writeFileSync as writeFileSync7 } from "fs";
773
956
  import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2 } from "fs/promises";
774
957
  import { createHash as createHash2 } from "crypto";
775
958
  import path12 from "path";
776
- import os6 from "os";
959
+ import os5 from "os";
777
960
 
778
961
  // src/drivers/claude.ts
779
962
  import { spawn } from "child_process";
780
- import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync2, statSync, writeFileSync as writeFileSync2 } from "fs";
781
- import os2 from "os";
782
- import path4 from "path";
783
963
 
784
964
  // src/drivers/cliTransport.ts
785
965
  import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
@@ -881,13 +1061,14 @@ Use the \`slock\` CLI for chat / task / attachment operations. The daemon inject
881
1061
  19. **\`slock profile update\`** \u2014 Update your own profile. Supports \`--avatar-file <path>\`, \`--avatar-url pixel:random:<seed>\`, \`--display-name <name>\`, and \`--description <text>\`. Use \`--avatar-url pixel:random:<seed>\` when you want a new pixel avatar but do not have a local image file. Values must be non-empty. Provide at least one flag per call; multiple flags can be combined.
882
1062
  20. **\`slock integration list\`** \u2014 List registered third-party services and this agent's active Slock Agent Logins.
883
1063
  21. **\`slock integration login\`** \u2014 Provision or reuse this agent's login for a registered third-party service.
884
- 22. **\`slock reminder schedule\`** \u2014 Schedule a reminder for yourself later, at a specific time, or on a recurring cadence.
885
- 23. **\`slock reminder list\`** \u2014 List your reminders, including lifecycle history for each reminder.
886
- 24. **\`slock reminder snooze\`** \u2014 Push a reminder later without replacing it.
887
- 25. **\`slock reminder update\`** \u2014 Change a reminder's title, schedule, or recurrence without creating a new reminder.
888
- 26. **\`slock reminder cancel\`** \u2014 Cancel one of your reminders by ID.
889
- 27. **\`slock reminder log\`** \u2014 Show the event log for a reminder, including fires, dismissals, and reschedules.
890
- 28. **\`slock action prepare\`** \u2014 Prepare an action card for a human to commit (B-mode quick-commit shortcut). Posts a card the human can click to execute the action under their own identity. Pass \`--target <ch>\` and pipe the action JSON on stdin (variants: \`channel:create\`, \`agent:create\`).
1064
+ 22. **\`slock integration env\`** \u2014 Print per-agent local CLI environment for a manifest-backed service that requires isolated HOME/XDG state.
1065
+ 23. **\`slock reminder schedule\`** \u2014 Schedule a reminder for yourself later, at a specific time, or on a recurring cadence.
1066
+ 24. **\`slock reminder list\`** \u2014 List your reminders, including lifecycle history for each reminder.
1067
+ 25. **\`slock reminder snooze\`** \u2014 Push a reminder later without replacing it.
1068
+ 26. **\`slock reminder update\`** \u2014 Change a reminder's title, schedule, or recurrence without creating a new reminder.
1069
+ 27. **\`slock reminder cancel\`** \u2014 Cancel one of your reminders by ID.
1070
+ 28. **\`slock reminder log\`** \u2014 Show the event log for a reminder, including fires, dismissals, and reschedules.
1071
+ 29. **\`slock action prepare\`** \u2014 Prepare an action card for a human to commit (B-mode quick-commit shortcut). Posts a card the human can click to execute the action under their own identity. Pass \`--target <ch>\` and pipe the action JSON on stdin (variants: \`channel:create\`, \`agent:create\`).
891
1072
 
892
1073
  The CLI prints human-readable canonical text on success (matching the format you see in received messages and history). On failure it prints JSON to stderr:
893
1074
  - failure \u2192 stderr \`{"ok":false,"code":"...","message":"..."}\` with non-zero exit
@@ -993,7 +1174,7 @@ Each channel has a **name** and optionally a **description** that define its pur
993
1174
  - If unsure where something belongs, call ${serverInfoCmd} to review channel descriptions.`;
994
1175
  const thirdPartyIntegrationsSection = isCli ? `### Third-party integrations
995
1176
 
996
- If a registered third-party service requires login, use Slock Agent Login through the CLI instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app, first run \`slock integration list\` and match the app to a registered service before browsing the app. Use \`slock integration login --service <service>\` to provision or reuse your agent login for that service. If the CLI reports that the \`integration\` command is unknown, the local daemon/CLI is too old for Slock Agent Login; report that the machine must be upgraded/restarted instead of calling internal HTTP endpoints yourself. When the command returns \`Agent login ready\` or \`Already logged in\`, the agent-side login is ready. If the output includes an app URL, open that URL as the service-provided third-party app surface; it should look like the service's normal Login with Slock callback and not require you to understand Slock's internal grant/request protocol. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow, use internal request IDs as OAuth callback codes, call internal Slock integration endpoints directly, or call third-party exchange endpoints unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use \`slock profile show\`. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the registered service / Slock Agent Login path.` : `### Third-party integrations
1177
+ If a registered third-party service requires login, use Slock Agent Login through the CLI instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app, first run \`slock integration list\` and match the app to a registered service before browsing the app. Use \`slock integration login --service <service>\` to provision or reuse your agent login for that service. If the service exposes an agent behavior manifest and you need to run its local CLI, run \`slock integration env --service <service>\` before invoking that CLI; if it prints exports, apply them first so service credentials stay under a per-agent profile HOME/XDG tree instead of the host user's global HOME. If it reports that no local env is required, do not invent HOME/XDG overrides. If it fails, do not run that local CLI with the host user's HOME; report that the service manifest is unsupported. Slock does not execute commands from remote manifests automatically. If the CLI reports that the \`integration\` command is unknown, the local daemon/CLI is too old for Slock Agent Login; report that the machine must be upgraded/restarted instead of calling internal HTTP endpoints yourself. When the command returns \`Agent login ready\` or \`Already logged in\`, the agent-side login is ready. If the output includes an app URL, open that URL as the service-provided third-party app surface; it should look like the service's normal Login with Slock callback and not require you to understand Slock's internal grant/request protocol. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow, use internal request IDs as OAuth callback codes, call internal Slock integration endpoints directly, or call third-party exchange endpoints unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use \`slock profile show\`. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the registered service / Slock Agent Login path.` : `### Third-party integrations
997
1178
 
998
1179
  If a registered third-party service requires login, use Slock Agent Login through the available registered-service interface instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app, first inspect the registered-service interface and match the app to a registered service before browsing the app. Once the registered-service interface reports the agent login is ready, the agent-side login is ready. If that interface provides an app URL, use it as the service-provided third-party app surface; it should look like the service's normal Login with Slock callback and not require you to understand Slock's internal grant/request protocol. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow or treat internal request IDs as OAuth callback codes unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use your Slock profile view. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the registered service / Slock Agent Login path.`;
999
1180
  const readingHistorySection = isCli ? `### Reading history
@@ -1368,6 +1549,17 @@ var proxyServerState = null;
1368
1549
  var proxyServerStartPromise = null;
1369
1550
  var proxyServerFactory = createProxyServer;
1370
1551
  var DECODED_RESPONSE_HEADERS = /* @__PURE__ */ new Set(["content-encoding", "content-length", "transfer-encoding"]);
1552
+ var HOP_BY_HOP_REQUEST_HEADERS = /* @__PURE__ */ new Set([
1553
+ "connection",
1554
+ "keep-alive",
1555
+ "proxy-authenticate",
1556
+ "proxy-authorization",
1557
+ "proxy-connection",
1558
+ "te",
1559
+ "trailer",
1560
+ "transfer-encoding",
1561
+ "upgrade"
1562
+ ]);
1371
1563
  var LOCAL_HELD_CONTEXT_LIMIT = 3;
1372
1564
  var AGENT_CREDENTIAL_PROXY_HOST = "127.0.0.1";
1373
1565
  var AGENT_CREDENTIAL_PROXY_BIND_MAX_ATTEMPTS = 3;
@@ -1467,9 +1659,12 @@ async function handleProxyRequest(req, res) {
1467
1659
  target = new URL2(req.url ?? "/", registration.serverUrl);
1468
1660
  const headers = new Headers();
1469
1661
  for (const [name, value] of Object.entries(req.headers)) {
1662
+ const normalizedName = name.toLowerCase();
1470
1663
  if (value === void 0) continue;
1471
- if (name.toLowerCase() === "host") continue;
1472
- if (name.toLowerCase() === "authorization") continue;
1664
+ if (normalizedName === "host") continue;
1665
+ if (normalizedName === "authorization") continue;
1666
+ if (normalizedName === "content-length") continue;
1667
+ if (HOP_BY_HOP_REQUEST_HEADERS.has(normalizedName)) continue;
1473
1668
  if (Array.isArray(value)) {
1474
1669
  for (const item of value) headers.append(name, item);
1475
1670
  } else {
@@ -1480,7 +1675,15 @@ async function handleProxyRequest(req, res) {
1480
1675
  headers.set("X-Agent-Id", registration.agentId);
1481
1676
  headers.set("X-Slock-Client", "cli");
1482
1677
  headers.set("X-Slock-Agent-Active-Capabilities", registration.activeCapabilities);
1483
- let body = method === "GET" || method === "HEAD" ? void 0 : req;
1678
+ let body;
1679
+ let rawBodyBuffer;
1680
+ if (method !== "GET" && method !== "HEAD") {
1681
+ rawBodyBuffer = await readRequestBody(req);
1682
+ const bodyBuffer = new ArrayBuffer(rawBodyBuffer.byteLength);
1683
+ new Uint8Array(bodyBuffer).set(rawBodyBuffer);
1684
+ body = bodyBuffer;
1685
+ headers.set("content-length", String(rawBodyBuffer.byteLength));
1686
+ }
1484
1687
  let sendTarget;
1485
1688
  const sideEffectAction = agentApiSideEffectAction(target.pathname);
1486
1689
  if (method === "GET" && target.pathname === "/internal/agent-api/events") {
@@ -1492,7 +1695,7 @@ async function handleProxyRequest(req, res) {
1492
1695
  }
1493
1696
  }
1494
1697
  if (method === "POST" && sideEffectAction) {
1495
- const rawBody = await readRequestBody(req);
1698
+ const rawBody = rawBodyBuffer?.toString("utf8") ?? "";
1496
1699
  const prepared = await prepareAgentApiSideEffectForward(registration, headers, rawBody, sideEffectAction);
1497
1700
  if (prepared.localResponse) {
1498
1701
  const responseText = JSON.stringify(prepared.localResponse);
@@ -1508,10 +1711,13 @@ async function handleProxyRequest(req, res) {
1508
1711
  const upstream = await daemonFetch(target, {
1509
1712
  method,
1510
1713
  headers,
1511
- body,
1512
- // Required by undici when forwarding a Node stream.
1513
- duplex: body ? "half" : void 0
1714
+ body
1514
1715
  });
1716
+ if (upstream.status >= 500) {
1717
+ registration.inboxCoordinator?.recordTransportNormalizedError?.(
1718
+ transportNormalizedErrorForHttpStatus(target, upstream.status, registration.launchId)
1719
+ );
1720
+ }
1515
1721
  if (shouldBufferJsonResponse(upstream, target.pathname, registration)) {
1516
1722
  const responseText = await upstream.text();
1517
1723
  consumeVisibleResponse(registration, target, sendTarget, responseText);
@@ -1534,9 +1740,12 @@ async function handleProxyRequest(req, res) {
1534
1740
  } catch (err) {
1535
1741
  const failure = proxyFailureForError(method, target, err);
1536
1742
  logger.warn(
1537
- `[Agent Credential Proxy] request failed (agent=${registration.agentId}, launch=${registration.launchId ?? "none"}, method=${failure.method}, path=${failure.pathname}, query_keys=${failure.queryKeys.join(",") || "none"}): ${failure.errorName}: ${failure.errorMessage}`
1743
+ `[Agent Credential Proxy] request failed (agent=${registration.agentId}, launch=${registration.launchId ?? "none"}, method=${failure.method}, path=${failure.pathname}, query_keys=${failure.queryKeys.join(",") || "none"}): ${failure.errorName}: ${failure.errorMessage}${failure.errorCause ? ` (cause=${failure.errorCause})` : ""}`
1538
1744
  );
1539
1745
  registration.inboxCoordinator?.recordProxyFailure?.(failure);
1746
+ registration.inboxCoordinator?.recordTransportNormalizedError?.(
1747
+ transportNormalizedErrorForError(target, err, registration.launchId)
1748
+ );
1540
1749
  writeProxyFailureResponse(res, failure);
1541
1750
  }
1542
1751
  }
@@ -1555,25 +1764,125 @@ function writeProxyFailureResponse(res, failure) {
1555
1764
  }
1556
1765
  function proxyFailureForError(method, target, err) {
1557
1766
  const queryKeys = target ? [.../* @__PURE__ */ new Set([...target.searchParams.keys()])].sort() : [];
1558
- return {
1767
+ const cause = err instanceof Error ? err.cause : void 0;
1768
+ const failure = {
1559
1769
  method,
1560
1770
  pathname: target?.pathname ?? "unknown",
1561
1771
  queryKeys,
1562
1772
  errorName: err instanceof Error ? err.name : typeof err,
1563
1773
  errorMessage: truncateProxyErrorMessage(err instanceof Error ? err.message : String(err))
1564
1774
  };
1775
+ const errorCause = describeProxyErrorCause(cause);
1776
+ if (errorCause) failure.errorCause = errorCause;
1777
+ return failure;
1778
+ }
1779
+ function describeProxyErrorCause(cause) {
1780
+ if (!cause) return void 0;
1781
+ if (cause instanceof Error) {
1782
+ const errorWithCode = cause;
1783
+ const code = typeof errorWithCode.code === "string" ? errorWithCode.code : void 0;
1784
+ return truncateProxyErrorMessage([code, cause.message].filter(Boolean).join(" "));
1785
+ }
1786
+ if (typeof cause === "object") {
1787
+ const causeObject = cause;
1788
+ const code = typeof causeObject.code === "string" ? causeObject.code : void 0;
1789
+ const message = typeof causeObject.message === "string" ? causeObject.message : void 0;
1790
+ const detail = [code, message].filter(Boolean).join(" ");
1791
+ if (detail) return truncateProxyErrorMessage(detail);
1792
+ }
1793
+ return truncateProxyErrorMessage(String(cause));
1565
1794
  }
1566
1795
  function truncateProxyErrorMessage(message) {
1567
1796
  const normalized = message.replace(/\s+/g, " ").trim();
1568
1797
  return normalized.length > 500 ? `${normalized.slice(0, 497)}...` : normalized;
1569
1798
  }
1799
+ function transportNormalizedErrorForHttpStatus(target, status, launchId) {
1800
+ return {
1801
+ normalizedCode: "server_5xx",
1802
+ routeFamily: routeFamilyForPath(target.pathname),
1803
+ responseStarted: true,
1804
+ upstreamLayer: "http_status",
1805
+ upstreamStatus: status,
1806
+ launchId,
1807
+ targetHostClass: daemonUpstreamTargetHostClass(target),
1808
+ // Today the local credential proxy is only used by CLI wrappers. If runtime
1809
+ // or daemon-internal callers use it later, plumb the caller identity here.
1810
+ downstreamCaller: "cli",
1811
+ upstream: "server"
1812
+ };
1813
+ }
1814
+ function transportNormalizedErrorForError(target, err, launchId) {
1815
+ return {
1816
+ normalizedCode: "transport_failure",
1817
+ routeFamily: routeFamilyForPath(target?.pathname ?? "unknown"),
1818
+ responseStarted: false,
1819
+ upstreamLayer: target ? upstreamLayerForProxyError(err) : "unknown",
1820
+ originalMessage: sanitizeTransportOriginalMessage(err instanceof Error ? err.message : String(err)),
1821
+ launchId,
1822
+ targetHostClass: target ? daemonUpstreamTargetHostClass(target) : "custom_server",
1823
+ // Today the local credential proxy is only used by CLI wrappers. If runtime
1824
+ // or daemon-internal callers use it later, plumb the caller identity here.
1825
+ downstreamCaller: "cli",
1826
+ upstream: "server"
1827
+ };
1828
+ }
1829
+ function routeFamilyForPath(pathname) {
1830
+ if (pathname === "/internal/agent-api/send") return "agent-api/send";
1831
+ if (pathname === "/internal/agent-api/events") return "agent-api/events";
1832
+ if (pathname === "/internal/agent-api/receive-ack") return "agent-api/events";
1833
+ if (pathname === "/internal/agent-api/tasks/claim") return "tasks/claim";
1834
+ if (pathname === "/internal/agent-api/tasks/update-status") return "tasks/update";
1835
+ if (pathname === "/internal/agent-api/tasks" || pathname.startsWith("/internal/agent-api/tasks/")) return "tasks";
1836
+ if (pathname.startsWith("/internal/agent-api/attachments/")) return "agent-api/attachments";
1837
+ if (/^\/internal\/agent-api\/messages\/[^/]+\/reactions$/.test(pathname)) return "agent-api/messages/reactions";
1838
+ if (pathname === "/internal/agent-api/server") return "server";
1839
+ if (pathname.startsWith("/internal/agent-api/history")) return "agent-api/events";
1840
+ if (pathname.startsWith("/internal/agent-api/search")) return "agent-api/events";
1841
+ if (pathname.startsWith("/internal/agent-api/channel-members")) return "channel-members";
1842
+ if (pathname.startsWith("/internal/agent-api/knowledge")) return "knowledge";
1843
+ if (pathname === "/internal/agent-api/profile" || pathname.startsWith("/internal/agent-api/profile/")) return "profile";
1844
+ if (pathname === "/internal/agent-api/integrations" || pathname.startsWith("/internal/agent-api/integrations/")) return "integrations";
1845
+ if (pathname === "/internal/agent-api/upload") return "attachments/upload";
1846
+ if (pathname === "/internal/agent-api/resolve-channel") return "resolve-channel";
1847
+ if (pathname === "/internal/agent-api/threads/unfollow") return "threads/unfollow";
1848
+ if (pathname === "/internal/agent-api/prepare-action") return "action/prepare";
1849
+ if (pathname === "/internal/agent-api/reminders" || pathname.startsWith("/internal/agent-api/reminders/")) return "reminders";
1850
+ if (/^\/internal\/agent-api\/channels\/[^/]+\/join$/.test(pathname)) return "channels/join";
1851
+ if (/^\/internal\/agent-api\/channels\/[^/]+\/leave$/.test(pathname)) return "channels/leave";
1852
+ return "unknown";
1853
+ }
1854
+ function daemonUpstreamTargetHostClass(url) {
1855
+ const hostname = url.hostname.toLowerCase();
1856
+ if (hostname === "api.slock.ai") return "api.slock.ai";
1857
+ return "custom_server";
1858
+ }
1859
+ function upstreamLayerForProxyError(err) {
1860
+ const code = errorCode(err).toUpperCase();
1861
+ const message = (err instanceof Error ? err.message : String(err)).toLowerCase();
1862
+ if (code === "ENOTFOUND" || code === "EAI_AGAIN" || message.includes("dns")) return "dns";
1863
+ if (code === "ECONNREFUSED" || code === "ECONNRESET" || code === "EPIPE" || code === "UND_ERR_SOCKET" || message.includes("socket")) return "tcp";
1864
+ if (code.includes("TLS") || message.includes("certificate") || message.includes("tls")) return "tls";
1865
+ if (code === "UND_ERR_HEADERS_TIMEOUT" || code === "UND_ERR_BODY_TIMEOUT" || message.includes("timeout")) return "read_timeout";
1866
+ if (message.includes("proxy")) return "proxy_connect";
1867
+ if (message.includes("fly")) return "fly_edge";
1868
+ return "unknown";
1869
+ }
1870
+ function errorCode(err) {
1871
+ if (typeof err === "object" && err && "code" in err && typeof err.code === "string") {
1872
+ return err.code;
1873
+ }
1874
+ if (typeof err === "object" && err && "cause" in err) return errorCode(err.cause);
1875
+ return "";
1876
+ }
1877
+ function sanitizeTransportOriginalMessage(message) {
1878
+ return truncateProxyErrorMessage(message).replace(/sk_(?:agent|machine|computer)_[A-Za-z0-9_-]+/g, "sk_[redacted]").replace(/sap_[A-Za-z0-9_-]+/g, "sap_[redacted]").replace(/https?:\/\/\S+/g, "[url]");
1879
+ }
1570
1880
  async function readRequestBody(req) {
1571
- let body = "";
1572
- req.setEncoding("utf8");
1881
+ const chunks = [];
1573
1882
  for await (const chunk of req) {
1574
- body += String(chunk);
1883
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1575
1884
  }
1576
- return body;
1885
+ return Buffer.concat(chunks);
1577
1886
  }
1578
1887
  function messageSeq(message) {
1579
1888
  return Number(message.seq ?? 0);
@@ -1748,7 +2057,7 @@ async function loadRecentTargetMessages(registration, headers, target) {
1748
2057
  const historyHeaders = new Headers(headers);
1749
2058
  historyHeaders.delete("content-length");
1750
2059
  historyHeaders.delete("content-type");
1751
- const res = await daemonFetch(historyUrl, { method: "GET", headers: historyHeaders });
2060
+ const res = await fetch(historyUrl, { method: "GET", headers: historyHeaders });
1752
2061
  if (!res.ok) return [];
1753
2062
  const parsed = await res.json().catch(() => null);
1754
2063
  return Array.isArray(parsed?.messages) ? normalizeVisibleMessages(parsed.messages, target) : [];
@@ -1949,8 +2258,9 @@ function unregisterAgentCredentialProxyForLaunch(input) {
1949
2258
  // src/drivers/cliTransport.ts
1950
2259
  var shellSingleQuote = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
1951
2260
  var powershellSingleQuote = (value) => `'${value.replace(/'/g, "''")}'`;
1952
- var DEFAULT_ACTIVE_CAPABILITIES = "send,read,mentions,tasks,reactions,server,channels";
2261
+ var DEFAULT_ACTIVE_CAPABILITIES = "send,read,mentions,tasks,reactions,server,channels,knowledge";
1953
2262
  var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
2263
+ var CLI_TRANSPORT_TRACE_DIR_ENV = "SLOCK_CLI_TRANSPORT_TRACE_DIR";
1954
2264
  var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
1955
2265
  var RAW_CREDENTIAL_ENV_DENYLIST = [
1956
2266
  "SLOCK_AGENT_CREDENTIAL_KEY"
@@ -2152,16 +2462,18 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
2152
2462
  }
2153
2463
  }
2154
2464
  const wrapperPath = platform === "win32" ? path2.join(slockDir, "slock.cmd") : posixWrapper;
2465
+ const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
2155
2466
  const spawnEnv = {
2156
2467
  ...process.env,
2157
2468
  FORCE_COLOR: "0",
2158
- ...ctx.config.envVars || {},
2469
+ ...launchRuntimeFields.envVars || {},
2159
2470
  ...extraEnv,
2160
2471
  ...platform === "win32" ? windowsUtf8Env() : {},
2161
2472
  ...runtimeContextEnv(ctx.config),
2162
2473
  [SLOCK_HOME_ENV]: slockHome,
2163
2474
  SLOCK_AGENT_ID: ctx.agentId,
2164
2475
  ...ctx.launchId ? { SLOCK_AGENT_LAUNCH_ID: ctx.launchId } : {},
2476
+ ...ctx.cliTransportTraceDir ? { [CLI_TRANSPORT_TRACE_DIR_ENV]: ctx.cliTransportTraceDir } : {},
2165
2477
  SLOCK_SERVER_URL: ctx.config.serverUrl,
2166
2478
  ...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
2167
2479
  PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
@@ -2186,6 +2498,129 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
2186
2498
  };
2187
2499
  }
2188
2500
 
2501
+ // src/drivers/claudeEventNormalizer.ts
2502
+ function collectResultErrorDetail(message, fallback) {
2503
+ const parts = [];
2504
+ if (Array.isArray(message.errors)) {
2505
+ for (const err of message.errors) {
2506
+ if (typeof err === "string" && err.trim()) parts.push(err.trim());
2507
+ }
2508
+ }
2509
+ if (typeof message.result === "string" && message.result.trim()) {
2510
+ parts.push(message.result.trim());
2511
+ }
2512
+ return parts.join(" | ") || fallback;
2513
+ }
2514
+ function isProviderApiFailureText(value, hasToolUse) {
2515
+ return !hasToolUse && /^\s*API Error:/i.test(value) && (/\b(?:ECONNRESET|EPIPE|ETIMEDOUT|ECONNREFUSED|ENOTFOUND|EAI_AGAIN)\b/i.test(value) || /\bUnable to connect to API\b/i.test(value) || /\b(?:timed out|timeout)\b/i.test(value) || /\b5\d{2}\b/.test(value));
2516
+ }
2517
+ var ClaudeEventNormalizer = class {
2518
+ normalizeLine(line) {
2519
+ let event;
2520
+ try {
2521
+ event = JSON.parse(line);
2522
+ } catch {
2523
+ return [];
2524
+ }
2525
+ const events = [];
2526
+ const pushResultError = (message, fallback) => {
2527
+ events.push({ kind: "error", message: collectResultErrorDetail(message, fallback) });
2528
+ };
2529
+ switch (event.type) {
2530
+ case "system":
2531
+ if (event.subtype === "init" && event.session_id) {
2532
+ events.push({ kind: "session_init", sessionId: event.session_id });
2533
+ }
2534
+ if (event.subtype === "status" && event.status === "compacting") {
2535
+ events.push({ kind: "compaction_started" });
2536
+ }
2537
+ if (event.subtype === "status" && event.status === "requesting") {
2538
+ events.push({
2539
+ kind: "internal_progress",
2540
+ source: "claude_system_status",
2541
+ itemType: "requesting",
2542
+ payloadBytes: Buffer.byteLength(line, "utf8")
2543
+ });
2544
+ }
2545
+ if (event.subtype === "compact_boundary") {
2546
+ events.push({ kind: "compaction_finished" });
2547
+ }
2548
+ break;
2549
+ case "stream_event":
2550
+ events.push({
2551
+ kind: "internal_progress",
2552
+ source: "claude_stream_event",
2553
+ itemType: typeof event.event?.type === "string" && event.event.type.length > 0 ? event.event.type : "unknown",
2554
+ payloadBytes: Buffer.byteLength(line, "utf8")
2555
+ });
2556
+ break;
2557
+ case "assistant": {
2558
+ const content = event.message?.content;
2559
+ if (Array.isArray(content)) {
2560
+ const hasToolUse = content.some((block) => block?.type === "tool_use");
2561
+ for (const block of content) {
2562
+ if (block.type === "thinking" && block.thinking) {
2563
+ events.push({ kind: "thinking", text: block.thinking });
2564
+ } else if (block.type === "text" && block.text) {
2565
+ if (isProviderApiFailureText(block.text, hasToolUse)) {
2566
+ events.push({ kind: "error", message: block.text });
2567
+ } else {
2568
+ events.push({ kind: "text", text: block.text });
2569
+ }
2570
+ } else if (block.type === "tool_use") {
2571
+ events.push({ kind: "tool_call", name: block.name || "unknown_tool", input: block.input });
2572
+ }
2573
+ }
2574
+ }
2575
+ break;
2576
+ }
2577
+ case "user": {
2578
+ const content = event.message?.content;
2579
+ if (Array.isArray(content)) {
2580
+ for (const block of content) {
2581
+ if (block.type === "tool_result") {
2582
+ events.push({ kind: "tool_output", name: block.name || block.tool_use_id || "tool_result" });
2583
+ }
2584
+ }
2585
+ }
2586
+ break;
2587
+ }
2588
+ case "result": {
2589
+ const subtype = typeof event.subtype === "string" ? event.subtype : "success";
2590
+ const stopReason = typeof event.stop_reason === "string" ? event.stop_reason : null;
2591
+ switch (subtype) {
2592
+ case "success":
2593
+ if (event.is_error && stopReason !== "max_tokens") {
2594
+ pushResultError(event, "Execution failed");
2595
+ }
2596
+ break;
2597
+ case "error_during_execution":
2598
+ if (stopReason !== "max_tokens") {
2599
+ pushResultError(event, "Execution failed");
2600
+ }
2601
+ break;
2602
+ case "error_max_budget_usd":
2603
+ pushResultError(event, "Budget limit exceeded");
2604
+ break;
2605
+ case "error_max_turns":
2606
+ pushResultError(event, "Max turns exceeded");
2607
+ break;
2608
+ case "error_max_structured_output_retries":
2609
+ pushResultError(event, "Structured output retries exceeded");
2610
+ break;
2611
+ }
2612
+ events.push({ kind: "turn_end", sessionId: event.session_id });
2613
+ break;
2614
+ }
2615
+ }
2616
+ return events;
2617
+ }
2618
+ };
2619
+
2620
+ // src/drivers/claudeLaunch.ts
2621
+ import { writeFileSync as writeFileSync2 } from "fs";
2622
+ import path4 from "path";
2623
+
2189
2624
  // src/drivers/probe.ts
2190
2625
  import { execFileSync } from "child_process";
2191
2626
  import { existsSync as existsSync2 } from "fs";
@@ -2386,12 +2821,10 @@ function resolveHomePath(relativePath, deps = {}) {
2386
2821
  return path3.join(homeDir, relativePath);
2387
2822
  }
2388
2823
 
2389
- // src/drivers/claude.ts
2824
+ // src/drivers/claudeLaunch.ts
2390
2825
  var CLAUDE_DESKTOP_CLI_RELATIVE_PATH = path4.join("Applications", "Claude Code URL Handler.app", "Contents", "MacOS", "claude");
2391
2826
  var CLAUDE_DESKTOP_CLI_SYSTEM_PATH = "/Applications/Claude Code URL Handler.app/Contents/MacOS/claude";
2392
2827
  var CLAUDE_SYSTEM_PROMPT_FILE = "claude-system-prompt.md";
2393
- var CLAUDE_MCP_CONFIG_FILE = "claude-mcp-config.json";
2394
- var SLOCK_RUNTIME_ACTIONS_MCP_SERVER_NAME = "chat";
2395
2828
  var CLAUDE_DISALLOWED_TOOLS = [
2396
2829
  "EnterPlanMode",
2397
2830
  "ExitPlanMode",
@@ -2417,81 +2850,54 @@ function probeClaude(deps = {}) {
2417
2850
  version: readCommandVersion(command, [], deps) ?? void 0
2418
2851
  };
2419
2852
  }
2420
- function isRecord(value) {
2421
- return value !== null && typeof value === "object" && !Array.isArray(value);
2422
- }
2423
- function expandClaudeMcpConfigVariables(raw, vars) {
2424
- let expanded = raw;
2425
- for (const [name, value] of Object.entries(vars)) {
2426
- const escapedValue = process.platform === "win32" ? value.replace(/\\/g, "\\\\") : value;
2427
- expanded = expanded.replaceAll(`\${${name}}`, escapedValue);
2853
+ function buildClaudeArgs(config, opts) {
2854
+ const launchRuntimeFields = runtimeConfigToLaunchFields(config);
2855
+ const args = [
2856
+ "--allow-dangerously-skip-permissions",
2857
+ "--dangerously-skip-permissions",
2858
+ "--verbose",
2859
+ "--permission-mode",
2860
+ "bypassPermissions",
2861
+ "--output-format",
2862
+ "stream-json",
2863
+ "--input-format",
2864
+ "stream-json",
2865
+ "--include-partial-messages",
2866
+ "--model",
2867
+ launchRuntimeFields.model || "sonnet",
2868
+ "--disallowed-tools",
2869
+ CLAUDE_DISALLOWED_TOOLS,
2870
+ "--append-system-prompt-file",
2871
+ opts.standingPromptFilePath
2872
+ ];
2873
+ if (launchRuntimeFields.reasoningEffort) {
2874
+ args.push("--effort", launchRuntimeFields.reasoningEffort);
2428
2875
  }
2429
- return expanded;
2430
- }
2431
- function readClaudeMcpServers(configPath, vars = {}) {
2432
- try {
2433
- const parsed = JSON.parse(
2434
- expandClaudeMcpConfigVariables(readFileSync2(configPath, "utf8"), vars)
2435
- );
2436
- if (!isRecord(parsed) || !isRecord(parsed.mcpServers)) return null;
2437
- return parsed.mcpServers;
2438
- } catch (err) {
2439
- logger.warn(
2440
- `[Claude] failed to read MCP config ${configPath}: ${err instanceof Error ? err.message : String(err)}`
2441
- );
2442
- return null;
2876
+ if (launchRuntimeFields.mode.kind === "fast") {
2877
+ args.push("--bare");
2443
2878
  }
2879
+ if (config.sessionId) {
2880
+ args.push("--resume", config.sessionId);
2881
+ }
2882
+ return args;
2444
2883
  }
2445
- function resolveClaudeConfigDir(ctx, home) {
2446
- const configured = ctx.config.envVars?.CLAUDE_CONFIG_DIR || process.env.CLAUDE_CONFIG_DIR;
2447
- return configured && path4.isAbsolute(configured) ? configured : path4.join(home, ".claude");
2884
+ function writeClaudeSystemPromptFile(standingPrompt, slockDir) {
2885
+ const systemPromptPath = path4.join(slockDir, CLAUDE_SYSTEM_PROMPT_FILE);
2886
+ writeFileSync2(systemPromptPath, standingPrompt, { mode: 384 });
2887
+ return systemPromptPath;
2448
2888
  }
2449
- function collectClaudeMcpConfigFiles(ctx, home) {
2450
- const files = [];
2451
- const pushIfFile = (candidate) => {
2452
- try {
2453
- if (existsSync3(candidate) && statSync(candidate).isFile()) {
2454
- files.push({ path: candidate });
2455
- }
2456
- } catch {
2457
- }
2889
+ function buildClaudeSpawnSpec(claudeCommand, platform = process.platform) {
2890
+ const lowerClaudeCommand = claudeCommand?.toLowerCase();
2891
+ const isBatchFile = Boolean(
2892
+ platform === "win32" && lowerClaudeCommand && (lowerClaudeCommand.endsWith(".cmd") || lowerClaudeCommand.endsWith(".bat"))
2893
+ );
2894
+ return {
2895
+ command: claudeCommand ?? "claude",
2896
+ shell: platform === "win32" && (!claudeCommand || isBatchFile)
2458
2897
  };
2459
- pushIfFile(path4.join(home, ".claude.json"));
2460
- pushIfFile(path4.join(ctx.workingDirectory, ".mcp.json"));
2461
- const pluginRoot = path4.join(resolveClaudeConfigDir(ctx, home), "plugins");
2462
- try {
2463
- for (const entry of readdirSync(pluginRoot)) {
2464
- const pluginPath = path4.join(pluginRoot, entry);
2465
- const configPath = path4.join(pluginPath, ".mcp.json");
2466
- try {
2467
- if (existsSync3(configPath) && statSync(configPath).isFile()) {
2468
- files.push({
2469
- path: configPath,
2470
- vars: { CLAUDE_PLUGIN_ROOT: pluginPath }
2471
- });
2472
- }
2473
- } catch {
2474
- }
2475
- }
2476
- } catch {
2477
- }
2478
- return files;
2479
- }
2480
- function buildClaudeUserMcpServers(ctx, home) {
2481
- const servers = /* @__PURE__ */ Object.create(null);
2482
- for (const configFile of collectClaudeMcpConfigFiles(ctx, home)) {
2483
- const mcpServers = readClaudeMcpServers(configFile.path, configFile.vars);
2484
- if (!mcpServers) continue;
2485
- for (const [name, server] of Object.entries(mcpServers)) {
2486
- if (!isRecord(server)) {
2487
- logger.warn(`[Claude] ignoring invalid MCP server "${name}" in ${configFile.path}`);
2488
- continue;
2489
- }
2490
- servers[name] = server;
2491
- }
2492
- }
2493
- return servers;
2494
2898
  }
2899
+
2900
+ // src/drivers/claude.ts
2495
2901
  var ClaudeDriver = class {
2496
2902
  id = "claude";
2497
2903
  lifecycle = {
@@ -2501,7 +2907,7 @@ var ClaudeDriver = class {
2501
2907
  };
2502
2908
  communication = {
2503
2909
  chat: "slock_cli",
2504
- runtimeControl: "mcp_runtime_actions"
2910
+ runtimeControl: "none"
2505
2911
  };
2506
2912
  session = {
2507
2913
  recovery: "resume_or_fresh"
@@ -2511,107 +2917,37 @@ var ClaudeDriver = class {
2511
2917
  toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
2512
2918
  };
2513
2919
  supportsStdinNotification = true;
2514
- mcpToolPrefix = "mcp__chat__";
2920
+ mcpToolPrefix = "";
2515
2921
  usesSlockCliForCommunication = true;
2516
2922
  // Claude Code supports same-turn steering, but raw stdin injection at an
2517
2923
  // arbitrary busy instant can collide with active signed thinking blocks. The
2518
2924
  // daemon therefore gates busy delivery on Claude stream-json boundaries.
2519
2925
  busyDeliveryMode = "gated";
2520
2926
  supportsNativeStandingPrompt = true;
2927
+ eventNormalizer = new ClaudeEventNormalizer();
2521
2928
  probe() {
2522
2929
  return probeClaude();
2523
2930
  }
2524
- buildClaudeArgs(config, standingPrompt, opts = {}) {
2525
- const args = [
2526
- "--allow-dangerously-skip-permissions",
2527
- "--dangerously-skip-permissions",
2528
- "--verbose",
2529
- "--permission-mode",
2530
- "bypassPermissions",
2531
- "--output-format",
2532
- "stream-json",
2533
- "--input-format",
2534
- "stream-json",
2535
- "--model",
2536
- config.model || "sonnet",
2537
- "--disallowed-tools",
2538
- CLAUDE_DISALLOWED_TOOLS
2539
- ];
2540
- if (opts.standingPromptFilePath) {
2541
- args.push("--append-system-prompt-file", opts.standingPromptFilePath);
2542
- } else {
2543
- args.push("--append-system-prompt", standingPrompt);
2544
- }
2545
- if (config.sessionId) {
2546
- args.push("--resume", config.sessionId);
2547
- }
2548
- return args;
2549
- }
2550
- buildRuntimeActionsMcpServer(ctx) {
2551
- const isTsSource = ctx.chatBridgePath.endsWith(".ts");
2552
- const command = isTsSource ? "npx" : "node";
2553
- const bridgeArgs = isTsSource ? ["tsx", ctx.chatBridgePath] : [ctx.chatBridgePath];
2554
- return {
2555
- command,
2556
- args: [
2557
- ...bridgeArgs,
2558
- "--agent-id",
2559
- ctx.agentId,
2560
- "--server-url",
2561
- ctx.config.serverUrl,
2562
- "--auth-token",
2563
- ctx.config.authToken || ctx.daemonApiKey,
2564
- "--runtime",
2565
- this.id,
2566
- ...ctx.launchId ? ["--launch-id", ctx.launchId] : [],
2567
- "--runtime-actions-only"
2568
- ]
2569
- };
2570
- }
2571
- buildRuntimeActionsMcpConfig(ctx, home = os2.homedir()) {
2572
- const userMcpServers = buildClaudeUserMcpServers(ctx, home);
2573
- if (Object.prototype.hasOwnProperty.call(userMcpServers, SLOCK_RUNTIME_ACTIONS_MCP_SERVER_NAME)) {
2574
- logger.warn(
2575
- `[Agent ${ctx.agentId}] Claude user MCP server "${SLOCK_RUNTIME_ACTIONS_MCP_SERVER_NAME}" is reserved by Slock runtime actions and will be ignored`
2576
- );
2577
- }
2578
- return JSON.stringify({
2579
- mcpServers: {
2580
- ...userMcpServers,
2581
- [SLOCK_RUNTIME_ACTIONS_MCP_SERVER_NAME]: this.buildRuntimeActionsMcpServer(ctx)
2582
- }
2583
- });
2584
- }
2585
- writeClaudeLaunchFiles(ctx, slockDir, home = os2.homedir()) {
2586
- const systemPromptPath = path4.join(slockDir, CLAUDE_SYSTEM_PROMPT_FILE);
2587
- const mcpConfigPath = path4.join(slockDir, CLAUDE_MCP_CONFIG_FILE);
2588
- writeFileSync2(systemPromptPath, ctx.standingPrompt, { mode: 384 });
2589
- writeFileSync2(mcpConfigPath, this.buildRuntimeActionsMcpConfig(ctx, home), { mode: 384 });
2590
- return { systemPromptPath, mcpConfigPath };
2931
+ buildClaudeArgs(config, opts) {
2932
+ return buildClaudeArgs(config, opts);
2591
2933
  }
2592
2934
  async spawn(ctx) {
2593
2935
  const { slockDir, tokenFile, spawnEnv } = await prepareCliTransport(ctx);
2594
- const { systemPromptPath, mcpConfigPath } = this.writeClaudeLaunchFiles(ctx, slockDir);
2595
- const args = this.buildClaudeArgs(ctx.config, ctx.standingPrompt, {
2936
+ const systemPromptPath = writeClaudeSystemPromptFile(ctx.standingPrompt, slockDir);
2937
+ const args = this.buildClaudeArgs(ctx.config, {
2596
2938
  standingPromptFilePath: systemPromptPath
2597
2939
  });
2598
- args.push("--mcp-config", mcpConfigPath, "--strict-mcp-config");
2599
2940
  delete spawnEnv.CLAUDECODE;
2600
2941
  logger.info(
2601
2942
  `[Agent ${ctx.agentId}] transport=cli cli=${ctx.slockCliPath} token_file=${tokenFile}`
2602
2943
  );
2603
2944
  const claudeCommand = resolveClaudeCommand();
2604
- const isWindows = process.platform === "win32";
2605
- const lowerClaudeCommand = claudeCommand?.toLowerCase();
2606
- const isBatchFile = Boolean(
2607
- isWindows && lowerClaudeCommand && (lowerClaudeCommand.endsWith(".cmd") || lowerClaudeCommand.endsWith(".bat"))
2608
- );
2609
- const useShell = isWindows && (!claudeCommand || isBatchFile);
2610
- const proc = spawn(claudeCommand ?? "claude", args, {
2945
+ const spawnSpec = buildClaudeSpawnSpec(claudeCommand);
2946
+ const proc = spawn(spawnSpec.command, args, {
2611
2947
  cwd: ctx.workingDirectory,
2612
2948
  stdio: ["pipe", "pipe", "pipe"],
2613
2949
  env: spawnEnv,
2614
- shell: useShell
2950
+ shell: spawnSpec.shell
2615
2951
  });
2616
2952
  const stdinMsg = JSON.stringify({
2617
2953
  type: "user",
@@ -2625,99 +2961,7 @@ var ClaudeDriver = class {
2625
2961
  return { process: proc };
2626
2962
  }
2627
2963
  parseLine(line) {
2628
- let event;
2629
- try {
2630
- event = JSON.parse(line);
2631
- } catch {
2632
- return [];
2633
- }
2634
- const events = [];
2635
- const pushResultError = (message, fallback) => {
2636
- const parts = [];
2637
- if (Array.isArray(message.errors)) {
2638
- for (const err of message.errors) {
2639
- if (typeof err === "string" && err.trim()) parts.push(err.trim());
2640
- }
2641
- }
2642
- if (typeof message.result === "string" && message.result.trim()) {
2643
- parts.push(message.result.trim());
2644
- }
2645
- const detail = parts.join(" | ") || fallback;
2646
- events.push({ kind: "error", message: detail });
2647
- };
2648
- const isProviderApiFailureText = (value, hasToolUse) => !hasToolUse && /^\s*API Error:/i.test(value) && (/\b(?:ECONNRESET|EPIPE|ETIMEDOUT|ECONNREFUSED|ENOTFOUND|EAI_AGAIN)\b/i.test(value) || /\bUnable to connect to API\b/i.test(value) || /\b(?:timed out|timeout)\b/i.test(value) || /\b5\d{2}\b/.test(value));
2649
- switch (event.type) {
2650
- case "system":
2651
- if (event.subtype === "init" && event.session_id) {
2652
- events.push({ kind: "session_init", sessionId: event.session_id });
2653
- }
2654
- if (event.subtype === "status" && event.status === "compacting") {
2655
- events.push({ kind: "compaction_started" });
2656
- }
2657
- if (event.subtype === "compact_boundary") {
2658
- events.push({ kind: "compaction_finished" });
2659
- }
2660
- break;
2661
- case "assistant": {
2662
- const content = event.message?.content;
2663
- if (Array.isArray(content)) {
2664
- const hasToolUse = content.some((block) => block?.type === "tool_use");
2665
- for (const block of content) {
2666
- if (block.type === "thinking" && block.thinking) {
2667
- events.push({ kind: "thinking", text: block.thinking });
2668
- } else if (block.type === "text" && block.text) {
2669
- if (isProviderApiFailureText(block.text, hasToolUse)) {
2670
- events.push({ kind: "error", message: block.text });
2671
- } else {
2672
- events.push({ kind: "text", text: block.text });
2673
- }
2674
- } else if (block.type === "tool_use") {
2675
- events.push({ kind: "tool_call", name: block.name || "unknown_tool", input: block.input });
2676
- }
2677
- }
2678
- }
2679
- break;
2680
- }
2681
- case "user": {
2682
- const content = event.message?.content;
2683
- if (Array.isArray(content)) {
2684
- for (const block of content) {
2685
- if (block.type === "tool_result") {
2686
- events.push({ kind: "tool_output", name: block.name || block.tool_use_id || "tool_result" });
2687
- }
2688
- }
2689
- }
2690
- break;
2691
- }
2692
- case "result": {
2693
- const subtype = typeof event.subtype === "string" ? event.subtype : "success";
2694
- const stopReason = typeof event.stop_reason === "string" ? event.stop_reason : null;
2695
- switch (subtype) {
2696
- case "success":
2697
- if (event.is_error && stopReason !== "max_tokens") {
2698
- pushResultError(event, "Execution failed");
2699
- }
2700
- break;
2701
- case "error_during_execution":
2702
- if (stopReason !== "max_tokens") {
2703
- pushResultError(event, "Execution failed");
2704
- }
2705
- break;
2706
- case "error_max_budget_usd":
2707
- pushResultError(event, "Budget limit exceeded");
2708
- break;
2709
- case "error_max_turns":
2710
- pushResultError(event, "Max turns exceeded");
2711
- break;
2712
- case "error_max_structured_output_retries":
2713
- pushResultError(event, "Structured output retries exceeded");
2714
- break;
2715
- }
2716
- events.push({ kind: "turn_end", sessionId: event.session_id });
2717
- break;
2718
- }
2719
- }
2720
- return events;
2964
+ return this.eventNormalizer.normalizeLine(line);
2721
2965
  }
2722
2966
  encodeStdinMessage(text, sessionId, _opts) {
2723
2967
  return JSON.stringify({
@@ -2731,7 +2975,7 @@ var ClaudeDriver = class {
2731
2975
  }
2732
2976
  buildSystemPrompt(config, _agentId) {
2733
2977
  return buildCliTransportSystemPrompt(config, {
2734
- toolPrefix: "mcp__chat__",
2978
+ toolPrefix: "",
2735
2979
  extraCriticalRules: [],
2736
2980
  postStartupNotes: [
2737
2981
  "**Claude runtime note:** While you are busy, Slock batches inbox-count notifications instead of injecting message content. Use `slock message check` at natural breakpoints to pull the pending messages before side-effect actions that depend on current context."
@@ -2744,8 +2988,8 @@ var ClaudeDriver = class {
2744
2988
 
2745
2989
  // src/drivers/codex.ts
2746
2990
  import { spawn as spawn2, execFileSync as execFileSync2, execSync } from "child_process";
2747
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
2748
- import os3 from "os";
2991
+ import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
2992
+ import os2 from "os";
2749
2993
  import path5 from "path";
2750
2994
 
2751
2995
  // src/runtimeTurnState.ts
@@ -3107,7 +3351,7 @@ var CodexEventNormalizer = class {
3107
3351
 
3108
3352
  // src/drivers/codex.ts
3109
3353
  function ensureGitRepoForCodex(workingDirectory, deps = {}) {
3110
- const existsSyncFn = deps.existsSyncFn ?? existsSync4;
3354
+ const existsSyncFn = deps.existsSyncFn ?? existsSync3;
3111
3355
  const execSyncFn = deps.execSyncFn ?? execSync;
3112
3356
  const gitDir = path5.join(workingDirectory, ".git");
3113
3357
  if (existsSyncFn(gitDir)) return;
@@ -3125,7 +3369,7 @@ function isWindowsSandboxRunner(commandPath) {
3125
3369
  return path5.basename(commandPath).toLowerCase().startsWith("codex-command-runner");
3126
3370
  }
3127
3371
  function resolveWindowsNpmCodexEntry(deps = {}) {
3128
- const existsSyncFn = deps.existsSyncFn ?? existsSync4;
3372
+ const existsSyncFn = deps.existsSyncFn ?? existsSync3;
3129
3373
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
3130
3374
  const env = deps.env ?? process.env;
3131
3375
  const winPath = path5.win32;
@@ -3147,7 +3391,7 @@ function resolveWindowsNpmCodexEntry(deps = {}) {
3147
3391
  return null;
3148
3392
  }
3149
3393
  function resolveWindowsCodexDesktopEntry(deps = {}) {
3150
- const existsSyncFn = deps.existsSyncFn ?? existsSync4;
3394
+ const existsSyncFn = deps.existsSyncFn ?? existsSync3;
3151
3395
  const env = deps.env ?? process.env;
3152
3396
  const homeDir = deps.homeDir;
3153
3397
  const winPath = path5.win32;
@@ -3299,11 +3543,15 @@ var CodexDriver = class {
3299
3543
  // the daemon. They replace the previous transcript-mtime heuristic.
3300
3544
  experimentalRawEvents: true
3301
3545
  };
3302
- if (ctx.config.model) {
3303
- threadParams.model = ctx.config.model;
3546
+ const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
3547
+ if (launchRuntimeFields.model) {
3548
+ threadParams.model = launchRuntimeFields.model;
3549
+ }
3550
+ if (launchRuntimeFields.reasoningEffort) {
3551
+ threadParams.config = { model_reasoning_effort: launchRuntimeFields.reasoningEffort };
3304
3552
  }
3305
- if (ctx.config.reasoningEffort) {
3306
- threadParams.config = { model_reasoning_effort: ctx.config.reasoningEffort };
3553
+ if (launchRuntimeFields.mode.kind === "fast") {
3554
+ threadParams.serviceTier = "priority";
3307
3555
  }
3308
3556
  if (ctx.config.sessionId) {
3309
3557
  return {
@@ -3459,12 +3707,12 @@ var CodexDriver = class {
3459
3707
  return detectCodexModels();
3460
3708
  }
3461
3709
  };
3462
- function detectCodexModels(home = os3.homedir()) {
3710
+ function detectCodexModels(home = os2.homedir()) {
3463
3711
  const cachePath = path5.join(home, ".codex", "models_cache.json");
3464
3712
  const configPath = path5.join(home, ".codex", "config.toml");
3465
3713
  let models = [];
3466
3714
  try {
3467
- const raw = readFileSync3(cachePath, "utf8");
3715
+ const raw = readFileSync2(cachePath, "utf8");
3468
3716
  const parsed = JSON.parse(raw);
3469
3717
  const entries = Array.isArray(parsed?.models) ? parsed.models : [];
3470
3718
  for (const entry of entries) {
@@ -3481,7 +3729,7 @@ function detectCodexModels(home = os3.homedir()) {
3481
3729
  if (models.length === 0) return null;
3482
3730
  let defaultModel;
3483
3731
  try {
3484
- const raw = readFileSync3(configPath, "utf8");
3732
+ const raw = readFileSync2(configPath, "utf8");
3485
3733
  const match = raw.match(/^\s*model\s*=\s*"([^"]+)"/m);
3486
3734
  if (match) defaultModel = match[1];
3487
3735
  } catch {
@@ -3512,7 +3760,7 @@ function buildAntigravityArgs(ctx) {
3512
3760
  const args = [
3513
3761
  "--print",
3514
3762
  "--print-timeout",
3515
- ctx.config.envVars?.ANTIGRAVITY_PRINT_TIMEOUT || DEFAULT_PRINT_TIMEOUT,
3763
+ runtimeConfigToLaunchFields(ctx.config).envVars?.ANTIGRAVITY_PRINT_TIMEOUT || DEFAULT_PRINT_TIMEOUT,
3516
3764
  "--dangerously-skip-permissions"
3517
3765
  ];
3518
3766
  if (ctx.config.sessionId) {
@@ -3691,11 +3939,12 @@ var CopilotDriver = class {
3691
3939
  "-p",
3692
3940
  ctx.prompt
3693
3941
  ];
3694
- if (ctx.config.model && ctx.config.model !== "default") {
3695
- args.push("--model", ctx.config.model);
3942
+ const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
3943
+ if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
3944
+ args.push("--model", launchRuntimeFields.model);
3696
3945
  }
3697
- if (ctx.config.reasoningEffort) {
3698
- args.push("--effort", ctx.config.reasoningEffort);
3946
+ if (launchRuntimeFields.reasoningEffort) {
3947
+ args.push("--effort", launchRuntimeFields.reasoningEffort);
3699
3948
  }
3700
3949
  if (ctx.config.sessionId) {
3701
3950
  args.push(`--resume=${ctx.config.sessionId}`);
@@ -3795,7 +4044,7 @@ var CopilotDriver = class {
3795
4044
 
3796
4045
  // src/drivers/cursor.ts
3797
4046
  import { spawn as spawn5, spawnSync } from "child_process";
3798
- import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync2, existsSync as existsSync5 } from "fs";
4047
+ import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
3799
4048
  import path7 from "path";
3800
4049
  async function buildCursorSpawnEnv(ctx, deps = {}) {
3801
4050
  const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" });
@@ -3851,7 +4100,7 @@ var CursorDriver = class {
3851
4100
  }
3852
4101
  async spawn(ctx) {
3853
4102
  const cursorDir = path7.join(ctx.workingDirectory, ".cursor");
3854
- if (!existsSync5(cursorDir)) {
4103
+ if (!existsSync4(cursorDir)) {
3855
4104
  mkdirSync2(cursorDir, { recursive: true });
3856
4105
  }
3857
4106
  const mcpConfigPath = path7.join(cursorDir, "mcp.json");
@@ -3864,8 +4113,9 @@ var CursorDriver = class {
3864
4113
  "--approve-mcps",
3865
4114
  "--trust"
3866
4115
  ];
3867
- if (ctx.config.model && ctx.config.model !== "default") {
3868
- args.push("--model", ctx.config.model);
4116
+ const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
4117
+ if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
4118
+ args.push("--model", launchRuntimeFields.model);
3869
4119
  }
3870
4120
  if (ctx.config.sessionId) {
3871
4121
  args.push("--resume", ctx.config.sessionId);
@@ -4000,14 +4250,15 @@ function runCursorModelsCommand() {
4000
4250
 
4001
4251
  // src/drivers/gemini.ts
4002
4252
  import { execFileSync as execFileSync3, spawn as spawn6 } from "child_process";
4003
- import { existsSync as existsSync6, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
4253
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
4004
4254
  import path8 from "path";
4005
4255
  async function buildGeminiSpawnEnv(ctx, platform = process.platform) {
4006
4256
  const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" }, platform);
4007
- if (!Object.prototype.hasOwnProperty.call(ctx.config.envVars ?? {}, "GEMINI_CLI_TRUST_WORKSPACE")) {
4257
+ const launchEnvVars = runtimeConfigToLaunchFields(ctx.config).envVars;
4258
+ if (!Object.prototype.hasOwnProperty.call(launchEnvVars ?? {}, "GEMINI_CLI_TRUST_WORKSPACE")) {
4008
4259
  spawnEnv.GEMINI_CLI_TRUST_WORKSPACE = "true";
4009
4260
  }
4010
- if (platform === "win32" && !Object.prototype.hasOwnProperty.call(ctx.config.envVars ?? {}, "GEMINI_PTY_INFO")) {
4261
+ if (platform === "win32" && !Object.prototype.hasOwnProperty.call(launchEnvVars ?? {}, "GEMINI_PTY_INFO")) {
4011
4262
  spawnEnv.GEMINI_PTY_INFO = "child_process";
4012
4263
  }
4013
4264
  return spawnEnv;
@@ -4027,8 +4278,9 @@ function buildGeminiArgs(config) {
4027
4278
  "-p",
4028
4279
  ""
4029
4280
  ];
4030
- if (config.model && config.model !== "default") {
4031
- args.push("--model", config.model);
4281
+ const launchRuntimeFields = runtimeConfigToLaunchFields(config);
4282
+ if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
4283
+ args.push("--model", launchRuntimeFields.model);
4032
4284
  }
4033
4285
  if (config.sessionId) {
4034
4286
  args.push("--resume", config.sessionId);
@@ -4041,7 +4293,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
4041
4293
  return { command: resolveCommandOnPath("gemini", deps) ?? "gemini", args: commandArgs };
4042
4294
  }
4043
4295
  const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
4044
- const existsSyncFn = deps.existsSyncFn ?? existsSync6;
4296
+ const existsSyncFn = deps.existsSyncFn ?? existsSync5;
4045
4297
  const env = deps.env ?? process.env;
4046
4298
  const winPath = path8.win32;
4047
4299
  let geminiEntry = null;
@@ -4214,8 +4466,8 @@ var GeminiDriver = class {
4214
4466
  // src/drivers/kimi.ts
4215
4467
  import { randomUUID as randomUUID2 } from "crypto";
4216
4468
  import { spawn as spawn7 } from "child_process";
4217
- import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync6 } from "fs";
4218
- import os4 from "os";
4469
+ import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "fs";
4470
+ import os3 from "os";
4219
4471
  import path9 from "path";
4220
4472
  var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
4221
4473
  var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
@@ -4288,7 +4540,7 @@ var KimiDriver = class {
4288
4540
  const systemPromptPath = path9.join(ctx.workingDirectory, KIMI_SYSTEM_PROMPT_FILE);
4289
4541
  const agentFilePath = path9.join(ctx.workingDirectory, KIMI_AGENT_FILE);
4290
4542
  const mcpConfigPath = path9.join(ctx.workingDirectory, KIMI_MCP_FILE);
4291
- if (!isResume || !existsSync7(systemPromptPath)) {
4543
+ if (!isResume || !existsSync6(systemPromptPath)) {
4292
4544
  writeFileSync6(systemPromptPath, ctx.prompt, "utf8");
4293
4545
  }
4294
4546
  writeFileSync6(agentFilePath, [
@@ -4316,8 +4568,9 @@ var KimiDriver = class {
4316
4568
  "--session",
4317
4569
  this.sessionId
4318
4570
  ];
4319
- if (ctx.config.model && ctx.config.model !== "default") {
4320
- args.push("--model", ctx.config.model);
4571
+ const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
4572
+ if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
4573
+ args.push("--model", launchRuntimeFields.model);
4321
4574
  }
4322
4575
  const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
4323
4576
  const launch = resolveKimiSpawn(args);
@@ -4443,11 +4696,11 @@ var KimiDriver = class {
4443
4696
  return detectKimiModels();
4444
4697
  }
4445
4698
  };
4446
- function detectKimiModels(home = os4.homedir()) {
4699
+ function detectKimiModels(home = os3.homedir()) {
4447
4700
  const configPath = path9.join(home, ".kimi", "config.toml");
4448
4701
  let raw;
4449
4702
  try {
4450
- raw = readFileSync4(configPath, "utf8");
4703
+ raw = readFileSync3(configPath, "utf8");
4451
4704
  } catch {
4452
4705
  return null;
4453
4706
  }
@@ -4471,8 +4724,8 @@ function detectKimiModels(home = os4.homedir()) {
4471
4724
 
4472
4725
  // src/drivers/opencode.ts
4473
4726
  import { spawn as spawn8, spawnSync as spawnSync2 } from "child_process";
4474
- import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
4475
- import os5 from "os";
4727
+ import { existsSync as existsSync7, readFileSync as readFileSync4 } from "fs";
4728
+ import os4 from "os";
4476
4729
  import path10 from "path";
4477
4730
  var CHAT_MCP_SERVER_NAME = "chat";
4478
4731
  var CHAT_MCP_TOOL_PREFIX = `${CHAT_MCP_SERVER_NAME}_`;
@@ -4517,13 +4770,13 @@ function parseOpenCodeConfigContent(raw) {
4517
4770
  return {};
4518
4771
  }
4519
4772
  function parseUserOpenCodeConfig(ctx) {
4520
- const raw = ctx.config.envVars?.OPENCODE_CONFIG_CONTENT;
4773
+ const raw = runtimeConfigToLaunchFields(ctx.config).envVars?.OPENCODE_CONFIG_CONTENT;
4521
4774
  return parseOpenCodeConfigContent(raw);
4522
4775
  }
4523
- function readLocalOpenCodeConfig(home = os5.homedir()) {
4776
+ function readLocalOpenCodeConfig(home = os4.homedir()) {
4524
4777
  const configPath = path10.join(home, ".config", "opencode", "opencode.json");
4525
4778
  try {
4526
- return parseOpenCodeConfigContent(readFileSync5(configPath, "utf8"));
4779
+ return parseOpenCodeConfigContent(readFileSync4(configPath, "utf8"));
4527
4780
  } catch {
4528
4781
  }
4529
4782
  return {};
@@ -4581,7 +4834,7 @@ function mergeOpenCodeConfigs(localConfig, envConfig) {
4581
4834
  }
4582
4835
  };
4583
4836
  }
4584
- function buildOpenCodeConfig(ctx, home = os5.homedir()) {
4837
+ function buildOpenCodeConfig(ctx, home = os4.homedir()) {
4585
4838
  const userConfig = mergeOpenCodeConfigs(readLocalOpenCodeConfig(home), parseUserOpenCodeConfig(ctx));
4586
4839
  const userAgents = recordField(userConfig.agent);
4587
4840
  const userSlockAgent = recordField(userAgents[SLOCK_AGENT_NAME]);
@@ -4606,7 +4859,7 @@ function buildOpenCodeConfig(ctx, home = os5.homedir()) {
4606
4859
  }
4607
4860
  };
4608
4861
  }
4609
- async function buildOpenCodeLaunchOptions(ctx, home = os5.homedir(), version = null) {
4862
+ async function buildOpenCodeLaunchOptions(ctx, home = os4.homedir(), version = null) {
4610
4863
  const slock = await prepareCliTransport(ctx, { NO_COLOR: "1" });
4611
4864
  const config = buildOpenCodeConfig(ctx, home);
4612
4865
  const env = {
@@ -4622,8 +4875,9 @@ async function buildOpenCodeLaunchOptions(ctx, home = os5.homedir(), version = n
4622
4875
  "--dir",
4623
4876
  ctx.workingDirectory
4624
4877
  ];
4625
- if (ctx.config.model && ctx.config.model !== "default") {
4626
- args.push("--model", ctx.config.model);
4878
+ const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
4879
+ if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
4880
+ args.push("--model", launchRuntimeFields.model);
4627
4881
  }
4628
4882
  if (requiresAgentCliFlag(version)) {
4629
4883
  args.push("--agent", SLOCK_AGENT_NAME);
@@ -4704,7 +4958,7 @@ function formatOpenCodeLabelToken(token) {
4704
4958
  if (/^\d/.test(token)) return token;
4705
4959
  return normalized.charAt(0).toUpperCase() + normalized.slice(1);
4706
4960
  }
4707
- function detectOpenCodeModels(home = os5.homedir(), runCommand = runOpenCodeModelsCommand) {
4961
+ function detectOpenCodeModels(home = os4.homedir(), runCommand = runOpenCodeModelsCommand) {
4708
4962
  const commandResult = runCommand(home);
4709
4963
  if (commandResult.error || commandResult.status !== 0) return null;
4710
4964
  return parseOpenCodeModelsOutput(commandResult.stdout);
@@ -4744,7 +4998,7 @@ function openCodeSpecForEntry(entry, commandArgs) {
4744
4998
  return { command: process.execPath, args: [entry, ...commandArgs], shell: false };
4745
4999
  }
4746
5000
  function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
4747
- const existsSyncFn = deps.existsSyncFn ?? existsSync8;
5001
+ const existsSyncFn = deps.existsSyncFn ?? existsSync7;
4748
5002
  const execFileSyncFn = deps.execFileSyncFn;
4749
5003
  const env = deps.env ?? process.env;
4750
5004
  const winPath = path10.win32;
@@ -4774,7 +5028,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
4774
5028
  }
4775
5029
  function extractWindowsShimTargets(commandPath, deps = {}) {
4776
5030
  if (!isWindowsCommandShim(commandPath)) return [];
4777
- const readFileSyncFn = deps.readFileSyncFn ?? readFileSync5;
5031
+ const readFileSyncFn = deps.readFileSyncFn ?? readFileSync4;
4778
5032
  const commandDir = path10.win32.dirname(commandPath);
4779
5033
  let raw;
4780
5034
  try {
@@ -4908,7 +5162,7 @@ var OpenCodeDriver = class {
4908
5162
  if (unsupportedMessage) {
4909
5163
  throw new Error(unsupportedMessage);
4910
5164
  }
4911
- const launch = await buildOpenCodeLaunchOptions(ctx, os5.homedir(), version);
5165
+ const launch = await buildOpenCodeLaunchOptions(ctx, os4.homedir(), version);
4912
5166
  const spawnSpec = resolveOpenCodeSpawn(launch.args);
4913
5167
  const proc = spawn8(spawnSpec.command, spawnSpec.args, {
4914
5168
  cwd: ctx.workingDirectory,
@@ -5500,7 +5754,7 @@ function findSessionJsonl(root, predicate) {
5500
5754
  if (depth < 0 || visited >= maxEntries) return null;
5501
5755
  let entries;
5502
5756
  try {
5503
- entries = readdirSync2(dir, { withFileTypes: true }).sort((a, b) => b.name.localeCompare(a.name));
5757
+ entries = readdirSync(dir, { withFileTypes: true }).sort((a, b) => b.name.localeCompare(a.name));
5504
5758
  } catch {
5505
5759
  return null;
5506
5760
  }
@@ -5546,11 +5800,11 @@ function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
5546
5800
  return null;
5547
5801
  }
5548
5802
  }
5549
- function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os6.homedir(), fallbackDir) {
5803
+ function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os5.homedir(), fallbackDir) {
5550
5804
  const directPath = path12.isAbsolute(sessionId) ? sessionId : null;
5551
5805
  if (directPath) {
5552
5806
  try {
5553
- if (statSync2(directPath).isFile()) {
5807
+ if (statSync(directPath).isFile()) {
5554
5808
  return { label: sessionId, path: directPath, runtime, reachable: true };
5555
5809
  }
5556
5810
  } catch {
@@ -6494,6 +6748,7 @@ var AgentProcessManager = class _AgentProcessManager {
6494
6748
  driverResolver;
6495
6749
  defaultAgentEnvVarsProvider;
6496
6750
  tracer;
6751
+ cliTransportTraceDir = null;
6497
6752
  deliveryTraceContexts = /* @__PURE__ */ new WeakMap();
6498
6753
  processExitTraceAttrs = /* @__PURE__ */ new WeakMap();
6499
6754
  agentVisibleBoundaries = /* @__PURE__ */ new Map();
@@ -6504,7 +6759,7 @@ var AgentProcessManager = class _AgentProcessManager {
6504
6759
  this.daemonApiKey = daemonApiKey;
6505
6760
  this.serverUrl = opts.serverUrl;
6506
6761
  this.dataDir = opts.dataDir || resolveSlockHomePath("agents");
6507
- this.runtimeSessionHomeDir = opts.runtimeSessionHomeDir || os6.homedir();
6762
+ this.runtimeSessionHomeDir = opts.runtimeSessionHomeDir || os5.homedir();
6508
6763
  this.driverResolver = opts.driverResolver || getDriver;
6509
6764
  this.defaultAgentEnvVarsProvider = opts.defaultAgentEnvVarsProvider || null;
6510
6765
  this.tracer = opts.tracer ?? noopTracer;
@@ -6524,6 +6779,9 @@ var AgentProcessManager = class _AgentProcessManager {
6524
6779
  setTracer(tracer) {
6525
6780
  this.tracer = tracer;
6526
6781
  }
6782
+ setCliTransportTraceDir(traceDir) {
6783
+ this.cliTransportTraceDir = traceDir;
6784
+ }
6527
6785
  visibleBoundaryMap(agentId) {
6528
6786
  let map = this.agentVisibleBoundaries.get(agentId);
6529
6787
  if (!map) {
@@ -6628,6 +6886,7 @@ var AgentProcessManager = class _AgentProcessManager {
6628
6886
  });
6629
6887
  },
6630
6888
  recordProxyFailure: (input) => this.recordAgentProxyFailure(agentId, input),
6889
+ recordTransportNormalizedError: (input) => this.recordAgentProxyTransportNormalizedError(agentId, input),
6631
6890
  recordFreshnessDecision: (input) => {
6632
6891
  this.recordDaemonTrace("daemon.agent.inbox.freshness_decision", {
6633
6892
  agentId,
@@ -6656,6 +6915,22 @@ var AgentProcessManager = class _AgentProcessManager {
6656
6915
  error_message: input.errorMessage
6657
6916
  }, "error");
6658
6917
  }
6918
+ recordAgentProxyTransportNormalizedError(agentId, input) {
6919
+ this.recordDaemonTrace("daemon.transport.normalized_error", {
6920
+ producer: "daemon",
6921
+ agentId,
6922
+ normalized_code: input.normalizedCode,
6923
+ route_family: input.routeFamily,
6924
+ response_started: input.responseStarted,
6925
+ upstream_layer: input.upstreamLayer,
6926
+ ...typeof input.upstreamStatus === "number" ? { upstream_status: input.upstreamStatus } : {},
6927
+ ...input.originalMessage ? { original_message: input.originalMessage } : {},
6928
+ launchId: input.launchId,
6929
+ target_host_class: input.targetHostClass,
6930
+ downstream_caller: input.downstreamCaller,
6931
+ upstream: input.upstream
6932
+ }, "error");
6933
+ }
6659
6934
  recordFreshnessDecisionActivity(agentId, input) {
6660
6935
  if (input.decision !== "local_hold" && input.decision !== "syncing_hold") return;
6661
6936
  const ap = this.agents.get(agentId);
@@ -7055,7 +7330,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
7055
7330
  slockCliPath: this.slockCliPath,
7056
7331
  daemonApiKey: this.daemonApiKey,
7057
7332
  launchId: launchId || null,
7058
- agentCredentialProxyInboxCoordinator: this.createAgentProxyInboxCoordinator(agentId)
7333
+ agentCredentialProxyInboxCoordinator: this.createAgentProxyInboxCoordinator(agentId),
7334
+ cliTransportTraceDir: this.cliTransportTraceDir
7059
7335
  });
7060
7336
  this.recordDaemonTrace("daemon.agent.spawn.created", {
7061
7337
  ...this.startQueueTraceAttrs(agentId, effectiveConfig, wakeMessage, unreadSummary, resumePrompt, launchId),
@@ -7388,7 +7664,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
7388
7664
  "X-Slock-Client": "daemon-server-session-worker"
7389
7665
  },
7390
7666
  body: JSON.stringify({
7391
- scopes: ["send", "read", "mentions", "tasks", "reactions", "server", "channels"],
7667
+ scopes: ["send", "read", "mentions", "tasks", "reactions", "server", "channels", "knowledge"],
7392
7668
  name: `runner:${config.runtime}:${agentId.slice(0, 8)}`
7393
7669
  })
7394
7670
  });
@@ -8199,7 +8475,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
8199
8475
  async listSkills(agentId, runtimeHint) {
8200
8476
  const agent = this.agents.get(agentId);
8201
8477
  const runtime = runtimeHint || agent?.config.runtime || "claude";
8202
- const home = os6.homedir();
8478
+ const home = os5.homedir();
8203
8479
  const workspaceDir = path12.join(this.dataDir, agentId);
8204
8480
  const paths = _AgentProcessManager.SKILL_PATHS[runtime] || _AgentProcessManager.SKILL_PATHS.claude;
8205
8481
  const globalResults = await Promise.all(
@@ -9626,8 +9902,8 @@ var ReminderCache = class {
9626
9902
 
9627
9903
  // src/machineLock.ts
9628
9904
  import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
9629
- import { mkdirSync as mkdirSync5, readFileSync as readFileSync6, rmSync as rmSync3, statSync as statSync3, writeFileSync as writeFileSync8 } from "fs";
9630
- import os7 from "os";
9905
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync8 } from "fs";
9906
+ import os6 from "os";
9631
9907
  import path13 from "path";
9632
9908
  var INCOMPLETE_LOCK_STALE_MS = 3e4;
9633
9909
  var DaemonMachineLockConflictError = class extends Error {
@@ -9654,14 +9930,14 @@ function ownerPath(lockDir) {
9654
9930
  }
9655
9931
  function readOwner(lockDir) {
9656
9932
  try {
9657
- return JSON.parse(readFileSync6(ownerPath(lockDir), "utf8"));
9933
+ return JSON.parse(readFileSync5(ownerPath(lockDir), "utf8"));
9658
9934
  } catch {
9659
9935
  return null;
9660
9936
  }
9661
9937
  }
9662
9938
  function lockAgeMs(lockDir) {
9663
9939
  try {
9664
- return Date.now() - statSync3(lockDir).mtimeMs;
9940
+ return Date.now() - statSync2(lockDir).mtimeMs;
9665
9941
  } catch {
9666
9942
  return null;
9667
9943
  }
@@ -9690,7 +9966,7 @@ function acquireDaemonMachineLock(options) {
9690
9966
  const owner = {
9691
9967
  pid: process.pid,
9692
9968
  token,
9693
- hostname: os7.hostname(),
9969
+ hostname: os6.hostname(),
9694
9970
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
9695
9971
  serverUrl: options.serverUrl,
9696
9972
  apiKeyFingerprint: fingerprint.slice(0, 16)
@@ -9733,7 +10009,7 @@ function acquireDaemonMachineLock(options) {
9733
10009
  }
9734
10010
 
9735
10011
  // src/localTraceSink.ts
9736
- import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync3, rmSync as rmSync4, statSync as statSync4, writeFileSync as writeFileSync9 } from "fs";
10012
+ import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync2, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync9 } from "fs";
9737
10013
  import path14 from "path";
9738
10014
  var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
9739
10015
  var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
@@ -9757,7 +10033,8 @@ var DIAGNOSTIC_ERROR_ATTRS = /* @__PURE__ */ new Set([
9757
10033
  "runtime_error_message_present",
9758
10034
  "runtime_error_message_length_bucket",
9759
10035
  "runtime_error_message_truncated",
9760
- "runtime_error_message_excerpt"
10036
+ "runtime_error_message_excerpt",
10037
+ "original_message"
9761
10038
  ]);
9762
10039
  var LocalRotatingTraceSink = class {
9763
10040
  traceDir;
@@ -9805,13 +10082,13 @@ var LocalRotatingTraceSink = class {
9805
10082
  `daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
9806
10083
  );
9807
10084
  writeFileSync9(this.currentFile, "", { flag: "a", mode: 384 });
9808
- this.currentSize = statSync4(this.currentFile).size;
10085
+ this.currentSize = statSync3(this.currentFile).size;
9809
10086
  this.currentFileOpenedAtMs = nowMs;
9810
10087
  this.pruneOldFiles();
9811
10088
  }
9812
10089
  }
9813
10090
  pruneOldFiles() {
9814
- const files = readdirSync3(this.traceDir).filter((name) => name.startsWith("daemon-trace-") && name.endsWith(".jsonl")).sort();
10091
+ const files = readdirSync2(this.traceDir).filter((name) => name.startsWith("daemon-trace-") && name.endsWith(".jsonl")).sort();
9815
10092
  const excess = files.length - this.maxFiles;
9816
10093
  if (excess <= 0) return;
9817
10094
  for (const file of files.slice(0, excess)) {
@@ -9851,14 +10128,13 @@ function sanitizeAttrs(attrs) {
9851
10128
  if (!attrs) return void 0;
9852
10129
  const sanitized = {};
9853
10130
  for (const [key, value] of Object.entries(attrs)) {
10131
+ if (value === null || value === void 0 || value === "") continue;
9854
10132
  if (isDiagnosticIdAttr(key)) {
9855
- if (value === null || value === void 0 || value === "") continue;
9856
10133
  sanitized[key] = sanitizeValue(value);
9857
10134
  continue;
9858
10135
  }
9859
10136
  if (isDiagnosticErrorAttr(key)) {
9860
- if (value === null || value === void 0 || value === "") continue;
9861
- sanitized[key] = sanitizeValue(value);
10137
+ sanitized[key] = sanitizeDiagnosticErrorValue(key, value);
9862
10138
  continue;
9863
10139
  }
9864
10140
  if (shouldDropAttr(key)) continue;
@@ -9878,6 +10154,11 @@ function sanitizeValue(value) {
9878
10154
  }
9879
10155
  return String(value);
9880
10156
  }
10157
+ function sanitizeDiagnosticErrorValue(key, value) {
10158
+ if (key !== "original_message" || typeof value !== "string") return sanitizeValue(value);
10159
+ const normalized = value.replace(/sk_(?:agent|machine|computer)_[A-Za-z0-9_-]+/g, "sk_[redacted]").replace(/sap_[A-Za-z0-9_-]+/g, "sap_[redacted]").replace(/https?:\/\/\S+/g, "[url]").replace(/\s+/g, " ").trim();
10160
+ return normalized.length > 240 ? `${normalized.slice(0, 237)}...` : normalized;
10161
+ }
9881
10162
  function shouldDropAttr(key) {
9882
10163
  const normalized = key.replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
9883
10164
  if (/(^|_)(api_key|auth_token|token|secret|password|cookie|credential)(_|$)/i.test(normalized)) {
@@ -10246,7 +10527,7 @@ function readPositiveIntegerEnv2(name, fallback) {
10246
10527
 
10247
10528
  // src/core.ts
10248
10529
  var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
10249
- var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels"];
10530
+ var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels", "knowledge"];
10250
10531
  var RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS2 = 3;
10251
10532
  var RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2 = 250;
10252
10533
  var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
@@ -10525,6 +10806,7 @@ var DaemonCore = class {
10525
10806
  sink: this.localTraceSink
10526
10807
  });
10527
10808
  this.agentManager.setTracer(this.tracer);
10809
+ this.agentManager.setCliTransportTraceDir(path16.join(machineDir, "traces"));
10528
10810
  }
10529
10811
  installTraceBundleUploader(machineDir) {
10530
10812
  if (!this.shouldEnableLocalTrace()) return;
@@ -10947,8 +11229,8 @@ var DaemonCore = class {
10947
11229
  capabilities: ["agent:start", "agent:stop", "agent:deliver", "workspace:files"],
10948
11230
  runtimes,
10949
11231
  runningAgents: runningAgentIds,
10950
- hostname: this.options.hostname ?? os8.hostname(),
10951
- os: this.options.osDescription ?? `${os8.platform()} ${os8.arch()}`,
11232
+ hostname: this.options.hostname ?? os7.hostname(),
11233
+ os: this.options.osDescription ?? `${os7.platform()} ${os7.arch()}`,
10952
11234
  daemonVersion: this.daemonVersion
10953
11235
  });
10954
11236
  this.recordDaemonTrace("daemon.ready.sent", {