chatroom-cli 1.43.2 → 1.44.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.
- package/dist/index.js +585 -150
- package/dist/index.js.map +16 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27123,6 +27123,207 @@ var init_claude = __esm(() => {
|
|
|
27123
27123
|
init_claude_code_agent_service();
|
|
27124
27124
|
});
|
|
27125
27125
|
|
|
27126
|
+
// src/infrastructure/services/remote-agents/commandcode/command-code-stream-reader.ts
|
|
27127
|
+
import { createInterface as createInterface5 } from "node:readline";
|
|
27128
|
+
|
|
27129
|
+
class CommandCodeStreamReader {
|
|
27130
|
+
textCallbacks = [];
|
|
27131
|
+
agentEndCallbacks = [];
|
|
27132
|
+
anyEventCallbacks = [];
|
|
27133
|
+
constructor(stream) {
|
|
27134
|
+
const rl = createInterface5({ input: stream, crlfDelay: Infinity });
|
|
27135
|
+
rl.on("line", (line) => {
|
|
27136
|
+
const trimmed = line.trim();
|
|
27137
|
+
if (!trimmed)
|
|
27138
|
+
return;
|
|
27139
|
+
for (const cb of this.anyEventCallbacks)
|
|
27140
|
+
cb();
|
|
27141
|
+
for (const cb of this.textCallbacks)
|
|
27142
|
+
cb(trimmed);
|
|
27143
|
+
});
|
|
27144
|
+
stream.on("close", () => {
|
|
27145
|
+
for (const cb of this.agentEndCallbacks)
|
|
27146
|
+
cb();
|
|
27147
|
+
});
|
|
27148
|
+
}
|
|
27149
|
+
onText(cb) {
|
|
27150
|
+
this.textCallbacks.push(cb);
|
|
27151
|
+
}
|
|
27152
|
+
onAnyEvent(cb) {
|
|
27153
|
+
this.anyEventCallbacks.push(cb);
|
|
27154
|
+
}
|
|
27155
|
+
onAgentEnd(cb) {
|
|
27156
|
+
this.agentEndCallbacks.push(cb);
|
|
27157
|
+
}
|
|
27158
|
+
}
|
|
27159
|
+
var init_command_code_stream_reader = () => {};
|
|
27160
|
+
|
|
27161
|
+
// src/infrastructure/services/remote-agents/commandcode/command-code-agent-service.ts
|
|
27162
|
+
var COMMANDCODE_COMMAND = "cmd", COMMANDCODE_MODELS, CommandCodeAgentService;
|
|
27163
|
+
var init_command_code_agent_service = __esm(() => {
|
|
27164
|
+
init_base_cli_agent_service();
|
|
27165
|
+
init_command_code_stream_reader();
|
|
27166
|
+
COMMANDCODE_MODELS = [
|
|
27167
|
+
"claude-sonnet-4-6",
|
|
27168
|
+
"claude-opus-4-7",
|
|
27169
|
+
"claude-opus-4-6",
|
|
27170
|
+
"claude-haiku-4-5",
|
|
27171
|
+
"gpt-5.5",
|
|
27172
|
+
"gpt-5.4",
|
|
27173
|
+
"gpt-5.3-codex",
|
|
27174
|
+
"gpt-5.4-mini",
|
|
27175
|
+
"google/gemini-3.5-flash",
|
|
27176
|
+
"google/gemini-3.1-flash-lite",
|
|
27177
|
+
"moonshotai/Kimi-K2.6",
|
|
27178
|
+
"moonshotai/Kimi-K2.5",
|
|
27179
|
+
"zai-org/GLM-5.1",
|
|
27180
|
+
"zai-org/GLM-5",
|
|
27181
|
+
"MiniMaxAI/MiniMax-M2.7",
|
|
27182
|
+
"MiniMaxAI/MiniMax-M2.5",
|
|
27183
|
+
"deepseek/deepseek-v4-pro",
|
|
27184
|
+
"deepseek/deepseek-v4-flash",
|
|
27185
|
+
"Qwen/Qwen3.6-Max-Preview",
|
|
27186
|
+
"Qwen/Qwen3.6-Plus",
|
|
27187
|
+
"Qwen/Qwen3.7-Max",
|
|
27188
|
+
"stepfun/Step-3.5-Flash"
|
|
27189
|
+
];
|
|
27190
|
+
CommandCodeAgentService = class CommandCodeAgentService extends BaseCLIAgentService {
|
|
27191
|
+
id = "commandcode";
|
|
27192
|
+
displayName = "CommandCode";
|
|
27193
|
+
command = COMMANDCODE_COMMAND;
|
|
27194
|
+
constructor(deps) {
|
|
27195
|
+
super(deps);
|
|
27196
|
+
}
|
|
27197
|
+
async isInstalled() {
|
|
27198
|
+
return this.checkInstalled(COMMANDCODE_COMMAND);
|
|
27199
|
+
}
|
|
27200
|
+
async getVersion() {
|
|
27201
|
+
return this.checkVersion(COMMANDCODE_COMMAND);
|
|
27202
|
+
}
|
|
27203
|
+
async listModels() {
|
|
27204
|
+
return COMMANDCODE_MODELS;
|
|
27205
|
+
}
|
|
27206
|
+
async spawn(options) {
|
|
27207
|
+
const args2 = ["-p", "--skip-onboarding", "--yolo", "--max-turns", "999999"];
|
|
27208
|
+
if (options.model) {
|
|
27209
|
+
args2.push("--model", options.model);
|
|
27210
|
+
}
|
|
27211
|
+
const fullPrompt = options.systemPrompt ? `${options.systemPrompt}
|
|
27212
|
+
|
|
27213
|
+
${options.prompt}` : options.prompt;
|
|
27214
|
+
const childProcess = this.deps.spawn(COMMANDCODE_COMMAND, args2, {
|
|
27215
|
+
cwd: options.workingDir,
|
|
27216
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
27217
|
+
shell: false,
|
|
27218
|
+
detached: true,
|
|
27219
|
+
env: {
|
|
27220
|
+
...process.env,
|
|
27221
|
+
GIT_EDITOR: "true",
|
|
27222
|
+
GIT_SEQUENCE_EDITOR: "true"
|
|
27223
|
+
}
|
|
27224
|
+
});
|
|
27225
|
+
childProcess.stdin?.write(fullPrompt);
|
|
27226
|
+
childProcess.stdin?.end();
|
|
27227
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
27228
|
+
if (childProcess.killed || childProcess.exitCode !== null) {
|
|
27229
|
+
throw new Error(`Agent process exited immediately (exit code: ${childProcess.exitCode})`);
|
|
27230
|
+
}
|
|
27231
|
+
if (!childProcess.pid) {
|
|
27232
|
+
throw new Error("Agent process started but has no PID");
|
|
27233
|
+
}
|
|
27234
|
+
const pid = childProcess.pid;
|
|
27235
|
+
const context4 = options.context;
|
|
27236
|
+
const entry = this.registerProcess(pid, context4);
|
|
27237
|
+
const roleTag = context4.role ?? "unknown";
|
|
27238
|
+
const chatroomSuffix = context4.chatroomId ? `@${context4.chatroomId.slice(-6)}` : "";
|
|
27239
|
+
const logPrefix = `[commandcode:${roleTag}${chatroomSuffix}`;
|
|
27240
|
+
const outputCallbacks = [];
|
|
27241
|
+
if (childProcess.stdout) {
|
|
27242
|
+
const reader = new CommandCodeStreamReader(childProcess.stdout);
|
|
27243
|
+
let textBuffer = "";
|
|
27244
|
+
const flushText = () => {
|
|
27245
|
+
if (!textBuffer)
|
|
27246
|
+
return;
|
|
27247
|
+
for (const line of textBuffer.split(`
|
|
27248
|
+
`)) {
|
|
27249
|
+
if (line)
|
|
27250
|
+
process.stdout.write(`${logPrefix} text] ${line}
|
|
27251
|
+
`);
|
|
27252
|
+
}
|
|
27253
|
+
textBuffer = "";
|
|
27254
|
+
};
|
|
27255
|
+
reader.onText((text) => {
|
|
27256
|
+
textBuffer += text;
|
|
27257
|
+
if (textBuffer.includes(`
|
|
27258
|
+
`))
|
|
27259
|
+
flushText();
|
|
27260
|
+
entry.lastOutputAt = Date.now();
|
|
27261
|
+
for (const cb of outputCallbacks)
|
|
27262
|
+
cb();
|
|
27263
|
+
});
|
|
27264
|
+
reader.onAnyEvent(() => {
|
|
27265
|
+
entry.lastOutputAt = Date.now();
|
|
27266
|
+
for (const cb of outputCallbacks)
|
|
27267
|
+
cb();
|
|
27268
|
+
});
|
|
27269
|
+
reader.onAgentEnd(() => {
|
|
27270
|
+
flushText();
|
|
27271
|
+
process.stdout.write(`${logPrefix} agent_end]
|
|
27272
|
+
`);
|
|
27273
|
+
});
|
|
27274
|
+
if (childProcess.stderr) {
|
|
27275
|
+
childProcess.stderr.pipe(process.stderr, { end: false });
|
|
27276
|
+
childProcess.stderr.on("data", () => {
|
|
27277
|
+
entry.lastOutputAt = Date.now();
|
|
27278
|
+
for (const cb of outputCallbacks)
|
|
27279
|
+
cb();
|
|
27280
|
+
});
|
|
27281
|
+
}
|
|
27282
|
+
return {
|
|
27283
|
+
pid,
|
|
27284
|
+
onExit: (cb) => {
|
|
27285
|
+
childProcess.on("exit", (code2, signal) => {
|
|
27286
|
+
this.deleteProcess(pid);
|
|
27287
|
+
cb({ code: code2, signal, context: context4 });
|
|
27288
|
+
});
|
|
27289
|
+
},
|
|
27290
|
+
onOutput: (cb) => {
|
|
27291
|
+
outputCallbacks.push(cb);
|
|
27292
|
+
},
|
|
27293
|
+
onAgentEnd: (cb) => {
|
|
27294
|
+
reader.onAgentEnd(cb);
|
|
27295
|
+
}
|
|
27296
|
+
};
|
|
27297
|
+
}
|
|
27298
|
+
if (childProcess.stderr) {
|
|
27299
|
+
childProcess.stderr.pipe(process.stderr, { end: false });
|
|
27300
|
+
childProcess.stderr.on("data", () => {
|
|
27301
|
+
entry.lastOutputAt = Date.now();
|
|
27302
|
+
for (const cb of outputCallbacks)
|
|
27303
|
+
cb();
|
|
27304
|
+
});
|
|
27305
|
+
}
|
|
27306
|
+
return {
|
|
27307
|
+
pid,
|
|
27308
|
+
onExit: (cb) => {
|
|
27309
|
+
childProcess.on("exit", (code2, signal) => {
|
|
27310
|
+
this.deleteProcess(pid);
|
|
27311
|
+
cb({ code: code2, signal, context: context4 });
|
|
27312
|
+
});
|
|
27313
|
+
},
|
|
27314
|
+
onOutput: (cb) => {
|
|
27315
|
+
outputCallbacks.push(cb);
|
|
27316
|
+
}
|
|
27317
|
+
};
|
|
27318
|
+
}
|
|
27319
|
+
};
|
|
27320
|
+
});
|
|
27321
|
+
|
|
27322
|
+
// src/infrastructure/services/remote-agents/commandcode/index.ts
|
|
27323
|
+
var init_commandcode = __esm(() => {
|
|
27324
|
+
init_command_code_agent_service();
|
|
27325
|
+
});
|
|
27326
|
+
|
|
27126
27327
|
// ../../node_modules/.pnpm/@opencode-ai+sdk@1.14.22/node_modules/@opencode-ai/sdk/dist/gen/types.gen.js
|
|
27127
27328
|
var init_types_gen = () => {};
|
|
27128
27329
|
|
|
@@ -29517,12 +29718,14 @@ function initHarnessRegistry() {
|
|
|
29517
29718
|
registerHarness(new PiAgentService);
|
|
29518
29719
|
registerHarness(new CursorAgentService);
|
|
29519
29720
|
registerHarness(new ClaudeCodeAgentService);
|
|
29721
|
+
registerHarness(new CommandCodeAgentService);
|
|
29520
29722
|
registerHarness(new CopilotAgentService);
|
|
29521
29723
|
initialized = true;
|
|
29522
29724
|
}
|
|
29523
29725
|
var initialized = false;
|
|
29524
29726
|
var init_init_registry = __esm(() => {
|
|
29525
29727
|
init_claude();
|
|
29728
|
+
init_commandcode();
|
|
29526
29729
|
init_copilot();
|
|
29527
29730
|
init_cursor();
|
|
29528
29731
|
init_opencode();
|
|
@@ -69493,6 +69696,7 @@ var init_errorCodes = __esm(() => {
|
|
|
69493
69696
|
COMMAND_NOT_RUNNING: "COMMAND_NOT_RUNNING",
|
|
69494
69697
|
TOO_MANY_COMMANDS: "TOO_MANY_COMMANDS",
|
|
69495
69698
|
INVALID_STATE_TRANSITION: "INVALID_STATE_TRANSITION",
|
|
69699
|
+
INVALID_RUN_STATE_TRANSITION: "INVALID_RUN_STATE_TRANSITION",
|
|
69496
69700
|
OUTPUT_CHUNK_TOO_LARGE: "OUTPUT_CHUNK_TOO_LARGE",
|
|
69497
69701
|
NOT_FOUND: "NOT_FOUND",
|
|
69498
69702
|
INVALID_BOT_TOKEN: "INVALID_BOT_TOKEN",
|
|
@@ -69573,6 +69777,7 @@ var init_errorCodes = __esm(() => {
|
|
|
69573
69777
|
BACKEND_ERROR_CODES.INVALID_STDIN_FORMAT,
|
|
69574
69778
|
BACKEND_ERROR_CODES.INVALID_BOT_TOKEN,
|
|
69575
69779
|
BACKEND_ERROR_CODES.INVALID_STATE_TRANSITION,
|
|
69780
|
+
BACKEND_ERROR_CODES.INVALID_RUN_STATE_TRANSITION,
|
|
69576
69781
|
BACKEND_ERROR_CODES.TASK_INVALID_TRANSITION,
|
|
69577
69782
|
BACKEND_ERROR_CODES.TASK_MISSING_REQUIRED_FIELD,
|
|
69578
69783
|
BACKEND_ERROR_CODES.TASK_VALIDATION_FAILED,
|
|
@@ -75936,31 +76141,248 @@ var init_file_tree_subscription = __esm(() => {
|
|
|
75936
76141
|
init_convex_error();
|
|
75937
76142
|
});
|
|
75938
76143
|
|
|
75939
|
-
// src/commands/machine/daemon-start/handlers/
|
|
75940
|
-
import {
|
|
75941
|
-
import {
|
|
75942
|
-
|
|
75943
|
-
|
|
75944
|
-
|
|
75945
|
-
|
|
75946
|
-
|
|
76144
|
+
// src/commands/machine/daemon-start/handlers/orphan-tracker.ts
|
|
76145
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
76146
|
+
import {
|
|
76147
|
+
appendFileSync,
|
|
76148
|
+
existsSync as existsSync3,
|
|
76149
|
+
mkdirSync as mkdirSync3,
|
|
76150
|
+
readFileSync as readFileSync5,
|
|
76151
|
+
renameSync,
|
|
76152
|
+
unlinkSync as unlinkSync2,
|
|
76153
|
+
writeFileSync as writeFileSync3
|
|
76154
|
+
} from "node:fs";
|
|
76155
|
+
import { homedir as homedir6 } from "node:os";
|
|
76156
|
+
import { join as join15 } from "node:path";
|
|
76157
|
+
function getUrlHash2() {
|
|
76158
|
+
const url2 = getConvexUrl();
|
|
76159
|
+
return createHash6("sha256").update(url2).digest("hex").substring(0, 8);
|
|
76160
|
+
}
|
|
76161
|
+
function getChildPidsFilePath() {
|
|
76162
|
+
const dir = join15(homedir6(), ".chatroom");
|
|
76163
|
+
return join15(dir, `daemon-children-${getUrlHash2()}.pids`);
|
|
76164
|
+
}
|
|
76165
|
+
function ensureChatroomDir3() {
|
|
76166
|
+
const dir = join15(homedir6(), ".chatroom");
|
|
76167
|
+
if (!existsSync3(dir)) {
|
|
76168
|
+
mkdirSync3(dir, { recursive: true, mode: 448 });
|
|
75947
76169
|
}
|
|
75948
76170
|
}
|
|
75949
|
-
function
|
|
75950
|
-
|
|
76171
|
+
function readPids() {
|
|
76172
|
+
const filePath = getChildPidsFilePath();
|
|
76173
|
+
if (!existsSync3(filePath))
|
|
76174
|
+
return [];
|
|
76175
|
+
try {
|
|
76176
|
+
return readFileSync5(filePath, "utf-8").split(`
|
|
76177
|
+
`).map((line) => parseInt(line.trim(), 10)).filter((n) => Number.isFinite(n) && n > 0);
|
|
76178
|
+
} catch {
|
|
76179
|
+
return [];
|
|
76180
|
+
}
|
|
75951
76181
|
}
|
|
75952
|
-
|
|
76182
|
+
function trackChildPid(pid) {
|
|
75953
76183
|
try {
|
|
75954
|
-
|
|
75955
|
-
|
|
75956
|
-
|
|
75957
|
-
|
|
75958
|
-
|
|
76184
|
+
ensureChatroomDir3();
|
|
76185
|
+
appendFileSync(getChildPidsFilePath(), `${pid}
|
|
76186
|
+
`, "utf-8");
|
|
76187
|
+
} catch (err) {
|
|
76188
|
+
console.warn(`[orphan-tracker] Failed to track child PID ${pid}: ${err}`);
|
|
76189
|
+
}
|
|
76190
|
+
}
|
|
76191
|
+
function untrackChildPid(pid) {
|
|
76192
|
+
try {
|
|
76193
|
+
const filePath = getChildPidsFilePath();
|
|
76194
|
+
if (!existsSync3(filePath))
|
|
76195
|
+
return;
|
|
76196
|
+
const remaining = readFileSync5(filePath, "utf-8").split(`
|
|
76197
|
+
`).filter((line) => {
|
|
76198
|
+
const n = parseInt(line.trim(), 10);
|
|
76199
|
+
return Number.isFinite(n) && n > 0 && n !== pid;
|
|
75959
76200
|
});
|
|
76201
|
+
const tmpPath = `${filePath}.tmp`;
|
|
76202
|
+
writeFileSync3(tmpPath, remaining.join(`
|
|
76203
|
+
`) + (remaining.length > 0 ? `
|
|
76204
|
+
` : ""), "utf-8");
|
|
76205
|
+
renameSync(tmpPath, filePath);
|
|
75960
76206
|
} catch (err) {
|
|
75961
|
-
console.warn(`[
|
|
76207
|
+
console.warn(`[orphan-tracker] Failed to untrack child PID ${pid}: ${err}`);
|
|
75962
76208
|
}
|
|
75963
76209
|
}
|
|
76210
|
+
function clearTrackedPids() {
|
|
76211
|
+
try {
|
|
76212
|
+
const filePath = getChildPidsFilePath();
|
|
76213
|
+
if (existsSync3(filePath)) {
|
|
76214
|
+
unlinkSync2(filePath);
|
|
76215
|
+
}
|
|
76216
|
+
} catch {}
|
|
76217
|
+
}
|
|
76218
|
+
async function reapOrphanedProcessGroups() {
|
|
76219
|
+
const pids = readPids();
|
|
76220
|
+
let reaped = 0;
|
|
76221
|
+
const checked = pids.length;
|
|
76222
|
+
for (const pgid of pids) {
|
|
76223
|
+
if (process.platform === "win32")
|
|
76224
|
+
continue;
|
|
76225
|
+
try {
|
|
76226
|
+
process.kill(-pgid, 0);
|
|
76227
|
+
} catch {
|
|
76228
|
+
continue;
|
|
76229
|
+
}
|
|
76230
|
+
try {
|
|
76231
|
+
process.kill(-pgid, "SIGTERM");
|
|
76232
|
+
} catch {
|
|
76233
|
+
continue;
|
|
76234
|
+
}
|
|
76235
|
+
const deadline = Date.now() + 500;
|
|
76236
|
+
let alive = true;
|
|
76237
|
+
while (Date.now() < deadline) {
|
|
76238
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
76239
|
+
try {
|
|
76240
|
+
process.kill(-pgid, 0);
|
|
76241
|
+
} catch {
|
|
76242
|
+
alive = false;
|
|
76243
|
+
break;
|
|
76244
|
+
}
|
|
76245
|
+
}
|
|
76246
|
+
if (alive) {
|
|
76247
|
+
try {
|
|
76248
|
+
process.kill(-pgid, "SIGKILL");
|
|
76249
|
+
} catch {}
|
|
76250
|
+
}
|
|
76251
|
+
console.log(`[orphan-tracker] Reaped orphan process group ${pgid}`);
|
|
76252
|
+
reaped++;
|
|
76253
|
+
}
|
|
76254
|
+
clearTrackedPids();
|
|
76255
|
+
return { reaped, checked };
|
|
76256
|
+
}
|
|
76257
|
+
var CHATROOM_DIR5;
|
|
76258
|
+
var init_orphan_tracker = __esm(() => {
|
|
76259
|
+
init_client2();
|
|
76260
|
+
CHATROOM_DIR5 = join15(homedir6(), ".chatroom");
|
|
76261
|
+
});
|
|
76262
|
+
|
|
76263
|
+
// src/commands/machine/daemon-start/handlers/process/state.ts
|
|
76264
|
+
function deriveTerminalStatus(code2, signal, terminationIntent) {
|
|
76265
|
+
if (terminationIntent !== null)
|
|
76266
|
+
return terminationIntent;
|
|
76267
|
+
if (code2 === 0)
|
|
76268
|
+
return "completed";
|
|
76269
|
+
if (signal !== null)
|
|
76270
|
+
return "stopped";
|
|
76271
|
+
return "failed";
|
|
76272
|
+
}
|
|
76273
|
+
var TERMINAL_STATES, PENDING_STOP_TTL_MS = 60000, SIGTERM_GRACE_PERIOD_MS = 5000, SOFT_TIMEOUT_MS, OUTPUT_FLUSH_INTERVAL_MS = 3000, MAX_BUFFER_SIZE;
|
|
76274
|
+
var init_state2 = __esm(() => {
|
|
76275
|
+
TERMINAL_STATES = new Set(["completed", "failed", "stopped", "killed"]);
|
|
76276
|
+
SOFT_TIMEOUT_MS = 24 * 60 * 60 * 1000;
|
|
76277
|
+
MAX_BUFFER_SIZE = 100 * 1024;
|
|
76278
|
+
});
|
|
76279
|
+
|
|
76280
|
+
// src/commands/machine/daemon-start/handlers/process/manager.ts
|
|
76281
|
+
class ProcessManager {
|
|
76282
|
+
runningProcesses = new Map;
|
|
76283
|
+
runningProcessesByCommand = new Map;
|
|
76284
|
+
pendingStops = new Map;
|
|
76285
|
+
has(runId) {
|
|
76286
|
+
return this.runningProcesses.has(runId);
|
|
76287
|
+
}
|
|
76288
|
+
get(runId) {
|
|
76289
|
+
return this.runningProcesses.get(runId);
|
|
76290
|
+
}
|
|
76291
|
+
getByCommand(commandKey) {
|
|
76292
|
+
const runId = this.runningProcessesByCommand.get(commandKey);
|
|
76293
|
+
if (runId === undefined)
|
|
76294
|
+
return;
|
|
76295
|
+
return this.runningProcesses.get(runId);
|
|
76296
|
+
}
|
|
76297
|
+
getAll() {
|
|
76298
|
+
return [...this.runningProcesses.entries()];
|
|
76299
|
+
}
|
|
76300
|
+
get size() {
|
|
76301
|
+
return this.runningProcesses.size;
|
|
76302
|
+
}
|
|
76303
|
+
register(runId, commandKey, process2) {
|
|
76304
|
+
this.runningProcesses.set(runId, process2);
|
|
76305
|
+
this.runningProcessesByCommand.set(commandKey, runId);
|
|
76306
|
+
}
|
|
76307
|
+
unregister(runId, commandKey) {
|
|
76308
|
+
this.runningProcesses.delete(runId);
|
|
76309
|
+
if (this.runningProcessesByCommand.get(commandKey) === runId) {
|
|
76310
|
+
this.runningProcessesByCommand.delete(commandKey);
|
|
76311
|
+
}
|
|
76312
|
+
}
|
|
76313
|
+
markPendingStop(runId) {
|
|
76314
|
+
this.pendingStops.set(runId, Date.now());
|
|
76315
|
+
}
|
|
76316
|
+
hasPendingStop(runId) {
|
|
76317
|
+
return this.pendingStops.has(runId);
|
|
76318
|
+
}
|
|
76319
|
+
consumePendingStop(runId) {
|
|
76320
|
+
const has5 = this.pendingStops.has(runId);
|
|
76321
|
+
if (has5)
|
|
76322
|
+
this.pendingStops.delete(runId);
|
|
76323
|
+
return has5;
|
|
76324
|
+
}
|
|
76325
|
+
evictStalePendingStops() {
|
|
76326
|
+
const evictBefore = Date.now() - PENDING_STOP_TTL_MS;
|
|
76327
|
+
for (const [runId, ts] of this.pendingStops) {
|
|
76328
|
+
if (ts < evictBefore)
|
|
76329
|
+
this.pendingStops.delete(runId);
|
|
76330
|
+
}
|
|
76331
|
+
}
|
|
76332
|
+
clear() {
|
|
76333
|
+
this.runningProcesses.clear();
|
|
76334
|
+
this.runningProcessesByCommand.clear();
|
|
76335
|
+
this.pendingStops.clear();
|
|
76336
|
+
}
|
|
76337
|
+
waitForExit(runId, ms) {
|
|
76338
|
+
return new Promise((resolve5) => {
|
|
76339
|
+
const interval = 100;
|
|
76340
|
+
let elapsed3 = 0;
|
|
76341
|
+
const timer = setInterval(() => {
|
|
76342
|
+
if (!this.runningProcesses.has(runId)) {
|
|
76343
|
+
clearInterval(timer);
|
|
76344
|
+
resolve5(true);
|
|
76345
|
+
return;
|
|
76346
|
+
}
|
|
76347
|
+
elapsed3 += interval;
|
|
76348
|
+
if (elapsed3 >= ms) {
|
|
76349
|
+
clearInterval(timer);
|
|
76350
|
+
resolve5(false);
|
|
76351
|
+
}
|
|
76352
|
+
}, interval);
|
|
76353
|
+
});
|
|
76354
|
+
}
|
|
76355
|
+
}
|
|
76356
|
+
var processManager;
|
|
76357
|
+
var init_manager = __esm(() => {
|
|
76358
|
+
init_state2();
|
|
76359
|
+
processManager = new ProcessManager;
|
|
76360
|
+
});
|
|
76361
|
+
|
|
76362
|
+
// src/commands/machine/daemon-start/handlers/process/killer.ts
|
|
76363
|
+
function killProcess(child, signal) {
|
|
76364
|
+
if (child.pid == null)
|
|
76365
|
+
return;
|
|
76366
|
+
try {
|
|
76367
|
+
process.kill(-child.pid, signal);
|
|
76368
|
+
} catch {}
|
|
76369
|
+
}
|
|
76370
|
+
async function killTrackedProcess(tracked) {
|
|
76371
|
+
killProcess(tracked.process, "SIGTERM");
|
|
76372
|
+
const exited = await processManager.waitForExit(tracked.runId, SIGTERM_GRACE_PERIOD_MS);
|
|
76373
|
+
if (!exited) {
|
|
76374
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing process: ${tracked.runId}`);
|
|
76375
|
+
killProcess(tracked.process, "SIGKILL");
|
|
76376
|
+
await processManager.waitForExit(tracked.runId, 1000);
|
|
76377
|
+
}
|
|
76378
|
+
}
|
|
76379
|
+
var init_killer = __esm(() => {
|
|
76380
|
+
init_state2();
|
|
76381
|
+
init_manager();
|
|
76382
|
+
});
|
|
76383
|
+
|
|
76384
|
+
// src/commands/machine/daemon-start/handlers/process/spawner.ts
|
|
76385
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
75964
76386
|
async function flushOutput(ctx, tracked) {
|
|
75965
76387
|
if (tracked.outputBuffer.length === 0)
|
|
75966
76388
|
return;
|
|
@@ -75986,91 +76408,14 @@ function appendToBuffer(ctx, tracked, data) {
|
|
|
75986
76408
|
flushOutput(ctx, tracked).catch(() => {});
|
|
75987
76409
|
}
|
|
75988
76410
|
}
|
|
75989
|
-
function
|
|
75990
|
-
try {
|
|
75991
|
-
child.kill(signal);
|
|
75992
|
-
} catch {}
|
|
75993
|
-
}
|
|
75994
|
-
function waitForExit(runIdStr, ms) {
|
|
75995
|
-
return new Promise((resolve5) => {
|
|
75996
|
-
const interval = 100;
|
|
75997
|
-
let elapsed3 = 0;
|
|
75998
|
-
const timer = setInterval(() => {
|
|
75999
|
-
if (!runningProcesses.has(runIdStr)) {
|
|
76000
|
-
clearInterval(timer);
|
|
76001
|
-
resolve5(true);
|
|
76002
|
-
return;
|
|
76003
|
-
}
|
|
76004
|
-
elapsed3 += interval;
|
|
76005
|
-
if (elapsed3 >= ms) {
|
|
76006
|
-
clearInterval(timer);
|
|
76007
|
-
resolve5(false);
|
|
76008
|
-
}
|
|
76009
|
-
}, interval);
|
|
76010
|
-
});
|
|
76011
|
-
}
|
|
76012
|
-
async function killTrackedProcess(tracked) {
|
|
76013
|
-
killProcess(tracked.process, "SIGTERM");
|
|
76014
|
-
const exited = await waitForExit(tracked.runId, SIGTERM_GRACE_PERIOD_MS);
|
|
76015
|
-
if (!exited) {
|
|
76016
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing process: ${tracked.runId}`);
|
|
76017
|
-
killProcess(tracked.process, "SIGKILL");
|
|
76018
|
-
await waitForExit(tracked.runId, 1000);
|
|
76019
|
-
}
|
|
76020
|
-
}
|
|
76021
|
-
async function onCommandRun(ctx, event) {
|
|
76411
|
+
function spawnCommandProcess(ctx, event, commandKey) {
|
|
76022
76412
|
const { workingDir, commandName, script, runId } = event;
|
|
76023
76413
|
const runIdStr = runId.toString();
|
|
76024
|
-
const commandKey = buildCommandKey(ctx.machineId, workingDir, commandName);
|
|
76025
|
-
if (runningProcesses.has(runIdStr)) {
|
|
76026
|
-
console.log(`[${formatTimestamp()}] ⚠️ Command already running: ${runIdStr}`);
|
|
76027
|
-
return;
|
|
76028
|
-
}
|
|
76029
|
-
if (pendingStops.has(runIdStr)) {
|
|
76030
|
-
pendingStops.delete(runIdStr);
|
|
76031
|
-
console.log(`[${formatTimestamp()}] ⏭️ Skipping command run due to pending stop: ${commandName} (${runIdStr})`);
|
|
76032
|
-
try {
|
|
76033
|
-
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76034
|
-
sessionId: ctx.sessionId,
|
|
76035
|
-
machineId: ctx.machineId,
|
|
76036
|
-
runId,
|
|
76037
|
-
status: "stopped"
|
|
76038
|
-
});
|
|
76039
|
-
} catch (err) {
|
|
76040
|
-
console.warn(`[${formatTimestamp()}] ⚠️ Failed to update status to stopped for pending-stop skip: ${getErrorMessage(err)}`);
|
|
76041
|
-
}
|
|
76042
|
-
return;
|
|
76043
|
-
}
|
|
76044
|
-
const priorRunId = runningProcessesByCommand.get(commandKey);
|
|
76045
|
-
if (priorRunId) {
|
|
76046
|
-
const priorTracked = runningProcesses.get(priorRunId);
|
|
76047
|
-
if (priorTracked) {
|
|
76048
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDD04 Replacing prior run ${priorRunId} with ${runIdStr} for ${commandName}`);
|
|
76049
|
-
clearInterval(priorTracked.flushTimer);
|
|
76050
|
-
if (priorTracked.softTimeoutTimer)
|
|
76051
|
-
clearTimeout(priorTracked.softTimeoutTimer);
|
|
76052
|
-
await killTrackedProcess(priorTracked);
|
|
76053
|
-
runningProcesses.delete(priorRunId);
|
|
76054
|
-
runningProcessesByCommand.delete(commandKey);
|
|
76055
|
-
}
|
|
76056
|
-
}
|
|
76057
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDE80 Running command: ${commandName} → ${script}`);
|
|
76058
|
-
if (!workingDir.startsWith("/")) {
|
|
76059
|
-
console.error(`[${formatTimestamp()}] ❌ Rejected command: workingDir is not absolute: ${workingDir}`);
|
|
76060
|
-
await reportRunFailed(ctx, runId, "Working directory is not an absolute path");
|
|
76061
|
-
return;
|
|
76062
|
-
}
|
|
76063
|
-
try {
|
|
76064
|
-
await access3(workingDir);
|
|
76065
|
-
} catch {
|
|
76066
|
-
console.error(`[${formatTimestamp()}] ❌ Rejected command: workingDir not found: ${workingDir}`);
|
|
76067
|
-
await reportRunFailed(ctx, runId, "Working directory not found");
|
|
76068
|
-
return;
|
|
76069
|
-
}
|
|
76070
76414
|
const child = spawn4("sh", ["-c", script], {
|
|
76071
76415
|
cwd: workingDir,
|
|
76072
76416
|
env: { ...process.env },
|
|
76073
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
76417
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
76418
|
+
detached: true
|
|
76074
76419
|
});
|
|
76075
76420
|
const tracked = {
|
|
76076
76421
|
process: child,
|
|
@@ -76081,16 +76426,20 @@ async function onCommandRun(ctx, event) {
|
|
|
76081
76426
|
flushTimer: setInterval(() => {
|
|
76082
76427
|
flushOutput(ctx, tracked).catch(() => {});
|
|
76083
76428
|
}, OUTPUT_FLUSH_INTERVAL_MS),
|
|
76084
|
-
softTimeoutTimer: null
|
|
76429
|
+
softTimeoutTimer: null,
|
|
76430
|
+
terminationIntent: null
|
|
76085
76431
|
};
|
|
76086
76432
|
tracked.flushTimer.unref?.();
|
|
76087
|
-
|
|
76088
|
-
|
|
76433
|
+
processManager.register(runIdStr, commandKey, tracked);
|
|
76434
|
+
if (child.pid != null) {
|
|
76435
|
+
trackChildPid(child.pid);
|
|
76436
|
+
}
|
|
76089
76437
|
const softTimeoutTimer = setTimeout(async () => {
|
|
76090
76438
|
console.log(`[${formatTimestamp()}] ⏰ Command soft timeout (24h): ${commandName} (runId: ${runIdStr})`);
|
|
76091
|
-
const currentTracked =
|
|
76439
|
+
const currentTracked = processManager.get(runIdStr);
|
|
76092
76440
|
if (!currentTracked)
|
|
76093
76441
|
return;
|
|
76442
|
+
currentTracked.terminationIntent = "killed";
|
|
76094
76443
|
try {
|
|
76095
76444
|
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76096
76445
|
sessionId: ctx.sessionId,
|
|
@@ -76104,7 +76453,7 @@ async function onCommandRun(ctx, event) {
|
|
|
76104
76453
|
}
|
|
76105
76454
|
killProcess(child, "SIGTERM");
|
|
76106
76455
|
setTimeout(() => {
|
|
76107
|
-
if (!
|
|
76456
|
+
if (!processManager.has(runIdStr))
|
|
76108
76457
|
return;
|
|
76109
76458
|
console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing timed-out process: ${runIdStr}`);
|
|
76110
76459
|
killProcess(child, "SIGKILL");
|
|
@@ -76112,17 +76461,6 @@ async function onCommandRun(ctx, event) {
|
|
|
76112
76461
|
}, SOFT_TIMEOUT_MS);
|
|
76113
76462
|
softTimeoutTimer.unref?.();
|
|
76114
76463
|
tracked.softTimeoutTimer = softTimeoutTimer;
|
|
76115
|
-
try {
|
|
76116
|
-
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76117
|
-
sessionId: ctx.sessionId,
|
|
76118
|
-
machineId: ctx.machineId,
|
|
76119
|
-
runId,
|
|
76120
|
-
status: "running",
|
|
76121
|
-
pid: child.pid
|
|
76122
|
-
});
|
|
76123
|
-
} catch (err) {
|
|
76124
|
-
console.warn(`[${formatTimestamp()}] ⚠️ Failed to update run status to running: ${getErrorMessage(err)}`);
|
|
76125
|
-
}
|
|
76126
76464
|
child.stdout?.on("data", (data) => {
|
|
76127
76465
|
appendToBuffer(ctx, tracked, data.toString());
|
|
76128
76466
|
});
|
|
@@ -76132,14 +76470,14 @@ async function onCommandRun(ctx, event) {
|
|
|
76132
76470
|
child.on("exit", async (code2, signal) => {
|
|
76133
76471
|
console.log(`[${formatTimestamp()}] \uD83C\uDFC1 Command exited: ${commandName} (code=${code2}, signal=${signal})`);
|
|
76134
76472
|
await flushOutput(ctx, tracked).catch(() => {});
|
|
76473
|
+
if (tracked.process.pid != null) {
|
|
76474
|
+
untrackChildPid(tracked.process.pid);
|
|
76475
|
+
}
|
|
76135
76476
|
clearInterval(tracked.flushTimer);
|
|
76136
76477
|
if (tracked.softTimeoutTimer)
|
|
76137
76478
|
clearTimeout(tracked.softTimeoutTimer);
|
|
76138
|
-
|
|
76139
|
-
|
|
76140
|
-
runningProcessesByCommand.delete(commandKey);
|
|
76141
|
-
}
|
|
76142
|
-
const status3 = code2 === 0 ? "completed" : signal ? "stopped" : "failed";
|
|
76479
|
+
processManager.unregister(runIdStr, commandKey);
|
|
76480
|
+
const status3 = deriveTerminalStatus(code2, signal, tracked.terminationIntent);
|
|
76143
76481
|
try {
|
|
76144
76482
|
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76145
76483
|
sessionId: ctx.sessionId,
|
|
@@ -76154,13 +76492,13 @@ async function onCommandRun(ctx, event) {
|
|
|
76154
76492
|
});
|
|
76155
76493
|
child.on("error", async (err) => {
|
|
76156
76494
|
console.error(`[${formatTimestamp()}] ❌ Command spawn failed: ${commandName}: ${err.message}`);
|
|
76495
|
+
if (tracked.process.pid != null) {
|
|
76496
|
+
untrackChildPid(tracked.process.pid);
|
|
76497
|
+
}
|
|
76157
76498
|
clearInterval(tracked.flushTimer);
|
|
76158
76499
|
if (tracked.softTimeoutTimer)
|
|
76159
76500
|
clearTimeout(tracked.softTimeoutTimer);
|
|
76160
|
-
|
|
76161
|
-
if (runningProcessesByCommand.get(commandKey) === runIdStr) {
|
|
76162
|
-
runningProcessesByCommand.delete(commandKey);
|
|
76163
|
-
}
|
|
76501
|
+
processManager.unregister(runIdStr, commandKey);
|
|
76164
76502
|
try {
|
|
76165
76503
|
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76166
76504
|
sessionId: ctx.sessionId,
|
|
@@ -76172,13 +76510,111 @@ async function onCommandRun(ctx, event) {
|
|
|
76172
76510
|
console.warn(`[${formatTimestamp()}] ⚠️ Failed to update run status on error: ${getErrorMessage(updateErr)}`);
|
|
76173
76511
|
}
|
|
76174
76512
|
});
|
|
76513
|
+
return tracked;
|
|
76514
|
+
}
|
|
76515
|
+
var init_spawner = __esm(() => {
|
|
76516
|
+
init_api3();
|
|
76517
|
+
init_convex_error();
|
|
76518
|
+
init_orphan_tracker();
|
|
76519
|
+
init_state2();
|
|
76520
|
+
init_manager();
|
|
76521
|
+
init_killer();
|
|
76522
|
+
});
|
|
76523
|
+
|
|
76524
|
+
// src/commands/machine/daemon-start/handlers/command-runner.ts
|
|
76525
|
+
import { access as access3 } from "node:fs/promises";
|
|
76526
|
+
function buildCommandKey(machineId, workingDir, commandName) {
|
|
76527
|
+
return `${machineId}|${workingDir}|${commandName}`;
|
|
76528
|
+
}
|
|
76529
|
+
async function reportRunFailed(ctx, runId, reason) {
|
|
76530
|
+
try {
|
|
76531
|
+
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76532
|
+
sessionId: ctx.sessionId,
|
|
76533
|
+
machineId: ctx.machineId,
|
|
76534
|
+
runId,
|
|
76535
|
+
status: "failed"
|
|
76536
|
+
});
|
|
76537
|
+
} catch (err) {
|
|
76538
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Failed to report run failure (${reason}): ${getErrorMessage(err)}`);
|
|
76539
|
+
}
|
|
76540
|
+
}
|
|
76541
|
+
async function onCommandRun(ctx, event) {
|
|
76542
|
+
const { workingDir, commandName, script, runId } = event;
|
|
76543
|
+
const runIdStr = runId.toString();
|
|
76544
|
+
const commandKey = buildCommandKey(ctx.machineId, workingDir, commandName);
|
|
76545
|
+
if (processManager.has(runIdStr)) {
|
|
76546
|
+
console.log(`[${formatTimestamp()}] ⚠️ Command already running: ${runIdStr}`);
|
|
76547
|
+
return;
|
|
76548
|
+
}
|
|
76549
|
+
if (processManager.consumePendingStop(runIdStr)) {
|
|
76550
|
+
console.log(`[${formatTimestamp()}] ⏭️ Skipping command run due to pending stop: ${commandName} (${runIdStr})`);
|
|
76551
|
+
try {
|
|
76552
|
+
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76553
|
+
sessionId: ctx.sessionId,
|
|
76554
|
+
machineId: ctx.machineId,
|
|
76555
|
+
runId,
|
|
76556
|
+
status: "stopped"
|
|
76557
|
+
});
|
|
76558
|
+
} catch (err) {
|
|
76559
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Failed to update status to stopped for pending-stop skip: ${getErrorMessage(err)}`);
|
|
76560
|
+
}
|
|
76561
|
+
return;
|
|
76562
|
+
}
|
|
76563
|
+
try {
|
|
76564
|
+
const currentRun = await ctx.deps.backend.query(api.commands.getRunStatus, {
|
|
76565
|
+
sessionId: ctx.sessionId,
|
|
76566
|
+
machineId: ctx.machineId,
|
|
76567
|
+
runId
|
|
76568
|
+
});
|
|
76569
|
+
if (currentRun && TERMINAL_STATES.has(currentRun.status)) {
|
|
76570
|
+
console.log(`[${formatTimestamp()}] ⏭️ Skipping command run — row already ${currentRun.status}: ${commandName} (${runIdStr})`);
|
|
76571
|
+
return;
|
|
76572
|
+
}
|
|
76573
|
+
} catch (err) {
|
|
76574
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Failed to check run status before spawn: ${getErrorMessage(err)}`);
|
|
76575
|
+
}
|
|
76576
|
+
const priorTracked = processManager.getByCommand(commandKey);
|
|
76577
|
+
if (priorTracked) {
|
|
76578
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDD04 Replacing prior run ${priorTracked.runId} with ${runIdStr} for ${commandName}`);
|
|
76579
|
+
priorTracked.terminationIntent = "killed";
|
|
76580
|
+
clearInterval(priorTracked.flushTimer);
|
|
76581
|
+
if (priorTracked.softTimeoutTimer)
|
|
76582
|
+
clearTimeout(priorTracked.softTimeoutTimer);
|
|
76583
|
+
await killTrackedProcess(priorTracked);
|
|
76584
|
+
processManager.unregister(priorTracked.runId, commandKey);
|
|
76585
|
+
}
|
|
76586
|
+
console.log(`[${formatTimestamp()}] \uD83D\uDE80 Running command: ${commandName} → ${script}`);
|
|
76587
|
+
if (!workingDir.startsWith("/")) {
|
|
76588
|
+
console.error(`[${formatTimestamp()}] ❌ Rejected command: workingDir is not absolute: ${workingDir}`);
|
|
76589
|
+
await reportRunFailed(ctx, runId, "Working directory is not an absolute path");
|
|
76590
|
+
return;
|
|
76591
|
+
}
|
|
76592
|
+
try {
|
|
76593
|
+
await access3(workingDir);
|
|
76594
|
+
} catch {
|
|
76595
|
+
console.error(`[${formatTimestamp()}] ❌ Rejected command: workingDir not found: ${workingDir}`);
|
|
76596
|
+
await reportRunFailed(ctx, runId, "Working directory not found");
|
|
76597
|
+
return;
|
|
76598
|
+
}
|
|
76599
|
+
const tracked = spawnCommandProcess(ctx, event, commandKey);
|
|
76600
|
+
try {
|
|
76601
|
+
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76602
|
+
sessionId: ctx.sessionId,
|
|
76603
|
+
machineId: ctx.machineId,
|
|
76604
|
+
runId,
|
|
76605
|
+
status: "running",
|
|
76606
|
+
pid: tracked.process.pid
|
|
76607
|
+
});
|
|
76608
|
+
} catch (err) {
|
|
76609
|
+
console.warn(`[${formatTimestamp()}] ⚠️ Failed to update run status to running: ${getErrorMessage(err)}`);
|
|
76610
|
+
}
|
|
76175
76611
|
}
|
|
76176
76612
|
async function onCommandStop(ctx, event) {
|
|
76177
76613
|
const runIdStr = event.runId.toString();
|
|
76178
|
-
const tracked =
|
|
76614
|
+
const tracked = processManager.get(runIdStr);
|
|
76179
76615
|
if (!tracked) {
|
|
76180
76616
|
console.log(`[${formatTimestamp()}] ⚠️ No running process found for run: ${runIdStr} — marking as stopped`);
|
|
76181
|
-
|
|
76617
|
+
processManager.markPendingStop(runIdStr);
|
|
76182
76618
|
try {
|
|
76183
76619
|
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76184
76620
|
sessionId: ctx.sessionId,
|
|
@@ -76197,13 +76633,8 @@ async function onCommandStop(ctx, event) {
|
|
|
76197
76633
|
clearTimeout(tracked.softTimeoutTimer);
|
|
76198
76634
|
tracked.softTimeoutTimer = null;
|
|
76199
76635
|
}
|
|
76200
|
-
|
|
76201
|
-
|
|
76202
|
-
if (!exitedAfterSigterm) {
|
|
76203
|
-
console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing process: ${runIdStr}`);
|
|
76204
|
-
killProcess(tracked.process, "SIGKILL");
|
|
76205
|
-
await waitForExit(runIdStr, 1000);
|
|
76206
|
-
}
|
|
76636
|
+
tracked.terminationIntent = "stopped";
|
|
76637
|
+
await killTrackedProcess(tracked);
|
|
76207
76638
|
try {
|
|
76208
76639
|
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76209
76640
|
sessionId: ctx.sessionId,
|
|
@@ -76216,15 +76647,14 @@ async function onCommandStop(ctx, event) {
|
|
|
76216
76647
|
}
|
|
76217
76648
|
}
|
|
76218
76649
|
async function shutdownAllCommands(ctx) {
|
|
76219
|
-
if (
|
|
76650
|
+
if (processManager.size === 0)
|
|
76220
76651
|
return;
|
|
76221
|
-
console.log(`[${formatTimestamp()}] Shutting down ${
|
|
76222
|
-
const trackedEntries =
|
|
76652
|
+
console.log(`[${formatTimestamp()}] Shutting down ${processManager.size} running command(s)...`);
|
|
76653
|
+
const trackedEntries = processManager.getAll();
|
|
76223
76654
|
for (const [, tracked] of trackedEntries) {
|
|
76224
76655
|
clearInterval(tracked.flushTimer);
|
|
76225
76656
|
if (tracked.softTimeoutTimer)
|
|
76226
76657
|
clearTimeout(tracked.softTimeoutTimer);
|
|
76227
|
-
await flushOutput(ctx, tracked).catch(() => {});
|
|
76228
76658
|
try {
|
|
76229
76659
|
await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
|
|
76230
76660
|
sessionId: ctx.sessionId,
|
|
@@ -76243,23 +76673,22 @@ async function shutdownAllCommands(ctx) {
|
|
|
76243
76673
|
t.unref?.();
|
|
76244
76674
|
});
|
|
76245
76675
|
for (const [, tracked] of trackedEntries) {
|
|
76246
|
-
if (
|
|
76676
|
+
if (processManager.has(tracked.runId)) {
|
|
76247
76677
|
killProcess(tracked.process, "SIGKILL");
|
|
76248
76678
|
}
|
|
76249
76679
|
}
|
|
76250
|
-
|
|
76251
|
-
|
|
76680
|
+
processManager.clear();
|
|
76681
|
+
clearTrackedPids();
|
|
76252
76682
|
console.log(`[${formatTimestamp()}] All commands stopped`);
|
|
76253
76683
|
}
|
|
76254
|
-
var runningProcesses, runningProcessesByCommand, pendingStops, PENDING_STOP_TTL_MS = 60000, OUTPUT_FLUSH_INTERVAL_MS = 3000, MAX_BUFFER_SIZE, SOFT_TIMEOUT_MS, SIGTERM_GRACE_PERIOD_MS = 5000;
|
|
76255
76684
|
var init_command_runner = __esm(() => {
|
|
76256
76685
|
init_api3();
|
|
76257
76686
|
init_convex_error();
|
|
76258
|
-
|
|
76259
|
-
|
|
76260
|
-
|
|
76261
|
-
|
|
76262
|
-
|
|
76687
|
+
init_orphan_tracker();
|
|
76688
|
+
init_state2();
|
|
76689
|
+
init_manager();
|
|
76690
|
+
init_spawner();
|
|
76691
|
+
init_killer();
|
|
76263
76692
|
});
|
|
76264
76693
|
|
|
76265
76694
|
// src/commands/machine/daemon-start/handlers/ping.ts
|
|
@@ -77228,21 +77657,25 @@ async function recoverState(ctx) {
|
|
|
77228
77657
|
console.log(` ⚠️ Failed to clear stale PIDs: ${getErrorMessage(e)}`);
|
|
77229
77658
|
}
|
|
77230
77659
|
try {
|
|
77231
|
-
const runResult = await ctx.deps.backend.mutation(api.commands.
|
|
77660
|
+
const runResult = await ctx.deps.backend.mutation(api.commands.reapOrphansForDaemonRestart, {
|
|
77232
77661
|
sessionId: ctx.sessionId,
|
|
77233
77662
|
machineId: ctx.machineId
|
|
77234
77663
|
});
|
|
77235
|
-
if (runResult.
|
|
77236
|
-
console.log(` \uD83E\uDDF9
|
|
77664
|
+
if (runResult.reapedCount > 0) {
|
|
77665
|
+
console.log(` \uD83E\uDDF9 Reaped ${runResult.reapedCount} command run(s) from previous daemon run (marked as daemon-restart)`);
|
|
77237
77666
|
}
|
|
77238
77667
|
} catch (e) {
|
|
77239
|
-
console.
|
|
77668
|
+
console.warn(` ⚠️ Failed to reap orphan command runs: ${getErrorMessage(e)}`);
|
|
77240
77669
|
}
|
|
77241
77670
|
}
|
|
77242
77671
|
async function initDaemon() {
|
|
77243
77672
|
if (!acquireLock()) {
|
|
77244
77673
|
process.exit(1);
|
|
77245
77674
|
}
|
|
77675
|
+
const { reaped } = await reapOrphanedProcessGroups();
|
|
77676
|
+
if (reaped > 0) {
|
|
77677
|
+
console.log(`[${formatTimestamp()}] Reaped ${reaped} orphaned process group(s) from previous daemon run`);
|
|
77678
|
+
}
|
|
77246
77679
|
const convexUrl = getConvexUrl();
|
|
77247
77680
|
const sessionId = await validateAuthentication(convexUrl);
|
|
77248
77681
|
const client4 = await getConvexClient();
|
|
@@ -77330,6 +77763,7 @@ var init_init2 = __esm(() => {
|
|
|
77330
77763
|
init_error_formatting();
|
|
77331
77764
|
init_version();
|
|
77332
77765
|
init_pid();
|
|
77766
|
+
init_orphan_tracker();
|
|
77333
77767
|
AUTH_WAIT_TIMEOUT_MS = 5 * 60 * 1000;
|
|
77334
77768
|
});
|
|
77335
77769
|
|
|
@@ -78075,7 +78509,7 @@ function evictStaleDedupEntries(tracker) {
|
|
|
78075
78509
|
if (ts < evictBefore)
|
|
78076
78510
|
tracker.commandStopIds.delete(id3);
|
|
78077
78511
|
}
|
|
78078
|
-
evictStalePendingStops();
|
|
78512
|
+
processManager.evictStalePendingStops();
|
|
78079
78513
|
}
|
|
78080
78514
|
async function dispatchCommandEvent(ctx, event, tracker) {
|
|
78081
78515
|
const eventId = event._id.toString();
|
|
@@ -78331,6 +78765,7 @@ var init_command_loop = __esm(() => {
|
|
|
78331
78765
|
init_file_tree_subscription();
|
|
78332
78766
|
init_git_subscription();
|
|
78333
78767
|
init_command_runner();
|
|
78768
|
+
init_manager();
|
|
78334
78769
|
init_init2();
|
|
78335
78770
|
init_observed_sync();
|
|
78336
78771
|
init_api3();
|
|
@@ -79446,5 +79881,5 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
|
79446
79881
|
});
|
|
79447
79882
|
program2.parse();
|
|
79448
79883
|
|
|
79449
|
-
//# debugId=
|
|
79884
|
+
//# debugId=DFA3745A7992596664756E2164756E21
|
|
79450
79885
|
//# sourceMappingURL=index.js.map
|