@slock-ai/daemon 0.54.2-play.20260528162546 → 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-MWGRDZGK.js → chunk-6Q3U5STT.js} +95 -497
- package/dist/cli/index.js +1144 -685
- package/dist/core.js +2 -6
- package/dist/index.js +3 -5
- package/package.json +1 -2
- package/dist/drivers/piSdkRunner.js +0 -96
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
} from "./chunk-VOZJ2ELH.js";
|
|
9
9
|
|
|
10
10
|
// src/core.ts
|
|
11
|
-
import
|
|
11
|
+
import path16 from "path";
|
|
12
12
|
import os7 from "os";
|
|
13
13
|
import { createRequire as createRequire2 } from "module";
|
|
14
14
|
import { accessSync } from "fs";
|
|
15
|
-
import { fileURLToPath
|
|
15
|
+
import { fileURLToPath } from "url";
|
|
16
16
|
|
|
17
17
|
// ../shared/src/slockRefs.ts
|
|
18
18
|
var SLOCK_REF_CHANNEL_NAME_PATTERN = String.raw`[\p{L}\p{N}_-]+`;
|
|
@@ -752,7 +752,6 @@ var RUNTIME_CONFIG_VERSION = 1;
|
|
|
752
752
|
var RUNTIMES = [
|
|
753
753
|
{ id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
|
|
754
754
|
{ id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
|
|
755
|
-
{ id: "pi", displayName: "Pi", binary: "pi", supported: true },
|
|
756
755
|
{ id: "antigravity", displayName: "Antigravity CLI", binary: "agy", supported: true },
|
|
757
756
|
{ id: "kimi", displayName: "Kimi CLI", binary: "kimi", supported: true },
|
|
758
757
|
{ id: "copilot", displayName: "Copilot CLI", binary: "copilot", supported: true },
|
|
@@ -805,13 +804,6 @@ var RUNTIME_MODELS = {
|
|
|
805
804
|
{ id: "openrouter/anthropic/claude-opus-4.5", label: "Claude Opus 4.5 via OpenRouter", verified: "suggestion_only" },
|
|
806
805
|
{ id: "fusecode/opus[1m]", label: "Opus 1M via FuseCode", verified: "suggestion_only" }
|
|
807
806
|
],
|
|
808
|
-
pi: [
|
|
809
|
-
{ id: "deepseek/deepseek-v4-pro", label: "DeepSeek V4 Pro" },
|
|
810
|
-
{ id: "deepseek/deepseek-v4-flash", label: "DeepSeek V4 Flash" },
|
|
811
|
-
{ id: "kimi-coding/kimi-for-coding", label: "Kimi for Coding" },
|
|
812
|
-
{ id: "zai/glm-5.1", label: "GLM-5.1" },
|
|
813
|
-
{ id: "zai/glm-4.7", label: "GLM-4.7" }
|
|
814
|
-
],
|
|
815
807
|
// Kimi CLI resolves model keys from each user's local config, so the safest
|
|
816
808
|
// built-in option is to defer to whatever default model the CLI already uses.
|
|
817
809
|
kimi: [
|
|
@@ -960,10 +952,10 @@ var DISPLAY_PLAN_CONFIG = {
|
|
|
960
952
|
};
|
|
961
953
|
|
|
962
954
|
// src/agentProcessManager.ts
|
|
963
|
-
import { mkdirSync as
|
|
955
|
+
import { mkdirSync as mkdirSync4, readdirSync, statSync, writeFileSync as writeFileSync7 } from "fs";
|
|
964
956
|
import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2 } from "fs/promises";
|
|
965
957
|
import { createHash as createHash2 } from "crypto";
|
|
966
|
-
import
|
|
958
|
+
import path12 from "path";
|
|
967
959
|
import os5 from "os";
|
|
968
960
|
|
|
969
961
|
// src/drivers/claude.ts
|
|
@@ -1547,19 +1539,6 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
|
|
|
1547
1539
|
return candidates.filter((candidate) => existsSync(candidate.path));
|
|
1548
1540
|
}
|
|
1549
1541
|
|
|
1550
|
-
// src/authEnv.ts
|
|
1551
|
-
var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
|
|
1552
|
-
var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
|
|
1553
|
-
function scrubDaemonAuthEnv(env) {
|
|
1554
|
-
delete env[DAEMON_API_KEY_ENV];
|
|
1555
|
-
return env;
|
|
1556
|
-
}
|
|
1557
|
-
function scrubDaemonChildEnv(env) {
|
|
1558
|
-
delete env[DAEMON_API_KEY_ENV];
|
|
1559
|
-
delete env[SLOCK_AGENT_TOKEN_ENV];
|
|
1560
|
-
return env;
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
1542
|
// src/agentCredentialProxy.ts
|
|
1564
1543
|
import { randomBytes } from "crypto";
|
|
1565
1544
|
import http from "http";
|
|
@@ -2154,9 +2133,7 @@ var DEFAULT_ACTIVE_CAPABILITIES = "send,read,mentions,tasks,reactions,server,cha
|
|
|
2154
2133
|
var LOOPBACK_NO_PROXY = "127.0.0.1,localhost";
|
|
2155
2134
|
var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
2156
2135
|
var RAW_CREDENTIAL_ENV_DENYLIST = [
|
|
2157
|
-
"
|
|
2158
|
-
"SLOCK_AGENT_CREDENTIAL_KEY",
|
|
2159
|
-
"SLOCK_AGENT_CREDENTIAL_KEY_FILE"
|
|
2136
|
+
"SLOCK_AGENT_CREDENTIAL_KEY"
|
|
2160
2137
|
];
|
|
2161
2138
|
var cachedOpencliBinPath;
|
|
2162
2139
|
function resolveOpencliBinPath() {
|
|
@@ -2370,7 +2347,7 @@ exec ${shellSingleQuote(process.execPath)} ${shellSingleQuote(opencliBinPath)} "
|
|
|
2370
2347
|
...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
|
|
2371
2348
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
2372
2349
|
};
|
|
2373
|
-
|
|
2350
|
+
delete spawnEnv.SLOCK_AGENT_TOKEN;
|
|
2374
2351
|
for (const key of RAW_CREDENTIAL_ENV_DENYLIST) {
|
|
2375
2352
|
delete spawnEnv[key];
|
|
2376
2353
|
}
|
|
@@ -2669,7 +2646,7 @@ function resolveCommandOnWindows(command, env, execFileSyncFn, existsSyncFn) {
|
|
|
2669
2646
|
}
|
|
2670
2647
|
function resolveCommandOnPath(command, deps = {}) {
|
|
2671
2648
|
const platform = deps.platform ?? process.platform;
|
|
2672
|
-
const env =
|
|
2649
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
2673
2650
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
2674
2651
|
const existsSyncFn = deps.existsSyncFn ?? existsSync2;
|
|
2675
2652
|
if (platform === "win32") {
|
|
@@ -2695,7 +2672,7 @@ function firstExistingPath(candidates, deps = {}) {
|
|
|
2695
2672
|
return null;
|
|
2696
2673
|
}
|
|
2697
2674
|
function readCommandVersion(command, args = [], deps = {}) {
|
|
2698
|
-
const env =
|
|
2675
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
2699
2676
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
2700
2677
|
try {
|
|
2701
2678
|
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
@@ -4126,11 +4103,11 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
|
|
|
4126
4103
|
return parseCursorModelsOutput(String(result.stdout || ""));
|
|
4127
4104
|
}
|
|
4128
4105
|
function buildCursorModelProbeEnv(deps = {}) {
|
|
4129
|
-
return
|
|
4106
|
+
return withWindowsUserEnvironment({
|
|
4130
4107
|
...deps.env ?? process.env,
|
|
4131
4108
|
FORCE_COLOR: "0",
|
|
4132
4109
|
NO_COLOR: "1"
|
|
4133
|
-
}, deps)
|
|
4110
|
+
}, deps);
|
|
4134
4111
|
}
|
|
4135
4112
|
function runCursorModelsCommand() {
|
|
4136
4113
|
return spawnSync("cursor-agent", ["models"], {
|
|
@@ -4186,7 +4163,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
4186
4163
|
}
|
|
4187
4164
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
4188
4165
|
const existsSyncFn = deps.existsSyncFn ?? existsSync5;
|
|
4189
|
-
const env =
|
|
4166
|
+
const env = deps.env ?? process.env;
|
|
4190
4167
|
const winPath = path8.win32;
|
|
4191
4168
|
let geminiEntry = null;
|
|
4192
4169
|
try {
|
|
@@ -4358,16 +4335,13 @@ var GeminiDriver = class {
|
|
|
4358
4335
|
// src/drivers/kimi.ts
|
|
4359
4336
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4360
4337
|
import { spawn as spawn7 } from "child_process";
|
|
4361
|
-
import {
|
|
4338
|
+
import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
4362
4339
|
import os3 from "os";
|
|
4363
4340
|
import path9 from "path";
|
|
4364
4341
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
4365
4342
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
4366
4343
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
4367
4344
|
var KIMI_MCP_FILE = ".slock-kimi-mcp.json";
|
|
4368
|
-
var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
|
|
4369
|
-
var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
|
|
4370
|
-
var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
|
|
4371
4345
|
function parseToolArguments(raw) {
|
|
4372
4346
|
if (typeof raw !== "string") return raw;
|
|
4373
4347
|
try {
|
|
@@ -4376,73 +4350,6 @@ function parseToolArguments(raw) {
|
|
|
4376
4350
|
return raw;
|
|
4377
4351
|
}
|
|
4378
4352
|
}
|
|
4379
|
-
function readKimiConfigSource(home = os3.homedir(), env = process.env) {
|
|
4380
|
-
const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
4381
|
-
if (inlineConfig && inlineConfig.trim()) {
|
|
4382
|
-
return {
|
|
4383
|
-
raw: inlineConfig,
|
|
4384
|
-
explicitPath: null,
|
|
4385
|
-
sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
|
|
4386
|
-
};
|
|
4387
|
-
}
|
|
4388
|
-
const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
4389
|
-
const configPath = explicitPath && explicitPath.trim() ? explicitPath : path9.join(home, ".kimi", "config.toml");
|
|
4390
|
-
try {
|
|
4391
|
-
return {
|
|
4392
|
-
raw: readFileSync3(configPath, "utf8"),
|
|
4393
|
-
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
4394
|
-
sourcePath: configPath
|
|
4395
|
-
};
|
|
4396
|
-
} catch {
|
|
4397
|
-
return {
|
|
4398
|
-
raw: null,
|
|
4399
|
-
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
4400
|
-
sourcePath: configPath
|
|
4401
|
-
};
|
|
4402
|
-
}
|
|
4403
|
-
}
|
|
4404
|
-
function buildKimiSpawnEnv(env = process.env) {
|
|
4405
|
-
const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
4406
|
-
delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
4407
|
-
delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
4408
|
-
return scrubDaemonChildEnv(spawnEnv);
|
|
4409
|
-
}
|
|
4410
|
-
function buildKimiEffectiveEnv(ctx, overrideEnv) {
|
|
4411
|
-
return {
|
|
4412
|
-
...process.env,
|
|
4413
|
-
...ctx.config.envVars || {},
|
|
4414
|
-
...overrideEnv || {}
|
|
4415
|
-
};
|
|
4416
|
-
}
|
|
4417
|
-
function buildKimiLaunchOptions(ctx, opts = {}) {
|
|
4418
|
-
const env = buildKimiEffectiveEnv(ctx, opts.env);
|
|
4419
|
-
const source = readKimiConfigSource(opts.home ?? os3.homedir(), env);
|
|
4420
|
-
const args = [];
|
|
4421
|
-
let configFilePath = null;
|
|
4422
|
-
let configContent = null;
|
|
4423
|
-
if (source.explicitPath) {
|
|
4424
|
-
configFilePath = source.explicitPath;
|
|
4425
|
-
} else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
|
|
4426
|
-
configFilePath = path9.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
|
|
4427
|
-
configContent = source.raw;
|
|
4428
|
-
if (opts.writeGeneratedConfig !== false) {
|
|
4429
|
-
writeFileSync6(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
|
|
4430
|
-
chmodSync(configFilePath, 384);
|
|
4431
|
-
}
|
|
4432
|
-
}
|
|
4433
|
-
if (configFilePath) {
|
|
4434
|
-
args.push("--config-file", configFilePath);
|
|
4435
|
-
}
|
|
4436
|
-
if (ctx.config.model && ctx.config.model !== "default") {
|
|
4437
|
-
args.push("--model", ctx.config.model);
|
|
4438
|
-
}
|
|
4439
|
-
return {
|
|
4440
|
-
args,
|
|
4441
|
-
env: buildKimiSpawnEnv(env),
|
|
4442
|
-
configFilePath,
|
|
4443
|
-
configContent
|
|
4444
|
-
};
|
|
4445
|
-
}
|
|
4446
4353
|
function resolveKimiSpawn(commandArgs, deps = {}) {
|
|
4447
4354
|
return {
|
|
4448
4355
|
command: resolveCommandOnPath("kimi", deps) ?? "kimi",
|
|
@@ -4466,25 +4373,7 @@ var KimiDriver = class {
|
|
|
4466
4373
|
};
|
|
4467
4374
|
model = {
|
|
4468
4375
|
detectedModelsVerifiedAs: "launchable",
|
|
4469
|
-
toLaunchSpec: (modelId
|
|
4470
|
-
if (!ctx) return { args: ["--model", modelId] };
|
|
4471
|
-
const launchCtx = {
|
|
4472
|
-
...ctx,
|
|
4473
|
-
config: {
|
|
4474
|
-
...ctx.config,
|
|
4475
|
-
model: modelId
|
|
4476
|
-
}
|
|
4477
|
-
};
|
|
4478
|
-
const launch = buildKimiLaunchOptions(launchCtx, {
|
|
4479
|
-
home: opts?.home,
|
|
4480
|
-
writeGeneratedConfig: false
|
|
4481
|
-
});
|
|
4482
|
-
return {
|
|
4483
|
-
args: launch.args,
|
|
4484
|
-
env: launch.env,
|
|
4485
|
-
configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
|
|
4486
|
-
};
|
|
4487
|
-
}
|
|
4376
|
+
toLaunchSpec: (modelId) => ({ args: ["--model", modelId] })
|
|
4488
4377
|
};
|
|
4489
4378
|
supportsStdinNotification = true;
|
|
4490
4379
|
mcpToolPrefix = "";
|
|
@@ -4538,7 +4427,6 @@ var KimiDriver = class {
|
|
|
4538
4427
|
}
|
|
4539
4428
|
}
|
|
4540
4429
|
}), "utf8");
|
|
4541
|
-
const launch = buildKimiLaunchOptions(ctx);
|
|
4542
4430
|
const args = [
|
|
4543
4431
|
"--wire",
|
|
4544
4432
|
"--yolo",
|
|
@@ -4547,16 +4435,15 @@ var KimiDriver = class {
|
|
|
4547
4435
|
"--mcp-config-file",
|
|
4548
4436
|
mcpConfigPath,
|
|
4549
4437
|
"--session",
|
|
4550
|
-
this.sessionId
|
|
4551
|
-
...launch.args
|
|
4438
|
+
this.sessionId
|
|
4552
4439
|
];
|
|
4553
4440
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
4554
4441
|
if (launchRuntimeFields.model && launchRuntimeFields.model !== "default") {
|
|
4555
4442
|
args.push("--model", launchRuntimeFields.model);
|
|
4556
4443
|
}
|
|
4557
4444
|
const spawnEnv = (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
4558
|
-
const
|
|
4559
|
-
const proc = spawn7(
|
|
4445
|
+
const launch = resolveKimiSpawn(args);
|
|
4446
|
+
const proc = spawn7(launch.command, launch.args, {
|
|
4560
4447
|
cwd: ctx.workingDirectory,
|
|
4561
4448
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4562
4449
|
env: spawnEnv,
|
|
@@ -4564,7 +4451,7 @@ var KimiDriver = class {
|
|
|
4564
4451
|
// and has an 8191-character command-line limit. Kimi's official
|
|
4565
4452
|
// installer/uv entrypoint is an executable, so launch it directly and
|
|
4566
4453
|
// keep prompts on stdin / files instead of routing through cmd.exe.
|
|
4567
|
-
shell:
|
|
4454
|
+
shell: launch.shell
|
|
4568
4455
|
});
|
|
4569
4456
|
proc.stdin?.write(JSON.stringify({
|
|
4570
4457
|
jsonrpc: "2.0",
|
|
@@ -4678,9 +4565,14 @@ var KimiDriver = class {
|
|
|
4678
4565
|
return detectKimiModels();
|
|
4679
4566
|
}
|
|
4680
4567
|
};
|
|
4681
|
-
function detectKimiModels(home = os3.homedir()
|
|
4682
|
-
const
|
|
4683
|
-
|
|
4568
|
+
function detectKimiModels(home = os3.homedir()) {
|
|
4569
|
+
const configPath = path9.join(home, ".kimi", "config.toml");
|
|
4570
|
+
let raw;
|
|
4571
|
+
try {
|
|
4572
|
+
raw = readFileSync3(configPath, "utf8");
|
|
4573
|
+
} catch {
|
|
4574
|
+
return null;
|
|
4575
|
+
}
|
|
4684
4576
|
const models = [];
|
|
4685
4577
|
const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
|
|
4686
4578
|
const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
|
|
@@ -4944,7 +4836,7 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
4944
4836
|
const platform = deps.platform ?? process.platform;
|
|
4945
4837
|
const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
|
|
4946
4838
|
const result = spawnSyncFn("opencode", ["models"], {
|
|
4947
|
-
env:
|
|
4839
|
+
env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
4948
4840
|
encoding: "utf8",
|
|
4949
4841
|
timeout: 5e3,
|
|
4950
4842
|
shell: platform === "win32"
|
|
@@ -5203,297 +5095,6 @@ var OpenCodeDriver = class {
|
|
|
5203
5095
|
}
|
|
5204
5096
|
};
|
|
5205
5097
|
|
|
5206
|
-
// src/drivers/pi.ts
|
|
5207
|
-
import { spawn as spawn9 } from "child_process";
|
|
5208
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
5209
|
-
import path11 from "path";
|
|
5210
|
-
import { fileURLToPath } from "url";
|
|
5211
|
-
import { getAgentDir, VERSION as PI_SDK_VERSION } from "@earendil-works/pi-coding-agent";
|
|
5212
|
-
var CHAT_MCP_TOOL_PREFIX2 = "chat_";
|
|
5213
|
-
var NO_MESSAGE_PROMPT2 = "No new messages are pending. Stop now.";
|
|
5214
|
-
var FIRST_MESSAGE_TASK_PREFIX2 = "First message task (system-triggered):";
|
|
5215
|
-
var MIN_SUPPORTED_PI_VERSION = "0.74.0";
|
|
5216
|
-
function parseSemver2(version) {
|
|
5217
|
-
const match = version.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
5218
|
-
if (!match) return null;
|
|
5219
|
-
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
5220
|
-
}
|
|
5221
|
-
function isSupportedPiVersion(version) {
|
|
5222
|
-
if (!version) return true;
|
|
5223
|
-
const actual = parseSemver2(version);
|
|
5224
|
-
const minimum = parseSemver2(MIN_SUPPORTED_PI_VERSION);
|
|
5225
|
-
if (!actual || !minimum) return true;
|
|
5226
|
-
for (let i = 0; i < 3; i += 1) {
|
|
5227
|
-
if (actual[i] > minimum[i]) return true;
|
|
5228
|
-
if (actual[i] < minimum[i]) return false;
|
|
5229
|
-
}
|
|
5230
|
-
return true;
|
|
5231
|
-
}
|
|
5232
|
-
function unsupportedPiVersionMessage(version) {
|
|
5233
|
-
if (!version || isSupportedPiVersion(version)) return null;
|
|
5234
|
-
return `Pi SDK ${version} is unsupported; requires @earendil-works/pi-coding-agent >= ${MIN_SUPPORTED_PI_VERSION}. Upgrade the daemon Pi dependency before starting this runtime.`;
|
|
5235
|
-
}
|
|
5236
|
-
function probePi(version = PI_SDK_VERSION) {
|
|
5237
|
-
const unsupportedMessage = unsupportedPiVersionMessage(version);
|
|
5238
|
-
if (unsupportedMessage) {
|
|
5239
|
-
return {
|
|
5240
|
-
available: false,
|
|
5241
|
-
version: `${version} (requires @earendil-works/pi-coding-agent >= ${MIN_SUPPORTED_PI_VERSION})`
|
|
5242
|
-
};
|
|
5243
|
-
}
|
|
5244
|
-
return { available: true, version };
|
|
5245
|
-
}
|
|
5246
|
-
function resolvePiSdkRunnerPath(moduleUrl = import.meta.url) {
|
|
5247
|
-
const moduleDir = path11.dirname(fileURLToPath(moduleUrl));
|
|
5248
|
-
const sourceSibling = path11.join(moduleDir, "piSdkRunner.ts");
|
|
5249
|
-
if (existsSync8(sourceSibling)) return sourceSibling;
|
|
5250
|
-
const bundledEntry = path11.join(moduleDir, "drivers", "piSdkRunner.js");
|
|
5251
|
-
if (existsSync8(bundledEntry)) return bundledEntry;
|
|
5252
|
-
return path11.join(moduleDir, "piSdkRunner.js");
|
|
5253
|
-
}
|
|
5254
|
-
function buildPiSdkNodeArgs(runnerPath = resolvePiSdkRunnerPath()) {
|
|
5255
|
-
if (runnerPath.endsWith(".ts")) {
|
|
5256
|
-
return [...process.execArgv, runnerPath];
|
|
5257
|
-
}
|
|
5258
|
-
return [runnerPath];
|
|
5259
|
-
}
|
|
5260
|
-
async function buildPiLaunchOptions(ctx, opts = {}) {
|
|
5261
|
-
const command = opts.command ?? process.execPath;
|
|
5262
|
-
const piDir = path11.join(ctx.workingDirectory, ".slock", "pi");
|
|
5263
|
-
const sessionDir = path11.join(piDir, "sessions");
|
|
5264
|
-
mkdirSync4(sessionDir, { recursive: true });
|
|
5265
|
-
const slock = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
5266
|
-
const runnerPath = opts.runnerPath ?? resolvePiSdkRunnerPath();
|
|
5267
|
-
const agentDir = opts.agentDir ?? getAgentDir();
|
|
5268
|
-
const runnerConfigPath = path11.join(
|
|
5269
|
-
piDir,
|
|
5270
|
-
`sdk-run-${(ctx.launchId || "launch").replace(/[^a-zA-Z0-9_.-]/g, "_")}.json`
|
|
5271
|
-
);
|
|
5272
|
-
const turnPrompt = ctx.prompt === ctx.standingPrompt ? NO_MESSAGE_PROMPT2 : ctx.prompt;
|
|
5273
|
-
const runnerConfig = {
|
|
5274
|
-
cwd: ctx.workingDirectory,
|
|
5275
|
-
agentDir,
|
|
5276
|
-
sessionDir,
|
|
5277
|
-
sessionId: ctx.config.sessionId || null,
|
|
5278
|
-
standingPrompt: ctx.standingPrompt,
|
|
5279
|
-
prompt: turnPrompt,
|
|
5280
|
-
model: ctx.config.model && ctx.config.model !== "default" ? ctx.config.model : null
|
|
5281
|
-
};
|
|
5282
|
-
writeFileSync7(runnerConfigPath, `${JSON.stringify(runnerConfig)}
|
|
5283
|
-
`, { encoding: "utf8", mode: 384 });
|
|
5284
|
-
const args = [
|
|
5285
|
-
...buildPiSdkNodeArgs(runnerPath),
|
|
5286
|
-
"--config",
|
|
5287
|
-
runnerConfigPath
|
|
5288
|
-
];
|
|
5289
|
-
return {
|
|
5290
|
-
command,
|
|
5291
|
-
args,
|
|
5292
|
-
env: slock.spawnEnv,
|
|
5293
|
-
sessionDir,
|
|
5294
|
-
agentDir,
|
|
5295
|
-
runnerConfigPath,
|
|
5296
|
-
sdkVersion: PI_SDK_VERSION
|
|
5297
|
-
};
|
|
5298
|
-
}
|
|
5299
|
-
function isSystemFirstMessageTask2(message) {
|
|
5300
|
-
return message.sender_id === "system" && message.channel_type === "channel" && message.channel_name === "all" && message.content.trimStart().startsWith(FIRST_MESSAGE_TASK_PREFIX2);
|
|
5301
|
-
}
|
|
5302
|
-
function buildPiSystemPrompt(config) {
|
|
5303
|
-
return buildCliTransportSystemPrompt(config, {
|
|
5304
|
-
toolPrefix: CHAT_MCP_TOOL_PREFIX2,
|
|
5305
|
-
extraCriticalRules: [
|
|
5306
|
-
"- Runtime Profile migration controls are not available in the Pi runtime yet. If asked to acknowledge a runtime migration, explain the blocker instead of inventing a command."
|
|
5307
|
-
],
|
|
5308
|
-
postStartupNotes: [
|
|
5309
|
-
"**Pi runtime note:** Slock launches you as a per-turn process. Complete the current wake using `slock` CLI commands, then stop; the daemon will restart you when new messages arrive."
|
|
5310
|
-
],
|
|
5311
|
-
includeStdinNotificationSection: false,
|
|
5312
|
-
messageNotificationStyle: "poll"
|
|
5313
|
-
});
|
|
5314
|
-
}
|
|
5315
|
-
function contentText(content) {
|
|
5316
|
-
if (!content) return "";
|
|
5317
|
-
const chunks = [];
|
|
5318
|
-
for (const item of content) {
|
|
5319
|
-
if (item.type === "text" && typeof item.text === "string") {
|
|
5320
|
-
chunks.push(item.text);
|
|
5321
|
-
}
|
|
5322
|
-
}
|
|
5323
|
-
return chunks.join("");
|
|
5324
|
-
}
|
|
5325
|
-
function apiKeyErrorMessage(line) {
|
|
5326
|
-
const trimmed = line.trim();
|
|
5327
|
-
if (!trimmed) return null;
|
|
5328
|
-
if (/no api key found/i.test(trimmed)) return trimmed;
|
|
5329
|
-
if (/api key.+required/i.test(trimmed)) return trimmed;
|
|
5330
|
-
if (/no models available/i.test(trimmed)) return trimmed;
|
|
5331
|
-
return null;
|
|
5332
|
-
}
|
|
5333
|
-
var PiDriver = class {
|
|
5334
|
-
id = "pi";
|
|
5335
|
-
lifecycle = {
|
|
5336
|
-
kind: "per_turn",
|
|
5337
|
-
start: "defer_until_concrete_message",
|
|
5338
|
-
exit: "terminate_on_turn_end",
|
|
5339
|
-
inFlightWake: "coalesce_into_pending"
|
|
5340
|
-
};
|
|
5341
|
-
communication = {
|
|
5342
|
-
chat: "slock_cli",
|
|
5343
|
-
runtimeControl: "none"
|
|
5344
|
-
};
|
|
5345
|
-
session = {
|
|
5346
|
-
recovery: "resume_or_fresh"
|
|
5347
|
-
};
|
|
5348
|
-
model = {
|
|
5349
|
-
detectedModelsVerifiedAs: "launchable",
|
|
5350
|
-
toLaunchSpec: async (modelId, ctx) => {
|
|
5351
|
-
if (!ctx) return modelId && modelId !== "default" ? { args: ["--model", modelId] } : { args: [] };
|
|
5352
|
-
const launchCtx = {
|
|
5353
|
-
...ctx,
|
|
5354
|
-
config: {
|
|
5355
|
-
...ctx.config,
|
|
5356
|
-
model: modelId
|
|
5357
|
-
}
|
|
5358
|
-
};
|
|
5359
|
-
const launch = await buildPiLaunchOptions(launchCtx);
|
|
5360
|
-
return {
|
|
5361
|
-
args: launch.args,
|
|
5362
|
-
env: launch.env,
|
|
5363
|
-
configFiles: [launch.runnerConfigPath],
|
|
5364
|
-
params: {
|
|
5365
|
-
agentDir: launch.agentDir,
|
|
5366
|
-
sessionDir: launch.sessionDir,
|
|
5367
|
-
sdkVersion: launch.sdkVersion,
|
|
5368
|
-
resources: "extensions/skills/prompt-templates/themes/context-files disabled by Slock policy"
|
|
5369
|
-
}
|
|
5370
|
-
};
|
|
5371
|
-
}
|
|
5372
|
-
};
|
|
5373
|
-
supportsStdinNotification = false;
|
|
5374
|
-
mcpToolPrefix = CHAT_MCP_TOOL_PREFIX2;
|
|
5375
|
-
busyDeliveryMode = "none";
|
|
5376
|
-
terminateProcessOnTurnEnd = true;
|
|
5377
|
-
deferSpawnUntilMessage = true;
|
|
5378
|
-
usesSlockCliForCommunication = true;
|
|
5379
|
-
sessionId = null;
|
|
5380
|
-
sessionAnnounced = false;
|
|
5381
|
-
apiKeyErrorAnnounced = false;
|
|
5382
|
-
turnEnded = false;
|
|
5383
|
-
assistantTextByMessageId = /* @__PURE__ */ new Map();
|
|
5384
|
-
shouldDeferWakeMessage(message) {
|
|
5385
|
-
return isSystemFirstMessageTask2(message);
|
|
5386
|
-
}
|
|
5387
|
-
probe() {
|
|
5388
|
-
return probePi();
|
|
5389
|
-
}
|
|
5390
|
-
async detectModels() {
|
|
5391
|
-
return null;
|
|
5392
|
-
}
|
|
5393
|
-
async spawn(ctx) {
|
|
5394
|
-
this.sessionId = ctx.config.sessionId || null;
|
|
5395
|
-
this.sessionAnnounced = false;
|
|
5396
|
-
this.apiKeyErrorAnnounced = false;
|
|
5397
|
-
this.turnEnded = false;
|
|
5398
|
-
this.assistantTextByMessageId.clear();
|
|
5399
|
-
const unsupportedMessage = unsupportedPiVersionMessage(PI_SDK_VERSION);
|
|
5400
|
-
if (unsupportedMessage) throw new Error(unsupportedMessage);
|
|
5401
|
-
const launch = await buildPiLaunchOptions(ctx);
|
|
5402
|
-
const proc = spawn9(launch.command, launch.args, {
|
|
5403
|
-
cwd: ctx.workingDirectory,
|
|
5404
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
5405
|
-
env: launch.env,
|
|
5406
|
-
shell: false
|
|
5407
|
-
});
|
|
5408
|
-
proc.stdin?.end();
|
|
5409
|
-
return { process: proc };
|
|
5410
|
-
}
|
|
5411
|
-
parseLine(line) {
|
|
5412
|
-
let event;
|
|
5413
|
-
try {
|
|
5414
|
-
event = JSON.parse(line);
|
|
5415
|
-
} catch {
|
|
5416
|
-
if (this.apiKeyErrorAnnounced) return [];
|
|
5417
|
-
const message = apiKeyErrorMessage(line);
|
|
5418
|
-
if (!message) return [];
|
|
5419
|
-
this.apiKeyErrorAnnounced = true;
|
|
5420
|
-
this.turnEnded = true;
|
|
5421
|
-
return [
|
|
5422
|
-
{ kind: "error", message },
|
|
5423
|
-
{ kind: "turn_end", sessionId: this.sessionId || void 0 }
|
|
5424
|
-
];
|
|
5425
|
-
}
|
|
5426
|
-
const events = [];
|
|
5427
|
-
if (event.type === "session" && event.id) {
|
|
5428
|
-
this.sessionId = event.id;
|
|
5429
|
-
}
|
|
5430
|
-
if (!this.sessionAnnounced && this.sessionId) {
|
|
5431
|
-
events.push({ kind: "session_init", sessionId: this.sessionId });
|
|
5432
|
-
this.sessionAnnounced = true;
|
|
5433
|
-
}
|
|
5434
|
-
switch (event.type) {
|
|
5435
|
-
case "agent_start":
|
|
5436
|
-
case "turn_start":
|
|
5437
|
-
events.push({ kind: "thinking", text: "" });
|
|
5438
|
-
break;
|
|
5439
|
-
case "message_update":
|
|
5440
|
-
case "message_end":
|
|
5441
|
-
if (event.message?.role === "assistant") {
|
|
5442
|
-
const key = event.message.id || "current";
|
|
5443
|
-
const currentText = contentText(event.message.content);
|
|
5444
|
-
const previousText = this.assistantTextByMessageId.get(key) ?? "";
|
|
5445
|
-
if (currentText.length > previousText.length && currentText.startsWith(previousText)) {
|
|
5446
|
-
events.push({ kind: "text", text: currentText.slice(previousText.length) });
|
|
5447
|
-
} else if (currentText && currentText !== previousText) {
|
|
5448
|
-
events.push({ kind: "text", text: currentText });
|
|
5449
|
-
}
|
|
5450
|
-
this.assistantTextByMessageId.set(key, currentText);
|
|
5451
|
-
if (event.message.stopReason === "error" || event.message.stopReason === "aborted") {
|
|
5452
|
-
events.push({ kind: "error", message: event.message.errorMessage || `Request ${event.message.stopReason}` });
|
|
5453
|
-
}
|
|
5454
|
-
}
|
|
5455
|
-
break;
|
|
5456
|
-
case "tool_execution_start":
|
|
5457
|
-
events.push({
|
|
5458
|
-
kind: "tool_call",
|
|
5459
|
-
name: event.toolName || "unknown_tool",
|
|
5460
|
-
input: event.args
|
|
5461
|
-
});
|
|
5462
|
-
break;
|
|
5463
|
-
case "tool_execution_end":
|
|
5464
|
-
events.push({
|
|
5465
|
-
kind: "tool_output",
|
|
5466
|
-
name: event.toolName || "unknown_tool"
|
|
5467
|
-
});
|
|
5468
|
-
if (event.isError) {
|
|
5469
|
-
events.push({ kind: "error", message: `Pi tool ${event.toolName || "unknown_tool"} failed` });
|
|
5470
|
-
}
|
|
5471
|
-
break;
|
|
5472
|
-
case "compaction_start":
|
|
5473
|
-
events.push({ kind: "compaction_started" });
|
|
5474
|
-
break;
|
|
5475
|
-
case "compaction_end":
|
|
5476
|
-
events.push({ kind: "compaction_finished" });
|
|
5477
|
-
if (event.errorMessage) events.push({ kind: "error", message: event.errorMessage });
|
|
5478
|
-
break;
|
|
5479
|
-
case "turn_end":
|
|
5480
|
-
case "agent_end":
|
|
5481
|
-
if (!this.turnEnded) {
|
|
5482
|
-
events.push({ kind: "turn_end", sessionId: this.sessionId || void 0 });
|
|
5483
|
-
this.turnEnded = true;
|
|
5484
|
-
}
|
|
5485
|
-
break;
|
|
5486
|
-
}
|
|
5487
|
-
return events;
|
|
5488
|
-
}
|
|
5489
|
-
encodeStdinMessage(_text, _sessionId, _opts) {
|
|
5490
|
-
return null;
|
|
5491
|
-
}
|
|
5492
|
-
buildSystemPrompt(config, _agentId) {
|
|
5493
|
-
return buildPiSystemPrompt(config);
|
|
5494
|
-
}
|
|
5495
|
-
};
|
|
5496
|
-
|
|
5497
5098
|
// src/drivers/index.ts
|
|
5498
5099
|
var driverFactories = {
|
|
5499
5100
|
claude: () => new ClaudeDriver(),
|
|
@@ -5503,8 +5104,7 @@ var driverFactories = {
|
|
|
5503
5104
|
cursor: () => new CursorDriver(),
|
|
5504
5105
|
gemini: () => new GeminiDriver(),
|
|
5505
5106
|
kimi: () => new KimiDriver(),
|
|
5506
|
-
opencode: () => new OpenCodeDriver()
|
|
5507
|
-
pi: () => new PiDriver()
|
|
5107
|
+
opencode: () => new OpenCodeDriver()
|
|
5508
5108
|
};
|
|
5509
5109
|
function getDriver(runtimeId) {
|
|
5510
5110
|
const createDriver = driverFactories[runtimeId];
|
|
@@ -5517,7 +5117,7 @@ function getDriver(runtimeId) {
|
|
|
5517
5117
|
|
|
5518
5118
|
// src/workspaces.ts
|
|
5519
5119
|
import { readdir, rm, stat } from "fs/promises";
|
|
5520
|
-
import
|
|
5120
|
+
import path11 from "path";
|
|
5521
5121
|
function isValidWorkspaceDirectoryName(directoryName) {
|
|
5522
5122
|
return !directoryName.includes("/") && !directoryName.includes("\\") && !directoryName.includes("..");
|
|
5523
5123
|
}
|
|
@@ -5525,7 +5125,7 @@ function resolveWorkspaceDirectoryPath(dataDir, directoryName) {
|
|
|
5525
5125
|
if (!isValidWorkspaceDirectoryName(directoryName)) {
|
|
5526
5126
|
return null;
|
|
5527
5127
|
}
|
|
5528
|
-
return
|
|
5128
|
+
return path11.join(dataDir, directoryName);
|
|
5529
5129
|
}
|
|
5530
5130
|
function emptyWorkspaceDirectorySummary(latestMtime = /* @__PURE__ */ new Date(0)) {
|
|
5531
5131
|
return {
|
|
@@ -5574,7 +5174,7 @@ async function summarizeWorkspaceDirectory(dirPath) {
|
|
|
5574
5174
|
return summary;
|
|
5575
5175
|
}
|
|
5576
5176
|
const childSummaries = await Promise.all(
|
|
5577
|
-
entries.map((entry) => summarizeWorkspaceEntry(
|
|
5177
|
+
entries.map((entry) => summarizeWorkspaceEntry(path11.join(dirPath, entry.name), entry))
|
|
5578
5178
|
);
|
|
5579
5179
|
for (const childSummary of childSummaries) {
|
|
5580
5180
|
summary = mergeWorkspaceDirectorySummaries(summary, childSummary);
|
|
@@ -5593,7 +5193,7 @@ async function scanWorkspaceDirectories(dataDir) {
|
|
|
5593
5193
|
if (!entry.isDirectory()) {
|
|
5594
5194
|
return null;
|
|
5595
5195
|
}
|
|
5596
|
-
const dirPath =
|
|
5196
|
+
const dirPath = path11.join(dataDir, entry.name);
|
|
5597
5197
|
try {
|
|
5598
5198
|
const summary = await summarizeWorkspaceDirectory(dirPath);
|
|
5599
5199
|
return {
|
|
@@ -6030,12 +5630,12 @@ function findSessionJsonl(root, predicate) {
|
|
|
6030
5630
|
for (const entry of entries) {
|
|
6031
5631
|
if (++visited > maxEntries) return null;
|
|
6032
5632
|
if (!entry.isFile() || !predicate(entry.name)) continue;
|
|
6033
|
-
return
|
|
5633
|
+
return path12.join(dir, entry.name);
|
|
6034
5634
|
}
|
|
6035
5635
|
for (const entry of entries) {
|
|
6036
5636
|
if (++visited > maxEntries) return null;
|
|
6037
5637
|
if (!entry.isDirectory()) continue;
|
|
6038
|
-
const found = visit(
|
|
5638
|
+
const found = visit(path12.join(dir, entry.name), depth - 1);
|
|
6039
5639
|
if (found) return found;
|
|
6040
5640
|
}
|
|
6041
5641
|
return null;
|
|
@@ -6048,10 +5648,10 @@ function safeSessionFilename(value) {
|
|
|
6048
5648
|
}
|
|
6049
5649
|
function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
6050
5650
|
try {
|
|
6051
|
-
const dir =
|
|
6052
|
-
|
|
6053
|
-
const filePath =
|
|
6054
|
-
|
|
5651
|
+
const dir = path12.join(fallbackDir, ".slock", "runtime-sessions");
|
|
5652
|
+
mkdirSync4(dir, { recursive: true });
|
|
5653
|
+
const filePath = path12.join(dir, `${runtime}-${safeSessionFilename(sessionId)}.jsonl`);
|
|
5654
|
+
writeFileSync7(filePath, JSON.stringify({
|
|
6055
5655
|
type: "runtime_session_handoff",
|
|
6056
5656
|
runtime,
|
|
6057
5657
|
sessionId,
|
|
@@ -6070,7 +5670,7 @@ function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
|
6070
5670
|
}
|
|
6071
5671
|
}
|
|
6072
5672
|
function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os5.homedir(), fallbackDir) {
|
|
6073
|
-
const directPath =
|
|
5673
|
+
const directPath = path12.isAbsolute(sessionId) ? sessionId : null;
|
|
6074
5674
|
if (directPath) {
|
|
6075
5675
|
try {
|
|
6076
5676
|
if (statSync(directPath).isFile()) {
|
|
@@ -6079,7 +5679,7 @@ function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os5.homedir(), f
|
|
|
6079
5679
|
} catch {
|
|
6080
5680
|
}
|
|
6081
5681
|
}
|
|
6082
|
-
const resolvedPath = runtime === "claude" ? findSessionJsonl(
|
|
5682
|
+
const resolvedPath = runtime === "claude" ? findSessionJsonl(path12.join(homeDir, ".claude", "projects"), (filename) => filename === `${sessionId}.jsonl`) : runtime === "codex" ? findSessionJsonl(path12.join(homeDir, ".codex", "sessions"), (filename) => filename.endsWith(".jsonl") && filename.includes(sessionId)) : null;
|
|
6083
5683
|
if (!resolvedPath && fallbackDir) {
|
|
6084
5684
|
const fallback = writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir);
|
|
6085
5685
|
if (fallback) return fallback;
|
|
@@ -7439,7 +7039,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
7439
7039
|
);
|
|
7440
7040
|
wakeMessage = void 0;
|
|
7441
7041
|
}
|
|
7442
|
-
const agentDataDir =
|
|
7042
|
+
const agentDataDir = path12.join(this.dataDir, agentId);
|
|
7443
7043
|
await mkdir(agentDataDir, { recursive: true });
|
|
7444
7044
|
let runtimeConfig = withLocalRuntimeContext(config, agentId, agentDataDir);
|
|
7445
7045
|
const legacyRuntimeProfileControl = runtimeConfig.runtimeProfileControl?.kind === "migration" ? runtimeConfig.runtimeProfileControl : null;
|
|
@@ -7453,23 +7053,23 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
7453
7053
|
);
|
|
7454
7054
|
runtimeConfig = { ...runtimeConfig, runtimeProfileControl: null };
|
|
7455
7055
|
}
|
|
7456
|
-
const memoryMdPath =
|
|
7056
|
+
const memoryMdPath = path12.join(agentDataDir, "MEMORY.md");
|
|
7457
7057
|
try {
|
|
7458
7058
|
await access(memoryMdPath);
|
|
7459
7059
|
} catch {
|
|
7460
7060
|
const initialMemoryMd = buildInitialMemoryMd(runtimeConfig);
|
|
7461
7061
|
await writeFile(memoryMdPath, initialMemoryMd);
|
|
7462
7062
|
}
|
|
7463
|
-
const notesDir =
|
|
7063
|
+
const notesDir = path12.join(agentDataDir, "notes");
|
|
7464
7064
|
await mkdir(notesDir, { recursive: true });
|
|
7465
7065
|
if (getOnboardingSeedMode(config) === FIRST_CINDY_SEED_MODE) {
|
|
7466
7066
|
const seedFiles = buildOnboardingSeedFiles();
|
|
7467
7067
|
for (const { relativePath, content } of seedFiles) {
|
|
7468
|
-
const fullPath =
|
|
7068
|
+
const fullPath = path12.join(agentDataDir, relativePath);
|
|
7469
7069
|
try {
|
|
7470
7070
|
await access(fullPath);
|
|
7471
7071
|
} catch {
|
|
7472
|
-
await mkdir(
|
|
7072
|
+
await mkdir(path12.dirname(fullPath), { recursive: true });
|
|
7473
7073
|
await writeFile(fullPath, content);
|
|
7474
7074
|
}
|
|
7475
7075
|
}
|
|
@@ -8346,7 +7946,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8346
7946
|
return true;
|
|
8347
7947
|
}
|
|
8348
7948
|
async resetWorkspace(agentId) {
|
|
8349
|
-
const agentDataDir =
|
|
7949
|
+
const agentDataDir = path12.join(this.dataDir, agentId);
|
|
8350
7950
|
try {
|
|
8351
7951
|
await rm2(agentDataDir, { recursive: true, force: true });
|
|
8352
7952
|
logger.info(`[Agent ${agentId}] Workspace reset complete (${agentDataDir})`);
|
|
@@ -8407,7 +8007,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8407
8007
|
return result;
|
|
8408
8008
|
}
|
|
8409
8009
|
buildRuntimeProfileReport(agentId, config, sessionId, launchId) {
|
|
8410
|
-
const workspacePath =
|
|
8010
|
+
const workspacePath = path12.join(this.dataDir, agentId);
|
|
8411
8011
|
return {
|
|
8412
8012
|
agentId,
|
|
8413
8013
|
launchId,
|
|
@@ -8664,7 +8264,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8664
8264
|
}
|
|
8665
8265
|
// Workspace file browsing
|
|
8666
8266
|
async getFileTree(agentId, dirPath) {
|
|
8667
|
-
const agentDir =
|
|
8267
|
+
const agentDir = path12.join(this.dataDir, agentId);
|
|
8668
8268
|
try {
|
|
8669
8269
|
await stat2(agentDir);
|
|
8670
8270
|
} catch {
|
|
@@ -8672,8 +8272,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8672
8272
|
}
|
|
8673
8273
|
let targetDir = agentDir;
|
|
8674
8274
|
if (dirPath) {
|
|
8675
|
-
const resolved =
|
|
8676
|
-
if (!resolved.startsWith(agentDir +
|
|
8275
|
+
const resolved = path12.resolve(agentDir, dirPath);
|
|
8276
|
+
if (!resolved.startsWith(agentDir + path12.sep) && resolved !== agentDir) {
|
|
8677
8277
|
return [];
|
|
8678
8278
|
}
|
|
8679
8279
|
targetDir = resolved;
|
|
@@ -8681,14 +8281,14 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8681
8281
|
return this.listDirectoryChildren(targetDir, agentDir);
|
|
8682
8282
|
}
|
|
8683
8283
|
async readFile(agentId, filePath) {
|
|
8684
|
-
const agentDir =
|
|
8685
|
-
const resolved =
|
|
8686
|
-
if (!resolved.startsWith(agentDir +
|
|
8284
|
+
const agentDir = path12.join(this.dataDir, agentId);
|
|
8285
|
+
const resolved = path12.resolve(agentDir, filePath);
|
|
8286
|
+
if (!resolved.startsWith(agentDir + path12.sep) && resolved !== agentDir) {
|
|
8687
8287
|
throw new Error("Access denied");
|
|
8688
8288
|
}
|
|
8689
8289
|
const info = await stat2(resolved);
|
|
8690
8290
|
if (info.isDirectory()) throw new Error("Cannot read a directory");
|
|
8691
|
-
const ext =
|
|
8291
|
+
const ext = path12.extname(resolved).toLowerCase();
|
|
8692
8292
|
if (WORKSPACE_TEXT_EXTENSIONS.has(ext) || ext === "") {
|
|
8693
8293
|
if (info.size > WORKSPACE_TEXT_FILE_MAX_BYTES) throw new Error("File too large");
|
|
8694
8294
|
const content = await readFile(resolved, "utf-8");
|
|
@@ -8723,13 +8323,13 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8723
8323
|
const agent = this.agents.get(agentId);
|
|
8724
8324
|
const runtime = runtimeHint || agent?.config.runtime || "claude";
|
|
8725
8325
|
const home = os5.homedir();
|
|
8726
|
-
const workspaceDir =
|
|
8326
|
+
const workspaceDir = path12.join(this.dataDir, agentId);
|
|
8727
8327
|
const paths = _AgentProcessManager.SKILL_PATHS[runtime] || _AgentProcessManager.SKILL_PATHS.claude;
|
|
8728
8328
|
const globalResults = await Promise.all(
|
|
8729
|
-
paths.global.map((p) => this.scanSkillsDir(
|
|
8329
|
+
paths.global.map((p) => this.scanSkillsDir(path12.join(home, p)))
|
|
8730
8330
|
);
|
|
8731
8331
|
const workspaceResults = await Promise.all(
|
|
8732
|
-
paths.workspace.map((p) => this.scanSkillsDir(
|
|
8332
|
+
paths.workspace.map((p) => this.scanSkillsDir(path12.join(workspaceDir, p)))
|
|
8733
8333
|
);
|
|
8734
8334
|
const dedup = (skills) => {
|
|
8735
8335
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -8758,7 +8358,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8758
8358
|
const skills = [];
|
|
8759
8359
|
for (const entry of entries) {
|
|
8760
8360
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
8761
|
-
const skillMd =
|
|
8361
|
+
const skillMd = path12.join(dir, entry.name, "SKILL.md");
|
|
8762
8362
|
try {
|
|
8763
8363
|
const content = await readFile(skillMd, "utf-8");
|
|
8764
8364
|
const skill = this.parseSkillMd(entry.name, content);
|
|
@@ -8769,7 +8369,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
8769
8369
|
} else if (entry.name.endsWith(".md")) {
|
|
8770
8370
|
const cmdName = entry.name.replace(/\.md$/, "");
|
|
8771
8371
|
try {
|
|
8772
|
-
const content = await readFile(
|
|
8372
|
+
const content = await readFile(path12.join(dir, entry.name), "utf-8");
|
|
8773
8373
|
const skill = this.parseSkillMd(cmdName, content);
|
|
8774
8374
|
skill.sourcePath = dir;
|
|
8775
8375
|
skills.push(skill);
|
|
@@ -9843,8 +9443,8 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
9843
9443
|
const nodes = [];
|
|
9844
9444
|
for (const entry of entries) {
|
|
9845
9445
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
9846
|
-
const fullPath =
|
|
9847
|
-
const relativePath =
|
|
9446
|
+
const fullPath = path12.join(dir, entry.name);
|
|
9447
|
+
const relativePath = path12.relative(rootDir, fullPath);
|
|
9848
9448
|
let info;
|
|
9849
9449
|
try {
|
|
9850
9450
|
info = await stat2(fullPath);
|
|
@@ -10149,9 +9749,9 @@ var ReminderCache = class {
|
|
|
10149
9749
|
|
|
10150
9750
|
// src/machineLock.ts
|
|
10151
9751
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
|
|
10152
|
-
import { mkdirSync as
|
|
9752
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync8 } from "fs";
|
|
10153
9753
|
import os6 from "os";
|
|
10154
|
-
import
|
|
9754
|
+
import path13 from "path";
|
|
10155
9755
|
var INCOMPLETE_LOCK_STALE_MS = 3e4;
|
|
10156
9756
|
var DaemonMachineLockConflictError = class extends Error {
|
|
10157
9757
|
code = "DAEMON_MACHINE_LOCK_HELD";
|
|
@@ -10173,7 +9773,7 @@ function resolveDefaultMachineStateRoot() {
|
|
|
10173
9773
|
return resolveSlockHomePath("machines");
|
|
10174
9774
|
}
|
|
10175
9775
|
function ownerPath(lockDir) {
|
|
10176
|
-
return
|
|
9776
|
+
return path13.join(lockDir, "owner.json");
|
|
10177
9777
|
}
|
|
10178
9778
|
function readOwner(lockDir) {
|
|
10179
9779
|
try {
|
|
@@ -10203,13 +9803,13 @@ function acquireDaemonMachineLock(options) {
|
|
|
10203
9803
|
const rootDir = options.rootDir ?? resolveDefaultMachineStateRoot();
|
|
10204
9804
|
const fingerprint = apiKeyFingerprint(options.apiKey);
|
|
10205
9805
|
const lockId = getDaemonMachineLockId(options.apiKey);
|
|
10206
|
-
const machineDir =
|
|
10207
|
-
const lockDir =
|
|
9806
|
+
const machineDir = path13.join(rootDir, lockId);
|
|
9807
|
+
const lockDir = path13.join(machineDir, "daemon.lock");
|
|
10208
9808
|
const token = randomUUID3();
|
|
10209
|
-
|
|
9809
|
+
mkdirSync5(machineDir, { recursive: true });
|
|
10210
9810
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
10211
9811
|
try {
|
|
10212
|
-
|
|
9812
|
+
mkdirSync5(lockDir);
|
|
10213
9813
|
const owner = {
|
|
10214
9814
|
pid: process.pid,
|
|
10215
9815
|
token,
|
|
@@ -10219,7 +9819,7 @@ function acquireDaemonMachineLock(options) {
|
|
|
10219
9819
|
apiKeyFingerprint: fingerprint.slice(0, 16)
|
|
10220
9820
|
};
|
|
10221
9821
|
try {
|
|
10222
|
-
|
|
9822
|
+
writeFileSync8(ownerPath(lockDir), `${JSON.stringify(owner, null, 2)}
|
|
10223
9823
|
`, { mode: 384 });
|
|
10224
9824
|
} catch (err) {
|
|
10225
9825
|
rmSync3(lockDir, { recursive: true, force: true });
|
|
@@ -10256,8 +9856,8 @@ function acquireDaemonMachineLock(options) {
|
|
|
10256
9856
|
}
|
|
10257
9857
|
|
|
10258
9858
|
// src/localTraceSink.ts
|
|
10259
|
-
import { appendFileSync, mkdirSync as
|
|
10260
|
-
import
|
|
9859
|
+
import { appendFileSync, mkdirSync as mkdirSync6, readdirSync as readdirSync2, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync9 } from "fs";
|
|
9860
|
+
import path14 from "path";
|
|
10261
9861
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
10262
9862
|
var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
|
|
10263
9863
|
var DEFAULT_MAX_FILES = 8;
|
|
@@ -10293,7 +9893,7 @@ var LocalRotatingTraceSink = class {
|
|
|
10293
9893
|
currentSize = 0;
|
|
10294
9894
|
sequence = 0;
|
|
10295
9895
|
constructor(options) {
|
|
10296
|
-
this.traceDir =
|
|
9896
|
+
this.traceDir = path14.join(options.machineDir, "traces");
|
|
10297
9897
|
this.maxFileBytes = Math.max(1024, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES));
|
|
10298
9898
|
const baseAgeMs = Math.max(1e3, Math.floor(options.maxFileAgeMs ?? DEFAULT_MAX_FILE_AGE_MS));
|
|
10299
9899
|
const ageJitterMs = Math.max(0, Math.floor(options.maxFileAgeJitterMs ?? 0));
|
|
@@ -10319,15 +9919,15 @@ var LocalRotatingTraceSink = class {
|
|
|
10319
9919
|
return this.currentFile;
|
|
10320
9920
|
}
|
|
10321
9921
|
ensureFile(nextBytes) {
|
|
10322
|
-
|
|
9922
|
+
mkdirSync6(this.traceDir, { recursive: true, mode: 448 });
|
|
10323
9923
|
const nowMs = this.nowMsProvider();
|
|
10324
9924
|
const shouldRotateForAge = this.currentFileOpenedAtMs !== null && nowMs - this.currentFileOpenedAtMs >= this.maxFileAgeMs;
|
|
10325
9925
|
if (!this.currentFile || this.currentSize + nextBytes > this.maxFileBytes || shouldRotateForAge) {
|
|
10326
|
-
this.currentFile =
|
|
9926
|
+
this.currentFile = path14.join(
|
|
10327
9927
|
this.traceDir,
|
|
10328
9928
|
`daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
|
|
10329
9929
|
);
|
|
10330
|
-
|
|
9930
|
+
writeFileSync9(this.currentFile, "", { flag: "a", mode: 384 });
|
|
10331
9931
|
this.currentSize = statSync3(this.currentFile).size;
|
|
10332
9932
|
this.currentFileOpenedAtMs = nowMs;
|
|
10333
9933
|
this.pruneOldFiles();
|
|
@@ -10338,7 +9938,7 @@ var LocalRotatingTraceSink = class {
|
|
|
10338
9938
|
const excess = files.length - this.maxFiles;
|
|
10339
9939
|
if (excess <= 0) return;
|
|
10340
9940
|
for (const file of files.slice(0, excess)) {
|
|
10341
|
-
rmSync4(
|
|
9941
|
+
rmSync4(path14.join(this.traceDir, file), { force: true });
|
|
10342
9942
|
}
|
|
10343
9943
|
}
|
|
10344
9944
|
};
|
|
@@ -10425,11 +10025,11 @@ function isDiagnosticErrorAttr(key) {
|
|
|
10425
10025
|
import { createHash as createHash5, randomUUID as randomUUID4 } from "crypto";
|
|
10426
10026
|
import { gzipSync } from "zlib";
|
|
10427
10027
|
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
10428
|
-
import
|
|
10028
|
+
import path15 from "path";
|
|
10429
10029
|
|
|
10430
10030
|
// src/directUploadCapability.ts
|
|
10431
|
-
function joinUrl(base,
|
|
10432
|
-
return `${base.replace(/\/+$/, "")}${
|
|
10031
|
+
function joinUrl(base, path17) {
|
|
10032
|
+
return `${base.replace(/\/+$/, "")}${path17}`;
|
|
10433
10033
|
}
|
|
10434
10034
|
function jsonHeaders(apiKey) {
|
|
10435
10035
|
return {
|
|
@@ -10648,7 +10248,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
10648
10248
|
}, nextMs);
|
|
10649
10249
|
}
|
|
10650
10250
|
async findUploadCandidates() {
|
|
10651
|
-
const traceDir =
|
|
10251
|
+
const traceDir = path15.join(this.options.machineDir, "traces");
|
|
10652
10252
|
let names;
|
|
10653
10253
|
try {
|
|
10654
10254
|
names = await readdir3(traceDir);
|
|
@@ -10660,8 +10260,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
10660
10260
|
const currentFile = this.options.currentFileProvider?.();
|
|
10661
10261
|
const candidates = [];
|
|
10662
10262
|
for (const name of names.filter((entry) => entry.startsWith("daemon-trace-") && entry.endsWith(".jsonl")).sort()) {
|
|
10663
|
-
const file =
|
|
10664
|
-
if (currentFile &&
|
|
10263
|
+
const file = path15.join(traceDir, name);
|
|
10264
|
+
if (currentFile && path15.resolve(file) === path15.resolve(currentFile)) continue;
|
|
10665
10265
|
if (await this.isUploaded(file)) continue;
|
|
10666
10266
|
try {
|
|
10667
10267
|
const info = await stat3(file);
|
|
@@ -10735,8 +10335,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
10735
10335
|
}
|
|
10736
10336
|
}
|
|
10737
10337
|
uploadStatePath(file) {
|
|
10738
|
-
const stateDir =
|
|
10739
|
-
return
|
|
10338
|
+
const stateDir = path15.join(this.options.machineDir, "trace-uploads");
|
|
10339
|
+
return path15.join(stateDir, `${path15.basename(file)}.uploaded.json`);
|
|
10740
10340
|
}
|
|
10741
10341
|
async isUploaded(file) {
|
|
10742
10342
|
try {
|
|
@@ -10748,9 +10348,9 @@ var DaemonTraceBundleUploader = class {
|
|
|
10748
10348
|
}
|
|
10749
10349
|
async markUploaded(file, metadata) {
|
|
10750
10350
|
const stateFile = this.uploadStatePath(file);
|
|
10751
|
-
await mkdir2(
|
|
10351
|
+
await mkdir2(path15.dirname(stateFile), { recursive: true, mode: 448 });
|
|
10752
10352
|
await writeFile2(stateFile, `${JSON.stringify({
|
|
10753
|
-
file:
|
|
10353
|
+
file: path15.basename(file),
|
|
10754
10354
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10755
10355
|
...metadata
|
|
10756
10356
|
}, null, 2)}
|
|
@@ -10772,7 +10372,7 @@ var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
|
|
|
10772
10372
|
var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels", "knowledge"];
|
|
10773
10373
|
var RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS2 = 3;
|
|
10774
10374
|
var RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2 = 250;
|
|
10775
|
-
var DAEMON_CLI_USAGE =
|
|
10375
|
+
var DAEMON_CLI_USAGE = "Usage: slock-daemon --server-url <url> --api-key <key>";
|
|
10776
10376
|
var RunnerCredentialMintError2 = class extends Error {
|
|
10777
10377
|
code;
|
|
10778
10378
|
retryable;
|
|
@@ -10808,9 +10408,9 @@ function runnerCredentialErrorDetail2(error) {
|
|
|
10808
10408
|
async function waitForRunnerCredentialRetry2() {
|
|
10809
10409
|
await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
|
|
10810
10410
|
}
|
|
10811
|
-
function parseDaemonCliArgs(args
|
|
10411
|
+
function parseDaemonCliArgs(args) {
|
|
10812
10412
|
let serverUrl = "";
|
|
10813
|
-
let apiKey =
|
|
10413
|
+
let apiKey = "";
|
|
10814
10414
|
for (let i = 0; i < args.length; i++) {
|
|
10815
10415
|
if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
|
|
10816
10416
|
if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
|
|
@@ -10827,23 +10427,23 @@ function readDaemonVersion(moduleUrl = import.meta.url) {
|
|
|
10827
10427
|
}
|
|
10828
10428
|
}
|
|
10829
10429
|
function resolveChatBridgePath(moduleUrl = import.meta.url) {
|
|
10830
|
-
const dirname =
|
|
10831
|
-
const jsPath =
|
|
10430
|
+
const dirname = path16.dirname(fileURLToPath(moduleUrl));
|
|
10431
|
+
const jsPath = path16.resolve(dirname, "chat-bridge.js");
|
|
10832
10432
|
try {
|
|
10833
10433
|
accessSync(jsPath);
|
|
10834
10434
|
return jsPath;
|
|
10835
10435
|
} catch {
|
|
10836
|
-
return
|
|
10436
|
+
return path16.resolve(dirname, "chat-bridge.ts");
|
|
10837
10437
|
}
|
|
10838
10438
|
}
|
|
10839
10439
|
function resolveSlockCliPath(moduleUrl = import.meta.url) {
|
|
10840
|
-
const thisDir =
|
|
10841
|
-
const bundledDistPath =
|
|
10440
|
+
const thisDir = path16.dirname(fileURLToPath(moduleUrl));
|
|
10441
|
+
const bundledDistPath = path16.resolve(thisDir, "cli", "index.js");
|
|
10842
10442
|
try {
|
|
10843
10443
|
accessSync(bundledDistPath);
|
|
10844
10444
|
return bundledDistPath;
|
|
10845
10445
|
} catch {
|
|
10846
|
-
const workspaceDistPath =
|
|
10446
|
+
const workspaceDistPath = path16.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
|
|
10847
10447
|
accessSync(workspaceDistPath);
|
|
10848
10448
|
return workspaceDistPath;
|
|
10849
10449
|
}
|
|
@@ -11022,7 +10622,7 @@ var DaemonCore = class {
|
|
|
11022
10622
|
}
|
|
11023
10623
|
resolveMachineStateRoot() {
|
|
11024
10624
|
if (this.options.machineStateDir) return this.options.machineStateDir;
|
|
11025
|
-
if (this.options.dataDir) return
|
|
10625
|
+
if (this.options.dataDir) return path16.join(path16.dirname(this.options.dataDir), "machines");
|
|
11026
10626
|
return resolveDefaultMachineStateRoot();
|
|
11027
10627
|
}
|
|
11028
10628
|
shouldEnableLocalTrace() {
|
|
@@ -11533,8 +11133,6 @@ var DaemonCore = class {
|
|
|
11533
11133
|
};
|
|
11534
11134
|
|
|
11535
11135
|
export {
|
|
11536
|
-
DAEMON_API_KEY_ENV,
|
|
11537
|
-
scrubDaemonAuthEnv,
|
|
11538
11136
|
resolveWorkspaceDirectoryPath,
|
|
11539
11137
|
scanWorkspaceDirectories,
|
|
11540
11138
|
deleteWorkspaceDirectory,
|