chatroom-cli 1.36.1 → 1.37.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/index.js +314 -56
- package/dist/index.js.map +10 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13426,6 +13426,10 @@ function startSessionEventForwarder(client4, options) {
|
|
|
13426
13426
|
const errorTarget = options.errorTarget ?? process.stderr;
|
|
13427
13427
|
let cancelled = false;
|
|
13428
13428
|
let doneResolve;
|
|
13429
|
+
let sessionStarted = false;
|
|
13430
|
+
const seenToolStates = new Map;
|
|
13431
|
+
let lastStatus;
|
|
13432
|
+
const agentEndCallbacks = [];
|
|
13429
13433
|
const donePromise = new Promise((resolve) => {
|
|
13430
13434
|
doneResolve = resolve;
|
|
13431
13435
|
});
|
|
@@ -13445,31 +13449,76 @@ function startSessionEventForwarder(client4, options) {
|
|
|
13445
13449
|
const eventSession = eventSessionId(event);
|
|
13446
13450
|
if (eventSession && eventSession !== options.sessionId)
|
|
13447
13451
|
continue;
|
|
13448
|
-
if (eventSession === undefined && event.type !== "session.idle" && event.type !== "session.compacted" && event.type !== "session.error" && event.type !== "session.status" && event.type !== "file.edited")
|
|
13452
|
+
if (eventSession === undefined && event.type !== "message.part.updated" && event.type !== "session.idle" && event.type !== "session.compacted" && event.type !== "session.error" && event.type !== "session.status" && event.type !== "file.edited")
|
|
13449
13453
|
continue;
|
|
13454
|
+
if (!sessionStarted) {
|
|
13455
|
+
sessionStarted = true;
|
|
13456
|
+
target.write(formatLogLine(options, "session] Started", `role: ${options.role}`) + `
|
|
13457
|
+
`);
|
|
13458
|
+
}
|
|
13450
13459
|
switch (event.type) {
|
|
13451
13460
|
case "message.part.updated": {
|
|
13452
13461
|
const props = event.properties;
|
|
13453
13462
|
const part = props?.part;
|
|
13454
|
-
if (part?.type === "text"
|
|
13455
|
-
|
|
13463
|
+
if (part?.type === "text") {
|
|
13464
|
+
const chunk = props?.delta !== undefined && props.delta !== "" ? props.delta : part.text;
|
|
13465
|
+
if (chunk) {
|
|
13466
|
+
target.write(formatLogLine(options, "text", chunk) + `
|
|
13456
13467
|
`);
|
|
13468
|
+
}
|
|
13469
|
+
} else if (part?.type === "reasoning") {
|
|
13470
|
+
const chunk = props?.delta !== undefined && props.delta !== "" ? props.delta : part.text;
|
|
13471
|
+
if (chunk) {
|
|
13472
|
+
target.write(formatLogLine(options, "thinking", chunk) + `
|
|
13473
|
+
`);
|
|
13474
|
+
}
|
|
13457
13475
|
} else if (part?.type === "tool" && part.tool) {
|
|
13458
|
-
|
|
13459
|
-
|
|
13476
|
+
let appendInput = function(base, input, tool) {
|
|
13477
|
+
if (!input || typeof input === "object" && Object.keys(input).length === 0) {
|
|
13478
|
+
return base;
|
|
13479
|
+
}
|
|
13480
|
+
const inp = input;
|
|
13481
|
+
if (tool === "bash" && typeof inp.command === "string") {
|
|
13482
|
+
return `${base}: ${inp.command}`;
|
|
13483
|
+
}
|
|
13484
|
+
const inputStr = typeof inp === "string" ? inp : JSON.stringify(inp);
|
|
13485
|
+
return `${base}: ${inputStr}`;
|
|
13486
|
+
};
|
|
13487
|
+
const state = typeof props?.state === "string" ? props.state : typeof part.state?.status === "string" ? part.state.status : "started";
|
|
13488
|
+
let payload = state;
|
|
13489
|
+
if (part.state?.input) {
|
|
13490
|
+
payload = appendInput(payload, part.state.input, part.tool);
|
|
13491
|
+
}
|
|
13492
|
+
if (state === "completed" && part.state?.time?.start !== undefined && part.state?.time?.end !== undefined) {
|
|
13493
|
+
const duration = ((part.state.time.end - part.state.time.start) / 1000).toFixed(1);
|
|
13494
|
+
payload = appendInput(`${state} (${duration}s)`, part.state.input, part.tool);
|
|
13495
|
+
}
|
|
13496
|
+
const callID = part.callID ?? "unknown";
|
|
13497
|
+
const seenKey = `${callID}:${state}`;
|
|
13498
|
+
if (!seenToolStates.has(seenKey)) {
|
|
13499
|
+
seenToolStates.set(seenKey, payload);
|
|
13500
|
+
target.write(formatLogLine(options, "tool: " + part.tool, payload) + `
|
|
13460
13501
|
`);
|
|
13502
|
+
}
|
|
13503
|
+
if (state === "completed" || state === "error") {
|
|
13504
|
+
seenToolStates.delete(seenKey);
|
|
13505
|
+
}
|
|
13461
13506
|
}
|
|
13462
13507
|
break;
|
|
13463
13508
|
}
|
|
13464
13509
|
case "file.edited": {
|
|
13465
13510
|
const props = event.properties;
|
|
13466
|
-
|
|
13511
|
+
const kind = props?.action ?? props?.kind;
|
|
13512
|
+
const filePayload = kind ? `${props?.file} (${kind})` : props?.file;
|
|
13513
|
+
target.write(formatLogLine(options, "file", filePayload) + `
|
|
13467
13514
|
`);
|
|
13468
13515
|
break;
|
|
13469
13516
|
}
|
|
13470
13517
|
case "session.idle": {
|
|
13471
13518
|
target.write(formatLogLine(options, "agent_end") + `
|
|
13472
13519
|
`);
|
|
13520
|
+
for (const cb of agentEndCallbacks)
|
|
13521
|
+
cb();
|
|
13473
13522
|
break;
|
|
13474
13523
|
}
|
|
13475
13524
|
case "session.compacted": {
|
|
@@ -13479,15 +13528,25 @@ function startSessionEventForwarder(client4, options) {
|
|
|
13479
13528
|
}
|
|
13480
13529
|
case "session.status": {
|
|
13481
13530
|
const props = event.properties;
|
|
13482
|
-
|
|
13531
|
+
const currentStatus = props?.status?.type;
|
|
13532
|
+
if (currentStatus !== lastStatus) {
|
|
13533
|
+
lastStatus = currentStatus;
|
|
13534
|
+
target.write(formatLogLine(options, "status", currentStatus) + `
|
|
13483
13535
|
`);
|
|
13536
|
+
}
|
|
13484
13537
|
break;
|
|
13485
13538
|
}
|
|
13486
13539
|
case "session.error": {
|
|
13487
13540
|
const props = event.properties;
|
|
13488
13541
|
const err = props?.error;
|
|
13489
13542
|
const errMsg = err?.name ? `${err.name}${err?.data?.message ? ": " + err.data.message : ""}` : String(err ?? "unknown");
|
|
13490
|
-
|
|
13543
|
+
let payload = errMsg;
|
|
13544
|
+
if (props?.tool) {
|
|
13545
|
+
payload += ` [tool: ${props.tool}]`;
|
|
13546
|
+
} else if (props?.command) {
|
|
13547
|
+
payload += ` [command: ${props.command}]`;
|
|
13548
|
+
}
|
|
13549
|
+
errorTarget.write(formatLogLine(options, "error", payload) + `
|
|
13491
13550
|
`);
|
|
13492
13551
|
break;
|
|
13493
13552
|
}
|
|
@@ -13508,7 +13567,10 @@ function startSessionEventForwarder(client4, options) {
|
|
|
13508
13567
|
stop: () => {
|
|
13509
13568
|
cancelled = true;
|
|
13510
13569
|
},
|
|
13511
|
-
done: donePromise
|
|
13570
|
+
done: donePromise,
|
|
13571
|
+
onAgentEnd: (cb) => {
|
|
13572
|
+
agentEndCallbacks.push(cb);
|
|
13573
|
+
}
|
|
13512
13574
|
};
|
|
13513
13575
|
}
|
|
13514
13576
|
|
|
@@ -13629,7 +13691,12 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
13629
13691
|
agent: selected.name,
|
|
13630
13692
|
...composedSystem ? { system: composedSystem } : {},
|
|
13631
13693
|
parts: [{ type: "text", text: prompt }],
|
|
13632
|
-
...modelParts ? { model: modelParts } : {}
|
|
13694
|
+
...modelParts ? { model: modelParts } : {},
|
|
13695
|
+
tools: {
|
|
13696
|
+
task: false,
|
|
13697
|
+
question: false,
|
|
13698
|
+
external_directory: false
|
|
13699
|
+
}
|
|
13633
13700
|
}
|
|
13634
13701
|
}), PROMPT_ASYNC_TIMEOUT_MS, "session.promptAsync");
|
|
13635
13702
|
} catch (err) {
|
|
@@ -13688,6 +13755,9 @@ var init_opencode_sdk_agent_service = __esm(() => {
|
|
|
13688
13755
|
},
|
|
13689
13756
|
onOutput: (cb) => {
|
|
13690
13757
|
outputCallbacks.push(cb);
|
|
13758
|
+
},
|
|
13759
|
+
onAgentEnd: (cb) => {
|
|
13760
|
+
forwarder?.onAgentEnd(cb);
|
|
13691
13761
|
}
|
|
13692
13762
|
};
|
|
13693
13763
|
}
|
|
@@ -58879,6 +58949,13 @@ function handlePing() {
|
|
|
58879
58949
|
// src/commands/machine/daemon-start/handlers/command-runner.ts
|
|
58880
58950
|
import { spawn as spawn3 } from "node:child_process";
|
|
58881
58951
|
import { access as access3 } from "node:fs/promises";
|
|
58952
|
+
function evictStalePendingStops() {
|
|
58953
|
+
const evictBefore = Date.now() - PENDING_STOP_TTL_MS;
|
|
58954
|
+
for (const [runId, ts] of pendingStops) {
|
|
58955
|
+
if (ts < evictBefore)
|
|
58956
|
+
pendingStops.delete(runId);
|
|
58957
|
+
}
|
|
58958
|
+
}
|
|
58882
58959
|
async function reportRunFailed(ctx, runId, reason) {
|
|
58883
58960
|
try {
|
|
58884
58961
|
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
@@ -58923,6 +59000,21 @@ async function onCommandRun(ctx, event) {
|
|
|
58923
59000
|
console.log(`[${formatTimestamp()}] ⚠️ Command already running: ${runIdStr}`);
|
|
58924
59001
|
return;
|
|
58925
59002
|
}
|
|
59003
|
+
if (pendingStops.has(runIdStr)) {
|
|
59004
|
+
pendingStops.delete(runIdStr);
|
|
59005
|
+
console.log(`[${formatTimestamp()}] ⏭️ Skipping command run due to pending stop: ${commandName} (${runIdStr})`);
|
|
59006
|
+
try {
|
|
59007
|
+
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
59008
|
+
sessionId: ctx.sessionId,
|
|
59009
|
+
machineId: ctx.machineId,
|
|
59010
|
+
runId,
|
|
59011
|
+
status: "stopped"
|
|
59012
|
+
});
|
|
59013
|
+
} catch (err) {
|
|
59014
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Failed to update status to stopped for pending-stop skip: ${getErrorMessage(err)}`);
|
|
59015
|
+
}
|
|
59016
|
+
return;
|
|
59017
|
+
}
|
|
58926
59018
|
console.log(`[${formatTimestamp()}] \uD83D\uDE80 Running command: ${commandName} → ${script}`);
|
|
58927
59019
|
if (!workingDir.startsWith("/")) {
|
|
58928
59020
|
console.error(`[${formatTimestamp()}] ❌ Rejected command: workingDir is not absolute: ${workingDir}`);
|
|
@@ -58942,6 +59034,34 @@ async function onCommandRun(ctx, event) {
|
|
|
58942
59034
|
stdio: ["ignore", "pipe", "pipe"],
|
|
58943
59035
|
detached: true
|
|
58944
59036
|
});
|
|
59037
|
+
const timeoutTimer = setTimeout(() => {
|
|
59038
|
+
console.log(`[${formatTimestamp()}] ⏰ Command timed out after ${DEFAULT_COMMAND_TIMEOUT_MS / 60000} minutes: ${commandName} (runId: ${runIdStr})`);
|
|
59039
|
+
const pid = child.pid;
|
|
59040
|
+
if (pid) {
|
|
59041
|
+
try {
|
|
59042
|
+
process.kill(-pid, "SIGTERM");
|
|
59043
|
+
} catch {
|
|
59044
|
+
child.kill("SIGTERM");
|
|
59045
|
+
}
|
|
59046
|
+
} else {
|
|
59047
|
+
child.kill("SIGTERM");
|
|
59048
|
+
}
|
|
59049
|
+
setTimeout(() => {
|
|
59050
|
+
if (!runningProcesses.has(runIdStr))
|
|
59051
|
+
return;
|
|
59052
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing timed-out process: ${runIdStr}`);
|
|
59053
|
+
if (pid) {
|
|
59054
|
+
try {
|
|
59055
|
+
process.kill(-pid, "SIGKILL");
|
|
59056
|
+
} catch {
|
|
59057
|
+
child.kill("SIGKILL");
|
|
59058
|
+
}
|
|
59059
|
+
} else {
|
|
59060
|
+
child.kill("SIGKILL");
|
|
59061
|
+
}
|
|
59062
|
+
}, SIGTERM_GRACE_PERIOD_MS);
|
|
59063
|
+
}, DEFAULT_COMMAND_TIMEOUT_MS);
|
|
59064
|
+
timeoutTimer.unref?.();
|
|
58945
59065
|
const tracked = {
|
|
58946
59066
|
process: child,
|
|
58947
59067
|
runId: runIdStr,
|
|
@@ -58949,7 +59069,8 @@ async function onCommandRun(ctx, event) {
|
|
|
58949
59069
|
chunkIndex: 0,
|
|
58950
59070
|
flushTimer: setInterval(() => {
|
|
58951
59071
|
flushOutput(ctx, tracked).catch(() => {});
|
|
58952
|
-
}, OUTPUT_FLUSH_INTERVAL_MS)
|
|
59072
|
+
}, OUTPUT_FLUSH_INTERVAL_MS),
|
|
59073
|
+
timeoutTimer
|
|
58953
59074
|
};
|
|
58954
59075
|
tracked.flushTimer.unref?.();
|
|
58955
59076
|
runningProcesses.set(runIdStr, tracked);
|
|
@@ -58974,6 +59095,8 @@ async function onCommandRun(ctx, event) {
|
|
|
58974
59095
|
console.log(`[${formatTimestamp()}] \uD83C\uDFC1 Command exited: ${commandName} (code=${code2}, signal=${signal})`);
|
|
58975
59096
|
await flushOutput(ctx, tracked).catch(() => {});
|
|
58976
59097
|
clearInterval(tracked.flushTimer);
|
|
59098
|
+
if (tracked.timeoutTimer)
|
|
59099
|
+
clearTimeout(tracked.timeoutTimer);
|
|
58977
59100
|
runningProcesses.delete(runIdStr);
|
|
58978
59101
|
const status = code2 === 0 ? "completed" : signal ? "stopped" : "failed";
|
|
58979
59102
|
try {
|
|
@@ -58991,6 +59114,8 @@ async function onCommandRun(ctx, event) {
|
|
|
58991
59114
|
child.on("error", async (err) => {
|
|
58992
59115
|
console.error(`[${formatTimestamp()}] ❌ Command spawn failed: ${commandName}: ${err.message}`);
|
|
58993
59116
|
clearInterval(tracked.flushTimer);
|
|
59117
|
+
if (tracked.timeoutTimer)
|
|
59118
|
+
clearTimeout(tracked.timeoutTimer);
|
|
58994
59119
|
runningProcesses.delete(runIdStr);
|
|
58995
59120
|
try {
|
|
58996
59121
|
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
@@ -59004,11 +59129,42 @@ async function onCommandRun(ctx, event) {
|
|
|
59004
59129
|
}
|
|
59005
59130
|
});
|
|
59006
59131
|
}
|
|
59132
|
+
function killProcess(child, signal) {
|
|
59133
|
+
const pid = child.pid;
|
|
59134
|
+
if (pid) {
|
|
59135
|
+
try {
|
|
59136
|
+
process.kill(-pid, signal);
|
|
59137
|
+
return;
|
|
59138
|
+
} catch {}
|
|
59139
|
+
}
|
|
59140
|
+
try {
|
|
59141
|
+
child.kill(signal);
|
|
59142
|
+
} catch {}
|
|
59143
|
+
}
|
|
59144
|
+
function waitForExit(runIdStr, ms) {
|
|
59145
|
+
return new Promise((resolve5) => {
|
|
59146
|
+
const interval = 100;
|
|
59147
|
+
let elapsed = 0;
|
|
59148
|
+
const timer = setInterval(() => {
|
|
59149
|
+
if (!runningProcesses.has(runIdStr)) {
|
|
59150
|
+
clearInterval(timer);
|
|
59151
|
+
resolve5(true);
|
|
59152
|
+
return;
|
|
59153
|
+
}
|
|
59154
|
+
elapsed += interval;
|
|
59155
|
+
if (elapsed >= ms) {
|
|
59156
|
+
clearInterval(timer);
|
|
59157
|
+
resolve5(false);
|
|
59158
|
+
}
|
|
59159
|
+
}, interval);
|
|
59160
|
+
});
|
|
59161
|
+
}
|
|
59007
59162
|
async function onCommandStop(ctx, event) {
|
|
59008
59163
|
const runIdStr = event.runId.toString();
|
|
59009
59164
|
const tracked = runningProcesses.get(runIdStr);
|
|
59010
59165
|
if (!tracked) {
|
|
59011
|
-
console.log(`[${formatTimestamp()}] ⚠️ No running process found for run: ${runIdStr}`);
|
|
59166
|
+
console.log(`[${formatTimestamp()}] ⚠️ No running process found for run: ${runIdStr} — marking as stopped`);
|
|
59167
|
+
pendingStops.set(runIdStr, Date.now());
|
|
59012
59168
|
try {
|
|
59013
59169
|
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
59014
59170
|
sessionId: ctx.sessionId,
|
|
@@ -59016,44 +59172,85 @@ async function onCommandStop(ctx, event) {
|
|
|
59016
59172
|
runId: event.runId,
|
|
59017
59173
|
status: "stopped"
|
|
59018
59174
|
});
|
|
59019
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDCDD Marked orphaned run as stopped: ${runIdStr}`);
|
|
59020
59175
|
} catch (err) {
|
|
59021
|
-
console.warn(`[${formatTimestamp()}] ⚠️ Failed to mark
|
|
59176
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Failed to mark run as stopped (will retry): ${getErrorMessage(err)}`);
|
|
59177
|
+
throw err;
|
|
59022
59178
|
}
|
|
59023
59179
|
return;
|
|
59024
59180
|
}
|
|
59025
59181
|
console.log(`[${formatTimestamp()}] \uD83D\uDED1 Stopping command run: ${runIdStr}`);
|
|
59026
|
-
|
|
59027
|
-
|
|
59028
|
-
|
|
59029
|
-
process.kill(-pid, "SIGTERM");
|
|
59030
|
-
} catch {
|
|
59031
|
-
tracked.process.kill("SIGTERM");
|
|
59032
|
-
}
|
|
59033
|
-
} else {
|
|
59034
|
-
tracked.process.kill("SIGTERM");
|
|
59182
|
+
if (tracked.timeoutTimer) {
|
|
59183
|
+
clearTimeout(tracked.timeoutTimer);
|
|
59184
|
+
tracked.timeoutTimer = null;
|
|
59035
59185
|
}
|
|
59036
|
-
|
|
59037
|
-
|
|
59038
|
-
|
|
59186
|
+
killProcess(tracked.process, "SIGTERM");
|
|
59187
|
+
const exitedAfterSigterm = await waitForExit(runIdStr, SIGTERM_GRACE_PERIOD_MS);
|
|
59188
|
+
if (!exitedAfterSigterm) {
|
|
59039
59189
|
console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing process: ${runIdStr}`);
|
|
59190
|
+
killProcess(tracked.process, "SIGKILL");
|
|
59191
|
+
const exitedAfterSigkill = await waitForExit(runIdStr, 1000);
|
|
59192
|
+
if (!exitedAfterSigkill) {
|
|
59193
|
+
console.error(`[${formatTimestamp()}] ❌ Failed to stop process for run: ${runIdStr} — process did not exit after SIGKILL`);
|
|
59194
|
+
}
|
|
59195
|
+
}
|
|
59196
|
+
try {
|
|
59197
|
+
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
59198
|
+
sessionId: ctx.sessionId,
|
|
59199
|
+
machineId: ctx.machineId,
|
|
59200
|
+
runId: event.runId,
|
|
59201
|
+
status: "stopped"
|
|
59202
|
+
});
|
|
59203
|
+
} catch (err) {
|
|
59204
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Failed to mark run as stopped in backend: ${getErrorMessage(err)}`);
|
|
59205
|
+
}
|
|
59206
|
+
}
|
|
59207
|
+
async function shutdownAllCommands(ctx) {
|
|
59208
|
+
if (runningProcesses.size === 0)
|
|
59209
|
+
return;
|
|
59210
|
+
console.log(`[${formatTimestamp()}] Shutting down ${runningProcesses.size} running command(s)...`);
|
|
59211
|
+
for (const [, tracked] of runningProcesses) {
|
|
59212
|
+
clearInterval(tracked.flushTimer);
|
|
59213
|
+
if (tracked.timeoutTimer)
|
|
59214
|
+
clearTimeout(tracked.timeoutTimer);
|
|
59215
|
+
await flushOutput(ctx, tracked).catch(() => {});
|
|
59216
|
+
const pid = tracked.process.pid;
|
|
59040
59217
|
if (pid) {
|
|
59041
59218
|
try {
|
|
59042
|
-
process.kill(-pid, "
|
|
59219
|
+
process.kill(-pid, "SIGTERM");
|
|
59043
59220
|
} catch {
|
|
59044
|
-
tracked.process.kill("
|
|
59221
|
+
tracked.process.kill("SIGTERM");
|
|
59045
59222
|
}
|
|
59046
59223
|
} else {
|
|
59047
|
-
tracked.process.kill("
|
|
59224
|
+
tracked.process.kill("SIGTERM");
|
|
59225
|
+
}
|
|
59226
|
+
}
|
|
59227
|
+
await new Promise((resolve5) => {
|
|
59228
|
+
const t = setTimeout(resolve5, 3000);
|
|
59229
|
+
t.unref?.();
|
|
59230
|
+
});
|
|
59231
|
+
for (const [, tracked] of runningProcesses) {
|
|
59232
|
+
const pid = tracked.process.pid;
|
|
59233
|
+
if (pid) {
|
|
59234
|
+
try {
|
|
59235
|
+
process.kill(-pid, "SIGKILL");
|
|
59236
|
+
} catch {}
|
|
59237
|
+
} else {
|
|
59238
|
+
try {
|
|
59239
|
+
tracked.process.kill("SIGKILL");
|
|
59240
|
+
} catch {}
|
|
59048
59241
|
}
|
|
59049
|
-
}
|
|
59242
|
+
}
|
|
59243
|
+
runningProcesses.clear();
|
|
59244
|
+
console.log(`[${formatTimestamp()}] All commands stopped`);
|
|
59050
59245
|
}
|
|
59051
|
-
var runningProcesses, OUTPUT_FLUSH_INTERVAL_MS = 3000, MAX_BUFFER_SIZE;
|
|
59246
|
+
var runningProcesses, pendingStops, PENDING_STOP_TTL_MS = 60000, OUTPUT_FLUSH_INTERVAL_MS = 3000, MAX_BUFFER_SIZE, DEFAULT_COMMAND_TIMEOUT_MS, SIGTERM_GRACE_PERIOD_MS = 5000;
|
|
59052
59247
|
var init_command_runner = __esm(() => {
|
|
59053
59248
|
init_api3();
|
|
59054
59249
|
init_convex_error();
|
|
59055
59250
|
runningProcesses = new Map;
|
|
59251
|
+
pendingStops = new Map;
|
|
59056
59252
|
MAX_BUFFER_SIZE = 100 * 1024;
|
|
59253
|
+
DEFAULT_COMMAND_TIMEOUT_MS = 30 * 60 * 1000;
|
|
59057
59254
|
});
|
|
59058
59255
|
|
|
59059
59256
|
// src/commands/machine/daemon-start/handlers/state-recovery.ts
|
|
@@ -59097,6 +59294,14 @@ var init_state_recovery = __esm(() => {
|
|
|
59097
59294
|
init_api3();
|
|
59098
59295
|
});
|
|
59099
59296
|
|
|
59297
|
+
// src/commands/machine/daemon-start/capabilities-snapshot.ts
|
|
59298
|
+
function harnessCapabilitiesFingerprint(harnesses, versions) {
|
|
59299
|
+
const h = [...harnesses].sort().join("\x01");
|
|
59300
|
+
const keys = Object.keys(versions).sort();
|
|
59301
|
+
const v3 = keys.map((k) => `${k}:${JSON.stringify(versions[k] ?? null)}`).join("\x02");
|
|
59302
|
+
return `${h}::${v3}`;
|
|
59303
|
+
}
|
|
59304
|
+
|
|
59100
59305
|
// src/infrastructure/local-api/routes/identity.ts
|
|
59101
59306
|
async function handleIdentity(_req, ctx) {
|
|
59102
59307
|
const identity = {
|
|
@@ -60294,6 +60499,17 @@ async function recoverState(ctx) {
|
|
|
60294
60499
|
} catch (e) {
|
|
60295
60500
|
console.log(` ⚠️ Failed to clear stale PIDs: ${getErrorMessage(e)}`);
|
|
60296
60501
|
}
|
|
60502
|
+
try {
|
|
60503
|
+
const runResult = await ctx.deps.backend.mutation(api.commands.clearStaleCommandRuns, {
|
|
60504
|
+
sessionId: ctx.sessionId,
|
|
60505
|
+
machineId: ctx.machineId
|
|
60506
|
+
});
|
|
60507
|
+
if (runResult.clearedCount > 0) {
|
|
60508
|
+
console.log(` \uD83E\uDDF9 Cleared ${runResult.clearedCount} stale command run(s) from backend`);
|
|
60509
|
+
}
|
|
60510
|
+
} catch (e) {
|
|
60511
|
+
console.log(` ⚠️ Failed to clear stale command runs: ${getErrorMessage(e)}`);
|
|
60512
|
+
}
|
|
60297
60513
|
}
|
|
60298
60514
|
async function initDaemon() {
|
|
60299
60515
|
if (!acquireLock()) {
|
|
@@ -60344,6 +60560,7 @@ async function initDaemon() {
|
|
|
60344
60560
|
agentServices,
|
|
60345
60561
|
lastPushedGitState: new Map,
|
|
60346
60562
|
lastPushedModels: availableModels,
|
|
60563
|
+
lastPushedHarnessFingerprint: harnessCapabilitiesFingerprint(config3.availableHarnesses, config3.harnessVersions),
|
|
60347
60564
|
observedSyncEnabled: featureFlags.observedSyncEnabled ?? false
|
|
60348
60565
|
};
|
|
60349
60566
|
registerEventListeners(ctx);
|
|
@@ -60392,6 +60609,7 @@ var init_init2 = __esm(() => {
|
|
|
60392
60609
|
|
|
60393
60610
|
// src/events/lifecycle/on-daemon-shutdown.ts
|
|
60394
60611
|
async function onDaemonShutdown(ctx) {
|
|
60612
|
+
await shutdownAllCommands(ctx);
|
|
60395
60613
|
const activeAgents = ctx.deps.agentProcessManager.listActive();
|
|
60396
60614
|
if (activeAgents.length > 0) {
|
|
60397
60615
|
console.log(`[${formatTimestamp()}] Stopping ${activeAgents.length} agent(s)...`);
|
|
@@ -60420,6 +60638,7 @@ async function onDaemonShutdown(ctx) {
|
|
|
60420
60638
|
}
|
|
60421
60639
|
var init_on_daemon_shutdown = __esm(() => {
|
|
60422
60640
|
init_api3();
|
|
60641
|
+
init_command_runner();
|
|
60423
60642
|
});
|
|
60424
60643
|
|
|
60425
60644
|
// src/infrastructure/git/git-writer.ts
|
|
@@ -60611,15 +60830,18 @@ function formatModelMap(map) {
|
|
|
60611
60830
|
return Object.entries(map).map(([harness, models]) => `${harness}: ${models.join(", ")}`).join("; ");
|
|
60612
60831
|
}
|
|
60613
60832
|
async function refreshModels(ctx) {
|
|
60614
|
-
if (!ctx.config)
|
|
60615
|
-
return;
|
|
60833
|
+
if (!ctx.config) {
|
|
60834
|
+
return { kind: "noop" };
|
|
60835
|
+
}
|
|
60616
60836
|
const models = await discoverModels(ctx.agentServices);
|
|
60617
60837
|
const freshConfig = ensureMachineRegistered();
|
|
60618
60838
|
ctx.config.availableHarnesses = freshConfig.availableHarnesses;
|
|
60619
60839
|
ctx.config.harnessVersions = freshConfig.harnessVersions;
|
|
60620
|
-
const
|
|
60621
|
-
|
|
60622
|
-
|
|
60840
|
+
const modelDiff = diffModels(ctx.lastPushedModels, models);
|
|
60841
|
+
const nextHarnessFingerprint = harnessCapabilitiesFingerprint(ctx.config.availableHarnesses, ctx.config.harnessVersions);
|
|
60842
|
+
const harnessFingerprintChanged = ctx.lastPushedHarnessFingerprint !== null && nextHarnessFingerprint !== ctx.lastPushedHarnessFingerprint;
|
|
60843
|
+
if (!modelDiff.hasChanges && !harnessFingerprintChanged) {
|
|
60844
|
+
return { kind: "skipped_no_changes" };
|
|
60623
60845
|
}
|
|
60624
60846
|
const totalCount = Object.values(models).flat().length;
|
|
60625
60847
|
try {
|
|
@@ -60631,15 +60853,19 @@ async function refreshModels(ctx) {
|
|
|
60631
60853
|
availableModels: models
|
|
60632
60854
|
});
|
|
60633
60855
|
ctx.lastPushedModels = models;
|
|
60634
|
-
|
|
60635
|
-
|
|
60856
|
+
ctx.lastPushedHarnessFingerprint = nextHarnessFingerprint;
|
|
60857
|
+
if (Object.keys(modelDiff.added).length > 0) {
|
|
60858
|
+
console.log(`[${formatTimestamp()}] ➕ New models detected — ${formatModelMap(modelDiff.added)}`);
|
|
60636
60859
|
}
|
|
60637
|
-
if (Object.keys(
|
|
60638
|
-
console.log(`[${formatTimestamp()}] ➖ Models no longer available — ${formatModelMap(
|
|
60860
|
+
if (Object.keys(modelDiff.removed).length > 0) {
|
|
60861
|
+
console.log(`[${formatTimestamp()}] ➖ Models no longer available — ${formatModelMap(modelDiff.removed)}`);
|
|
60639
60862
|
}
|
|
60640
60863
|
console.log(`[${formatTimestamp()}] \uD83D\uDD04 Model refresh pushed: ${totalCount > 0 ? `${totalCount} models` : "none discovered"}`);
|
|
60864
|
+
return { kind: "pushed" };
|
|
60641
60865
|
} catch (error) {
|
|
60642
|
-
|
|
60866
|
+
const message = getErrorMessage(error);
|
|
60867
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Model refresh failed: ${message}`);
|
|
60868
|
+
return { kind: "failed", message };
|
|
60643
60869
|
}
|
|
60644
60870
|
}
|
|
60645
60871
|
function evictStaleDedupEntries(tracker) {
|
|
@@ -60656,6 +60882,10 @@ function evictStaleDedupEntries(tracker) {
|
|
|
60656
60882
|
if (ts2 < evictBefore)
|
|
60657
60883
|
tracker.gitRefreshIds.delete(id);
|
|
60658
60884
|
}
|
|
60885
|
+
for (const [id, ts2] of tracker.capabilitiesRefreshIds) {
|
|
60886
|
+
if (ts2 < evictBefore)
|
|
60887
|
+
tracker.capabilitiesRefreshIds.delete(id);
|
|
60888
|
+
}
|
|
60659
60889
|
for (const [id, ts2] of tracker.localActionIds) {
|
|
60660
60890
|
if (ts2 < evictBefore)
|
|
60661
60891
|
tracker.localActionIds.delete(id);
|
|
@@ -60668,6 +60898,7 @@ function evictStaleDedupEntries(tracker) {
|
|
|
60668
60898
|
if (ts2 < evictBefore)
|
|
60669
60899
|
tracker.commandStopIds.delete(id);
|
|
60670
60900
|
}
|
|
60901
|
+
evictStalePendingStops();
|
|
60671
60902
|
}
|
|
60672
60903
|
async function dispatchCommandEvent(ctx, event, tracker) {
|
|
60673
60904
|
const eventId = event._id.toString();
|
|
@@ -60675,40 +60906,40 @@ async function dispatchCommandEvent(ctx, event, tracker) {
|
|
|
60675
60906
|
if (event.type === "agent.requestStart") {
|
|
60676
60907
|
if (tracker.commandIds.has(eventId))
|
|
60677
60908
|
return;
|
|
60678
|
-
tracker.commandIds.set(eventId, Date.now());
|
|
60679
60909
|
await onRequestStartAgent(ctx, event);
|
|
60910
|
+
tracker.commandIds.set(eventId, Date.now());
|
|
60680
60911
|
} else if (event.type === "agent.requestStop") {
|
|
60681
60912
|
if (tracker.commandIds.has(eventId))
|
|
60682
60913
|
return;
|
|
60683
|
-
tracker.commandIds.set(eventId, Date.now());
|
|
60684
60914
|
await onRequestStopAgent(ctx, event);
|
|
60915
|
+
tracker.commandIds.set(eventId, Date.now());
|
|
60685
60916
|
} else if (event.type === "daemon.ping") {
|
|
60686
60917
|
if (tracker.pingIds.has(eventId))
|
|
60687
60918
|
return;
|
|
60688
|
-
tracker.pingIds.set(eventId, Date.now());
|
|
60689
60919
|
handlePing();
|
|
60690
60920
|
await ctx.deps.backend.mutation(api.machines.ackPing, {
|
|
60691
60921
|
sessionId: ctx.sessionId,
|
|
60692
60922
|
machineId: ctx.machineId,
|
|
60693
60923
|
pingEventId: event._id
|
|
60694
60924
|
});
|
|
60925
|
+
tracker.pingIds.set(eventId, Date.now());
|
|
60695
60926
|
} else if (event.type === "daemon.gitRefresh") {
|
|
60696
60927
|
if (tracker.gitRefreshIds.has(eventId))
|
|
60697
60928
|
return;
|
|
60698
|
-
tracker.gitRefreshIds.set(eventId, Date.now());
|
|
60699
60929
|
const stateKey = makeGitStateKey(ctx.machineId, event.workingDir);
|
|
60700
60930
|
ctx.lastPushedGitState.delete(stateKey);
|
|
60701
60931
|
console.log(`[${formatTimestamp()}] \uD83D\uDD04 Git refresh requested for ${event.workingDir}`);
|
|
60702
60932
|
await pushGitState(ctx);
|
|
60933
|
+
tracker.gitRefreshIds.set(eventId, Date.now());
|
|
60703
60934
|
} else if (event.type === "daemon.localAction") {
|
|
60704
60935
|
if (tracker.localActionIds.has(eventId))
|
|
60705
60936
|
return;
|
|
60706
|
-
tracker.localActionIds.set(eventId, Date.now());
|
|
60707
60937
|
console.log(`[${formatTimestamp()}] \uD83D\uDDA5️ Local action: ${event.action} → ${event.workingDir}`);
|
|
60708
60938
|
const result = await executeLocalAction(event.action, event.workingDir);
|
|
60709
60939
|
if (!result.success) {
|
|
60710
60940
|
console.warn(`[${formatTimestamp()}] ⚠️ Local action failed: ${result.error}`);
|
|
60711
60941
|
}
|
|
60942
|
+
tracker.localActionIds.set(eventId, Date.now());
|
|
60712
60943
|
} else if (eventType === "command.run") {
|
|
60713
60944
|
if (tracker.commandRunIds.has(eventId))
|
|
60714
60945
|
return;
|
|
@@ -60717,8 +60948,42 @@ async function dispatchCommandEvent(ctx, event, tracker) {
|
|
|
60717
60948
|
} else if (eventType === "command.stop") {
|
|
60718
60949
|
if (tracker.commandStopIds.has(eventId))
|
|
60719
60950
|
return;
|
|
60720
|
-
tracker.commandStopIds.set(eventId, Date.now());
|
|
60721
60951
|
await onCommandStop(ctx, event);
|
|
60952
|
+
tracker.commandStopIds.set(eventId, Date.now());
|
|
60953
|
+
} else if (event.type === "daemon.refreshCapabilities") {
|
|
60954
|
+
if (tracker.capabilitiesRefreshIds.has(eventId))
|
|
60955
|
+
return;
|
|
60956
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD04 Manual capabilities refresh requested`);
|
|
60957
|
+
const outcome = await refreshModels(ctx);
|
|
60958
|
+
tracker.capabilitiesRefreshIds.set(eventId, Date.now());
|
|
60959
|
+
const batchId = "batchId" in event && event.batchId !== undefined ? event.batchId : undefined;
|
|
60960
|
+
if (!batchId) {
|
|
60961
|
+
return;
|
|
60962
|
+
}
|
|
60963
|
+
let status;
|
|
60964
|
+
let errorMessage;
|
|
60965
|
+
if (outcome.kind === "pushed") {
|
|
60966
|
+
status = "completed";
|
|
60967
|
+
} else if (outcome.kind === "skipped_no_changes") {
|
|
60968
|
+
status = "skipped_no_changes";
|
|
60969
|
+
} else if (outcome.kind === "failed") {
|
|
60970
|
+
status = "failed";
|
|
60971
|
+
errorMessage = outcome.message;
|
|
60972
|
+
} else {
|
|
60973
|
+
status = "failed";
|
|
60974
|
+
errorMessage = "Daemon configuration unavailable";
|
|
60975
|
+
}
|
|
60976
|
+
try {
|
|
60977
|
+
await ctx.deps.backend.mutation(api.machines.reportCapabilitiesRefreshResult, {
|
|
60978
|
+
sessionId: ctx.sessionId,
|
|
60979
|
+
batchId,
|
|
60980
|
+
machineId: ctx.machineId,
|
|
60981
|
+
status,
|
|
60982
|
+
errorMessage
|
|
60983
|
+
});
|
|
60984
|
+
} catch (error) {
|
|
60985
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Capabilities refresh report failed: ${getErrorMessage(error)}`);
|
|
60986
|
+
}
|
|
60722
60987
|
}
|
|
60723
60988
|
}
|
|
60724
60989
|
async function startCommandLoop(ctx) {
|
|
@@ -60790,6 +61055,7 @@ Listening for commands...`);
|
|
|
60790
61055
|
commandIds: new Map,
|
|
60791
61056
|
pingIds: new Map,
|
|
60792
61057
|
gitRefreshIds: new Map,
|
|
61058
|
+
capabilitiesRefreshIds: new Map,
|
|
60793
61059
|
localActionIds: new Map,
|
|
60794
61060
|
commandRunIds: new Map,
|
|
60795
61061
|
commandStopIds: new Map
|
|
@@ -60810,15 +61076,8 @@ Listening for commands...`);
|
|
|
60810
61076
|
}
|
|
60811
61077
|
}
|
|
60812
61078
|
});
|
|
60813
|
-
const modelRefreshTimer = setInterval(() => {
|
|
60814
|
-
refreshModels(ctx).catch((err) => {
|
|
60815
|
-
console.warn(`[${formatTimestamp()}] ⚠️ Model refresh error: ${getErrorMessage(err)}`);
|
|
60816
|
-
});
|
|
60817
|
-
}, MODEL_REFRESH_INTERVAL_MS);
|
|
60818
|
-
modelRefreshTimer.unref();
|
|
60819
61079
|
return await new Promise(() => {});
|
|
60820
61080
|
}
|
|
60821
|
-
var MODEL_REFRESH_INTERVAL_MS;
|
|
60822
61081
|
var init_command_loop = __esm(() => {
|
|
60823
61082
|
init_on_request_start_agent();
|
|
60824
61083
|
init_on_request_stop_agent();
|
|
@@ -60837,7 +61096,6 @@ var init_command_loop = __esm(() => {
|
|
|
60837
61096
|
init_local_actions();
|
|
60838
61097
|
init_machine();
|
|
60839
61098
|
init_convex_error();
|
|
60840
|
-
MODEL_REFRESH_INTERVAL_MS = 10 * 1000;
|
|
60841
61099
|
});
|
|
60842
61100
|
|
|
60843
61101
|
// src/commands/machine/daemon-start/index.ts
|
|
@@ -61934,5 +62192,5 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
61934
62192
|
});
|
|
61935
62193
|
program2.parse();
|
|
61936
62194
|
|
|
61937
|
-
//# debugId=
|
|
62195
|
+
//# debugId=967EF2E82583BAE364756E2164756E21
|
|
61938
62196
|
//# sourceMappingURL=index.js.map
|