chatroom-cli 1.38.5 → 1.38.6

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 CHANGED
@@ -75858,6 +75858,9 @@ function evictStalePendingStops() {
75858
75858
  pendingStops.delete(runId);
75859
75859
  }
75860
75860
  }
75861
+ function buildCommandKey(machineId, workingDir, commandName) {
75862
+ return `${machineId}|${workingDir}|${commandName}`;
75863
+ }
75861
75864
  async function reportRunFailed(ctx, runId, reason) {
75862
75865
  try {
75863
75866
  await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
@@ -75895,9 +75898,42 @@ function appendToBuffer(ctx, tracked, data) {
75895
75898
  flushOutput(ctx, tracked).catch(() => {});
75896
75899
  }
75897
75900
  }
75901
+ function killProcess(child, signal) {
75902
+ try {
75903
+ child.kill(signal);
75904
+ } catch {}
75905
+ }
75906
+ function waitForExit(runIdStr, ms) {
75907
+ return new Promise((resolve5) => {
75908
+ const interval = 100;
75909
+ let elapsed3 = 0;
75910
+ const timer = setInterval(() => {
75911
+ if (!runningProcesses.has(runIdStr)) {
75912
+ clearInterval(timer);
75913
+ resolve5(true);
75914
+ return;
75915
+ }
75916
+ elapsed3 += interval;
75917
+ if (elapsed3 >= ms) {
75918
+ clearInterval(timer);
75919
+ resolve5(false);
75920
+ }
75921
+ }, interval);
75922
+ });
75923
+ }
75924
+ async function killTrackedProcess(tracked) {
75925
+ killProcess(tracked.process, "SIGTERM");
75926
+ const exited = await waitForExit(tracked.runId, SIGTERM_GRACE_PERIOD_MS);
75927
+ if (!exited) {
75928
+ console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing process: ${tracked.runId}`);
75929
+ killProcess(tracked.process, "SIGKILL");
75930
+ await waitForExit(tracked.runId, 1000);
75931
+ }
75932
+ }
75898
75933
  async function onCommandRun(ctx, event) {
75899
75934
  const { workingDir, commandName, script, runId } = event;
75900
75935
  const runIdStr = runId.toString();
75936
+ const commandKey = buildCommandKey(ctx.machineId, workingDir, commandName);
75901
75937
  if (runningProcesses.has(runIdStr)) {
75902
75938
  console.log(`[${formatTimestamp()}] ⚠️ Command already running: ${runIdStr}`);
75903
75939
  return;
@@ -75917,6 +75953,19 @@ async function onCommandRun(ctx, event) {
75917
75953
  }
75918
75954
  return;
75919
75955
  }
75956
+ const priorRunId = runningProcessesByCommand.get(commandKey);
75957
+ if (priorRunId) {
75958
+ const priorTracked = runningProcesses.get(priorRunId);
75959
+ if (priorTracked) {
75960
+ console.log(`[${formatTimestamp()}] \uD83D\uDD04 Replacing prior run ${priorRunId} with ${runIdStr} for ${commandName}`);
75961
+ clearInterval(priorTracked.flushTimer);
75962
+ if (priorTracked.softTimeoutTimer)
75963
+ clearTimeout(priorTracked.softTimeoutTimer);
75964
+ await killTrackedProcess(priorTracked);
75965
+ runningProcesses.delete(priorRunId);
75966
+ runningProcessesByCommand.delete(commandKey);
75967
+ }
75968
+ }
75920
75969
  console.log(`[${formatTimestamp()}] \uD83D\uDE80 Running command: ${commandName} → ${script}`);
75921
75970
  if (!workingDir.startsWith("/")) {
75922
75971
  console.error(`[${formatTimestamp()}] ❌ Rejected command: workingDir is not absolute: ${workingDir}`);
@@ -75933,49 +75982,48 @@ async function onCommandRun(ctx, event) {
75933
75982
  const child = spawn4("sh", ["-c", script], {
75934
75983
  cwd: workingDir,
75935
75984
  env: { ...process.env },
75936
- stdio: ["ignore", "pipe", "pipe"],
75937
- detached: true
75985
+ stdio: ["ignore", "pipe", "pipe"]
75938
75986
  });
75939
- const timeoutTimer = setTimeout(() => {
75940
- console.log(`[${formatTimestamp()}] ⏰ Command timed out after ${DEFAULT_COMMAND_TIMEOUT_MS / 60000} minutes: ${commandName} (runId: ${runIdStr})`);
75941
- const pid = child.pid;
75942
- if (pid) {
75943
- try {
75944
- process.kill(-pid, "SIGTERM");
75945
- } catch {
75946
- child.kill("SIGTERM");
75947
- }
75948
- } else {
75949
- child.kill("SIGTERM");
75950
- }
75951
- setTimeout(() => {
75952
- if (!runningProcesses.has(runIdStr))
75953
- return;
75954
- console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing timed-out process: ${runIdStr}`);
75955
- if (pid) {
75956
- try {
75957
- process.kill(-pid, "SIGKILL");
75958
- } catch {
75959
- child.kill("SIGKILL");
75960
- }
75961
- } else {
75962
- child.kill("SIGKILL");
75963
- }
75964
- }, SIGTERM_GRACE_PERIOD_MS);
75965
- }, DEFAULT_COMMAND_TIMEOUT_MS);
75966
- timeoutTimer.unref?.();
75967
75987
  const tracked = {
75968
75988
  process: child,
75969
75989
  runId: runIdStr,
75990
+ commandKey,
75970
75991
  outputBuffer: "",
75971
75992
  chunkIndex: 0,
75972
75993
  flushTimer: setInterval(() => {
75973
75994
  flushOutput(ctx, tracked).catch(() => {});
75974
75995
  }, OUTPUT_FLUSH_INTERVAL_MS),
75975
- timeoutTimer
75996
+ softTimeoutTimer: null
75976
75997
  };
75977
75998
  tracked.flushTimer.unref?.();
75978
75999
  runningProcesses.set(runIdStr, tracked);
76000
+ runningProcessesByCommand.set(commandKey, runIdStr);
76001
+ const softTimeoutTimer = setTimeout(async () => {
76002
+ console.log(`[${formatTimestamp()}] ⏰ Command soft timeout (24h): ${commandName} (runId: ${runIdStr})`);
76003
+ const currentTracked = runningProcesses.get(runIdStr);
76004
+ if (!currentTracked)
76005
+ return;
76006
+ try {
76007
+ await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
76008
+ sessionId: ctx.sessionId,
76009
+ machineId: ctx.machineId,
76010
+ runId,
76011
+ status: "killed",
76012
+ terminationReason: "timeout-24h"
76013
+ });
76014
+ } catch (err) {
76015
+ console.warn(`[${formatTimestamp()}] ⚠️ Failed to mark run as killed (timeout): ${getErrorMessage(err)}`);
76016
+ }
76017
+ killProcess(child, "SIGTERM");
76018
+ setTimeout(() => {
76019
+ if (!runningProcesses.has(runIdStr))
76020
+ return;
76021
+ console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing timed-out process: ${runIdStr}`);
76022
+ killProcess(child, "SIGKILL");
76023
+ }, SIGTERM_GRACE_PERIOD_MS);
76024
+ }, SOFT_TIMEOUT_MS);
76025
+ softTimeoutTimer.unref?.();
76026
+ tracked.softTimeoutTimer = softTimeoutTimer;
75979
76027
  try {
75980
76028
  await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
75981
76029
  sessionId: ctx.sessionId,
@@ -75997,9 +76045,12 @@ async function onCommandRun(ctx, event) {
75997
76045
  console.log(`[${formatTimestamp()}] \uD83C\uDFC1 Command exited: ${commandName} (code=${code2}, signal=${signal})`);
75998
76046
  await flushOutput(ctx, tracked).catch(() => {});
75999
76047
  clearInterval(tracked.flushTimer);
76000
- if (tracked.timeoutTimer)
76001
- clearTimeout(tracked.timeoutTimer);
76048
+ if (tracked.softTimeoutTimer)
76049
+ clearTimeout(tracked.softTimeoutTimer);
76002
76050
  runningProcesses.delete(runIdStr);
76051
+ if (runningProcessesByCommand.get(commandKey) === runIdStr) {
76052
+ runningProcessesByCommand.delete(commandKey);
76053
+ }
76003
76054
  const status3 = code2 === 0 ? "completed" : signal ? "stopped" : "failed";
76004
76055
  try {
76005
76056
  await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
@@ -76016,9 +76067,12 @@ async function onCommandRun(ctx, event) {
76016
76067
  child.on("error", async (err) => {
76017
76068
  console.error(`[${formatTimestamp()}] ❌ Command spawn failed: ${commandName}: ${err.message}`);
76018
76069
  clearInterval(tracked.flushTimer);
76019
- if (tracked.timeoutTimer)
76020
- clearTimeout(tracked.timeoutTimer);
76070
+ if (tracked.softTimeoutTimer)
76071
+ clearTimeout(tracked.softTimeoutTimer);
76021
76072
  runningProcesses.delete(runIdStr);
76073
+ if (runningProcessesByCommand.get(commandKey) === runIdStr) {
76074
+ runningProcessesByCommand.delete(commandKey);
76075
+ }
76022
76076
  try {
76023
76077
  await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
76024
76078
  sessionId: ctx.sessionId,
@@ -76031,36 +76085,6 @@ async function onCommandRun(ctx, event) {
76031
76085
  }
76032
76086
  });
76033
76087
  }
76034
- function killProcess(child, signal) {
76035
- const pid = child.pid;
76036
- if (pid) {
76037
- try {
76038
- process.kill(-pid, signal);
76039
- return;
76040
- } catch {}
76041
- }
76042
- try {
76043
- child.kill(signal);
76044
- } catch {}
76045
- }
76046
- function waitForExit(runIdStr, ms) {
76047
- return new Promise((resolve5) => {
76048
- const interval = 100;
76049
- let elapsed3 = 0;
76050
- const timer = setInterval(() => {
76051
- if (!runningProcesses.has(runIdStr)) {
76052
- clearInterval(timer);
76053
- resolve5(true);
76054
- return;
76055
- }
76056
- elapsed3 += interval;
76057
- if (elapsed3 >= ms) {
76058
- clearInterval(timer);
76059
- resolve5(false);
76060
- }
76061
- }, interval);
76062
- });
76063
- }
76064
76088
  async function onCommandStop(ctx, event) {
76065
76089
  const runIdStr = event.runId.toString();
76066
76090
  const tracked = runningProcesses.get(runIdStr);
@@ -76081,19 +76105,16 @@ async function onCommandStop(ctx, event) {
76081
76105
  return;
76082
76106
  }
76083
76107
  console.log(`[${formatTimestamp()}] \uD83D\uDED1 Stopping command run: ${runIdStr}`);
76084
- if (tracked.timeoutTimer) {
76085
- clearTimeout(tracked.timeoutTimer);
76086
- tracked.timeoutTimer = null;
76108
+ if (tracked.softTimeoutTimer) {
76109
+ clearTimeout(tracked.softTimeoutTimer);
76110
+ tracked.softTimeoutTimer = null;
76087
76111
  }
76088
76112
  killProcess(tracked.process, "SIGTERM");
76089
76113
  const exitedAfterSigterm = await waitForExit(runIdStr, SIGTERM_GRACE_PERIOD_MS);
76090
76114
  if (!exitedAfterSigterm) {
76091
76115
  console.log(`[${formatTimestamp()}] \uD83D\uDD2A Force-killing process: ${runIdStr}`);
76092
76116
  killProcess(tracked.process, "SIGKILL");
76093
- const exitedAfterSigkill = await waitForExit(runIdStr, 1000);
76094
- if (!exitedAfterSigkill) {
76095
- console.error(`[${formatTimestamp()}] ❌ Failed to stop process for run: ${runIdStr} — process did not exit after SIGKILL`);
76096
- }
76117
+ await waitForExit(runIdStr, 1000);
76097
76118
  }
76098
76119
  try {
76099
76120
  await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
@@ -76110,49 +76131,47 @@ async function shutdownAllCommands(ctx) {
76110
76131
  if (runningProcesses.size === 0)
76111
76132
  return;
76112
76133
  console.log(`[${formatTimestamp()}] Shutting down ${runningProcesses.size} running command(s)...`);
76113
- for (const [, tracked] of runningProcesses) {
76134
+ const trackedEntries = [...runningProcesses.entries()];
76135
+ for (const [, tracked] of trackedEntries) {
76114
76136
  clearInterval(tracked.flushTimer);
76115
- if (tracked.timeoutTimer)
76116
- clearTimeout(tracked.timeoutTimer);
76137
+ if (tracked.softTimeoutTimer)
76138
+ clearTimeout(tracked.softTimeoutTimer);
76117
76139
  await flushOutput(ctx, tracked).catch(() => {});
76118
- const pid = tracked.process.pid;
76119
- if (pid) {
76120
- try {
76121
- process.kill(-pid, "SIGTERM");
76122
- } catch {
76123
- tracked.process.kill("SIGTERM");
76124
- }
76125
- } else {
76126
- tracked.process.kill("SIGTERM");
76140
+ try {
76141
+ await ctx.deps.backend.mutation(api.commands.updateRunStatus, {
76142
+ sessionId: ctx.sessionId,
76143
+ machineId: ctx.machineId,
76144
+ runId: tracked.runId,
76145
+ status: "killed",
76146
+ terminationReason: "daemon-shutdown"
76147
+ });
76148
+ } catch (err) {
76149
+ console.warn(`[${formatTimestamp()}] ⚠️ Failed to mark run as killed on shutdown: ${getErrorMessage(err)}`);
76127
76150
  }
76151
+ killProcess(tracked.process, "SIGTERM");
76128
76152
  }
76129
76153
  await new Promise((resolve5) => {
76130
76154
  const t = setTimeout(resolve5, 3000);
76131
76155
  t.unref?.();
76132
76156
  });
76133
- for (const [, tracked] of runningProcesses) {
76134
- const pid = tracked.process.pid;
76135
- if (pid) {
76136
- try {
76137
- process.kill(-pid, "SIGKILL");
76138
- } catch {}
76139
- } else {
76140
- try {
76141
- tracked.process.kill("SIGKILL");
76142
- } catch {}
76157
+ for (const [, tracked] of trackedEntries) {
76158
+ if (runningProcesses.has(tracked.runId)) {
76159
+ killProcess(tracked.process, "SIGKILL");
76143
76160
  }
76144
76161
  }
76145
76162
  runningProcesses.clear();
76163
+ runningProcessesByCommand.clear();
76146
76164
  console.log(`[${formatTimestamp()}] All commands stopped`);
76147
76165
  }
76148
- 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;
76166
+ 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;
76149
76167
  var init_command_runner = __esm(() => {
76150
76168
  init_api3();
76151
76169
  init_convex_error();
76152
76170
  runningProcesses = new Map;
76171
+ runningProcessesByCommand = new Map;
76153
76172
  pendingStops = new Map;
76154
76173
  MAX_BUFFER_SIZE = 100 * 1024;
76155
- DEFAULT_COMMAND_TIMEOUT_MS = 30 * 60 * 1000;
76174
+ SOFT_TIMEOUT_MS = 24 * 60 * 60 * 1000;
76156
76175
  });
76157
76176
 
76158
76177
  // src/commands/machine/daemon-start/handlers/ping.ts
@@ -79289,5 +79308,5 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
79289
79308
  });
79290
79309
  program2.parse();
79291
79310
 
79292
- //# debugId=A3C30103B208BB9B64756E2164756E21
79311
+ //# debugId=1884CBA22481288264756E2164756E21
79293
79312
  //# sourceMappingURL=index.js.map