@botiverse/raft-daemon 0.62.0 → 0.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -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";
|
|
@@ -1599,12 +1599,12 @@ var DISPLAY_PLAN_CONFIG = {
|
|
|
1599
1599
|
var FREE_MONTHLY_FILE_UPLOAD_LIMIT_BYTES = 100 * 1024 * 1024;
|
|
1600
1600
|
|
|
1601
1601
|
// src/agentProcessManager.ts
|
|
1602
|
-
import { existsSync as existsSync9, mkdirSync as
|
|
1602
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync6, 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,77 @@ 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";
|
|
5206
|
+
import { mkdirSync as mkdirSync3 } from "fs";
|
|
5181
5207
|
import path6 from "path";
|
|
5208
|
+
function readConfiguredCodexHome(env) {
|
|
5209
|
+
const raw = env.CODEX_HOME;
|
|
5210
|
+
return typeof raw === "string" && raw.trim().length > 0 ? raw : null;
|
|
5211
|
+
}
|
|
5212
|
+
function readNonEmpty(value) {
|
|
5213
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
5214
|
+
}
|
|
5215
|
+
function safeCodexHomePathPart(value) {
|
|
5216
|
+
const safe = value.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
5217
|
+
return safe.length > 0 ? safe : "agent";
|
|
5218
|
+
}
|
|
5219
|
+
function resolveSlockManagedCodexHome(slockHome, agentId) {
|
|
5220
|
+
return path6.join(path6.resolve(slockHome), "codex-home", safeCodexHomePathPart(agentId));
|
|
5221
|
+
}
|
|
5222
|
+
function resolveDefaultCodexHomeRootForAgent(agentId, opts = {}) {
|
|
5223
|
+
return resolveSlockManagedCodexHome(readNonEmpty(opts.slockHome) ?? resolveSlockHome(opts.env), agentId);
|
|
5224
|
+
}
|
|
5225
|
+
function applyDefaultCodexHomeToEnv(env, agentId, opts = {}) {
|
|
5226
|
+
if (readConfiguredCodexHome(env)) return null;
|
|
5227
|
+
const codexHome = resolveDefaultCodexHomeRootForAgent(agentId, {
|
|
5228
|
+
slockHome: readNonEmpty(opts.slockHome) ?? readNonEmpty(env.SLOCK_HOME) ?? void 0,
|
|
5229
|
+
env
|
|
5230
|
+
});
|
|
5231
|
+
mkdirSync3(codexHome, { recursive: true });
|
|
5232
|
+
env.CODEX_HOME = codexHome;
|
|
5233
|
+
return codexHome;
|
|
5234
|
+
}
|
|
5235
|
+
function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
|
|
5236
|
+
const raw = readConfiguredCodexHome(env);
|
|
5237
|
+
if (raw) {
|
|
5238
|
+
return path6.resolve(opts.cwd ?? process.cwd(), raw);
|
|
5239
|
+
}
|
|
5240
|
+
return path6.join(opts.defaultHomeDir ?? os3.homedir(), ".codex");
|
|
5241
|
+
}
|
|
5242
|
+
function hasConfiguredCodexHome(config, baseEnv = process.env) {
|
|
5243
|
+
const launchRuntimeFields = config ? runtimeConfigToLaunchFields(config) : null;
|
|
5244
|
+
return Boolean(readConfiguredCodexHome({
|
|
5245
|
+
...baseEnv,
|
|
5246
|
+
...launchRuntimeFields?.envVars || {}
|
|
5247
|
+
}));
|
|
5248
|
+
}
|
|
5249
|
+
function resolveCodexHomeRootFromConfig(config, defaultHomeDir, cwd, baseEnv = process.env, opts = {}) {
|
|
5250
|
+
const launchRuntimeFields = runtimeConfigToLaunchFields(config);
|
|
5251
|
+
const env = {
|
|
5252
|
+
...baseEnv,
|
|
5253
|
+
...launchRuntimeFields.envVars || {}
|
|
5254
|
+
};
|
|
5255
|
+
if (readConfiguredCodexHome(env)) {
|
|
5256
|
+
return resolveCodexHomeRootFromEnv(env, { defaultHomeDir, cwd });
|
|
5257
|
+
}
|
|
5258
|
+
if (opts.agentId) {
|
|
5259
|
+
return resolveDefaultCodexHomeRootForAgent(opts.agentId, { slockHome: opts.slockHome, env });
|
|
5260
|
+
}
|
|
5261
|
+
return resolveCodexHomeRootFromEnv(env, { defaultHomeDir, cwd });
|
|
5262
|
+
}
|
|
5263
|
+
function codexStateRootCandidates(homeDirOrCodexRoot) {
|
|
5264
|
+
return [
|
|
5265
|
+
homeDirOrCodexRoot,
|
|
5266
|
+
path6.join(homeDirOrCodexRoot, ".codex")
|
|
5267
|
+
];
|
|
5268
|
+
}
|
|
5269
|
+
function codexSessionRootCandidates(homeDirOrCodexRoot) {
|
|
5270
|
+
return codexStateRootCandidates(homeDirOrCodexRoot).map((root) => path6.join(root, "sessions"));
|
|
5271
|
+
}
|
|
5182
5272
|
|
|
5183
5273
|
// src/runtimeTurnState.ts
|
|
5184
5274
|
var RuntimeTurnState = class {
|
|
@@ -5359,7 +5449,7 @@ function codexNotificationDiagnosticEvent(message) {
|
|
|
5359
5449
|
return null;
|
|
5360
5450
|
}
|
|
5361
5451
|
const sessionId = codexMessageThreadId(message);
|
|
5362
|
-
const
|
|
5452
|
+
const path19 = boundedString(params.path);
|
|
5363
5453
|
return {
|
|
5364
5454
|
kind: "runtime_diagnostic",
|
|
5365
5455
|
severity: "warning",
|
|
@@ -5367,12 +5457,42 @@ function codexNotificationDiagnosticEvent(message) {
|
|
|
5367
5457
|
itemType: message.method,
|
|
5368
5458
|
message: diagnosticMessage,
|
|
5369
5459
|
...details ? { details } : {},
|
|
5370
|
-
...
|
|
5460
|
+
...path19 ? { path: path19 } : {},
|
|
5371
5461
|
...params.range !== void 0 ? { range: params.range } : {},
|
|
5372
5462
|
payloadBytes: payloadBytes(params),
|
|
5373
5463
|
...sessionId ? { sessionId } : {}
|
|
5374
5464
|
};
|
|
5375
5465
|
}
|
|
5466
|
+
function codexThreadStatusChangedEvent(message) {
|
|
5467
|
+
if (message.method !== "thread/status/changed") return null;
|
|
5468
|
+
const params = message.params ?? {};
|
|
5469
|
+
const status = params.status ?? params.thread?.status;
|
|
5470
|
+
if (!status || typeof status !== "object") return null;
|
|
5471
|
+
const statusType = nonEmptyString2(status.type);
|
|
5472
|
+
const sessionId = codexMessageThreadId(message);
|
|
5473
|
+
if (statusType === "systemError") {
|
|
5474
|
+
const statusMessage = boundedString(status.message) ?? boundedString(status.error?.message) ?? getCodexNotificationErrorMessage(params) ?? "Codex thread entered system error state";
|
|
5475
|
+
return {
|
|
5476
|
+
kind: "error",
|
|
5477
|
+
message: statusMessage
|
|
5478
|
+
};
|
|
5479
|
+
}
|
|
5480
|
+
if (statusType !== "active" || !Array.isArray(status.activeFlags)) return null;
|
|
5481
|
+
const activeFlags = status.activeFlags.filter((flag) => typeof flag === "string");
|
|
5482
|
+
const waitFlags = activeFlags.filter((flag) => flag === "waitingOnApproval" || flag === "waitingOnUserInput");
|
|
5483
|
+
if (waitFlags.length === 0) return null;
|
|
5484
|
+
const waitLabel = waitFlags.includes("waitingOnApproval") && waitFlags.includes("waitingOnUserInput") ? "approval and user input" : waitFlags.includes("waitingOnApproval") ? "approval" : "user input";
|
|
5485
|
+
return {
|
|
5486
|
+
kind: "runtime_diagnostic",
|
|
5487
|
+
severity: "warning",
|
|
5488
|
+
source: "codex_app_server_notification",
|
|
5489
|
+
itemType: "thread/status/changed",
|
|
5490
|
+
message: `Codex thread is waiting on ${waitLabel}`,
|
|
5491
|
+
details: `Active flags: ${waitFlags.join(", ")}`,
|
|
5492
|
+
payloadBytes: payloadBytes(params),
|
|
5493
|
+
...sessionId ? { sessionId } : {}
|
|
5494
|
+
};
|
|
5495
|
+
}
|
|
5376
5496
|
function joinReasoningSummaryText(item) {
|
|
5377
5497
|
const summary = Array.isArray(item.summary) ? item.summary.filter((entry) => typeof entry === "string") : [];
|
|
5378
5498
|
return summary.join("\n").trim();
|
|
@@ -5400,10 +5520,27 @@ function codexMcpToolName(item) {
|
|
|
5400
5520
|
function codexMessageThreadId(message) {
|
|
5401
5521
|
return nonEmptyString2(message.params?.threadId) ?? nonEmptyString2(message.params?.thread?.id) ?? nonEmptyString2(message.params?.sessionId);
|
|
5402
5522
|
}
|
|
5523
|
+
function codexAgentMessagePhase(value) {
|
|
5524
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
5525
|
+
}
|
|
5526
|
+
function codexAgentMessageDeltaPhase(message) {
|
|
5527
|
+
return codexAgentMessagePhase(message.params?.phase) ?? codexAgentMessagePhase(message.params?.item?.phase);
|
|
5528
|
+
}
|
|
5529
|
+
function isUserVisibleAgentMessagePhase(phase) {
|
|
5530
|
+
return phase === null || phase === "final_answer";
|
|
5531
|
+
}
|
|
5532
|
+
function codexSuppressedAgentMessageEvent(itemType, phase, text, itemId) {
|
|
5533
|
+
return codexNotificationProgressEvent(itemType, {
|
|
5534
|
+
...typeof itemId === "string" ? { itemId } : {},
|
|
5535
|
+
...phase ? { phase } : {},
|
|
5536
|
+
bytes: Buffer.byteLength(text, "utf8")
|
|
5537
|
+
});
|
|
5538
|
+
}
|
|
5403
5539
|
var CodexEventNormalizer = class {
|
|
5404
5540
|
currentThreadId = null;
|
|
5405
5541
|
sessionAnnounced = false;
|
|
5406
5542
|
streamedAgentMessageIds = /* @__PURE__ */ new Set();
|
|
5543
|
+
agentMessagePhases = /* @__PURE__ */ new Map();
|
|
5407
5544
|
streamedReasoningIds = /* @__PURE__ */ new Set();
|
|
5408
5545
|
fileChangeToolCallCounts = /* @__PURE__ */ new Map();
|
|
5409
5546
|
turnState = new RuntimeTurnState();
|
|
@@ -5412,6 +5549,7 @@ var CodexEventNormalizer = class {
|
|
|
5412
5549
|
this.turnState.reset();
|
|
5413
5550
|
this.sessionAnnounced = false;
|
|
5414
5551
|
this.streamedAgentMessageIds.clear();
|
|
5552
|
+
this.agentMessagePhases.clear();
|
|
5415
5553
|
this.streamedReasoningIds.clear();
|
|
5416
5554
|
this.fileChangeToolCallCounts.clear();
|
|
5417
5555
|
}
|
|
@@ -5489,12 +5627,17 @@ var CodexEventNormalizer = class {
|
|
|
5489
5627
|
case "item/agentMessage/delta": {
|
|
5490
5628
|
const delta = message.params?.delta;
|
|
5491
5629
|
const itemId = message.params?.itemId;
|
|
5630
|
+
const phase = codexAgentMessageDeltaPhase(message) ?? (typeof itemId === "string" ? this.agentMessagePhases.get(itemId) ?? null : null);
|
|
5492
5631
|
if (typeof itemId === "string") {
|
|
5493
5632
|
this.streamedAgentMessageIds.add(itemId);
|
|
5494
5633
|
}
|
|
5495
5634
|
if (typeof delta === "string" && delta.length > 0) {
|
|
5496
5635
|
this.turnState.markProgress();
|
|
5497
|
-
|
|
5636
|
+
if (isUserVisibleAgentMessagePhase(phase)) {
|
|
5637
|
+
events.push({ kind: "text", text: delta });
|
|
5638
|
+
} else {
|
|
5639
|
+
events.push(codexSuppressedAgentMessageEvent("agent_message_non_final_delta", phase, delta, itemId));
|
|
5640
|
+
}
|
|
5498
5641
|
}
|
|
5499
5642
|
break;
|
|
5500
5643
|
}
|
|
@@ -5545,6 +5688,13 @@ var CodexEventNormalizer = class {
|
|
|
5545
5688
|
}
|
|
5546
5689
|
break;
|
|
5547
5690
|
}
|
|
5691
|
+
case "thread/status/changed": {
|
|
5692
|
+
const event = codexThreadStatusChangedEvent(message);
|
|
5693
|
+
if (event) {
|
|
5694
|
+
events.push(event);
|
|
5695
|
+
}
|
|
5696
|
+
break;
|
|
5697
|
+
}
|
|
5548
5698
|
case "item/started":
|
|
5549
5699
|
case "item/completed": {
|
|
5550
5700
|
const item = message.params?.item;
|
|
@@ -5566,12 +5716,21 @@ var CodexEventNormalizer = class {
|
|
|
5566
5716
|
}
|
|
5567
5717
|
break;
|
|
5568
5718
|
case "agentMessage":
|
|
5719
|
+
if ((isStarted || isCompleted) && typeof item.id === "string") {
|
|
5720
|
+
this.agentMessagePhases.set(item.id, codexAgentMessagePhase(item.phase));
|
|
5721
|
+
}
|
|
5569
5722
|
if (isCompleted && typeof item.id === "string" && !this.streamedAgentMessageIds.has(item.id) && typeof item.text === "string" && item.text.length > 0) {
|
|
5723
|
+
const phase = codexAgentMessagePhase(item.phase);
|
|
5570
5724
|
this.turnState.markProgress();
|
|
5571
|
-
|
|
5725
|
+
if (isUserVisibleAgentMessagePhase(phase)) {
|
|
5726
|
+
events.push({ kind: "text", text: item.text });
|
|
5727
|
+
} else {
|
|
5728
|
+
events.push(codexSuppressedAgentMessageEvent("agent_message_non_final_completed", phase, item.text, item.id));
|
|
5729
|
+
}
|
|
5572
5730
|
}
|
|
5573
5731
|
if (isCompleted && typeof item.id === "string") {
|
|
5574
5732
|
this.streamedAgentMessageIds.delete(item.id);
|
|
5733
|
+
this.agentMessagePhases.delete(item.id);
|
|
5575
5734
|
}
|
|
5576
5735
|
break;
|
|
5577
5736
|
case "commandExecution":
|
|
@@ -5710,14 +5869,15 @@ var CodexEventNormalizer = class {
|
|
|
5710
5869
|
|
|
5711
5870
|
// src/drivers/codex.ts
|
|
5712
5871
|
var CODEX_DESKTOP_BUNDLE_PATH = "/Applications/Codex.app/Contents/Resources/codex";
|
|
5872
|
+
var CODEX_APP_SERVER_PROBE_ARGS = ["app-server", "--help"];
|
|
5713
5873
|
function isWindowsSandboxRunner(commandPath) {
|
|
5714
|
-
return
|
|
5874
|
+
return path7.basename(commandPath).toLowerCase().startsWith("codex-command-runner");
|
|
5715
5875
|
}
|
|
5716
5876
|
function resolveWindowsNpmCodexEntry(deps = {}) {
|
|
5717
5877
|
const existsSyncFn = deps.existsSyncFn ?? existsSync5;
|
|
5718
5878
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
|
|
5719
5879
|
const env = deps.env ?? process.env;
|
|
5720
|
-
const winPath =
|
|
5880
|
+
const winPath = path7.win32;
|
|
5721
5881
|
try {
|
|
5722
5882
|
const globalRoot = String(execFileSyncFn("npm", ["root", "-g"], {
|
|
5723
5883
|
encoding: "utf8",
|
|
@@ -5739,7 +5899,7 @@ function resolveWindowsCodexDesktopEntry(deps = {}) {
|
|
|
5739
5899
|
const existsSyncFn = deps.existsSyncFn ?? existsSync5;
|
|
5740
5900
|
const env = deps.env ?? process.env;
|
|
5741
5901
|
const homeDir = deps.homeDir;
|
|
5742
|
-
const winPath =
|
|
5902
|
+
const winPath = path7.win32;
|
|
5743
5903
|
const candidates = [
|
|
5744
5904
|
env.LOCALAPPDATA ? winPath.join(env.LOCALAPPDATA, "OpenAI", "Codex", "bin", "codex.exe") : null,
|
|
5745
5905
|
env.USERPROFILE ? winPath.join(env.USERPROFILE, "AppData", "Local", "OpenAI", "Codex", "bin", "codex.exe") : null,
|
|
@@ -5750,69 +5910,158 @@ function resolveWindowsCodexDesktopEntry(deps = {}) {
|
|
|
5750
5910
|
}
|
|
5751
5911
|
return null;
|
|
5752
5912
|
}
|
|
5753
|
-
function
|
|
5913
|
+
function codexSpawnCandidates(deps = {}) {
|
|
5754
5914
|
const platform = deps.platform ?? process.platform;
|
|
5755
5915
|
if (platform === "win32") {
|
|
5916
|
+
const candidates2 = [];
|
|
5756
5917
|
const npmEntry = resolveWindowsNpmCodexEntry(deps);
|
|
5757
|
-
if (npmEntry)
|
|
5918
|
+
if (npmEntry) {
|
|
5919
|
+
candidates2.push({
|
|
5920
|
+
source: "npm_global",
|
|
5921
|
+
command: process.execPath,
|
|
5922
|
+
argsPrefix: [npmEntry],
|
|
5923
|
+
shell: false
|
|
5924
|
+
});
|
|
5925
|
+
}
|
|
5758
5926
|
const command = resolveCommandOnPath("codex", deps);
|
|
5759
|
-
if (command && !isWindowsSandboxRunner(command))
|
|
5760
|
-
|
|
5927
|
+
if (command && !isWindowsSandboxRunner(command)) {
|
|
5928
|
+
candidates2.push({
|
|
5929
|
+
source: "path",
|
|
5930
|
+
command,
|
|
5931
|
+
argsPrefix: [],
|
|
5932
|
+
shell: requiresWindowsShell(command, platform)
|
|
5933
|
+
});
|
|
5934
|
+
}
|
|
5935
|
+
const desktopEntry = resolveWindowsCodexDesktopEntry(deps);
|
|
5936
|
+
if (desktopEntry && !candidates2.some((candidate) => candidate.command === desktopEntry)) {
|
|
5937
|
+
candidates2.push({
|
|
5938
|
+
source: "desktop_install",
|
|
5939
|
+
command: desktopEntry,
|
|
5940
|
+
argsPrefix: [],
|
|
5941
|
+
shell: false
|
|
5942
|
+
});
|
|
5943
|
+
}
|
|
5944
|
+
return candidates2;
|
|
5761
5945
|
}
|
|
5946
|
+
const candidates = [];
|
|
5762
5947
|
const pathCommand = resolveCommandOnPath("codex", deps);
|
|
5763
|
-
if (pathCommand)
|
|
5948
|
+
if (pathCommand) {
|
|
5949
|
+
candidates.push({
|
|
5950
|
+
source: "path",
|
|
5951
|
+
command: pathCommand,
|
|
5952
|
+
argsPrefix: [],
|
|
5953
|
+
shell: false
|
|
5954
|
+
});
|
|
5955
|
+
}
|
|
5764
5956
|
if (platform === "darwin") {
|
|
5765
|
-
|
|
5957
|
+
const bundleCommand = firstExistingPath([CODEX_DESKTOP_BUNDLE_PATH], deps);
|
|
5958
|
+
if (bundleCommand && !candidates.some((candidate) => candidate.command === bundleCommand)) {
|
|
5959
|
+
candidates.push({
|
|
5960
|
+
source: "desktop_bundle",
|
|
5961
|
+
command: bundleCommand,
|
|
5962
|
+
argsPrefix: [],
|
|
5963
|
+
shell: false
|
|
5964
|
+
});
|
|
5965
|
+
}
|
|
5766
5966
|
}
|
|
5767
|
-
return
|
|
5967
|
+
return candidates;
|
|
5968
|
+
}
|
|
5969
|
+
function formatCodexCandidate(candidate) {
|
|
5970
|
+
return [candidate.command, ...candidate.argsPrefix].join(" ");
|
|
5971
|
+
}
|
|
5972
|
+
function describeCodexProbeFailure(error) {
|
|
5973
|
+
if (error && typeof error === "object") {
|
|
5974
|
+
const candidate = error;
|
|
5975
|
+
if (typeof candidate.status === "number") return `exit status ${candidate.status}`;
|
|
5976
|
+
if (typeof candidate.signal === "string") return `terminated by ${candidate.signal}`;
|
|
5977
|
+
if (typeof candidate.code === "string") return candidate.code;
|
|
5978
|
+
}
|
|
5979
|
+
return "probe failed";
|
|
5980
|
+
}
|
|
5981
|
+
function validateCodexAppServer(candidate, deps = {}) {
|
|
5982
|
+
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
|
|
5983
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
5984
|
+
try {
|
|
5985
|
+
execFileSyncFn(candidate.command, [...candidate.argsPrefix, ...CODEX_APP_SERVER_PROBE_ARGS], {
|
|
5986
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5987
|
+
env,
|
|
5988
|
+
timeout: 5e3,
|
|
5989
|
+
shell: candidate.shell
|
|
5990
|
+
});
|
|
5991
|
+
return null;
|
|
5992
|
+
} catch (error) {
|
|
5993
|
+
return describeCodexProbeFailure(error);
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
function readCodexCandidateVersion(candidate, deps = {}) {
|
|
5997
|
+
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync2;
|
|
5998
|
+
const env = withWindowsUserEnvironment(deps.env ?? process.env, deps);
|
|
5999
|
+
try {
|
|
6000
|
+
const output = execFileSyncFn(candidate.command, [...candidate.argsPrefix, "--version"], {
|
|
6001
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
6002
|
+
env,
|
|
6003
|
+
timeout: 5e3,
|
|
6004
|
+
shell: candidate.shell
|
|
6005
|
+
});
|
|
6006
|
+
return (Buffer.isBuffer(output) ? output.toString("utf8") : String(output ?? "")).trim().split(/\r?\n/)[0] || null;
|
|
6007
|
+
} catch {
|
|
6008
|
+
return null;
|
|
6009
|
+
}
|
|
6010
|
+
}
|
|
6011
|
+
function resolveCompatibleCodexCandidate(deps = {}) {
|
|
6012
|
+
const rejected = [];
|
|
6013
|
+
for (const candidate of codexSpawnCandidates(deps)) {
|
|
6014
|
+
const failure = validateCodexAppServer(candidate, deps);
|
|
6015
|
+
if (!failure) return { candidate, rejected };
|
|
6016
|
+
rejected.push(`${candidate.source} ${formatCodexCandidate(candidate)} rejected: app-server probe ${failure}`);
|
|
6017
|
+
}
|
|
6018
|
+
return { candidate: null, rejected };
|
|
5768
6019
|
}
|
|
5769
6020
|
function probeCodex(deps = {}) {
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5777
|
-
} catch {
|
|
5778
|
-
return { available: false };
|
|
5779
|
-
}
|
|
6021
|
+
const { candidate, rejected } = resolveCompatibleCodexCandidate(deps);
|
|
6022
|
+
const diagnostic = rejected.length > 0 ? rejected.join("; ") : void 0;
|
|
6023
|
+
if (!candidate) {
|
|
6024
|
+
return {
|
|
6025
|
+
available: false,
|
|
6026
|
+
diagnostic: diagnostic ?? "No Codex CLI app-server candidate was found."
|
|
6027
|
+
};
|
|
5780
6028
|
}
|
|
5781
|
-
const command = resolveCodexCommand(deps);
|
|
5782
|
-
if (!command) return { available: false };
|
|
5783
6029
|
return {
|
|
5784
6030
|
available: true,
|
|
5785
|
-
version:
|
|
6031
|
+
version: readCodexCandidateVersion(candidate, deps) ?? void 0,
|
|
6032
|
+
...diagnostic ? { diagnostic } : {}
|
|
5786
6033
|
};
|
|
5787
6034
|
}
|
|
5788
6035
|
function resolveCodexSpawn(commandArgs, deps = {}) {
|
|
5789
|
-
|
|
5790
|
-
|
|
6036
|
+
const { candidate, rejected } = resolveCompatibleCodexCandidate(deps);
|
|
6037
|
+
if (candidate) {
|
|
6038
|
+
return { command: candidate.command, args: [...candidate.argsPrefix, ...commandArgs], shell: candidate.shell };
|
|
5791
6039
|
}
|
|
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 };
|
|
6040
|
+
const diagnostic = rejected.length > 0 ? ` Rejected candidates: ${rejected.join("; ")}.` : "";
|
|
6041
|
+
if ((deps.platform ?? process.platform) === "win32") {
|
|
6042
|
+
throw new Error(
|
|
6043
|
+
"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
|
|
6044
|
+
);
|
|
5807
6045
|
}
|
|
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
|
-
);
|
|
6046
|
+
throw new Error(`Cannot resolve a compatible Codex CLI app-server entry point.${diagnostic}`);
|
|
5811
6047
|
}
|
|
5812
6048
|
function isCodexMissingRolloutError(message) {
|
|
5813
6049
|
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
6050
|
}
|
|
5815
|
-
function
|
|
6051
|
+
function codexMissingRolloutRecoveryMessage() {
|
|
6052
|
+
return "Codex could not resume its previous thread; Slock started a fresh Codex thread.";
|
|
6053
|
+
}
|
|
6054
|
+
function codexMissingRolloutRecoveryDetails() {
|
|
6055
|
+
return "Use Slock conversation history and local MEMORY.md/notes as the recovery point; do not assume prior Codex thread context is loaded.";
|
|
6056
|
+
}
|
|
6057
|
+
function prependCodexRecoveryNotice(prompt, recovery) {
|
|
6058
|
+
return `${recovery.message}
|
|
6059
|
+
|
|
6060
|
+
${recovery.details}
|
|
6061
|
+
|
|
6062
|
+
${prompt}`;
|
|
6063
|
+
}
|
|
6064
|
+
function classifyCodexResumeError(message, requestedSessionId) {
|
|
5816
6065
|
if (isCodexMissingRolloutError(message)) {
|
|
5817
6066
|
return {
|
|
5818
6067
|
kind: "missing_rollout",
|
|
@@ -5826,6 +6075,15 @@ function classifyCodexResumeError(message) {
|
|
|
5826
6075
|
resume_error_class: "missing_rollout",
|
|
5827
6076
|
recovery_action: "fallback_fresh_thread"
|
|
5828
6077
|
}
|
|
6078
|
+
},
|
|
6079
|
+
recovery: {
|
|
6080
|
+
kind: "runtime_recovery",
|
|
6081
|
+
source: "codex_resume_missing_rollout",
|
|
6082
|
+
resumeErrorClass: "missing_rollout",
|
|
6083
|
+
recoveryAction: "fallback_fresh_thread",
|
|
6084
|
+
message: codexMissingRolloutRecoveryMessage(),
|
|
6085
|
+
details: codexMissingRolloutRecoveryDetails(),
|
|
6086
|
+
...requestedSessionId ? { requestedSessionId } : {}
|
|
5829
6087
|
}
|
|
5830
6088
|
};
|
|
5831
6089
|
}
|
|
@@ -5849,6 +6107,26 @@ function isJsonRpcResponse(message) {
|
|
|
5849
6107
|
function isCodexServerRequest(message) {
|
|
5850
6108
|
return message.id !== void 0 && typeof message.method === "string" && !isJsonRpcResponse(message);
|
|
5851
6109
|
}
|
|
6110
|
+
function payloadBytes2(value) {
|
|
6111
|
+
try {
|
|
6112
|
+
return Buffer.byteLength(JSON.stringify(value), "utf8");
|
|
6113
|
+
} catch {
|
|
6114
|
+
return void 0;
|
|
6115
|
+
}
|
|
6116
|
+
}
|
|
6117
|
+
function extractCodexHome(result) {
|
|
6118
|
+
if (!result || typeof result !== "object") return null;
|
|
6119
|
+
const candidate = result.codexHome;
|
|
6120
|
+
return typeof candidate === "string" && candidate.trim().length > 0 ? candidate : null;
|
|
6121
|
+
}
|
|
6122
|
+
function isCompatibleInitializeResult(result) {
|
|
6123
|
+
if (!result || typeof result !== "object" || Array.isArray(result)) return false;
|
|
6124
|
+
const userAgent = result.userAgent;
|
|
6125
|
+
return typeof userAgent === "string" && userAgent.trim().length > 0;
|
|
6126
|
+
}
|
|
6127
|
+
function unsupportedInitializeResultMessage() {
|
|
6128
|
+
return "Codex app-server initialize response is missing the expected userAgent handshake field; upgrade Codex CLI to a compatible app-server build.";
|
|
6129
|
+
}
|
|
5852
6130
|
var CodexDriver = class {
|
|
5853
6131
|
id = "codex";
|
|
5854
6132
|
lifecycle = {
|
|
@@ -5919,11 +6197,19 @@ var CodexDriver = class {
|
|
|
5919
6197
|
pendingThreadRequestId = null;
|
|
5920
6198
|
pendingThreadRequestMethod = null;
|
|
5921
6199
|
pendingResumeFallbackParams = null;
|
|
6200
|
+
pendingResumeThreadId = null;
|
|
5922
6201
|
pendingInitialTurnRequestId = null;
|
|
6202
|
+
pendingDeliveryRequests = /* @__PURE__ */ new Map();
|
|
5923
6203
|
initialTurnStarted = false;
|
|
5924
6204
|
normalizer = new CodexEventNormalizer();
|
|
6205
|
+
codexHomeRoot = null;
|
|
6206
|
+
spawnWorkingDirectory = null;
|
|
6207
|
+
get currentRuntimeHomeDir() {
|
|
6208
|
+
return this.codexHomeRoot;
|
|
6209
|
+
}
|
|
5925
6210
|
async spawn(ctx) {
|
|
5926
6211
|
const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
6212
|
+
applyDefaultCodexHomeToEnv(spawnEnv, ctx.agentId, { slockHome: ctx.slockHome });
|
|
5927
6213
|
this.process = null;
|
|
5928
6214
|
this.requestId = 0;
|
|
5929
6215
|
this.pendingInitialPrompt = ctx.prompt;
|
|
@@ -5932,9 +6218,16 @@ var CodexDriver = class {
|
|
|
5932
6218
|
this.pendingThreadRequestId = null;
|
|
5933
6219
|
this.pendingThreadRequestMethod = null;
|
|
5934
6220
|
this.pendingResumeFallbackParams = null;
|
|
6221
|
+
this.pendingResumeThreadId = null;
|
|
5935
6222
|
this.pendingInitialTurnRequestId = null;
|
|
6223
|
+
this.pendingDeliveryRequests.clear();
|
|
5936
6224
|
this.initialTurnStarted = false;
|
|
5937
6225
|
this.normalizer.reset();
|
|
6226
|
+
this.spawnWorkingDirectory = ctx.workingDirectory;
|
|
6227
|
+
this.codexHomeRoot = resolveCodexHomeRootFromEnv(spawnEnv, {
|
|
6228
|
+
defaultHomeDir: os4.homedir(),
|
|
6229
|
+
cwd: ctx.workingDirectory
|
|
6230
|
+
});
|
|
5938
6231
|
const args = ["app-server", "--listen", "stdio://"];
|
|
5939
6232
|
const { command, args: spawnArgs, shell } = resolveCodexSpawn(args);
|
|
5940
6233
|
const proc = spawn2(command, spawnArgs, {
|
|
@@ -5969,6 +6262,24 @@ var CodexDriver = class {
|
|
|
5969
6262
|
const isResponse = isJsonRpcResponse(message);
|
|
5970
6263
|
if (isResponse && hasJsonRpcField(message, "result")) {
|
|
5971
6264
|
if (message.id === this.initializeRequestId) {
|
|
6265
|
+
if (!isCompatibleInitializeResult(message.result)) {
|
|
6266
|
+
this.initializeRequestId = null;
|
|
6267
|
+
this.pendingThreadRequest = null;
|
|
6268
|
+
this.pendingThreadRequestId = null;
|
|
6269
|
+
this.pendingThreadRequestMethod = null;
|
|
6270
|
+
this.pendingResumeFallbackParams = null;
|
|
6271
|
+
this.pendingResumeThreadId = null;
|
|
6272
|
+
events.push({
|
|
6273
|
+
kind: "error",
|
|
6274
|
+
message: unsupportedInitializeResultMessage(),
|
|
6275
|
+
startupRequestMethod: "initialize"
|
|
6276
|
+
});
|
|
6277
|
+
return events;
|
|
6278
|
+
}
|
|
6279
|
+
const codexHome = extractCodexHome(message.result);
|
|
6280
|
+
if (codexHome) {
|
|
6281
|
+
this.codexHomeRoot = path7.resolve(this.spawnWorkingDirectory ?? process.cwd(), codexHome);
|
|
6282
|
+
}
|
|
5972
6283
|
this.initializeRequestId = null;
|
|
5973
6284
|
this.sendNotification("initialized", {});
|
|
5974
6285
|
if (this.pendingThreadRequest) {
|
|
@@ -5984,6 +6295,7 @@ var CodexDriver = class {
|
|
|
5984
6295
|
this.pendingThreadRequestId = null;
|
|
5985
6296
|
this.pendingThreadRequestMethod = null;
|
|
5986
6297
|
this.pendingResumeFallbackParams = null;
|
|
6298
|
+
this.pendingResumeThreadId = null;
|
|
5987
6299
|
events.push({
|
|
5988
6300
|
kind: "error",
|
|
5989
6301
|
message: message.error?.message || "Codex app-server request failed",
|
|
@@ -5995,9 +6307,16 @@ var CodexDriver = class {
|
|
|
5995
6307
|
if (hasJsonRpcField(message, "error")) {
|
|
5996
6308
|
const errorMessage = message.error?.message || "Codex app-server request failed";
|
|
5997
6309
|
const requestMethod = this.pendingThreadRequestMethod;
|
|
5998
|
-
const resumeErrorClassification = requestMethod === "thread/resume" ? classifyCodexResumeError(errorMessage) : null;
|
|
6310
|
+
const resumeErrorClassification = requestMethod === "thread/resume" ? classifyCodexResumeError(errorMessage, this.pendingResumeThreadId || void 0) : null;
|
|
5999
6311
|
if (this.pendingResumeFallbackParams && resumeErrorClassification?.kind === "missing_rollout") {
|
|
6000
6312
|
events.push(resumeErrorClassification.telemetry);
|
|
6313
|
+
events.push(resumeErrorClassification.recovery);
|
|
6314
|
+
if (this.pendingInitialPrompt) {
|
|
6315
|
+
this.pendingInitialPrompt = prependCodexRecoveryNotice(
|
|
6316
|
+
this.pendingInitialPrompt,
|
|
6317
|
+
resumeErrorClassification.recovery
|
|
6318
|
+
);
|
|
6319
|
+
}
|
|
6001
6320
|
this.sendThreadRequest("thread/start", this.pendingResumeFallbackParams);
|
|
6002
6321
|
this.pendingResumeFallbackParams = null;
|
|
6003
6322
|
return events;
|
|
@@ -6005,12 +6324,14 @@ var CodexDriver = class {
|
|
|
6005
6324
|
this.pendingThreadRequestId = null;
|
|
6006
6325
|
this.pendingThreadRequestMethod = null;
|
|
6007
6326
|
this.pendingResumeFallbackParams = null;
|
|
6327
|
+
this.pendingResumeThreadId = null;
|
|
6008
6328
|
events.push(requestMethod ? { kind: "error", message: errorMessage, startupRequestMethod: requestMethod } : { kind: "error", message: errorMessage });
|
|
6009
6329
|
return events;
|
|
6010
6330
|
}
|
|
6011
6331
|
this.pendingThreadRequestId = null;
|
|
6012
6332
|
this.pendingThreadRequestMethod = null;
|
|
6013
6333
|
this.pendingResumeFallbackParams = null;
|
|
6334
|
+
this.pendingResumeThreadId = null;
|
|
6014
6335
|
}
|
|
6015
6336
|
if (isResponse && message.id === this.pendingInitialTurnRequestId) {
|
|
6016
6337
|
this.pendingInitialTurnRequestId = null;
|
|
@@ -6025,6 +6346,21 @@ var CodexDriver = class {
|
|
|
6025
6346
|
}
|
|
6026
6347
|
return events;
|
|
6027
6348
|
}
|
|
6349
|
+
if (isResponse && message.id !== void 0 && this.pendingDeliveryRequests.has(message.id)) {
|
|
6350
|
+
const requestMethod = this.pendingDeliveryRequests.get(message.id);
|
|
6351
|
+
this.pendingDeliveryRequests.delete(message.id);
|
|
6352
|
+
if (hasJsonRpcField(message, "error")) {
|
|
6353
|
+
const params = message.error ?? {};
|
|
6354
|
+
events.push({
|
|
6355
|
+
kind: "delivery_error",
|
|
6356
|
+
message: message.error?.message || "Codex app-server request failed",
|
|
6357
|
+
requestMethod,
|
|
6358
|
+
source: "codex_app_server_response",
|
|
6359
|
+
payloadBytes: payloadBytes2(params)
|
|
6360
|
+
});
|
|
6361
|
+
}
|
|
6362
|
+
return events;
|
|
6363
|
+
}
|
|
6028
6364
|
const result = this.normalizer.normalizeMessage(message);
|
|
6029
6365
|
if (result.turnStarted) {
|
|
6030
6366
|
this.pendingInitialTurnRequestId = null;
|
|
@@ -6043,9 +6379,11 @@ var CodexDriver = class {
|
|
|
6043
6379
|
const mode = opts?.mode || "busy";
|
|
6044
6380
|
if (mode === "busy") {
|
|
6045
6381
|
if (!this.normalizer.canSteerBusy) return null;
|
|
6382
|
+
const id2 = this.nextRequestId();
|
|
6383
|
+
this.pendingDeliveryRequests.set(id2, "turn/steer");
|
|
6046
6384
|
return JSON.stringify({
|
|
6047
6385
|
jsonrpc: "2.0",
|
|
6048
|
-
id:
|
|
6386
|
+
id: id2,
|
|
6049
6387
|
method: "turn/steer",
|
|
6050
6388
|
params: {
|
|
6051
6389
|
threadId: this.normalizer.threadId,
|
|
@@ -6054,9 +6392,11 @@ var CodexDriver = class {
|
|
|
6054
6392
|
}
|
|
6055
6393
|
});
|
|
6056
6394
|
}
|
|
6395
|
+
const id = this.nextRequestId();
|
|
6396
|
+
this.pendingDeliveryRequests.set(id, "turn/start");
|
|
6057
6397
|
return JSON.stringify({
|
|
6058
6398
|
jsonrpc: "2.0",
|
|
6059
|
-
id
|
|
6399
|
+
id,
|
|
6060
6400
|
method: "turn/start",
|
|
6061
6401
|
params: {
|
|
6062
6402
|
threadId: this.normalizer.threadId,
|
|
@@ -6112,9 +6452,11 @@ var CodexDriver = class {
|
|
|
6112
6452
|
this.pendingThreadRequestId = id;
|
|
6113
6453
|
this.pendingThreadRequestMethod = method;
|
|
6114
6454
|
this.pendingResumeFallbackParams = null;
|
|
6455
|
+
this.pendingResumeThreadId = null;
|
|
6115
6456
|
if (method === "thread/resume") {
|
|
6116
6457
|
const { threadId: _threadId, ...freshParams } = params;
|
|
6117
6458
|
this.pendingResumeFallbackParams = freshParams;
|
|
6459
|
+
this.pendingResumeThreadId = typeof _threadId === "string" && _threadId.trim() ? _threadId.trim() : null;
|
|
6118
6460
|
}
|
|
6119
6461
|
return id;
|
|
6120
6462
|
}
|
|
@@ -6126,12 +6468,194 @@ var CodexDriver = class {
|
|
|
6126
6468
|
}) + "\n");
|
|
6127
6469
|
}
|
|
6128
6470
|
async detectModels() {
|
|
6129
|
-
return detectCodexModels();
|
|
6471
|
+
return await detectCodexModelsFromAppServer() ?? detectCodexModels(resolveCodexHomeRootFromEnv());
|
|
6130
6472
|
}
|
|
6131
6473
|
};
|
|
6132
|
-
function
|
|
6133
|
-
|
|
6134
|
-
|
|
6474
|
+
function asNonEmptyString(value) {
|
|
6475
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
6476
|
+
}
|
|
6477
|
+
function modelListPage(result) {
|
|
6478
|
+
if (!result || typeof result !== "object") return null;
|
|
6479
|
+
const object = result;
|
|
6480
|
+
const entries = Array.isArray(object.data) ? object.data : Array.isArray(object.models) ? object.models : null;
|
|
6481
|
+
if (!entries) return null;
|
|
6482
|
+
return {
|
|
6483
|
+
entries,
|
|
6484
|
+
nextCursor: asNonEmptyString(object.nextCursor)
|
|
6485
|
+
};
|
|
6486
|
+
}
|
|
6487
|
+
function modelListRequestParams(cursor) {
|
|
6488
|
+
return cursor ? { cursor } : {};
|
|
6489
|
+
}
|
|
6490
|
+
function stringArray(values, read) {
|
|
6491
|
+
const result = [];
|
|
6492
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6493
|
+
for (const value of values) {
|
|
6494
|
+
const item = read(value);
|
|
6495
|
+
if (!item || seen.has(item)) continue;
|
|
6496
|
+
seen.add(item);
|
|
6497
|
+
result.push(item);
|
|
6498
|
+
}
|
|
6499
|
+
return result;
|
|
6500
|
+
}
|
|
6501
|
+
function codexReasoningEfforts(value) {
|
|
6502
|
+
if (!Array.isArray(value)) return [];
|
|
6503
|
+
return stringArray(value, (entry) => {
|
|
6504
|
+
if (typeof entry === "string") return asNonEmptyString(entry);
|
|
6505
|
+
if (!entry || typeof entry !== "object") return null;
|
|
6506
|
+
const object = entry;
|
|
6507
|
+
return asNonEmptyString(object.reasoningEffort) ?? asNonEmptyString(object.id);
|
|
6508
|
+
});
|
|
6509
|
+
}
|
|
6510
|
+
function codexServiceTierIds(value) {
|
|
6511
|
+
if (!Array.isArray(value)) return [];
|
|
6512
|
+
return stringArray(value, (entry) => {
|
|
6513
|
+
if (typeof entry === "string") return asNonEmptyString(entry);
|
|
6514
|
+
if (!entry || typeof entry !== "object") return null;
|
|
6515
|
+
const object = entry;
|
|
6516
|
+
return asNonEmptyString(object.id) ?? asNonEmptyString(object.serviceTier);
|
|
6517
|
+
});
|
|
6518
|
+
}
|
|
6519
|
+
function codexModelInfoFromAppServer(entry) {
|
|
6520
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return null;
|
|
6521
|
+
const object = entry;
|
|
6522
|
+
if (object.hidden === true) return null;
|
|
6523
|
+
const id = asNonEmptyString(object.id) ?? asNonEmptyString(object.model) ?? asNonEmptyString(object.slug);
|
|
6524
|
+
if (!id) return null;
|
|
6525
|
+
const label = asNonEmptyString(object.displayName) ?? asNonEmptyString(object.display_name) ?? asNonEmptyString(object.label) ?? id;
|
|
6526
|
+
const supportedReasoningEfforts = codexReasoningEfforts(object.supportedReasoningEfforts);
|
|
6527
|
+
const serviceTiers = codexServiceTierIds(object.serviceTiers);
|
|
6528
|
+
const additionalSpeedTiers = codexServiceTierIds(object.additionalSpeedTiers);
|
|
6529
|
+
const runtimeServiceTiers = serviceTiers.length > 0 ? serviceTiers : additionalSpeedTiers;
|
|
6530
|
+
const defaultReasoningEffort = asNonEmptyString(object.defaultReasoningEffort);
|
|
6531
|
+
const defaultServiceTier = asNonEmptyString(object.defaultServiceTier);
|
|
6532
|
+
return {
|
|
6533
|
+
id,
|
|
6534
|
+
label,
|
|
6535
|
+
verified: "launchable",
|
|
6536
|
+
...supportedReasoningEfforts.length > 0 ? { supportedReasoningEfforts } : {},
|
|
6537
|
+
...defaultReasoningEffort ? { defaultReasoningEffort } : {},
|
|
6538
|
+
...runtimeServiceTiers.length > 0 ? { serviceTiers: runtimeServiceTiers } : {},
|
|
6539
|
+
...defaultServiceTier ? { defaultServiceTier } : {}
|
|
6540
|
+
};
|
|
6541
|
+
}
|
|
6542
|
+
function codexModelSetFromAppServerEntries(entries) {
|
|
6543
|
+
const models = [];
|
|
6544
|
+
let defaultModel;
|
|
6545
|
+
for (const entry of entries) {
|
|
6546
|
+
const model = codexModelInfoFromAppServer(entry);
|
|
6547
|
+
if (!model) continue;
|
|
6548
|
+
models.push(model);
|
|
6549
|
+
if (!defaultModel && typeof entry === "object" && entry && entry.isDefault === true) {
|
|
6550
|
+
defaultModel = model.id;
|
|
6551
|
+
}
|
|
6552
|
+
}
|
|
6553
|
+
return models.length > 0 ? { models, default: defaultModel } : null;
|
|
6554
|
+
}
|
|
6555
|
+
async function detectCodexModelsFromAppServer(options = {}) {
|
|
6556
|
+
const env = options.env ?? process.env;
|
|
6557
|
+
let launch;
|
|
6558
|
+
try {
|
|
6559
|
+
launch = resolveCodexSpawn(["app-server", "--listen", "stdio://"], { env });
|
|
6560
|
+
} catch {
|
|
6561
|
+
return null;
|
|
6562
|
+
}
|
|
6563
|
+
return await new Promise((resolve) => {
|
|
6564
|
+
const timeoutMs = options.timeoutMs ?? 5e3;
|
|
6565
|
+
const proc = spawn2(launch.command, launch.args, {
|
|
6566
|
+
cwd: options.cwd ?? process.cwd(),
|
|
6567
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
6568
|
+
env,
|
|
6569
|
+
shell: launch.shell
|
|
6570
|
+
});
|
|
6571
|
+
let settled = false;
|
|
6572
|
+
let buffer = "";
|
|
6573
|
+
let requestId = 0;
|
|
6574
|
+
let initializeRequestId = null;
|
|
6575
|
+
let modelListRequestId = null;
|
|
6576
|
+
let pageCount = 0;
|
|
6577
|
+
const entries = [];
|
|
6578
|
+
const finish = (result) => {
|
|
6579
|
+
if (settled) return;
|
|
6580
|
+
settled = true;
|
|
6581
|
+
clearTimeout(timer);
|
|
6582
|
+
proc.kill();
|
|
6583
|
+
resolve(result);
|
|
6584
|
+
};
|
|
6585
|
+
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
6586
|
+
const sendRequest = (method, params) => {
|
|
6587
|
+
requestId += 1;
|
|
6588
|
+
const id = requestId;
|
|
6589
|
+
proc.stdin?.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
|
|
6590
|
+
return id;
|
|
6591
|
+
};
|
|
6592
|
+
const sendNotification = (method, params) => {
|
|
6593
|
+
proc.stdin?.write(JSON.stringify({ jsonrpc: "2.0", method, params }) + "\n");
|
|
6594
|
+
};
|
|
6595
|
+
const requestModelPage = (cursor) => {
|
|
6596
|
+
pageCount += 1;
|
|
6597
|
+
modelListRequestId = sendRequest("model/list", modelListRequestParams(cursor));
|
|
6598
|
+
};
|
|
6599
|
+
proc.once("error", () => finish(null));
|
|
6600
|
+
proc.once("exit", () => finish(null));
|
|
6601
|
+
proc.stdout?.on("data", (chunk) => {
|
|
6602
|
+
if (settled) return;
|
|
6603
|
+
buffer += chunk.toString();
|
|
6604
|
+
for (; ; ) {
|
|
6605
|
+
const newline = buffer.indexOf("\n");
|
|
6606
|
+
if (newline === -1) break;
|
|
6607
|
+
const line = buffer.slice(0, newline).trim();
|
|
6608
|
+
buffer = buffer.slice(newline + 1);
|
|
6609
|
+
if (!line) continue;
|
|
6610
|
+
const message = parseCodexJsonRpcLine(line);
|
|
6611
|
+
if (!message || !isJsonRpcResponse(message)) continue;
|
|
6612
|
+
if (message.id === initializeRequestId) {
|
|
6613
|
+
if (!hasJsonRpcField(message, "result") || !isCompatibleInitializeResult(message.result)) {
|
|
6614
|
+
finish(null);
|
|
6615
|
+
return;
|
|
6616
|
+
}
|
|
6617
|
+
sendNotification("initialized", {});
|
|
6618
|
+
requestModelPage(null);
|
|
6619
|
+
continue;
|
|
6620
|
+
}
|
|
6621
|
+
if (message.id === modelListRequestId) {
|
|
6622
|
+
if (!hasJsonRpcField(message, "result")) {
|
|
6623
|
+
finish(null);
|
|
6624
|
+
return;
|
|
6625
|
+
}
|
|
6626
|
+
const page = modelListPage(message.result);
|
|
6627
|
+
if (!page) {
|
|
6628
|
+
finish(null);
|
|
6629
|
+
return;
|
|
6630
|
+
}
|
|
6631
|
+
entries.push(...page.entries);
|
|
6632
|
+
if (page.nextCursor && pageCount < 5) {
|
|
6633
|
+
requestModelPage(page.nextCursor);
|
|
6634
|
+
continue;
|
|
6635
|
+
}
|
|
6636
|
+
finish(codexModelSetFromAppServerEntries(entries));
|
|
6637
|
+
return;
|
|
6638
|
+
}
|
|
6639
|
+
}
|
|
6640
|
+
});
|
|
6641
|
+
initializeRequestId = sendRequest("initialize", {
|
|
6642
|
+
clientInfo: { name: "slock-daemon", version: "1.0.0" },
|
|
6643
|
+
capabilities: { experimentalApi: true }
|
|
6644
|
+
});
|
|
6645
|
+
});
|
|
6646
|
+
}
|
|
6647
|
+
function detectCodexModels(home = resolveCodexHomeRootFromEnv()) {
|
|
6648
|
+
let cachePath = null;
|
|
6649
|
+
let configPath = null;
|
|
6650
|
+
for (const root of codexStateRootCandidates(home)) {
|
|
6651
|
+
const candidate = path7.join(root, "models_cache.json");
|
|
6652
|
+
if (existsSync5(candidate)) {
|
|
6653
|
+
cachePath = candidate;
|
|
6654
|
+
configPath = path7.join(root, "config.toml");
|
|
6655
|
+
break;
|
|
6656
|
+
}
|
|
6657
|
+
}
|
|
6658
|
+
if (!cachePath || !configPath) return null;
|
|
6135
6659
|
let models = [];
|
|
6136
6660
|
try {
|
|
6137
6661
|
const raw = readFileSync2(cachePath, "utf8");
|
|
@@ -6601,7 +7125,7 @@ function runCursorModelsCommand() {
|
|
|
6601
7125
|
// src/drivers/gemini.ts
|
|
6602
7126
|
import { execFileSync as execFileSync3, spawn as spawn6 } from "child_process";
|
|
6603
7127
|
import { existsSync as existsSync6 } from "fs";
|
|
6604
|
-
import
|
|
7128
|
+
import path8 from "path";
|
|
6605
7129
|
async function buildGeminiSpawnEnv(ctx, platform = process.platform) {
|
|
6606
7130
|
const { spawnEnv } = await prepareCliTransport(ctx, { NO_COLOR: "1" }, platform);
|
|
6607
7131
|
const launchEnvVars = runtimeConfigToLaunchFields(ctx.config).envVars;
|
|
@@ -6645,7 +7169,7 @@ function resolveGeminiSpawn(commandArgs, deps = {}) {
|
|
|
6645
7169
|
const execFileSyncFn = deps.execFileSyncFn ?? execFileSync3;
|
|
6646
7170
|
const existsSyncFn = deps.existsSyncFn ?? existsSync6;
|
|
6647
7171
|
const env = deps.env ?? process.env;
|
|
6648
|
-
const winPath =
|
|
7172
|
+
const winPath = path8.win32;
|
|
6649
7173
|
let geminiEntry = null;
|
|
6650
7174
|
try {
|
|
6651
7175
|
const globalRoot = normalizeExecOutput2(execFileSyncFn("npm", ["root", "-g"], {
|
|
@@ -6782,8 +7306,8 @@ var GeminiDriver = class {
|
|
|
6782
7306
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
6783
7307
|
import { spawn as spawn7 } from "child_process";
|
|
6784
7308
|
import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
6785
|
-
import
|
|
6786
|
-
import
|
|
7309
|
+
import os5 from "os";
|
|
7310
|
+
import path9 from "path";
|
|
6787
7311
|
var KIMI_WIRE_PROTOCOL_VERSION = "1.3";
|
|
6788
7312
|
var KIMI_SYSTEM_PROMPT_FILE = ".slock-kimi-system.md";
|
|
6789
7313
|
var KIMI_AGENT_FILE = ".slock-kimi-agent.yaml";
|
|
@@ -6830,8 +7354,8 @@ var KimiDriver = class {
|
|
|
6830
7354
|
this.sessionId = ctx.config.sessionId || randomUUID2();
|
|
6831
7355
|
this.sessionAnnounced = false;
|
|
6832
7356
|
this.promptRequestId = randomUUID2();
|
|
6833
|
-
const systemPromptPath =
|
|
6834
|
-
const agentFilePath =
|
|
7357
|
+
const systemPromptPath = path9.join(ctx.workingDirectory, KIMI_SYSTEM_PROMPT_FILE);
|
|
7358
|
+
const agentFilePath = path9.join(ctx.workingDirectory, KIMI_AGENT_FILE);
|
|
6835
7359
|
if (!isResume || !existsSync7(systemPromptPath)) {
|
|
6836
7360
|
writeFileSync3(systemPromptPath, ctx.prompt, "utf8");
|
|
6837
7361
|
}
|
|
@@ -6977,8 +7501,8 @@ var KimiDriver = class {
|
|
|
6977
7501
|
return detectKimiModels();
|
|
6978
7502
|
}
|
|
6979
7503
|
};
|
|
6980
|
-
function detectKimiModels(home =
|
|
6981
|
-
const configPath =
|
|
7504
|
+
function detectKimiModels(home = os5.homedir()) {
|
|
7505
|
+
const configPath = path9.join(home, ".kimi", "config.toml");
|
|
6982
7506
|
let raw;
|
|
6983
7507
|
try {
|
|
6984
7508
|
raw = readFileSync3(configPath, "utf8");
|
|
@@ -7006,8 +7530,8 @@ function detectKimiModels(home = os4.homedir()) {
|
|
|
7006
7530
|
// src/drivers/kimi-sdk.ts
|
|
7007
7531
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
7008
7532
|
import { EventEmitter } from "events";
|
|
7009
|
-
import { mkdirSync as
|
|
7010
|
-
import
|
|
7533
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync4 } from "fs";
|
|
7534
|
+
import path10 from "path";
|
|
7011
7535
|
import { createRequire as createRequire2 } from "module";
|
|
7012
7536
|
import {
|
|
7013
7537
|
createKimiHarness,
|
|
@@ -7032,7 +7556,7 @@ function createKimiSdkEventMappingState(sessionId = null) {
|
|
|
7032
7556
|
};
|
|
7033
7557
|
}
|
|
7034
7558
|
function buildKimiSessionDir(workingDirectory) {
|
|
7035
|
-
return
|
|
7559
|
+
return path10.join(workingDirectory, KIMI_SESSION_DIR);
|
|
7036
7560
|
}
|
|
7037
7561
|
function kimiErrorMessage(error) {
|
|
7038
7562
|
if (typeof error === "string" && error.trim()) return error.trim();
|
|
@@ -7155,12 +7679,12 @@ var KIMI_SDK_RUNTIME_SESSION_DESCRIPTOR = {
|
|
|
7155
7679
|
};
|
|
7156
7680
|
async function createKimiAgentSessionForContext(ctx, sessionId) {
|
|
7157
7681
|
const sessionDir = buildKimiSessionDir(ctx.workingDirectory);
|
|
7158
|
-
|
|
7682
|
+
mkdirSync4(sessionDir, { recursive: true });
|
|
7159
7683
|
const cliTransport = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
7160
7684
|
const spawnEnv = cliTransport.spawnEnv;
|
|
7161
7685
|
const wrapperPath = cliTransport.wrapperPath;
|
|
7162
|
-
const homeDir = spawnEnv.KIMI_HOME || (process.env.HOME ?
|
|
7163
|
-
|
|
7686
|
+
const homeDir = spawnEnv.KIMI_HOME || (process.env.HOME ? path10.join(process.env.HOME, ".kimi") : path10.join(ctx.workingDirectory, ".kimi"));
|
|
7687
|
+
mkdirSync4(homeDir, { recursive: true });
|
|
7164
7688
|
const harness = createKimiHarness({
|
|
7165
7689
|
homeDir,
|
|
7166
7690
|
identity: {
|
|
@@ -7384,7 +7908,7 @@ So instead of \`raft message send ...\`, run \`${this.wrapperPath} message send
|
|
|
7384
7908
|
};
|
|
7385
7909
|
function detectKimiSdkModels(home = resolveKimiHome(), ctx = {}) {
|
|
7386
7910
|
const span = ctx.span;
|
|
7387
|
-
const configPath =
|
|
7911
|
+
const configPath = path10.join(home, "config.toml");
|
|
7388
7912
|
const homeFromEnv = Boolean(process.env.KIMI_CODE_HOME);
|
|
7389
7913
|
const emit2 = (outcome, extra = {}) => {
|
|
7390
7914
|
span?.addEvent("daemon.kimi_sdk.models.config", {
|
|
@@ -7492,8 +8016,8 @@ var KimiSdkDriver = class {
|
|
|
7492
8016
|
// src/drivers/opencode.ts
|
|
7493
8017
|
import { spawn as spawn8, spawnSync as spawnSync2 } from "child_process";
|
|
7494
8018
|
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
|
|
7495
|
-
import
|
|
7496
|
-
import
|
|
8019
|
+
import os6 from "os";
|
|
8020
|
+
import path11 from "path";
|
|
7497
8021
|
var SLOCK_AGENT_NAME = "slock";
|
|
7498
8022
|
var NO_MESSAGE_PROMPT = "No new messages are pending. Stop now.";
|
|
7499
8023
|
var FIRST_MESSAGE_TASK_PREFIX = "First message task (system-triggered):";
|
|
@@ -7521,8 +8045,8 @@ function parseUserOpenCodeConfig(ctx) {
|
|
|
7521
8045
|
const raw = runtimeConfigToLaunchFields(ctx.config).envVars?.OPENCODE_CONFIG_CONTENT;
|
|
7522
8046
|
return parseOpenCodeConfigContent(raw);
|
|
7523
8047
|
}
|
|
7524
|
-
function readLocalOpenCodeConfig(home =
|
|
7525
|
-
const configPath =
|
|
8048
|
+
function readLocalOpenCodeConfig(home = os6.homedir()) {
|
|
8049
|
+
const configPath = path11.join(home, ".config", "opencode", "opencode.json");
|
|
7526
8050
|
try {
|
|
7527
8051
|
return parseOpenCodeConfigContent(readFileSync5(configPath, "utf8"));
|
|
7528
8052
|
} catch {
|
|
@@ -7582,7 +8106,7 @@ function mergeOpenCodeConfigs(localConfig, envConfig) {
|
|
|
7582
8106
|
}
|
|
7583
8107
|
};
|
|
7584
8108
|
}
|
|
7585
|
-
function buildOpenCodeConfig(ctx, home =
|
|
8109
|
+
function buildOpenCodeConfig(ctx, home = os6.homedir()) {
|
|
7586
8110
|
const userConfig = mergeOpenCodeConfigs(readLocalOpenCodeConfig(home), parseUserOpenCodeConfig(ctx));
|
|
7587
8111
|
const userAgents = recordField(userConfig.agent);
|
|
7588
8112
|
const userSlockAgent = recordField(userAgents[SLOCK_AGENT_NAME]);
|
|
@@ -7600,7 +8124,7 @@ function buildOpenCodeConfig(ctx, home = os5.homedir()) {
|
|
|
7600
8124
|
mcp: recordField(userConfig.mcp)
|
|
7601
8125
|
};
|
|
7602
8126
|
}
|
|
7603
|
-
async function buildOpenCodeLaunchOptions(ctx, home =
|
|
8127
|
+
async function buildOpenCodeLaunchOptions(ctx, home = os6.homedir(), version = null) {
|
|
7604
8128
|
const slock = await prepareCliTransport(ctx, { NO_COLOR: "1" });
|
|
7605
8129
|
const config = buildOpenCodeConfig(ctx, home);
|
|
7606
8130
|
const env = {
|
|
@@ -7699,7 +8223,7 @@ function formatOpenCodeLabelToken(token) {
|
|
|
7699
8223
|
if (/^\d/.test(token)) return token;
|
|
7700
8224
|
return normalized.charAt(0).toUpperCase() + normalized.slice(1);
|
|
7701
8225
|
}
|
|
7702
|
-
function detectOpenCodeModels(home =
|
|
8226
|
+
function detectOpenCodeModels(home = os6.homedir(), runCommand = runOpenCodeModelsCommand) {
|
|
7703
8227
|
const commandResult = runCommand(home);
|
|
7704
8228
|
if (commandResult.error || commandResult.status !== 0) return null;
|
|
7705
8229
|
return parseOpenCodeModelsOutput(commandResult.stdout);
|
|
@@ -7720,11 +8244,11 @@ function runOpenCodeModelsCommand(home, deps = {}) {
|
|
|
7720
8244
|
};
|
|
7721
8245
|
}
|
|
7722
8246
|
function isWindowsCommandShim(commandPath) {
|
|
7723
|
-
const ext =
|
|
8247
|
+
const ext = path11.win32.extname(commandPath).toLowerCase();
|
|
7724
8248
|
return ext === ".cmd" || ext === ".bat";
|
|
7725
8249
|
}
|
|
7726
8250
|
function opencodePackageEntryCandidates(packageRoot) {
|
|
7727
|
-
const winPath =
|
|
8251
|
+
const winPath = path11.win32;
|
|
7728
8252
|
return [
|
|
7729
8253
|
winPath.join(packageRoot, "bin", "opencode.exe"),
|
|
7730
8254
|
winPath.join(packageRoot, "bin", "opencode.js"),
|
|
@@ -7733,7 +8257,7 @@ function opencodePackageEntryCandidates(packageRoot) {
|
|
|
7733
8257
|
];
|
|
7734
8258
|
}
|
|
7735
8259
|
function openCodeSpecForEntry(entry, commandArgs) {
|
|
7736
|
-
if (
|
|
8260
|
+
if (path11.win32.extname(entry).toLowerCase() === ".exe") {
|
|
7737
8261
|
return { command: entry, args: commandArgs, shell: false };
|
|
7738
8262
|
}
|
|
7739
8263
|
return { command: process.execPath, args: [entry, ...commandArgs], shell: false };
|
|
@@ -7742,7 +8266,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
|
7742
8266
|
const existsSyncFn = deps.existsSyncFn ?? existsSync8;
|
|
7743
8267
|
const execFileSyncFn = deps.execFileSyncFn;
|
|
7744
8268
|
const env = deps.env ?? process.env;
|
|
7745
|
-
const winPath =
|
|
8269
|
+
const winPath = path11.win32;
|
|
7746
8270
|
const candidates = [];
|
|
7747
8271
|
if (execFileSyncFn) {
|
|
7748
8272
|
try {
|
|
@@ -7770,7 +8294,7 @@ function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
|
7770
8294
|
function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
7771
8295
|
if (!isWindowsCommandShim(commandPath)) return [];
|
|
7772
8296
|
const readFileSyncFn = deps.readFileSyncFn ?? readFileSync5;
|
|
7773
|
-
const commandDir =
|
|
8297
|
+
const commandDir = path11.win32.dirname(commandPath);
|
|
7774
8298
|
let raw;
|
|
7775
8299
|
try {
|
|
7776
8300
|
raw = String(readFileSyncFn(commandPath, "utf8"));
|
|
@@ -7781,7 +8305,7 @@ function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
|
7781
8305
|
const dp0Pattern = /%~dp0\\?([^"\r\n]*?opencode\.(?:exe|js|mjs|cjs))/gi;
|
|
7782
8306
|
for (const match of raw.matchAll(dp0Pattern)) {
|
|
7783
8307
|
const relative = match[1]?.replace(/^\\+/, "");
|
|
7784
|
-
if (relative) candidates.push(
|
|
8308
|
+
if (relative) candidates.push(path11.win32.normalize(path11.win32.join(commandDir, relative)));
|
|
7785
8309
|
}
|
|
7786
8310
|
return candidates;
|
|
7787
8311
|
}
|
|
@@ -7795,7 +8319,7 @@ function resolveOpenCodeSpawn(commandArgs, deps = {}) {
|
|
|
7795
8319
|
};
|
|
7796
8320
|
}
|
|
7797
8321
|
const command = resolveCommandOnPath("opencode", deps);
|
|
7798
|
-
if (command &&
|
|
8322
|
+
if (command && path11.win32.extname(command).toLowerCase() === ".exe") {
|
|
7799
8323
|
return { command, args: commandArgs, shell: false };
|
|
7800
8324
|
}
|
|
7801
8325
|
const packageEntry = resolveWindowsOpenCodePackageEntry(command, deps);
|
|
@@ -7900,7 +8424,7 @@ var OpenCodeDriver = class {
|
|
|
7900
8424
|
if (unsupportedMessage) {
|
|
7901
8425
|
throw new Error(unsupportedMessage);
|
|
7902
8426
|
}
|
|
7903
|
-
const launch = await buildOpenCodeLaunchOptions(ctx,
|
|
8427
|
+
const launch = await buildOpenCodeLaunchOptions(ctx, os6.homedir(), version);
|
|
7904
8428
|
const spawnSpec = resolveOpenCodeSpawn(launch.args);
|
|
7905
8429
|
const proc = spawn8(spawnSpec.command, spawnSpec.args, {
|
|
7906
8430
|
cwd: ctx.workingDirectory,
|
|
@@ -7967,8 +8491,8 @@ var OpenCodeDriver = class {
|
|
|
7967
8491
|
// src/drivers/pi.ts
|
|
7968
8492
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
7969
8493
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
7970
|
-
import { mkdirSync as
|
|
7971
|
-
import
|
|
8494
|
+
import { mkdirSync as mkdirSync5, readdirSync as readdirSync2 } from "fs";
|
|
8495
|
+
import path12 from "path";
|
|
7972
8496
|
import {
|
|
7973
8497
|
AuthStorage,
|
|
7974
8498
|
createBashTool,
|
|
@@ -7995,7 +8519,7 @@ function createPiSdkEventMappingState(sessionId = null) {
|
|
|
7995
8519
|
};
|
|
7996
8520
|
}
|
|
7997
8521
|
function buildPiSessionDir(workingDirectory) {
|
|
7998
|
-
return
|
|
8522
|
+
return path12.join(workingDirectory, PI_SESSION_DIR);
|
|
7999
8523
|
}
|
|
8000
8524
|
async function buildPiSpawnEnv(ctx) {
|
|
8001
8525
|
return (await prepareCliTransport(ctx, { NO_COLOR: "1" })).spawnEnv;
|
|
@@ -8017,7 +8541,7 @@ function findPiSessionFile(sessionDir, sessionId) {
|
|
|
8017
8541
|
}
|
|
8018
8542
|
const suffix = `_${sessionId}.jsonl`;
|
|
8019
8543
|
const match = entries.find((entry) => entry.endsWith(suffix));
|
|
8020
|
-
return match ?
|
|
8544
|
+
return match ? path12.join(sessionDir, match) : null;
|
|
8021
8545
|
}
|
|
8022
8546
|
function detectPiModelsFromRegistry(modelRegistry) {
|
|
8023
8547
|
const models = [];
|
|
@@ -8235,7 +8759,7 @@ var PI_IDLE_PROMPT_RETRY_MS = 25;
|
|
|
8235
8759
|
var PI_IDLE_PROMPT_MAX_WAIT_MS = 1e3;
|
|
8236
8760
|
async function createPiAgentSessionForContext(ctx, sessionId) {
|
|
8237
8761
|
const sessionDir = buildPiSessionDir(ctx.workingDirectory);
|
|
8238
|
-
|
|
8762
|
+
mkdirSync5(sessionDir, { recursive: true });
|
|
8239
8763
|
const launchRuntimeFields = runtimeConfigToLaunchFields(ctx.config);
|
|
8240
8764
|
const requestedModel = launchRuntimeFields.model || "default";
|
|
8241
8765
|
const traceSpan = ctx.tracer?.startSpan("daemon.pi.session.create", {
|
|
@@ -8253,7 +8777,7 @@ async function createPiAgentSessionForContext(ctx, sessionId) {
|
|
|
8253
8777
|
try {
|
|
8254
8778
|
const spawnEnv = await buildPiSpawnEnv(ctx);
|
|
8255
8779
|
const agentDir = spawnEnv.PI_CODING_AGENT_DIR || getAgentDir();
|
|
8256
|
-
const authStorage = AuthStorage.create(
|
|
8780
|
+
const authStorage = AuthStorage.create(path12.join(agentDir, "auth.json"));
|
|
8257
8781
|
const settingsManager = SettingsManager.create(ctx.workingDirectory, agentDir);
|
|
8258
8782
|
const services = await createAgentSessionServices({
|
|
8259
8783
|
cwd: ctx.workingDirectory,
|
|
@@ -8652,6 +9176,9 @@ var ChildProcessRuntimeSession = class {
|
|
|
8652
9176
|
get currentSessionId() {
|
|
8653
9177
|
return this.driver.currentSessionId;
|
|
8654
9178
|
}
|
|
9179
|
+
get currentRuntimeHomeDir() {
|
|
9180
|
+
return this.driver.currentRuntimeHomeDir;
|
|
9181
|
+
}
|
|
8655
9182
|
get exitCode() {
|
|
8656
9183
|
return this.process?.exitCode ?? null;
|
|
8657
9184
|
}
|
|
@@ -8775,7 +9302,7 @@ function getDriver(runtimeId) {
|
|
|
8775
9302
|
|
|
8776
9303
|
// src/workspaces.ts
|
|
8777
9304
|
import { readdir, rm, stat } from "fs/promises";
|
|
8778
|
-
import
|
|
9305
|
+
import path13 from "path";
|
|
8779
9306
|
function isValidWorkspaceDirectoryName(directoryName) {
|
|
8780
9307
|
return !directoryName.includes("/") && !directoryName.includes("\\") && !directoryName.includes("..");
|
|
8781
9308
|
}
|
|
@@ -8783,7 +9310,7 @@ function resolveWorkspaceDirectoryPath(dataDir, directoryName) {
|
|
|
8783
9310
|
if (!isValidWorkspaceDirectoryName(directoryName)) {
|
|
8784
9311
|
return null;
|
|
8785
9312
|
}
|
|
8786
|
-
return
|
|
9313
|
+
return path13.join(dataDir, directoryName);
|
|
8787
9314
|
}
|
|
8788
9315
|
function emptyWorkspaceDirectorySummary(latestMtime = /* @__PURE__ */ new Date(0)) {
|
|
8789
9316
|
return {
|
|
@@ -8832,7 +9359,7 @@ async function summarizeWorkspaceDirectory(dirPath) {
|
|
|
8832
9359
|
return summary;
|
|
8833
9360
|
}
|
|
8834
9361
|
const childSummaries = await Promise.all(
|
|
8835
|
-
entries.map((entry) => summarizeWorkspaceEntry(
|
|
9362
|
+
entries.map((entry) => summarizeWorkspaceEntry(path13.join(dirPath, entry.name), entry))
|
|
8836
9363
|
);
|
|
8837
9364
|
for (const childSummary of childSummaries) {
|
|
8838
9365
|
summary = mergeWorkspaceDirectorySummaries(summary, childSummary);
|
|
@@ -8851,7 +9378,7 @@ async function scanWorkspaceDirectories(dataDir) {
|
|
|
8851
9378
|
if (!entry.isDirectory()) {
|
|
8852
9379
|
return null;
|
|
8853
9380
|
}
|
|
8854
|
-
const dirPath =
|
|
9381
|
+
const dirPath = path13.join(dataDir, entry.name);
|
|
8855
9382
|
try {
|
|
8856
9383
|
const summary = await summarizeWorkspaceDirectory(dirPath);
|
|
8857
9384
|
return {
|
|
@@ -9400,17 +9927,17 @@ function allowedTranscriptRootsForRuntime(runtime, homeDir, workspaceDir) {
|
|
|
9400
9927
|
const roots = [workspaceDir];
|
|
9401
9928
|
switch (runtime) {
|
|
9402
9929
|
case "claude":
|
|
9403
|
-
roots.push(
|
|
9930
|
+
roots.push(path14.join(homeDir, ".claude"));
|
|
9404
9931
|
break;
|
|
9405
9932
|
case "codex":
|
|
9406
|
-
roots.push(
|
|
9933
|
+
roots.push(homeDir, path14.join(homeDir, ".codex"));
|
|
9407
9934
|
break;
|
|
9408
9935
|
case "kimi":
|
|
9409
9936
|
case "kimi-sdk":
|
|
9410
|
-
roots.push(
|
|
9937
|
+
roots.push(path14.join(homeDir, ".kimi"));
|
|
9411
9938
|
break;
|
|
9412
9939
|
case "pi":
|
|
9413
|
-
roots.push(
|
|
9940
|
+
roots.push(path14.join(homeDir, ".pi"), path14.join(homeDir, ".pi", "agent"));
|
|
9414
9941
|
break;
|
|
9415
9942
|
}
|
|
9416
9943
|
return roots;
|
|
@@ -9421,8 +9948,8 @@ async function isPathWithinAllowedRoots(filePath, roots) {
|
|
|
9421
9948
|
for (const root of roots) {
|
|
9422
9949
|
const realRoot = await realpath(root).catch(() => null);
|
|
9423
9950
|
if (!realRoot) continue;
|
|
9424
|
-
const rel =
|
|
9425
|
-
if (!rel.startsWith("..") && !
|
|
9951
|
+
const rel = path14.relative(realRoot, real);
|
|
9952
|
+
if (!rel.startsWith("..") && !path14.isAbsolute(rel)) return true;
|
|
9426
9953
|
}
|
|
9427
9954
|
return false;
|
|
9428
9955
|
}
|
|
@@ -9469,12 +9996,12 @@ function findSessionJsonl(root, predicate) {
|
|
|
9469
9996
|
for (const entry of entries) {
|
|
9470
9997
|
if (++visited > maxEntries) return null;
|
|
9471
9998
|
if (!entry.isFile() || !predicate(entry.name)) continue;
|
|
9472
|
-
return
|
|
9999
|
+
return path14.join(dir, entry.name);
|
|
9473
10000
|
}
|
|
9474
10001
|
for (const entry of entries) {
|
|
9475
10002
|
if (++visited > maxEntries) return null;
|
|
9476
10003
|
if (!entry.isDirectory()) continue;
|
|
9477
|
-
const found = visit(
|
|
10004
|
+
const found = visit(path14.join(dir, entry.name), depth - 1);
|
|
9478
10005
|
if (found) return found;
|
|
9479
10006
|
}
|
|
9480
10007
|
return null;
|
|
@@ -9482,7 +10009,7 @@ function findSessionJsonl(root, predicate) {
|
|
|
9482
10009
|
return visit(root, maxDepth);
|
|
9483
10010
|
}
|
|
9484
10011
|
function findKimiSdkSessionDir(sessionId, agentId, homeDir) {
|
|
9485
|
-
const indexPath =
|
|
10012
|
+
const indexPath = path14.join(homeDir, ".kimi", "session_index.jsonl");
|
|
9486
10013
|
try {
|
|
9487
10014
|
const index = readFileSync6(indexPath, "utf8");
|
|
9488
10015
|
for (const line of index.split("\n")) {
|
|
@@ -9497,12 +10024,12 @@ function findKimiSdkSessionDir(sessionId, agentId, homeDir) {
|
|
|
9497
10024
|
}
|
|
9498
10025
|
} catch {
|
|
9499
10026
|
}
|
|
9500
|
-
const sessionsRoot =
|
|
10027
|
+
const sessionsRoot = path14.join(homeDir, ".kimi", "sessions");
|
|
9501
10028
|
try {
|
|
9502
10029
|
const prefix = agentId ? `wd_${agentId}_` : `wd_`;
|
|
9503
10030
|
for (const entry of readdirSync3(sessionsRoot, { withFileTypes: true })) {
|
|
9504
10031
|
if (!entry.isDirectory() || !entry.name.startsWith(prefix)) continue;
|
|
9505
|
-
const candidate =
|
|
10032
|
+
const candidate = path14.join(sessionsRoot, entry.name, `session_${sessionId}`);
|
|
9506
10033
|
if (existsSync9(candidate)) return candidate;
|
|
9507
10034
|
}
|
|
9508
10035
|
} catch {
|
|
@@ -9511,16 +10038,16 @@ function findKimiSdkSessionDir(sessionId, agentId, homeDir) {
|
|
|
9511
10038
|
}
|
|
9512
10039
|
function findPiSessionFile2(sessionId, workingDirectory, homeDir) {
|
|
9513
10040
|
if (workingDirectory) {
|
|
9514
|
-
const piSessionsDir =
|
|
10041
|
+
const piSessionsDir = path14.join(workingDirectory, ".pi-sessions");
|
|
9515
10042
|
try {
|
|
9516
|
-
const files = readdirSync3(piSessionsDir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => ({ name: e.name, path:
|
|
10043
|
+
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
10044
|
if (files[0]) return files[0].path;
|
|
9518
10045
|
} catch {
|
|
9519
10046
|
}
|
|
9520
10047
|
}
|
|
9521
10048
|
const legacyRoots = [
|
|
9522
|
-
|
|
9523
|
-
|
|
10049
|
+
path14.join(homeDir, ".pi", "agent"),
|
|
10050
|
+
path14.join(homeDir, ".pi")
|
|
9524
10051
|
];
|
|
9525
10052
|
for (const root of legacyRoots) {
|
|
9526
10053
|
const found = findSessionJsonl(root, (filename) => filename.endsWith(".jsonl") && filename.includes(sessionId));
|
|
@@ -9534,9 +10061,9 @@ function safeSessionFilename(value) {
|
|
|
9534
10061
|
}
|
|
9535
10062
|
function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
9536
10063
|
try {
|
|
9537
|
-
const dir =
|
|
9538
|
-
|
|
9539
|
-
const filePath =
|
|
10064
|
+
const dir = path14.join(fallbackDir, ".slock", "runtime-sessions");
|
|
10065
|
+
mkdirSync6(dir, { recursive: true });
|
|
10066
|
+
const filePath = path14.join(dir, `${runtime}-${safeSessionFilename(sessionId)}.jsonl`);
|
|
9540
10067
|
writeFileSync4(filePath, JSON.stringify({
|
|
9541
10068
|
type: "runtime_session_handoff",
|
|
9542
10069
|
runtime,
|
|
@@ -9555,27 +10082,40 @@ function writeRuntimeSessionHandoff(runtime, sessionId, fallbackDir) {
|
|
|
9555
10082
|
return null;
|
|
9556
10083
|
}
|
|
9557
10084
|
}
|
|
9558
|
-
function resolveRuntimeHomeDir(config, defaultHomeDir, workspacePath) {
|
|
10085
|
+
function resolveRuntimeHomeDir(config, defaultHomeDir, workspacePath, opts = {}) {
|
|
9559
10086
|
if (isClaudeCustomProviderConfig(config)) {
|
|
9560
10087
|
return getClaudeProviderStatePaths(workspacePath).home;
|
|
9561
10088
|
}
|
|
10089
|
+
if (config.runtime === "codex") {
|
|
10090
|
+
return resolveCodexHomeRootFromConfig(config, defaultHomeDir, workspacePath, process.env, opts);
|
|
10091
|
+
}
|
|
9562
10092
|
return defaultHomeDir;
|
|
9563
10093
|
}
|
|
9564
|
-
function ensureRuntimeHomeDir(config, defaultHomeDir, workspacePath) {
|
|
10094
|
+
function ensureRuntimeHomeDir(config, defaultHomeDir, workspacePath, opts = {}) {
|
|
9565
10095
|
if (isClaudeCustomProviderConfig(config)) {
|
|
9566
10096
|
return ensureClaudeProviderStatePaths(workspacePath).home;
|
|
9567
10097
|
}
|
|
10098
|
+
if (config.runtime === "codex") {
|
|
10099
|
+
const home = resolveCodexHomeRootFromConfig(config, defaultHomeDir, workspacePath, process.env, opts);
|
|
10100
|
+
if (opts.agentId) {
|
|
10101
|
+
mkdirSync6(home, { recursive: true });
|
|
10102
|
+
}
|
|
10103
|
+
return home;
|
|
10104
|
+
}
|
|
9568
10105
|
return defaultHomeDir;
|
|
9569
10106
|
}
|
|
9570
|
-
function resolveRuntimeSessionRef(runtime, sessionId, homeDir =
|
|
10107
|
+
function resolveRuntimeSessionRef(runtime, sessionId, homeDir = os7.homedir(), fallbackDir, opts) {
|
|
9571
10108
|
let resolvedPath = null;
|
|
9572
10109
|
let lookupMethod = "none";
|
|
9573
10110
|
if (runtime === "claude") {
|
|
9574
10111
|
lookupMethod = "claude_jsonl";
|
|
9575
|
-
resolvedPath = findSessionJsonl(
|
|
10112
|
+
resolvedPath = findSessionJsonl(path14.join(homeDir, ".claude", "projects"), (filename) => filename === `${sessionId}.jsonl`);
|
|
9576
10113
|
} else if (runtime === "codex") {
|
|
9577
10114
|
lookupMethod = "codex_jsonl";
|
|
9578
|
-
|
|
10115
|
+
for (const root of codexSessionRootCandidates(homeDir)) {
|
|
10116
|
+
resolvedPath = findSessionJsonl(root, (filename) => filename.endsWith(".jsonl") && filename.includes(sessionId));
|
|
10117
|
+
if (resolvedPath) break;
|
|
10118
|
+
}
|
|
9579
10119
|
} else if (runtime === "kimi-sdk" || runtime === "kimi") {
|
|
9580
10120
|
lookupMethod = "kimi_sdk_index";
|
|
9581
10121
|
resolvedPath = findKimiSdkSessionDir(sessionId, opts?.agentId, homeDir);
|
|
@@ -10312,6 +10852,28 @@ function runtimeDiagnosticTraceAttrs(event) {
|
|
|
10312
10852
|
session_id_present: Boolean(event.sessionId)
|
|
10313
10853
|
};
|
|
10314
10854
|
}
|
|
10855
|
+
function runtimeRecoveryTrajectoryEntry(event) {
|
|
10856
|
+
const lines = [event.message];
|
|
10857
|
+
if (event.details && event.details !== event.message) {
|
|
10858
|
+
lines.push(event.details);
|
|
10859
|
+
}
|
|
10860
|
+
return {
|
|
10861
|
+
kind: "system",
|
|
10862
|
+
title: "Codex resume recovery",
|
|
10863
|
+
text: lines.join("\n")
|
|
10864
|
+
};
|
|
10865
|
+
}
|
|
10866
|
+
function runtimeRecoveryTraceAttrs(event) {
|
|
10867
|
+
return {
|
|
10868
|
+
kind: event.kind,
|
|
10869
|
+
source: event.source,
|
|
10870
|
+
resume_error_class: event.resumeErrorClass,
|
|
10871
|
+
recovery_action: event.recoveryAction,
|
|
10872
|
+
requested_session_id_present: Boolean(event.requestedSessionId),
|
|
10873
|
+
message_present: Boolean(event.message),
|
|
10874
|
+
details_present: Boolean(event.details)
|
|
10875
|
+
};
|
|
10876
|
+
}
|
|
10315
10877
|
function currentErrorCandidates(ap) {
|
|
10316
10878
|
return [
|
|
10317
10879
|
ap.runtimeErrorSinceProgress ? ap.lastRuntimeError : null,
|
|
@@ -10635,6 +11197,7 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
10635
11197
|
sendToServer;
|
|
10636
11198
|
daemonApiKey;
|
|
10637
11199
|
serverUrl;
|
|
11200
|
+
slockHome;
|
|
10638
11201
|
dataDir;
|
|
10639
11202
|
runtimeSessionHomeDir;
|
|
10640
11203
|
driverResolver;
|
|
@@ -10664,8 +11227,9 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
10664
11227
|
this.sendToServer = sendToServer;
|
|
10665
11228
|
this.daemonApiKey = daemonApiKey;
|
|
10666
11229
|
this.serverUrl = opts.serverUrl;
|
|
10667
|
-
this.
|
|
10668
|
-
this.
|
|
11230
|
+
this.slockHome = opts.slockHome ? path14.resolve(opts.slockHome) : resolveSlockHome();
|
|
11231
|
+
this.dataDir = opts.dataDir || resolveSlockHomePath("agents", this.slockHome);
|
|
11232
|
+
this.runtimeSessionHomeDir = opts.runtimeSessionHomeDir || os7.homedir();
|
|
10669
11233
|
this.driverResolver = opts.driverResolver || getDriver;
|
|
10670
11234
|
this.defaultAgentEnvVarsProvider = opts.defaultAgentEnvVarsProvider || null;
|
|
10671
11235
|
this.tracer = opts.tracer ?? noopTracer;
|
|
@@ -10794,6 +11358,70 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
10794
11358
|
this.sendStdinNotification(agentId);
|
|
10795
11359
|
}, delayMs);
|
|
10796
11360
|
}
|
|
11361
|
+
flushAsyncRejectedIdleDelivery(agentId) {
|
|
11362
|
+
const ap = this.agents.get(agentId);
|
|
11363
|
+
if (!ap) return false;
|
|
11364
|
+
const count = ap.notifications.takePendingAndClearTimer();
|
|
11365
|
+
if (count === 0) return false;
|
|
11366
|
+
if (!ap.driver.supportsStdinNotification || !ap.sessionId || ap.inbox.length === 0) {
|
|
11367
|
+
ap.notifications.add(count);
|
|
11368
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery.async_rejected.retry", {
|
|
11369
|
+
agentId,
|
|
11370
|
+
runtime: ap.config.runtime,
|
|
11371
|
+
model: ap.config.model,
|
|
11372
|
+
launchId: ap.launchId || void 0,
|
|
11373
|
+
mode: "idle",
|
|
11374
|
+
outcome: "queued_without_stdin",
|
|
11375
|
+
inbox_count: ap.inbox.length,
|
|
11376
|
+
pending_notification_count: ap.notifications.pendingCount,
|
|
11377
|
+
session_id_present: Boolean(ap.sessionId),
|
|
11378
|
+
supports_stdin_notification: ap.driver.supportsStdinNotification
|
|
11379
|
+
});
|
|
11380
|
+
return false;
|
|
11381
|
+
}
|
|
11382
|
+
if (!this.isApmIdle(ap)) {
|
|
11383
|
+
ap.notifications.add(count);
|
|
11384
|
+
return this.sendStdinNotification(agentId, { forceUnsupportedRetry: true });
|
|
11385
|
+
}
|
|
11386
|
+
ap.notifications.pruneContributedToPending(ap.inbox, ap.sessionId);
|
|
11387
|
+
const messages = ap.notifications.filterUncontributedMessages(ap.inbox, ap.sessionId);
|
|
11388
|
+
if (messages.length === 0) {
|
|
11389
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery.async_rejected.retry", {
|
|
11390
|
+
agentId,
|
|
11391
|
+
runtime: ap.config.runtime,
|
|
11392
|
+
model: ap.config.model,
|
|
11393
|
+
launchId: ap.launchId || void 0,
|
|
11394
|
+
mode: "idle",
|
|
11395
|
+
outcome: "suppressed_already_contributed",
|
|
11396
|
+
inbox_count: ap.inbox.length,
|
|
11397
|
+
pending_notification_count: count,
|
|
11398
|
+
session_id_present: true
|
|
11399
|
+
});
|
|
11400
|
+
return false;
|
|
11401
|
+
}
|
|
11402
|
+
this.commitApmIdleState(agentId, ap, false);
|
|
11403
|
+
this.startRuntimeTrace(agentId, ap, "async-rejected-idle-delivery-retry", messages);
|
|
11404
|
+
this.broadcastActivity(agentId, "working", "Message received");
|
|
11405
|
+
const accepted = this.deliverInboxUpdateViaStdin(
|
|
11406
|
+
agentId,
|
|
11407
|
+
ap,
|
|
11408
|
+
messages,
|
|
11409
|
+
"idle",
|
|
11410
|
+
"async_rejected_idle_delivery_retry"
|
|
11411
|
+
);
|
|
11412
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery.async_rejected.retry", {
|
|
11413
|
+
agentId,
|
|
11414
|
+
runtime: ap.config.runtime,
|
|
11415
|
+
model: ap.config.model,
|
|
11416
|
+
launchId: ap.launchId || void 0,
|
|
11417
|
+
mode: "idle",
|
|
11418
|
+
outcome: accepted ? "written" : "not_written",
|
|
11419
|
+
inbox_count: ap.inbox.length,
|
|
11420
|
+
messages_count: messages.length,
|
|
11421
|
+
session_id_present: true
|
|
11422
|
+
});
|
|
11423
|
+
return accepted;
|
|
11424
|
+
}
|
|
10797
11425
|
isApmIdle(ap) {
|
|
10798
11426
|
return ap.gatedSteering.isIdle;
|
|
10799
11427
|
}
|
|
@@ -11252,6 +11880,23 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
11252
11880
|
...runtimeDiagnosticTraceAttrs(event)
|
|
11253
11881
|
});
|
|
11254
11882
|
}
|
|
11883
|
+
recordRuntimeRecoveryActivity(agentId, ap, event) {
|
|
11884
|
+
this.sendToServer({
|
|
11885
|
+
type: "agent:activity",
|
|
11886
|
+
agentId,
|
|
11887
|
+
activity: ap.lastActivity || "online",
|
|
11888
|
+
detail: ap.lastActivityDetail || "",
|
|
11889
|
+
entries: [runtimeRecoveryTrajectoryEntry(event)],
|
|
11890
|
+
launchId: ap.launchId || void 0,
|
|
11891
|
+
clientSeq: this.nextActivityClientSeq(agentId)
|
|
11892
|
+
});
|
|
11893
|
+
this.recordDaemonTrace("daemon.runtime.recovery.visible", {
|
|
11894
|
+
agentId,
|
|
11895
|
+
launchId: ap.launchId || void 0,
|
|
11896
|
+
runtime: ap.config.runtime,
|
|
11897
|
+
...runtimeRecoveryTraceAttrs(event)
|
|
11898
|
+
});
|
|
11899
|
+
}
|
|
11255
11900
|
recordDaemonTrace(name, attrs, status = "ok", parentTraceparent) {
|
|
11256
11901
|
const span = this.tracer.startSpan(name, {
|
|
11257
11902
|
parent: parseTraceparent(parentTraceparent),
|
|
@@ -11589,26 +12234,26 @@ var AgentProcessManager = class _AgentProcessManager {
|
|
|
11589
12234
|
let pendingStartRebind;
|
|
11590
12235
|
const originalLaunchId = launchId || null;
|
|
11591
12236
|
try {
|
|
11592
|
-
const agentDataDir =
|
|
12237
|
+
const agentDataDir = path14.join(this.dataDir, agentId);
|
|
11593
12238
|
await mkdir(agentDataDir, { recursive: true });
|
|
11594
12239
|
const initialRuntimeConfig = withLocalRuntimeContext(config, agentId, agentDataDir);
|
|
11595
|
-
const memoryMdPath =
|
|
12240
|
+
const memoryMdPath = path14.join(agentDataDir, "MEMORY.md");
|
|
11596
12241
|
try {
|
|
11597
12242
|
await access(memoryMdPath);
|
|
11598
12243
|
} catch {
|
|
11599
12244
|
const initialMemoryMd = buildInitialMemoryMd(initialRuntimeConfig);
|
|
11600
12245
|
await writeFile(memoryMdPath, initialMemoryMd);
|
|
11601
12246
|
}
|
|
11602
|
-
const notesDir =
|
|
12247
|
+
const notesDir = path14.join(agentDataDir, "notes");
|
|
11603
12248
|
await mkdir(notesDir, { recursive: true });
|
|
11604
12249
|
if (getOnboardingSeedMode(config) === FIRST_CINDY_SEED_MODE) {
|
|
11605
12250
|
const seedFiles = buildOnboardingSeedFiles();
|
|
11606
12251
|
for (const { relativePath, content } of seedFiles) {
|
|
11607
|
-
const fullPath =
|
|
12252
|
+
const fullPath = path14.join(agentDataDir, relativePath);
|
|
11608
12253
|
try {
|
|
11609
12254
|
await access(fullPath);
|
|
11610
12255
|
} catch {
|
|
11611
|
-
await mkdir(
|
|
12256
|
+
await mkdir(path14.dirname(fullPath), { recursive: true });
|
|
11612
12257
|
await writeFile(fullPath, content);
|
|
11613
12258
|
}
|
|
11614
12259
|
}
|
|
@@ -11762,6 +12407,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
11762
12407
|
workingDirectory: agentDataDir,
|
|
11763
12408
|
slockCliPath: this.slockCliPath,
|
|
11764
12409
|
daemonApiKey: this.daemonApiKey,
|
|
12410
|
+
slockHome: this.slockHome,
|
|
11765
12411
|
launchId: effectiveLaunchId,
|
|
11766
12412
|
agentCredentialProxyInboxCoordinator: this.createAgentProxyInboxCoordinator(agentId),
|
|
11767
12413
|
cliTransportTraceDir: this.cliTransportTraceDir,
|
|
@@ -12921,7 +13567,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
12921
13567
|
return true;
|
|
12922
13568
|
}
|
|
12923
13569
|
async resetWorkspace(agentId) {
|
|
12924
|
-
const agentDataDir =
|
|
13570
|
+
const agentDataDir = path14.join(this.dataDir, agentId);
|
|
12925
13571
|
try {
|
|
12926
13572
|
await rm2(agentDataDir, { recursive: true, force: true });
|
|
12927
13573
|
logger.info(`[Agent ${agentId}] Workspace reset complete (${agentDataDir})`);
|
|
@@ -12981,9 +13627,9 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
12981
13627
|
}
|
|
12982
13628
|
return result;
|
|
12983
13629
|
}
|
|
12984
|
-
buildRuntimeProfileReport(agentId, config, sessionId, launchId) {
|
|
12985
|
-
const workspacePath =
|
|
12986
|
-
const runtimeHomeDir = resolveRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspacePath);
|
|
13630
|
+
buildRuntimeProfileReport(agentId, config, sessionId, launchId, observedRuntimeHomeDir) {
|
|
13631
|
+
const workspacePath = path14.join(this.dataDir, agentId);
|
|
13632
|
+
const runtimeHomeDir = observedRuntimeHomeDir || resolveRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspacePath, { agentId, slockHome: this.slockHome });
|
|
12987
13633
|
return {
|
|
12988
13634
|
agentId,
|
|
12989
13635
|
launchId,
|
|
@@ -13004,7 +13650,13 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13004
13650
|
getAgentRuntimeProfileReport(agentId) {
|
|
13005
13651
|
const running = this.agents.get(agentId);
|
|
13006
13652
|
if (running) {
|
|
13007
|
-
return this.buildRuntimeProfileReport(
|
|
13653
|
+
return this.buildRuntimeProfileReport(
|
|
13654
|
+
agentId,
|
|
13655
|
+
running.config,
|
|
13656
|
+
running.sessionId,
|
|
13657
|
+
running.launchId,
|
|
13658
|
+
running.runtime.currentRuntimeHomeDir
|
|
13659
|
+
);
|
|
13008
13660
|
}
|
|
13009
13661
|
const idle = this.idleAgentConfigs.get(agentId);
|
|
13010
13662
|
if (idle) {
|
|
@@ -13277,7 +13929,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13277
13929
|
}
|
|
13278
13930
|
// Workspace file browsing
|
|
13279
13931
|
async getFileTree(agentId, dirPath) {
|
|
13280
|
-
const agentDir =
|
|
13932
|
+
const agentDir = path14.join(this.dataDir, agentId);
|
|
13281
13933
|
try {
|
|
13282
13934
|
await stat2(agentDir);
|
|
13283
13935
|
} catch {
|
|
@@ -13285,8 +13937,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13285
13937
|
}
|
|
13286
13938
|
let targetDir = agentDir;
|
|
13287
13939
|
if (dirPath) {
|
|
13288
|
-
const resolved =
|
|
13289
|
-
if (!resolved.startsWith(agentDir +
|
|
13940
|
+
const resolved = path14.resolve(agentDir, dirPath);
|
|
13941
|
+
if (!resolved.startsWith(agentDir + path14.sep) && resolved !== agentDir) {
|
|
13290
13942
|
return [];
|
|
13291
13943
|
}
|
|
13292
13944
|
targetDir = resolved;
|
|
@@ -13294,14 +13946,14 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13294
13946
|
return this.listDirectoryChildren(targetDir, agentDir);
|
|
13295
13947
|
}
|
|
13296
13948
|
async readFile(agentId, filePath) {
|
|
13297
|
-
const agentDir =
|
|
13298
|
-
const resolved =
|
|
13299
|
-
if (!resolved.startsWith(agentDir +
|
|
13949
|
+
const agentDir = path14.join(this.dataDir, agentId);
|
|
13950
|
+
const resolved = path14.resolve(agentDir, filePath);
|
|
13951
|
+
if (!resolved.startsWith(agentDir + path14.sep) && resolved !== agentDir) {
|
|
13300
13952
|
throw new Error("Access denied");
|
|
13301
13953
|
}
|
|
13302
13954
|
const info = await stat2(resolved);
|
|
13303
13955
|
if (info.isDirectory()) throw new Error("Cannot read a directory");
|
|
13304
|
-
const ext =
|
|
13956
|
+
const ext = path14.extname(resolved).toLowerCase();
|
|
13305
13957
|
if (WORKSPACE_TEXT_EXTENSIONS.has(ext) || ext === "") {
|
|
13306
13958
|
if (info.size > WORKSPACE_TEXT_FILE_MAX_BYTES) throw new Error("File too large");
|
|
13307
13959
|
const content = await readFile(resolved, "utf-8");
|
|
@@ -13352,8 +14004,8 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13352
14004
|
};
|
|
13353
14005
|
}
|
|
13354
14006
|
const runtime = config.runtime;
|
|
13355
|
-
const workspaceDir =
|
|
13356
|
-
const homeDir = ensureRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspaceDir);
|
|
14007
|
+
const workspaceDir = path14.join(this.dataDir, agentId);
|
|
14008
|
+
const homeDir = agent?.runtime.currentRuntimeHomeDir || ensureRuntimeHomeDir(config, this.runtimeSessionHomeDir, workspaceDir, { agentId, slockHome: this.slockHome });
|
|
13357
14009
|
if (!actualSessionId) {
|
|
13358
14010
|
return {
|
|
13359
14011
|
runtime,
|
|
@@ -13391,7 +14043,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13391
14043
|
let redacted = false;
|
|
13392
14044
|
if (ref.reachable && ref.path) {
|
|
13393
14045
|
try {
|
|
13394
|
-
const resolved =
|
|
14046
|
+
const resolved = path14.resolve(ref.path);
|
|
13395
14047
|
const allowedRoots = allowedTranscriptRootsForRuntime(runtime, homeDir, workspaceDir);
|
|
13396
14048
|
if (!await isPathWithinAllowedRoots(resolved, allowedRoots)) {
|
|
13397
14049
|
throw new Error("resolved session path is outside allowed runtime directories");
|
|
@@ -13402,7 +14054,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13402
14054
|
throw new Error("symbolic links are not allowed");
|
|
13403
14055
|
}
|
|
13404
14056
|
if (info.isDirectory()) {
|
|
13405
|
-
targetPath =
|
|
14057
|
+
targetPath = path14.join(resolved, "state.json");
|
|
13406
14058
|
}
|
|
13407
14059
|
if (!await isPathWithinAllowedRoots(targetPath, allowedRoots)) {
|
|
13408
14060
|
throw new Error("resolved session state path is outside allowed runtime directories");
|
|
@@ -13514,14 +14166,22 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13514
14166
|
const idle = this.idleAgentConfigs.get(agentId);
|
|
13515
14167
|
const config = agent?.config ?? idle?.config ?? null;
|
|
13516
14168
|
const runtime = runtimeHint || config?.runtime || "claude";
|
|
13517
|
-
const workspaceDir =
|
|
13518
|
-
const
|
|
14169
|
+
const workspaceDir = path14.join(this.dataDir, agentId);
|
|
14170
|
+
const hostHome = os7.homedir();
|
|
14171
|
+
const home = agent?.runtime.currentRuntimeHomeDir || (config ? ensureRuntimeHomeDir(config, hostHome, workspaceDir, { agentId, slockHome: this.slockHome }) : runtime === "codex" ? resolveDefaultCodexHomeRootForAgent(agentId, { slockHome: this.slockHome }) : hostHome);
|
|
13519
14172
|
const paths = _AgentProcessManager.SKILL_PATHS[runtime] || _AgentProcessManager.SKILL_PATHS.claude;
|
|
14173
|
+
const globalDirs = runtime === "codex" ? [
|
|
14174
|
+
path14.join(home, "skills"),
|
|
14175
|
+
path14.join(home, "skills", ".system"),
|
|
14176
|
+
path14.join(home, ".agents", "skills"),
|
|
14177
|
+
...hasConfiguredCodexHome(config) ? [] : [path14.join(hostHome, ".agents", "skills")]
|
|
14178
|
+
] : paths.global.map((p) => path14.join(home, p));
|
|
14179
|
+
const workspaceDirs = paths.workspace.map((p) => path14.join(workspaceDir, p));
|
|
13520
14180
|
const globalResults = await Promise.all(
|
|
13521
|
-
|
|
14181
|
+
globalDirs.map((dir) => this.scanSkillsDir(dir))
|
|
13522
14182
|
);
|
|
13523
14183
|
const workspaceResults = await Promise.all(
|
|
13524
|
-
|
|
14184
|
+
workspaceDirs.map((dir) => this.scanSkillsDir(dir))
|
|
13525
14185
|
);
|
|
13526
14186
|
const dedup = (skills) => {
|
|
13527
14187
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -13550,7 +14210,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13550
14210
|
const skills = [];
|
|
13551
14211
|
for (const entry of entries) {
|
|
13552
14212
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
13553
|
-
const skillMd =
|
|
14213
|
+
const skillMd = path14.join(dir, entry.name, "SKILL.md");
|
|
13554
14214
|
try {
|
|
13555
14215
|
const content = await readFile(skillMd, "utf-8");
|
|
13556
14216
|
const skill = this.parseSkillMd(entry.name, content);
|
|
@@ -13561,7 +14221,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13561
14221
|
} else if (entry.name.endsWith(".md")) {
|
|
13562
14222
|
const cmdName = entry.name.replace(/\.md$/, "");
|
|
13563
14223
|
try {
|
|
13564
|
-
const content = await readFile(
|
|
14224
|
+
const content = await readFile(path14.join(dir, entry.name), "utf-8");
|
|
13565
14225
|
const skill = this.parseSkillMd(cmdName, content);
|
|
13566
14226
|
skill.sourcePath = dir;
|
|
13567
14227
|
skills.push(skill);
|
|
@@ -13982,6 +14642,43 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
13982
14642
|
recordRuntimeTraceEvent(agentId, ap, name, attrs) {
|
|
13983
14643
|
this.startRuntimeTrace(agentId, ap, "runtime-progress").addEvent(name, attrs);
|
|
13984
14644
|
}
|
|
14645
|
+
restoreRuntimeDeliveryAfterAsyncRejection(agentId, ap, event) {
|
|
14646
|
+
const pendingBefore = ap.notifications.pendingCount;
|
|
14647
|
+
const restoredMessages = ap.inbox.filter(
|
|
14648
|
+
(message) => ap.notifications.hasContributedMessage(message, ap.sessionId)
|
|
14649
|
+
);
|
|
14650
|
+
ap.notifications.clearNoticeFingerprint();
|
|
14651
|
+
const restoredNotificationCount = ap.driver.supportsStdinNotification && ap.sessionId && restoredMessages.length > 0 ? ap.notifications.add(restoredMessages.length) : 0;
|
|
14652
|
+
if (event.requestMethod === "turn/start") {
|
|
14653
|
+
this.commitApmIdleState(agentId, ap, true);
|
|
14654
|
+
}
|
|
14655
|
+
const idleRetryScheduled = event.requestMethod === "turn/start" && restoredNotificationCount > 0 ? ap.notifications.schedule(() => {
|
|
14656
|
+
this.flushAsyncRejectedIdleDelivery(agentId);
|
|
14657
|
+
}, this.stdinNotificationRetryMs) : false;
|
|
14658
|
+
const attrs = {
|
|
14659
|
+
request_method: event.requestMethod,
|
|
14660
|
+
source: event.source,
|
|
14661
|
+
payloadBytes: event.payloadBytes,
|
|
14662
|
+
inbox_count: ap.inbox.length,
|
|
14663
|
+
restored_messages_count: restoredMessages.length,
|
|
14664
|
+
pending_notification_count_before: pendingBefore,
|
|
14665
|
+
pending_notification_count_after: ap.notifications.pendingCount,
|
|
14666
|
+
restored_notification_count: restoredNotificationCount,
|
|
14667
|
+
session_id_present: Boolean(ap.sessionId),
|
|
14668
|
+
supports_stdin_notification: ap.driver.supportsStdinNotification,
|
|
14669
|
+
busy_delivery_mode: ap.driver.busyDeliveryMode,
|
|
14670
|
+
restored_idle_state: event.requestMethod === "turn/start",
|
|
14671
|
+
idle_retry_scheduled: idleRetryScheduled
|
|
14672
|
+
};
|
|
14673
|
+
this.recordRuntimeTraceEvent(agentId, ap, "runtime.delivery.async_rejected", attrs);
|
|
14674
|
+
this.recordDaemonTrace("daemon.agent.stdin_delivery.async_rejected", {
|
|
14675
|
+
agentId,
|
|
14676
|
+
launchId: ap.launchId || void 0,
|
|
14677
|
+
runtime: ap.config.runtime,
|
|
14678
|
+
model: ap.config.model,
|
|
14679
|
+
...attrs
|
|
14680
|
+
}, "error");
|
|
14681
|
+
}
|
|
13985
14682
|
noteRuntimeProgress(ap, eventKind) {
|
|
13986
14683
|
ap.runtimeProgress.noteRuntimeEvent(eventKind);
|
|
13987
14684
|
this.invalidateRecoveryErrorView(ap);
|
|
@@ -14170,7 +14867,7 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
14170
14867
|
if ((ap.driver.startupReadiness ?? "first_event") !== "initial_turn") {
|
|
14171
14868
|
return true;
|
|
14172
14869
|
}
|
|
14173
|
-
return event.kind !== "session_init" && event.kind !== "internal_progress" && event.kind !== "runtime_diagnostic";
|
|
14870
|
+
return event.kind !== "session_init" && event.kind !== "internal_progress" && event.kind !== "runtime_diagnostic" && event.kind !== "runtime_recovery";
|
|
14174
14871
|
}
|
|
14175
14872
|
handleRuntimeStartupTimeout(agentId, ap, timeoutMs) {
|
|
14176
14873
|
const current = this.agents.get(agentId);
|
|
@@ -14366,6 +15063,21 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
14366
15063
|
if (ap) this.recordRuntimeTelemetry(agentId, ap, event);
|
|
14367
15064
|
return;
|
|
14368
15065
|
}
|
|
15066
|
+
if (event.kind === "delivery_error") {
|
|
15067
|
+
if (ap) {
|
|
15068
|
+
this.restoreRuntimeDeliveryAfterAsyncRejection(agentId, ap, event);
|
|
15069
|
+
} else {
|
|
15070
|
+
this.recordDaemonTrace("daemon.agent.delivery_error.received_without_process", {
|
|
15071
|
+
agentId,
|
|
15072
|
+
event_kind: event.kind,
|
|
15073
|
+
runtime: driver.id,
|
|
15074
|
+
request_method: event.requestMethod,
|
|
15075
|
+
source: event.source,
|
|
15076
|
+
payloadBytes: event.payloadBytes
|
|
15077
|
+
});
|
|
15078
|
+
}
|
|
15079
|
+
return;
|
|
15080
|
+
}
|
|
14369
15081
|
if (ap && isStartupRequestErrorEvent(event)) {
|
|
14370
15082
|
this.handleRuntimeStartupRequestError(agentId, ap, event);
|
|
14371
15083
|
return;
|
|
@@ -14382,13 +15094,15 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
14382
15094
|
source: event.source,
|
|
14383
15095
|
itemType: event.itemType,
|
|
14384
15096
|
payloadBytes: event.payloadBytes
|
|
14385
|
-
} : event.kind === "runtime_diagnostic" ? runtimeDiagnosticTraceAttrs(event) : { kind: event.kind };
|
|
15097
|
+
} : event.kind === "runtime_diagnostic" ? runtimeDiagnosticTraceAttrs(event) : event.kind === "runtime_recovery" ? runtimeRecoveryTraceAttrs(event) : { kind: event.kind };
|
|
14386
15098
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.event.received", eventAttrs);
|
|
14387
|
-
|
|
15099
|
+
const recordProgressObservedAfterStall = () => {
|
|
15100
|
+
if (!wasStalled) return;
|
|
14388
15101
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.progress.observed", { afterStall: true });
|
|
14389
|
-
}
|
|
15102
|
+
};
|
|
14390
15103
|
if (event.kind === "internal_progress") {
|
|
14391
15104
|
ap.runtimeProgress.noteInternalProgress();
|
|
15105
|
+
recordProgressObservedAfterStall();
|
|
14392
15106
|
this.invalidateRecoveryErrorView(ap);
|
|
14393
15107
|
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
14394
15108
|
this.recordRuntimeTraceEvent(agentId, ap, "runtime.progress.internal_observed", {
|
|
@@ -14405,11 +15119,17 @@ Use ${communicationCommand("read_history")} to catch up on the channels listed a
|
|
|
14405
15119
|
}
|
|
14406
15120
|
if (event.kind === "runtime_diagnostic") {
|
|
14407
15121
|
this.noteRuntimeProgress(ap, event.kind);
|
|
15122
|
+
recordProgressObservedAfterStall();
|
|
14408
15123
|
this.clearRuntimeErrorDeliveryBackoffAfterProgress(agentId, ap, event.kind);
|
|
14409
15124
|
this.recordRuntimeDiagnosticActivity(agentId, ap, event);
|
|
14410
15125
|
return;
|
|
14411
15126
|
}
|
|
15127
|
+
if (event.kind === "runtime_recovery") {
|
|
15128
|
+
this.recordRuntimeRecoveryActivity(agentId, ap, event);
|
|
15129
|
+
return;
|
|
15130
|
+
}
|
|
14412
15131
|
this.noteRuntimeProgress(ap, event.kind);
|
|
15132
|
+
recordProgressObservedAfterStall();
|
|
14413
15133
|
} else if (event.kind !== "internal_progress") {
|
|
14414
15134
|
this.recordDaemonTrace("daemon.agent.event.received_without_process", {
|
|
14415
15135
|
agentId,
|
|
@@ -15166,8 +15886,8 @@ ${RESPONSE_TARGET_HINT}`);
|
|
|
15166
15886
|
const nodes = [];
|
|
15167
15887
|
for (const entry of entries) {
|
|
15168
15888
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
15169
|
-
const fullPath =
|
|
15170
|
-
const relativePath =
|
|
15889
|
+
const fullPath = path14.join(dir, entry.name);
|
|
15890
|
+
const relativePath = path14.relative(rootDir, fullPath);
|
|
15171
15891
|
let info;
|
|
15172
15892
|
try {
|
|
15173
15893
|
info = await stat2(fullPath);
|
|
@@ -15541,9 +16261,9 @@ var ReminderCache = class {
|
|
|
15541
16261
|
|
|
15542
16262
|
// src/machineLock.ts
|
|
15543
16263
|
import { createHash as createHash4, randomUUID as randomUUID6 } from "crypto";
|
|
15544
|
-
import { mkdirSync as
|
|
15545
|
-
import
|
|
15546
|
-
import
|
|
16264
|
+
import { mkdirSync as mkdirSync7, readFileSync as readFileSync7, rmSync as rmSync3, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
16265
|
+
import os8 from "os";
|
|
16266
|
+
import path15 from "path";
|
|
15547
16267
|
var INCOMPLETE_LOCK_STALE_MS = 3e4;
|
|
15548
16268
|
var DaemonMachineLockConflictError = class extends Error {
|
|
15549
16269
|
code = "DAEMON_MACHINE_LOCK_HELD";
|
|
@@ -15565,7 +16285,7 @@ function resolveDefaultMachineStateRoot() {
|
|
|
15565
16285
|
return resolveSlockHomePath("machines");
|
|
15566
16286
|
}
|
|
15567
16287
|
function ownerPath(lockDir) {
|
|
15568
|
-
return
|
|
16288
|
+
return path15.join(lockDir, "owner.json");
|
|
15569
16289
|
}
|
|
15570
16290
|
function readOwner(lockDir) {
|
|
15571
16291
|
try {
|
|
@@ -15595,17 +16315,17 @@ function acquireDaemonMachineLock(options) {
|
|
|
15595
16315
|
const rootDir = options.rootDir ?? resolveDefaultMachineStateRoot();
|
|
15596
16316
|
const fingerprint = apiKeyFingerprint(options.apiKey);
|
|
15597
16317
|
const lockId = getDaemonMachineLockId(options.apiKey);
|
|
15598
|
-
const machineDir =
|
|
15599
|
-
const lockDir =
|
|
16318
|
+
const machineDir = path15.join(rootDir, lockId);
|
|
16319
|
+
const lockDir = path15.join(machineDir, "daemon.lock");
|
|
15600
16320
|
const token = randomUUID6();
|
|
15601
|
-
|
|
16321
|
+
mkdirSync7(machineDir, { recursive: true });
|
|
15602
16322
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
15603
16323
|
try {
|
|
15604
|
-
|
|
16324
|
+
mkdirSync7(lockDir);
|
|
15605
16325
|
const owner = {
|
|
15606
16326
|
pid: process.pid,
|
|
15607
16327
|
token,
|
|
15608
|
-
hostname:
|
|
16328
|
+
hostname: os8.hostname(),
|
|
15609
16329
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15610
16330
|
serverUrl: options.serverUrl,
|
|
15611
16331
|
apiKeyFingerprint: fingerprint.slice(0, 16)
|
|
@@ -15656,8 +16376,8 @@ function acquireDaemonMachineLock(options) {
|
|
|
15656
16376
|
}
|
|
15657
16377
|
|
|
15658
16378
|
// src/localTraceSink.ts
|
|
15659
|
-
import { appendFileSync, mkdirSync as
|
|
15660
|
-
import
|
|
16379
|
+
import { appendFileSync, mkdirSync as mkdirSync8, readdirSync as readdirSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
16380
|
+
import path16 from "path";
|
|
15661
16381
|
var DEFAULT_MAX_FILE_BYTES = 5 * 1024 * 1024;
|
|
15662
16382
|
var DEFAULT_MAX_FILE_AGE_MS = 5 * 60 * 1e3;
|
|
15663
16383
|
var DEFAULT_MAX_FILES = 8;
|
|
@@ -15694,7 +16414,7 @@ var LocalRotatingTraceSink = class {
|
|
|
15694
16414
|
currentSize = 0;
|
|
15695
16415
|
sequence = 0;
|
|
15696
16416
|
constructor(options) {
|
|
15697
|
-
this.traceDir =
|
|
16417
|
+
this.traceDir = path16.join(options.machineDir, "traces");
|
|
15698
16418
|
this.maxFileBytes = Math.max(1024, Math.floor(options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES));
|
|
15699
16419
|
const baseAgeMs = Math.max(1e3, Math.floor(options.maxFileAgeMs ?? DEFAULT_MAX_FILE_AGE_MS));
|
|
15700
16420
|
const ageJitterMs = Math.max(0, Math.floor(options.maxFileAgeJitterMs ?? 0));
|
|
@@ -15720,11 +16440,11 @@ var LocalRotatingTraceSink = class {
|
|
|
15720
16440
|
return this.currentFile;
|
|
15721
16441
|
}
|
|
15722
16442
|
ensureFile(nextBytes) {
|
|
15723
|
-
|
|
16443
|
+
mkdirSync8(this.traceDir, { recursive: true, mode: 448 });
|
|
15724
16444
|
const nowMs = this.nowMsProvider();
|
|
15725
16445
|
const shouldRotateForAge = this.currentFileOpenedAtMs !== null && nowMs - this.currentFileOpenedAtMs >= this.maxFileAgeMs;
|
|
15726
16446
|
if (!this.currentFile || this.currentSize + nextBytes > this.maxFileBytes || shouldRotateForAge) {
|
|
15727
|
-
this.currentFile =
|
|
16447
|
+
this.currentFile = path16.join(
|
|
15728
16448
|
this.traceDir,
|
|
15729
16449
|
`daemon-trace-${safeTimestamp(nowMs)}-${process.pid}-${String(this.sequence++).padStart(4, "0")}.jsonl`
|
|
15730
16450
|
);
|
|
@@ -15739,7 +16459,7 @@ var LocalRotatingTraceSink = class {
|
|
|
15739
16459
|
const excess = files.length - this.maxFiles;
|
|
15740
16460
|
if (excess <= 0) return;
|
|
15741
16461
|
for (const file of files.slice(0, excess)) {
|
|
15742
|
-
rmSync4(
|
|
16462
|
+
rmSync4(path16.join(this.traceDir, file), { force: true });
|
|
15743
16463
|
}
|
|
15744
16464
|
}
|
|
15745
16465
|
};
|
|
@@ -15830,7 +16550,7 @@ function isDiagnosticErrorAttr(key) {
|
|
|
15830
16550
|
import { createHash as createHash6, randomUUID as randomUUID7 } from "crypto";
|
|
15831
16551
|
import { gzipSync as gzipSync2 } from "zlib";
|
|
15832
16552
|
import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, stat as stat3, writeFile as writeFile2 } from "fs/promises";
|
|
15833
|
-
import
|
|
16553
|
+
import path17 from "path";
|
|
15834
16554
|
|
|
15835
16555
|
// src/traceJitter.ts
|
|
15836
16556
|
import { createHash as createHash5 } from "crypto";
|
|
@@ -15929,7 +16649,7 @@ var DaemonTraceBundleUploader = class {
|
|
|
15929
16649
|
}, nextMs);
|
|
15930
16650
|
}
|
|
15931
16651
|
async findUploadCandidates() {
|
|
15932
|
-
const traceDir =
|
|
16652
|
+
const traceDir = path17.join(this.options.machineDir, "traces");
|
|
15933
16653
|
let names;
|
|
15934
16654
|
try {
|
|
15935
16655
|
names = await readdir3(traceDir);
|
|
@@ -15941,8 +16661,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
15941
16661
|
const currentFile = this.options.currentFileProvider?.();
|
|
15942
16662
|
const candidates = [];
|
|
15943
16663
|
for (const name of names.filter((entry) => entry.startsWith("daemon-trace-") && entry.endsWith(".jsonl")).sort()) {
|
|
15944
|
-
const file =
|
|
15945
|
-
if (currentFile &&
|
|
16664
|
+
const file = path17.join(traceDir, name);
|
|
16665
|
+
if (currentFile && path17.resolve(file) === path17.resolve(currentFile)) continue;
|
|
15946
16666
|
if (await this.isUploaded(file)) continue;
|
|
15947
16667
|
try {
|
|
15948
16668
|
const info = await stat3(file);
|
|
@@ -16016,8 +16736,8 @@ var DaemonTraceBundleUploader = class {
|
|
|
16016
16736
|
}
|
|
16017
16737
|
}
|
|
16018
16738
|
uploadStatePath(file) {
|
|
16019
|
-
const stateDir =
|
|
16020
|
-
return
|
|
16739
|
+
const stateDir = path17.join(this.options.machineDir, "trace-uploads");
|
|
16740
|
+
return path17.join(stateDir, `${path17.basename(file)}.uploaded.json`);
|
|
16021
16741
|
}
|
|
16022
16742
|
async isUploaded(file) {
|
|
16023
16743
|
try {
|
|
@@ -16029,9 +16749,9 @@ var DaemonTraceBundleUploader = class {
|
|
|
16029
16749
|
}
|
|
16030
16750
|
async markUploaded(file, metadata) {
|
|
16031
16751
|
const stateFile = this.uploadStatePath(file);
|
|
16032
|
-
await mkdir2(
|
|
16752
|
+
await mkdir2(path17.dirname(stateFile), { recursive: true, mode: 448 });
|
|
16033
16753
|
await writeFile2(stateFile, `${JSON.stringify({
|
|
16034
|
-
file:
|
|
16754
|
+
file: path17.basename(file),
|
|
16035
16755
|
uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16036
16756
|
...metadata
|
|
16037
16757
|
}, null, 2)}
|
|
@@ -16180,13 +16900,13 @@ function readDaemonVersion(moduleUrl = import.meta.url) {
|
|
|
16180
16900
|
}
|
|
16181
16901
|
}
|
|
16182
16902
|
function resolveSlockCliPath(moduleUrl = import.meta.url) {
|
|
16183
|
-
const thisDir =
|
|
16184
|
-
const bundledDistPath =
|
|
16903
|
+
const thisDir = path18.dirname(fileURLToPath(moduleUrl));
|
|
16904
|
+
const bundledDistPath = path18.resolve(thisDir, "cli", "index.js");
|
|
16185
16905
|
try {
|
|
16186
16906
|
accessSync(bundledDistPath);
|
|
16187
16907
|
return bundledDistPath;
|
|
16188
16908
|
} catch {
|
|
16189
|
-
const workspaceDistPath =
|
|
16909
|
+
const workspaceDistPath = path18.resolve(thisDir, "..", "..", "cli", "dist", "index.js");
|
|
16190
16910
|
accessSync(workspaceDistPath);
|
|
16191
16911
|
return workspaceDistPath;
|
|
16192
16912
|
}
|
|
@@ -16200,11 +16920,12 @@ function resolveSlockCliPathOrEmpty(moduleUrl = import.meta.url) {
|
|
|
16200
16920
|
}
|
|
16201
16921
|
async function runBundledSlockCli(argv) {
|
|
16202
16922
|
process.argv = [process.execPath, "slock", ...argv];
|
|
16203
|
-
await import("./dist-
|
|
16923
|
+
await import("./dist-5BEASCX5.js");
|
|
16204
16924
|
}
|
|
16205
16925
|
function detectRuntimes(tracer = noopTracer) {
|
|
16206
16926
|
const ids = [];
|
|
16207
16927
|
const versions = {};
|
|
16928
|
+
const diagnostics = {};
|
|
16208
16929
|
const span = tracer.startSpan("daemon.runtime.detect", {
|
|
16209
16930
|
surface: "daemon",
|
|
16210
16931
|
kind: "internal",
|
|
@@ -16220,20 +16941,26 @@ function detectRuntimes(tracer = noopTracer) {
|
|
|
16220
16941
|
const probe = driver.probe();
|
|
16221
16942
|
if (!probe.available) {
|
|
16222
16943
|
if (probe.version) versions[runtime.id] = probe.version;
|
|
16944
|
+
if (probe.diagnostic) diagnostics[runtime.id] = probe.diagnostic;
|
|
16223
16945
|
span.addEvent("daemon.runtime.detect.checked", {
|
|
16224
16946
|
runtime: runtime.id,
|
|
16225
16947
|
outcome: "unavailable",
|
|
16226
16948
|
version_present: Boolean(probe.version),
|
|
16949
|
+
diagnostic_present: Boolean(probe.diagnostic),
|
|
16950
|
+
...probe.diagnostic ? { diagnostic: probe.diagnostic } : {},
|
|
16227
16951
|
binary_path_present: false
|
|
16228
16952
|
});
|
|
16229
16953
|
continue;
|
|
16230
16954
|
}
|
|
16231
16955
|
ids.push(runtime.id);
|
|
16232
16956
|
if (probe.version) versions[runtime.id] = probe.version;
|
|
16957
|
+
if (probe.diagnostic) diagnostics[runtime.id] = probe.diagnostic;
|
|
16233
16958
|
span.addEvent("daemon.runtime.detect.checked", {
|
|
16234
16959
|
runtime: runtime.id,
|
|
16235
16960
|
outcome: "available",
|
|
16236
16961
|
version_present: Boolean(probe.version),
|
|
16962
|
+
diagnostic_present: Boolean(probe.diagnostic),
|
|
16963
|
+
...probe.diagnostic ? { diagnostic: probe.diagnostic } : {},
|
|
16237
16964
|
binary_path_present: false
|
|
16238
16965
|
});
|
|
16239
16966
|
continue;
|
|
@@ -16276,7 +17003,7 @@ function detectRuntimes(tracer = noopTracer) {
|
|
|
16276
17003
|
detected_runtime_count: ids.length
|
|
16277
17004
|
}
|
|
16278
17005
|
});
|
|
16279
|
-
return { ids, versions };
|
|
17006
|
+
return { ids, versions, ...Object.keys(diagnostics).length > 0 ? { diagnostics } : {} };
|
|
16280
17007
|
}
|
|
16281
17008
|
function readPositiveIntegerEnv3(name, fallback) {
|
|
16282
17009
|
const raw = process.env[name];
|
|
@@ -16398,7 +17125,7 @@ var DaemonCore = class {
|
|
|
16398
17125
|
}
|
|
16399
17126
|
resolveMachineStateRoot() {
|
|
16400
17127
|
if (this.options.machineStateDir) return this.options.machineStateDir;
|
|
16401
|
-
if (this.options.dataDir) return
|
|
17128
|
+
if (this.options.dataDir) return path18.join(path18.dirname(this.options.dataDir), "machines");
|
|
16402
17129
|
return resolveDefaultMachineStateRoot();
|
|
16403
17130
|
}
|
|
16404
17131
|
shouldEnableLocalTrace() {
|
|
@@ -16425,7 +17152,7 @@ var DaemonCore = class {
|
|
|
16425
17152
|
sink: this.localTraceSink
|
|
16426
17153
|
}));
|
|
16427
17154
|
this.agentManager.setTracer(this.tracer);
|
|
16428
|
-
this.agentManager.setCliTransportTraceDir(
|
|
17155
|
+
this.agentManager.setCliTransportTraceDir(path18.join(machineDir, "traces"));
|
|
16429
17156
|
}
|
|
16430
17157
|
installTraceBundleUploader(machineDir) {
|
|
16431
17158
|
if (!this.shouldEnableLocalTrace()) return;
|
|
@@ -16973,9 +17700,12 @@ var DaemonCore = class {
|
|
|
16973
17700
|
});
|
|
16974
17701
|
}
|
|
16975
17702
|
handleConnect() {
|
|
16976
|
-
const { ids: runtimes, versions: runtimeVersions } = this.runtimeDetector();
|
|
17703
|
+
const { ids: runtimes, versions: runtimeVersions, diagnostics: runtimeDiagnostics = {} } = this.runtimeDetector();
|
|
16977
17704
|
const runtimeInfo = runtimes.map((id) => runtimeVersions[id] ? `${id} (${runtimeVersions[id]})` : id);
|
|
16978
17705
|
logger.info(`[Daemon] Detected runtimes: ${runtimeInfo.join(", ") || "none"}`);
|
|
17706
|
+
for (const [runtime, diagnostic] of Object.entries(runtimeDiagnostics)) {
|
|
17707
|
+
logger.warn(`[Daemon] Runtime ${runtime} diagnostic: ${diagnostic}`);
|
|
17708
|
+
}
|
|
16979
17709
|
if (!this.opencliWrappersRegenerated) {
|
|
16980
17710
|
this.opencliWrappersRegenerated = true;
|
|
16981
17711
|
try {
|
|
@@ -16995,8 +17725,8 @@ var DaemonCore = class {
|
|
|
16995
17725
|
capabilities: ["agent:start", "agent:stop", "agent:deliver", "workspace:files"],
|
|
16996
17726
|
runtimes,
|
|
16997
17727
|
runningAgents: runningAgentIds,
|
|
16998
|
-
hostname: this.options.hostname ??
|
|
16999
|
-
os: this.options.osDescription ?? `${
|
|
17728
|
+
hostname: this.options.hostname ?? os9.hostname(),
|
|
17729
|
+
os: this.options.osDescription ?? `${os9.platform()} ${os9.arch()}`,
|
|
17000
17730
|
daemonVersion: this.daemonVersion,
|
|
17001
17731
|
...this.computerVersion ? { computerVersion: this.computerVersion } : {}
|
|
17002
17732
|
});
|