@slock-ai/daemon 0.52.0 → 0.52.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-XEHIMW55.js → chunk-HSBOURQE.js} +170 -16
- package/dist/core.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -823,6 +823,7 @@ function buildPrompt(config, variant, opts) {
|
|
|
823
823
|
"- Always communicate through `slock` CLI commands. This is your only output channel.",
|
|
824
824
|
...opts.extraCriticalRules,
|
|
825
825
|
"- Use only the provided `slock` CLI commands for messaging.",
|
|
826
|
+
"- Do not combine multiple `slock` CLI commands in one shell command. Run one `slock` command per tool call, read its output, then decide the next command.",
|
|
826
827
|
"- Always claim a task via `slock task claim` before starting work on it. If the claim fails, move on to a different task."
|
|
827
828
|
] : [
|
|
828
829
|
`- Always communicate through ${sendCmd}. This is your only output channel.`,
|
|
@@ -1810,6 +1811,18 @@ function consumeVisibleResponse(registration, targetUrl, sendTarget, responseTex
|
|
|
1810
1811
|
});
|
|
1811
1812
|
return;
|
|
1812
1813
|
}
|
|
1814
|
+
if (targetUrl.pathname === "/internal/agent-api/send" && parsed.state === "sent") {
|
|
1815
|
+
const messageSeq2 = typeof parsed.messageSeq === "number" && Number.isFinite(parsed.messageSeq) ? Math.floor(parsed.messageSeq) : void 0;
|
|
1816
|
+
if (sendTarget && messageSeq2 && messageSeq2 > 0) {
|
|
1817
|
+
coordinator.consumeVisibleMessages({
|
|
1818
|
+
target: sendTarget,
|
|
1819
|
+
messages: normalizeVisibleMessages([{ seq: messageSeq2, id: parsed.messageId }], sendTarget),
|
|
1820
|
+
boundarySeq: messageSeq2,
|
|
1821
|
+
source: "agent_api_send_commit"
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
return;
|
|
1825
|
+
}
|
|
1813
1826
|
if (targetUrl.pathname === "/internal/agent-api/events" && Array.isArray(parsed.events)) {
|
|
1814
1827
|
const messages = normalizeVisibleMessages(parsed.events);
|
|
1815
1828
|
coordinator.consumeVisibleMessages({ messages, source: "agent_api_events" });
|
|
@@ -3786,7 +3799,7 @@ function detectKimiModels(home = os4.homedir()) {
|
|
|
3786
3799
|
|
|
3787
3800
|
// src/drivers/opencode.ts
|
|
3788
3801
|
import { spawn as spawn7, spawnSync as spawnSync2 } from "child_process";
|
|
3789
|
-
import { readFileSync as readFileSync4 } from "fs";
|
|
3802
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "fs";
|
|
3790
3803
|
import os5 from "os";
|
|
3791
3804
|
import path10 from "path";
|
|
3792
3805
|
var CHAT_MCP_SERVER_NAME = "chat";
|
|
@@ -4024,11 +4037,14 @@ function detectOpenCodeModels(home = os5.homedir(), runCommand = runOpenCodeMode
|
|
|
4024
4037
|
if (commandResult.error || commandResult.status !== 0) return null;
|
|
4025
4038
|
return parseOpenCodeModelsOutput(commandResult.stdout);
|
|
4026
4039
|
}
|
|
4027
|
-
function runOpenCodeModelsCommand(home) {
|
|
4028
|
-
const
|
|
4040
|
+
function runOpenCodeModelsCommand(home, deps = {}) {
|
|
4041
|
+
const platform = deps.platform ?? process.platform;
|
|
4042
|
+
const spawnSyncFn = deps.spawnSyncFn ?? spawnSync2;
|
|
4043
|
+
const result = spawnSyncFn("opencode", ["models"], {
|
|
4029
4044
|
env: { ...process.env, HOME: home, FORCE_COLOR: "0", NO_COLOR: "1" },
|
|
4030
4045
|
encoding: "utf8",
|
|
4031
|
-
timeout: 5e3
|
|
4046
|
+
timeout: 5e3,
|
|
4047
|
+
shell: platform === "win32"
|
|
4032
4048
|
});
|
|
4033
4049
|
return {
|
|
4034
4050
|
status: result.status,
|
|
@@ -4036,6 +4052,102 @@ function runOpenCodeModelsCommand(home) {
|
|
|
4036
4052
|
error: result.error
|
|
4037
4053
|
};
|
|
4038
4054
|
}
|
|
4055
|
+
function isWindowsCommandShim(commandPath) {
|
|
4056
|
+
const ext = path10.win32.extname(commandPath).toLowerCase();
|
|
4057
|
+
return ext === ".cmd" || ext === ".bat";
|
|
4058
|
+
}
|
|
4059
|
+
function opencodePackageEntryCandidates(packageRoot) {
|
|
4060
|
+
const winPath = path10.win32;
|
|
4061
|
+
return [
|
|
4062
|
+
winPath.join(packageRoot, "bin", "opencode.exe"),
|
|
4063
|
+
winPath.join(packageRoot, "bin", "opencode.js"),
|
|
4064
|
+
winPath.join(packageRoot, "bin", "opencode.mjs"),
|
|
4065
|
+
winPath.join(packageRoot, "dist", "index.js")
|
|
4066
|
+
];
|
|
4067
|
+
}
|
|
4068
|
+
function openCodeSpecForEntry(entry, commandArgs) {
|
|
4069
|
+
if (path10.win32.extname(entry).toLowerCase() === ".exe") {
|
|
4070
|
+
return { command: entry, args: commandArgs, shell: false };
|
|
4071
|
+
}
|
|
4072
|
+
return { command: process.execPath, args: [entry, ...commandArgs], shell: false };
|
|
4073
|
+
}
|
|
4074
|
+
function resolveWindowsOpenCodePackageEntry(commandPath, deps = {}) {
|
|
4075
|
+
const existsSyncFn = deps.existsSyncFn ?? existsSync8;
|
|
4076
|
+
const execFileSyncFn = deps.execFileSyncFn;
|
|
4077
|
+
const env = deps.env ?? process.env;
|
|
4078
|
+
const winPath = path10.win32;
|
|
4079
|
+
const candidates = [];
|
|
4080
|
+
if (execFileSyncFn) {
|
|
4081
|
+
try {
|
|
4082
|
+
const globalRoot = String(execFileSyncFn("npm", ["root", "-g"], {
|
|
4083
|
+
encoding: "utf8",
|
|
4084
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
4085
|
+
env
|
|
4086
|
+
})).trim();
|
|
4087
|
+
if (globalRoot) {
|
|
4088
|
+
candidates.push(...opencodePackageEntryCandidates(winPath.join(globalRoot, "opencode-ai")));
|
|
4089
|
+
}
|
|
4090
|
+
} catch {
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
if (commandPath) {
|
|
4094
|
+
const commandDir = winPath.dirname(commandPath);
|
|
4095
|
+
candidates.push(...opencodePackageEntryCandidates(winPath.join(commandDir, "node_modules", "opencode-ai")));
|
|
4096
|
+
candidates.push(...extractWindowsShimTargets(commandPath, deps));
|
|
4097
|
+
}
|
|
4098
|
+
for (const candidate of candidates) {
|
|
4099
|
+
if (existsSyncFn(candidate)) return candidate;
|
|
4100
|
+
}
|
|
4101
|
+
return null;
|
|
4102
|
+
}
|
|
4103
|
+
function extractWindowsShimTargets(commandPath, deps = {}) {
|
|
4104
|
+
if (!isWindowsCommandShim(commandPath)) return [];
|
|
4105
|
+
const readFileSyncFn = deps.readFileSyncFn ?? readFileSync4;
|
|
4106
|
+
const commandDir = path10.win32.dirname(commandPath);
|
|
4107
|
+
let raw;
|
|
4108
|
+
try {
|
|
4109
|
+
raw = String(readFileSyncFn(commandPath, "utf8"));
|
|
4110
|
+
} catch {
|
|
4111
|
+
return [];
|
|
4112
|
+
}
|
|
4113
|
+
const candidates = [];
|
|
4114
|
+
const dp0Pattern = /%~dp0\\?([^"\r\n]*?opencode\.(?:exe|js|mjs|cjs))/gi;
|
|
4115
|
+
for (const match of raw.matchAll(dp0Pattern)) {
|
|
4116
|
+
const relative = match[1]?.replace(/^\\+/, "");
|
|
4117
|
+
if (relative) candidates.push(path10.win32.normalize(path10.win32.join(commandDir, relative)));
|
|
4118
|
+
}
|
|
4119
|
+
return candidates;
|
|
4120
|
+
}
|
|
4121
|
+
function resolveOpenCodeSpawn(commandArgs, deps = {}) {
|
|
4122
|
+
const platform = deps.platform ?? process.platform;
|
|
4123
|
+
if (platform !== "win32") {
|
|
4124
|
+
return {
|
|
4125
|
+
command: resolveCommandOnPath("opencode", deps) ?? "opencode",
|
|
4126
|
+
args: commandArgs,
|
|
4127
|
+
shell: false
|
|
4128
|
+
};
|
|
4129
|
+
}
|
|
4130
|
+
const command = resolveCommandOnPath("opencode", deps);
|
|
4131
|
+
if (command && path10.win32.extname(command).toLowerCase() === ".exe") {
|
|
4132
|
+
return { command, args: commandArgs, shell: false };
|
|
4133
|
+
}
|
|
4134
|
+
const packageEntry = resolveWindowsOpenCodePackageEntry(command, deps);
|
|
4135
|
+
if (packageEntry) return openCodeSpecForEntry(packageEntry, commandArgs);
|
|
4136
|
+
if (command && !isWindowsCommandShim(command)) {
|
|
4137
|
+
return { command, args: commandArgs, shell: false };
|
|
4138
|
+
}
|
|
4139
|
+
throw new Error(
|
|
4140
|
+
"Cannot resolve OpenCode CLI entry point on Windows without cmd.exe. Install the native OpenCode executable or install opencode-ai globally so Slock can launch node_modules/opencode-ai/bin/opencode.exe directly."
|
|
4141
|
+
);
|
|
4142
|
+
}
|
|
4143
|
+
function readOpenCodeVersion(deps = {}) {
|
|
4144
|
+
try {
|
|
4145
|
+
const launch = resolveOpenCodeSpawn([], deps);
|
|
4146
|
+
return readCommandVersion(launch.command, launch.args, deps);
|
|
4147
|
+
} catch {
|
|
4148
|
+
return null;
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4039
4151
|
function isSystemFirstMessageTask(message) {
|
|
4040
4152
|
return message.sender_id === "system" && message.channel_type === "channel" && message.channel_name === "all" && message.content.trimStart().startsWith(FIRST_MESSAGE_TASK_PREFIX);
|
|
4041
4153
|
}
|
|
@@ -4078,7 +4190,7 @@ var OpenCodeDriver = class {
|
|
|
4078
4190
|
model: modelId
|
|
4079
4191
|
}
|
|
4080
4192
|
};
|
|
4081
|
-
const version =
|
|
4193
|
+
const version = readOpenCodeVersion();
|
|
4082
4194
|
const launch = buildOpenCodeLaunchOptions(launchCtx, opts?.home, version);
|
|
4083
4195
|
return {
|
|
4084
4196
|
args: launch.args,
|
|
@@ -4099,8 +4211,13 @@ var OpenCodeDriver = class {
|
|
|
4099
4211
|
sessionId = null;
|
|
4100
4212
|
sessionAnnounced = false;
|
|
4101
4213
|
probe() {
|
|
4102
|
-
|
|
4103
|
-
|
|
4214
|
+
let version;
|
|
4215
|
+
try {
|
|
4216
|
+
const launch = resolveOpenCodeSpawn([]);
|
|
4217
|
+
version = readCommandVersion(launch.command, launch.args);
|
|
4218
|
+
} catch {
|
|
4219
|
+
return { available: false };
|
|
4220
|
+
}
|
|
4104
4221
|
const unsupportedMessage = unsupportedOpenCodeVersionMessage(version);
|
|
4105
4222
|
if (unsupportedMessage) {
|
|
4106
4223
|
return {
|
|
@@ -4108,7 +4225,7 @@ var OpenCodeDriver = class {
|
|
|
4108
4225
|
version: `${version} (requires >= ${MIN_SUPPORTED_OPENCODE_VERSION})`
|
|
4109
4226
|
};
|
|
4110
4227
|
}
|
|
4111
|
-
return { available: true, version };
|
|
4228
|
+
return { available: true, version: version ?? void 0 };
|
|
4112
4229
|
}
|
|
4113
4230
|
async detectModels() {
|
|
4114
4231
|
return detectOpenCodeModels();
|
|
@@ -4116,17 +4233,18 @@ var OpenCodeDriver = class {
|
|
|
4116
4233
|
spawn(ctx) {
|
|
4117
4234
|
this.sessionId = ctx.config.sessionId || null;
|
|
4118
4235
|
this.sessionAnnounced = false;
|
|
4119
|
-
const version =
|
|
4236
|
+
const version = readOpenCodeVersion();
|
|
4120
4237
|
const unsupportedMessage = unsupportedOpenCodeVersionMessage(version);
|
|
4121
4238
|
if (unsupportedMessage) {
|
|
4122
4239
|
throw new Error(unsupportedMessage);
|
|
4123
4240
|
}
|
|
4124
4241
|
const launch = buildOpenCodeLaunchOptions(ctx, os5.homedir(), version);
|
|
4125
|
-
const
|
|
4242
|
+
const spawnSpec = resolveOpenCodeSpawn(launch.args);
|
|
4243
|
+
const proc = spawn7(spawnSpec.command, spawnSpec.args, {
|
|
4126
4244
|
cwd: ctx.workingDirectory,
|
|
4127
4245
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4128
4246
|
env: launch.env,
|
|
4129
|
-
shell:
|
|
4247
|
+
shell: spawnSpec.shell
|
|
4130
4248
|
});
|
|
4131
4249
|
proc.stdin?.end();
|
|
4132
4250
|
return { process: proc };
|
|
@@ -4364,6 +4482,7 @@ function classifyRuntimeError(message, httpStatus) {
|
|
|
4364
4482
|
return "ProviderApiError";
|
|
4365
4483
|
}
|
|
4366
4484
|
if (/\btimeout|timed out\b/i.test(message)) return "TimeoutError";
|
|
4485
|
+
if (/stream closed before response\.completed|error decoding response body/i.test(message)) return "ProviderStreamError";
|
|
4367
4486
|
if (/\brate.?limit|too many requests\b/i.test(message)) return "RateLimitError";
|
|
4368
4487
|
if (/\bnot found\b/i.test(message)) return "NotFoundError";
|
|
4369
4488
|
return "RuntimeError";
|
|
@@ -5238,12 +5357,21 @@ function classifyTerminalFailure(ap) {
|
|
|
5238
5357
|
].filter((value) => !!value);
|
|
5239
5358
|
for (const text of candidates) {
|
|
5240
5359
|
const lower = text.toLowerCase();
|
|
5241
|
-
if (lower.includes("usage limit") || lower.includes("quota exceeded") || lower.includes("quota limit") || lower.includes("budget limit exceeded") || lower.includes("usage not included in your plan") || lower.includes("modelnotfounderror") || lower.includes("requested entity was not found") || lower.includes("model deprecated") || lower.includes("model not found")) {
|
|
5360
|
+
if (lower.includes("usage limit") || lower.includes("quota exceeded") || lower.includes("quota limit") || lower.includes("budget limit exceeded") || lower.includes("usage not included in your plan") || lower.includes("modelnotfounderror") || lower.includes("requested entity was not found") || lower.includes("model deprecated") || lower.includes("model not found") || isProviderStreamFailureText(text)) {
|
|
5242
5361
|
return text;
|
|
5243
5362
|
}
|
|
5244
5363
|
}
|
|
5245
5364
|
return null;
|
|
5246
5365
|
}
|
|
5366
|
+
function isProviderStreamFailureText(text) {
|
|
5367
|
+
return /stream closed before response\.completed|error decoding response body/i.test(text);
|
|
5368
|
+
}
|
|
5369
|
+
function isCodexProviderReconnectLog(text) {
|
|
5370
|
+
return /Reconnecting\.\.\.\s*\d+\s*\/\s*\d+/i.test(text);
|
|
5371
|
+
}
|
|
5372
|
+
function isCodexBenignTransportLog(text) {
|
|
5373
|
+
return /Falling back from WebSockets/i.test(text);
|
|
5374
|
+
}
|
|
5247
5375
|
function hasDirectStdinRecoveryEvidence(ap) {
|
|
5248
5376
|
const candidates = [
|
|
5249
5377
|
ap.lastRuntimeError,
|
|
@@ -6095,8 +6223,24 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6095
6223
|
proc.stderr?.on("data", (chunk) => {
|
|
6096
6224
|
const text = chunk.toString().trim();
|
|
6097
6225
|
if (!text) return;
|
|
6098
|
-
if (/Reconnecting\.\.\.|Falling back from WebSockets/i.test(text)) return;
|
|
6099
6226
|
const current = this.agents.get(agentId);
|
|
6227
|
+
if (driver.id === "codex" && isCodexProviderReconnectLog(text)) {
|
|
6228
|
+
if (current) {
|
|
6229
|
+
current.recentStderr = pushRecentStderr(current.recentStderr, text);
|
|
6230
|
+
}
|
|
6231
|
+
this.recordDaemonTrace("daemon.agent.provider_reconnect", {
|
|
6232
|
+
agentId,
|
|
6233
|
+
launchId: current?.launchId || void 0,
|
|
6234
|
+
runtime: config.runtime,
|
|
6235
|
+
model: config.model
|
|
6236
|
+
});
|
|
6237
|
+
this.broadcastActivity(agentId, "working", "Codex reconnecting to provider\u2026", [
|
|
6238
|
+
{ kind: "text", text }
|
|
6239
|
+
]);
|
|
6240
|
+
logger.info(`[Agent ${agentId} stderr]: ${text}`);
|
|
6241
|
+
return;
|
|
6242
|
+
}
|
|
6243
|
+
if (driver.id === "codex" && isCodexBenignTransportLog(text)) return;
|
|
6100
6244
|
if (current) {
|
|
6101
6245
|
current.recentStderr = pushRecentStderr(current.recentStderr, text);
|
|
6102
6246
|
}
|
|
@@ -6240,10 +6384,20 @@ Use ${communicationCommand(driver, "read_history")} to catch up on the channels
|
|
|
6240
6384
|
}
|
|
6241
6385
|
this.broadcastActivity(agentId, "online", "Process idle");
|
|
6242
6386
|
} else {
|
|
6243
|
-
this.idleAgentConfigs.delete(agentId);
|
|
6244
6387
|
const reason = formatCrashReason(finalCode, finalSignal, ap);
|
|
6245
|
-
|
|
6246
|
-
|
|
6388
|
+
if (terminalFailureDetail && isProviderStreamFailureText(terminalFailureDetail)) {
|
|
6389
|
+
this.idleAgentConfigs.set(agentId, {
|
|
6390
|
+
config: { ...ap.config, sessionId: ap.sessionId },
|
|
6391
|
+
sessionId: ap.sessionId,
|
|
6392
|
+
launchId: ap.launchId
|
|
6393
|
+
});
|
|
6394
|
+
logger.warn(`[Agent ${agentId}] Recoverable provider stream failure (${reason}) \u2014 keeping agent wakeable`);
|
|
6395
|
+
this.sendAgentStatus(agentId, "active", ap.launchId);
|
|
6396
|
+
} else {
|
|
6397
|
+
this.idleAgentConfigs.delete(agentId);
|
|
6398
|
+
logger.error(`[Agent ${agentId}] Process crashed (${reason}) \u2014 marking inactive`);
|
|
6399
|
+
this.sendAgentStatus(agentId, "inactive", ap.launchId);
|
|
6400
|
+
}
|
|
6247
6401
|
if (terminalFailureDetail) {
|
|
6248
6402
|
this.broadcastActivity(
|
|
6249
6403
|
agentId,
|
package/dist/core.js
CHANGED
package/dist/index.js
CHANGED