chatroom-cli 1.11.1 → 1.11.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.
Files changed (2) hide show
  1. package/dist/index.js +39 -50
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11134,34 +11134,10 @@ var init_daemon_state = __esm(() => {
11134
11134
  STATE_DIR = join4(CHATROOM_DIR3, "machines", "state");
11135
11135
  });
11136
11136
 
11137
- // src/infrastructure/machine/intentional-stops.ts
11138
- function agentKey2(chatroomId, role) {
11139
- return `${chatroomId}:${role.toLowerCase()}`;
11140
- }
11141
- function markIntentionalStop(chatroomId, role, reason = "user.stop") {
11142
- pendingStops.set(agentKey2(chatroomId, role), reason);
11143
- }
11144
- function consumeIntentionalStop(chatroomId, role) {
11145
- const key = agentKey2(chatroomId, role);
11146
- const reason = pendingStops.get(key) ?? null;
11147
- if (reason !== null) {
11148
- pendingStops.delete(key);
11149
- }
11150
- return reason;
11151
- }
11152
- function clearIntentionalStop(chatroomId, role) {
11153
- pendingStops.delete(agentKey2(chatroomId, role));
11154
- }
11155
- var pendingStops;
11156
- var init_intentional_stops = __esm(() => {
11157
- pendingStops = new Map;
11158
- });
11159
-
11160
11137
  // src/infrastructure/machine/index.ts
11161
11138
  var init_machine = __esm(() => {
11162
11139
  init_storage2();
11163
11140
  init_daemon_state();
11164
- init_intentional_stops();
11165
11141
  });
11166
11142
 
11167
11143
  // src/commands/auth-status/index.ts
@@ -14285,11 +14261,16 @@ function formatTimestamp() {
14285
14261
  return new Date().toISOString().replace("T", " ").substring(0, 19);
14286
14262
  }
14287
14263
 
14264
+ // src/commands/machine/daemon-start/types.ts
14265
+ function agentKey2(chatroomId, role) {
14266
+ return `${chatroomId}:${role.toLowerCase()}`;
14267
+ }
14268
+
14288
14269
  // src/events/lifecycle/on-agent-shutdown.ts
14289
14270
  async function onAgentShutdown(ctx, options) {
14290
14271
  const { chatroomId, role, pid, skipKill } = options;
14291
14272
  try {
14292
- ctx.deps.stops.mark(chatroomId, role, options.stopReason ?? "user.stop");
14273
+ ctx.pendingStops.set(agentKey2(chatroomId, role), options.stopReason ?? "user.stop");
14293
14274
  } catch (e) {
14294
14275
  console.log(` ⚠️ Failed to mark intentional stop for ${role}: ${e.message}`);
14295
14276
  }
@@ -14349,6 +14330,7 @@ async function onAgentShutdown(ctx, options) {
14349
14330
  cleaned: killed || (skipKill ?? false)
14350
14331
  };
14351
14332
  }
14333
+ var init_on_agent_shutdown = () => {};
14352
14334
 
14353
14335
  // src/events/lifecycle/on-daemon-shutdown.ts
14354
14336
  async function onDaemonShutdown(ctx) {
@@ -14389,6 +14371,7 @@ async function onDaemonShutdown(ctx) {
14389
14371
  var AGENT_SHUTDOWN_TIMEOUT_MS = 5000;
14390
14372
  var init_on_daemon_shutdown = __esm(() => {
14391
14373
  init_api3();
14374
+ init_on_agent_shutdown();
14392
14375
  });
14393
14376
 
14394
14377
  // src/commands/machine/daemon-start/handlers/shared.ts
@@ -14675,12 +14658,12 @@ class DaemonEventBus {
14675
14658
 
14676
14659
  // src/events/daemon/agent/on-agent-exited.ts
14677
14660
  function onAgentExited(ctx, payload) {
14678
- const { chatroomId, role, pid, code: code2, signal, stopReason, intentional } = payload;
14661
+ const { chatroomId, role, pid, code: code2, signal, stopReason } = payload;
14679
14662
  const ts = formatTimestamp();
14680
14663
  console.log(`[${ts}] Agent stopped: ${stopReason} (${role})`);
14681
14664
  const isDaemonRespawn = stopReason === "daemon.respawn";
14682
- const isIntentional = intentional && !isDaemonRespawn;
14683
- if (isIntentional) {
14665
+ const isIntentional = stopReason === "user.stop" || stopReason === "platform.team_switch" || stopReason === "agent_process.turn_end" || stopReason === "agent_process.turn_end_quick_fail";
14666
+ if (isIntentional && !isDaemonRespawn) {
14684
14667
  console.log(`[${ts}] ℹ️ Agent process exited after intentional stop ` + `(PID: ${pid}, role: ${role}, code: ${code2}, signal: ${signal})`);
14685
14668
  } else if (isDaemonRespawn) {
14686
14669
  console.log(`[${ts}] \uD83D\uDD04 Agent process stopped for respawn ` + `(PID: ${pid}, role: ${role}, code: ${code2}, signal: ${signal})`);
@@ -14693,11 +14676,11 @@ function onAgentExited(ctx, payload) {
14693
14676
  chatroomId,
14694
14677
  role,
14695
14678
  pid,
14696
- intentional,
14697
14679
  stopReason,
14698
14680
  stopSignal: stopReason === "agent_process.signal" ? signal ?? undefined : undefined,
14699
14681
  exitCode: code2 ?? undefined,
14700
- signal: signal ?? undefined
14682
+ signal: signal ?? undefined,
14683
+ agentHarness: payload.agentHarness
14701
14684
  }).catch((err) => {
14702
14685
  console.log(` ⚠️ Failed to record agent exit event: ${err.message}`);
14703
14686
  });
@@ -14773,11 +14756,6 @@ function createDefaultDeps19() {
14773
14756
  fs: {
14774
14757
  stat
14775
14758
  },
14776
- stops: {
14777
- mark: markIntentionalStop,
14778
- consume: consumeIntentionalStop,
14779
- clear: clearIntentionalStop
14780
- },
14781
14759
  machine: {
14782
14760
  clearAgentPid,
14783
14761
  persistAgentPid,
@@ -14909,7 +14887,7 @@ async function initDaemon() {
14909
14887
  agentServices,
14910
14888
  activeWorkingDirs: new Set,
14911
14889
  lastPushedGitState: new Map,
14912
- agentEndedTurn: new Map
14890
+ pendingStops: new Map
14913
14891
  };
14914
14892
  registerEventListeners(ctx);
14915
14893
  logStartup(ctx, availableModels);
@@ -14922,7 +14900,6 @@ var init_init2 = __esm(() => {
14922
14900
  init_storage();
14923
14901
  init_client2();
14924
14902
  init_machine();
14925
- init_intentional_stops();
14926
14903
  init_remote_agents();
14927
14904
  init_harness_spawning();
14928
14905
  init_error_formatting();
@@ -15031,10 +15008,9 @@ async function executeStartAgent(ctx, args) {
15031
15008
  return { result: msg2, failed: true };
15032
15009
  }
15033
15010
  const { pid } = spawnResult;
15011
+ const spawnedAt = Date.now();
15034
15012
  const msg = `Agent spawned (PID: ${pid})`;
15035
15013
  console.log(` ✅ ${msg}`);
15036
- const agentEndKey = `${chatroomId}:${role.toLowerCase()}`;
15037
- ctx.agentEndedTurn.delete(agentEndKey);
15038
15014
  ctx.deps.spawning.recordSpawn(chatroomId);
15039
15015
  try {
15040
15016
  await ctx.deps.backend.mutation(api.machines.updateSpawnedAgent, {
@@ -15061,7 +15037,11 @@ async function executeStartAgent(ctx, args) {
15061
15037
  ctx.activeWorkingDirs.add(workingDir);
15062
15038
  spawnResult.onExit(({ code: code2, signal }) => {
15063
15039
  ctx.deps.spawning.recordExit(chatroomId);
15064
- const pendingReason = ctx.deps.stops.consume(chatroomId, role);
15040
+ const key = agentKey2(chatroomId, role);
15041
+ const pendingReason = ctx.pendingStops.get(key) ?? null;
15042
+ if (pendingReason) {
15043
+ ctx.pendingStops.delete(key);
15044
+ }
15065
15045
  const stopReason = pendingReason ?? resolveStopReason(code2, signal, false);
15066
15046
  ctx.events.emit("agent:exited", {
15067
15047
  chatroomId,
@@ -15070,12 +15050,16 @@ async function executeStartAgent(ctx, args) {
15070
15050
  code: code2,
15071
15051
  signal,
15072
15052
  stopReason,
15073
- intentional: pendingReason !== null
15053
+ agentHarness
15074
15054
  });
15075
15055
  });
15076
15056
  if (spawnResult.onAgentEnd) {
15077
15057
  spawnResult.onAgentEnd(() => {
15078
- ctx.agentEndedTurn.set(agentEndKey, true);
15058
+ const elapsed = Date.now() - spawnedAt;
15059
+ const isHealthyTurn = elapsed >= MIN_HEALTHY_TURN_MS;
15060
+ const stopReason = isHealthyTurn ? "agent_process.turn_end" : "agent_process.turn_end_quick_fail";
15061
+ const key = agentKey2(chatroomId, role);
15062
+ ctx.pendingStops.set(key, stopReason);
15079
15063
  try {
15080
15064
  ctx.deps.processes.kill(-pid, "SIGTERM");
15081
15065
  } catch {}
@@ -15095,23 +15079,27 @@ async function executeStartAgent(ctx, args) {
15095
15079
  });
15096
15080
  return { result: msg, failed: false };
15097
15081
  }
15082
+ var MIN_HEALTHY_TURN_MS = 30000;
15098
15083
  var init_start_agent = __esm(() => {
15099
15084
  init_api3();
15100
15085
  init_client2();
15086
+ init_on_agent_shutdown();
15101
15087
  });
15102
15088
 
15103
15089
  // src/events/daemon/agent/on-request-start-agent.ts
15104
15090
  async function onRequestStartAgent(ctx, event) {
15091
+ const eventId = event._id.toString();
15105
15092
  if (Date.now() > event.deadline) {
15106
- console.log(`[daemon] ⏰ Skipping expired agent.requestStart for role=${event.role} (deadline passed)`);
15093
+ console.log(`[daemon] ⏰ Skipping expired agent.requestStart for role=${event.role} (id: ${eventId}, deadline passed)`);
15107
15094
  return;
15108
15095
  }
15109
15096
  const spawnCheck = ctx.deps.spawning.shouldAllowSpawn(event.chatroomId, event.reason);
15110
15097
  if (!spawnCheck.allowed) {
15111
15098
  const retryMsg = spawnCheck.retryAfterMs ? ` Retry after ${spawnCheck.retryAfterMs}ms.` : "";
15112
- console.warn(`[daemon] ⚠️ Spawn suppressed for chatroom=${event.chatroomId} role=${event.role} reason=${event.reason}.${retryMsg}`);
15099
+ console.warn(`[daemon] ⚠️ Spawn suppressed for chatroom=${event.chatroomId} role=${event.role} reason=${event.reason} (id: ${eventId}).${retryMsg}`);
15113
15100
  return;
15114
15101
  }
15102
+ console.log(`[daemon] Processing agent.requestStart (id: ${eventId})`);
15115
15103
  await executeStartAgent(ctx, {
15116
15104
  chatroomId: event.chatroomId,
15117
15105
  role: event.role,
@@ -15200,6 +15188,7 @@ async function executeStopAgent(ctx, args) {
15200
15188
  }
15201
15189
  var init_stop_agent = __esm(() => {
15202
15190
  init_api3();
15191
+ init_on_agent_shutdown();
15203
15192
  init_shared();
15204
15193
  });
15205
15194
 
@@ -15775,12 +15764,12 @@ class PiRestartPolicy {
15775
15764
  if (task.status !== "pending" && task.status !== "acknowledged") {
15776
15765
  return false;
15777
15766
  }
15778
- if (!context?.agentEndedTurn) {
15767
+ if (!context?.pendingStops) {
15779
15768
  return false;
15780
15769
  }
15781
- const key = `${task.chatroomId}:${agentConfig.role}`;
15782
- const hasEndedTurn = context.agentEndedTurn.get(key);
15783
- return hasEndedTurn === true;
15770
+ const key = `${task.chatroomId}:${agentConfig.role.toLowerCase()}`;
15771
+ const pendingReason = context.pendingStops.get(key);
15772
+ return pendingReason === "agent_process.turn_end";
15784
15773
  }
15785
15774
  }
15786
15775
  function getRestartPolicyForHarness(harness) {
@@ -15814,7 +15803,7 @@ function startTaskMonitor(ctx) {
15814
15803
  try {
15815
15804
  const wsClient2 = await getConvexWsClient();
15816
15805
  const agentEndContext = {
15817
- agentEndedTurn: ctx.agentEndedTurn
15806
+ pendingStops: ctx.pendingStops
15818
15807
  };
15819
15808
  unsubscribe = wsClient2.onUpdate(api.machines.getAssignedTasks, {
15820
15809
  sessionId: ctx.sessionId,
@@ -16008,7 +15997,7 @@ Listening for commands...`);
16008
15997
  evictStaleDedupEntries(processedCommandIds, processedPingIds, processedGitRefreshIds);
16009
15998
  for (const event of result.events) {
16010
15999
  try {
16011
- console.log(`[${formatTimestamp()}] \uD83D\uDCE1 Stream command event: ${event.type}`);
16000
+ console.log(`[${formatTimestamp()}] \uD83D\uDCE1 Stream command event: ${event.type} (id: ${event._id})`);
16012
16001
  await dispatchCommandEvent(ctx, event, processedCommandIds, processedPingIds, processedGitRefreshIds);
16013
16002
  } catch (err) {
16014
16003
  console.error(`[${formatTimestamp()}] ❌ Stream command event failed: ${err.message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chatroom-cli",
3
- "version": "1.11.1",
3
+ "version": "1.11.2",
4
4
  "description": "CLI for multi-agent chatroom collaboration",
5
5
  "type": "module",
6
6
  "bin": {