chatroom-cli 1.53.1 → 1.53.3

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
@@ -28015,7 +28015,7 @@ ${options.prompt}` : options.prompt;
28015
28015
  process.stderr.write(`${logPrefix} spawn-error] ${reason}
28016
28016
  `);
28017
28017
  } finally {
28018
- if (!session.agentClosed && !session.preserveForResume) {
28018
+ if (!session.agentClosed && session.aborted && !session.preserveForResume) {
28019
28019
  try {
28020
28020
  agent.close();
28021
28021
  session.agentClosed = true;
@@ -79715,9 +79715,11 @@ var init_featureFlags = __esm(() => {
79715
79715
  });
79716
79716
 
79717
79717
  // ../../services/backend/config/reliability.ts
79718
- var DAEMON_HEARTBEAT_INTERVAL_MS = 30000, AGENT_REQUEST_DEADLINE_MS = 120000, OBSERVATION_TTL_MS = 60000, OBSERVED_FULL_PUSH_INTERVAL_MS, OBSERVED_SAFETY_POLL_MS = 30000;
79718
+ var DAEMON_HEARTBEAT_INTERVAL_MS = 30000, AGENT_REQUEST_DEADLINE_MS = 120000, OBSERVATION_TTL_MS = 60000, OBSERVED_FULL_PUSH_INTERVAL_MS, OBSERVED_SAFETY_POLL_MS = 30000, WORKSPACE_RECENCY_WINDOW_MS, WORKSPACE_LIST_RECONCILE_MS;
79719
79719
  var init_reliability = __esm(() => {
79720
79720
  OBSERVED_FULL_PUSH_INTERVAL_MS = 5 * 60000;
79721
+ WORKSPACE_RECENCY_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
79722
+ WORKSPACE_LIST_RECONCILE_MS = 60 * 60 * 1000;
79721
79723
  });
79722
79724
 
79723
79725
  // src/commands/machine/daemon-start/capabilities-snapshot.ts
@@ -79987,34 +79989,30 @@ var init_command_discovery = __esm(() => {
79987
79989
  });
79988
79990
 
79989
79991
  // src/commands/machine/daemon-start/workspace-cache.ts
79990
- function invalidateWorkspacesForMachineCache(ctx) {
79991
- delete ctx._workspacesCache;
79992
- }
79993
79992
  async function getWorkspacesForMachine(ctx) {
79994
- const extended = ctx;
79995
- const now = Date.now();
79996
- const cached4 = extended._workspacesCache;
79997
- if (cached4 && now - cached4.fetchedAt < CACHE_TTL_MS) {
79998
- return cached4.workspaces;
79993
+ const store = ctx.workspaceListStore;
79994
+ if (store && store.updatedAt > 0) {
79995
+ return store.workspaces;
79999
79996
  }
80000
79997
  try {
80001
- const workspaces = await ctx.deps.backend.query(api.workspaces.listWorkspacesForMachine, {
79998
+ const workspaces = await ctx.deps.backend.query(api.workspaces.listRecentlyObservedWorkspacesForMachine, {
80002
79999
  sessionId: ctx.sessionId,
80003
80000
  machineId: ctx.machineId
80004
80001
  });
80005
- extended._workspacesCache = { fetchedAt: now, workspaces };
80006
- return workspaces;
80002
+ const mapped = workspaces.map((ws) => ({ workingDir: ws.workingDir }));
80003
+ if (store) {
80004
+ store.workspaces = mapped;
80005
+ store.updatedAt = Date.now();
80006
+ }
80007
+ return mapped;
80007
80008
  } catch (err) {
80008
80009
  console.warn(`[${formatTimestamp()}] ⚠️ Failed to query workspaces: ${getErrorMessage(err)}`);
80009
80010
  return [];
80010
80011
  }
80011
80012
  }
80012
- var CACHE_TTL_MS;
80013
80013
  var init_workspace_cache = __esm(() => {
80014
- init_reliability();
80015
80014
  init_api3();
80016
80015
  init_convex_error();
80017
- CACHE_TTL_MS = DAEMON_HEARTBEAT_INTERVAL_MS;
80018
80016
  });
80019
80017
 
80020
80018
  // src/commands/machine/daemon-start/command-sync-heartbeat.ts
@@ -83159,7 +83157,45 @@ var init_output_store = __esm(() => {
83159
83157
  RUN_ID_RE = /^[a-z0-9]+$/i;
83160
83158
  });
83161
83159
 
83162
- // src/commands/machine/daemon-start/handlers/process/log-observer-sync.ts
83160
+ // src/commands/machine/daemon-start/handlers/process/log-observer-subscription.ts
83161
+ function setsEqual(a, b) {
83162
+ if (a.size !== b.size)
83163
+ return false;
83164
+ for (const id3 of a) {
83165
+ if (!b.has(id3))
83166
+ return false;
83167
+ }
83168
+ return true;
83169
+ }
83170
+ function formatRunIdShort(runId) {
83171
+ return runId.length > 8 ? `${runId.slice(0, 8)}…` : runId;
83172
+ }
83173
+ function logObserverSetChangeIfNeeded(runs) {
83174
+ const nextObserved = new Set;
83175
+ const nextPending = new Set;
83176
+ for (const run3 of runs) {
83177
+ nextObserved.add(run3._id);
83178
+ if (run3.pendingFullOutputSync) {
83179
+ nextPending.add(run3._id);
83180
+ }
83181
+ }
83182
+ if (setsEqual(observedRunIds, nextObserved) && setsEqual(pendingFullSyncRunIds, nextPending)) {
83183
+ return;
83184
+ }
83185
+ const runSummaries = [...nextObserved].map(formatRunIdShort).join(", ") || "none";
83186
+ console.log(`[${formatTimestamp()}] \uD83D\uDCDC Log observers updated: ${nextObserved.size} run(s) [${runSummaries}] pendingFull=${nextPending.size}`);
83187
+ }
83188
+ function applyObservedRuns(runs) {
83189
+ logObserverSetChangeIfNeeded(runs);
83190
+ observedRunIds.clear();
83191
+ pendingFullSyncRunIds.clear();
83192
+ for (const run3 of runs) {
83193
+ observedRunIds.add(run3._id);
83194
+ if (run3.pendingFullOutputSync) {
83195
+ pendingFullSyncRunIds.add(run3._id);
83196
+ }
83197
+ }
83198
+ }
83163
83199
  function isRunLogObserved(runId) {
83164
83200
  return observedRunIds.has(runId);
83165
83201
  }
@@ -83169,77 +83205,41 @@ function consumePendingFullSync(runId) {
83169
83205
  pendingFullSyncRunIds.delete(runId);
83170
83206
  return true;
83171
83207
  }
83172
- function startLogObserverPoll(ctx) {
83208
+ function startLogObserverSubscription(ctx, wsClient2) {
83209
+ const queryArgs = {
83210
+ sessionId: ctx.sessionId,
83211
+ machineId: ctx.machineId
83212
+ };
83173
83213
  let stopped = false;
83174
- let consecutiveIdlePolls = 0;
83175
- let pollInFlight = false;
83176
- let timeoutHandle = null;
83177
- const scheduleNext = (delayMs) => {
83214
+ const unsubscribe = wsClient2.onUpdate(api.daemon.commands.listRunsWithLogObservers, queryArgs, (runs) => {
83178
83215
  if (stopped)
83179
83216
  return;
83180
- if (timeoutHandle)
83181
- clearTimeout(timeoutHandle);
83182
- timeoutHandle = setTimeout(() => {
83183
- poll4();
83184
- }, delayMs);
83185
- timeoutHandle.unref?.();
83186
- };
83187
- const poll4 = async () => {
83188
- if (stopped || pollInFlight)
83189
- return;
83190
- const hasLocalObservers = observedRunIds.size > 0;
83191
- if (!hasLocalObservers && consecutiveIdlePolls >= IDLE_SKIP_AFTER_CONSECUTIVE) {
83192
- scheduleNext(IDLE_POLL_INTERVAL_MS);
83193
- return;
83194
- }
83195
- pollInFlight = true;
83196
- try {
83197
- const runs = await ctx.deps.backend.query(api.commands.listRunsWithLogObservers, {
83198
- sessionId: ctx.sessionId,
83199
- machineId: ctx.machineId
83200
- });
83201
- observedRunIds.clear();
83202
- pendingFullSyncRunIds.clear();
83203
- for (const run3 of runs) {
83204
- observedRunIds.add(run3._id);
83205
- if (run3.pendingFullOutputSync) {
83206
- pendingFullSyncRunIds.add(run3._id);
83207
- }
83208
- }
83209
- const isActive2 = runs.length > 0 || hasLocalObservers;
83210
- if (isActive2) {
83211
- consecutiveIdlePolls = 0;
83212
- scheduleNext(ACTIVE_POLL_INTERVAL_MS);
83213
- } else {
83214
- consecutiveIdlePolls++;
83215
- scheduleNext(consecutiveIdlePolls >= IDLE_SKIP_AFTER_CONSECUTIVE ? IDLE_POLL_INTERVAL_MS : ACTIVE_POLL_INTERVAL_MS);
83216
- }
83217
- } catch (err) {
83218
- console.warn(`[${formatTimestamp()}] ⚠️ Log-observer poll failed: ${getErrorMessage(err)}`);
83219
- scheduleNext(ACTIVE_POLL_INTERVAL_MS);
83220
- } finally {
83221
- pollInFlight = false;
83222
- }
83223
- };
83224
- poll4();
83217
+ applyObservedRuns(runs ?? []);
83218
+ }, (err) => {
83219
+ console.warn(`[${formatTimestamp()}] ⚠️ Log-observer subscription error: ${getErrorMessage(err)}`);
83220
+ });
83221
+ console.log(`[${formatTimestamp()}] \uD83D\uDCDC Log-observer subscription started`);
83225
83222
  return {
83226
83223
  stop: () => {
83227
83224
  stopped = true;
83228
- if (timeoutHandle)
83229
- clearTimeout(timeoutHandle);
83225
+ unsubscribe();
83230
83226
  observedRunIds.clear();
83231
83227
  pendingFullSyncRunIds.clear();
83228
+ console.log(`[${formatTimestamp()}] \uD83D\uDCDC Log-observer subscription stopped`);
83232
83229
  }
83233
83230
  };
83234
83231
  }
83235
- var observedRunIds, pendingFullSyncRunIds, ACTIVE_POLL_INTERVAL_MS, IDLE_POLL_INTERVAL_MS = 15000, IDLE_SKIP_AFTER_CONSECUTIVE = 3;
83236
- var init_log_observer_sync = __esm(() => {
83232
+ var observedRunIds, pendingFullSyncRunIds;
83233
+ var init_log_observer_subscription = __esm(() => {
83237
83234
  init_api3();
83238
83235
  init_convex_error();
83239
- init_state2();
83240
83236
  observedRunIds = new Set;
83241
83237
  pendingFullSyncRunIds = new Set;
83242
- ACTIVE_POLL_INTERVAL_MS = OUTPUT_FLUSH_INTERVAL_MS;
83238
+ });
83239
+
83240
+ // src/commands/machine/daemon-start/handlers/process/log-observer-sync.ts
83241
+ var init_log_observer_sync = __esm(() => {
83242
+ init_log_observer_subscription();
83243
83243
  });
83244
83244
 
83245
83245
  // src/commands/machine/daemon-start/handlers/process/spawner.ts
@@ -83819,7 +83819,7 @@ function isProcessAlive(kill, pid) {
83819
83819
  }
83820
83820
  }
83821
83821
 
83822
- // src/infrastructure/machine/stop-reason.ts
83822
+ // src/domain/agent-lifecycle/entities/stop-reason.ts
83823
83823
  function resolveStopReason(code2, signal) {
83824
83824
  if (signal !== null)
83825
83825
  return "agent_process.signal";
@@ -83828,11 +83828,59 @@ function resolveStopReason(code2, signal) {
83828
83828
  return "agent_process.crashed";
83829
83829
  }
83830
83830
 
83831
+ // src/domain/agent-lifecycle/policies/preserve-session.ts
83832
+ function shouldRetainHarnessSessionForReconnect(reason) {
83833
+ switch (reason) {
83834
+ case "user.stop":
83835
+ case "agent_process.exited_clean":
83836
+ case "agent_process.signal":
83837
+ case "agent_process.crashed":
83838
+ return true;
83839
+ default:
83840
+ return false;
83841
+ }
83842
+ }
83843
+ function shouldPreserveHarnessTeardown(reason, supportsSessionResume, hasHarnessSessionId) {
83844
+ return hasHarnessSessionId && supportsSessionResume && shouldRetainHarnessSessionForReconnect(reason);
83845
+ }
83846
+
83847
+ // src/domain/agent-lifecycle/policies/decide-resume-path.ts
83848
+ function decideResumePathOnRestart(input) {
83849
+ if (!input.supportsSessionResume) {
83850
+ return "cold";
83851
+ }
83852
+ if (input.wantResume && input.hasStoredSnapshot) {
83853
+ return "daemon_memory";
83854
+ }
83855
+ return "cold";
83856
+ }
83857
+ function shouldAutoRestartAfterProcessExit(stopReason) {
83858
+ switch (stopReason) {
83859
+ case "user.stop":
83860
+ case "platform.team_switch":
83861
+ case "daemon.shutdown":
83862
+ case "daemon.respawn":
83863
+ return false;
83864
+ default:
83865
+ return true;
83866
+ }
83867
+ }
83868
+
83869
+ // src/domain/agent-lifecycle/index.ts
83870
+ var init_agent_lifecycle = () => {};
83871
+
83831
83872
  // ../../services/backend/src/domain/entities/harness/claude.config.ts
83832
83873
  var claudeCapabilities;
83833
83874
  var init_claude_config = __esm(() => {
83834
83875
  claudeCapabilities = {
83835
- supportsSessionResume: false
83876
+ runtimeKind: "cli",
83877
+ supportsSessionResume: false,
83878
+ lifecycle: {
83879
+ turnCompleted: false,
83880
+ outputActivity: true,
83881
+ processExited: true
83882
+ },
83883
+ wireEvents: []
83836
83884
  };
83837
83885
  });
83838
83886
 
@@ -83840,7 +83888,14 @@ var init_claude_config = __esm(() => {
83840
83888
  var commandcodeCapabilities;
83841
83889
  var init_commandcode_config = __esm(() => {
83842
83890
  commandcodeCapabilities = {
83843
- supportsSessionResume: false
83891
+ runtimeKind: "cli",
83892
+ supportsSessionResume: false,
83893
+ lifecycle: {
83894
+ turnCompleted: true,
83895
+ outputActivity: true,
83896
+ processExited: true
83897
+ },
83898
+ wireEvents: ["wire.log.agent_end"]
83844
83899
  };
83845
83900
  });
83846
83901
 
@@ -83848,7 +83903,14 @@ var init_commandcode_config = __esm(() => {
83848
83903
  var copilotCapabilities;
83849
83904
  var init_copilot_config = __esm(() => {
83850
83905
  copilotCapabilities = {
83851
- supportsSessionResume: false
83906
+ runtimeKind: "cli",
83907
+ supportsSessionResume: false,
83908
+ lifecycle: {
83909
+ turnCompleted: true,
83910
+ outputActivity: true,
83911
+ processExited: true
83912
+ },
83913
+ wireEvents: ["wire.log.agent_end"]
83852
83914
  };
83853
83915
  });
83854
83916
 
@@ -83856,7 +83918,14 @@ var init_copilot_config = __esm(() => {
83856
83918
  var cursorCapabilities;
83857
83919
  var init_cursor_config = __esm(() => {
83858
83920
  cursorCapabilities = {
83859
- supportsSessionResume: false
83921
+ runtimeKind: "cli",
83922
+ supportsSessionResume: false,
83923
+ lifecycle: {
83924
+ turnCompleted: true,
83925
+ outputActivity: true,
83926
+ processExited: true
83927
+ },
83928
+ wireEvents: ["wire.log.agent_end"]
83860
83929
  };
83861
83930
  });
83862
83931
 
@@ -83864,7 +83933,14 @@ var init_cursor_config = __esm(() => {
83864
83933
  var cursorSdkCapabilities;
83865
83934
  var init_cursor_sdk_config = __esm(() => {
83866
83935
  cursorSdkCapabilities = {
83867
- supportsSessionResume: true
83936
+ runtimeKind: "sdk",
83937
+ supportsSessionResume: true,
83938
+ lifecycle: {
83939
+ turnCompleted: true,
83940
+ outputActivity: true,
83941
+ processExited: true
83942
+ },
83943
+ wireEvents: ["sdk.cursor.message", "sdk.cursor.run.completed", "wire.log.agent_end"]
83868
83944
  };
83869
83945
  });
83870
83946
 
@@ -83872,7 +83948,14 @@ var init_cursor_sdk_config = __esm(() => {
83872
83948
  var opencodeCapabilities;
83873
83949
  var init_opencode_config = __esm(() => {
83874
83950
  opencodeCapabilities = {
83875
- supportsSessionResume: false
83951
+ runtimeKind: "cli",
83952
+ supportsSessionResume: false,
83953
+ lifecycle: {
83954
+ turnCompleted: false,
83955
+ outputActivity: true,
83956
+ processExited: true
83957
+ },
83958
+ wireEvents: []
83876
83959
  };
83877
83960
  });
83878
83961
 
@@ -83880,7 +83963,14 @@ var init_opencode_config = __esm(() => {
83880
83963
  var opencodeSdkCapabilities;
83881
83964
  var init_opencode_sdk_config = __esm(() => {
83882
83965
  opencodeSdkCapabilities = {
83883
- supportsSessionResume: true
83966
+ runtimeKind: "sdk",
83967
+ supportsSessionResume: true,
83968
+ lifecycle: {
83969
+ turnCompleted: true,
83970
+ outputActivity: true,
83971
+ processExited: true
83972
+ },
83973
+ wireEvents: ["sdk.opencode.session.idle", "sdk.opencode.session.event"]
83884
83974
  };
83885
83975
  });
83886
83976
 
@@ -83888,7 +83978,22 @@ var init_opencode_sdk_config = __esm(() => {
83888
83978
  var piCapabilities;
83889
83979
  var init_pi_config = __esm(() => {
83890
83980
  piCapabilities = {
83891
- supportsSessionResume: true
83981
+ runtimeKind: "cli",
83982
+ supportsSessionResume: true,
83983
+ lifecycle: {
83984
+ turnCompleted: true,
83985
+ outputActivity: true,
83986
+ processExited: true
83987
+ },
83988
+ wireEvents: [
83989
+ "wire.ndjson.agent_start",
83990
+ "wire.ndjson.agent_end",
83991
+ "wire.ndjson.message_update",
83992
+ "wire.ndjson.tool_execution_start",
83993
+ "wire.ndjson.tool_execution_end",
83994
+ "wire.ndjson.get_state",
83995
+ "wire.log.agent_end"
83996
+ ]
83892
83997
  };
83893
83998
  });
83894
83999
 
@@ -84010,11 +84115,11 @@ class AgentProcessManager {
84010
84115
  const key = agentKey2(opts.chatroomId, opts.role);
84011
84116
  const slot = this.slots.get(key);
84012
84117
  if (slot?.resumeInFlight) {
84013
- console.log(`[AgentProcessManager] agent_end: skipping duplicate resume for ${opts.role} (resume already in flight)`);
84118
+ console.log(`[AgentProcessManager] lifecycle.turn.completed: skipping duplicate resume for ${opts.role} (resume already in flight)`);
84014
84119
  return;
84015
84120
  }
84016
84121
  const capabilities = getHarnessCapabilities(opts.harness);
84017
- console.log(`[AgentProcessManager] agent_end: role=${opts.role} pid=${opts.pid} harness=${opts.harness} supportsResume=${capabilities.supportsSessionResume}`);
84122
+ console.log(`[AgentProcessManager] lifecycle.turn.completed: role=${opts.role} pid=${opts.pid} harness=${opts.harness} supportsResume=${capabilities.supportsSessionResume}`);
84018
84123
  if (capabilities.supportsSessionResume) {
84019
84124
  const service = this.deps.agentServices.get(opts.harness);
84020
84125
  if (service?.resumeTurn) {
@@ -84082,6 +84187,18 @@ class AgentProcessManager {
84082
84187
  const harness = slot.harness;
84083
84188
  const model = slot.model;
84084
84189
  const workingDir = slot.workingDir;
84190
+ const harnessSessionId = slot.harnessSessionId;
84191
+ if (harness && harnessSessionId && getHarnessCapabilities(harness).supportsSessionResume && shouldRetainHarnessSessionForReconnect(stopReason)) {
84192
+ const service = this.deps.agentServices.get(harness);
84193
+ const harnessMeta = service ? this.readHarnessReconnectMetadata(service, opts.pid) : undefined;
84194
+ this.recordLastHarnessSession(key, {
84195
+ harnessSessionId,
84196
+ harness,
84197
+ agentName: harnessMeta?.agentName ?? "",
84198
+ workingDir: workingDir ?? "",
84199
+ model: model ?? harnessMeta?.model
84200
+ });
84201
+ }
84085
84202
  slot.state = "idle";
84086
84203
  slot.pid = undefined;
84087
84204
  slot.startedAt = undefined;
@@ -84108,13 +84225,10 @@ class AgentProcessManager {
84108
84225
  for (const service of this.deps.agentServices.values()) {
84109
84226
  service.untrack(opts.pid);
84110
84227
  }
84111
- const isIntentionalStop = stopReason === "user.stop" || stopReason === "platform.team_switch" || stopReason === "daemon.shutdown";
84112
- const isDaemonRespawn = stopReason === "daemon.respawn";
84113
- if (isIntentionalStop) {
84114
- this.deps.crashLoop.clear(opts.chatroomId, opts.role);
84115
- return;
84116
- }
84117
- if (isDaemonRespawn) {
84228
+ if (!shouldAutoRestartAfterProcessExit(stopReason)) {
84229
+ if (stopReason === "user.stop" || stopReason === "platform.team_switch" || stopReason === "daemon.shutdown") {
84230
+ this.deps.crashLoop.clear(opts.chatroomId, opts.role);
84231
+ }
84118
84232
  return;
84119
84233
  }
84120
84234
  if (!harness || !workingDir) {
@@ -84473,7 +84587,12 @@ class AgentProcessManager {
84473
84587
  return { success: false, error: `Unknown agent harness: ${opts.agentHarness}` };
84474
84588
  }
84475
84589
  let spawnResult;
84476
- if (wantResume) {
84590
+ const resumePath = decideResumePathOnRestart({
84591
+ supportsSessionResume: getHarnessCapabilities(opts.agentHarness).supportsSessionResume,
84592
+ wantResume,
84593
+ hasStoredSnapshot: this.lastHarnessSessions.has(key)
84594
+ });
84595
+ if (resumePath === "daemon_memory") {
84477
84596
  spawnResult = await this.tryDaemonMemoryResume({
84478
84597
  key,
84479
84598
  chatroomId: opts.chatroomId,
@@ -84590,7 +84709,8 @@ class AgentProcessManager {
84590
84709
  try {
84591
84710
  const harness = slot.harness;
84592
84711
  const service = harness ? this.deps.agentServices.get(harness) : undefined;
84593
- const preserveForResume = opts.reason === "user.stop" && Boolean(slot.harnessSessionId);
84712
+ const supportsResume = harness ? getHarnessCapabilities(harness).supportsSessionResume : false;
84713
+ const preserveForResume = shouldPreserveHarnessTeardown(opts.reason, supportsResume, Boolean(slot.harnessSessionId));
84594
84714
  if (harness && slot.harnessSessionId) {
84595
84715
  if (preserveForResume) {
84596
84716
  const harnessMeta = service ? this.readHarnessReconnectMetadata(service, pid) : undefined;
@@ -84668,6 +84788,7 @@ var AGENT_EXIT_RETRY_INTERVAL_MS = 1e4;
84668
84788
  var init_agent_process_manager = __esm(() => {
84669
84789
  init_orphan_tracker();
84670
84790
  init_api3();
84791
+ init_agent_lifecycle();
84671
84792
  init_types();
84672
84793
  init_generator();
84673
84794
  });
@@ -85246,6 +85367,62 @@ var init_observed_sync = __esm(() => {
85246
85367
  init_convex_error();
85247
85368
  });
85248
85369
 
85370
+ // src/commands/machine/daemon-start/workspace-list-subscription.ts
85371
+ function toSyncWorkspaces(workspaces) {
85372
+ return workspaces.map((ws) => ({ workingDir: ws.workingDir }));
85373
+ }
85374
+ function applyWorkspaceList(ctx, workspaces) {
85375
+ if (!ctx.workspaceListStore)
85376
+ return;
85377
+ ctx.workspaceListStore.workspaces = toSyncWorkspaces(workspaces);
85378
+ ctx.workspaceListStore.updatedAt = Date.now();
85379
+ }
85380
+ function startWorkspaceListSubscription(ctx, wsClient2) {
85381
+ ctx.workspaceListStore = { workspaces: [], updatedAt: 0 };
85382
+ const queryArgs = {
85383
+ sessionId: ctx.sessionId,
85384
+ machineId: ctx.machineId,
85385
+ recencyWindowMs: WORKSPACE_RECENCY_WINDOW_MS
85386
+ };
85387
+ let stopped = false;
85388
+ let reconcileInFlight = false;
85389
+ const unsubscribe = wsClient2.onUpdate(api.workspaces.listRecentlyObservedWorkspacesForMachine, queryArgs, (workspaces) => {
85390
+ if (stopped)
85391
+ return;
85392
+ applyWorkspaceList(ctx, workspaces ?? []);
85393
+ }, (err) => {
85394
+ console.warn(`[${formatTimestamp()}] ⚠️ Workspace-list subscription error: ${getErrorMessage(err)}`);
85395
+ });
85396
+ const reconcileTimer = setInterval(() => {
85397
+ if (stopped || reconcileInFlight)
85398
+ return;
85399
+ reconcileInFlight = true;
85400
+ ctx.deps.backend.query(api.workspaces.listRecentlyObservedWorkspacesForMachine, queryArgs).then((workspaces) => {
85401
+ if (!stopped)
85402
+ applyWorkspaceList(ctx, workspaces ?? []);
85403
+ }).catch((err) => {
85404
+ console.warn(`[${formatTimestamp()}] ⚠️ Workspace-list reconcile failed: ${getErrorMessage(err)}`);
85405
+ }).finally(() => {
85406
+ reconcileInFlight = false;
85407
+ });
85408
+ }, WORKSPACE_LIST_RECONCILE_MS);
85409
+ console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Workspace-list subscription started`);
85410
+ return {
85411
+ stop: () => {
85412
+ stopped = true;
85413
+ unsubscribe();
85414
+ clearInterval(reconcileTimer);
85415
+ delete ctx.workspaceListStore;
85416
+ console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Workspace-list subscription stopped`);
85417
+ }
85418
+ };
85419
+ }
85420
+ var init_workspace_list_subscription = __esm(() => {
85421
+ init_reliability();
85422
+ init_api3();
85423
+ init_convex_error();
85424
+ });
85425
+
85249
85426
  // src/infrastructure/git/git-writer.ts
85250
85427
  import { exec as exec5 } from "node:child_process";
85251
85428
  import { promisify as promisify5 } from "node:util";
@@ -85961,7 +86138,6 @@ async function startCommandLoop(ctx) {
85961
86138
  }).then(() => {
85962
86139
  heartbeatCount++;
85963
86140
  console.log(`[${formatTimestamp()}] \uD83D\uDC93 Daemon heartbeat #${heartbeatCount} OK`);
85964
- invalidateWorkspacesForMachineCache(ctx);
85965
86141
  if (!ctx.observedSyncEnabled) {
85966
86142
  pushGitState(ctx).catch((err) => {
85967
86143
  console.warn(`[${formatTimestamp()}] ⚠️ Git state push failed: ${getErrorMessage(err)}`);
@@ -85981,8 +86157,9 @@ async function startCommandLoop(ctx) {
85981
86157
  let gitSubscriptionHandle = null;
85982
86158
  let fileContentSubscriptionHandle = null;
85983
86159
  let fileTreeSubscriptionHandle = null;
86160
+ let workspaceListSubscriptionHandle = null;
85984
86161
  let observedSyncSubscriptionHandle = null;
85985
- let logObserverPollHandle = null;
86162
+ let logObserverSubscriptionHandle = null;
85986
86163
  let pendingPromptSubscriptionHandle = null;
85987
86164
  let pendingHarnessSessionSubscriptionHandle = null;
85988
86165
  let commandSubscriptionHandle = null;
@@ -86006,10 +86183,12 @@ async function startCommandLoop(ctx) {
86006
86183
  fileContentSubscriptionHandle.stop();
86007
86184
  if (fileTreeSubscriptionHandle)
86008
86185
  fileTreeSubscriptionHandle.stop();
86186
+ if (workspaceListSubscriptionHandle)
86187
+ workspaceListSubscriptionHandle.stop();
86009
86188
  if (observedSyncSubscriptionHandle)
86010
86189
  observedSyncSubscriptionHandle.stop();
86011
- if (logObserverPollHandle)
86012
- logObserverPollHandle.stop();
86190
+ if (logObserverSubscriptionHandle)
86191
+ logObserverSubscriptionHandle.stop();
86013
86192
  if (pendingPromptSubscriptionHandle)
86014
86193
  pendingPromptSubscriptionHandle.stop();
86015
86194
  if (pendingHarnessSessionSubscriptionHandle)
@@ -86035,10 +86214,11 @@ async function startCommandLoop(ctx) {
86035
86214
  gitSubscriptionHandle = startGitRequestSubscription(ctx, wsClient2);
86036
86215
  fileContentSubscriptionHandle = startFileContentSubscription(ctx, wsClient2);
86037
86216
  fileTreeSubscriptionHandle = startFileTreeSubscription(ctx, wsClient2);
86217
+ workspaceListSubscriptionHandle = startWorkspaceListSubscription(ctx, wsClient2);
86038
86218
  if (ctx.observedSyncEnabled) {
86039
86219
  observedSyncSubscriptionHandle = startObservedSyncSubscription(ctx, wsClient2);
86040
86220
  }
86041
- logObserverPollHandle = startLogObserverPoll(ctx);
86221
+ logObserverSubscriptionHandle = startLogObserverSubscription(ctx, wsClient2);
86042
86222
  if (featureFlags.directHarnessWorkers) {
86043
86223
  const sessionRepository = new ConvexSessionRepository({
86044
86224
  backend: ctx.deps.backend,
@@ -86128,8 +86308,8 @@ var init_command_loop = __esm(() => {
86128
86308
  init_manager();
86129
86309
  init_init2();
86130
86310
  init_log_observer_sync();
86131
- init_workspace_cache();
86132
86311
  init_observed_sync();
86312
+ init_workspace_list_subscription();
86133
86313
  init_api3();
86134
86314
  init_client2();
86135
86315
  init_local_actions();
@@ -87304,8 +87484,8 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
87304
87484
  if (!sessionId)
87305
87485
  return;
87306
87486
  const client4 = await getConvexClient2();
87307
- sendLifecycleHeartbeat2(client4, { sessionId, chatroomId, role, action: actionCommand.name() });
87487
+ sendLifecycleHeartbeat2(client4, { sessionId, chatroomId, role });
87308
87488
  });
87309
87489
  program2.parse();
87310
87490
 
87311
- //# debugId=D59205F0E7B31DAD64756E2164756E21
87491
+ //# debugId=738F13B9B9408F0B64756E2164756E21