chatroom-cli 1.0.75 → 1.0.81

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.
Files changed (2) hide show
  1. package/dist/index.js +110 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10263,7 +10263,12 @@ class ProcessDriver {
10263
10263
  return {
10264
10264
  success: true,
10265
10265
  message: "Agent spawned successfully",
10266
- handle
10266
+ handle,
10267
+ onExit: (callback) => {
10268
+ childProcess.on("exit", (code2, signal) => {
10269
+ callback(code2, signal);
10270
+ });
10271
+ }
10267
10272
  };
10268
10273
  } catch (error) {
10269
10274
  return {
@@ -10276,7 +10281,26 @@ class ProcessDriver {
10276
10281
  if (handle.type !== "process" || !handle.pid) {
10277
10282
  throw new Error(`Cannot stop: handle has no PID (type=${handle.type})`);
10278
10283
  }
10279
- process.kill(handle.pid, "SIGTERM");
10284
+ const pid = handle.pid;
10285
+ try {
10286
+ process.kill(pid, "SIGTERM");
10287
+ } catch {
10288
+ return;
10289
+ }
10290
+ const KILL_TIMEOUT_MS = 5000;
10291
+ const POLL_INTERVAL_MS = 200;
10292
+ const deadline = Date.now() + KILL_TIMEOUT_MS;
10293
+ while (Date.now() < deadline) {
10294
+ try {
10295
+ process.kill(pid, 0);
10296
+ } catch {
10297
+ return;
10298
+ }
10299
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
10300
+ }
10301
+ try {
10302
+ process.kill(pid, "SIGKILL");
10303
+ } catch {}
10280
10304
  }
10281
10305
  async isAlive(handle) {
10282
10306
  if (handle.type !== "process" || !handle.pid) {
@@ -10677,6 +10701,9 @@ var init_register_agent = __esm(() => {
10677
10701
  init_client2();
10678
10702
  init_machine();
10679
10703
  });
10704
+
10705
+ // ../../services/backend/config/reliability.ts
10706
+ var HEARTBEAT_INTERVAL_MS = 30000, HEARTBEAT_TTL_MS = 60000, DAEMON_HEARTBEAT_INTERVAL_MS = 30000;
10680
10707
  // ../../services/backend/prompts/base/cli/task-started/command.ts
10681
10708
  function taskStartedCommand(params) {
10682
10709
  const prefix = params.cliEnvPrefix || "";
@@ -10904,6 +10931,7 @@ async function waitForTask(chatroomId, options) {
10904
10931
  sessionId,
10905
10932
  chatroomId,
10906
10933
  role,
10934
+ readyUntil: Date.now() + HEARTBEAT_TTL_MS,
10907
10935
  connectionId
10908
10936
  });
10909
10937
  const connectionTime = new Date().toISOString().replace("T", " ").substring(0, 19);
@@ -10911,34 +10939,62 @@ async function waitForTask(chatroomId, options) {
10911
10939
  console.log(`[${connectionTime}] ⏳ Connecting to chatroom as "${role}"...`);
10912
10940
  }
10913
10941
  try {
10914
- const convexUrl2 = getConvexUrl();
10915
10942
  const initPromptResult = await client2.query(api.messages.getInitPrompt, {
10916
10943
  sessionId,
10917
10944
  chatroomId,
10918
10945
  role,
10919
- convexUrl: convexUrl2
10946
+ convexUrl
10920
10947
  });
10921
10948
  if (initPromptResult?.prompt) {
10922
10949
  const connectedTime = new Date().toISOString().replace("T", " ").substring(0, 19);
10923
10950
  console.log(`[${connectedTime}] ✅ Connected. Waiting for task...
10924
10951
  `);
10925
- console.log("<!-- REFERENCE: Agent Initialization");
10926
- console.log("");
10927
- console.log("".repeat(50));
10928
- console.log("\uD83D\uDCCB AGENT INITIALIZATION PROMPT");
10929
- console.log("".repeat(50));
10930
- console.log("");
10931
- console.log(getWaitForTaskGuidance());
10932
- console.log("");
10933
- console.log("".repeat(50));
10934
- console.log("");
10935
- console.log(initPromptResult.prompt);
10936
- console.log("");
10937
- console.log("".repeat(50));
10938
- console.log("-->");
10939
- console.log("");
10952
+ if (!initPromptResult.hasSystemPromptControl) {
10953
+ console.log("<!-- REFERENCE: Agent Initialization");
10954
+ console.log("");
10955
+ console.log("".repeat(50));
10956
+ console.log("\uD83D\uDCCB AGENT INITIALIZATION PROMPT");
10957
+ console.log("".repeat(50));
10958
+ console.log("");
10959
+ console.log(getWaitForTaskGuidance());
10960
+ console.log("");
10961
+ console.log("".repeat(50));
10962
+ console.log("");
10963
+ console.log(initPromptResult.prompt);
10964
+ console.log("");
10965
+ console.log("".repeat(50));
10966
+ console.log("-->");
10967
+ console.log("");
10968
+ }
10940
10969
  }
10941
10970
  } catch {}
10971
+ const heartbeatTimer = setInterval(() => {
10972
+ client2.mutation(api.participants.heartbeat, {
10973
+ sessionId,
10974
+ chatroomId,
10975
+ role,
10976
+ connectionId
10977
+ }).catch((err) => {
10978
+ if (!silent) {
10979
+ console.warn(`⚠️ Heartbeat failed: ${err.message}`);
10980
+ }
10981
+ });
10982
+ }, HEARTBEAT_INTERVAL_MS);
10983
+ heartbeatTimer.unref();
10984
+ let cleanedUp = false;
10985
+ const cleanup = async () => {
10986
+ if (cleanedUp)
10987
+ return;
10988
+ cleanedUp = true;
10989
+ clearInterval(heartbeatTimer);
10990
+ try {
10991
+ await client2.mutation(api.participants.leave, {
10992
+ sessionId,
10993
+ chatroomId,
10994
+ role
10995
+ });
10996
+ } catch {}
10997
+ };
10942
10998
  let taskProcessed = false;
10943
10999
  let unsubscribe = null;
10944
11000
  const handlePendingTasks = async (pendingTasks) => {
@@ -10952,6 +11008,8 @@ async function waitForTask(chatroomId, options) {
10952
11008
  if (currentConnectionId && currentConnectionId !== connectionId) {
10953
11009
  if (unsubscribe)
10954
11010
  unsubscribe();
11011
+ clearInterval(heartbeatTimer);
11012
+ cleanedUp = true;
10955
11013
  const takeoverTime = new Date().toISOString().replace("T", " ").substring(0, 19);
10956
11014
  console.log(`
10957
11015
  ${"─".repeat(50)}`);
@@ -11002,6 +11060,8 @@ ${"─".repeat(50)}`);
11002
11060
  }
11003
11061
  if (unsubscribe)
11004
11062
  unsubscribe();
11063
+ clearInterval(heartbeatTimer);
11064
+ cleanedUp = true;
11005
11065
  const activeUntil = Date.now() + DEFAULT_ACTIVE_TIMEOUT_MS;
11006
11066
  await client2.mutation(api.participants.updateStatus, {
11007
11067
  sessionId,
@@ -11038,18 +11098,20 @@ ${"─".repeat(50)}`);
11038
11098
  const handleSignal = (_signal) => {
11039
11099
  if (unsubscribe)
11040
11100
  unsubscribe();
11041
- const signalTime = new Date().toISOString().replace("T", " ").substring(0, 19);
11042
- console.log(`
11101
+ cleanup().finally(() => {
11102
+ const signalTime = new Date().toISOString().replace("T", " ").substring(0, 19);
11103
+ console.log(`
11043
11104
  ${"─".repeat(50)}`);
11044
- console.log(`⚠️ RECONNECTION REQUIRED
11105
+ console.log(`⚠️ RECONNECTION REQUIRED
11045
11106
  `);
11046
- console.log(`[${signalTime}] Why: Process interrupted (unexpected termination)`);
11047
- console.log(`Impact: You are no longer listening for tasks`);
11048
- console.log(`Action: Run this command immediately to resume availability
11107
+ console.log(`[${signalTime}] Why: Process interrupted (unexpected termination)`);
11108
+ console.log(`Impact: You are no longer listening for tasks`);
11109
+ console.log(`Action: Run this command immediately to resume availability
11049
11110
  `);
11050
- console.log(waitForTaskCommand({ chatroomId, role, cliEnvPrefix }));
11051
- console.log(`${"─".repeat(50)}`);
11052
- process.exit(0);
11111
+ console.log(waitForTaskCommand({ chatroomId, role, cliEnvPrefix }));
11112
+ console.log(`${"─".repeat(50)}`);
11113
+ process.exit(0);
11114
+ });
11053
11115
  };
11054
11116
  process.on("SIGINT", () => handleSignal("SIGINT"));
11055
11117
  process.on("SIGTERM", () => handleSignal("SIGTERM"));
@@ -13064,6 +13126,16 @@ async function handleStartAgent(ctx, command) {
13064
13126
  } catch (e) {
13065
13127
  console.log(` ⚠️ Failed to update PID in backend: ${e.message}`);
13066
13128
  }
13129
+ if (startResult.onExit) {
13130
+ const spawnedPid = startResult.handle.pid;
13131
+ startResult.onExit((code2, signal) => {
13132
+ const ts = formatTimestamp();
13133
+ console.log(`[${ts}] ⚠️ Agent process exited unexpectedly ` + `(PID: ${spawnedPid}, role: ${role}, code: ${code2}, signal: ${signal})`);
13134
+ clearAgentPidEverywhere(ctx, chatroomId, role).catch((err) => {
13135
+ console.log(` ⚠️ Failed to clear PID after exit: ${err.message}`);
13136
+ });
13137
+ });
13138
+ }
13067
13139
  }
13068
13140
  return { result: msg, failed: false };
13069
13141
  }
@@ -13324,9 +13396,19 @@ Run any chatroom command first to register this machine,`);
13324
13396
  return ctx;
13325
13397
  }
13326
13398
  async function startCommandLoop(ctx) {
13399
+ const heartbeatTimer = setInterval(() => {
13400
+ ctx.client.mutation(api.machines.daemonHeartbeat, {
13401
+ sessionId: ctx.sessionId,
13402
+ machineId: ctx.machineId
13403
+ }).catch((err) => {
13404
+ console.warn(`[${formatTimestamp()}] ⚠️ Daemon heartbeat failed: ${err.message}`);
13405
+ });
13406
+ }, DAEMON_HEARTBEAT_INTERVAL_MS);
13407
+ heartbeatTimer.unref();
13327
13408
  const shutdown = async () => {
13328
13409
  console.log(`
13329
13410
  [${formatTimestamp()}] Shutting down...`);
13411
+ clearInterval(heartbeatTimer);
13330
13412
  try {
13331
13413
  await ctx.client.mutation(api.machines.updateDaemonStatus, {
13332
13414
  sessionId: ctx.sessionId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatroom-cli",
3
- "version": "1.0.75",
3
+ "version": "1.0.81",
4
4
  "description": "CLI for multi-agent chatroom collaboration",
5
5
  "type": "module",
6
6
  "bin": {