@botiverse/raft-daemon 0.62.0 → 0.63.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/core.ts
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import path18 from "path";
|
|
3
|
+
import os9 from "os";
|
|
4
4
|
import { createRequire as createRequire3 } from "module";
|
|
5
5
|
import { accessSync } from "fs";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
@@ -1602,9 +1602,9 @@ var FREE_MONTHLY_FILE_UPLOAD_LIMIT_BYTES = 100 * 1024 * 1024;
|
|
|
1602
1602
|
import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync6, readdirSync as readdirSync3, statSync, writeFileSync as writeFileSync4 } from "fs";
|
|
1603
1603
|
import { mkdir, writeFile, access, readdir as readdir2, stat as stat2, readFile, rm as rm2, lstat, realpath, open } from "fs/promises";
|
|
1604
1604
|
import { createHash as createHash3, randomUUID as randomUUID5 } from "crypto";
|
|
1605
|
-
import
|
|
1605
|
+
import path14 from "path";
|
|
1606
1606
|
import { gzipSync } from "zlib";
|
|
1607
|
-
import
|
|
1607
|
+
import os7 from "os";
|
|
1608
1608
|
|
|
1609
1609
|
// src/proxy.ts
|
|
1610
1610
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
@@ -1873,8 +1873,8 @@ async function executeResponseRequest(url, init, {
|
|
|
1873
1873
|
}
|
|
1874
1874
|
|
|
1875
1875
|
// src/directUploadCapability.ts
|
|
1876
|
-
function joinUrl(base,
|
|
1877
|
-
return `${base.replace(/\/+$/, "")}${
|
|
1876
|
+
function joinUrl(base, path19) {
|
|
1877
|
+
return `${base.replace(/\/+$/, "")}${path19}`;
|
|
1878
1878
|
}
|
|
1879
1879
|
function jsonHeaders(apiKey) {
|
|
1880
1880
|
return {
|
|
@@ -3024,7 +3024,7 @@ function projectApmRuntimeStallDiagnostic(input) {
|
|
|
3024
3024
|
gatedPhase: input.runtimeDescriptorBusyDelivery === "gated" ? input.gatedPhase : void 0,
|
|
3025
3025
|
outstandingToolUses: input.outstandingToolUses,
|
|
3026
3026
|
compacting: input.compacting,
|
|
3027
|
-
|
|
3027
|
+
...input.reviewing === true ? { reviewing: true } : {},
|
|
3028
3028
|
recentStderrCount: input.recentStderrCount,
|
|
3029
3029
|
recentStdoutCount: input.recentStdoutCount,
|
|
3030
3030
|
...input.runtimeTraceCounterAttrs ?? {}
|
|
@@ -4150,6 +4150,17 @@ var safePathPart = (value) => value.replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
|
4150
4150
|
var RAW_CREDENTIAL_ENV_DENYLIST = [
|
|
4151
4151
|
"SLOCK_AGENT_CREDENTIAL_KEY"
|
|
4152
4152
|
];
|
|
4153
|
+
var WORKSPACE_CLI_TRANSPORT_FILENAMES = [
|
|
4154
|
+
"agent-token",
|
|
4155
|
+
"slock",
|
|
4156
|
+
"slock.cmd",
|
|
4157
|
+
"slock.ps1",
|
|
4158
|
+
"raft",
|
|
4159
|
+
"raft.cmd",
|
|
4160
|
+
"raft.ps1",
|
|
4161
|
+
"opencli",
|
|
4162
|
+
"opencli.cmd"
|
|
4163
|
+
];
|
|
4153
4164
|
function deriveCliFallbackCandidates(cliPath) {
|
|
4154
4165
|
if (!cliPath || cliPath === "__cli") return [];
|
|
4155
4166
|
const normalized = cliPath.split(path2.sep).join("/");
|
|
@@ -4210,6 +4221,18 @@ function resolveOpencliBinPath() {
|
|
|
4210
4221
|
return null;
|
|
4211
4222
|
}
|
|
4212
4223
|
}
|
|
4224
|
+
function buildCliTransportDir(slockHome, agentId, launchId) {
|
|
4225
|
+
return path2.join(slockHome, "cli-transport", safePathPart(agentId), buildCliTransportLaunchPart(launchId));
|
|
4226
|
+
}
|
|
4227
|
+
function buildCliTransportLaunchPart(launchId) {
|
|
4228
|
+
return safePathPart(launchId || `pid-${process.pid}`);
|
|
4229
|
+
}
|
|
4230
|
+
function cleanupWorkspaceCliTransportFiles(workingDirectory) {
|
|
4231
|
+
const legacySlockDir = path2.join(workingDirectory, ".slock");
|
|
4232
|
+
for (const filename of WORKSPACE_CLI_TRANSPORT_FILENAMES) {
|
|
4233
|
+
rmSync(path2.join(legacySlockDir, filename), { force: true });
|
|
4234
|
+
}
|
|
4235
|
+
}
|
|
4213
4236
|
function writeOpencliWrapper(slockDir, opencliBinPath, platform = process.platform) {
|
|
4214
4237
|
const fallbacks = deriveOpencliFallbackCandidates(opencliBinPath);
|
|
4215
4238
|
let binPath = opencliBinPath;
|
|
@@ -4340,9 +4363,10 @@ async function prepareCliTransport(ctx, extraEnv = {}, platform = process.platfo
|
|
|
4340
4363
|
);
|
|
4341
4364
|
}
|
|
4342
4365
|
}
|
|
4343
|
-
const
|
|
4366
|
+
const slockHome = ctx.slockHome ? path2.resolve(ctx.slockHome) : resolveSlockHome();
|
|
4367
|
+
cleanupWorkspaceCliTransportFiles(ctx.workingDirectory);
|
|
4368
|
+
const slockDir = buildCliTransportDir(slockHome, ctx.agentId, ctx.launchId);
|
|
4344
4369
|
mkdirSync(slockDir, { recursive: true });
|
|
4345
|
-
const slockHome = resolveSlockHome();
|
|
4346
4370
|
const tokenFile = path2.join(slockDir, "agent-token");
|
|
4347
4371
|
const agentCredentialKey = ctx.config.agentCredentialKey;
|
|
4348
4372
|
let agentCredentialProxy = null;
|
|
@@ -4357,7 +4381,7 @@ async function prepareCliTransport(ctx, extraEnv = {}, platform = process.platfo
|
|
|
4357
4381
|
activeCapabilities: DEFAULT_ACTIVE_CAPABILITIES,
|
|
4358
4382
|
inboxCoordinator: ctx.agentCredentialProxyInboxCoordinator
|
|
4359
4383
|
});
|
|
4360
|
-
const launchPart =
|
|
4384
|
+
const launchPart = buildCliTransportLaunchPart(ctx.launchId);
|
|
4361
4385
|
const proxyTokenDir = path2.join(slockHome, "agent-proxy-tokens", safePathPart(ctx.agentId));
|
|
4362
4386
|
mkdirSync(proxyTokenDir, { recursive: true, mode: 448 });
|
|
4363
4387
|
agentCredentialProxyTokenFile = path2.join(proxyTokenDir, `${launchPart}.token`);
|
|
@@ -4474,7 +4498,6 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
|
|
|
4474
4498
|
...ctx.launchId ? { SLOCK_AGENT_LAUNCH_ID: ctx.launchId } : {},
|
|
4475
4499
|
...ctx.cliTransportTraceDir ? { [CLI_TRANSPORT_TRACE_DIR_ENV]: ctx.cliTransportTraceDir } : {},
|
|
4476
4500
|
SLOCK_SERVER_URL: ctx.config.serverUrl,
|
|
4477
|
-
...agentCredentialProxy ? {} : { SLOCK_AGENT_TOKEN_FILE: tokenFile },
|
|
4478
4501
|
PATH: `${slockDir}${path2.delimiter}${process.env.PATH ?? ""}`
|
|
4479
4502
|
};
|
|
4480
4503
|
delete spawnEnv.SLOCK_AGENT_TOKEN;
|
|
@@ -4485,9 +4508,7 @@ set "SLOCK_AGENT_ACTIVE_CAPABILITIES=${DEFAULT_ACTIVE_CAPABILITIES}"\r
|
|
|
4485
4508
|
delete spawnEnv.SLOCK_AGENT_PROXY_TOKEN;
|
|
4486
4509
|
delete spawnEnv.SLOCK_AGENT_PROXY_TOKEN_FILE;
|
|
4487
4510
|
delete spawnEnv.SLOCK_AGENT_ACTIVE_CAPABILITIES;
|
|
4488
|
-
|
|
4489
|
-
delete spawnEnv.SLOCK_AGENT_TOKEN_FILE;
|
|
4490
|
-
}
|
|
4511
|
+
delete spawnEnv.SLOCK_AGENT_TOKEN_FILE;
|
|
4491
4512
|
return {
|
|
4492
4513
|
slockDir,
|
|
4493
4514
|
tokenFile,
|
|
@@ -5177,8 +5198,47 @@ var ClaudeDriver = class {
|
|
|
5177
5198
|
// src/drivers/codex.ts
|
|
5178
5199
|
import { spawn as spawn2, execFileSync as execFileSync2 } from "child_process";
|
|
5179
5200
|
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "fs";
|
|
5201
|
+
import os4 from "os";
|
|
5202
|
+
import path7 from "path";
|
|
5203
|
+
|
|
5204
|
+
// src/drivers/codexHome.ts
|
|
5180
5205
|
import os3 from "os";
|
|
5181
5206
|
import path6 from "path";
|
|
5207
|
+
function readConfiguredCodexHome(env) {
|
|
5208
|
+
const raw = env.CODEX_HOME;
|
|
5209
|
+
return typeof raw === "string" && raw.trim().length > 0 ? raw : null;
|
|
5210
|
+
}
|
|
5211
|
+
function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
|
|
5212
|
+
const raw = readConfiguredCodexHome(env);
|
|
5213
|
+
if (raw) {
|
|
5214
|
+
return path6.resolve(opts.cwd ?? process.cwd(), raw);
|
|
5215
|
+
}
|
|
5216
|
+
return path6.join(opts.defaultHomeDir ?? os3.homedir(), ".codex");
|
|
5217
|
+
}
|
|
5218
|
+
function hasConfiguredCodexHome(config, baseEnv = process.env) {
|
|
5219
|
+
const launchRuntimeFields = config ? runtimeConfigToLaunchFields(config) : null;
|
|
5220
|
+
return Boolean(readConfiguredCodexHome({
|
|
5221
|
+
...baseEnv,
|
|
5222
|
+
...launchRuntimeFields?.envVars || {}
|
|
5223
|
+
}));
|
|
5224
|
+
}
|
|
5225
|
+
function resolveCodexHomeRootFromConfig(config, defaultHomeDir, cwd, baseEnv = process.env, _opts = {}) {
|
|
5226
|
+
const launchRuntimeFields = runtimeConfigToLaunchFields(config);
|
|
5227
|
+
const env = {
|
|
5228
|
+
...baseEnv,
|
|
5229
|
+
...launchRuntimeFields.envVars || {}
|
|
5230
|
+
};
|
|
5231
|
+
return resolveCodexHomeRootFromEnv(env, { defaultHomeDir, cwd });
|
|
5232
|
+
}
|
|
5233
|
+
function codexStateRootCandidates(homeDirOrCodexRoot) {
|
|
5234
|
+
return [
|
|
5235
|
+
homeDirOrCodexRoot,
|
|
5236
|
+
path6.join(homeDirOrCodexRoot, ".codex")
|
|
5237
|
+
];
|
|
5238
|
+
}
|
|
5239
|
+
function codexSessionRootCandidates(homeDirOrCodexRoot) {
|
|
5240
|
+
return codexStateRootCandidates(homeDirOrCodexRoot).map((root) => path6.join(root, "sessions"));
|
|
5241
|
+
}
|
|
5182
5242
|
|
|
5183
5243
|
// src/runtimeTurnState.ts
|
|
5184
5244
|
var RuntimeTurnState = class {
|
|
@@ -5359,7 +5419,7 @@ function codexNotificationDiagnosticEvent(message) {
|
|
|
5359
5419
|
return null;
|
|
5360
5420
|
}
|
|
5361
5421
|
const sessionId = codexMessageThreadId(message);
|
|
5362
|
-
const
|
|
5422
|
+
const path19 = boundedString(params.path);
|
|
5363
5423
|
return {
|
|
5364
5424
|
kind: "runtime_diagnostic",
|
|
5365
5425
|
severity: "warning",
|
|
@@ -5367,12 +5427,42 @@ function codexNotificationDiagnosticEvent(message) {
|
|
|
5367
5427
|
itemType: message.method,
|
|
5368
5428
|
message: diagnosticMessage,
|
|
5369
5429
|
...details ? { details } : {},
|
|
5370
|
-
...
|
|
5430
|
+
...path19 ? { path: path19 } : {},
|
|
5371
5431
|
...params.range !== void 0 ? { range: params.range } : {},
|
|
5372
5432
|
payloadBytes: payloadBytes(params),
|
|
5373
5433
|
...sessionId ? { sessionId } : {}
|
|
5374
5434
|
};
|
|
5375
5435
|
}
|
|
5436
|
+
function codexThreadStatusChangedEvent(message) {
|
|
5437
|
+
if (message.method !== "thread/status/changed") return null;
|
|
5438
|
+
const params = message.params ?? {};
|
|
5439
|
+
const status = params.status ?? params.thread?.status;
|
|
5440
|
+
if (!status || typeof status !== "object") return null;
|
|
5441
|
+
const statusType = nonEmptyString2(status.type);
|
|
5442
|
+
const sessionId = codexMessageThreadId(message);
|
|
5443
|
+
if (statusType === "systemError") {
|
|
5444
|
+
const statusMessage = boundedString(status.message) ?? boundedString(status.error?.message) ?? getCodexNotificationErrorMessage(params) ?? "Codex thread entered system error state";
|
|
5445
|
+
return {
|
|
5446
|
+
kind: "error",
|
|
5447
|
+
message: statusMessage
|
|
5448
|
+
};
|
|
5449
|
+
}
|
|
5450
|
+
if (statusType !== "active" || !Array.isArray(status.activeFlags)) return null;
|
|
5451
|
+
const activeFlags = status.activeFlags.filter((flag) => typeof flag === "string");
|
|
5452
|
+
const waitFlags = activeFlags.filter((flag) => flag === "waitingOnApproval" || flag === "waitingOnUserInput");
|
|
5453
|
+
if (waitFlags.length === 0) return null;
|
|
5454
|
+
const waitLabel = waitFlags.includes("waitingOnApproval") && waitFlags.includes("waitingOnUserInput") ? "approval and user input" : waitFlags.includes("waitingOnApproval") ? "approval" : "user input";
|
|
5455
|
+
return {
|
|
5456
|
+
kind: "runtime_diagnostic",
|
|
5457
|
+
severity: "warning",
|
|
5458
|
+
source: "codex_app_server_notification",
|
|
5459
|
+
itemType: "thread/status/changed",
|
|
5460
|
+
message: `Codex thread is waiting on ${waitLabel}`,
|
|
5461
|
+
details: `Active flags: ${waitFlags.join(", ")}`,
|
|
5462
|
+
payloadBytes: payloadBytes(params),
|
|
5463
|
+
...sessionId ? { sessionId } : {}
|
|
5464
|
+
};
|
|
5465
|
+
}
|
|
5376
5466
|
function joinReasoningSummaryText(item) {
|
|
5377
5467
|
const summary = Array.isArray(item.summary) ? item.summary.filter((entry) => typeof entry === "string") : [];
|
|
5378
5468
|
return summary.join("\n").trim();
|
|
@@ -5400,10 +5490,27 @@ function codexMcpToolName(item) {
|
|
|
5400
5490
|
function codexMessageThreadId(message) {
|
|
5401
5491
|
return nonEmptyString2(message.params?.threadId) ?? nonEmptyString2(message.params?.thread?.id) ?? nonEmptyString2(message.params?.sessionId);
|
|
5402
5492
|
}
|
|
5493
|
+
function codexAgentMessagePhase(value) {
|
|
5494
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
5495
|
+
}
|
|
5496
|
+
function codexAgentMessageDeltaPhase(message) {
|
|
5497
|
+
return codexAgentMessagePhase(message.params?.phase) ?? codexAgentMessagePhase(message.params?.item?.phase);
|
|
5498
|
+
}
|
|
5499
|
+
function isUserVisibleAgentMessagePhase(phase) {
|
|
5500
|
+
return phase === null || phase === "final_answer";
|
|
5501
|
+
}
|
|
5502
|
+
function codexSuppressedAgentMessageEvent(itemType, phase, text, itemId) {
|
|
5503
|
+
return codexNotificationProgressEvent(itemType, {
|
|
5504
|
+
...typeof itemId === "string" ? { itemId } : {},
|
|
5505
|
+
...phase ? { phase } : {},
|
|
5506
|
+
bytes: Buffer.byteLength(text, "utf8")
|
|
5507
|
+
});
|
|
5508
|
+
}
|
|
5403
5509
|
var CodexEventNormalizer = class {
|
|
5404
5510
|
currentThreadId = null;
|
|
5405
5511
|
sessionAnnounced = false;
|
|
5406
5512
|
streamedAgentMessageIds = /* @__PURE__ */ new Set();
|
|
5513
|
+
agentMessagePhases = /* @__PURE__ */ new Map();
|
|
5407
5514
|
streamedReasoningIds = /* @__PURE__ */ new Set();
|
|
5408
5515
|
fileChangeToolCallCounts = /* @__PURE__ */ new Map();
|
|
5409
5516
|
turnState = new RuntimeTurnState();
|
|
@@ -5412,6 +5519,7 @@ var CodexEventNormalizer = class {
|
|
|
5412
5519
|
this.turnState.reset();
|
|
5413
5520
|
this.sessionAnnounced = false;
|
|
5414
5521
|
this.streamedAgentMessageIds.clear();
|
|
5522
|
+
this.agentMessagePhases.clear();
|
|
5415
5523
|
this.streamedReasoningIds.clear();
|
|
5416
5524
|
this.fileChangeToolCallCounts.clear();
|
|
5417
5525
|
}
|
|
@@ -5489,12 +5597,17 @@ var CodexEventNormalizer = class {
|
|
|
5489
5597
|
case "item/agentMessage/delta": {
|
|
5490
5598
|
const delta = message.params?.delta;
|
|
5491
5599
|
const itemId = message.params?.itemId;
|
|
5600
|
+
const phase = codexAgentMessageDeltaPhase(message) ?? (typeof itemId === "string" ? this.agentMessagePhases.get(itemId) ?? null : null);
|
|
5492
5601
|
if (typeof itemId === "string") {
|
|
5493
5602
|
this.streamedAgentMessageIds.add(itemId);
|
|
5494
5603
|
}
|
|
5495
5604
|
if (typeof delta === "string" && delta.length > 0) {
|
|
5496
5605
|
this.turnState.markProgress();
|
|
5497
|
-
|
|
5606
|
+
if (isUserVisibleAgentMessagePhase(phase)) {
|
|
5607
|
+
events.push({ kind: "text", text: delta });
|
|
5608
|
+
} else {
|
|
5609
|
+
events.push(codexSuppressedAgentMessageEvent("agent_message_non_final_delta", phase, delta, itemId));
|
|
5610
|
+
}
|
|
5498
5611
|
}
|
|
5499
5612
|
break;
|
|
5500
5613
|
}
|
|
@@ -5545,6 +5658,13 @@ var CodexEventNormalizer = class {
|
|
|
5545
5658
|
}
|
|
5546
5659
|
break;
|
|
5547
5660
|
}
|
|
5661
|
+
case "thread/status/changed": {
|
|
5662
|
+
const event = codexThreadStatusChangedEvent(message);
|
|
5663
|
+
if (event) {
|
|
5664
|
+
events.push(event);
|
|
5665
|
+
}
|
|
5666
|
+
break;
|
|
5667
|
+
}
|
|
5548
5668
|
case "item/started":
|
|
5549
5669
|
case "item/completed": {
|
|
5550
5670
|
const item = message.params?.item;
|
|
@@ -5566,12 +5686,21 @@ var CodexEventNormalizer = class {
|
|
|
5566
5686
|
}
|
|
5567
5687
|
break;
|
|
5568
5688
|
case "agentMessage":
|
|
5689
|
+
if ((isStarted || isCompleted) && typeof item.id === "string") {
|
|
5690
|
+
this.agentMessagePhases.set(item.id, codexAgentMessagePhase(item.phase));
|
|
5691
|
+
}
|
|
5569
5692
|
if (isCompleted && typeof item.id === "string" && !this.streamedAgentMessageIds.has(item.id) && typeof item.text === "string" && item.text.length > 0) {
|
|
5693
|
+
const phase = codexAgentMessagePhase(item.phase);
|
|
5570
5694
|
this.turnState.markProgress();
|
|
5571
|
-
|
|
5695
|
+
if (isUserVisibleAgentMessagePhase(phase)) {
|
|
5696
|
+
events.push({ kind: "text", text: item.text });
|
|
5697
|
+
} else {
|
|
5698
|
+
events.push(codexSuppressedAgentMessageEvent("agent_message_non_final_completed", phase, item.text, item.id));
|
|
5699
|
+
}
|
|
5572
5700
|
}
|
|
5573
5701
|
if (isCompleted && typeof item.id === "string") {
|
|
5574
5702
|
this.streamedAgentMessageIds.delete(item.id);
|
|
5703
|
+
this.agentMessagePhases.delete(item.id);
|
|
5575
5704
|
}
|
|
5576
5705
|
break;
|
|
5577
5706
|
case "commandExecution":
|
|
@@ -5710,14 +5839,15 @@ var CodexEventNormalizer = class {
|
|
|
5710
5839
|
|
|
5711
5840
|
// src/drivers/codex.ts
|
|
5712
5841
|
var CODEX_DESKTOP_BUNDLE_PATH = "/Applications/Codex.app/Contents/Resources/codex";
|
|
5842
|
+
var CODEX_APP_SERVER_PROBE_ARGS = ["app-server", "--help"];
|
|
5713
5843
|
function isWindowsSandboxRunner(commandPath) {
|
|
5714
|
-
return
|
|
5844
|
+
return path7.basename(commandPath).toLowerCase().startsWith("codex-command-runner");
|
|
5715
5845
|
}
|
|
5716
5846
|
function resolveWindowsNpmCodexEntry(deps = {}) {
|
|
5717
5847
|
const existsSyncFn = deps.existsSyncFn ?? existsSync5;
|
|
5718
5848
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
|
|
5719
5849
|
const env = deps.env ?? process.env;
|
|
5720
|
-
const winPath =
|
|
5850
|
+
const winPath = path7.win32;
|
|
5721
5851
|
try {
|
|
5722
5852
|
const globalRoot = String(execFileSyncFn("npm", ["root", "-g"], {
|
|
5723
5853
|
encoding: "utf8",
|
|
@@ -5739,7 +5869,7 @@ function resolveWindowsCodexDesktopEntry(deps = {}) {
|
|
|
5739
5869
|
const existsSyncFn = deps.existsSyncFn ?? existsSync5;
|
|
5740
5870
|
const env = deps.env ?? process.env;
|
|
5741
5871
|
const homeDir = deps.homeDir;
|
|
5742
|
-
const winPath =
|
|
5872
|
+
const winPath = path7.win32;
|
|
5743
5873
|
const candidates = [
|
|
5744
5874
|
env.LOCALAPPDATA ? winPath.join(env.LOCALAPPDATA, "OpenAI", "Codex", "bin", "codex.exe") : null,
|
|
5745
5875
|
env.USERPROFILE ? winPath.join(env.USERPROFILE, "AppData", "Local", "OpenAI", "Codex", "bin", "codex.exe") : null,
|
|
@@ -5750,69 +5880,158 @@ function resolveWindowsCodexDesktopEntry(deps = {}) {
|
|
|
5750
5880
|
}
|
|
5751
5881
|
return null;
|
|
5752
5882
|
}
|
|
5753
|
-
function
|
|
5883
|
+
function codexSpawnCandidates(deps = {}) {
|
|
5754
5884
|
const platform = deps.platform ?? process.platform;
|
|
5755
5885
|
if (platform === "win32") {
|
|
5886
|
+
const candidates2 = [];
|
|
5756
5887
|
const npmEntry = resolveWindowsNpmCodexEntry(deps);
|
|
5757
|
-
if (npmEntry)
|
|
5888
|
+
if (npmEntry) {
|
|
5889
|
+
candidates2.push({
|
|
5890
|
+
source: "npm_global",
|
|
5891
|
+
command: process.execPath,
|
|
5892
|
+
argsPrefix: [npmEntry],
|
|
5893
|
+
shell: false
|
|
5894
|
+
});
|
|
5895
|
+
}
|
|
5758
5896
|
const command = resolveCommandOnPath("codex", deps);
|
|
5759
|
-
if (command && !isWindowsSandboxRunner(command))
|
|
5760
|
-
|
|
5897
|
+
if (command && !isWindowsSandboxRunner(command)) {
|
|
5898
|
+
candidates2.push({
|
|
5899
|
+
source: "path",
|
|
5900
|
+
command,
|
|
5901
|
+
argsPrefix: [],
|
|
5902
|
+
shell: requiresWindowsShell(command, platform)
|
|
5903
|
+
});
|
|
5904
|
+
}
|
|
5905
|
+
const desktopEntry = resolveWindowsCodexDesktopEntry(deps);
|
|
5906
|
+
if (desktopEntry && !candidates2.some((candidate) => candidate.command === desktopEntry)) {
|
|
5907
|
+
candidates2.push({
|
|
5908
|
+
source: "desktop_install",
|
|
5909
|
+
command: desktopEntry,
|
|
5910
|
+
argsPrefix: [],
|
|
5911
|
+
shell: false
|
|
5912
|
+
});
|
|
5913
|
+
}
|
|
5914
|
+
return candidates2;
|
|
5761
5915
|
}
|
|
5916
|
+
const candidates = [];
|
|
5762
5917
|
const pathCommand = resolveCommandOnPath("codex", deps);
|
|
5763
|
-
if (pathCommand)
|
|
5918
|
+
if (pathCommand) {
|
|
5919
|
+
candidates.push({
|
|
5920
|
+
source: "path",
|
|
5921
|
+
command: pathCommand,
|
|
5922
|
+
argsPrefix: [],
|
|
5923
|
+
shell: false
|
|
5924
|
+
});
|
|
5925
|
+
}
|
|
5764
5926
|
if (platform === "darwin") {
|
|
5765
|
-
|
|
5927
|
+
const bundleCommand = firstExistingPath([CODEX_DESKTOP_BUNDLE_PATH], deps);
|
|
5928
|
+
if (bundleCommand && !candidates.some((candidate) => candidate.command === bundleCommand)) {
|
|
5929
|
+
candidates.push({
|
|
5930
|
+
source: "desktop_bundle",
|
|
5931
|
+
command: bundleCommand,
|
|
5932
|
+
argsPrefix: [],
|
|
5933
|
+
shell: false
|
|
5934
|
+
});
|
|
5935
|
+
}
|
|
5766
5936
|
}
|
|
5767
|
-
return
|
|
5937
|
+
return candidates;
|
|
5938
|
+
}
|
|
5939
|
+
function formatCodexCandidate(candidate) {
|
|
5940
|
+
return [candidate.command, ...candidate.argsPrefix].join(" ");
|
|
5941
|
+
}
|
|
5942
|
+
function describeCodexProbeFailure(error) {
|
|
5943
|
+
if (error && typeof error === "object") {
|
|
5944
|
+
const candidate = error;
|
|
5945
|
+
if (typeof candidate.status === "number") return `exit status ${candidate.status}`;
|
|
5946
|
+
if (typeof candidate.signal === "string") return `terminated by ${candidate.signal}`;
|
|
5947
|
+
if (typeof candidate.code === "string") return candidate.code;
|
|
5948
|
+
}
|
|
5949
|
+
return "probe failed";
|
|
5950
|
+
}
|
|
5951
|
+
function validateCodexAppServer(candidate, deps = {}) {
|
|
5952
|
+
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
|
|
5953
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
5954
|
+
try {
|
|
5955
|
+
execFileSyncFn(candidate.command, [...candidate.argsPrefix, ...CODEX_APP_SERVER_PROBE_ARGS], {
|
|
5956
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5957
|
+
env,
|
|
5958
|
+
timeout: 5e3,
|
|
5959
|
+
shell: candidate.shell
|
|
5960
|
+
});
|
|
5961
|
+
return null;
|
|
5962
|
+
} catch (error) {
|
|
5963
|
+
return describeCodexProbeFailure(error);
|
|
5964
|
+
}
|
|
5965
|
+
}
|
|
5966
|
+
function readCodexCandidateVersion(candidate, deps = {}) {
|
|
5967
|
+
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
|
|
5968
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
5969
|
+
try {
|
|
5970
|
+
const output = execFileSyncFn(candidate.command, [...candidate.argsPrefix, "--version"], {
|
|
5971
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5972
|
+
env,
|
|
5973
|
+
timeout: 5e3,
|
|
5974
|
+
shell: candidate.shell
|
|
5975
|
+
});
|
|
5976
|
+
return (Buffer.isBuffer(output) ? output.toString("utf8") : String(output ?? "")).trim().split(/\r?\n/)[0] || null;
|
|
5977
|
+
} catch {
|
|
5978
|
+
return null;
|
|
5979
|
+
}
|
|
5980
|
+
}
|
|
5981
|
+
function resolveCompatibleCodexCandidate(deps = {}) {
|
|
5982
|
+
const rejected = [];
|
|
5983
|
+
for (const candidate of codexSpawnCandidates(deps)) {
|
|
5984
|
+
const failure = validateCodexAppServer(candidate, deps);
|
|
5985
|
+
if (!failure) return { candidate, rejected };
|
|
5986
|
+
rejected.push(`${candidate.source} ${formatCodexCandidate(candidate)} rejected: app-server probe ${failure}`);
|
|
5987
|
+
}
|
|
5988
|
+
return { candidate: null, rejected };
|
|
5768
5989
|
}
|
|
5769
5990
|
function probeCodex(deps = {}) {
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
} catch {
|
|
5778
|
-
return { available: false };
|
|
5779
|
-
}
|
|
5991
|
+
const { candidate, rejected } = resolveCompatibleCodexCandidate(deps);
|
|
5992
|
+
const diagnostic = rejected.length > 0 ? rejected.join("; ") : void 0;
|
|
5993
|
+
if (!candidate) {
|
|
5994
|
+
return {
|
|
5995
|
+
available: false,
|
|
5996
|
+
diagnostic: diagnostic ?? "No Codex CLI app-server candidate was found."
|
|
5997
|
+
};
|
|
5780
5998
|
}
|
|
5781
|
-
const command = resolveCodexCommand(deps);
|
|
5782
|
-
if (!command) return { available: false };
|
|
5783
5999
|
return {
|
|
5784
6000
|
available: true,
|
|
5785
|
-
version:
|
|
6001
|
+
version: readCodexCandidateVersion(candidate, deps) ?? void 0,
|
|
6002
|
+
...diagnostic ? { diagnostic } : {}
|
|
5786
6003
|
};
|
|
5787
6004
|
}
|
|
5788
6005
|
function resolveCodexSpawn(commandArgs, deps = {}) {
|
|
5789
|
-
|
|
5790
|
-
|
|
6006
|
+
const { candidate, rejected } = resolveCompatibleCodexCandidate(deps);
|
|
6007
|
+
if (candidate) {
|
|
6008
|
+
return { command: candidate.command, args: [...candidate.argsPrefix, ...commandArgs], shell: candidate.shell };
|
|
5791
6009
|
}
|
|
5792
|
-
const
|
|
5793
|
-
if (
|
|
5794
|
-
|
|
5795
|
-
command
|
|
5796
|
-
|
|
5797
|
-
shell: false
|
|
5798
|
-
};
|
|
5799
|
-
}
|
|
5800
|
-
const command = resolveCommandOnPath("codex", deps);
|
|
5801
|
-
if (command && !isWindowsSandboxRunner(command)) {
|
|
5802
|
-
return { command, args: commandArgs, shell: requiresWindowsShell(command, deps.platform) };
|
|
5803
|
-
}
|
|
5804
|
-
const desktopEntry = resolveWindowsCodexDesktopEntry(deps);
|
|
5805
|
-
if (desktopEntry) {
|
|
5806
|
-
return { command: desktopEntry, args: commandArgs, shell: false };
|
|
6010
|
+
const diagnostic = rejected.length > 0 ? ` Rejected candidates: ${rejected.join("; ")}.` : "";
|
|
6011
|
+
if ((deps.platform ?? process.platform) === "win32") {
|
|
6012
|
+
throw new Error(
|
|
6013
|
+
"Cannot resolve a compatible Codex CLI app-server entry point on Windows. Install Codex Desktop or install @openai/codex globally via npm (npm i -g @openai/codex). Ignoring .codex/.sandbox-bin/codex-command-runner because it is a sandbox helper, not the Codex CLI." + diagnostic
|
|
6014
|
+
);
|
|
5807
6015
|
}
|
|
5808
|
-
throw new Error(
|
|
5809
|
-
"Cannot resolve Codex CLI entry point on Windows. Install Codex Desktop or install @openai/codex globally via npm (npm i -g @openai/codex). Ignoring .codex/.sandbox-bin/codex-command-runner because it is a sandbox helper, not the Codex CLI."
|
|
5810
|
-
);
|
|
6016
|
+
throw new Error(`Cannot resolve a compatible Codex CLI app-server entry point.${diagnostic}`);
|
|
5811
6017
|
}
|
|
5812
6018
|
function isCodexMissingRolloutError(message) {
|
|
5813
6019
|
return /\bno\s+rollout\s+found\b/i.test(message) || /\bmissing\s+rollout\b/i.test(message) || /\brollout\b.*\b(not found|missing)\b/i.test(message) || /\bthread\b.*\b(not found|missing)\b/i.test(message) || /\bmissing\s+thread\b/i.test(message);
|
|
5814
6020
|
}
|
|
5815
|
-
function
|
|
6021
|
+
function codexMissingRolloutRecoveryMessage() {
|
|
6022
|
+
return "Codex could not resume its previous thread; Slock started a fresh Codex thread.";
|
|
6023
|
+
}
|
|
6024
|
+
function codexMissingRolloutRecoveryDetails() {
|
|
6025
|
+
return "Use Slock conversation history and local MEMORY.md/notes as the recovery point; do not assume prior Codex thread context is loaded.";
|
|
6026
|
+
}
|
|
6027
|
+
function prependCodexRecoveryNotice(prompt, recovery) {
|
|
6028
|
+
return `${recovery.message}
|
|
6029
|
+
|
|
6030
|
+
${recovery.details}
|
|
6031
|
+
|
|
6032
|
+
${prompt}`;
|
|
6033
|
+
}
|
|
6034
|
+
function classifyCodexResumeError(message, requestedSessionId) {
|
|
5816
6035
|
if (isCodexMissingRolloutError(message)) {
|
|
5817
6036
|
return {
|
|
5818
6037
|
kind: "missing_rollout",
|
|
@@ -5826,6 +6045,15 @@ function classifyCodexResumeError(message) {
|
|
|
5826
6045
|
resume_error_class: "missing_rollout",
|
|
5827
6046
|
recovery_action: "fallback_fresh_thread"
|
|
5828
6047
|
}
|
|
6048
|
+
},
|
|
6049
|
+
recovery: {
|
|
6050
|
+
kind: "runtime_recovery",
|
|
6051
|
+
source: "codex_resume_missing_rollout",
|
|
6052
|
+
resumeErrorClass: "missing_rollout",
|
|
6053
|
+
recoveryAction: "fallback_fresh_thread",
|
|
6054
|
+
message: codexMissingRolloutRecoveryMessage(),
|
|
6055
|
+
details: codexMissingRolloutRecoveryDetails(),
|
|
6056
|
+
...requestedSessionId ? { requestedSessionId } : {}
|
|
5829
6057
|
}
|
|
5830
6058
|
};
|
|
5831
6059
|
}
|
|
@@ -5849,6 +6077,26 @@ function isJsonRpcResponse(message) {
|
|
|
5849
6077
|
function isCodexServerRequest(message) {
|
|
5850
6078
|
return message.id !== void 0 && typeof message.method === "string" && !isJsonRpcResponse(message);
|
|
5851
6079
|
}
|
|
6080
|
+
function payloadBytes2(value) {
|
|
6081
|
+
try {
|
|
6082
|
+
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
6083
|
+
} catch {
|
|
6084
|
+
return void 0;
|
|
6085
|
+
}
|
|
6086
|
+
}
|
|
6087
|
+
function extractCodexHome(result) {
|
|
6088
|
+
if (!result || typeof result !== "object") return null;
|
|
6089
|
+
const candidate = result.codexHome;
|
|
6090
|
+
return typeof candidate === "string" && candidate.trim().length > 0 ? candidate : null;
|
|
6091
|
+
}
|
|
6092
|
+
function isCompatibleInitializeResult(result) {
|
|
6093
|
+
if (!result || typeof result !== "object" || Array.isArray(result)) return false;
|
|
6094
|
+
const userAgent = result.userAgent;
|
|
6095
|
+
return typeof userAgent === "string" && userAgent.trim().length > 0;
|
|
6096
|
+
}
|
|
6097
|
+
function unsupportedInitializeResultMessage() {
|
|
6098
|
+
return "Codex app-server initialize response is missing the expected userAgent handshake field; upgrade Codex CLI to a compatible app-server build.";
|
|
6099
|
+
}
|
|
5852
6100
|
var CodexDriver = class {
|
|
5853
6101
|
id = "codex";
|
|
5854
6102
|
lifecycle = {
|
|
@@ -5919,9 +6167,16 @@ var CodexDriver = class {
|
|
|
5919
6167
|
pendingThreadRequestId = null;
|
|
5920
6168
|
pendingThreadRequestMethod = null;
|
|
5921
6169
|
pendingResumeFallbackParams = null;
|
|
6170
|
+
pendingResumeThreadId = null;
|
|
5922
6171
|
pendingInitialTurnRequestId = null;
|
|
6172
|
+
pendingDeliveryRequests = /* @__PURE__ */ new Map();
|
|
5923
6173
|
initialTurnStarted = false;
|
|
5924
6174
|
normalizer = new CodexEventNormalizer();
|
|
6175
|
+
codexHomeRoot = null;
|
|
6176
|
+
spawnWorkingDirectory = null;
|
|
6177
|
+
get currentRuntimeHomeDir() {
|
|
6178
|
+
return this.codexHomeRoot;
|
|
6179
|
+
}
|
|
5925
6180
|
async spawn(ctx) {
|
|
5926
6181
|
const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
5927
6182
|
this.process = null;
|
|
@@ -5932,9 +6187,16 @@ var CodexDriver = class {
|
|
|
5932
6187
|
this.pendingThreadRequestId = null;
|
|
5933
6188
|
this.pendingThreadRequestMethod = null;
|
|
5934
6189
|
this.pendingResumeFallbackParams = null;
|
|
6190
|
+
this.pendingResumeThreadId = null;
|
|
5935
6191
|
this.pendingInitialTurnRequestId = null;
|
|
6192
|
+
this.pendingDeliveryRequests.clear();
|
|
5936
6193
|
this.initialTurnStarted = false;
|
|
5937
6194
|
this.normalizer.reset();
|
|
6195
|
+
this.spawnWorkingDirectory = ctx.workingDirectory;
|
|
6196
|
+
this.codexHomeRoot = resolveCodexHomeRootFromEnv(spawnEnv, {
|
|
6197
|
+
defaultHomeDir: os4.homedir(),
|
|
6198
|
+
cwd: ctx.workingDirectory
|
|
6199
|
+
});
|
|
5938
6200
|
const args = ["app-server", "--listen", "stdio://"];
|
|
5939
6201
|
const { command, args: spawnArgs, shell } = resolveCodexSpawn(args);
|
|
5940
6202
|
const proc = spawn2(command, spawnArgs, {
|
|
@@ -5969,6 +6231,24 @@ var CodexDriver = class {
|
|
|
5969
6231
|
const isResponse = isJsonRpcResponse(message);
|
|
5970
6232
|
if (isResponse && hasJsonRpcField(message, "result")) {
|
|
5971
6233
|
if (message.id === this.initializeRequestId) {
|
|
6234
|
+
if (!isCompatibleInitializeResult(message.result)) {
|
|
6235
|
+
this.initializeRequestId = null;
|
|
6236
|
+
this.pendingThreadRequest = null;
|
|
6237
|
+
this.pendingThreadRequestId = null;
|
|
6238
|
+
this.pendingThreadRequestMethod = null;
|
|
6239
|
+
this.pendingResumeFallbackParams = null;
|
|
6240
|
+
this.pendingResumeThreadId = null;
|
|
6241
|
+
events.push({
|
|
6242
|
+
kind: "error",
|
|
6243
|
+
message: unsupportedInitializeResultMessage(),
|
|
6244
|
+
startupRequestMethod: "initialize"
|
|
6245
|
+
});
|
|
6246
|
+
return events;
|
|
6247
|
+
}
|
|
6248
|
+
const codexHome = extractCodexHome(message.result);
|
|
6249
|
+
if (codexHome) {
|
|
6250
|
+
this.codexHomeRoot = path7.resolve(this.spawnWorkingDirectory ?? process.cwd(), codexHome);
|
|
6251
|
+
}
|
|
5972
6252
|
this.initializeRequestId = null;
|
|
5973
6253
|
this.sendNotification("initialized", {});
|
|
5974
6254
|
if (this.pendingThreadRequest) {
|
|
@@ -5984,6 +6264,7 @@ var CodexDriver = class {
|
|
|
5984
6264
|
this.pendingThreadRequestId = null;
|
|
5985
6265
|
this.pendingThreadRequestMethod = null;
|
|
5986
6266
|
this.pendingResumeFallbackParams = null;
|
|
6267
|
+
this.pendingResumeThreadId = null;
|
|
5987
6268
|
events.push({
|
|
5988
6269
|
kind: "error",
|
|
5989
6270
|
message: message.error?.message || "Codex app-server request failed",
|
|
@@ -5995,9 +6276,16 @@ var CodexDriver = class {
|
|
|
5995
6276
|
if (hasJsonRpcField(message, "error")) {
|
|
5996
6277
|
const errorMessage = message.error?.message || "Codex app-server request failed";
|
|
5997
6278
|
const requestMethod = this.pendingThreadRequestMethod;
|
|
5998
|
-
const resumeErrorClassification = requestMethod === "thread/resume" ? classifyCodexResumeError(errorMessage) : null;
|
|
6279
|
+
const resumeErrorClassification = requestMethod === "thread/resume" ? classifyCodexResumeError(errorMessage, this.pendingResumeThreadId || void 0) : null;
|
|
5999
6280
|
if (this.pendingResumeFallbackParams && resumeErrorClassification?.kind === "missing_rollout") {
|
|
6000
6281
|
events.push(resumeErrorClassification.telemetry);
|
|
6282
|
+
events.push(resumeErrorClassification.recovery);
|
|
6283
|
+
if (this.pendingInitialPrompt) {
|
|
6284
|
+
this.pendingInitialPrompt = prependCodexRecoveryNotice(
|
|
6285
|
+
this.pendingInitialPrompt,
|
|
6286
|
+
resumeErrorClassification.recovery
|
|
6287
|
+
);
|
|
6288
|
+
}
|
|
6001
6289
|
this.sendThreadRequest("thread/start", this.pendingResumeFallbackParams);
|
|
6002
6290
|
this.pendingResumeFallbackParams = null;
|
|
6003
6291
|
return events;
|
|
@@ -6005,12 +6293,14 @@ var CodexDriver = class {
|
|
|
6005
6293
|
this.pendingThreadRequestId = null;
|
|
6006
6294
|
this.pendingThreadRequestMethod = null;
|
|
6007
6295
|
this.pendingResumeFallbackParams = null;
|
|
6296
|
+
this.pendingResumeThreadId = null;
|
|
6008
6297
|
events.push(requestMethod ? { kind: "error", message: errorMessage, startupRequestMethod: requestMethod } : { kind: "error", message: errorMessage });
|
|
6009
6298
|
return events;
|
|
6010
6299
|
}
|
|
6011
6300
|
this.pendingThreadRequestId = null;
|
|
6012
6301
|
this.pendingThreadRequestMethod = null;
|
|
6013
6302
|
this.pendingResumeFallbackParams = null;
|
|
6303
|
+
this.pendingResumeThreadId = null;
|
|
6014
6304
|
}
|
|
6015
6305
|
if (isResponse && message.id === this.pendingInitialTurnRequestId) {
|
|
6016
6306
|
this.pendingInitialTurnRequestId = null;
|
|
@@ -6025,6 +6315,21 @@ var CodexDriver = class {
|
|
|
6025
6315
|
}
|
|
6026
6316
|
return events;
|
|
6027
6317
|
}
|
|
6318
|
+
if (isResponse && message.id !== void 0 && this.pendingDeliveryRequests.has(message.id)) {
|
|
6319
|
+
const requestMethod = this.pendingDeliveryRequests.get(message.id);
|
|
6320
|
+
this.pendingDeliveryRequests.delete(message.id);
|
|
6321
|
+
if (hasJsonRpcField(message, "error")) {
|
|
6322
|
+
const params = message.error ?? {};
|
|
6323
|
+
events.push({
|
|
6324
|
+
kind: "delivery_error",
|
|
6325
|
+
message: message.error?.message || "Codex app-server request failed",
|
|
6326
|
+
requestMethod,
|
|
6327
|
+
source: "codex_app_server_response",
|
|
6328
|
+
payloadBytes: payloadBytes2(params)
|
|
6329
|
+
});
|
|
6330
|
+
}
|
|
6331
|
+
return events;
|
|
6332
|
+
}
|
|
6028
6333
|
const result = this.normalizer.normalizeMessage(message);
|
|
6029
6334
|
if (result.turnStarted) {
|
|
6030
6335
|
this.pendingInitialTurnRequestId = null;
|
|
@@ -6043,9 +6348,11 @@ var CodexDriver = class {
|
|
|
6043
6348
|
const mode = opts?.mode || "busy";
|
|
6044
6349
|
if (mode === "busy") {
|
|
6045
6350
|
if (!this.normalizer.canSteerBusy) return null;
|
|
6351
|
+
const id2 = this.nextRequestId();
|
|
6352
|
+
this.pendingDeliveryRequests.set(id2, "turn/steer");
|
|
6046
6353
|
return JSON.stringify({
|
|
6047
6354
|
jsonrpc: "2.0",
|
|
6048
|
-
id:
|
|
6355
|
+
id: id2,
|
|
6049
6356
|
method: "turn/steer",
|
|
6050
6357
|
params: {
|
|
6051
6358
|
threadId: this.normalizer.threadId,
|
|
@@ -6054,9 +6361,11 @@ var CodexDriver = class {
|
|
|
6054
6361
|
}
|
|
6055
6362
|
});
|
|
6056
6363
|
}
|
|
6364
|
+
const id = this.nextRequestId();
|
|
6365
|
+
this.pendingDeliveryRequests.set(id, "turn/start");
|
|
6057
6366
|
return JSON.stringify({
|
|
6058
6367
|
jsonrpc: "2.0",
|
|
6059
|
-
id
|
|
6368
|
+
id,
|
|
6060
6369
|
method: "turn/start",
|
|
6061
6370
|
params: {
|
|
6062
6371
|
threadId: this.normalizer.threadId,
|
|
@@ -6112,9 +6421,11 @@ var CodexDriver = class {
|
|
|
6112
6421
|
this.pendingThreadRequestId = id;
|
|
6113
6422
|
this.pendingThreadRequestMethod = method;
|
|
6114
6423
|
this.pendingResumeFallbackParams = null;
|
|
6424
|
+
this.pendingResumeThreadId = null;
|
|
6115
6425
|
if (method === "thread/resume") {
|
|
6116
6426
|
const { threadId: _threadId, ...freshParams } = params;
|
|
6117
6427
|
this.pendingResumeFallbackParams = freshParams;
|
|
6428
|
+
this.pendingResumeThreadId = typeof _threadId === "string" && _threadId.trim() ? _threadId.trim() : null;
|
|
6118
6429
|
}
|
|
6119
6430
|
return id;
|
|
6120
6431
|
}
|
|
@@ -6126,12 +6437,194 @@ var CodexDriver = class {
|
|
|
6126
6437
|
}) + "\n");
|
|
6127
6438
|
}
|
|
6128
6439
|
async detectModels() {
|
|
6129
|
-
return detectCodexModels();
|
|
6440
|
+
return await detectCodexModelsFromAppServer() ?? detectCodexModels(resolveCodexHomeRootFromEnv());
|
|
6130
6441
|
}
|
|
6131
6442
|
};
|
|
6132
|
-
function
|
|
6133
|
-
|
|
6134
|
-
|
|
6443
|
+
function asNonEmptyString(value) {
|
|
6444
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
6445
|
+
}
|
|
6446
|
+
function modelListPage(result) {
|
|
6447
|
+
if (!result || typeof result !== "object") return null;
|
|
6448
|
+
const object = result;
|
|
6449
|
+
const entries = Array.isArray(object.data) ? object.data : Array.isArray(object.models) ? object.models : null;
|
|
6450
|
+
if (!entries) return null;
|
|
6451
|
+
return {
|
|
6452
|
+
entries,
|
|
6453
|
+
nextCursor: asNonEmptyString(object.nextCursor)
|
|
6454
|
+
};
|
|
6455
|
+
}
|
|
6456
|
+
function modelListRequestParams(cursor) {
|
|
6457
|
+
return cursor ? { cursor } : {};
|
|
6458
|
+
}
|
|
6459
|
+
function stringArray(values, read) {
|
|
6460
|
+
const result = [];
|
|
6461
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6462
|
+
for (const value of values) {
|
|
6463
|
+
const item = read(value);
|
|
6464
|
+
if (!item || seen.has(item)) continue;
|
|
6465
|
+
seen.add(item);
|
|
6466
|
+
result.push(item);
|
|
6467
|
+
}
|
|
6468
|
+
return result;
|
|
6469
|
+
}
|
|
6470
|
+
function codexReasoningEfforts(value) {
|
|
6471
|
+
if (!Array.isArray(value)) return [];
|
|
6472
|
+
return stringArray(value, (entry) => {
|
|
6473
|
+
if (typeof entry === "string") return asNonEmptyString(entry);
|
|
6474
|
+
if (!entry || typeof entry !== "object") return null;
|
|
6475
|
+
const object = entry;
|
|
6476
|
+
return asNonEmptyString(object.reasoningEffort) ?? asNonEmptyString(object.id);
|
|
6477
|
+
});
|
|
6478
|
+
}
|
|
6479
|
+
function codexServiceTierIds(value) {
|
|
6480
|
+
if (!Array.isArray(value)) return [];
|
|
6481
|
+
return stringArray(value, (entry) => {
|
|
6482
|
+
if (typeof entry === "string") return asNonEmptyString(entry);
|
|
6483
|
+
if (!entry || typeof entry !== "object") return null;
|
|
6484
|
+
const object = entry;
|
|
6485
|
+
return asNonEmptyString(object.id) ?? asNonEmptyString(object.serviceTier);
|
|
6486
|
+
});
|
|
6487
|
+
}
|
|
6488
|
+
function codexModelInfoFromAppServer(entry) {
|
|
6489
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
6490
|
+
const object = entry;
|
|
6491
|
+
if (object.hidden === true) return null;
|
|
6492
|
+
const id = asNonEmptyString(object.id) ?? asNonEmptyString(object.model) ?? asNonEmptyString(object.slug);
|
|
6493
|
+
if (!id) return null;
|
|
6494
|
+
const label = asNonEmptyString(object.displayName) ?? asNonEmptyString(object.display_name) ?? asNonEmptyString(object.label) ?? id;
|
|
6495
|
+
const supportedReasoningEfforts = codexReasoningEfforts(object.supportedReasoningEfforts);
|
|
6496
|
+
const serviceTiers = codexServiceTierIds(object.serviceTiers);
|
|
6497
|
+
const additionalSpeedTiers = codexServiceTierIds(object.additionalSpeedTiers);
|
|
6498
|
+
const runtimeServiceTiers = serviceTiers.length > 0 ? serviceTiers : additionalSpeedTiers;
|
|
6499
|
+
const defaultReasoningEffort = asNonEmptyString(object.defaultReasoningEffort);
|
|
6500
|
+
const defaultServiceTier = asNonEmptyString(object.defaultServiceTier);
|
|
6501
|
+
return {
|
|
6502
|
+
id,
|
|
6503
|
+
label,
|
|
6504
|
+
verified: "launchable",
|
|
6505
|
+
...supportedReasoningEfforts.length > 0 ? { supportedReasoningEfforts } : {},
|
|
6506
|
+
...defaultReasoningEffort ? { defaultReasoningEffort } : {},
|
|
6507
|
+
...runtimeServiceTiers.length > 0 ? { serviceTiers: runtimeServiceTiers } : {},
|
|
6508
|
+
...defaultServiceTier ? { defaultServiceTier } : {}
|
|
6509
|
+
};
|
|
6510
|
+
}
|
|
6511
|
+
function codexModelSetFromAppServerEntries(entries) {
|
|
6512
|
+
const models = [];
|
|
6513
|
+
let defaultModel;
|
|
6514
|
+
for (const entry of entries) {
|
|
6515
|
+
const model = codexModelInfoFromAppServer(entry);
|
|
6516
|
+
if (!model) continue;
|
|
6517
|
+
models.push(model);
|
|
6518
|
+
if (!defaultModel && typeof entry === "object" && entry && entry.isDefault === true) {
|
|
6519
|
+
defaultModel = model.id;
|
|
6520
|
+
}
|
|
6521
|
+
}
|
|
6522
|
+
return models.length > 0 ? { models, default: defaultModel } : null;
|
|
6523
|
+
}
|
|
6524
|
+
async function detectCodexModelsFromAppServer(options = {}) {
|
|
6525
|
+
const env = options.env ?? process.env;
|
|
6526
|
+
let launch;
|
|
6527
|
+
try {
|
|
6528
|
+
launch = resolveCodexSpawn(["app-server", "--listen", "stdio://"], { env });
|
|
6529
|
+
} catch {
|
|
6530
|
+
return null;
|
|
6531
|
+
}
|
|
6532
|
+
return await new Promise((resolve) => {
|
|
6533
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
6534
|
+
const proc = spawn2(launch.command, launch.args, {
|
|
6535
|
+
cwd: options.cwd ?? process.cwd(),
|
|
6536
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
6537
|
+
env,
|
|
6538
|
+
shell: launch.shell
|
|
6539
|
+
});
|
|
6540
|
+
let settled = false;
|
|
6541
|
+
let buffer = "";
|
|
6542
|
+
let requestId = 0;
|
|
6543
|
+
let initializeRequestId = null;
|
|
6544
|
+
let modelListRequestId = null;
|
|
6545
|
+
let pageCount = 0;
|
|
6546
|
+
const entries = [];
|
|
6547
|
+
const finish = (result) => {
|
|
6548
|
+
if (settled) return;
|
|
6549
|
+
settled = true;
|
|
6550
|
+
clearTimeout(timer);
|
|
6551
|
+
proc.kill();
|
|
6552
|
+
resolve(result);
|
|
6553
|
+
};
|
|
6554
|
+
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
6555
|
+
const sendRequest = (method, params) => {
|
|
6556
|
+
requestId += 1;
|
|
6557
|
+
const id = requestId;
|
|
6558
|
+
proc.stdin?.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
|
|
6559
|
+
return id;
|
|
6560
|
+
};
|
|
6561
|
+
const sendNotification = (method, params) => {
|
|
6562
|
+
proc.stdin?.write(JSON.stringify({ jsonrpc: "2.0", method, params }) + "\n");
|
|
6563
|
+
};
|
|
6564
|
+
const requestModelPage = (cursor) => {
|
|
6565
|
+
pageCount += 1;
|
|
6566
|
+
modelListRequestId = sendRequest("model/list", modelListRequestParams(cursor));
|
|
6567
|
+
};
|
|
6568
|
+
proc.once("error", () => finish(null));
|
|
6569
|
+
proc.once("exit", () => finish(null));
|
|
6570
|
+
proc.stdout?.on("data", (chunk) => {
|
|
6571
|
+
if (settled) return;
|
|
6572
|
+
buffer += chunk.toString();
|
|
6573
|
+
for (; ; ) {
|
|
6574
|
+
const newline = buffer.indexOf("\n");
|
|
6575
|
+
if (newline === -1) break;
|
|
6576
|
+
const line = buffer.slice(0, newline).trim();
|
|
6577
|
+
buffer = buffer.slice(newline + 1);
|
|
6578
|
+
if (!line) continue;
|
|
6579
|
+
const message = parseCodexJsonRpcLine(line);
|
|
6580
|
+
if (!message || !isJsonRpcResponse(message)) continue;
|
|
6581
|
+
if (message.id === initializeRequestId) {
|
|
6582
|
+
if (!hasJsonRpcField(message, "result") || !isCompatibleInitializeResult(message.result)) {
|
|
6583
|
+
finish(null);
|
|
6584
|
+
return;
|
|
6585
|
+
}
|
|
6586
|
+
sendNotification("initialized", {});
|
|
6587
|
+
requestModelPage(null);
|
|
6588
|
+
continue;
|
|
6589
|
+
}
|
|
6590
|
+
if (message.id === modelListRequestId) {
|
|
6591
|
+
if (!hasJsonRpcField(message, "result")) {
|
|
6592
|
+
finish(null);
|
|
6593
|
+
return;
|
|
6594
|
+
}
|
|
6595
|
+
const page = modelListPage(message.result);
|
|
6596
|
+
if (!page) {
|
|
6597
|
+
finish(null);
|
|
6598
|
+
return;
|
|
6599
|
+
}
|
|
6600
|
+
entries.push(...page.entries);
|
|
6601
|
+
if (page.nextCursor && pageCount < 5) {
|
|
6602
|
+
requestModelPage(page.nextCursor);
|
|
6603
|
+
continue;
|
|
6604
|
+
}
|
|
6605
|
+
finish(codexModelSetFromAppServerEntries(entries));
|
|
6606
|
+
return;
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
});
|
|
6610
|
+
initializeRequestId = sendRequest("initialize", {
|
|
6611
|
+
clientInfo: { name: "slock-daemon", version: "1.0.0" },
|
|
6612
|
+
capabilities: { experimentalApi: true }
|
|
6613
|
+
});
|
|
6614
|
+
});
|
|
6615
|
+
}
|
|
6616
|
+
function detectCodexModels(home = resolveCodexHomeRootFromEnv()) {
|
|
6617
|
+
let cachePath = null;
|
|
6618
|
+
let configPath = null;
|
|
6619
|
+
for (const root of codexStateRootCandidates(home)) {
|
|
6620
|
+
const candidate = path7.join(root, "models_cache.json");
|
|
6621
|
+
if (existsSync5(candidate)) {
|
|
6622
|
+
cachePath = candidate;
|
|
6623
|
+
configPath = path7.join(root, "config.toml");
|
|
6624
|
+
break;
|
|
6625
|
+
}
|
|
6626
|
+
}
|
|
6627
|
+
if (!cachePath || !configPath) return null;
|
|
6135
6628
|
let models = [];
|
|
6136
6629
|
try {
|
|
6137
6630
|
const raw = readFileSync2(cachePath, "utf8");
|
|
@@ -6601,7 +7094,7 @@ function runCursorModelsCommand() {
|
|
|
6601
7094
|
// src/drivers/gemini.ts
|
|
6602
7095
|
import { execFileSync as execFileSync3, spawn as spawn6 } from "child_process";
|
|
6603
7096
|
import { existsSync as existsSync6 } from "fs";
|
|
6604
|
-
import
|
|
7097
|
+
import path8 from "path";
|
|
6605
7098
|
async function buildGeminiSpawnEnv(ctx, platform = process.platform) {
|
|
6606
7099
|
const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" }, platform);
|
|
6607
7100
|
const launchEnvVars = runtimeConfigToLaunchFields(ctx.config).envVars;
|
|
@@ -6645,7 +7138,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
6645
7138
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
6646
7139
|
const existsSyncFn = deps.existsSyncFn ?? existsSync6;
|
|
6647
7140
|
const env = deps.env ?? process.env;
|
|
6648
|
-
const winPath =
|
|
7141
|
+
const winPath = path8.win32;
|
|
6649
7142
|
let geminiEntry = null;
|
|
6650
7143
|
try {
|
|
6651
7144
|
const globalRoot = normalizeExecOutput2(execFileSyncFn("npm", ["root", "-g"], {
|
|
@@ -6782,8 +7275,8 @@ var GeminiDriver = class {
|
|
|
6782
7275
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
6783
7276
|
import { spawn as spawn7 } from "child_process";
|
|
6784
7277
|
import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
6785
|
-
import
|
|
6786
|
-
import
|
|
7278
|
+
import os5 from "os";
|
|
7279
|
+
import path9 from "path";
|
|
6787
7280
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
6788
7281
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
6789
7282
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
@@ -6830,8 +7323,8 @@ var KimiDriver = class {
|
|
|
6830
7323
|
this.sessionId = ctx.config.sessionId || randomUUID2();
|
|
6831
7324
|
this.sessionAnnounced = false;
|
|
6832
7325
|
this.promptRequestId = randomUUID2();
|
|
6833
|
-
const systemPromptPath =
|
|
6834
|
-
const agentFilePath =
|
|
7326
|
+
const systemPromptPath = path9.join(ctx.workingDirectory, KIMI_SYSTEM_PROMPT_FILE);
|
|
7327
|
+
const agentFilePath = path9.join(ctx.workingDirectory, KIMI_AGENT_FILE);
|
|
6835
7328
|
if (!isResume || !existsSync7(systemPromptPath)) {
|
|
6836
7329
|
writeFileSync3(systemPromptPath, ctx.prompt, "utf8");
|
|
6837
7330
|
}
|
|
@@ -6977,8 +7470,8 @@ var KimiDriver = class {
|
|
|
6977
7470
|
return detectKimiModels();
|
|
6978
7471
|
}
|
|
6979
7472
|
};
|
|
6980
|
-
function detectKimiModels(home =
|
|
6981
|
-
const configPath =
|
|
7473
|
+
function detectKimiModels(home = os5.homedir()) {
|
|
7474
|
+
const configPath = path9.join(home, ".kimi", "config.toml");
|
|
6982
7475
|
let raw;
|
|
6983
7476
|
try {
|
|
6984
7477
|
raw = readFileSync3(configPath, "utf8");
|
|
@@ -7007,7 +7500,7 @@ function detectKimiModels(home = os4.homedir()) {
|
|
|
7007
7500
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
7008
7501
|
import { EventEmitter } from "events";
|
|
7009
7502
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync4 } from "fs";
|
|
7010
|
-
import
|
|
7503
|
+
import path10 from "path";
|
|
7011
7504
|
import { createRequire as createRequire2 } from "module";
|
|
7012
7505
|
import {
|
|
7013
7506
|
createKimiHarness,
|
|
@@ -7032,7 +7525,7 @@ function createKimiSdkEventMappingState(sessionId = null) {
|
|
|
7032
7525
|
};
|
|
7033
7526
|
}
|
|
7034
7527
|
function buildKimiSessionDir(workingDirectory) {
|
|
7035
|
-
return
|
|
7528
|
+
return path10.join(workingDirectory, KIMI_SESSION_DIR);
|
|
7036
7529
|
}
|
|
7037
7530
|
function kimiErrorMessage(error) {
|
|
7038
7531
|
if (typeof error === "string" && error.trim()) return error.trim();
|
|
@@ -7159,7 +7652,7 @@ async function createKimiAgentSessionForContext(ctx, sessionId) {
|
|
|
7159
7652
|
const cliTransport = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
7160
7653
|
const spawnEnv = cliTransport.spawnEnv;
|
|
7161
7654
|
const wrapperPath = cliTransport.wrapperPath;
|
|
7162
|
-
const homeDir = spawnEnv.KIMI_HOME || (process.env.HOME ?
|
|
7655
|
+
const homeDir = spawnEnv.KIMI_HOME || (process.env.HOME ? path10.join(process.env.HOME, ".kimi") : path10.join(ctx.workingDirectory, ".kimi"));
|
|
7163
7656
|
mkdirSync3(homeDir, { recursive: true });
|
|
7164
7657
|
const harness = createKimiHarness({
|
|
7165
7658
|
homeDir,
|
|
@@ -7384,7 +7877,7 @@ So instead of \`raft message send ...\`, run \`${this.wrapperPath} message send
|
|
|
7384
7877
|
};
|
|
7385
7878
|
function detectKimiSdkModels(home = resolveKimiHome(), ctx = {}) {
|
|
7386
7879
|
const span = ctx.span;
|
|
7387
|
-
const configPath =
|
|
7880
|
+
const configPath = path10.join(home, "config.toml");
|
|
7388
7881
|
const homeFromEnv = Boolean(process.env.KIMI_CODE_HOME);
|
|
7389
7882
|
const emit2 = (outcome, extra = {}) => {
|
|
7390
7883
|
span?.addEvent("daemon.kimi_sdk.models.config", {
|
|
@@ -7492,8 +7985,8 @@ var KimiSdkDriver = class {
|
|
|
7492
7985
|
// src/drivers/opencode.ts
|
|
7493
7986
|
import { spawn as spawn8, spawnSync as spawnSync2 } from "child_process";
|
|
7494
7987
|
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
|
|
7495
|
-
import
|
|
7496
|
-
import
|
|
7988
|
+
import os6 from "os";
|
|
7989
|
+
import path11 from "path";
|
|
7497
7990
|
var SLOCK_AGENT_NAME = "slock";
|
|
7498
7991
|
var NO_MESSAGE_PROMPT = "No new messages are pending. Stop now.";
|
|
7499
7992
|
var FIRST_MESSAGE_TASK_PREFIX = "First message task (system-triggered):";
|
|
@@ -7521,8 +8014,8 @@ function parseUserOpenCodeConfig(ctx) {
|
|
|
7521
8014
|
const raw = runtimeConfigToLaunchFields(ctx.config).envVars?.OPENCODE_CONFIG_CONTENT;
|
|
7522
8015
|
return parseOpenCodeConfigContent(raw);
|
|
7523
8016
|
}
|
|
7524
|
-
function readLocalOpenCodeConfig(home =
|
|
7525
|
-
const configPath =
|
|
8017
|
+
function readLocalOpenCodeConfig(home = os6.homedir()) {
|
|
8018
|
+
const configPath = path11.join(home, ".config", "opencode", "opencode.json");
|
|
7526
8019
|
try {
|
|
7527
8020
|
return parseOpenCodeConfigContent(readFileSync5(configPath, "utf8"));
|
|
7528
8021
|
} catch {
|
|
@@ -7582,7 +8075,7 @@ function mergeOpenCodeConfigs(localConfig, envConfig) {
|
|
|
7582
8075
|
}
|
|
7583
8076
|
};
|
|
7584
8077
|
}
|
|
7585
|
-
function buildOpenCodeConfig(ctx, home =
|
|
8078
|
+
function buildOpenCodeConfig(ctx, home = os6.homedir()) {
|
|
7586
8079
|
const userConfig = mergeOpenCodeConfigs(readLocalOpenCodeConfig(home), parseUserOpenCodeConfig(ctx));
|
|
7587
8080
|
const userAgents = recordField(userConfig.agent);
|
|
7588
8081
|
const userSlockAgent = recordField(userAgents[SLOCK_AGENT_NAME]);
|
|
@@ -7600,7 +8093,7 @@ function buildOpenCodeConfig(ctx, home = os5.homedir()) {
|
|
|
7600
8093
|
mcp: recordField(userConfig.mcp)
|
|
7601
8094
|
};
|
|
7602
8095
|
}
|
|
7603
|
-
async function buildOpenCodeLaunchOptions(ctx, home =
|
|
8096
|
+
async function buildOpenCodeLaunchOptions(ctx, home = os6.homedir(), version = null) {
|
|
7604
8097
|
const slock = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
7605
8098
|
const config = buildOpenCodeConfig(ctx, home);
|
|
7606
8099
|
const env = {
|
|
@@ -7699,7 +8192,7 @@ function formatOpenCodeLabelToken(token) {
|
|
|
7699
8192
|
if (/^\d/.test(token)) return token;
|
|
7700
8193
|
return normalized.charAt(0).toUpperCase() + normalized.slice(1);
|
|
7701
8194
|
}
|
|
7702
|
-
function detectOpenCodeModels(home =
|
|
8195
|
+
function detectOpenCodeModels(home = os6.homedir(), runCommand = runOpenCodeModelsCommand) {
|
|
7703
8196
|
const commandResult = runCommand(home);
|
|
7704
8197
|
if (commandResult.error || commandResult.status !== 0) return null;
|
|
7705
8198
|
return parseOpenCodeModelsOutput(commandResult.stdout);
|
|
@@ -7720,11 +8213,11 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
7720
8213
|
};
|
|
7721
8214
|
}
|
|
7722
8215
|
function isWindowsCommandShim(commandPath) {
|
|
7723
|
-
const ext =
|
|
8216
|
+
const ext = path11.win32.extname(commandPath).toLowerCase();
|
|
7724
8217
|
return ext === ".cmd" || ext === ".bat";
|
|
7725
8218
|
}
|
|
7726
8219
|
function opencodePackageEntryCandidates(packageRoot) {
|
|
7727
|
-
const winPath =
|
|
8220
|
+
const winPath = path11.win32;
|
|
7728
8221
|
return [
|
|
7729
8222
|
winPath.join(packageRoot, "bin", "opencode.exe"),
|
|
7730
8223
|
winPath.join(packageRoot, "bin", "opencode.js"),
|
|
@@ -7733,7 +8226,7 @@ function opencodePackageEntryCandidates(packageRoot) {
|
|
|
7733
8226
|
];
|
|
7734
8227
|
}
|
|
7735
8228
|
function openCodeSpecForEntry(entry, commandArgs) {
|
|
7736
|
-
if (
|
|
8229
|
+
if (path11.win32.extname(entry).toLowerCase() === ".exe") {
|
|
7737
8230
|
return { command: entry, args: commandArgs, shell: false };
|
|
7738
8231
|
}
|
|
7739
8232
|
return { command: process.execPath, args: [entry, ...commandArgs], shell: false };
|
|
@@ -7742,7 +8235,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
|
7742
8235
|
const existsSyncFn = deps.existsSyncFn ?? existsSync8;
|
|
7743
8236
|
const execFileSyncFn = deps.execFileSyncFn;
|
|
7744
8237
|
const env = deps.env ?? process.env;
|
|
7745
|
-
const winPath =
|
|
8238
|
+
const winPath = path11.win32;
|
|
7746
8239
|
const candidates = [];
|
|
7747
8240
|
if (execFileSyncFn) {
|
|
7748
8241
|
try {
|
|
@@ -7770,7 +8263,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
|
7770
8263
|
function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
7771
8264
|
if (!isWindowsCommandShim(commandPath)) return [];
|
|
7772
8265
|
const readFileSyncFn = deps.readFileSyncFn ?? readFileSync5;
|
|
7773
|
-
const commandDir =
|
|
8266
|
+
const commandDir = path11.win32.dirname(commandPath);
|
|
7774
8267
|
let raw;
|
|
7775
8268
|
try {
|
|
7776
8269
|
raw = String(readFileSyncFn(commandPath, "utf8"));
|
|
@@ -7781,7 +8274,7 @@ function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
|
7781
8274
|
const dp0Pattern = /%~dp0\\?([^"\r\n]*?opencode\.(?:exe|js|mjs|cjs))/gi;
|
|
7782
8275
|
for (const match of raw.matchAll(dp0Pattern)) {
|
|
7783
8276
|
const relative = match[1]?.replace(/^\\+/, "");
|
|
7784
|
-
if (relative) candidates.push(
|
|
8277
|
+
if (relative) candidates.push(path11.win32.normalize(path11.win32.join(commandDir, relative)));
|
|
7785
8278
|
}
|
|
7786
8279
|
return candidates;
|
|
7787
8280
|
}
|
|
@@ -7795,7 +8288,7 @@ function resolveOpenCodeSpawn(commandArgs, deps = {}) {
|
|
|
7795
8288
|
};
|
|
7796
8289
|
}
|
|
7797
8290
|
const command = resolveCommandOnPath("opencode", deps);
|
|
7798
|
-
if (command &&
|
|
8291
|
+
if (command && path11.win32.extname(command).toLowerCase() === ".exe") {
|
|
7799
8292
|
return { command, args: commandArgs, shell: false };
|
|
7800
8293
|
}
|
|
7801
8294
|
const packageEntry = resolveWindowsOpenCodePackageEntry(command, deps);
|
|
@@ -7900,7 +8393,7 @@ var OpenCodeDriver = class {
|
|
|
7900
8393
|
if (unsupportedMessage) {
|
|
7901
8394
|
throw new Error(unsupportedMessage);
|
|
7902
8395
|
}
|
|
7903
|
-
const launch = await buildOpenCodeLaunchOptions(ctx,
|
|
8396
|
+
const launch = await buildOpenCodeLaunchOptions(ctx, os6.homedir(), version);
|
|
7904
8397
|
const spawnSpec = resolveOpenCodeSpawn(launch.args);
|
|
7905
8398
|
const proc = spawn8(spawnSpec.command, spawnSpec.args, {
|
|
7906
8399
|
cwd: ctx.workingDirectory,
|
|
@@ -7968,7 +8461,7 @@ var OpenCodeDriver = class {
|
|
|
7968
8461
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
7969
8462
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
7970
8463
|
import { mkdirSync as mkdirSync4, readdirSync as readdirSync2 } from "fs";
|
|
7971
|
-
import
|
|
8464
|
+
import path12 from "path";
|
|
7972
8465
|
import {
|
|
7973
8466
|
AuthStorage,
|
|
7974
8467
|
createBashTool,
|
|
@@ -7995,7 +8488,7 @@ function createPiSdkEventMappingState(sessionId = null) {
|
|
|
7995
8488
|
};
|
|
7996
8489
|
}
|
|
7997
8490
|
function buildPiSessionDir(workingDirectory) {
|
|
7998
|
-
return
|
|
8491
|
+
return path12.join(workingDirectory, PI_SESSION_DIR);
|
|
7999
8492
|
}
|
|
8000
8493
|
async function buildPiSpawnEnv(ctx) {
|
|
8001
8494
|
return (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
@@ -8017,7 +8510,7 @@ function findPiSessionFile(sessionDir, sessionId) {
|
|
|
8017
8510
|
}
|
|
8018
8511
|
const suffix = `_${sessionId}.jsonl`;
|
|
8019
8512
|
const match = entries.find((entry) => entry.endsWith(suffix));
|
|
8020
|
-
return match ?
|
|
8513
|
+
return match ? path12.join(sessionDir, match) : null;
|
|
8021
8514
|
}
|
|
8022
8515
|
function detectPiModelsFromRegistry(modelRegistry) {
|
|
8023
8516
|
const models = [];
|
|
@@ -8253,7 +8746,7 @@ async function createPiAgentSessionForContext(ctx, sessionId) {
|
|
|
8253
8746
|
try {
|
|
8254
8747
|
const spawnEnv = await buildPiSpawnEnv(ctx);
|
|
8255
8748
|
const agentDir = spawnEnv.PI_CODING_AGENT_DIR || getAgentDir();
|
|
8256
|
-
const authStorage = AuthStorage.create(
|
|
8749
|
+
const authStorage = AuthStorage.create(path12.join(agentDir, "auth.json"));
|
|
8257
8750
|
const settingsManager = SettingsManager.create(ctx.workingDirectory, agentDir);
|
|
8258
8751
|
const services = await createAgentSessionServices({
|
|
8259
8752
|
cwd: ctx.workingDirectory,
|
|
@@ -8652,6 +9145,9 @@ var ChildProcessRuntimeSession = class {
|
|
|
8652
9145
|
get currentSessionId() {
|
|
8653
9146
|
return this.driver.currentSessionId;
|
|
8654
9147
|
}
|
|
9148
|
+
get currentRuntimeHomeDir() {
|
|
9149
|
+
return this.driver.currentRuntimeHomeDir;
|
|
9150
|
+
}
|
|
8655
9151
|
get exitCode() {
|
|
8656
9152
|
return this.process?.exitCode ?? null;
|
|
8657
9153
|
}
|
|
@@ -8775,7 +9271,7 @@ function getDriver(runtimeId) {
|
|
|
8775
9271
|
|
|
8776
9272
|
// src/workspaces.ts
|
|
8777
9273
|
import { readdir, rm, stat } from "fs/promises";
|
|
8778
|
-
import
|
|
9274
|
+
import path13 from "path";
|
|
8779
9275
|
function isValidWorkspaceDirectoryName(directoryName) {
|
|
8780
9276
|
return !directoryName.includes("/") && !directoryName.includes("\\") && !directoryName.includes("..");
|
|
8781
9277
|
}
|
|
@@ -8783,7 +9279,7 @@ function resolveWorkspaceDirectoryPath(dataDir, directoryName) {
|
|
|
8783
9279
|
if (!isValidWorkspaceDirectoryName(directoryName)) {
|
|
8784
9280
|
return null;
|
|
8785
9281
|
}
|
|
8786
|
-
return
|
|
9282
|
+
return path13.join(dataDir, directoryName);
|
|
8787
9283
|
}
|
|
8788
9284
|
function emptyWorkspaceDirectorySummary(latestMtime = /* @__PURE__ */ new Date(0)) {
|
|
8789
9285
|
return {
|
|
@@ -8832,7 +9328,7 @@ async function summarizeWorkspaceDirectory(dirPath) {
|
|
|
8832
9328
|
return summary;
|
|
8833
9329
|
}
|
|
8834
9330
|
const childSummaries = await Promise.all(
|
|
8835
|
-
entries.map((entry) => summarizeWorkspaceEntry(
|
|
9331
|
+
entries.map((entry) => summarizeWorkspaceEntry(path13.join(dirPath, entry.name), entry))
|
|
8836
9332
|
);
|
|
8837
9333
|
for (const childSummary of childSummaries) {
|
|
8838
9334
|
summary = mergeWorkspaceDirectorySummaries(summary, childSummary);
|
|
@@ -8851,7 +9347,7 @@ async function scanWorkspaceDirectories(dataDir) {
|
|
|
8851
9347
|
if (!entry.isDirectory()) {
|
|
8852
9348
|
return null;
|
|
8853
9349
|
}
|
|
8854
|
-
const dirPath =
|
|
9350
|
+
const dirPath = path13.join(dataDir, entry.name);
|
|
8855
9351
|
try {
|
|
8856
9352
|
const summary = await summarizeWorkspaceDirectory(dirPath);
|
|
8857
9353
|
return {
|
|
@@ -9400,17 +9896,17 @@ function allowedTranscriptRootsForRuntime(runtime, homeDir, workspaceDir) {
|
|
|
9400
9896
|
const roots = [workspaceDir];
|
|
9401
9897
|
switch (runtime) {
|
|
9402
9898
|
case "claude":
|
|
9403
|
-
roots.push(
|
|
9899
|
+
roots.push(path14.join(homeDir, ".claude"));
|
|
9404
9900
|
break;
|
|
9405
9901
|
case "codex":
|
|
9406
|
-
roots.push(
|
|
9902
|
+
roots.push(homeDir, path14.join(homeDir, ".codex"));
|
|
9407
9903
|
break;
|
|
9408
9904
|
case "kimi":
|
|
9409
9905
|
case "kimi-sdk":
|
|
9410
|
-
roots.push(
|
|
9906
|
+
roots.push(path14.join(homeDir, ".kimi"));
|
|
9411
9907
|
break;
|
|
9412
9908
|
case "pi":
|
|
9413
|
-
roots.push(
|
|
9909
|
+
roots.push(path14.join(homeDir, ".pi"), path14.join(homeDir, ".pi", "agent"));
|
|
9414
9910
|
break;
|
|
9415
9911
|
}
|
|
9416
9912
|
return roots;
|
|
@@ -9421,8 +9917,8 @@ async function isPathWithinAllowedRoots(filePath, roots) {
|
|
|
9421
9917
|
for (const root of roots) {
|
|
9422
9918
|
const realRoot = await realpath(root).catch(() => null);
|
|
9423
9919
|
if (!realRoot) continue;
|
|
9424
|
-
const rel =
|
|
9425
|
-
if (!rel.startsWith("..") && !
|
|
9920
|
+
const rel = path14.relative(realRoot, real);
|
|
9921
|
+
if (!rel.startsWith("..") && !path14.isAbsolute(rel)) return true;
|
|
9426
9922
|
}
|
|
9427
9923
|
return false;
|
|
9428
9924
|
}
|
|
@@ -9469,12 +9965,12 @@ function findSessionJsonl(root, predicate) {
|
|
|
9469
9965
|
for (const entry of entries) {
|
|
9470
9966
|
if (++visited > maxEntries) return null;
|
|
9471
9967
|
if (!entry.isFile() || !predicate(entry.name)) continue;
|
|
9472
|
-
return
|
|
9968
|
+
return path14.join(dir, entry.name);
|
|
9473
9969
|
}
|
|
9474
9970
|
for (const entry of entries) {
|
|
9475
9971
|
if (++visited > maxEntries) return null;
|
|
9476
9972
|
if (!entry.isDirectory()) continue;
|
|
9477
|
-
const found = visit(
|
|
9973
|
+
const found = visit(path14.join(dir, entry.name), depth - 1);
|
|
9478
9974
|
if (found) return found;
|
|
9479
9975
|
}
|
|
9480
9976
|
return null;
|
|
@@ -9482,7 +9978,7 @@ function findSessionJsonl(root, predicate) {
|
|
|
9482
9978
|
return visit(root, maxDepth);
|
|
9483
9979
|
}
|
|
9484
9980
|
function findKimiSdkSessionDir(sessionId, agentId, homeDir) {
|
|
9485
|
-
const indexPath =
|
|
9981
|
+
const indexPath = path14.join(homeDir, ".kimi", "session_index.jsonl");
|
|
9486
9982
|
try {
|
|
9487
9983
|
const index = readFileSync6(indexPath, "utf8");
|
|
9488
9984
|
for (const line of index.split("\n")) {
|
|
@@ -9497,12 +9993,12 @@ function findKimiSdkSessionDir(sessionId, agentId, homeDir) {
|
|
|
9497
9993
|
}
|
|
9498
9994
|
} catch {
|
|
9499
9995
|
}
|
|
9500
|
-
const sessionsRoot =
|
|
9996
|
+
const sessionsRoot = path14.join(homeDir, ".kimi", "sessions");
|
|
9501
9997
|
try {
|
|
9502
9998
|
const prefix = agentId ? `wd_${agentId}_` : `wd_`;
|
|
9503
9999
|
for (const entry of readdirSync3(sessionsRoot, { withFileTypes: true })) {
|
|
9504
10000
|
if (!entry.isDirectory() || !entry.name.startsWith(prefix)) continue;
|
|
9505
|
-
const candidate =
|
|
10001
|
+
const candidate = path14.join(sessionsRoot, entry.name, `session_${sessionId}`);
|
|
9506
10002
|
if (existsSync9(candidate)) return candidate;
|
|
9507
10003
|
}
|
|
9508
10004
|
} catch {
|
|
@@ -9511,16 +10007,16 @@ function findKimiSdkSessionDir(sessionId, agentId, homeDir) {
|
|
|
9511
10007
|
}
|
|
9512
10008
|
function findPiSessionFile2(sessionId, workingDirectory, homeDir) {
|
|
9513
10009
|
if (workingDirectory) {
|
|
9514
|
-
const piSessionsDir =
|
|
10010
|
+
const piSessionsDir = path14.join(workingDirectory, ".pi-sessions");
|
|
9515
10011
|
try {
|
|
9516
|
-
const files = readdirSync3(piSessionsDir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => ({ name: e.name, path:
|
|
10012
|
+
const files = readdirSync3(piSessionsDir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => ({ name: e.name, path: path14.join(piSessionsDir, e.name), stat: statSync(path14.join(piSessionsDir, e.name)) })).filter((f) => f.stat.isFile() && f.name.includes(sessionId)).sort((a, b) => b.stat.mtimeMs - a.stat.mtimeMs);
|
|
9517
10013
|
if (files[0]) return files[0].path;
|
|
9518
10014
|
} catch {
|
|
9519
10015
|
}
|
|
9520
10016
|
}
|
|
9521
10017
|
const legacyRoots = [
|
|
9522
|
-
|
|
9523
|
-
|
|
10018
|
+
path14.join(homeDir, ".pi", "agent"),
|
|
10019
|
+
path14.join(homeDir, ".pi")
|
|
9524
10020
|
];
|
|
9525
10021
|
for (const root of legacyRoots) {
|
|
9526
10022
|
const found = findSessionJsonl(root, (filename) => filename.endsWith(".jsonl") && filename.includes(sessionId));
|
|
@@ -9534,9 +10030,9 @@ function safeSessionFilename(value) {
|
|
|
9534
10030
|
}
|
|
9535
10031
|
function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
9536
10032
|
try {
|
|
9537
|
-
const dir =
|
|
10033
|
+
const dir = path14.join(fallbackDir, ".slock", "runtime-sessions");
|
|
9538
10034
|
mkdirSync5(dir, { recursive: true });
|
|
9539
|
-
const filePath =
|
|
10035
|
+
const filePath = path14.join(dir, `${runtime}-${safeSessionFilename(sessionId)}.jsonl`);
|
|
9540
10036
|
writeFileSync4(filePath, JSON.stringify({
|
|
9541
10037
|
type: "runtime_session_handoff",
|
|
9542
10038
|
runtime,
|
|
@@ -9555,27 +10051,40 @@ function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
|
9555
10051
|
return null;
|
|
9556
10052
|
}
|
|
9557
10053
|
}
|
|
9558
|
-
function resolveRuntimeHomeDir(config, defaultHomeDir, workspacePath) {
|
|
10054
|
+
function resolveRuntimeHomeDir(config, defaultHomeDir, workspacePath, opts = {}) {
|
|
9559
10055
|
if (isClaudeCustomProviderConfig(config)) {
|
|
9560
10056
|
return getClaudeProviderStatePaths(workspacePath).home;
|
|
9561
10057
|
}
|
|
10058
|
+
if (config.runtime === "codex") {
|
|
10059
|
+
return resolveCodexHomeRootFromConfig(config, defaultHomeDir, workspacePath, process.env, opts);
|
|
10060
|
+
}
|
|
9562
10061
|
return defaultHomeDir;
|
|
9563
10062
|
}
|
|
9564
|
-
function ensureRuntimeHomeDir(config, defaultHomeDir, workspacePath) {
|
|
10063
|
+
function ensureRuntimeHomeDir(config, defaultHomeDir, workspacePath, opts = {}) {
|
|
9565
10064
|
if (isClaudeCustomProviderConfig(config)) {
|
|
9566
10065
|
return ensureClaudeProviderStatePaths(workspacePath).home;
|
|
9567
10066
|
}
|
|
10067
|
+
if (config.runtime === "codex") {
|
|
10068
|
+
const home = resolveCodexHomeRootFromConfig(config, defaultHomeDir, workspacePath, process.env, opts);
|
|
10069
|
+
if (opts.agentId) {
|
|
10070
|
+
mkdirSync5(home, { recursive: true });
|
|
10071
|
+
}
|
|
10072
|
+
return home;
|
|
10073
|
+
}
|
|
9568
10074
|
return defaultHomeDir;
|
|
9569
10075
|
}
|
|
9570
|
-
function resolveRuntimeSessionRef(runtime, sessionId, homeDir =
|
|
10076
|
+
function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os7.homedir(), fallbackDir, opts) {
|
|
9571
10077
|
let resolvedPath = null;
|
|
9572
10078
|
let lookupMethod = "none";
|
|
9573
10079
|
if (runtime === "claude") {
|
|
9574
10080
|
lookupMethod = "claude_jsonl";
|
|
9575
|
-
resolvedPath = findSessionJsonl(
|
|
10081
|
+
resolvedPath = findSessionJsonl(path14.join(homeDir, ".claude", "projects"), (filename) => filename === `${sessionId}.jsonl`);
|
|
9576
10082
|
} else if (runtime === "codex") {
|
|
9577
10083
|
lookupMethod = "codex_jsonl";
|
|
9578
|
-
|
|
10084
|
+
for (const root of codexSessionRootCandidates(homeDir)) {
|
|
10085
|
+
resolvedPath = findSessionJsonl(root, (filename) => filename.endsWith(".jsonl") && filename.includes(sessionId));
|
|
10086
|
+
if (resolvedPath) break;
|
|
10087
|
+
}
|
|
9579
10088
|
} else if (runtime === "kimi-sdk" || runtime === "kimi") {
|
|
9580
10089
|
lookupMethod = "kimi_sdk_index";
|
|
9581
10090
|
resolvedPath = findKimiSdkSessionDir(sessionId, opts?.agentId, homeDir);
|
|
@@ -10312,6 +10821,28 @@ function runtimeDiagnosticTraceAttrs(event) {
|
|
|
10312
10821
|
session_id_present: Boolean(event.sessionId)
|
|
10313
10822
|
};
|
|
10314
10823
|
}
|
|
10824
|
+
function runtimeRecoveryTrajectoryEntry(event) {
|
|
10825
|
+
const lines = [event.message];
|
|
10826
|
+
if (event.details && event.details !== event.message) {
|
|
10827
|
+
lines.push(event.details);
|
|
10828
|
+
}
|
|
10829
|
+
return {
|
|
10830
|
+
kind: "system",
|
|
10831
|
+
title: "Codex resume recovery",
|
|
10832
|
+
text: lines.join("\n")
|
|
10833
|
+
};
|
|
10834
|
+
}
|
|
10835
|
+
function runtimeRecoveryTraceAttrs(event) {
|
|
10836
|
+
return {
|
|
10837
|
+
kind: event.kind,
|
|
10838
|
+
source: event.source,
|
|
10839
|
+
resume_error_class: event.resumeErrorClass,
|
|
10840
|
+
recovery_action: event.recoveryAction,
|
|
10841
|
+
requested_session_id_present: Boolean(event.requestedSessionId),
|
|
10842
|
+
message_present: Boolean(event.message),
|
|
10843
|
+
details_present: Boolean(event.details)
|
|
10844
|
+
};
|
|
10845
|
+
}
|
|
10315
10846
|
function currentErrorCandidates(ap) {
|
|
10316
10847
|
return [
|
|
10317
10848
|
ap.runtimeErrorSinceProgress ? ap.lastRuntimeError : null,
|
|
@@ -10635,6 +11166,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
10635
11166
|
sendToServer;
|
|
10636
11167
|
daemonApiKey;
|
|
10637
11168
|
serverUrl;
|
|
11169
|
+
slockHome;
|
|
10638
11170
|
dataDir;
|
|
10639
11171
|
runtimeSessionHomeDir;
|
|
10640
11172
|
driverResolver;
|
|
@@ -10664,8 +11196,9 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
10664
11196
|
this.sendToServer = sendToServer;
|
|
10665
11197
|
this.daemonApiKey = daemonApiKey;
|
|
10666
11198
|
this.serverUrl = opts.serverUrl;
|
|
10667
|
-
this.
|
|
10668
|
-
this.
|
|
11199
|
+
this.slockHome = opts.slockHome ? path14.resolve(opts.slockHome) : resolveSlockHome();
|
|
11200
|
+
this.dataDir = opts.dataDir || resolveSlockHomePath("agents", this.slockHome);
|
|
11201
|
+
this.runtimeSessionHomeDir = opts.runtimeSessionHomeDir || os7.homedir();
|
|
10669
11202
|
this.driverResolver = opts.driverResolver || getDriver;
|
|
10670
11203
|
this.defaultAgentEnvVarsProvider = opts.defaultAgentEnvVarsProvider || null;
|
|
10671
11204
|
this.tracer = opts.tracer ?? noopTracer;
|
|
@@ -10794,6 +11327,70 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
10794
11327
|
this.sendStdinNotification(agentId);
|
|
10795
11328
|
}, delayMs);
|
|
10796
11329
|
}
|
|
11330
|
+
flushAsyncRejectedIdleDelivery(agentId) {
|
|
11331
|
+
const ap = this.agents.get(agentId);
|
|
11332
|
+
if (!ap) return false;
|
|
11333
|
+
const count = ap.notifications.takePendingAndClearTimer();
|
|
11334
|
+
if (count === 0) return false;
|
|
11335
|
+
if (!ap.driver.supportsStdinNotification || !ap.sessionId || ap.inbox.length === 0) {
|
|
11336
|
+
ap.notifications.add(count);
|
|
11337
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery.async_rejected.retry", {
|
|
11338
|
+
agentId,
|
|
11339
|
+
runtime: ap.config.runtime,
|
|
11340
|
+
model: ap.config.model,
|
|
11341
|
+
launchId: ap.launchId || void 0,
|
|
11342
|
+
mode: "idle",
|
|
11343
|
+
outcome: "queued_without_stdin",
|
|
11344
|
+
inbox_count: ap.inbox.length,
|
|
11345
|
+
pending_notification_count: ap.notifications.pendingCount,
|
|
11346
|
+
session_id_present: Boolean(ap.sessionId),
|
|
11347
|
+
supports_stdin_notification: ap.driver.supportsStdinNotification
|
|
11348
|
+
});
|
|
11349
|
+
return false;
|
|
11350
|
+
}
|
|
11351
|
+
if (!this.isApmIdle(ap)) {
|
|
11352
|
+
ap.notifications.add(count);
|
|
11353
|
+
return this.sendStdinNotification(agentId, { forceUnsupportedRetry: true });
|
|
11354
|
+
}
|
|
11355
|
+
ap.notifications.pruneContributedToPending(ap.inbox, ap.sessionId);
|
|
11356
|
+
const messages = ap.notifications.filterUncontributedMessages(ap.inbox, ap.sessionId);
|
|
11357
|
+
if (messages.length === 0) {
|
|
11358
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery.async_rejected.retry", {
|
|
11359
|
+
agentId,
|
|
11360
|
+
runtime: ap.config.runtime,
|
|
11361
|
+
model: ap.config.model,
|
|
11362
|
+
launchId: ap.launchId || void 0,
|
|
11363
|
+
mode: "idle",
|
|
11364
|
+
outcome: "suppressed_already_contributed",
|
|
11365
|
+
inbox_count: ap.inbox.length,
|
|
11366
|
+
pending_notification_count: count,
|
|
11367
|
+
session_id_present: true
|
|
11368
|
+
});
|
|
11369
|
+
return false;
|
|
11370
|
+
}
|
|
11371
|
+
this.commitApmIdleState(agentId, ap, false);
|
|
11372
|
+
this.startRuntimeTrace(agentId, ap, "async-rejected-idle-delivery-retry", messages);
|
|
11373
|
+
this.broadcastActivity(agentId, "working", "Message received");
|
|
11374
|
+
const accepted = this.deliverInboxUpdateViaStdin(
|
|
11375
|
+
agentId,
|
|
11376
|
+
ap,
|
|
11377
|
+
messages,
|
|
11378
|
+
"idle",
|
|
11379
|
+
"async_rejected_idle_delivery_retry"
|
|
11380
|
+
);
|
|
11381
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery.async_rejected.retry", {
|
|
11382
|
+
agentId,
|
|
11383
|
+
runtime: ap.config.runtime,
|
|
11384
|
+
model: ap.config.model,
|
|
11385
|
+
launchId: ap.launchId || void 0,
|
|
11386
|
+
mode: "idle",
|
|
11387
|
+
outcome: accepted ? "written" : "not_written",
|
|
11388
|
+
inbox_count: ap.inbox.length,
|
|
11389
|
+
messages_count: messages.length,
|
|
11390
|
+
session_id_present: true
|
|
11391
|
+
});
|
|
11392
|
+
return accepted;
|
|
11393
|
+
}
|
|
10797
11394
|
isApmIdle(ap) {
|
|
10798
11395
|
return ap.gatedSteering.isIdle;
|
|
10799
11396
|
}
|
|
@@ -11252,6 +11849,23 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
11252
11849
|
...runtimeDiagnosticTraceAttrs(event)
|
|
11253
11850
|
});
|
|
11254
11851
|
}
|
|
11852
|
+
recordRuntimeRecoveryActivity(agentId, ap, event) {
|
|
11853
|
+
this.sendToServer({
|
|
11854
|
+
type: "agent:activity",
|
|
11855
|
+
agentId,
|
|
11856
|
+
activity: ap.lastActivity || "online",
|
|
11857
|
+
detail: ap.lastActivityDetail || "",
|
|
11858
|
+
entries: [runtimeRecoveryTrajectoryEntry(event)],
|
|
11859
|
+
launchId: ap.launchId || void 0,
|
|
11860
|
+
clientSeq: this.nextActivityClientSeq(agentId)
|
|
11861
|
+
});
|
|
11862
|
+
this.recordDaemonTrace("daemon.runtime.recovery.visible", {
|
|
11863
|
+
agentId,
|
|
11864
|
+
launchId: ap.launchId || void 0,
|
|
11865
|
+
runtime: ap.config.runtime,
|
|
11866
|
+
...runtimeRecoveryTraceAttrs(event)
|
|
11867
|
+
});
|
|
11868
|
+
}
|
|
11255
11869
|
recordDaemonTrace(name, attrs, status = "ok", parentTraceparent) {
|
|
11256
11870
|
const span = this.tracer.startSpan(name, {
|
|
11257
11871
|
parent: parseTraceparent(parentTraceparent),
|
|
@@ -11589,26 +12203,26 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
11589
12203
|
let pendingStartRebind;
|
|
11590
12204
|
const originalLaunchId = launchId || null;
|
|
11591
12205
|
try {
|
|
11592
|
-
const agentDataDir =
|
|
12206
|
+
const agentDataDir = path14.join(this.dataDir, agentId);
|
|
11593
12207
|
await mkdir(agentDataDir, { recursive: true });
|
|
11594
12208
|
const initialRuntimeConfig = withLocalRuntimeContext(config, agentId, agentDataDir);
|
|
11595
|
-
const memoryMdPath =
|
|
12209
|
+
const memoryMdPath = path14.join(agentDataDir, "MEMORY.md");
|
|
11596
12210
|
try {
|
|
11597
12211
|
await access(memoryMdPath);
|
|
11598
12212
|
} catch {
|
|
11599
12213
|
const initialMemoryMd = buildInitialMemoryMd(initialRuntimeConfig);
|
|
11600
12214
|
await writeFile(memoryMdPath, initialMemoryMd);
|
|
11601
12215
|
}
|
|
11602
|
-
const notesDir =
|
|
12216
|
+
const notesDir = path14.join(agentDataDir, "notes");
|
|
11603
12217
|
await mkdir(notesDir, { recursive: true });
|
|
11604
12218
|
if (getOnboardingSeedMode(config) === FIRST_CINDY_SEED_MODE) {
|
|
11605
12219
|
const seedFiles = buildOnboardingSeedFiles();
|
|
11606
12220
|
for (const { relativePath, content } of seedFiles) {
|
|
11607
|
-
const fullPath =
|
|
12221
|
+
const fullPath = path14.join(agentDataDir, relativePath);
|
|
11608
12222
|
try {
|
|
11609
12223
|
await access(fullPath);
|
|
11610
12224
|
} catch {
|
|
11611
|
-
await mkdir(
|
|
12225
|
+
await mkdir(path14.dirname(fullPath), { recursive: true });
|
|
11612
12226
|
await writeFile(fullPath, content);
|
|
11613
12227
|
}
|
|
11614
12228
|
}
|
|
@@ -11762,6 +12376,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11762
12376
|
workingDirectory: agentDataDir,
|
|
11763
12377
|
slockCliPath: this.slockCliPath,
|
|
11764
12378
|
daemonApiKey: this.daemonApiKey,
|
|
12379
|
+
slockHome: this.slockHome,
|
|
11765
12380
|
launchId: effectiveLaunchId,
|
|
11766
12381
|
agentCredentialProxyInboxCoordinator: this.createAgentProxyInboxCoordinator(agentId),
|
|
11767
12382
|
cliTransportTraceDir: this.cliTransportTraceDir,
|
|
@@ -12921,7 +13536,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
12921
13536
|
return true;
|
|
12922
13537
|
}
|
|
12923
13538
|
async resetWorkspace(agentId) {
|
|
12924
|
-
const agentDataDir =
|
|
13539
|
+
const agentDataDir = path14.join(this.dataDir, agentId);
|
|
12925
13540
|
try {
|
|
12926
13541
|
await rm2(agentDataDir, { recursive: true, force: true });
|
|
12927
13542
|
logger.info(`[Agent ${agentId}] Workspace reset complete (${agentDataDir})`);
|
|
@@ -12981,9 +13596,9 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
12981
13596
|
}
|
|
12982
13597
|
return result;
|
|
12983
13598
|
}
|
|
12984
|
-
buildRuntimeProfileReport(agentId, config, sessionId, launchId) {
|
|
12985
|
-
const workspacePath =
|
|
12986
|
-
const runtimeHomeDir = resolveRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspacePath);
|
|
13599
|
+
buildRuntimeProfileReport(agentId, config, sessionId, launchId, observedRuntimeHomeDir) {
|
|
13600
|
+
const workspacePath = path14.join(this.dataDir, agentId);
|
|
13601
|
+
const runtimeHomeDir = observedRuntimeHomeDir || resolveRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspacePath, { agentId, slockHome: this.slockHome });
|
|
12987
13602
|
return {
|
|
12988
13603
|
agentId,
|
|
12989
13604
|
launchId,
|
|
@@ -13004,7 +13619,13 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13004
13619
|
getAgentRuntimeProfileReport(agentId) {
|
|
13005
13620
|
const running = this.agents.get(agentId);
|
|
13006
13621
|
if (running) {
|
|
13007
|
-
return this.buildRuntimeProfileReport(
|
|
13622
|
+
return this.buildRuntimeProfileReport(
|
|
13623
|
+
agentId,
|
|
13624
|
+
running.config,
|
|
13625
|
+
running.sessionId,
|
|
13626
|
+
running.launchId,
|
|
13627
|
+
running.runtime.currentRuntimeHomeDir
|
|
13628
|
+
);
|
|
13008
13629
|
}
|
|
13009
13630
|
const idle = this.idleAgentConfigs.get(agentId);
|
|
13010
13631
|
if (idle) {
|
|
@@ -13277,7 +13898,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13277
13898
|
}
|
|
13278
13899
|
// Workspace file browsing
|
|
13279
13900
|
async getFileTree(agentId, dirPath) {
|
|
13280
|
-
const agentDir =
|
|
13901
|
+
const agentDir = path14.join(this.dataDir, agentId);
|
|
13281
13902
|
try {
|
|
13282
13903
|
await stat2(agentDir);
|
|
13283
13904
|
} catch {
|
|
@@ -13285,8 +13906,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13285
13906
|
}
|
|
13286
13907
|
let targetDir = agentDir;
|
|
13287
13908
|
if (dirPath) {
|
|
13288
|
-
const resolved =
|
|
13289
|
-
if (!resolved.startsWith(agentDir +
|
|
13909
|
+
const resolved = path14.resolve(agentDir, dirPath);
|
|
13910
|
+
if (!resolved.startsWith(agentDir + path14.sep) && resolved !== agentDir) {
|
|
13290
13911
|
return [];
|
|
13291
13912
|
}
|
|
13292
13913
|
targetDir = resolved;
|
|
@@ -13294,14 +13915,14 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13294
13915
|
return this.listDirectoryChildren(targetDir, agentDir);
|
|
13295
13916
|
}
|
|
13296
13917
|
async readFile(agentId, filePath) {
|
|
13297
|
-
const agentDir =
|
|
13298
|
-
const resolved =
|
|
13299
|
-
if (!resolved.startsWith(agentDir +
|
|
13918
|
+
const agentDir = path14.join(this.dataDir, agentId);
|
|
13919
|
+
const resolved = path14.resolve(agentDir, filePath);
|
|
13920
|
+
if (!resolved.startsWith(agentDir + path14.sep) && resolved !== agentDir) {
|
|
13300
13921
|
throw new Error("Access denied");
|
|
13301
13922
|
}
|
|
13302
13923
|
const info = await stat2(resolved);
|
|
13303
13924
|
if (info.isDirectory()) throw new Error("Cannot read a directory");
|
|
13304
|
-
const ext =
|
|
13925
|
+
const ext = path14.extname(resolved).toLowerCase();
|
|
13305
13926
|
if (WORKSPACE_TEXT_EXTENSIONS.has(ext) || ext === "") {
|
|
13306
13927
|
if (info.size > WORKSPACE_TEXT_FILE_MAX_BYTES) throw new Error("File too large");
|
|
13307
13928
|
const content = await readFile(resolved, "utf-8");
|
|
@@ -13352,8 +13973,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13352
13973
|
};
|
|
13353
13974
|
}
|
|
13354
13975
|
const runtime = config.runtime;
|
|
13355
|
-
const workspaceDir =
|
|
13356
|
-
const homeDir = ensureRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspaceDir);
|
|
13976
|
+
const workspaceDir = path14.join(this.dataDir, agentId);
|
|
13977
|
+
const homeDir = agent?.runtime.currentRuntimeHomeDir || ensureRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspaceDir, { agentId, slockHome: this.slockHome });
|
|
13357
13978
|
if (!actualSessionId) {
|
|
13358
13979
|
return {
|
|
13359
13980
|
runtime,
|
|
@@ -13391,7 +14012,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13391
14012
|
let redacted = false;
|
|
13392
14013
|
if (ref.reachable && ref.path) {
|
|
13393
14014
|
try {
|
|
13394
|
-
const resolved =
|
|
14015
|
+
const resolved = path14.resolve(ref.path);
|
|
13395
14016
|
const allowedRoots = allowedTranscriptRootsForRuntime(runtime, homeDir, workspaceDir);
|
|
13396
14017
|
if (!await isPathWithinAllowedRoots(resolved, allowedRoots)) {
|
|
13397
14018
|
throw new Error("resolved session path is outside allowed runtime directories");
|
|
@@ -13402,7 +14023,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13402
14023
|
throw new Error("symbolic links are not allowed");
|
|
13403
14024
|
}
|
|
13404
14025
|
if (info.isDirectory()) {
|
|
13405
|
-
targetPath =
|
|
14026
|
+
targetPath = path14.join(resolved, "state.json");
|
|
13406
14027
|
}
|
|
13407
14028
|
if (!await isPathWithinAllowedRoots(targetPath, allowedRoots)) {
|
|
13408
14029
|
throw new Error("resolved session state path is outside allowed runtime directories");
|
|
@@ -13514,14 +14135,22 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13514
14135
|
const idle = this.idleAgentConfigs.get(agentId);
|
|
13515
14136
|
const config = agent?.config ?? idle?.config ?? null;
|
|
13516
14137
|
const runtime = runtimeHint || config?.runtime || "claude";
|
|
13517
|
-
const workspaceDir =
|
|
13518
|
-
const
|
|
14138
|
+
const workspaceDir = path14.join(this.dataDir, agentId);
|
|
14139
|
+
const hostHome = os7.homedir();
|
|
14140
|
+
const home = agent?.runtime.currentRuntimeHomeDir || (config ? ensureRuntimeHomeDir(config, hostHome, workspaceDir, { agentId, slockHome: this.slockHome }) : runtime === "codex" ? resolveCodexHomeRootFromEnv(process.env, { defaultHomeDir: hostHome, cwd: workspaceDir }) : hostHome);
|
|
13519
14141
|
const paths = _AgentProcessManager.SKILL_PATHS[runtime] || _AgentProcessManager.SKILL_PATHS.claude;
|
|
14142
|
+
const globalDirs = runtime === "codex" ? [
|
|
14143
|
+
path14.join(home, "skills"),
|
|
14144
|
+
path14.join(home, "skills", ".system"),
|
|
14145
|
+
path14.join(home, ".agents", "skills"),
|
|
14146
|
+
...hasConfiguredCodexHome(config) ? [] : [path14.join(hostHome, ".agents", "skills")]
|
|
14147
|
+
] : paths.global.map((p) => path14.join(home, p));
|
|
14148
|
+
const workspaceDirs = paths.workspace.map((p) => path14.join(workspaceDir, p));
|
|
13520
14149
|
const globalResults = await Promise.all(
|
|
13521
|
-
|
|
14150
|
+
globalDirs.map((dir) => this.scanSkillsDir(dir))
|
|
13522
14151
|
);
|
|
13523
14152
|
const workspaceResults = await Promise.all(
|
|
13524
|
-
|
|
14153
|
+
workspaceDirs.map((dir) => this.scanSkillsDir(dir))
|
|
13525
14154
|
);
|
|
13526
14155
|
const dedup = (skills) => {
|
|
13527
14156
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -13550,7 +14179,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13550
14179
|
const skills = [];
|
|
13551
14180
|
for (const entry of entries) {
|
|
13552
14181
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
13553
|
-
const skillMd =
|
|
14182
|
+
const skillMd = path14.join(dir, entry.name, "SKILL.md");
|
|
13554
14183
|
try {
|
|
13555
14184
|
const content = await readFile(skillMd, "utf-8");
|
|
13556
14185
|
const skill = this.parseSkillMd(entry.name, content);
|
|
@@ -13561,7 +14190,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13561
14190
|
} else if (entry.name.endsWith(".md")) {
|
|
13562
14191
|
const cmdName = entry.name.replace(/\.md$/, "");
|
|
13563
14192
|
try {
|
|
13564
|
-
const content = await readFile(
|
|
14193
|
+
const content = await readFile(path14.join(dir, entry.name), "utf-8");
|
|
13565
14194
|
const skill = this.parseSkillMd(cmdName, content);
|
|
13566
14195
|
skill.sourcePath = dir;
|
|
13567
14196
|
skills.push(skill);
|
|
@@ -13982,6 +14611,43 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13982
14611
|
recordRuntimeTraceEvent(agentId, ap, name, attrs) {
|
|
13983
14612
|
this.startRuntimeTrace(agentId, ap, "runtime-progress").addEvent(name, attrs);
|
|
13984
14613
|
}
|
|
14614
|
+
restoreRuntimeDeliveryAfterAsyncRejection(agentId, ap, event) {
|
|
14615
|
+
const pendingBefore = ap.notifications.pendingCount;
|
|
14616
|
+
const restoredMessages = ap.inbox.filter(
|
|
14617
|
+
(message) => ap.notifications.hasContributedMessage(message, ap.sessionId)
|
|
14618
|
+
);
|
|
14619
|
+
ap.notifications.clearNoticeFingerprint();
|
|
14620
|
+
const restoredNotificationCount = ap.driver.supportsStdinNotification && ap.sessionId && restoredMessages.length > 0 ? ap.notifications.add(restoredMessages.length) : 0;
|
|
14621
|
+
if (event.requestMethod === "turn/start") {
|
|
14622
|
+
this.commitApmIdleState(agentId, ap, true);
|
|
14623
|
+
}
|
|
14624
|
+
const idleRetryScheduled = event.requestMethod === "turn/start" && restoredNotificationCount > 0 ? ap.notifications.schedule(() => {
|
|
14625
|
+
this.flushAsyncRejectedIdleDelivery(agentId);
|
|
14626
|
+
}, this.stdinNotificationRetryMs) : false;
|
|
14627
|
+
const attrs = {
|
|
14628
|
+
request_method: event.requestMethod,
|
|
14629
|
+
source: event.source,
|
|
14630
|
+
payloadBytes: event.payloadBytes,
|
|
14631
|
+
inbox_count: ap.inbox.length,
|
|
14632
|
+
restored_messages_count: restoredMessages.length,
|
|
14633
|
+
pending_notification_count_before: pendingBefore,
|
|
14634
|
+
pending_notification_count_after: ap.notifications.pendingCount,
|
|
14635
|
+
restored_notification_count: restoredNotificationCount,
|
|
14636
|
+
session_id_present: Boolean(ap.sessionId),
|
|
14637
|
+
supports_stdin_notification: ap.driver.supportsStdinNotification,
|
|
14638
|
+
busy_delivery_mode: ap.driver.busyDeliveryMode,
|
|
14639
|
+
restored_idle_state: event.requestMethod === "turn/start",
|
|
14640
|
+
idle_retry_scheduled: idleRetryScheduled
|
|
14641
|
+
};
|
|
14642
|
+
this.recordRuntimeTraceEvent(agentId, ap, "runtime.delivery.async_rejected", attrs);
|
|
14643
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery.async_rejected", {
|
|
14644
|
+
agentId,
|
|
14645
|
+
launchId: ap.launchId || void 0,
|
|
14646
|
+
runtime: ap.config.runtime,
|
|
14647
|
+
model: ap.config.model,
|
|
14648
|
+
...attrs
|
|
14649
|
+
}, "error");
|
|
14650
|
+
}
|
|
13985
14651
|
noteRuntimeProgress(ap, eventKind) {
|
|
13986
14652
|
ap.runtimeProgress.noteRuntimeEvent(eventKind);
|
|
13987
14653
|
this.invalidateRecoveryErrorView(ap);
|
|
@@ -14170,7 +14836,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
14170
14836
|
if ((ap.driver.startupReadiness ?? "first_event") !== "initial_turn") {
|
|
14171
14837
|
return true;
|
|
14172
14838
|
}
|
|
14173
|
-
return event.kind !== "session_init" && event.kind !== "internal_progress" && event.kind !== "runtime_diagnostic";
|
|
14839
|
+
return event.kind !== "session_init" && event.kind !== "internal_progress" && event.kind !== "runtime_diagnostic" && event.kind !== "runtime_recovery";
|
|
14174
14840
|
}
|
|
14175
14841
|
handleRuntimeStartupTimeout(agentId, ap, timeoutMs) {
|
|
14176
14842
|
const current = this.agents.get(agentId);
|
|
@@ -14366,6 +15032,21 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
14366
15032
|
if (ap) this.recordRuntimeTelemetry(agentId, ap, event);
|
|
14367
15033
|
return;
|
|
14368
15034
|
}
|
|
15035
|
+
if (event.kind === "delivery_error") {
|
|
15036
|
+
if (ap) {
|
|
15037
|
+
this.restoreRuntimeDeliveryAfterAsyncRejection(agentId, ap, event);
|
|
15038
|
+
} else {
|
|
15039
|
+
this.recordDaemonTrace("daemon.agent.delivery_error.received_without_process", {
|
|
15040
|
+
agentId,
|
|
15041
|
+
event_kind: event.kind,
|
|
15042
|
+
runtime: driver.id,
|
|
15043
|
+
request_method: event.requestMethod,
|
|
15044
|
+
source: event.source,
|
|
15045
|
+
payloadBytes: event.payloadBytes
|
|
15046
|
+
});
|
|
15047
|
+
}
|
|
15048
|
+
return;
|
|
15049
|
+
}
|
|
14369
15050
|
if (ap && isStartupRequestErrorEvent(event)) {
|
|
14370
15051
|
this.handleRuntimeStartupRequestError(agentId, ap, event);
|
|
14371
15052
|
return;
|
|
@@ -14382,13 +15063,15 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
14382
15063
|
source: event.source,
|
|
14383
15064
|
itemType: event.itemType,
|
|
14384
15065
|
payloadBytes: event.payloadBytes
|
|
14385
|
-
} : event.kind === "runtime_diagnostic" ? runtimeDiagnosticTraceAttrs(event) : { kind: event.kind };
|
|
15066
|
+
} : event.kind === "runtime_diagnostic" ? runtimeDiagnosticTraceAttrs(event) : event.kind === "runtime_recovery" ? runtimeRecoveryTraceAttrs(event) : { kind: event.kind };
|
|
14386
15067
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.event.received", eventAttrs);
|
|
14387
|
-
|
|
15068
|
+
const recordProgressObservedAfterStall = () => {
|
|
15069
|
+
if (!wasStalled) return;
|
|
14388
15070
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.progress.observed", { afterStall: true });
|
|
14389
|
-
}
|
|
15071
|
+
};
|
|
14390
15072
|
if (event.kind === "internal_progress") {
|
|
14391
15073
|
ap.runtimeProgress.noteInternalProgress();
|
|
15074
|
+
recordProgressObservedAfterStall();
|
|
14392
15075
|
this.invalidateRecoveryErrorView(ap);
|
|
14393
15076
|
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
14394
15077
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.progress.internal_observed", {
|
|
@@ -14405,11 +15088,17 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
14405
15088
|
}
|
|
14406
15089
|
if (event.kind === "runtime_diagnostic") {
|
|
14407
15090
|
this.noteRuntimeProgress(ap, event.kind);
|
|
15091
|
+
recordProgressObservedAfterStall();
|
|
14408
15092
|
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
14409
15093
|
this.recordRuntimeDiagnosticActivity(agentId, ap, event);
|
|
14410
15094
|
return;
|
|
14411
15095
|
}
|
|
15096
|
+
if (event.kind === "runtime_recovery") {
|
|
15097
|
+
this.recordRuntimeRecoveryActivity(agentId, ap, event);
|
|
15098
|
+
return;
|
|
15099
|
+
}
|
|
14412
15100
|
this.noteRuntimeProgress(ap, event.kind);
|
|
15101
|
+
recordProgressObservedAfterStall();
|
|
14413
15102
|
} else if (event.kind !== "internal_progress") {
|
|
14414
15103
|
this.recordDaemonTrace("daemon.agent.event.received_without_process", {
|
|
14415
15104
|
agentId,
|
|
@@ -15166,8 +15855,8 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
15166
15855
|
const nodes = [];
|
|
15167
15856
|
for (const entry of entries) {
|
|
15168
15857
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
15169
|
-
const fullPath =
|
|
15170
|
-
const relativePath =
|
|
15858
|
+
const fullPath = path14.join(dir, entry.name);
|
|
15859
|
+
const relativePath = path14.relative(rootDir, fullPath);
|
|
15171
15860
|
let info;
|
|
15172
15861
|
try {
|
|
15173
15862
|
info = await stat2(fullPath);
|
|
@@ -15542,8 +16231,8 @@ var ReminderCache = class {
|
|
|
15542
16231
|
// src/machineLock.ts
|
|
15543
16232
|
import { createHash as createHash4, randomUUID as randomUUID6 } from "crypto";
|
|
15544
16233
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync7, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
15545
|
-
import
|
|
15546
|
-
import
|
|
16234
|
+
import os8 from "os";
|
|
16235
|
+
import path15 from "path";
|
|
15547
16236
|
var INCOMPLETE_LOCK_STALE_MS = 3e4;
|
|
15548
16237
|
var DaemonMachineLockConflictError = class extends Error {
|
|
15549
16238
|
code = "DAEMON_MACHINE_LOCK_HELD";
|
|
@@ -15565,7 +16254,7 @@ function resolveDefaultMachineStateRoot() {
|
|
|
15565
16254
|
return resolveSlockHomePath("machines");
|
|
15566
16255
|
}
|
|
15567
16256
|
function ownerPath(lockDir) {
|
|
15568
|
-
return
|
|
16257
|
+
return path15.join(lockDir, "owner.json");
|
|
15569
16258
|
}
|
|
15570
16259
|
function readOwner(lockDir) {
|
|
15571
16260
|
try {
|
|
@@ -15595,8 +16284,8 @@ function acquireDaemonMachineLock(options) {
|
|
|
15595
16284
|
const rootDir = options.rootDir ?? resolveDefaultMachineStateRoot();
|
|
15596
16285
|
const fingerprint = apiKeyFingerprint(options.apiKey);
|
|
15597
16286
|
const lockId = getDaemonMachineLockId(options.apiKey);
|
|
15598
|
-
const machineDir =
|
|
15599
|
-
const lockDir =
|
|
16287
|
+
const machineDir = path15.join(rootDir, lockId);
|
|
16288
|
+
const lockDir = path15.join(machineDir, "daemon.lock");
|
|
15600
16289
|
const token = randomUUID6();
|
|
15601
16290
|
mkdirSync6(machineDir, { recursive: true });
|
|
15602
16291
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
@@ -15605,7 +16294,7 @@ function acquireDaemonMachineLock(options) {
|
|
|
15605
16294
|
const owner = {
|
|
15606
16295
|
pid: process.pid,
|
|
15607
16296
|
token,
|
|
15608
|
-
hostname:
|
|
16297
|
+
hostname: os8.hostname(),
|
|
15609
16298
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15610
16299
|
serverUrl: options.serverUrl,
|
|
15611
16300
|
apiKeyFingerprint: fingerprint.slice(0, 16)
|
|
@@ -15657,7 +16346,7 @@ function acquireDaemonMachineLock(options) {
|
|
|
15657
16346
|
|
|
15658
16347
|
// src/localTraceSink.ts
|
|
15659
16348
|
import { appendFileSync, mkdirSync as mkdirSync7, readdirSync as readdirSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
15660
|
-
import
|
|
16349
|
+
import path16 from "path";
|
|
15661
16350
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
15662
16351
|
var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
|
|
15663
16352
|
var DEFAULT_MAX_FILES = 8;
|
|
@@ -15694,7 +16383,7 @@ var LocalRotatingTraceSink = class {
|
|
|
15694
16383
|
currentSize = 0;
|
|
15695
16384
|
sequence = 0;
|
|
15696
16385
|
constructor(options) {
|
|
15697
|
-
this.traceDir =
|
|
16386
|
+
this.traceDir = path16.join(options.machineDir, "traces");
|
|
15698
16387
|
this.maxFileBytes = Math.max(1024, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES));
|
|
15699
16388
|
const baseAgeMs = Math.max(1e3, Math.floor(options.maxFileAgeMs ?? DEFAULT_MAX_FILE_AGE_MS));
|
|
15700
16389
|
const ageJitterMs = Math.max(0, Math.floor(options.maxFileAgeJitterMs ?? 0));
|
|
@@ -15724,7 +16413,7 @@ var LocalRotatingTraceSink = class {
|
|
|
15724
16413
|
const nowMs = this.nowMsProvider();
|
|
15725
16414
|
const shouldRotateForAge = this.currentFileOpenedAtMs !== null && nowMs - this.currentFileOpenedAtMs >= this.maxFileAgeMs;
|
|
15726
16415
|
if (!this.currentFile || this.currentSize + nextBytes > this.maxFileBytes || shouldRotateForAge) {
|
|
15727
|
-
this.currentFile =
|
|
16416
|
+
this.currentFile = path16.join(
|
|
15728
16417
|
this.traceDir,
|
|
15729
16418
|
`daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
|
|
15730
16419
|
);
|
|
@@ -15739,7 +16428,7 @@ var LocalRotatingTraceSink = class {
|
|
|
15739
16428
|
const excess = files.length - this.maxFiles;
|
|
15740
16429
|
if (excess <= 0) return;
|
|
15741
16430
|
for (const file of files.slice(0, excess)) {
|
|
15742
|
-
rmSync4(
|
|
16431
|
+
rmSync4(path16.join(this.traceDir, file), { force: true });
|
|
15743
16432
|
}
|
|
15744
16433
|
}
|
|
15745
16434
|
};
|
|
@@ -15830,7 +16519,7 @@ function isDiagnosticErrorAttr(key) {
|
|
|
15830
16519
|
import { createHash as createHash6, randomUUID as randomUUID7 } from "crypto";
|
|
15831
16520
|
import { gzipSync as gzipSync2 } from "zlib";
|
|
15832
16521
|
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
15833
|
-
import
|
|
16522
|
+
import path17 from "path";
|
|
15834
16523
|
|
|
15835
16524
|
// src/traceJitter.ts
|
|
15836
16525
|
import { createHash as createHash5 } from "crypto";
|
|
@@ -15929,7 +16618,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
15929
16618
|
}, nextMs);
|
|
15930
16619
|
}
|
|
15931
16620
|
async findUploadCandidates() {
|
|
15932
|
-
const traceDir =
|
|
16621
|
+
const traceDir = path17.join(this.options.machineDir, "traces");
|
|
15933
16622
|
let names;
|
|
15934
16623
|
try {
|
|
15935
16624
|
names = await readdir3(traceDir);
|
|
@@ -15941,8 +16630,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
15941
16630
|
const currentFile = this.options.currentFileProvider?.();
|
|
15942
16631
|
const candidates = [];
|
|
15943
16632
|
for (const name of names.filter((entry) => entry.startsWith("daemon-trace-") && entry.endsWith(".jsonl")).sort()) {
|
|
15944
|
-
const file =
|
|
15945
|
-
if (currentFile &&
|
|
16633
|
+
const file = path17.join(traceDir, name);
|
|
16634
|
+
if (currentFile && path17.resolve(file) === path17.resolve(currentFile)) continue;
|
|
15946
16635
|
if (await this.isUploaded(file)) continue;
|
|
15947
16636
|
try {
|
|
15948
16637
|
const info = await stat3(file);
|
|
@@ -16016,8 +16705,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
16016
16705
|
}
|
|
16017
16706
|
}
|
|
16018
16707
|
uploadStatePath(file) {
|
|
16019
|
-
const stateDir =
|
|
16020
|
-
return
|
|
16708
|
+
const stateDir = path17.join(this.options.machineDir, "trace-uploads");
|
|
16709
|
+
return path17.join(stateDir, `${path17.basename(file)}.uploaded.json`);
|
|
16021
16710
|
}
|
|
16022
16711
|
async isUploaded(file) {
|
|
16023
16712
|
try {
|
|
@@ -16029,9 +16718,9 @@ var DaemonTraceBundleUploader = class {
|
|
|
16029
16718
|
}
|
|
16030
16719
|
async markUploaded(file, metadata) {
|
|
16031
16720
|
const stateFile = this.uploadStatePath(file);
|
|
16032
|
-
await mkdir2(
|
|
16721
|
+
await mkdir2(path17.dirname(stateFile), { recursive: true, mode: 448 });
|
|
16033
16722
|
await writeFile2(stateFile, `${JSON.stringify({
|
|
16034
|
-
file:
|
|
16723
|
+
file: path17.basename(file),
|
|
16035
16724
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16036
16725
|
...metadata
|
|
16037
16726
|
}, null, 2)}
|
|
@@ -16180,13 +16869,13 @@ function readDaemonVersion(moduleUrl = import.meta.url) {
|
|
|
16180
16869
|
}
|
|
16181
16870
|
}
|
|
16182
16871
|
function resolveSlockCliPath(moduleUrl = import.meta.url) {
|
|
16183
|
-
const thisDir =
|
|
16184
|
-
const bundledDistPath =
|
|
16872
|
+
const thisDir = path18.dirname(fileURLToPath(moduleUrl));
|
|
16873
|
+
const bundledDistPath = path18.resolve(thisDir, "cli", "index.js");
|
|
16185
16874
|
try {
|
|
16186
16875
|
accessSync(bundledDistPath);
|
|
16187
16876
|
return bundledDistPath;
|
|
16188
16877
|
} catch {
|
|
16189
|
-
const workspaceDistPath =
|
|
16878
|
+
const workspaceDistPath = path18.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
|
|
16190
16879
|
accessSync(workspaceDistPath);
|
|
16191
16880
|
return workspaceDistPath;
|
|
16192
16881
|
}
|
|
@@ -16200,11 +16889,12 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
|
|
|
16200
16889
|
}
|
|
16201
16890
|
async function runBundledSlockCli(argv) {
|
|
16202
16891
|
process.argv = [process.execPath, "slock", ...argv];
|
|
16203
|
-
await import("./dist-
|
|
16892
|
+
await import("./dist-5BEASCX5.js");
|
|
16204
16893
|
}
|
|
16205
16894
|
function detectRuntimes(tracer = noopTracer) {
|
|
16206
16895
|
const ids = [];
|
|
16207
16896
|
const versions = {};
|
|
16897
|
+
const diagnostics = {};
|
|
16208
16898
|
const span = tracer.startSpan("daemon.runtime.detect", {
|
|
16209
16899
|
surface: "daemon",
|
|
16210
16900
|
kind: "internal",
|
|
@@ -16220,20 +16910,26 @@ function detectRuntimes(tracer = noopTracer) {
|
|
|
16220
16910
|
const probe = driver.probe();
|
|
16221
16911
|
if (!probe.available) {
|
|
16222
16912
|
if (probe.version) versions[runtime.id] = probe.version;
|
|
16913
|
+
if (probe.diagnostic) diagnostics[runtime.id] = probe.diagnostic;
|
|
16223
16914
|
span.addEvent("daemon.runtime.detect.checked", {
|
|
16224
16915
|
runtime: runtime.id,
|
|
16225
16916
|
outcome: "unavailable",
|
|
16226
16917
|
version_present: Boolean(probe.version),
|
|
16918
|
+
diagnostic_present: Boolean(probe.diagnostic),
|
|
16919
|
+
...probe.diagnostic ? { diagnostic: probe.diagnostic } : {},
|
|
16227
16920
|
binary_path_present: false
|
|
16228
16921
|
});
|
|
16229
16922
|
continue;
|
|
16230
16923
|
}
|
|
16231
16924
|
ids.push(runtime.id);
|
|
16232
16925
|
if (probe.version) versions[runtime.id] = probe.version;
|
|
16926
|
+
if (probe.diagnostic) diagnostics[runtime.id] = probe.diagnostic;
|
|
16233
16927
|
span.addEvent("daemon.runtime.detect.checked", {
|
|
16234
16928
|
runtime: runtime.id,
|
|
16235
16929
|
outcome: "available",
|
|
16236
16930
|
version_present: Boolean(probe.version),
|
|
16931
|
+
diagnostic_present: Boolean(probe.diagnostic),
|
|
16932
|
+
...probe.diagnostic ? { diagnostic: probe.diagnostic } : {},
|
|
16237
16933
|
binary_path_present: false
|
|
16238
16934
|
});
|
|
16239
16935
|
continue;
|
|
@@ -16276,7 +16972,7 @@ function detectRuntimes(tracer = noopTracer) {
|
|
|
16276
16972
|
detected_runtime_count: ids.length
|
|
16277
16973
|
}
|
|
16278
16974
|
});
|
|
16279
|
-
return { ids, versions };
|
|
16975
|
+
return { ids, versions, ...Object.keys(diagnostics).length > 0 ? { diagnostics } : {} };
|
|
16280
16976
|
}
|
|
16281
16977
|
function readPositiveIntegerEnv3(name, fallback) {
|
|
16282
16978
|
const raw = process.env[name];
|
|
@@ -16398,7 +17094,7 @@ var DaemonCore = class {
|
|
|
16398
17094
|
}
|
|
16399
17095
|
resolveMachineStateRoot() {
|
|
16400
17096
|
if (this.options.machineStateDir) return this.options.machineStateDir;
|
|
16401
|
-
if (this.options.dataDir) return
|
|
17097
|
+
if (this.options.dataDir) return path18.join(path18.dirname(this.options.dataDir), "machines");
|
|
16402
17098
|
return resolveDefaultMachineStateRoot();
|
|
16403
17099
|
}
|
|
16404
17100
|
shouldEnableLocalTrace() {
|
|
@@ -16425,7 +17121,7 @@ var DaemonCore = class {
|
|
|
16425
17121
|
sink: this.localTraceSink
|
|
16426
17122
|
}));
|
|
16427
17123
|
this.agentManager.setTracer(this.tracer);
|
|
16428
|
-
this.agentManager.setCliTransportTraceDir(
|
|
17124
|
+
this.agentManager.setCliTransportTraceDir(path18.join(machineDir, "traces"));
|
|
16429
17125
|
}
|
|
16430
17126
|
installTraceBundleUploader(machineDir) {
|
|
16431
17127
|
if (!this.shouldEnableLocalTrace()) return;
|
|
@@ -16973,9 +17669,12 @@ var DaemonCore = class {
|
|
|
16973
17669
|
});
|
|
16974
17670
|
}
|
|
16975
17671
|
handleConnect() {
|
|
16976
|
-
const { ids: runtimes, versions: runtimeVersions } = this.runtimeDetector();
|
|
17672
|
+
const { ids: runtimes, versions: runtimeVersions, diagnostics: runtimeDiagnostics = {} } = this.runtimeDetector();
|
|
16977
17673
|
const runtimeInfo = runtimes.map((id) => runtimeVersions[id] ? `${id} (${runtimeVersions[id]})` : id);
|
|
16978
17674
|
logger.info(`[Daemon] Detected runtimes: ${runtimeInfo.join(", ") || "none"}`);
|
|
17675
|
+
for (const [runtime, diagnostic] of Object.entries(runtimeDiagnostics)) {
|
|
17676
|
+
logger.warn(`[Daemon] Runtime ${runtime} diagnostic: ${diagnostic}`);
|
|
17677
|
+
}
|
|
16979
17678
|
if (!this.opencliWrappersRegenerated) {
|
|
16980
17679
|
this.opencliWrappersRegenerated = true;
|
|
16981
17680
|
try {
|
|
@@ -16995,8 +17694,8 @@ var DaemonCore = class {
|
|
|
16995
17694
|
capabilities: ["agent:start", "agent:stop", "agent:deliver", "workspace:files"],
|
|
16996
17695
|
runtimes,
|
|
16997
17696
|
runningAgents: runningAgentIds,
|
|
16998
|
-
hostname: this.options.hostname ??
|
|
16999
|
-
os: this.options.osDescription ?? `${
|
|
17697
|
+
hostname: this.options.hostname ?? os9.hostname(),
|
|
17698
|
+
os: this.options.osDescription ?? `${os9.platform()} ${os9.arch()}`,
|
|
17000
17699
|
daemonVersion: this.daemonVersion,
|
|
17001
17700
|
...this.computerVersion ? { computerVersion: this.computerVersion } : {}
|
|
17002
17701
|
});
|