@slock-ai/daemon 0.46.1 → 0.46.2-play.20260510065637
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/chat-bridge.js
CHANGED
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
buildFetchDispatcher,
|
|
5
5
|
executeJsonRequest,
|
|
6
6
|
executeResponseRequest,
|
|
7
|
-
logger
|
|
8
|
-
|
|
7
|
+
logger,
|
|
8
|
+
resolveSlockHomePath
|
|
9
|
+
} from "./chunk-B7XIMLOT.js";
|
|
9
10
|
|
|
10
11
|
// src/chat-bridge.ts
|
|
11
12
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -722,8 +723,7 @@ Use this ID in send_message's attachment_ids parameter to include it in a messag
|
|
|
722
723
|
try {
|
|
723
724
|
const fs = await import("fs");
|
|
724
725
|
const path = await import("path");
|
|
725
|
-
const
|
|
726
|
-
const cacheDir = path.join(os.homedir(), ".slock", "attachments");
|
|
726
|
+
const cacheDir = resolveSlockHomePath("attachments");
|
|
727
727
|
fs.mkdirSync(cacheDir, { recursive: true });
|
|
728
728
|
const existing = fs.readdirSync(cacheDir).find((f) => f.startsWith(attachment_id));
|
|
729
729
|
if (existing) {
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS,
|
|
3
|
+
SLOCK_HOME_ENV,
|
|
3
4
|
buildWebSocketOptions,
|
|
4
5
|
executeJsonRequest,
|
|
5
6
|
executeResponseRequest,
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
listLegacySlockStatePaths,
|
|
8
|
+
logger,
|
|
9
|
+
resolveSlockHome,
|
|
10
|
+
resolveSlockHomePath
|
|
11
|
+
} from "./chunk-B7XIMLOT.js";
|
|
8
12
|
|
|
9
13
|
// src/core.ts
|
|
10
14
|
import path15 from "path";
|
|
@@ -688,6 +692,7 @@ var DISPLAY_PLAN_CONFIG = {
|
|
|
688
692
|
// src/agentProcessManager.ts
|
|
689
693
|
import { mkdirSync as mkdirSync4, readdirSync as readdirSync2, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
690
694
|
import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2 } from "fs/promises";
|
|
695
|
+
import { createHash as createHash2 } from "crypto";
|
|
691
696
|
import path11 from "path";
|
|
692
697
|
import os5 from "os";
|
|
693
698
|
|
|
@@ -1093,6 +1098,17 @@ Keep the user informed. They cannot see your internal reasoning, so:
|
|
|
1093
1098
|
- For multi-step work, send short progress updates (e.g. "Working on step 2/3\u2026").
|
|
1094
1099
|
- When done, summarize the result.
|
|
1095
1100
|
- Keep updates concise \u2014 one or two sentences. Don't flood the chat.
|
|
1101
|
+
- For long answers where users need the conclusion first but details still matter, put the conclusion and next action outside any collapse, then use sanitized HTML details blocks for optional depth:
|
|
1102
|
+
|
|
1103
|
+
\`\`\`html
|
|
1104
|
+
<details>
|
|
1105
|
+
<summary>Evidence, logs, or edge cases</summary>
|
|
1106
|
+
|
|
1107
|
+
Detailed notes go here.
|
|
1108
|
+
</details>
|
|
1109
|
+
\`\`\`
|
|
1110
|
+
|
|
1111
|
+
Do not hide the main recommendation, blocker, or required action inside \`<details>\`; only fold supporting evidence, logs, alternatives, or extended rationale.
|
|
1096
1112
|
|
|
1097
1113
|
### Conversation etiquette
|
|
1098
1114
|
|
|
@@ -1272,6 +1288,7 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(ctx.slockCliPath)}
|
|
|
1272
1288
|
...ctx.config.envVars || {},
|
|
1273
1289
|
...extraEnv,
|
|
1274
1290
|
...runtimeContextEnv(ctx.config),
|
|
1291
|
+
[SLOCK_HOME_ENV]: resolveSlockHome(),
|
|
1275
1292
|
SLOCK_AGENT_ID: ctx.agentId,
|
|
1276
1293
|
...ctx.launchId ? { SLOCK_AGENT_LAUNCH_ID: ctx.launchId } : {},
|
|
1277
1294
|
SLOCK_SERVER_URL: ctx.config.serverUrl,
|
|
@@ -2228,6 +2245,15 @@ function detectCodexModels(home = os2.homedir()) {
|
|
|
2228
2245
|
import { spawn as spawn3 } from "child_process";
|
|
2229
2246
|
import path5 from "path";
|
|
2230
2247
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
2248
|
+
function buildCopilotSpawnEnv(ctx) {
|
|
2249
|
+
return {
|
|
2250
|
+
...process.env,
|
|
2251
|
+
FORCE_COLOR: "0",
|
|
2252
|
+
NO_COLOR: "1",
|
|
2253
|
+
...ctx.config.envVars || {},
|
|
2254
|
+
[SLOCK_HOME_ENV]: resolveSlockHome()
|
|
2255
|
+
};
|
|
2256
|
+
}
|
|
2231
2257
|
var CopilotDriver = class {
|
|
2232
2258
|
id = "copilot";
|
|
2233
2259
|
lifecycle = {
|
|
@@ -2286,7 +2312,7 @@ var CopilotDriver = class {
|
|
|
2286
2312
|
if (ctx.config.sessionId) {
|
|
2287
2313
|
args.push(`--resume=${ctx.config.sessionId}`);
|
|
2288
2314
|
}
|
|
2289
|
-
const spawnEnv =
|
|
2315
|
+
const spawnEnv = buildCopilotSpawnEnv(ctx);
|
|
2290
2316
|
const proc = spawn3("copilot", args, {
|
|
2291
2317
|
cwd: ctx.workingDirectory,
|
|
2292
2318
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -2383,6 +2409,15 @@ var CopilotDriver = class {
|
|
|
2383
2409
|
import { spawn as spawn4, spawnSync } from "child_process";
|
|
2384
2410
|
import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
|
|
2385
2411
|
import path6 from "path";
|
|
2412
|
+
function buildCursorSpawnEnv(ctx) {
|
|
2413
|
+
return {
|
|
2414
|
+
...process.env,
|
|
2415
|
+
FORCE_COLOR: "0",
|
|
2416
|
+
NO_COLOR: "1",
|
|
2417
|
+
...ctx.config.envVars || {},
|
|
2418
|
+
[SLOCK_HOME_ENV]: resolveSlockHome()
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2386
2421
|
var CursorDriver = class {
|
|
2387
2422
|
id = "cursor";
|
|
2388
2423
|
lifecycle = {
|
|
@@ -2437,7 +2472,7 @@ var CursorDriver = class {
|
|
|
2437
2472
|
args.push("--resume", ctx.config.sessionId);
|
|
2438
2473
|
}
|
|
2439
2474
|
args.push(ctx.prompt);
|
|
2440
|
-
const spawnEnv =
|
|
2475
|
+
const spawnEnv = buildCursorSpawnEnv(ctx);
|
|
2441
2476
|
const proc = spawn4("cursor-agent", args, {
|
|
2442
2477
|
cwd: ctx.workingDirectory,
|
|
2443
2478
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -2772,13 +2807,16 @@ var GeminiDriver = class {
|
|
|
2772
2807
|
// src/drivers/kimi.ts
|
|
2773
2808
|
import { randomUUID } from "crypto";
|
|
2774
2809
|
import { spawn as spawn6 } from "child_process";
|
|
2775
|
-
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
2810
|
+
import { chmodSync, existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
2776
2811
|
import os3 from "os";
|
|
2777
2812
|
import path8 from "path";
|
|
2778
2813
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
2779
2814
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
2780
2815
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
2781
2816
|
var KIMI_MCP_FILE = ".slock-kimi-mcp.json";
|
|
2817
|
+
var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
|
|
2818
|
+
var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
|
|
2819
|
+
var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
|
|
2782
2820
|
function parseToolArguments(raw) {
|
|
2783
2821
|
if (typeof raw !== "string") return raw;
|
|
2784
2822
|
try {
|
|
@@ -2787,6 +2825,73 @@ function parseToolArguments(raw) {
|
|
|
2787
2825
|
return raw;
|
|
2788
2826
|
}
|
|
2789
2827
|
}
|
|
2828
|
+
function readKimiConfigSource(home = os3.homedir(), env = process.env) {
|
|
2829
|
+
const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
2830
|
+
if (inlineConfig && inlineConfig.trim()) {
|
|
2831
|
+
return {
|
|
2832
|
+
raw: inlineConfig,
|
|
2833
|
+
explicitPath: null,
|
|
2834
|
+
sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
|
|
2835
|
+
};
|
|
2836
|
+
}
|
|
2837
|
+
const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
2838
|
+
const configPath = explicitPath && explicitPath.trim() ? explicitPath : path8.join(home, ".kimi", "config.toml");
|
|
2839
|
+
try {
|
|
2840
|
+
return {
|
|
2841
|
+
raw: readFileSync3(configPath, "utf8"),
|
|
2842
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
2843
|
+
sourcePath: configPath
|
|
2844
|
+
};
|
|
2845
|
+
} catch {
|
|
2846
|
+
return {
|
|
2847
|
+
raw: null,
|
|
2848
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
2849
|
+
sourcePath: configPath
|
|
2850
|
+
};
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
function buildKimiSpawnEnv(env = process.env) {
|
|
2854
|
+
const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
2855
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
2856
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
2857
|
+
return spawnEnv;
|
|
2858
|
+
}
|
|
2859
|
+
function buildKimiEffectiveEnv(ctx, overrideEnv) {
|
|
2860
|
+
return {
|
|
2861
|
+
...process.env,
|
|
2862
|
+
...ctx.config.envVars || {},
|
|
2863
|
+
...overrideEnv || {}
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
function buildKimiLaunchOptions(ctx, opts = {}) {
|
|
2867
|
+
const env = buildKimiEffectiveEnv(ctx, opts.env);
|
|
2868
|
+
const source = readKimiConfigSource(opts.home ?? os3.homedir(), env);
|
|
2869
|
+
const args = [];
|
|
2870
|
+
let configFilePath = null;
|
|
2871
|
+
let configContent = null;
|
|
2872
|
+
if (source.explicitPath) {
|
|
2873
|
+
configFilePath = source.explicitPath;
|
|
2874
|
+
} else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
|
|
2875
|
+
configFilePath = path8.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
|
|
2876
|
+
configContent = source.raw;
|
|
2877
|
+
if (opts.writeGeneratedConfig !== false) {
|
|
2878
|
+
writeFileSync6(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
|
|
2879
|
+
chmodSync(configFilePath, 384);
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
if (configFilePath) {
|
|
2883
|
+
args.push("--config-file", configFilePath);
|
|
2884
|
+
}
|
|
2885
|
+
if (ctx.config.model && ctx.config.model !== "default") {
|
|
2886
|
+
args.push("--model", ctx.config.model);
|
|
2887
|
+
}
|
|
2888
|
+
return {
|
|
2889
|
+
args,
|
|
2890
|
+
env: buildKimiSpawnEnv(env),
|
|
2891
|
+
configFilePath,
|
|
2892
|
+
configContent
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2790
2895
|
var KimiDriver = class {
|
|
2791
2896
|
id = "kimi";
|
|
2792
2897
|
lifecycle = {
|
|
@@ -2803,7 +2908,25 @@ var KimiDriver = class {
|
|
|
2803
2908
|
};
|
|
2804
2909
|
model = {
|
|
2805
2910
|
detectedModelsVerifiedAs: "launchable",
|
|
2806
|
-
toLaunchSpec: (modelId) =>
|
|
2911
|
+
toLaunchSpec: (modelId, ctx, opts) => {
|
|
2912
|
+
if (!ctx) return { args: ["--model", modelId] };
|
|
2913
|
+
const launchCtx = {
|
|
2914
|
+
...ctx,
|
|
2915
|
+
config: {
|
|
2916
|
+
...ctx.config,
|
|
2917
|
+
model: modelId
|
|
2918
|
+
}
|
|
2919
|
+
};
|
|
2920
|
+
const launch = buildKimiLaunchOptions(launchCtx, {
|
|
2921
|
+
home: opts?.home,
|
|
2922
|
+
writeGeneratedConfig: false
|
|
2923
|
+
});
|
|
2924
|
+
return {
|
|
2925
|
+
args: launch.args,
|
|
2926
|
+
env: launch.env,
|
|
2927
|
+
configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
|
|
2928
|
+
};
|
|
2929
|
+
}
|
|
2807
2930
|
};
|
|
2808
2931
|
supportsStdinNotification = true;
|
|
2809
2932
|
mcpToolPrefix = "";
|
|
@@ -2855,6 +2978,7 @@ var KimiDriver = class {
|
|
|
2855
2978
|
}
|
|
2856
2979
|
}
|
|
2857
2980
|
}), "utf8");
|
|
2981
|
+
const launch = buildKimiLaunchOptions(ctx);
|
|
2858
2982
|
const args = [
|
|
2859
2983
|
"--wire",
|
|
2860
2984
|
"--yolo",
|
|
@@ -2863,16 +2987,13 @@ var KimiDriver = class {
|
|
|
2863
2987
|
"--mcp-config-file",
|
|
2864
2988
|
mcpConfigPath,
|
|
2865
2989
|
"--session",
|
|
2866
|
-
this.sessionId
|
|
2990
|
+
this.sessionId,
|
|
2991
|
+
...launch.args
|
|
2867
2992
|
];
|
|
2868
|
-
if (ctx.config.model && ctx.config.model !== "default") {
|
|
2869
|
-
args.push("--model", ctx.config.model);
|
|
2870
|
-
}
|
|
2871
|
-
const spawnEnv = { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
2872
2993
|
const proc = spawn6("kimi", args, {
|
|
2873
2994
|
cwd: ctx.workingDirectory,
|
|
2874
2995
|
stdio: ["pipe", "pipe", "pipe"],
|
|
2875
|
-
env:
|
|
2996
|
+
env: launch.env,
|
|
2876
2997
|
shell: process.platform === "win32"
|
|
2877
2998
|
});
|
|
2878
2999
|
proc.stdin?.write(JSON.stringify({
|
|
@@ -2989,14 +3110,9 @@ var KimiDriver = class {
|
|
|
2989
3110
|
return detectKimiModels();
|
|
2990
3111
|
}
|
|
2991
3112
|
};
|
|
2992
|
-
function detectKimiModels(home = os3.homedir()) {
|
|
2993
|
-
const
|
|
2994
|
-
|
|
2995
|
-
try {
|
|
2996
|
-
raw = readFileSync3(configPath, "utf8");
|
|
2997
|
-
} catch {
|
|
2998
|
-
return null;
|
|
2999
|
-
}
|
|
3113
|
+
function detectKimiModels(home = os3.homedir(), opts = {}) {
|
|
3114
|
+
const raw = readKimiConfigSource(home, opts.env).raw;
|
|
3115
|
+
if (raw === null) return null;
|
|
3000
3116
|
const models = [];
|
|
3001
3117
|
const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
|
|
3002
3118
|
const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
|
|
@@ -3527,8 +3643,86 @@ async function deleteWorkspaceDirectory(dataDir, directoryName) {
|
|
|
3527
3643
|
}
|
|
3528
3644
|
}
|
|
3529
3645
|
|
|
3646
|
+
// src/runtimeErrorDiagnostics.ts
|
|
3647
|
+
import { createHash } from "crypto";
|
|
3648
|
+
var MAX_RUNTIME_ERROR_MESSAGE_EXCERPT_CHARS = 4096;
|
|
3649
|
+
function buildRuntimeErrorDiagnosticEnvelope(message) {
|
|
3650
|
+
const rawMessage = String(message || "");
|
|
3651
|
+
const scrubbed = scrubRuntimeErrorDiagnosticText(rawMessage);
|
|
3652
|
+
const { value: excerpt, truncated } = truncateDiagnosticText(scrubbed, MAX_RUNTIME_ERROR_MESSAGE_EXCERPT_CHARS);
|
|
3653
|
+
const httpStatus = extractHttpStatus(rawMessage);
|
|
3654
|
+
const runtimeErrorClass = classifyRuntimeError(rawMessage, httpStatus);
|
|
3655
|
+
const fingerprint = fingerprintRuntimeError(scrubbed);
|
|
3656
|
+
const spanAttrs = {
|
|
3657
|
+
runtime_error_class: runtimeErrorClass,
|
|
3658
|
+
runtime_error_fingerprint: fingerprint,
|
|
3659
|
+
runtime_error_message_present: rawMessage.length > 0,
|
|
3660
|
+
runtime_error_message_length_bucket: bucketLength(rawMessage.length),
|
|
3661
|
+
runtime_error_message_truncated: truncated
|
|
3662
|
+
};
|
|
3663
|
+
if (httpStatus !== null) {
|
|
3664
|
+
spanAttrs.runtime_error_http_status = httpStatus;
|
|
3665
|
+
}
|
|
3666
|
+
return {
|
|
3667
|
+
spanAttrs,
|
|
3668
|
+
eventAttrs: {
|
|
3669
|
+
...spanAttrs,
|
|
3670
|
+
runtime_error_message_excerpt: excerpt
|
|
3671
|
+
}
|
|
3672
|
+
};
|
|
3673
|
+
}
|
|
3674
|
+
function scrubRuntimeErrorDiagnosticText(value) {
|
|
3675
|
+
return value.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]{8,}/gi, "Bearer [REDACTED_TOKEN]").replace(/\b(?:sk|sk-ant|sk-proj|xox[baprs]?)-[A-Za-z0-9_-]{8,}\b/g, "[REDACTED_TOKEN]").replace(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g, "[REDACTED_EMAIL]").replace(/https?:\/\/[^\s"'<>]+/gi, (url) => redactUrlQuery(url)).replace(/\/Users\/[^\s"'<>:]+(?:\/[^\s"'<>:]+)*/g, "[REDACTED_PATH]").replace(/\/home\/[^\s"'<>:]+(?:\/[^\s"'<>:]+)*/g, "[REDACTED_PATH]").replace(/[A-Za-z]:\\Users\\[^\s"'<>:]+(?:\\[^\s"'<>:]+)*/g, "[REDACTED_PATH]");
|
|
3676
|
+
}
|
|
3677
|
+
function truncateDiagnosticText(value, maxChars) {
|
|
3678
|
+
if (value.length <= maxChars) return { value, truncated: false };
|
|
3679
|
+
return { value: value.slice(0, maxChars), truncated: true };
|
|
3680
|
+
}
|
|
3681
|
+
function extractHttpStatus(message) {
|
|
3682
|
+
const match = /\b(?:HTTP|status(?:\s+code)?|API\s+Error)[:\s]+([45]\d{2})\b/i.exec(message) ?? /\b([45]\d{2})\s+(?:Bad Request|Unauthorized|Forbidden|Not Found|Conflict|Too Many Requests|Internal Server Error|Service Unavailable)\b/i.exec(message);
|
|
3683
|
+
if (!match) return null;
|
|
3684
|
+
const status = Number(match[1]);
|
|
3685
|
+
return Number.isInteger(status) ? status : null;
|
|
3686
|
+
}
|
|
3687
|
+
function classifyRuntimeError(message, httpStatus) {
|
|
3688
|
+
const explicit = /\b([A-Z][A-Za-z0-9_]*(?:Error|Exception))\b/.exec(message);
|
|
3689
|
+
if (explicit) return explicit[1];
|
|
3690
|
+
if (httpStatus !== null) {
|
|
3691
|
+
if (httpStatus === 429) return "RateLimitError";
|
|
3692
|
+
if (httpStatus === 401 || httpStatus === 403) return "AuthError";
|
|
3693
|
+
if (httpStatus === 404) return "NotFoundError";
|
|
3694
|
+
if (httpStatus >= 500) return "ProviderServerError";
|
|
3695
|
+
return "ProviderApiError";
|
|
3696
|
+
}
|
|
3697
|
+
if (/\btimeout|timed out\b/i.test(message)) return "TimeoutError";
|
|
3698
|
+
if (/\brate.?limit|too many requests\b/i.test(message)) return "RateLimitError";
|
|
3699
|
+
if (/\bnot found\b/i.test(message)) return "NotFoundError";
|
|
3700
|
+
return "RuntimeError";
|
|
3701
|
+
}
|
|
3702
|
+
function fingerprintRuntimeError(value) {
|
|
3703
|
+
const normalized = value.toLowerCase().replace(/[0-9a-f]{12,}/g, "<hex>").replace(/\b\d+\b/g, "<num>").replace(/\s+/g, " ").trim();
|
|
3704
|
+
return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
3705
|
+
}
|
|
3706
|
+
function bucketLength(length) {
|
|
3707
|
+
if (length === 0) return "0";
|
|
3708
|
+
if (length < 1024) return "<1k";
|
|
3709
|
+
if (length < 4096) return "1k-4k";
|
|
3710
|
+
if (length < 16384) return "4k-16k";
|
|
3711
|
+
return "16k+";
|
|
3712
|
+
}
|
|
3713
|
+
function redactUrlQuery(value) {
|
|
3714
|
+
try {
|
|
3715
|
+
const url = new URL(value);
|
|
3716
|
+
if (url.search) url.search = "?[REDACTED_QUERY]";
|
|
3717
|
+
if (url.username) url.username = "[REDACTED_USER]";
|
|
3718
|
+
if (url.password) url.password = "[REDACTED_PASSWORD]";
|
|
3719
|
+
return url.toString();
|
|
3720
|
+
} catch {
|
|
3721
|
+
return value.replace(/\?.*$/, "?[REDACTED_QUERY]");
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
|
|
3530
3725
|
// src/agentProcessManager.ts
|
|
3531
|
-
var DATA_DIR = path11.join(os5.homedir(), ".slock", "agents");
|
|
3532
3726
|
var DEFAULT_MAX_CONCURRENT_AGENT_STARTS = 5;
|
|
3533
3727
|
var DEFAULT_AGENT_START_INTERVAL_MS = 500;
|
|
3534
3728
|
var WORKSPACE_TEXT_FILE_MAX_BYTES = 1048576;
|
|
@@ -4212,6 +4406,20 @@ function runtimeProfileNotificationFromMessage(message) {
|
|
|
4212
4406
|
function runtimeProfileNotificationTitle(kind) {
|
|
4213
4407
|
return kind === "migration" ? "Runtime Profile migration" : "Runtime Profile notice";
|
|
4214
4408
|
}
|
|
4409
|
+
function hashRuntimeProfileKey(key) {
|
|
4410
|
+
if (!key) return void 0;
|
|
4411
|
+
return createHash2("sha256").update(key).digest("hex").slice(0, 16);
|
|
4412
|
+
}
|
|
4413
|
+
function runtimeProfileTurnControl(kind, key, source) {
|
|
4414
|
+
return {
|
|
4415
|
+
kind,
|
|
4416
|
+
source,
|
|
4417
|
+
keyHash: hashRuntimeProfileKey(key) ?? null,
|
|
4418
|
+
keyPresent: Boolean(key),
|
|
4419
|
+
injectedAtMs: Date.now(),
|
|
4420
|
+
migrationDoneToolObserved: false
|
|
4421
|
+
};
|
|
4422
|
+
}
|
|
4215
4423
|
function pushRecentLines(lines, chunk, maxLines, maxLineLength) {
|
|
4216
4424
|
const next = [...lines];
|
|
4217
4425
|
for (const rawLine of chunk.split(/\r?\n/)) {
|
|
@@ -4400,13 +4608,14 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
4400
4608
|
defaultAgentEnvVarsProvider;
|
|
4401
4609
|
tracer;
|
|
4402
4610
|
deliveryTraceContexts = /* @__PURE__ */ new WeakMap();
|
|
4611
|
+
processExitTraceAttrs = /* @__PURE__ */ new WeakMap();
|
|
4403
4612
|
constructor(chatBridgePath, sendToServer, daemonApiKey, opts) {
|
|
4404
4613
|
this.chatBridgePath = chatBridgePath;
|
|
4405
4614
|
this.slockCliPath = opts.slockCliPath ?? "";
|
|
4406
4615
|
this.sendToServer = sendToServer;
|
|
4407
4616
|
this.daemonApiKey = daemonApiKey;
|
|
4408
4617
|
this.serverUrl = opts.serverUrl;
|
|
4409
|
-
this.dataDir = opts.dataDir ||
|
|
4618
|
+
this.dataDir = opts.dataDir || resolveSlockHomePath("agents");
|
|
4410
4619
|
this.runtimeSessionHomeDir = opts.runtimeSessionHomeDir || os5.homedir();
|
|
4411
4620
|
this.driverResolver = opts.driverResolver || getDriver;
|
|
4412
4621
|
this.defaultAgentEnvVarsProvider = opts.defaultAgentEnvVarsProvider || null;
|
|
@@ -4798,6 +5007,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
4798
5007
|
exitCode: null,
|
|
4799
5008
|
exitSignal: null,
|
|
4800
5009
|
expectedTerminationReason: null,
|
|
5010
|
+
runtimeProfileTurnControl: runtimeConfig.runtimeProfileControl ? runtimeProfileTurnControl(runtimeConfig.runtimeProfileControl.kind, runtimeConfig.runtimeProfileControl.key, "agent_config") : null,
|
|
4801
5011
|
pendingTrajectory: null,
|
|
4802
5012
|
gatedSteering: createGatedSteeringState()
|
|
4803
5013
|
};
|
|
@@ -4872,7 +5082,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
4872
5082
|
clean_exit: code === 0,
|
|
4873
5083
|
runtime_trace_active: Boolean(current?.runtimeTraceSpan),
|
|
4874
5084
|
inbox_count: current?.inbox.length ?? 0,
|
|
4875
|
-
pending_notification_count: current?.pendingNotificationCount ?? 0
|
|
5085
|
+
pending_notification_count: current?.pendingNotificationCount ?? 0,
|
|
5086
|
+
...this.processExitTraceAttrs.get(proc)
|
|
4876
5087
|
});
|
|
4877
5088
|
logger.info(`[Agent ${agentId}] Process exited with code ${code}${signal ? ` (signal ${signal})` : ""}`);
|
|
4878
5089
|
});
|
|
@@ -4900,7 +5111,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
4900
5111
|
outcome: processEndedCleanly ? "process-exit" : "process-crash",
|
|
4901
5112
|
expectedTerminationReason: ap.expectedTerminationReason || void 0,
|
|
4902
5113
|
exitCode: finalCode,
|
|
4903
|
-
exitSignal: finalSignal
|
|
5114
|
+
exitSignal: finalSignal,
|
|
5115
|
+
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "process_exit")
|
|
4904
5116
|
});
|
|
4905
5117
|
if (processEndedCleanly) {
|
|
4906
5118
|
this.finishCompactionIfActive(agentId, "Context compaction finished (inferred from process exit)");
|
|
@@ -5063,6 +5275,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
5063
5275
|
agentId,
|
|
5064
5276
|
kind,
|
|
5065
5277
|
key_present: Boolean(key),
|
|
5278
|
+
key_hash: hashRuntimeProfileKey(key),
|
|
5066
5279
|
outcome: ap.sessionId ? "queued_busy" : "queued_before_session",
|
|
5067
5280
|
runtime: ap.config.runtime,
|
|
5068
5281
|
session_id_present: Boolean(ap.sessionId),
|
|
@@ -5085,6 +5298,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
5085
5298
|
agentId,
|
|
5086
5299
|
kind,
|
|
5087
5300
|
key_present: Boolean(key),
|
|
5301
|
+
key_hash: hashRuntimeProfileKey(key),
|
|
5088
5302
|
outcome: "queued_during_start",
|
|
5089
5303
|
startup_pending: true,
|
|
5090
5304
|
starting_inbox_count: pending.length,
|
|
@@ -5121,6 +5335,11 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
5121
5335
|
}
|
|
5122
5336
|
this.clearCompactionWatchdog(ap);
|
|
5123
5337
|
this.agents.delete(agentId);
|
|
5338
|
+
this.processExitTraceAttrs.set(ap.process, {
|
|
5339
|
+
stop_source: silent ? "daemon_internal" : "explicit_request",
|
|
5340
|
+
stop_wait_requested: wait,
|
|
5341
|
+
stop_silent: silent
|
|
5342
|
+
});
|
|
5124
5343
|
ap.process.kill("SIGTERM");
|
|
5125
5344
|
if (!silent) {
|
|
5126
5345
|
this.sendRuntimeProfileReportFor(agentId, ap.config, ap.sessionId, ap.launchId);
|
|
@@ -5411,7 +5630,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
5411
5630
|
attrs: {
|
|
5412
5631
|
agentId,
|
|
5413
5632
|
control_kind: kind,
|
|
5414
|
-
key_present: Boolean(key)
|
|
5633
|
+
key_present: Boolean(key),
|
|
5634
|
+
key_hash: hashRuntimeProfileKey(key)
|
|
5415
5635
|
}
|
|
5416
5636
|
});
|
|
5417
5637
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -5444,7 +5664,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
5444
5664
|
}
|
|
5445
5665
|
if (ap?.sessionId && ap.driver.supportsStdinNotification && ap.isIdle) {
|
|
5446
5666
|
ap.isIdle = false;
|
|
5447
|
-
this.startRuntimeTrace(agentId, ap, "runtime-profile");
|
|
5667
|
+
this.startRuntimeTrace(agentId, ap, "runtime-profile", [message]);
|
|
5448
5668
|
const written = this.deliverMessagesViaStdin(agentId, ap, [message], "idle");
|
|
5449
5669
|
span.end(written ? "ok" : "error", {
|
|
5450
5670
|
attrs: {
|
|
@@ -5539,6 +5759,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
5539
5759
|
agentId,
|
|
5540
5760
|
control_kind: control.kind,
|
|
5541
5761
|
key_present: Boolean(control.key),
|
|
5762
|
+
key_hash: hashRuntimeProfileKey(control.key),
|
|
5542
5763
|
launchId: launchId || void 0,
|
|
5543
5764
|
source: "agent_config"
|
|
5544
5765
|
}
|
|
@@ -5903,7 +6124,10 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
5903
6124
|
deliveryId: context.deliveryId,
|
|
5904
6125
|
delivery_correlation_id: context.deliveryId,
|
|
5905
6126
|
control_kind: notification.kind,
|
|
5906
|
-
key_present: Boolean(notification.key)
|
|
6127
|
+
key_present: Boolean(notification.key),
|
|
6128
|
+
runtime_profile_control_kind: notification.kind,
|
|
6129
|
+
runtime_profile_key_hash: hashRuntimeProfileKey(notification.key),
|
|
6130
|
+
runtime_profile_key_present: Boolean(notification.key)
|
|
5907
6131
|
};
|
|
5908
6132
|
}
|
|
5909
6133
|
return {
|
|
@@ -5914,8 +6138,63 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
5914
6138
|
delivery_correlation_id: context.deliveryId ?? first.message_id
|
|
5915
6139
|
};
|
|
5916
6140
|
}
|
|
6141
|
+
runtimeProfileTurnControlTraceAttrs(control) {
|
|
6142
|
+
if (!control) return {};
|
|
6143
|
+
const pendingAgeMs = Math.max(0, Date.now() - control.injectedAtMs);
|
|
6144
|
+
return {
|
|
6145
|
+
runtime_profile_control_kind: control.kind,
|
|
6146
|
+
runtime_profile_control_source: control.source,
|
|
6147
|
+
runtime_profile_key_hash: control.keyHash || void 0,
|
|
6148
|
+
runtime_profile_key_present: control.keyPresent,
|
|
6149
|
+
runtime_profile_pending_age_ms: pendingAgeMs,
|
|
6150
|
+
runtime_profile_requires_ack: control.kind === "migration",
|
|
6151
|
+
runtime_profile_migration_done_observed: control.kind === "migration" ? control.migrationDoneToolObserved : void 0
|
|
6152
|
+
};
|
|
6153
|
+
}
|
|
6154
|
+
activateRuntimeProfileTurnControl(ap, control) {
|
|
6155
|
+
ap.runtimeProfileTurnControl = control;
|
|
6156
|
+
}
|
|
6157
|
+
runtimeProfileTurnControlFromMessages(messages, source = "message") {
|
|
6158
|
+
const notifications = messages?.map((message) => runtimeProfileNotificationFromMessage(message)).filter((candidate) => Boolean(candidate)) ?? [];
|
|
6159
|
+
const notification = notifications.find((candidate) => candidate.kind === "migration") ?? notifications[0];
|
|
6160
|
+
if (!notification) return null;
|
|
6161
|
+
return runtimeProfileTurnControl(notification.kind, notification.key, source);
|
|
6162
|
+
}
|
|
6163
|
+
noteRuntimeProfileToolCall(agentId, ap, toolName) {
|
|
6164
|
+
const control = ap.runtimeProfileTurnControl;
|
|
6165
|
+
if (!control || control.kind !== "migration") return;
|
|
6166
|
+
if (!toolName.includes("runtime_profile_migration_done")) return;
|
|
6167
|
+
control.migrationDoneToolObserved = true;
|
|
6168
|
+
this.recordRuntimeTraceEvent(agentId, ap, "runtime_profile.migration_done_tool.observed", {
|
|
6169
|
+
...this.runtimeProfileTurnControlTraceAttrs(control),
|
|
6170
|
+
tool: toolName
|
|
6171
|
+
});
|
|
6172
|
+
}
|
|
6173
|
+
finalizeRuntimeProfileTurnControl(agentId, ap, terminal) {
|
|
6174
|
+
const control = ap.runtimeProfileTurnControl;
|
|
6175
|
+
if (!control) return {};
|
|
6176
|
+
const attrs = this.runtimeProfileTurnControlTraceAttrs(control);
|
|
6177
|
+
if (control.kind === "migration" && !control.migrationDoneToolObserved) {
|
|
6178
|
+
this.recordRuntimeTraceEvent(agentId, ap, "runtime_profile.migration.turn_without_ack", {
|
|
6179
|
+
...attrs,
|
|
6180
|
+
terminal,
|
|
6181
|
+
inbox_count: ap.inbox.length,
|
|
6182
|
+
pending_notification_count: ap.pendingNotificationCount
|
|
6183
|
+
});
|
|
6184
|
+
}
|
|
6185
|
+
ap.runtimeProfileTurnControl = null;
|
|
6186
|
+
return {
|
|
6187
|
+
...attrs,
|
|
6188
|
+
runtime_profile_turn_terminal: terminal,
|
|
6189
|
+
runtime_profile_turn_outcome: control.kind === "migration" ? control.migrationDoneToolObserved ? "migration_done_observed" : "missing_migration_done" : "notice_only"
|
|
6190
|
+
};
|
|
6191
|
+
}
|
|
5917
6192
|
startRuntimeTrace(agentId, ap, reason, messages) {
|
|
5918
6193
|
if (ap.runtimeTraceSpan) return ap.runtimeTraceSpan;
|
|
6194
|
+
const messageControl = this.runtimeProfileTurnControlFromMessages(messages);
|
|
6195
|
+
if (messageControl) {
|
|
6196
|
+
this.activateRuntimeProfileTurnControl(ap, messageControl);
|
|
6197
|
+
}
|
|
5919
6198
|
const span = this.tracer.startSpan("daemon.runtime.turn", {
|
|
5920
6199
|
surface: "daemon",
|
|
5921
6200
|
kind: "internal",
|
|
@@ -5925,10 +6204,15 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
5925
6204
|
model: ap.config.model,
|
|
5926
6205
|
reason,
|
|
5927
6206
|
hasSession: Boolean(ap.sessionId),
|
|
5928
|
-
...this.messagesTraceAttrs(messages)
|
|
6207
|
+
...this.messagesTraceAttrs(messages),
|
|
6208
|
+
...this.runtimeProfileTurnControlTraceAttrs(ap.runtimeProfileTurnControl)
|
|
5929
6209
|
}
|
|
5930
6210
|
});
|
|
5931
|
-
span.addEvent("daemon.turn.started", {
|
|
6211
|
+
span.addEvent("daemon.turn.started", {
|
|
6212
|
+
reason,
|
|
6213
|
+
...this.messagesTraceAttrs(messages),
|
|
6214
|
+
...this.runtimeProfileTurnControlTraceAttrs(ap.runtimeProfileTurnControl)
|
|
6215
|
+
});
|
|
5932
6216
|
ap.runtimeTraceSpan = span;
|
|
5933
6217
|
return span;
|
|
5934
6218
|
}
|
|
@@ -6034,7 +6318,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6034
6318
|
ageMs: staleForMs,
|
|
6035
6319
|
lastActivity: ap.lastActivity,
|
|
6036
6320
|
lastActivityDetailPresent: Boolean(ap.lastActivityDetail),
|
|
6037
|
-
lastActivityDetailKind: classifyActivityDetailForTrace(ap.lastActivityDetail)
|
|
6321
|
+
lastActivityDetailKind: classifyActivityDetailForTrace(ap.lastActivityDetail),
|
|
6322
|
+
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_stalled")
|
|
6038
6323
|
});
|
|
6039
6324
|
this.broadcastActivity(agentId, "error", diagnostic.detail);
|
|
6040
6325
|
return true;
|
|
@@ -6065,7 +6350,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6065
6350
|
lastActivityDetailPresent: Boolean(ap.lastActivityDetail),
|
|
6066
6351
|
lastActivityDetailKind: classifyActivityDetailForTrace(ap.lastActivityDetail),
|
|
6067
6352
|
pendingMessages: ap.inbox.length,
|
|
6068
|
-
recovery: "terminate_for_queued_message"
|
|
6353
|
+
recovery: "terminate_for_queued_message",
|
|
6354
|
+
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_stalled")
|
|
6069
6355
|
});
|
|
6070
6356
|
ap.expectedTerminationReason = "stalled_recovery";
|
|
6071
6357
|
const runtimeLabel = ap.driver.id === "opencode" ? "OpenCode" : ap.driver.id;
|
|
@@ -6074,6 +6360,11 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6074
6360
|
);
|
|
6075
6361
|
this.broadcastActivity(agentId, "working", `Restarting stalled ${runtimeLabel} runtime for queued message`);
|
|
6076
6362
|
try {
|
|
6363
|
+
this.processExitTraceAttrs.set(ap.process, {
|
|
6364
|
+
stop_source: "stalled_recovery",
|
|
6365
|
+
expectedTerminationReason: "stalled_recovery",
|
|
6366
|
+
queued_messages_count: ap.inbox.length
|
|
6367
|
+
});
|
|
6077
6368
|
ap.process.kill("SIGTERM");
|
|
6078
6369
|
} catch (err) {
|
|
6079
6370
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -6122,6 +6413,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6122
6413
|
if (ap) {
|
|
6123
6414
|
ap.gatedSteering.outstandingToolUses++;
|
|
6124
6415
|
this.clearGatedInFlightBatch(agentId, ap, "non_error_progress");
|
|
6416
|
+
this.noteRuntimeProfileToolCall(agentId, ap, invocation.toolName);
|
|
6125
6417
|
this.recordRuntimeTraceEvent(agentId, ap, "tool.call.started", { tool: invocation.toolName });
|
|
6126
6418
|
this.setGatedSteeringPhase(agentId, ap, "tool_wait", {
|
|
6127
6419
|
event: "tool_call",
|
|
@@ -6211,11 +6503,18 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6211
6503
|
this.broadcastActivity(agentId, "online", "Idle");
|
|
6212
6504
|
}
|
|
6213
6505
|
}
|
|
6214
|
-
this.endRuntimeTrace(ap, "ok", {
|
|
6506
|
+
this.endRuntimeTrace(ap, "ok", {
|
|
6507
|
+
outcome: "turn-completed",
|
|
6508
|
+
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "turn_end")
|
|
6509
|
+
});
|
|
6215
6510
|
if (ap.driver.terminateProcessOnTurnEnd) {
|
|
6216
6511
|
ap.expectedTerminationReason = "turn_end";
|
|
6217
6512
|
logger.info(`[Agent ${agentId}] Turn completed; terminating ${ap.driver.id} process`);
|
|
6218
6513
|
try {
|
|
6514
|
+
this.processExitTraceAttrs.set(ap.process, {
|
|
6515
|
+
stop_source: "turn_end",
|
|
6516
|
+
expectedTerminationReason: "turn_end"
|
|
6517
|
+
});
|
|
6219
6518
|
ap.process.kill("SIGTERM");
|
|
6220
6519
|
} catch (err) {
|
|
6221
6520
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -6233,6 +6532,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6233
6532
|
this.flushPendingTrajectory(agentId);
|
|
6234
6533
|
if (ap) ap.lastRuntimeError = event.message;
|
|
6235
6534
|
if (ap) {
|
|
6535
|
+
const runtimeErrorDiagnostics = buildRuntimeErrorDiagnosticEnvelope(event.message);
|
|
6236
6536
|
this.setGatedSteeringPhase(agentId, ap, "error", { event: "error" });
|
|
6237
6537
|
if (ap.driver.busyDeliveryMode === "gated" && this.isThinkingBlockMutationError(event.message)) {
|
|
6238
6538
|
this.requeueGatedInFlightBatch(agentId, ap, "thinking_block_mutation_error");
|
|
@@ -6246,8 +6546,12 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6246
6546
|
`[Agent ${agentId}] Disabled Claude tool-boundary gated steering after thinking-block mutation error; lastFlushReason=${ap.gatedSteering.lastFlushReason || "none"}`
|
|
6247
6547
|
);
|
|
6248
6548
|
}
|
|
6249
|
-
this.recordRuntimeTraceEvent(agentId, ap, "runtime.error",
|
|
6250
|
-
this.endRuntimeTrace(ap, "error", {
|
|
6549
|
+
this.recordRuntimeTraceEvent(agentId, ap, "runtime.error", runtimeErrorDiagnostics.eventAttrs);
|
|
6550
|
+
this.endRuntimeTrace(ap, "error", {
|
|
6551
|
+
outcome: "runtime-error",
|
|
6552
|
+
...runtimeErrorDiagnostics.spanAttrs,
|
|
6553
|
+
...this.finalizeRuntimeProfileTurnControl(agentId, ap, "runtime_error")
|
|
6554
|
+
});
|
|
6251
6555
|
if (ap.driver.supportsStdinNotification && classifyTerminalFailure(ap)) {
|
|
6252
6556
|
ap.isIdle = true;
|
|
6253
6557
|
ap.pendingNotificationCount = 0;
|
|
@@ -6721,11 +7025,10 @@ var ReminderCache = class {
|
|
|
6721
7025
|
};
|
|
6722
7026
|
|
|
6723
7027
|
// src/machineLock.ts
|
|
6724
|
-
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
7028
|
+
import { createHash as createHash3, randomUUID as randomUUID2 } from "crypto";
|
|
6725
7029
|
import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync2, statSync as statSync3, writeFileSync as writeFileSync8 } from "fs";
|
|
6726
7030
|
import os6 from "os";
|
|
6727
7031
|
import path12 from "path";
|
|
6728
|
-
var DEFAULT_MACHINE_STATE_ROOT = path12.join(os6.homedir(), ".slock", "machines");
|
|
6729
7032
|
var INCOMPLETE_LOCK_STALE_MS = 3e4;
|
|
6730
7033
|
var DaemonMachineLockConflictError = class extends Error {
|
|
6731
7034
|
code = "DAEMON_MACHINE_LOCK_HELD";
|
|
@@ -6738,11 +7041,14 @@ var DaemonMachineLockConflictError = class extends Error {
|
|
|
6738
7041
|
}
|
|
6739
7042
|
};
|
|
6740
7043
|
function apiKeyFingerprint(apiKey) {
|
|
6741
|
-
return
|
|
7044
|
+
return createHash3("sha256").update(apiKey).digest("hex");
|
|
6742
7045
|
}
|
|
6743
7046
|
function getDaemonMachineLockId(apiKey) {
|
|
6744
7047
|
return `machine-${apiKeyFingerprint(apiKey).slice(0, 16)}`;
|
|
6745
7048
|
}
|
|
7049
|
+
function resolveDefaultMachineStateRoot() {
|
|
7050
|
+
return resolveSlockHomePath("machines");
|
|
7051
|
+
}
|
|
6746
7052
|
function ownerPath(lockDir) {
|
|
6747
7053
|
return path12.join(lockDir, "owner.json");
|
|
6748
7054
|
}
|
|
@@ -6771,7 +7077,7 @@ function isProcessAlive(pid) {
|
|
|
6771
7077
|
}
|
|
6772
7078
|
}
|
|
6773
7079
|
function acquireDaemonMachineLock(options) {
|
|
6774
|
-
const rootDir = options.rootDir ??
|
|
7080
|
+
const rootDir = options.rootDir ?? resolveDefaultMachineStateRoot();
|
|
6775
7081
|
const fingerprint = apiKeyFingerprint(options.apiKey);
|
|
6776
7082
|
const lockId = getDaemonMachineLockId(options.apiKey);
|
|
6777
7083
|
const machineDir = path12.join(rootDir, lockId);
|
|
@@ -6830,6 +7136,7 @@ function acquireDaemonMachineLock(options) {
|
|
|
6830
7136
|
import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync3, rmSync as rmSync3, statSync as statSync4, writeFileSync as writeFileSync9 } from "fs";
|
|
6831
7137
|
import path13 from "path";
|
|
6832
7138
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
7139
|
+
var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
|
|
6833
7140
|
var DEFAULT_MAX_FILES = 8;
|
|
6834
7141
|
var DIAGNOSTIC_ID_ATTRS = /* @__PURE__ */ new Set([
|
|
6835
7142
|
"serverId",
|
|
@@ -6843,17 +7150,37 @@ var DIAGNOSTIC_ID_ATTRS = /* @__PURE__ */ new Set([
|
|
|
6843
7150
|
"deliveryCorrelationId",
|
|
6844
7151
|
"delivery_correlation_id"
|
|
6845
7152
|
]);
|
|
7153
|
+
var DIAGNOSTIC_ERROR_ATTRS = /* @__PURE__ */ new Set([
|
|
7154
|
+
"runtime_error_class",
|
|
7155
|
+
"runtime_error_fingerprint",
|
|
7156
|
+
"runtime_error_http_status",
|
|
7157
|
+
"runtime_error_message_present",
|
|
7158
|
+
"runtime_error_message_length_bucket",
|
|
7159
|
+
"runtime_error_message_truncated",
|
|
7160
|
+
"runtime_error_message_excerpt"
|
|
7161
|
+
]);
|
|
6846
7162
|
var LocalRotatingTraceSink = class {
|
|
6847
7163
|
traceDir;
|
|
6848
7164
|
maxFileBytes;
|
|
7165
|
+
maxFileAgeMs;
|
|
6849
7166
|
maxFiles;
|
|
7167
|
+
nowMsProvider;
|
|
6850
7168
|
currentFile = null;
|
|
7169
|
+
currentFileOpenedAtMs = null;
|
|
6851
7170
|
currentSize = 0;
|
|
6852
7171
|
sequence = 0;
|
|
6853
7172
|
constructor(options) {
|
|
6854
7173
|
this.traceDir = path13.join(options.machineDir, "traces");
|
|
6855
7174
|
this.maxFileBytes = Math.max(1024, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES));
|
|
7175
|
+
const baseAgeMs = Math.max(1e3, Math.floor(options.maxFileAgeMs ?? DEFAULT_MAX_FILE_AGE_MS));
|
|
7176
|
+
const ageJitterMs = Math.max(0, Math.floor(options.maxFileAgeJitterMs ?? 0));
|
|
7177
|
+
this.maxFileAgeMs = baseAgeMs + ageJitterMs;
|
|
6856
7178
|
this.maxFiles = Math.max(1, Math.floor(options.maxFiles ?? DEFAULT_MAX_FILES));
|
|
7179
|
+
this.nowMsProvider = options.nowMsProvider ?? Date.now;
|
|
7180
|
+
}
|
|
7181
|
+
/** Exposed for observability — the effective rotation age after jitter. */
|
|
7182
|
+
getMaxFileAgeMs() {
|
|
7183
|
+
return this.maxFileAgeMs;
|
|
6857
7184
|
}
|
|
6858
7185
|
record(span) {
|
|
6859
7186
|
try {
|
|
@@ -6870,13 +7197,16 @@ var LocalRotatingTraceSink = class {
|
|
|
6870
7197
|
}
|
|
6871
7198
|
ensureFile(nextBytes) {
|
|
6872
7199
|
mkdirSync6(this.traceDir, { recursive: true, mode: 448 });
|
|
6873
|
-
|
|
7200
|
+
const nowMs = this.nowMsProvider();
|
|
7201
|
+
const shouldRotateForAge = this.currentFileOpenedAtMs !== null && nowMs - this.currentFileOpenedAtMs >= this.maxFileAgeMs;
|
|
7202
|
+
if (!this.currentFile || this.currentSize + nextBytes > this.maxFileBytes || shouldRotateForAge) {
|
|
6874
7203
|
this.currentFile = path13.join(
|
|
6875
7204
|
this.traceDir,
|
|
6876
|
-
`daemon-trace-${safeTimestamp(
|
|
7205
|
+
`daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
|
|
6877
7206
|
);
|
|
6878
7207
|
writeFileSync9(this.currentFile, "", { flag: "a", mode: 384 });
|
|
6879
7208
|
this.currentSize = statSync4(this.currentFile).size;
|
|
7209
|
+
this.currentFileOpenedAtMs = nowMs;
|
|
6880
7210
|
this.pruneOldFiles();
|
|
6881
7211
|
}
|
|
6882
7212
|
}
|
|
@@ -6926,6 +7256,11 @@ function sanitizeAttrs(attrs) {
|
|
|
6926
7256
|
sanitized[key] = sanitizeValue(value);
|
|
6927
7257
|
continue;
|
|
6928
7258
|
}
|
|
7259
|
+
if (isDiagnosticErrorAttr(key)) {
|
|
7260
|
+
if (value === null || value === void 0 || value === "") continue;
|
|
7261
|
+
sanitized[key] = sanitizeValue(value);
|
|
7262
|
+
continue;
|
|
7263
|
+
}
|
|
6929
7264
|
if (shouldDropAttr(key)) continue;
|
|
6930
7265
|
sanitized[key] = sanitizeValue(value);
|
|
6931
7266
|
}
|
|
@@ -6959,9 +7294,12 @@ function shouldDropAttr(key) {
|
|
|
6959
7294
|
function isDiagnosticIdAttr(key) {
|
|
6960
7295
|
return DIAGNOSTIC_ID_ATTRS.has(key);
|
|
6961
7296
|
}
|
|
7297
|
+
function isDiagnosticErrorAttr(key) {
|
|
7298
|
+
return DIAGNOSTIC_ERROR_ATTRS.has(key);
|
|
7299
|
+
}
|
|
6962
7300
|
|
|
6963
7301
|
// src/traceBundleUpload.ts
|
|
6964
|
-
import { createHash as
|
|
7302
|
+
import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
|
|
6965
7303
|
import { gzipSync } from "zlib";
|
|
6966
7304
|
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
6967
7305
|
import path14 from "path";
|
|
@@ -7090,6 +7428,35 @@ async function uploadWithSignedCapability({
|
|
|
7090
7428
|
return { capability, session, uploadResponse };
|
|
7091
7429
|
}
|
|
7092
7430
|
|
|
7431
|
+
// src/traceJitter.ts
|
|
7432
|
+
import { createHash as createHash4 } from "crypto";
|
|
7433
|
+
var INITIAL_UPLOAD_DELAY_SPAN_MS = 3e4;
|
|
7434
|
+
var UPLOAD_INTERVAL_JITTER_SPAN_MS = 6e4;
|
|
7435
|
+
var MAX_FILE_AGE_JITTER_SPAN_MS = 6e4;
|
|
7436
|
+
function computeTraceJitter(lockId) {
|
|
7437
|
+
const seed = createHash4("sha256").update(lockId).digest();
|
|
7438
|
+
return {
|
|
7439
|
+
initialUploadDelayMs: seed.readUInt32BE(0) % INITIAL_UPLOAD_DELAY_SPAN_MS,
|
|
7440
|
+
uploadIntervalJitterMs: seed.readUInt32BE(4) % UPLOAD_INTERVAL_JITTER_SPAN_MS,
|
|
7441
|
+
maxFileAgeJitterMs: seed.readUInt32BE(8) % MAX_FILE_AGE_JITTER_SPAN_MS
|
|
7442
|
+
};
|
|
7443
|
+
}
|
|
7444
|
+
var NO_JITTER = {
|
|
7445
|
+
initialUploadDelayMs: 0,
|
|
7446
|
+
uploadIntervalJitterMs: 0,
|
|
7447
|
+
maxFileAgeJitterMs: 0
|
|
7448
|
+
};
|
|
7449
|
+
function bucketDelayMs(delayMs) {
|
|
7450
|
+
if (delayMs < 1e3) return "0-1s";
|
|
7451
|
+
if (delayMs < 5e3) return "1-5s";
|
|
7452
|
+
if (delayMs < 15e3) return "5-15s";
|
|
7453
|
+
if (delayMs < 3e4) return "15-30s";
|
|
7454
|
+
if (delayMs < 6e4) return "30-60s";
|
|
7455
|
+
if (delayMs < 3e5) return "60s-5m";
|
|
7456
|
+
if (delayMs < 6e5) return "5-10m";
|
|
7457
|
+
return "10m+";
|
|
7458
|
+
}
|
|
7459
|
+
|
|
7093
7460
|
// src/traceBundleUpload.ts
|
|
7094
7461
|
var TRACE_UPLOAD_SCOPE = "daemon-trace-bundle:create";
|
|
7095
7462
|
var DEFAULT_UPLOAD_INTERVAL_MS = 5 * 60 * 1e3;
|
|
@@ -7097,30 +7464,66 @@ var DEFAULT_MIN_FILE_AGE_MS = 60 * 1e3;
|
|
|
7097
7464
|
var DEFAULT_MAX_FILES_PER_RUN = 4;
|
|
7098
7465
|
var DaemonTraceBundleUploader = class {
|
|
7099
7466
|
options;
|
|
7100
|
-
|
|
7467
|
+
jitter;
|
|
7468
|
+
timers;
|
|
7469
|
+
initialDelayTimer = null;
|
|
7470
|
+
intervalTimer = null;
|
|
7471
|
+
stopped = false;
|
|
7101
7472
|
constructor(options) {
|
|
7102
7473
|
this.options = options;
|
|
7474
|
+
this.jitter = options.jitter ?? (options.lockId ? computeTraceJitter(options.lockId) : NO_JITTER);
|
|
7475
|
+
this.timers = options.timers ?? {
|
|
7476
|
+
setTimeout: globalThis.setTimeout.bind(globalThis),
|
|
7477
|
+
setInterval: globalThis.setInterval.bind(globalThis),
|
|
7478
|
+
clearTimeout: globalThis.clearTimeout.bind(globalThis),
|
|
7479
|
+
clearInterval: globalThis.clearInterval.bind(globalThis)
|
|
7480
|
+
};
|
|
7103
7481
|
}
|
|
7104
7482
|
start() {
|
|
7105
|
-
if (this.
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7483
|
+
if (this.stopped) return;
|
|
7484
|
+
if (this.initialDelayTimer || this.intervalTimer) return;
|
|
7485
|
+
const initialDelayMs = this.jitter.initialUploadDelayMs;
|
|
7486
|
+
this.initialDelayTimer = this.timers.setTimeout(() => {
|
|
7487
|
+
this.initialDelayTimer = null;
|
|
7488
|
+
if (this.stopped) return;
|
|
7489
|
+
void this.uploadOnce("initial");
|
|
7490
|
+
this.scheduleNextTick();
|
|
7491
|
+
}, initialDelayMs);
|
|
7110
7492
|
}
|
|
7111
7493
|
stop() {
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7494
|
+
this.stopped = true;
|
|
7495
|
+
if (this.initialDelayTimer) {
|
|
7496
|
+
this.timers.clearTimeout(this.initialDelayTimer);
|
|
7497
|
+
this.initialDelayTimer = null;
|
|
7498
|
+
}
|
|
7499
|
+
if (this.intervalTimer) {
|
|
7500
|
+
this.timers.clearTimeout(this.intervalTimer);
|
|
7501
|
+
this.intervalTimer = null;
|
|
7502
|
+
}
|
|
7115
7503
|
}
|
|
7116
|
-
|
|
7504
|
+
/**
|
|
7505
|
+
* Drive a single upload pass. `trigger` is surfaced as a span attribute so
|
|
7506
|
+
* we can distinguish startup drain vs steady-state ticks in ScopeDB.
|
|
7507
|
+
*/
|
|
7508
|
+
async uploadOnce(trigger = "manual") {
|
|
7117
7509
|
const files = await this.findUploadCandidates();
|
|
7118
7510
|
let uploaded = 0;
|
|
7119
7511
|
for (const file of files.slice(0, this.options.maxFilesPerRun ?? DEFAULT_MAX_FILES_PER_RUN)) {
|
|
7120
|
-
if (await this.uploadFile(file)) uploaded += 1;
|
|
7512
|
+
if (await this.uploadFile(file, trigger)) uploaded += 1;
|
|
7121
7513
|
}
|
|
7122
7514
|
return { attempted: files.length, uploaded };
|
|
7123
7515
|
}
|
|
7516
|
+
scheduleNextTick() {
|
|
7517
|
+
if (this.stopped) return;
|
|
7518
|
+
const baseIntervalMs = this.options.intervalMs ?? readPositiveIntegerEnv2("SLOCK_DAEMON_TRACE_UPLOAD_INTERVAL_MS", DEFAULT_UPLOAD_INTERVAL_MS);
|
|
7519
|
+
const nextMs = baseIntervalMs + this.jitter.uploadIntervalJitterMs;
|
|
7520
|
+
this.intervalTimer = this.timers.setTimeout(() => {
|
|
7521
|
+
this.intervalTimer = null;
|
|
7522
|
+
if (this.stopped) return;
|
|
7523
|
+
void this.uploadOnce("interval");
|
|
7524
|
+
this.scheduleNextTick();
|
|
7525
|
+
}, nextMs);
|
|
7526
|
+
}
|
|
7124
7527
|
async findUploadCandidates() {
|
|
7125
7528
|
const traceDir = path14.join(this.options.machineDir, "traces");
|
|
7126
7529
|
let names;
|
|
@@ -7147,13 +7550,16 @@ var DaemonTraceBundleUploader = class {
|
|
|
7147
7550
|
}
|
|
7148
7551
|
return candidates;
|
|
7149
7552
|
}
|
|
7150
|
-
async uploadFile(file) {
|
|
7553
|
+
async uploadFile(file, trigger) {
|
|
7151
7554
|
const span = this.options.tracer?.startSpan("daemon.bundle.upload", {
|
|
7152
7555
|
surface: "daemon",
|
|
7153
7556
|
kind: "producer",
|
|
7154
7557
|
attrs: {
|
|
7155
7558
|
file_present: true,
|
|
7156
|
-
worker_url_present: Boolean(this.options.workerUrl)
|
|
7559
|
+
worker_url_present: Boolean(this.options.workerUrl),
|
|
7560
|
+
upload_trigger: trigger,
|
|
7561
|
+
initial_delay_ms_bucket: bucketDelayMs(this.jitter.initialUploadDelayMs),
|
|
7562
|
+
interval_jitter_ms_bucket: bucketDelayMs(this.jitter.uploadIntervalJitterMs)
|
|
7157
7563
|
}
|
|
7158
7564
|
});
|
|
7159
7565
|
try {
|
|
@@ -7229,7 +7635,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
7229
7635
|
}
|
|
7230
7636
|
};
|
|
7231
7637
|
function sha256Hex(body) {
|
|
7232
|
-
return
|
|
7638
|
+
return createHash5("sha256").update(body).digest("hex");
|
|
7233
7639
|
}
|
|
7234
7640
|
function readPositiveIntegerEnv2(name, fallback) {
|
|
7235
7641
|
const value = process.env[name];
|
|
@@ -7239,6 +7645,7 @@ function readPositiveIntegerEnv2(name, fallback) {
|
|
|
7239
7645
|
}
|
|
7240
7646
|
|
|
7241
7647
|
// src/core.ts
|
|
7648
|
+
var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
|
|
7242
7649
|
var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
|
|
7243
7650
|
function parseDaemonCliArgs(args) {
|
|
7244
7651
|
let serverUrl = "";
|
|
@@ -7407,6 +7814,7 @@ var DaemonCore = class {
|
|
|
7407
7814
|
daemonVersion;
|
|
7408
7815
|
chatBridgePath;
|
|
7409
7816
|
slockCliPath;
|
|
7817
|
+
slockHome;
|
|
7410
7818
|
runtimeDetector;
|
|
7411
7819
|
agentManager;
|
|
7412
7820
|
connection;
|
|
@@ -7421,6 +7829,8 @@ var DaemonCore = class {
|
|
|
7421
7829
|
this.daemonVersion = options.daemonVersion ?? readDaemonVersion();
|
|
7422
7830
|
this.chatBridgePath = options.chatBridgePath ?? resolveChatBridgePath();
|
|
7423
7831
|
this.slockCliPath = options.slockCliPath ?? resolveSlockCliPath();
|
|
7832
|
+
this.slockHome = resolveSlockHome();
|
|
7833
|
+
process.env[SLOCK_HOME_ENV] = this.slockHome;
|
|
7424
7834
|
this.injectedTracer = Boolean(options.tracer);
|
|
7425
7835
|
this.tracer = options.tracer ?? noopTracer;
|
|
7426
7836
|
this.runtimeDetector = options.runtimeDetector ?? (() => detectRuntimes(this.tracer));
|
|
@@ -7430,7 +7840,7 @@ var DaemonCore = class {
|
|
|
7430
7840
|
});
|
|
7431
7841
|
let connection;
|
|
7432
7842
|
const agentManagerOptions = {
|
|
7433
|
-
dataDir: options.dataDir,
|
|
7843
|
+
dataDir: options.dataDir ?? resolveSlockHomePath("agents", this.slockHome),
|
|
7434
7844
|
serverUrl: options.serverUrl,
|
|
7435
7845
|
defaultAgentEnvVarsProvider: options.defaultAgentEnvVarsProvider,
|
|
7436
7846
|
slockCliPath: this.slockCliPath,
|
|
@@ -7452,18 +7862,25 @@ var DaemonCore = class {
|
|
|
7452
7862
|
resolveMachineStateRoot() {
|
|
7453
7863
|
if (this.options.machineStateDir) return this.options.machineStateDir;
|
|
7454
7864
|
if (this.options.dataDir) return path15.join(path15.dirname(this.options.dataDir), "machines");
|
|
7455
|
-
return
|
|
7865
|
+
return resolveDefaultMachineStateRoot();
|
|
7456
7866
|
}
|
|
7457
7867
|
shouldEnableLocalTrace() {
|
|
7458
7868
|
if (this.injectedTracer) return false;
|
|
7459
7869
|
if (!this.options.localTrace) return false;
|
|
7460
7870
|
return process.env.SLOCK_DAEMON_LOCAL_TRACE !== "0";
|
|
7461
7871
|
}
|
|
7872
|
+
resolveTraceJitter() {
|
|
7873
|
+
const lockId = this.machineLock?.lockId;
|
|
7874
|
+
return lockId ? computeTraceJitter(lockId) : NO_JITTER;
|
|
7875
|
+
}
|
|
7462
7876
|
installLocalTraceSink(machineDir) {
|
|
7463
7877
|
if (!this.shouldEnableLocalTrace()) return;
|
|
7878
|
+
const jitter = this.resolveTraceJitter();
|
|
7464
7879
|
this.localTraceSink = new LocalRotatingTraceSink({
|
|
7465
7880
|
machineDir,
|
|
7466
7881
|
maxFileBytes: this.options.localTraceMaxFileBytes ?? readPositiveIntegerEnv3("SLOCK_DAEMON_TRACE_MAX_FILE_BYTES", 5 * 1024 * 1024),
|
|
7882
|
+
maxFileAgeMs: this.options.localTraceMaxFileAgeMs ?? readPositiveIntegerEnv3("SLOCK_DAEMON_TRACE_MAX_FILE_AGE_MS", 5 * 60 * 1e3),
|
|
7883
|
+
maxFileAgeJitterMs: jitter.maxFileAgeJitterMs,
|
|
7467
7884
|
maxFiles: this.options.localTraceMaxFiles ?? readPositiveIntegerEnv3("SLOCK_DAEMON_TRACE_MAX_FILES", 8)
|
|
7468
7885
|
});
|
|
7469
7886
|
this.tracer = new BasicTracer({
|
|
@@ -7474,20 +7891,27 @@ var DaemonCore = class {
|
|
|
7474
7891
|
installTraceBundleUploader(machineDir) {
|
|
7475
7892
|
if (!this.shouldEnableLocalTrace()) return;
|
|
7476
7893
|
if (this.traceBundleUploader) return;
|
|
7477
|
-
|
|
7478
|
-
|
|
7894
|
+
if (process.env.SLOCK_DAEMON_TRACE_UPLOAD_DISABLED === "1") return;
|
|
7895
|
+
const workerUrl = process.env.SLOCK_DAEMON_TRACE_UPLOAD_URL || DEFAULT_TRACE_UPLOAD_URL;
|
|
7479
7896
|
this.traceBundleUploader = new DaemonTraceBundleUploader({
|
|
7480
7897
|
machineDir,
|
|
7481
7898
|
serverUrl: this.options.serverUrl,
|
|
7482
7899
|
apiKey: this.options.apiKey,
|
|
7483
7900
|
workerUrl,
|
|
7484
7901
|
tracer: this.tracer,
|
|
7485
|
-
currentFileProvider: () => this.localTraceSink?.getCurrentFile() ?? null
|
|
7902
|
+
currentFileProvider: () => this.localTraceSink?.getCurrentFile() ?? null,
|
|
7903
|
+
lockId: this.machineLock?.lockId
|
|
7486
7904
|
});
|
|
7487
7905
|
this.traceBundleUploader.start();
|
|
7488
7906
|
}
|
|
7489
7907
|
start() {
|
|
7490
7908
|
logger.info("[Slock Daemon] Starting...");
|
|
7909
|
+
logger.info(`[Slock Daemon] ${SLOCK_HOME_ENV}=${this.slockHome}`);
|
|
7910
|
+
for (const legacy of listLegacySlockStatePaths(this.slockHome)) {
|
|
7911
|
+
logger.warn(
|
|
7912
|
+
`[Slock Daemon] Legacy Slock state exists outside ${SLOCK_HOME_ENV}: ${legacy.path}. This daemon will use ${legacy.destination}; migrate manually if that ${legacy.description} should move with this installation.`
|
|
7913
|
+
);
|
|
7914
|
+
}
|
|
7491
7915
|
if (!this.machineLock) {
|
|
7492
7916
|
this.machineLock = acquireDaemonMachineLock({
|
|
7493
7917
|
apiKey: this.options.apiKey,
|
|
@@ -207,6 +207,45 @@ async function executeResponseRequest(url, init, {
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
// src/slockHome.ts
|
|
211
|
+
import os from "os";
|
|
212
|
+
import path from "path";
|
|
213
|
+
import { existsSync } from "fs";
|
|
214
|
+
var SLOCK_HOME_ENV = "SLOCK_HOME";
|
|
215
|
+
function resolveDefaultSlockHome(homeDir = os.homedir()) {
|
|
216
|
+
return path.resolve(path.join(homeDir, ".slock"));
|
|
217
|
+
}
|
|
218
|
+
function resolveSlockHome(env = process.env, homeDir = os.homedir()) {
|
|
219
|
+
const raw = env[SLOCK_HOME_ENV]?.trim();
|
|
220
|
+
const root = raw && raw.length > 0 ? raw : resolveDefaultSlockHome(homeDir);
|
|
221
|
+
return path.resolve(root);
|
|
222
|
+
}
|
|
223
|
+
function resolveSlockHomePath(childPath, slockHome = resolveSlockHome()) {
|
|
224
|
+
return path.join(slockHome, childPath);
|
|
225
|
+
}
|
|
226
|
+
function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.homedir()) {
|
|
227
|
+
const defaultHome = resolveDefaultSlockHome(homeDir);
|
|
228
|
+
if (path.resolve(slockHome) === defaultHome) return [];
|
|
229
|
+
const candidates = [
|
|
230
|
+
{
|
|
231
|
+
path: path.join(defaultHome, "agents"),
|
|
232
|
+
destination: path.join(slockHome, "agents"),
|
|
233
|
+
description: "agent workspaces and per-agent runtime wrapper state"
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
path: path.join(defaultHome, "machines"),
|
|
237
|
+
destination: path.join(slockHome, "machines"),
|
|
238
|
+
description: "daemon machine locks, local traces, and machine-scoped state"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
path: path.join(defaultHome, "attachments"),
|
|
242
|
+
destination: path.join(slockHome, "attachments"),
|
|
243
|
+
description: "chat bridge attachment download cache"
|
|
244
|
+
}
|
|
245
|
+
];
|
|
246
|
+
return candidates.filter((candidate) => existsSync(candidate.path));
|
|
247
|
+
}
|
|
248
|
+
|
|
210
249
|
export {
|
|
211
250
|
subscribeDaemonLogs,
|
|
212
251
|
logger,
|
|
@@ -214,5 +253,9 @@ export {
|
|
|
214
253
|
buildFetchDispatcher,
|
|
215
254
|
DEFAULT_CHAT_BRIDGE_TOOL_TIMEOUT_MS,
|
|
216
255
|
executeJsonRequest,
|
|
217
|
-
executeResponseRequest
|
|
256
|
+
executeResponseRequest,
|
|
257
|
+
SLOCK_HOME_ENV,
|
|
258
|
+
resolveSlockHome,
|
|
259
|
+
resolveSlockHomePath,
|
|
260
|
+
listLegacySlockStatePaths
|
|
218
261
|
};
|
package/dist/core.js
CHANGED
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
resolveSlockCliPath,
|
|
10
10
|
resolveWorkspaceDirectoryPath,
|
|
11
11
|
scanWorkspaceDirectories
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7EZVMA2D.js";
|
|
13
13
|
import {
|
|
14
14
|
subscribeDaemonLogs
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-B7XIMLOT.js";
|
|
16
16
|
export {
|
|
17
17
|
DAEMON_CLI_USAGE,
|
|
18
18
|
DaemonCore,
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
DAEMON_CLI_USAGE,
|
|
4
4
|
DaemonCore,
|
|
5
5
|
parseDaemonCliArgs
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-7EZVMA2D.js";
|
|
7
|
+
import "./chunk-B7XIMLOT.js";
|
|
8
8
|
|
|
9
9
|
// src/index.ts
|
|
10
10
|
var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
|