@slock-ai/daemon 0.51.0 → 0.51.1-play.20260519174619
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-NAMH7BB6.js → chunk-NZM6RHMZ.js} +524 -102
- package/dist/cli/index.js +165 -1
- package/dist/core.js +6 -2
- package/dist/drivers/piSdkRunner.js +96 -0
- package/dist/index.js +5 -3
- package/package.json +2 -1
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
} from "./chunk-KNMCE6WB.js";
|
|
8
8
|
|
|
9
9
|
// src/core.ts
|
|
10
|
-
import
|
|
10
|
+
import path17 from "path";
|
|
11
11
|
import os8 from "os";
|
|
12
12
|
import { createRequire } from "module";
|
|
13
13
|
import { accessSync } from "fs";
|
|
14
|
-
import { fileURLToPath } from "url";
|
|
14
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
15
15
|
|
|
16
16
|
// ../shared/src/tracing/index.ts
|
|
17
17
|
var DEFAULT_TRACE_FLAGS = "00";
|
|
@@ -723,6 +723,7 @@ var SERVER_CAPABILITY_MATRIX = {
|
|
|
723
723
|
var RUNTIMES = [
|
|
724
724
|
{ id: "claude", displayName: "Claude Code", binary: "claude", supported: true },
|
|
725
725
|
{ id: "codex", displayName: "Codex CLI", binary: "codex", supported: true },
|
|
726
|
+
{ id: "pi", displayName: "Pi", binary: "pi", supported: true },
|
|
726
727
|
{ id: "kimi", displayName: "Kimi CLI", binary: "kimi", supported: true },
|
|
727
728
|
{ id: "copilot", displayName: "Copilot CLI", binary: "copilot", supported: true },
|
|
728
729
|
{ id: "cursor", displayName: "Cursor CLI", binary: "cursor-agent", supported: true },
|
|
@@ -764,10 +765,10 @@ var DISPLAY_PLAN_CONFIG = {
|
|
|
764
765
|
};
|
|
765
766
|
|
|
766
767
|
// src/agentProcessManager.ts
|
|
767
|
-
import { mkdirSync as
|
|
768
|
+
import { mkdirSync as mkdirSync5, readdirSync as readdirSync2, statSync as statSync2, writeFileSync as writeFileSync8 } from "fs";
|
|
768
769
|
import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2 } from "fs/promises";
|
|
769
770
|
import { createHash as createHash2 } from "crypto";
|
|
770
|
-
import
|
|
771
|
+
import path13 from "path";
|
|
771
772
|
import os6 from "os";
|
|
772
773
|
|
|
773
774
|
// src/drivers/claude.ts
|
|
@@ -871,13 +872,15 @@ Use the \`slock\` CLI for chat / task / attachment operations. The daemon inject
|
|
|
871
872
|
17. **\`slock attachment view\`** \u2014 Download an attached file by its attachment ID so you can inspect it locally.
|
|
872
873
|
18. **\`slock profile show\`** \u2014 Show your own profile, or another visible profile via \`@handle\`. Mirrors the canonical Slock profile view.
|
|
873
874
|
19. **\`slock profile update\`** \u2014 Update your own profile. Supports \`--avatar-file <path>\`, \`--avatar-url pixel:random:<seed>\`, \`--display-name <name>\`, and \`--description <text>\`. Use \`--avatar-url pixel:random:<seed>\` when you want a new pixel avatar but do not have a local image file. Values must be non-empty. Provide at least one flag per call; multiple flags can be combined.
|
|
874
|
-
20. **\`slock
|
|
875
|
-
21. **\`slock
|
|
876
|
-
22. **\`slock reminder
|
|
877
|
-
23. **\`slock reminder
|
|
878
|
-
24. **\`slock reminder
|
|
879
|
-
25. **\`slock reminder
|
|
880
|
-
26. **\`slock
|
|
875
|
+
20. **\`slock integration list\`** \u2014 List registered third-party services and this agent's active Slock Agent Logins.
|
|
876
|
+
21. **\`slock integration login\`** \u2014 Provision or reuse this agent's login for a registered third-party service.
|
|
877
|
+
22. **\`slock reminder schedule\`** \u2014 Schedule a reminder for yourself later, at a specific time, or on a recurring cadence.
|
|
878
|
+
23. **\`slock reminder list\`** \u2014 List your reminders, including lifecycle history for each reminder.
|
|
879
|
+
24. **\`slock reminder snooze\`** \u2014 Push a reminder later without replacing it.
|
|
880
|
+
25. **\`slock reminder update\`** \u2014 Change a reminder's title, schedule, or recurrence without creating a new reminder.
|
|
881
|
+
26. **\`slock reminder cancel\`** \u2014 Cancel one of your reminders by ID.
|
|
882
|
+
27. **\`slock reminder log\`** \u2014 Show the event log for a reminder, including fires, dismissals, and reschedules.
|
|
883
|
+
28. **\`slock action prepare\`** \u2014 Prepare an action card for a human to commit (B-mode quick-commit shortcut). Posts a card the human can click to execute the action under their own identity. Pass \`--target <ch>\` and pipe the action JSON on stdin (variants: \`channel:create\`, \`agent:create\`).
|
|
881
884
|
|
|
882
885
|
The CLI prints human-readable canonical text on success (matching the format you see in received messages and history). On failure it prints JSON to stderr:
|
|
883
886
|
- failure \u2192 stderr \`{"ok":false,"code":"...","message":"..."}\` with non-zero exit
|
|
@@ -978,6 +981,11 @@ Each channel has a **name** and optionally a **description** that define its pur
|
|
|
978
981
|
- **Reply in context** \u2014 always respond in the channel/thread the message came from.
|
|
979
982
|
- **Stay on topic** \u2014 when proactively sharing results or updates, post in the channel most relevant to the work. Don't scatter messages across unrelated channels.
|
|
980
983
|
- If unsure where something belongs, call ${serverInfoCmd} to review channel descriptions.`;
|
|
984
|
+
const thirdPartyIntegrationsSection = isCli ? `### Third-party integrations
|
|
985
|
+
|
|
986
|
+
If a registered third-party service requires login, use Slock Agent Login through the CLI instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app, first run \`slock integration list\` and match the app to a registered service before browsing the app. Use \`slock integration login --service <service>\` to provision or reuse your agent login for that service. When the command returns \`Agent login ready\` or \`Already logged in\`, the agent-side login is ready. If the output includes an app URL, open that URL as the service-provided third-party app surface; it should look like the service's normal Login with Slock callback and not require you to understand Slock's internal grant/request protocol. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow, use internal request IDs as OAuth callback codes, or call third-party exchange endpoints unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use \`slock profile show\`. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the registered service / Slock Agent Login path.` : `### Third-party integrations
|
|
987
|
+
|
|
988
|
+
If a registered third-party service requires login, use Slock Agent Login through the available registered-service interface instead of asking the human to copy tokens or complete human OAuth for you. If a human asks you to sign into, open, use, or fetch identity from a third-party app, first inspect the registered-service interface and match the app to a registered service before browsing the app. Once the registered-service interface reports the agent login is ready, the agent-side login is ready. If that interface provides an app URL, use it as the service-provided third-party app surface; it should look like the service's normal Login with Slock callback and not require you to understand Slock's internal grant/request protocol. Do not crawl third-party routes looking for a session before trying the registered-service login path. Do not open the human \`Login with Slock\` browser flow or treat internal request IDs as OAuth callback codes unless a human explicitly asks you to debug that server-to-server protocol. If the service or human asks for your Slock Agent identity card, use your Slock profile view. Third-party pages may show \`Login with Slock\`; for agent-facing access, prefer the registered service / Slock Agent Login path.`;
|
|
981
989
|
const readingHistorySection = isCli ? `### Reading history
|
|
982
990
|
|
|
983
991
|
\`slock message read --channel "#channel-name"\` or \`slock message read --channel dm:@peer-name\` or \`slock message read --channel "#channel:shortid"\`
|
|
@@ -1149,6 +1157,8 @@ ${discoverySection}
|
|
|
1149
1157
|
|
|
1150
1158
|
${channelAwarenessSection}
|
|
1151
1159
|
|
|
1160
|
+
${thirdPartyIntegrationsSection}
|
|
1161
|
+
|
|
1152
1162
|
${readingHistorySection}
|
|
1153
1163
|
|
|
1154
1164
|
${historicalReferenceSection}
|
|
@@ -1180,6 +1190,17 @@ Keep the user informed. They cannot see your internal reasoning, so:
|
|
|
1180
1190
|
- For multi-step work, send short progress updates (e.g. "Working on step 2/3\u2026").
|
|
1181
1191
|
- When done, summarize the result.
|
|
1182
1192
|
- Keep updates concise \u2014 one or two sentences. Don't flood the chat.
|
|
1193
|
+
- 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:
|
|
1194
|
+
|
|
1195
|
+
\`\`\`html
|
|
1196
|
+
<details>
|
|
1197
|
+
<summary>Evidence, logs, or edge cases</summary>
|
|
1198
|
+
|
|
1199
|
+
Detailed notes go here.
|
|
1200
|
+
</details>
|
|
1201
|
+
\`\`\`
|
|
1202
|
+
|
|
1203
|
+
Do not hide the main recommendation, blocker, or required action inside \`<details>\`; only fold supporting evidence, logs, alternatives, or extended rationale.
|
|
1183
1204
|
|
|
1184
1205
|
### Conversation etiquette
|
|
1185
1206
|
|
|
@@ -1349,12 +1370,26 @@ function listLegacySlockStatePaths(slockHome = resolveSlockHome(), homeDir = os.
|
|
|
1349
1370
|
return candidates.filter((candidate) => existsSync(candidate.path));
|
|
1350
1371
|
}
|
|
1351
1372
|
|
|
1373
|
+
// src/authEnv.ts
|
|
1374
|
+
var DAEMON_API_KEY_ENV = "SLOCK_MACHINE_API_KEY";
|
|
1375
|
+
var SLOCK_AGENT_TOKEN_ENV = "SLOCK_AGENT_TOKEN";
|
|
1376
|
+
function scrubDaemonAuthEnv(env) {
|
|
1377
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
1378
|
+
return env;
|
|
1379
|
+
}
|
|
1380
|
+
function scrubDaemonChildEnv(env) {
|
|
1381
|
+
delete env[DAEMON_API_KEY_ENV];
|
|
1382
|
+
delete env[SLOCK_AGENT_TOKEN_ENV];
|
|
1383
|
+
return env;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1352
1386
|
// src/agentCredentialProxy.ts
|
|
1353
1387
|
import { randomBytes } from "crypto";
|
|
1354
1388
|
import http from "http";
|
|
1355
1389
|
import { URL as URL2 } from "url";
|
|
1356
1390
|
var registrations = /* @__PURE__ */ new Map();
|
|
1357
1391
|
var servers = /* @__PURE__ */ new Map();
|
|
1392
|
+
var DECODED_RESPONSE_HEADERS = /* @__PURE__ */ new Set(["content-encoding", "content-length", "transfer-encoding"]);
|
|
1358
1393
|
function allocatePort() {
|
|
1359
1394
|
return 43e3 + randomBytes(2).readUInt16BE(0) % 1e4;
|
|
1360
1395
|
}
|
|
@@ -1370,6 +1405,14 @@ function ensureServer(port) {
|
|
|
1370
1405
|
server.unref();
|
|
1371
1406
|
servers.set(port, server);
|
|
1372
1407
|
}
|
|
1408
|
+
function responseHeadersForLocalProxy(upstream) {
|
|
1409
|
+
const headers = {};
|
|
1410
|
+
for (const [name, value] of upstream.headers.entries()) {
|
|
1411
|
+
if (DECODED_RESPONSE_HEADERS.has(name.toLowerCase())) continue;
|
|
1412
|
+
headers[name] = value;
|
|
1413
|
+
}
|
|
1414
|
+
return headers;
|
|
1415
|
+
}
|
|
1373
1416
|
async function handleProxyRequest(req, res) {
|
|
1374
1417
|
const auth = req.headers.authorization;
|
|
1375
1418
|
const token = typeof auth === "string" && auth.startsWith("Bearer ") ? auth.slice("Bearer ".length) : "";
|
|
@@ -1423,11 +1466,11 @@ async function handleProxyRequest(req, res) {
|
|
|
1423
1466
|
if (shouldBufferJsonResponse(upstream, target.pathname, registration)) {
|
|
1424
1467
|
const responseText = await upstream.text();
|
|
1425
1468
|
consumeVisibleResponse(registration, target, sendTarget, responseText);
|
|
1426
|
-
res.writeHead(upstream.status,
|
|
1469
|
+
res.writeHead(upstream.status, responseHeadersForLocalProxy(upstream));
|
|
1427
1470
|
res.end(responseText);
|
|
1428
1471
|
return;
|
|
1429
1472
|
}
|
|
1430
|
-
res.writeHead(upstream.status,
|
|
1473
|
+
res.writeHead(upstream.status, responseHeadersForLocalProxy(upstream));
|
|
1431
1474
|
if (upstream.body) {
|
|
1432
1475
|
const reader = upstream.body.getReader();
|
|
1433
1476
|
try {
|
|
@@ -1724,7 +1767,7 @@ ${cmdCredentialLine}"${process.execPath}" "${ctx.slockCliPath}" %*\r
|
|
|
1724
1767
|
...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
|
|
1725
1768
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
1726
1769
|
};
|
|
1727
|
-
|
|
1770
|
+
scrubDaemonChildEnv(spawnEnv);
|
|
1728
1771
|
delete spawnEnv.SLOCK_AGENT_CREDENTIAL_KEY;
|
|
1729
1772
|
delete spawnEnv.SLOCK_AGENT_CREDENTIAL_KEY_FILE;
|
|
1730
1773
|
delete spawnEnv.SLOCK_AGENT_PROXY_URL;
|
|
@@ -1771,7 +1814,7 @@ function resolveCommandOnWindows(command, env, execFileSyncFn) {
|
|
|
1771
1814
|
}
|
|
1772
1815
|
function resolveCommandOnPath(command, deps = {}) {
|
|
1773
1816
|
const platform = deps.platform ?? process.platform;
|
|
1774
|
-
const env = deps.env ?? process.env;
|
|
1817
|
+
const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
|
|
1775
1818
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
1776
1819
|
if (platform === "win32") {
|
|
1777
1820
|
return resolveCommandOnWindows(command, env, execFileSyncFn);
|
|
@@ -1796,7 +1839,7 @@ function firstExistingPath(candidates, deps = {}) {
|
|
|
1796
1839
|
return null;
|
|
1797
1840
|
}
|
|
1798
1841
|
function readCommandVersion(command, args = [], deps = {}) {
|
|
1799
|
-
const env = deps.env ?? process.env;
|
|
1842
|
+
const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
|
|
1800
1843
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync;
|
|
1801
1844
|
try {
|
|
1802
1845
|
const output = normalizeExecOutput(execFileSyncFn(command, [...args, "--version"], {
|
|
@@ -3093,7 +3136,7 @@ function detectCursorModels(runCommand = runCursorModelsCommand) {
|
|
|
3093
3136
|
}
|
|
3094
3137
|
function runCursorModelsCommand() {
|
|
3095
3138
|
return spawnSync("cursor-agent", ["models"], {
|
|
3096
|
-
env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
3139
|
+
env: scrubDaemonChildEnv({ ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" }),
|
|
3097
3140
|
encoding: "utf8",
|
|
3098
3141
|
timeout: 5e3
|
|
3099
3142
|
});
|
|
@@ -3140,7 +3183,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
3140
3183
|
}
|
|
3141
3184
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
3142
3185
|
const existsSyncFn = deps.existsSyncFn ?? existsSync6;
|
|
3143
|
-
const env = deps.env ?? process.env;
|
|
3186
|
+
const env = scrubDaemonChildEnv({ ...deps.env ?? process.env });
|
|
3144
3187
|
const winPath = path8.win32;
|
|
3145
3188
|
let geminiEntry = null;
|
|
3146
3189
|
try {
|
|
@@ -3314,13 +3357,16 @@ var GeminiDriver = class {
|
|
|
3314
3357
|
// src/drivers/kimi.ts
|
|
3315
3358
|
import { randomUUID } from "crypto";
|
|
3316
3359
|
import { spawn as spawn6 } from "child_process";
|
|
3317
|
-
import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
3360
|
+
import { chmodSync, existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
3318
3361
|
import os4 from "os";
|
|
3319
3362
|
import path9 from "path";
|
|
3320
3363
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
3321
3364
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
3322
3365
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
3323
3366
|
var KIMI_MCP_FILE = ".slock-kimi-mcp.json";
|
|
3367
|
+
var KIMI_GENERATED_CONFIG_FILE = ".slock-kimi-config.toml";
|
|
3368
|
+
var SLOCK_KIMI_CONFIG_CONTENT_ENV = "SLOCK_KIMI_CONFIG_CONTENT";
|
|
3369
|
+
var SLOCK_KIMI_CONFIG_FILE_ENV = "SLOCK_KIMI_CONFIG_FILE";
|
|
3324
3370
|
function parseToolArguments(raw) {
|
|
3325
3371
|
if (typeof raw !== "string") return raw;
|
|
3326
3372
|
try {
|
|
@@ -3329,6 +3375,73 @@ function parseToolArguments(raw) {
|
|
|
3329
3375
|
return raw;
|
|
3330
3376
|
}
|
|
3331
3377
|
}
|
|
3378
|
+
function readKimiConfigSource(home = os4.homedir(), env = process.env) {
|
|
3379
|
+
const inlineConfig = env[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
3380
|
+
if (inlineConfig && inlineConfig.trim()) {
|
|
3381
|
+
return {
|
|
3382
|
+
raw: inlineConfig,
|
|
3383
|
+
explicitPath: null,
|
|
3384
|
+
sourcePath: SLOCK_KIMI_CONFIG_CONTENT_ENV
|
|
3385
|
+
};
|
|
3386
|
+
}
|
|
3387
|
+
const explicitPath = env[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
3388
|
+
const configPath = explicitPath && explicitPath.trim() ? explicitPath : path9.join(home, ".kimi", "config.toml");
|
|
3389
|
+
try {
|
|
3390
|
+
return {
|
|
3391
|
+
raw: readFileSync3(configPath, "utf8"),
|
|
3392
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
3393
|
+
sourcePath: configPath
|
|
3394
|
+
};
|
|
3395
|
+
} catch {
|
|
3396
|
+
return {
|
|
3397
|
+
raw: null,
|
|
3398
|
+
explicitPath: explicitPath && explicitPath.trim() ? explicitPath : null,
|
|
3399
|
+
sourcePath: configPath
|
|
3400
|
+
};
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
function buildKimiSpawnEnv(env = process.env) {
|
|
3404
|
+
const spawnEnv = { ...env, FORCE_COLOR: "0", NO_COLOR: "1" };
|
|
3405
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_CONTENT_ENV];
|
|
3406
|
+
delete spawnEnv[SLOCK_KIMI_CONFIG_FILE_ENV];
|
|
3407
|
+
return scrubDaemonChildEnv(spawnEnv);
|
|
3408
|
+
}
|
|
3409
|
+
function buildKimiEffectiveEnv(ctx, overrideEnv) {
|
|
3410
|
+
return {
|
|
3411
|
+
...process.env,
|
|
3412
|
+
...ctx.config.envVars || {},
|
|
3413
|
+
...overrideEnv || {}
|
|
3414
|
+
};
|
|
3415
|
+
}
|
|
3416
|
+
function buildKimiLaunchOptions(ctx, opts = {}) {
|
|
3417
|
+
const env = buildKimiEffectiveEnv(ctx, opts.env);
|
|
3418
|
+
const source = readKimiConfigSource(opts.home ?? os4.homedir(), env);
|
|
3419
|
+
const args = [];
|
|
3420
|
+
let configFilePath = null;
|
|
3421
|
+
let configContent = null;
|
|
3422
|
+
if (source.explicitPath) {
|
|
3423
|
+
configFilePath = source.explicitPath;
|
|
3424
|
+
} else if (source.raw !== null && source.sourcePath === SLOCK_KIMI_CONFIG_CONTENT_ENV) {
|
|
3425
|
+
configFilePath = path9.join(ctx.workingDirectory, KIMI_GENERATED_CONFIG_FILE);
|
|
3426
|
+
configContent = source.raw;
|
|
3427
|
+
if (opts.writeGeneratedConfig !== false) {
|
|
3428
|
+
writeFileSync6(configFilePath, source.raw, { encoding: "utf8", mode: 384 });
|
|
3429
|
+
chmodSync(configFilePath, 384);
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
if (configFilePath) {
|
|
3433
|
+
args.push("--config-file", configFilePath);
|
|
3434
|
+
}
|
|
3435
|
+
if (ctx.config.model && ctx.config.model !== "default") {
|
|
3436
|
+
args.push("--model", ctx.config.model);
|
|
3437
|
+
}
|
|
3438
|
+
return {
|
|
3439
|
+
args,
|
|
3440
|
+
env: buildKimiSpawnEnv(env),
|
|
3441
|
+
configFilePath,
|
|
3442
|
+
configContent
|
|
3443
|
+
};
|
|
3444
|
+
}
|
|
3332
3445
|
function resolveKimiSpawn(commandArgs, deps = {}) {
|
|
3333
3446
|
return {
|
|
3334
3447
|
command: resolveCommandOnPath("kimi", deps) ?? "kimi",
|
|
@@ -3352,7 +3465,25 @@ var KimiDriver = class {
|
|
|
3352
3465
|
};
|
|
3353
3466
|
model = {
|
|
3354
3467
|
detectedModelsVerifiedAs: "launchable",
|
|
3355
|
-
toLaunchSpec: (modelId) =>
|
|
3468
|
+
toLaunchSpec: (modelId, ctx, opts) => {
|
|
3469
|
+
if (!ctx) return { args: ["--model", modelId] };
|
|
3470
|
+
const launchCtx = {
|
|
3471
|
+
...ctx,
|
|
3472
|
+
config: {
|
|
3473
|
+
...ctx.config,
|
|
3474
|
+
model: modelId
|
|
3475
|
+
}
|
|
3476
|
+
};
|
|
3477
|
+
const launch = buildKimiLaunchOptions(launchCtx, {
|
|
3478
|
+
home: opts?.home,
|
|
3479
|
+
writeGeneratedConfig: false
|
|
3480
|
+
});
|
|
3481
|
+
return {
|
|
3482
|
+
args: launch.args,
|
|
3483
|
+
env: launch.env,
|
|
3484
|
+
configFiles: launch.configFilePath ? [launch.configFilePath] : void 0
|
|
3485
|
+
};
|
|
3486
|
+
}
|
|
3356
3487
|
};
|
|
3357
3488
|
supportsStdinNotification = true;
|
|
3358
3489
|
mcpToolPrefix = "";
|
|
@@ -3406,6 +3537,7 @@ var KimiDriver = class {
|
|
|
3406
3537
|
}
|
|
3407
3538
|
}
|
|
3408
3539
|
}), "utf8");
|
|
3540
|
+
const launch = buildKimiLaunchOptions(ctx);
|
|
3409
3541
|
const args = [
|
|
3410
3542
|
"--wire",
|
|
3411
3543
|
"--yolo",
|
|
@@ -3414,14 +3546,15 @@ var KimiDriver = class {
|
|
|
3414
3546
|
"--mcp-config-file",
|
|
3415
3547
|
mcpConfigPath,
|
|
3416
3548
|
"--session",
|
|
3417
|
-
this.sessionId
|
|
3549
|
+
this.sessionId,
|
|
3550
|
+
...launch.args
|
|
3418
3551
|
];
|
|
3419
3552
|
if (ctx.config.model && ctx.config.model !== "default") {
|
|
3420
3553
|
args.push("--model", ctx.config.model);
|
|
3421
3554
|
}
|
|
3422
3555
|
const spawnEnv = prepareCliTransport(ctx, { NO_COLOR: "1" }).spawnEnv;
|
|
3423
|
-
const
|
|
3424
|
-
const proc = spawn6(
|
|
3556
|
+
const spawnTarget = resolveKimiSpawn(args);
|
|
3557
|
+
const proc = spawn6(spawnTarget.command, spawnTarget.args, {
|
|
3425
3558
|
cwd: ctx.workingDirectory,
|
|
3426
3559
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3427
3560
|
env: spawnEnv,
|
|
@@ -3429,7 +3562,7 @@ var KimiDriver = class {
|
|
|
3429
3562
|
// and has an 8191-character command-line limit. Kimi's official
|
|
3430
3563
|
// installer/uv entrypoint is an executable, so launch it directly and
|
|
3431
3564
|
// keep prompts on stdin / files instead of routing through cmd.exe.
|
|
3432
|
-
shell:
|
|
3565
|
+
shell: spawnTarget.shell
|
|
3433
3566
|
});
|
|
3434
3567
|
proc.stdin?.write(JSON.stringify({
|
|
3435
3568
|
jsonrpc: "2.0",
|
|
@@ -3545,14 +3678,9 @@ var KimiDriver = class {
|
|
|
3545
3678
|
return detectKimiModels();
|
|
3546
3679
|
}
|
|
3547
3680
|
};
|
|
3548
|
-
function detectKimiModels(home = os4.homedir()) {
|
|
3549
|
-
const
|
|
3550
|
-
|
|
3551
|
-
try {
|
|
3552
|
-
raw = readFileSync3(configPath, "utf8");
|
|
3553
|
-
} catch {
|
|
3554
|
-
return null;
|
|
3555
|
-
}
|
|
3681
|
+
function detectKimiModels(home = os4.homedir(), opts = {}) {
|
|
3682
|
+
const raw = readKimiConfigSource(home, opts.env).raw;
|
|
3683
|
+
if (raw === null) return null;
|
|
3556
3684
|
const models = [];
|
|
3557
3685
|
const sectionRe = /^\s*\[models(?:\.([^\]]+)|"\.[^"]+"|\."[^"]+")\s*\]\s*$/gm;
|
|
3558
3686
|
const lineRe = /^\s*\[models\.(.+?)\s*\]\s*$/gm;
|
|
@@ -3813,7 +3941,7 @@ function detectOpenCodeModels(home = os5.homedir(), runCommand = runOpenCodeMode
|
|
|
3813
3941
|
}
|
|
3814
3942
|
function runOpenCodeModelsCommand(home) {
|
|
3815
3943
|
const result = spawnSync2("opencode", ["models"], {
|
|
3816
|
-
env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
3944
|
+
env: scrubDaemonChildEnv({ ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" }),
|
|
3817
3945
|
encoding: "utf8",
|
|
3818
3946
|
timeout: 5e3
|
|
3819
3947
|
});
|
|
@@ -3971,6 +4099,297 @@ var OpenCodeDriver = class {
|
|
|
3971
4099
|
}
|
|
3972
4100
|
};
|
|
3973
4101
|
|
|
4102
|
+
// src/drivers/pi.ts
|
|
4103
|
+
import { spawn as spawn8 } from "child_process";
|
|
4104
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
4105
|
+
import path11 from "path";
|
|
4106
|
+
import { fileURLToPath } from "url";
|
|
4107
|
+
import { getAgentDir, VERSION as PI_SDK_VERSION } from "@earendil-works/pi-coding-agent";
|
|
4108
|
+
var CHAT_MCP_TOOL_PREFIX2 = "chat_";
|
|
4109
|
+
var NO_MESSAGE_PROMPT2 = "No new messages are pending. Stop now.";
|
|
4110
|
+
var FIRST_MESSAGE_TASK_PREFIX2 = "First message task (system-triggered):";
|
|
4111
|
+
var MIN_SUPPORTED_PI_VERSION = "0.74.0";
|
|
4112
|
+
function parseSemver2(version) {
|
|
4113
|
+
const match = version.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
4114
|
+
if (!match) return null;
|
|
4115
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
4116
|
+
}
|
|
4117
|
+
function isSupportedPiVersion(version) {
|
|
4118
|
+
if (!version) return true;
|
|
4119
|
+
const actual = parseSemver2(version);
|
|
4120
|
+
const minimum = parseSemver2(MIN_SUPPORTED_PI_VERSION);
|
|
4121
|
+
if (!actual || !minimum) return true;
|
|
4122
|
+
for (let i = 0; i < 3; i += 1) {
|
|
4123
|
+
if (actual[i] > minimum[i]) return true;
|
|
4124
|
+
if (actual[i] < minimum[i]) return false;
|
|
4125
|
+
}
|
|
4126
|
+
return true;
|
|
4127
|
+
}
|
|
4128
|
+
function unsupportedPiVersionMessage(version) {
|
|
4129
|
+
if (!version || isSupportedPiVersion(version)) return null;
|
|
4130
|
+
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.`;
|
|
4131
|
+
}
|
|
4132
|
+
function probePi(version = PI_SDK_VERSION) {
|
|
4133
|
+
const unsupportedMessage = unsupportedPiVersionMessage(version);
|
|
4134
|
+
if (unsupportedMessage) {
|
|
4135
|
+
return {
|
|
4136
|
+
available: false,
|
|
4137
|
+
version: `${version} (requires @earendil-works/pi-coding-agent >= ${MIN_SUPPORTED_PI_VERSION})`
|
|
4138
|
+
};
|
|
4139
|
+
}
|
|
4140
|
+
return { available: true, version };
|
|
4141
|
+
}
|
|
4142
|
+
function resolvePiSdkRunnerPath(moduleUrl = import.meta.url) {
|
|
4143
|
+
const moduleDir = path11.dirname(fileURLToPath(moduleUrl));
|
|
4144
|
+
const sourceSibling = path11.join(moduleDir, "piSdkRunner.ts");
|
|
4145
|
+
if (existsSync8(sourceSibling)) return sourceSibling;
|
|
4146
|
+
const bundledEntry = path11.join(moduleDir, "drivers", "piSdkRunner.js");
|
|
4147
|
+
if (existsSync8(bundledEntry)) return bundledEntry;
|
|
4148
|
+
return path11.join(moduleDir, "piSdkRunner.js");
|
|
4149
|
+
}
|
|
4150
|
+
function buildPiSdkNodeArgs(runnerPath = resolvePiSdkRunnerPath()) {
|
|
4151
|
+
if (runnerPath.endsWith(".ts")) {
|
|
4152
|
+
return [...process.execArgv, runnerPath];
|
|
4153
|
+
}
|
|
4154
|
+
return [runnerPath];
|
|
4155
|
+
}
|
|
4156
|
+
function buildPiLaunchOptions(ctx, opts = {}) {
|
|
4157
|
+
const command = opts.command ?? process.execPath;
|
|
4158
|
+
const piDir = path11.join(ctx.workingDirectory, ".slock", "pi");
|
|
4159
|
+
const sessionDir = path11.join(piDir, "sessions");
|
|
4160
|
+
mkdirSync4(sessionDir, { recursive: true });
|
|
4161
|
+
const slock = prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
4162
|
+
const runnerPath = opts.runnerPath ?? resolvePiSdkRunnerPath();
|
|
4163
|
+
const agentDir = opts.agentDir ?? getAgentDir();
|
|
4164
|
+
const runnerConfigPath = path11.join(
|
|
4165
|
+
piDir,
|
|
4166
|
+
`sdk-run-${(ctx.launchId || "launch").replace(/[^a-zA-Z0-9_.-]/g, "_")}.json`
|
|
4167
|
+
);
|
|
4168
|
+
const turnPrompt = ctx.prompt === ctx.standingPrompt ? NO_MESSAGE_PROMPT2 : ctx.prompt;
|
|
4169
|
+
const runnerConfig = {
|
|
4170
|
+
cwd: ctx.workingDirectory,
|
|
4171
|
+
agentDir,
|
|
4172
|
+
sessionDir,
|
|
4173
|
+
sessionId: ctx.config.sessionId || null,
|
|
4174
|
+
standingPrompt: ctx.standingPrompt,
|
|
4175
|
+
prompt: turnPrompt,
|
|
4176
|
+
model: ctx.config.model && ctx.config.model !== "default" ? ctx.config.model : null
|
|
4177
|
+
};
|
|
4178
|
+
writeFileSync7(runnerConfigPath, `${JSON.stringify(runnerConfig)}
|
|
4179
|
+
`, { encoding: "utf8", mode: 384 });
|
|
4180
|
+
const args = [
|
|
4181
|
+
...buildPiSdkNodeArgs(runnerPath),
|
|
4182
|
+
"--config",
|
|
4183
|
+
runnerConfigPath
|
|
4184
|
+
];
|
|
4185
|
+
return {
|
|
4186
|
+
command,
|
|
4187
|
+
args,
|
|
4188
|
+
env: slock.spawnEnv,
|
|
4189
|
+
sessionDir,
|
|
4190
|
+
agentDir,
|
|
4191
|
+
runnerConfigPath,
|
|
4192
|
+
sdkVersion: PI_SDK_VERSION
|
|
4193
|
+
};
|
|
4194
|
+
}
|
|
4195
|
+
function isSystemFirstMessageTask2(message) {
|
|
4196
|
+
return message.sender_id === "system" && message.channel_type === "channel" && message.channel_name === "all" && message.content.trimStart().startsWith(FIRST_MESSAGE_TASK_PREFIX2);
|
|
4197
|
+
}
|
|
4198
|
+
function buildPiSystemPrompt(config) {
|
|
4199
|
+
return buildCliTransportSystemPrompt(config, {
|
|
4200
|
+
toolPrefix: CHAT_MCP_TOOL_PREFIX2,
|
|
4201
|
+
extraCriticalRules: [
|
|
4202
|
+
"- 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."
|
|
4203
|
+
],
|
|
4204
|
+
postStartupNotes: [
|
|
4205
|
+
"**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."
|
|
4206
|
+
],
|
|
4207
|
+
includeStdinNotificationSection: false,
|
|
4208
|
+
messageNotificationStyle: "poll"
|
|
4209
|
+
});
|
|
4210
|
+
}
|
|
4211
|
+
function contentText(content) {
|
|
4212
|
+
if (!content) return "";
|
|
4213
|
+
const chunks = [];
|
|
4214
|
+
for (const item of content) {
|
|
4215
|
+
if (item.type === "text" && typeof item.text === "string") {
|
|
4216
|
+
chunks.push(item.text);
|
|
4217
|
+
}
|
|
4218
|
+
}
|
|
4219
|
+
return chunks.join("");
|
|
4220
|
+
}
|
|
4221
|
+
function apiKeyErrorMessage(line) {
|
|
4222
|
+
const trimmed = line.trim();
|
|
4223
|
+
if (!trimmed) return null;
|
|
4224
|
+
if (/no api key found/i.test(trimmed)) return trimmed;
|
|
4225
|
+
if (/api key.+required/i.test(trimmed)) return trimmed;
|
|
4226
|
+
if (/no models available/i.test(trimmed)) return trimmed;
|
|
4227
|
+
return null;
|
|
4228
|
+
}
|
|
4229
|
+
var PiDriver = class {
|
|
4230
|
+
id = "pi";
|
|
4231
|
+
lifecycle = {
|
|
4232
|
+
kind: "per_turn",
|
|
4233
|
+
start: "defer_until_concrete_message",
|
|
4234
|
+
exit: "terminate_on_turn_end",
|
|
4235
|
+
inFlightWake: "coalesce_into_pending"
|
|
4236
|
+
};
|
|
4237
|
+
communication = {
|
|
4238
|
+
chat: "slock_cli",
|
|
4239
|
+
runtimeControl: "none"
|
|
4240
|
+
};
|
|
4241
|
+
session = {
|
|
4242
|
+
recovery: "resume_or_fresh"
|
|
4243
|
+
};
|
|
4244
|
+
model = {
|
|
4245
|
+
detectedModelsVerifiedAs: "launchable",
|
|
4246
|
+
toLaunchSpec: (modelId, ctx) => {
|
|
4247
|
+
if (!ctx) return modelId && modelId !== "default" ? { args: ["--model", modelId] } : { args: [] };
|
|
4248
|
+
const launchCtx = {
|
|
4249
|
+
...ctx,
|
|
4250
|
+
config: {
|
|
4251
|
+
...ctx.config,
|
|
4252
|
+
model: modelId
|
|
4253
|
+
}
|
|
4254
|
+
};
|
|
4255
|
+
const launch = buildPiLaunchOptions(launchCtx);
|
|
4256
|
+
return {
|
|
4257
|
+
args: launch.args,
|
|
4258
|
+
env: launch.env,
|
|
4259
|
+
configFiles: [launch.runnerConfigPath],
|
|
4260
|
+
params: {
|
|
4261
|
+
agentDir: launch.agentDir,
|
|
4262
|
+
sessionDir: launch.sessionDir,
|
|
4263
|
+
sdkVersion: launch.sdkVersion,
|
|
4264
|
+
resources: "extensions/skills/prompt-templates/themes/context-files disabled by Slock policy"
|
|
4265
|
+
}
|
|
4266
|
+
};
|
|
4267
|
+
}
|
|
4268
|
+
};
|
|
4269
|
+
supportsStdinNotification = false;
|
|
4270
|
+
mcpToolPrefix = CHAT_MCP_TOOL_PREFIX2;
|
|
4271
|
+
busyDeliveryMode = "none";
|
|
4272
|
+
terminateProcessOnTurnEnd = true;
|
|
4273
|
+
deferSpawnUntilMessage = true;
|
|
4274
|
+
usesSlockCliForCommunication = true;
|
|
4275
|
+
sessionId = null;
|
|
4276
|
+
sessionAnnounced = false;
|
|
4277
|
+
apiKeyErrorAnnounced = false;
|
|
4278
|
+
turnEnded = false;
|
|
4279
|
+
assistantTextByMessageId = /* @__PURE__ */ new Map();
|
|
4280
|
+
shouldDeferWakeMessage(message) {
|
|
4281
|
+
return isSystemFirstMessageTask2(message);
|
|
4282
|
+
}
|
|
4283
|
+
probe() {
|
|
4284
|
+
return probePi();
|
|
4285
|
+
}
|
|
4286
|
+
async detectModels() {
|
|
4287
|
+
return null;
|
|
4288
|
+
}
|
|
4289
|
+
spawn(ctx) {
|
|
4290
|
+
this.sessionId = ctx.config.sessionId || null;
|
|
4291
|
+
this.sessionAnnounced = false;
|
|
4292
|
+
this.apiKeyErrorAnnounced = false;
|
|
4293
|
+
this.turnEnded = false;
|
|
4294
|
+
this.assistantTextByMessageId.clear();
|
|
4295
|
+
const unsupportedMessage = unsupportedPiVersionMessage(PI_SDK_VERSION);
|
|
4296
|
+
if (unsupportedMessage) throw new Error(unsupportedMessage);
|
|
4297
|
+
const launch = buildPiLaunchOptions(ctx);
|
|
4298
|
+
const proc = spawn8(launch.command, launch.args, {
|
|
4299
|
+
cwd: ctx.workingDirectory,
|
|
4300
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
4301
|
+
env: launch.env,
|
|
4302
|
+
shell: false
|
|
4303
|
+
});
|
|
4304
|
+
proc.stdin?.end();
|
|
4305
|
+
return { process: proc };
|
|
4306
|
+
}
|
|
4307
|
+
parseLine(line) {
|
|
4308
|
+
let event;
|
|
4309
|
+
try {
|
|
4310
|
+
event = JSON.parse(line);
|
|
4311
|
+
} catch {
|
|
4312
|
+
if (this.apiKeyErrorAnnounced) return [];
|
|
4313
|
+
const message = apiKeyErrorMessage(line);
|
|
4314
|
+
if (!message) return [];
|
|
4315
|
+
this.apiKeyErrorAnnounced = true;
|
|
4316
|
+
this.turnEnded = true;
|
|
4317
|
+
return [
|
|
4318
|
+
{ kind: "error", message },
|
|
4319
|
+
{ kind: "turn_end", sessionId: this.sessionId || void 0 }
|
|
4320
|
+
];
|
|
4321
|
+
}
|
|
4322
|
+
const events = [];
|
|
4323
|
+
if (event.type === "session" && event.id) {
|
|
4324
|
+
this.sessionId = event.id;
|
|
4325
|
+
}
|
|
4326
|
+
if (!this.sessionAnnounced && this.sessionId) {
|
|
4327
|
+
events.push({ kind: "session_init", sessionId: this.sessionId });
|
|
4328
|
+
this.sessionAnnounced = true;
|
|
4329
|
+
}
|
|
4330
|
+
switch (event.type) {
|
|
4331
|
+
case "agent_start":
|
|
4332
|
+
case "turn_start":
|
|
4333
|
+
events.push({ kind: "thinking", text: "" });
|
|
4334
|
+
break;
|
|
4335
|
+
case "message_update":
|
|
4336
|
+
case "message_end":
|
|
4337
|
+
if (event.message?.role === "assistant") {
|
|
4338
|
+
const key = event.message.id || "current";
|
|
4339
|
+
const currentText = contentText(event.message.content);
|
|
4340
|
+
const previousText = this.assistantTextByMessageId.get(key) ?? "";
|
|
4341
|
+
if (currentText.length > previousText.length && currentText.startsWith(previousText)) {
|
|
4342
|
+
events.push({ kind: "text", text: currentText.slice(previousText.length) });
|
|
4343
|
+
} else if (currentText && currentText !== previousText) {
|
|
4344
|
+
events.push({ kind: "text", text: currentText });
|
|
4345
|
+
}
|
|
4346
|
+
this.assistantTextByMessageId.set(key, currentText);
|
|
4347
|
+
if (event.message.stopReason === "error" || event.message.stopReason === "aborted") {
|
|
4348
|
+
events.push({ kind: "error", message: event.message.errorMessage || `Request ${event.message.stopReason}` });
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
break;
|
|
4352
|
+
case "tool_execution_start":
|
|
4353
|
+
events.push({
|
|
4354
|
+
kind: "tool_call",
|
|
4355
|
+
name: event.toolName || "unknown_tool",
|
|
4356
|
+
input: event.args
|
|
4357
|
+
});
|
|
4358
|
+
break;
|
|
4359
|
+
case "tool_execution_end":
|
|
4360
|
+
events.push({
|
|
4361
|
+
kind: "tool_output",
|
|
4362
|
+
name: event.toolName || "unknown_tool"
|
|
4363
|
+
});
|
|
4364
|
+
if (event.isError) {
|
|
4365
|
+
events.push({ kind: "error", message: `Pi tool ${event.toolName || "unknown_tool"} failed` });
|
|
4366
|
+
}
|
|
4367
|
+
break;
|
|
4368
|
+
case "compaction_start":
|
|
4369
|
+
events.push({ kind: "compaction_started" });
|
|
4370
|
+
break;
|
|
4371
|
+
case "compaction_end":
|
|
4372
|
+
events.push({ kind: "compaction_finished" });
|
|
4373
|
+
if (event.errorMessage) events.push({ kind: "error", message: event.errorMessage });
|
|
4374
|
+
break;
|
|
4375
|
+
case "turn_end":
|
|
4376
|
+
case "agent_end":
|
|
4377
|
+
if (!this.turnEnded) {
|
|
4378
|
+
events.push({ kind: "turn_end", sessionId: this.sessionId || void 0 });
|
|
4379
|
+
this.turnEnded = true;
|
|
4380
|
+
}
|
|
4381
|
+
break;
|
|
4382
|
+
}
|
|
4383
|
+
return events;
|
|
4384
|
+
}
|
|
4385
|
+
encodeStdinMessage(_text, _sessionId, _opts) {
|
|
4386
|
+
return null;
|
|
4387
|
+
}
|
|
4388
|
+
buildSystemPrompt(config, _agentId) {
|
|
4389
|
+
return buildPiSystemPrompt(config);
|
|
4390
|
+
}
|
|
4391
|
+
};
|
|
4392
|
+
|
|
3974
4393
|
// src/drivers/index.ts
|
|
3975
4394
|
var driverFactories = {
|
|
3976
4395
|
claude: () => new ClaudeDriver(),
|
|
@@ -3979,7 +4398,8 @@ var driverFactories = {
|
|
|
3979
4398
|
cursor: () => new CursorDriver(),
|
|
3980
4399
|
gemini: () => new GeminiDriver(),
|
|
3981
4400
|
kimi: () => new KimiDriver(),
|
|
3982
|
-
opencode: () => new OpenCodeDriver()
|
|
4401
|
+
opencode: () => new OpenCodeDriver(),
|
|
4402
|
+
pi: () => new PiDriver()
|
|
3983
4403
|
};
|
|
3984
4404
|
function getDriver(runtimeId) {
|
|
3985
4405
|
const createDriver = driverFactories[runtimeId];
|
|
@@ -3992,7 +4412,7 @@ function getDriver(runtimeId) {
|
|
|
3992
4412
|
|
|
3993
4413
|
// src/workspaces.ts
|
|
3994
4414
|
import { readdir, rm, stat } from "fs/promises";
|
|
3995
|
-
import
|
|
4415
|
+
import path12 from "path";
|
|
3996
4416
|
function isValidWorkspaceDirectoryName(directoryName) {
|
|
3997
4417
|
return !directoryName.includes("/") && !directoryName.includes("\\") && !directoryName.includes("..");
|
|
3998
4418
|
}
|
|
@@ -4000,7 +4420,7 @@ function resolveWorkspaceDirectoryPath(dataDir, directoryName) {
|
|
|
4000
4420
|
if (!isValidWorkspaceDirectoryName(directoryName)) {
|
|
4001
4421
|
return null;
|
|
4002
4422
|
}
|
|
4003
|
-
return
|
|
4423
|
+
return path12.join(dataDir, directoryName);
|
|
4004
4424
|
}
|
|
4005
4425
|
function emptyWorkspaceDirectorySummary(latestMtime = /* @__PURE__ */ new Date(0)) {
|
|
4006
4426
|
return {
|
|
@@ -4049,7 +4469,7 @@ async function summarizeWorkspaceDirectory(dirPath) {
|
|
|
4049
4469
|
return summary;
|
|
4050
4470
|
}
|
|
4051
4471
|
const childSummaries = await Promise.all(
|
|
4052
|
-
entries.map((entry) => summarizeWorkspaceEntry(
|
|
4472
|
+
entries.map((entry) => summarizeWorkspaceEntry(path12.join(dirPath, entry.name), entry))
|
|
4053
4473
|
);
|
|
4054
4474
|
for (const childSummary of childSummaries) {
|
|
4055
4475
|
summary = mergeWorkspaceDirectorySummaries(summary, childSummary);
|
|
@@ -4068,7 +4488,7 @@ async function scanWorkspaceDirectories(dataDir) {
|
|
|
4068
4488
|
if (!entry.isDirectory()) {
|
|
4069
4489
|
return null;
|
|
4070
4490
|
}
|
|
4071
|
-
const dirPath =
|
|
4491
|
+
const dirPath = path12.join(dataDir, entry.name);
|
|
4072
4492
|
try {
|
|
4073
4493
|
const summary = await summarizeWorkspaceDirectory(dirPath);
|
|
4074
4494
|
return {
|
|
@@ -4325,12 +4745,12 @@ function findSessionJsonl(root, predicate) {
|
|
|
4325
4745
|
for (const entry of entries) {
|
|
4326
4746
|
if (++visited > maxEntries) return null;
|
|
4327
4747
|
if (!entry.isFile() || !predicate(entry.name)) continue;
|
|
4328
|
-
return
|
|
4748
|
+
return path13.join(dir, entry.name);
|
|
4329
4749
|
}
|
|
4330
4750
|
for (const entry of entries) {
|
|
4331
4751
|
if (++visited > maxEntries) return null;
|
|
4332
4752
|
if (!entry.isDirectory()) continue;
|
|
4333
|
-
const found = visit(
|
|
4753
|
+
const found = visit(path13.join(dir, entry.name), depth - 1);
|
|
4334
4754
|
if (found) return found;
|
|
4335
4755
|
}
|
|
4336
4756
|
return null;
|
|
@@ -4343,10 +4763,10 @@ function safeSessionFilename(value) {
|
|
|
4343
4763
|
}
|
|
4344
4764
|
function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
4345
4765
|
try {
|
|
4346
|
-
const dir =
|
|
4347
|
-
|
|
4348
|
-
const filePath =
|
|
4349
|
-
|
|
4766
|
+
const dir = path13.join(fallbackDir, ".slock", "runtime-sessions");
|
|
4767
|
+
mkdirSync5(dir, { recursive: true });
|
|
4768
|
+
const filePath = path13.join(dir, `${runtime}-${safeSessionFilename(sessionId)}.jsonl`);
|
|
4769
|
+
writeFileSync8(filePath, JSON.stringify({
|
|
4350
4770
|
type: "runtime_session_handoff",
|
|
4351
4771
|
runtime,
|
|
4352
4772
|
sessionId,
|
|
@@ -4365,7 +4785,7 @@ function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
|
4365
4785
|
}
|
|
4366
4786
|
}
|
|
4367
4787
|
function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os6.homedir(), fallbackDir) {
|
|
4368
|
-
const directPath =
|
|
4788
|
+
const directPath = path13.isAbsolute(sessionId) ? sessionId : null;
|
|
4369
4789
|
if (directPath) {
|
|
4370
4790
|
try {
|
|
4371
4791
|
if (statSync2(directPath).isFile()) {
|
|
@@ -4374,7 +4794,7 @@ function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os6.homedir(), f
|
|
|
4374
4794
|
} catch {
|
|
4375
4795
|
}
|
|
4376
4796
|
}
|
|
4377
|
-
const resolvedPath = runtime === "claude" ? findSessionJsonl(
|
|
4797
|
+
const resolvedPath = runtime === "claude" ? findSessionJsonl(path13.join(homeDir, ".claude", "projects"), (filename) => filename === `${sessionId}.jsonl`) : runtime === "codex" ? findSessionJsonl(path13.join(homeDir, ".codex", "sessions"), (filename) => filename.endsWith(".jsonl") && filename.includes(sessionId)) : null;
|
|
4378
4798
|
if (!resolvedPath && fallbackDir) {
|
|
4379
4799
|
const fallback = writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir);
|
|
4380
4800
|
if (fallback) return fallback;
|
|
@@ -5608,26 +6028,26 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
5608
6028
|
this.recordDaemonTrace("daemon.agent.spawn.started", this.startQueueTraceAttrs(agentId, config, wakeMessage, unreadSummary, resumePrompt, launchId));
|
|
5609
6029
|
try {
|
|
5610
6030
|
const driver = this.driverResolver(config.runtime || "claude");
|
|
5611
|
-
const agentDataDir =
|
|
6031
|
+
const agentDataDir = path13.join(this.dataDir, agentId);
|
|
5612
6032
|
await mkdir(agentDataDir, { recursive: true });
|
|
5613
6033
|
const runtimeConfig = withLocalRuntimeContext(config, agentId, agentDataDir);
|
|
5614
|
-
const memoryMdPath =
|
|
6034
|
+
const memoryMdPath = path13.join(agentDataDir, "MEMORY.md");
|
|
5615
6035
|
try {
|
|
5616
6036
|
await access(memoryMdPath);
|
|
5617
6037
|
} catch {
|
|
5618
6038
|
const initialMemoryMd = buildInitialMemoryMd(runtimeConfig);
|
|
5619
6039
|
await writeFile(memoryMdPath, initialMemoryMd);
|
|
5620
6040
|
}
|
|
5621
|
-
const notesDir =
|
|
6041
|
+
const notesDir = path13.join(agentDataDir, "notes");
|
|
5622
6042
|
await mkdir(notesDir, { recursive: true });
|
|
5623
6043
|
if (getOnboardingSeedMode(config) === FIRST_CINDY_SEED_MODE) {
|
|
5624
6044
|
const seedFiles = buildOnboardingSeedFiles();
|
|
5625
6045
|
for (const { relativePath, content } of seedFiles) {
|
|
5626
|
-
const fullPath =
|
|
6046
|
+
const fullPath = path13.join(agentDataDir, relativePath);
|
|
5627
6047
|
try {
|
|
5628
6048
|
await access(fullPath);
|
|
5629
6049
|
} catch {
|
|
5630
|
-
await mkdir(
|
|
6050
|
+
await mkdir(path13.dirname(fullPath), { recursive: true });
|
|
5631
6051
|
await writeFile(fullPath, content);
|
|
5632
6052
|
}
|
|
5633
6053
|
}
|
|
@@ -6472,7 +6892,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6472
6892
|
return true;
|
|
6473
6893
|
}
|
|
6474
6894
|
async resetWorkspace(agentId) {
|
|
6475
|
-
const agentDataDir =
|
|
6895
|
+
const agentDataDir = path13.join(this.dataDir, agentId);
|
|
6476
6896
|
try {
|
|
6477
6897
|
await rm2(agentDataDir, { recursive: true, force: true });
|
|
6478
6898
|
logger.info(`[Agent ${agentId}] Workspace reset complete (${agentDataDir})`);
|
|
@@ -6509,7 +6929,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6509
6929
|
return result;
|
|
6510
6930
|
}
|
|
6511
6931
|
buildRuntimeProfileReport(agentId, config, sessionId, launchId) {
|
|
6512
|
-
const workspacePath =
|
|
6932
|
+
const workspacePath = path13.join(this.dataDir, agentId);
|
|
6513
6933
|
return {
|
|
6514
6934
|
agentId,
|
|
6515
6935
|
launchId,
|
|
@@ -6766,7 +7186,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6766
7186
|
}
|
|
6767
7187
|
// Workspace file browsing
|
|
6768
7188
|
async getFileTree(agentId, dirPath) {
|
|
6769
|
-
const agentDir =
|
|
7189
|
+
const agentDir = path13.join(this.dataDir, agentId);
|
|
6770
7190
|
try {
|
|
6771
7191
|
await stat2(agentDir);
|
|
6772
7192
|
} catch {
|
|
@@ -6774,8 +7194,8 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6774
7194
|
}
|
|
6775
7195
|
let targetDir = agentDir;
|
|
6776
7196
|
if (dirPath) {
|
|
6777
|
-
const resolved =
|
|
6778
|
-
if (!resolved.startsWith(agentDir +
|
|
7197
|
+
const resolved = path13.resolve(agentDir, dirPath);
|
|
7198
|
+
if (!resolved.startsWith(agentDir + path13.sep) && resolved !== agentDir) {
|
|
6779
7199
|
return [];
|
|
6780
7200
|
}
|
|
6781
7201
|
targetDir = resolved;
|
|
@@ -6783,14 +7203,14 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6783
7203
|
return this.listDirectoryChildren(targetDir, agentDir);
|
|
6784
7204
|
}
|
|
6785
7205
|
async readFile(agentId, filePath) {
|
|
6786
|
-
const agentDir =
|
|
6787
|
-
const resolved =
|
|
6788
|
-
if (!resolved.startsWith(agentDir +
|
|
7206
|
+
const agentDir = path13.join(this.dataDir, agentId);
|
|
7207
|
+
const resolved = path13.resolve(agentDir, filePath);
|
|
7208
|
+
if (!resolved.startsWith(agentDir + path13.sep) && resolved !== agentDir) {
|
|
6789
7209
|
throw new Error("Access denied");
|
|
6790
7210
|
}
|
|
6791
7211
|
const info = await stat2(resolved);
|
|
6792
7212
|
if (info.isDirectory()) throw new Error("Cannot read a directory");
|
|
6793
|
-
const ext =
|
|
7213
|
+
const ext = path13.extname(resolved).toLowerCase();
|
|
6794
7214
|
if (WORKSPACE_TEXT_EXTENSIONS.has(ext) || ext === "") {
|
|
6795
7215
|
if (info.size > WORKSPACE_TEXT_FILE_MAX_BYTES) throw new Error("File too large");
|
|
6796
7216
|
const content = await readFile(resolved, "utf-8");
|
|
@@ -6825,13 +7245,13 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6825
7245
|
const agent = this.agents.get(agentId);
|
|
6826
7246
|
const runtime = runtimeHint || agent?.config.runtime || "claude";
|
|
6827
7247
|
const home = os6.homedir();
|
|
6828
|
-
const workspaceDir =
|
|
7248
|
+
const workspaceDir = path13.join(this.dataDir, agentId);
|
|
6829
7249
|
const paths = _AgentProcessManager.SKILL_PATHS[runtime] || _AgentProcessManager.SKILL_PATHS.claude;
|
|
6830
7250
|
const globalResults = await Promise.all(
|
|
6831
|
-
paths.global.map((p) => this.scanSkillsDir(
|
|
7251
|
+
paths.global.map((p) => this.scanSkillsDir(path13.join(home, p)))
|
|
6832
7252
|
);
|
|
6833
7253
|
const workspaceResults = await Promise.all(
|
|
6834
|
-
paths.workspace.map((p) => this.scanSkillsDir(
|
|
7254
|
+
paths.workspace.map((p) => this.scanSkillsDir(path13.join(workspaceDir, p)))
|
|
6835
7255
|
);
|
|
6836
7256
|
const dedup = (skills) => {
|
|
6837
7257
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -6860,7 +7280,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6860
7280
|
const skills = [];
|
|
6861
7281
|
for (const entry of entries) {
|
|
6862
7282
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
6863
|
-
const skillMd =
|
|
7283
|
+
const skillMd = path13.join(dir, entry.name, "SKILL.md");
|
|
6864
7284
|
try {
|
|
6865
7285
|
const content = await readFile(skillMd, "utf-8");
|
|
6866
7286
|
const skill = this.parseSkillMd(entry.name, content);
|
|
@@ -6871,7 +7291,7 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6871
7291
|
} else if (entry.name.endsWith(".md")) {
|
|
6872
7292
|
const cmdName = entry.name.replace(/\.md$/, "");
|
|
6873
7293
|
try {
|
|
6874
|
-
const content = await readFile(
|
|
7294
|
+
const content = await readFile(path13.join(dir, entry.name), "utf-8");
|
|
6875
7295
|
const skill = this.parseSkillMd(cmdName, content);
|
|
6876
7296
|
skill.sourcePath = dir;
|
|
6877
7297
|
skills.push(skill);
|
|
@@ -7859,8 +8279,8 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
7859
8279
|
const nodes = [];
|
|
7860
8280
|
for (const entry of entries) {
|
|
7861
8281
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
7862
|
-
const fullPath =
|
|
7863
|
-
const relativePath =
|
|
8282
|
+
const fullPath = path13.join(dir, entry.name);
|
|
8283
|
+
const relativePath = path13.relative(rootDir, fullPath);
|
|
7864
8284
|
let info;
|
|
7865
8285
|
try {
|
|
7866
8286
|
info = await stat2(fullPath);
|
|
@@ -8163,9 +8583,9 @@ var ReminderCache = class {
|
|
|
8163
8583
|
|
|
8164
8584
|
// src/machineLock.ts
|
|
8165
8585
|
import { createHash as createHash3, randomUUID as randomUUID2 } from "crypto";
|
|
8166
|
-
import { mkdirSync as
|
|
8586
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync5, rmSync as rmSync3, statSync as statSync3, writeFileSync as writeFileSync9 } from "fs";
|
|
8167
8587
|
import os7 from "os";
|
|
8168
|
-
import
|
|
8588
|
+
import path14 from "path";
|
|
8169
8589
|
var INCOMPLETE_LOCK_STALE_MS = 3e4;
|
|
8170
8590
|
var DaemonMachineLockConflictError = class extends Error {
|
|
8171
8591
|
code = "DAEMON_MACHINE_LOCK_HELD";
|
|
@@ -8187,7 +8607,7 @@ function resolveDefaultMachineStateRoot() {
|
|
|
8187
8607
|
return resolveSlockHomePath("machines");
|
|
8188
8608
|
}
|
|
8189
8609
|
function ownerPath(lockDir) {
|
|
8190
|
-
return
|
|
8610
|
+
return path14.join(lockDir, "owner.json");
|
|
8191
8611
|
}
|
|
8192
8612
|
function readOwner(lockDir) {
|
|
8193
8613
|
try {
|
|
@@ -8217,13 +8637,13 @@ function acquireDaemonMachineLock(options) {
|
|
|
8217
8637
|
const rootDir = options.rootDir ?? resolveDefaultMachineStateRoot();
|
|
8218
8638
|
const fingerprint = apiKeyFingerprint(options.apiKey);
|
|
8219
8639
|
const lockId = getDaemonMachineLockId(options.apiKey);
|
|
8220
|
-
const machineDir =
|
|
8221
|
-
const lockDir =
|
|
8640
|
+
const machineDir = path14.join(rootDir, lockId);
|
|
8641
|
+
const lockDir = path14.join(machineDir, "daemon.lock");
|
|
8222
8642
|
const token = randomUUID2();
|
|
8223
|
-
|
|
8643
|
+
mkdirSync6(machineDir, { recursive: true });
|
|
8224
8644
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
8225
8645
|
try {
|
|
8226
|
-
|
|
8646
|
+
mkdirSync6(lockDir);
|
|
8227
8647
|
const owner = {
|
|
8228
8648
|
pid: process.pid,
|
|
8229
8649
|
token,
|
|
@@ -8233,7 +8653,7 @@ function acquireDaemonMachineLock(options) {
|
|
|
8233
8653
|
apiKeyFingerprint: fingerprint.slice(0, 16)
|
|
8234
8654
|
};
|
|
8235
8655
|
try {
|
|
8236
|
-
|
|
8656
|
+
writeFileSync9(ownerPath(lockDir), `${JSON.stringify(owner, null, 2)}
|
|
8237
8657
|
`, { mode: 384 });
|
|
8238
8658
|
} catch (err) {
|
|
8239
8659
|
rmSync3(lockDir, { recursive: true, force: true });
|
|
@@ -8270,8 +8690,8 @@ function acquireDaemonMachineLock(options) {
|
|
|
8270
8690
|
}
|
|
8271
8691
|
|
|
8272
8692
|
// src/localTraceSink.ts
|
|
8273
|
-
import { appendFileSync, mkdirSync as
|
|
8274
|
-
import
|
|
8693
|
+
import { appendFileSync, mkdirSync as mkdirSync7, readdirSync as readdirSync3, rmSync as rmSync4, statSync as statSync4, writeFileSync as writeFileSync10 } from "fs";
|
|
8694
|
+
import path15 from "path";
|
|
8275
8695
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
8276
8696
|
var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
|
|
8277
8697
|
var DEFAULT_MAX_FILES = 8;
|
|
@@ -8307,7 +8727,7 @@ var LocalRotatingTraceSink = class {
|
|
|
8307
8727
|
currentSize = 0;
|
|
8308
8728
|
sequence = 0;
|
|
8309
8729
|
constructor(options) {
|
|
8310
|
-
this.traceDir =
|
|
8730
|
+
this.traceDir = path15.join(options.machineDir, "traces");
|
|
8311
8731
|
this.maxFileBytes = Math.max(1024, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES));
|
|
8312
8732
|
const baseAgeMs = Math.max(1e3, Math.floor(options.maxFileAgeMs ?? DEFAULT_MAX_FILE_AGE_MS));
|
|
8313
8733
|
const ageJitterMs = Math.max(0, Math.floor(options.maxFileAgeJitterMs ?? 0));
|
|
@@ -8333,15 +8753,15 @@ var LocalRotatingTraceSink = class {
|
|
|
8333
8753
|
return this.currentFile;
|
|
8334
8754
|
}
|
|
8335
8755
|
ensureFile(nextBytes) {
|
|
8336
|
-
|
|
8756
|
+
mkdirSync7(this.traceDir, { recursive: true, mode: 448 });
|
|
8337
8757
|
const nowMs = this.nowMsProvider();
|
|
8338
8758
|
const shouldRotateForAge = this.currentFileOpenedAtMs !== null && nowMs - this.currentFileOpenedAtMs >= this.maxFileAgeMs;
|
|
8339
8759
|
if (!this.currentFile || this.currentSize + nextBytes > this.maxFileBytes || shouldRotateForAge) {
|
|
8340
|
-
this.currentFile =
|
|
8760
|
+
this.currentFile = path15.join(
|
|
8341
8761
|
this.traceDir,
|
|
8342
8762
|
`daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
|
|
8343
8763
|
);
|
|
8344
|
-
|
|
8764
|
+
writeFileSync10(this.currentFile, "", { flag: "a", mode: 384 });
|
|
8345
8765
|
this.currentSize = statSync4(this.currentFile).size;
|
|
8346
8766
|
this.currentFileOpenedAtMs = nowMs;
|
|
8347
8767
|
this.pruneOldFiles();
|
|
@@ -8352,7 +8772,7 @@ var LocalRotatingTraceSink = class {
|
|
|
8352
8772
|
const excess = files.length - this.maxFiles;
|
|
8353
8773
|
if (excess <= 0) return;
|
|
8354
8774
|
for (const file of files.slice(0, excess)) {
|
|
8355
|
-
rmSync4(
|
|
8775
|
+
rmSync4(path15.join(this.traceDir, file), { force: true });
|
|
8356
8776
|
}
|
|
8357
8777
|
}
|
|
8358
8778
|
};
|
|
@@ -8439,11 +8859,11 @@ function isDiagnosticErrorAttr(key) {
|
|
|
8439
8859
|
import { createHash as createHash5, randomUUID as randomUUID3 } from "crypto";
|
|
8440
8860
|
import { gzipSync } from "zlib";
|
|
8441
8861
|
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
8442
|
-
import
|
|
8862
|
+
import path16 from "path";
|
|
8443
8863
|
|
|
8444
8864
|
// src/directUploadCapability.ts
|
|
8445
|
-
function joinUrl(base,
|
|
8446
|
-
return `${base.replace(/\/+$/, "")}${
|
|
8865
|
+
function joinUrl(base, path18) {
|
|
8866
|
+
return `${base.replace(/\/+$/, "")}${path18}`;
|
|
8447
8867
|
}
|
|
8448
8868
|
function jsonHeaders(apiKey) {
|
|
8449
8869
|
return {
|
|
@@ -8662,7 +9082,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
8662
9082
|
}, nextMs);
|
|
8663
9083
|
}
|
|
8664
9084
|
async findUploadCandidates() {
|
|
8665
|
-
const traceDir =
|
|
9085
|
+
const traceDir = path16.join(this.options.machineDir, "traces");
|
|
8666
9086
|
let names;
|
|
8667
9087
|
try {
|
|
8668
9088
|
names = await readdir3(traceDir);
|
|
@@ -8674,8 +9094,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
8674
9094
|
const currentFile = this.options.currentFileProvider?.();
|
|
8675
9095
|
const candidates = [];
|
|
8676
9096
|
for (const name of names.filter((entry) => entry.startsWith("daemon-trace-") && entry.endsWith(".jsonl")).sort()) {
|
|
8677
|
-
const file =
|
|
8678
|
-
if (currentFile &&
|
|
9097
|
+
const file = path16.join(traceDir, name);
|
|
9098
|
+
if (currentFile && path16.resolve(file) === path16.resolve(currentFile)) continue;
|
|
8679
9099
|
if (await this.isUploaded(file)) continue;
|
|
8680
9100
|
try {
|
|
8681
9101
|
const info = await stat3(file);
|
|
@@ -8749,8 +9169,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
8749
9169
|
}
|
|
8750
9170
|
}
|
|
8751
9171
|
uploadStatePath(file) {
|
|
8752
|
-
const stateDir =
|
|
8753
|
-
return
|
|
9172
|
+
const stateDir = path16.join(this.options.machineDir, "trace-uploads");
|
|
9173
|
+
return path16.join(stateDir, `${path16.basename(file)}.uploaded.json`);
|
|
8754
9174
|
}
|
|
8755
9175
|
async isUploaded(file) {
|
|
8756
9176
|
try {
|
|
@@ -8762,9 +9182,9 @@ var DaemonTraceBundleUploader = class {
|
|
|
8762
9182
|
}
|
|
8763
9183
|
async markUploaded(file, metadata) {
|
|
8764
9184
|
const stateFile = this.uploadStatePath(file);
|
|
8765
|
-
await mkdir2(
|
|
9185
|
+
await mkdir2(path16.dirname(stateFile), { recursive: true, mode: 448 });
|
|
8766
9186
|
await writeFile2(stateFile, `${JSON.stringify({
|
|
8767
|
-
file:
|
|
9187
|
+
file: path16.basename(file),
|
|
8768
9188
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8769
9189
|
...metadata
|
|
8770
9190
|
}, null, 2)}
|
|
@@ -8786,7 +9206,7 @@ var DEFAULT_TRACE_UPLOAD_URL = "https://slock-trace-upload.botiverse.dev";
|
|
|
8786
9206
|
var RUNNER_CREDENTIAL_SCOPES = ["send", "read", "mentions", "tasks", "reactions", "server", "channels"];
|
|
8787
9207
|
var RUNNER_CREDENTIAL_MINT_MAX_ATTEMPTS2 = 3;
|
|
8788
9208
|
var RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2 = 250;
|
|
8789
|
-
var DAEMON_CLI_USAGE =
|
|
9209
|
+
var DAEMON_CLI_USAGE = `Usage: slock-daemon --server-url <url> (--api-key <key> or ${DAEMON_API_KEY_ENV}=<key>)`;
|
|
8790
9210
|
var RunnerCredentialMintError2 = class extends Error {
|
|
8791
9211
|
code;
|
|
8792
9212
|
retryable;
|
|
@@ -8822,9 +9242,9 @@ function runnerCredentialErrorDetail2(error) {
|
|
|
8822
9242
|
async function waitForRunnerCredentialRetry2() {
|
|
8823
9243
|
await new Promise((resolve) => setTimeout(resolve, RUNNER_CREDENTIAL_MINT_RETRY_DELAY_MS2));
|
|
8824
9244
|
}
|
|
8825
|
-
function parseDaemonCliArgs(args) {
|
|
9245
|
+
function parseDaemonCliArgs(args, env = {}) {
|
|
8826
9246
|
let serverUrl = "";
|
|
8827
|
-
let apiKey = "";
|
|
9247
|
+
let apiKey = env[DAEMON_API_KEY_ENV] ?? "";
|
|
8828
9248
|
for (let i = 0; i < args.length; i++) {
|
|
8829
9249
|
if (args[i] === "--server-url" && args[i + 1]) serverUrl = args[++i];
|
|
8830
9250
|
if (args[i] === "--api-key" && args[i + 1]) apiKey = args[++i];
|
|
@@ -8841,23 +9261,23 @@ function readDaemonVersion(moduleUrl = import.meta.url) {
|
|
|
8841
9261
|
}
|
|
8842
9262
|
}
|
|
8843
9263
|
function resolveChatBridgePath(moduleUrl = import.meta.url) {
|
|
8844
|
-
const dirname =
|
|
8845
|
-
const jsPath =
|
|
9264
|
+
const dirname = path17.dirname(fileURLToPath2(moduleUrl));
|
|
9265
|
+
const jsPath = path17.resolve(dirname, "chat-bridge.js");
|
|
8846
9266
|
try {
|
|
8847
9267
|
accessSync(jsPath);
|
|
8848
9268
|
return jsPath;
|
|
8849
9269
|
} catch {
|
|
8850
|
-
return
|
|
9270
|
+
return path17.resolve(dirname, "chat-bridge.ts");
|
|
8851
9271
|
}
|
|
8852
9272
|
}
|
|
8853
9273
|
function resolveSlockCliPath(moduleUrl = import.meta.url) {
|
|
8854
|
-
const thisDir =
|
|
8855
|
-
const bundledDistPath =
|
|
9274
|
+
const thisDir = path17.dirname(fileURLToPath2(moduleUrl));
|
|
9275
|
+
const bundledDistPath = path17.resolve(thisDir, "cli", "index.js");
|
|
8856
9276
|
try {
|
|
8857
9277
|
accessSync(bundledDistPath);
|
|
8858
9278
|
return bundledDistPath;
|
|
8859
9279
|
} catch {
|
|
8860
|
-
const workspaceDistPath =
|
|
9280
|
+
const workspaceDistPath = path17.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
|
|
8861
9281
|
accessSync(workspaceDistPath);
|
|
8862
9282
|
return workspaceDistPath;
|
|
8863
9283
|
}
|
|
@@ -9036,7 +9456,7 @@ var DaemonCore = class {
|
|
|
9036
9456
|
}
|
|
9037
9457
|
resolveMachineStateRoot() {
|
|
9038
9458
|
if (this.options.machineStateDir) return this.options.machineStateDir;
|
|
9039
|
-
if (this.options.dataDir) return
|
|
9459
|
+
if (this.options.dataDir) return path17.join(path17.dirname(this.options.dataDir), "machines");
|
|
9040
9460
|
return resolveDefaultMachineStateRoot();
|
|
9041
9461
|
}
|
|
9042
9462
|
shouldEnableLocalTrace() {
|
|
@@ -9538,6 +9958,8 @@ var DaemonCore = class {
|
|
|
9538
9958
|
};
|
|
9539
9959
|
|
|
9540
9960
|
export {
|
|
9961
|
+
DAEMON_API_KEY_ENV,
|
|
9962
|
+
scrubDaemonAuthEnv,
|
|
9541
9963
|
resolveWorkspaceDirectoryPath,
|
|
9542
9964
|
scanWorkspaceDirectories,
|
|
9543
9965
|
deleteWorkspaceDirectory,
|