chatroom-cli 1.106.0 → 1.107.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 CHANGED
@@ -78981,6 +78981,9 @@ var init_machine_service = __esm(() => {
78981
78981
  RegisterAgentMachineService = class RegisterAgentMachineService extends exports_Context.Tag("RegisterAgentMachineService")() {
78982
78982
  };
78983
78983
  });
78984
+ // ../../services/backend/convex/workspaceFileTree/access.ts
78985
+ var FILE_TREE_SYNC_DISABLED_CODE = "FILE_TREE_SYNC_DISABLED";
78986
+ var init_access = () => {};
78984
78987
 
78985
78988
  // src/utils/convex-error.ts
78986
78989
  function formatConvexErrorObject(data) {
@@ -79013,8 +79016,23 @@ function getErrorMessage(error) {
79013
79016
  return formatServerError(error);
79014
79017
  return String(error);
79015
79018
  }
79019
+ function getConvexErrorCode(error) {
79020
+ if (!(error instanceof ConvexError))
79021
+ return;
79022
+ const data = error.data;
79023
+ if (data !== null && typeof data === "object" && "code" in data) {
79024
+ const code2 = data.code;
79025
+ if (typeof code2 === "string")
79026
+ return code2;
79027
+ }
79028
+ return;
79029
+ }
79030
+ function isFileTreeSyncDisabledError(error) {
79031
+ return getConvexErrorCode(error) === FILE_TREE_SYNC_DISABLED_CODE;
79032
+ }
79016
79033
  var SERVER_ERROR_HINT;
79017
79034
  var init_convex_error = __esm(() => {
79035
+ init_access();
79018
79036
  init_values();
79019
79037
  SERVER_ERROR_HINT = "This is a generic server error — likely a backend arg-validator rejection or a CLI/backend version mismatch." + " Verify the CLI and backend are on the same commit (run `pnpm install` and check `git log -1 origin/master`).";
79020
79038
  });
@@ -116251,11 +116269,20 @@ async function publishCheckpointUntilPruned(session2, normalizedWorkingDir, snap
116251
116269
  assertCheckpointAccepted(result);
116252
116270
  return checkpointRevision;
116253
116271
  }
116254
- function createWorkspaceFileTreeCheckpointSend(session2, normalizedWorkingDir) {
116272
+ function createWorkspaceFileTreeCheckpointSend(session2, normalizedWorkingDir, options) {
116255
116273
  return async (state) => {
116256
- const snapshot = await syncScannedFileTree(session2, normalizedWorkingDir, state.tree, computeFileTreeDataHash(state.tree), randomUUID11());
116257
- const revision = await publishCheckpointUntilPruned(session2, normalizedWorkingDir, snapshot, state.revision);
116258
- return { revision };
116274
+ try {
116275
+ const snapshot = await syncScannedFileTree(session2, normalizedWorkingDir, state.tree, computeFileTreeDataHash(state.tree), randomUUID11());
116276
+ const revision = await publishCheckpointUntilPruned(session2, normalizedWorkingDir, snapshot, state.revision);
116277
+ return { revision };
116278
+ } catch (error51) {
116279
+ if (!isFileTreeSyncDisabledError(error51))
116280
+ throw error51;
116281
+ (async () => options?.onSyncDisabled?.())().catch(() => {
116282
+ return;
116283
+ });
116284
+ return { revision: state.revision };
116285
+ }
116259
116286
  };
116260
116287
  }
116261
116288
  var init_workspace_file_tree_checkpoint_send = __esm(() => {
@@ -116264,6 +116291,7 @@ var init_workspace_file_tree_checkpoint_send = __esm(() => {
116264
116291
  init_file_tree_data_hash();
116265
116292
  init_blob_snapshot_publish();
116266
116293
  init_sharded_snapshot_publish();
116294
+ init_convex_error();
116267
116295
  });
116268
116296
 
116269
116297
  // src/daemon/infrastructure/outbox/workspace-file-tree-delta-send.ts
@@ -116285,52 +116313,81 @@ function toDeltaOperations(delta) {
116285
116313
  }))
116286
116314
  ];
116287
116315
  }
116288
- function createWorkspaceFileTreeDeltaSend(session2, normalizedWorkingDir) {
116316
+ function createWorkspaceFileTreeDeltaSend(session2, normalizedWorkingDir, options) {
116289
116317
  return async (unit) => {
116290
- const result = await session2.backend.mutation(api.workspaceFiles.applyFileTreeDeltaBatch, {
116291
- sessionId: session2.sessionId,
116292
- machineId: session2.machineId,
116293
- workingDir: normalizedWorkingDir,
116294
- operationId: unit.delta.operationId,
116295
- baseRevision: unit.baseRevision,
116296
- operations: toDeltaOperations(unit.delta)
116297
- });
116298
- if (result.status === "resync-required") {
116299
- return { status: "conflict", revision: result.expectedRevision };
116318
+ try {
116319
+ const result = await session2.backend.mutation(api.workspaceFiles.applyFileTreeDeltaBatch, {
116320
+ sessionId: session2.sessionId,
116321
+ machineId: session2.machineId,
116322
+ workingDir: normalizedWorkingDir,
116323
+ operationId: unit.delta.operationId,
116324
+ baseRevision: unit.baseRevision,
116325
+ operations: toDeltaOperations(unit.delta)
116326
+ });
116327
+ if (result.status === "resync-required") {
116328
+ return { status: "conflict", revision: result.expectedRevision };
116329
+ }
116330
+ return result;
116331
+ } catch (error51) {
116332
+ if (!isFileTreeSyncDisabledError(error51))
116333
+ throw error51;
116334
+ (async () => options?.onSyncDisabled?.())().catch(() => {
116335
+ return;
116336
+ });
116337
+ return { status: "applied", revision: unit.baseRevision };
116300
116338
  }
116301
- return result;
116302
116339
  };
116303
116340
  }
116304
116341
  var init_workspace_file_tree_delta_send = __esm(() => {
116305
116342
  init_api3();
116343
+ init_convex_error();
116306
116344
  });
116307
116345
 
116308
116346
  // src/daemon/entry/files/file-tree-subscription.ts
116309
116347
  function logSubscriptionWarn(label, err) {
116310
116348
  console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage(err)}`);
116311
116349
  }
116312
- async function runOneShotFileTreeSync(session2, workingDir) {
116350
+ async function runOneShotFileTreeSync(session2, workingDir, coordinators, checkpointOutboxRegistry, deltaOutboxRegistry) {
116313
116351
  const normalized = normalizeWorkingDirForLookup(workingDir);
116314
- const tree = await scanFileTree(normalized);
116315
- const send = createWorkspaceFileTreeCheckpointSend(session2, normalized);
116316
- await send({ tree, revision: 0 });
116317
- await session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
116318
- sessionId: session2.sessionId,
116319
- machineId: session2.machineId,
116320
- workingDir: normalized
116321
- });
116352
+ let syncDisabled = false;
116353
+ try {
116354
+ const tree = await scanFileTree(normalized);
116355
+ const send = createWorkspaceFileTreeCheckpointSend(session2, normalized, {
116356
+ onSyncDisabled: () => {
116357
+ syncDisabled = true;
116358
+ }
116359
+ });
116360
+ await send({ tree, revision: 0 });
116361
+ if (syncDisabled) {
116362
+ await stopFileTreeSyncForDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116363
+ return;
116364
+ }
116365
+ await session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
116366
+ sessionId: session2.sessionId,
116367
+ machineId: session2.machineId,
116368
+ workingDir: normalized
116369
+ });
116370
+ } catch (error51) {
116371
+ if (!isFileTreeSyncDisabledError(error51))
116372
+ throw error51;
116373
+ await stopFileTreeSyncForDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116374
+ }
116322
116375
  }
116323
116376
  async function stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized) {
116324
116377
  const coordinatorPromise = coordinators.get(normalized);
116325
- if (!coordinatorPromise)
116326
- return;
116327
- coordinators.delete(normalized);
116328
- await coordinatorPromise.then((coordinator2) => coordinator2.stop()).catch(() => {
116329
- return;
116330
- });
116378
+ if (coordinatorPromise) {
116379
+ coordinators.delete(normalized);
116380
+ await coordinatorPromise.then((coordinator2) => coordinator2.stop()).catch(() => {
116381
+ return;
116382
+ });
116383
+ }
116331
116384
  await checkpointOutboxRegistry?.stop(normalized);
116332
116385
  await deltaOutboxRegistry?.stop(normalized);
116333
116386
  }
116387
+ async function stopFileTreeSyncForDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized) {
116388
+ await stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116389
+ console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree sync disabled: ${normalized}`);
116390
+ }
116334
116391
  async function drainPendingFileTreeReleaseRequests(session2, coordinators, checkpointOutboxRegistry, deltaOutboxRegistry) {
116335
116392
  while (true) {
116336
116393
  const releases = await session2.backend.query(api.workspaceFiles.getPendingFileTreeReleaseRequests, {
@@ -116346,13 +116403,12 @@ async function drainPendingFileTreeReleaseRequests(session2, coordinators, check
116346
116403
  let successCount = 0;
116347
116404
  for (const normalized of releasesByDir) {
116348
116405
  try {
116349
- await stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116406
+ await stopFileTreeSyncForDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116350
116407
  await session2.backend.mutation(api.workspaceFiles.fulfillFileTreeReleaseRequest, {
116351
116408
  sessionId: session2.sessionId,
116352
116409
  machineId: session2.machineId,
116353
116410
  workingDir: normalized
116354
116411
  });
116355
- console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree coordinator stopped: ${normalized}`);
116356
116412
  successCount++;
116357
116413
  } catch (err) {
116358
116414
  logSubscriptionWarn(`File tree release failed for ${normalized}`, err);
@@ -116371,7 +116427,7 @@ async function processOnePendingFileTreeRequest(session2, coordinators, ensureCo
116371
116427
  });
116372
116428
  if (!lease?.leaseActive) {
116373
116429
  await stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116374
- await runOneShotFileTreeSync(session2, normalized);
116430
+ await runOneShotFileTreeSync(session2, normalized, coordinators, checkpointOutboxRegistry, deltaOutboxRegistry);
116375
116431
  console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree ready: ${normalized} (${Date.now() - start3}ms, one-shot)`);
116376
116432
  return;
116377
116433
  }
@@ -116404,6 +116460,10 @@ async function processPendingFileTreeRequests(session2, coordinators, ensureCoor
116404
116460
  try {
116405
116461
  await processOnePendingFileTreeRequest(session2, coordinators, ensureCoordinator, normalized, force, checkpointOutboxRegistry, deltaOutboxRegistry);
116406
116462
  } catch (err) {
116463
+ if (isFileTreeSyncDisabledError(err)) {
116464
+ await stopFileTreeSyncForDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116465
+ return;
116466
+ }
116407
116467
  logSubscriptionWarn(`File tree failed for ${normalized}`, err);
116408
116468
  }
116409
116469
  });
@@ -116420,16 +116480,40 @@ var startFileTreeSubscriptionEffect = () => exports_Effect.gen(function* () {
116420
116480
  const session2 = yield* DaemonSessionService;
116421
116481
  const coordinators = new Map;
116422
116482
  const checkpointOutboxRegistry = createWorkspaceFileTreeCheckpointOutboxRegistry(session2.machineId, (normalized) => {
116423
- const send = createWorkspaceFileTreeCheckpointSend(session2, normalized);
116483
+ const onSyncDisabled = () => stopFileTreeSyncForDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116484
+ const send = createWorkspaceFileTreeCheckpointSend(session2, normalized, {
116485
+ onSyncDisabled
116486
+ });
116424
116487
  return async (state) => {
116425
116488
  const result = await send(state);
116426
116489
  console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree checkpoint: ${normalized} (${state.tree.entries.length} entries, revision ${result.revision})`);
116427
116490
  return result;
116428
116491
  };
116429
116492
  }, {
116430
- onError: (normalized, error51) => logSubscriptionWarn(`File tree checkpoint outbox failed for ${normalized}`, error51)
116493
+ onError: (normalized, error51) => {
116494
+ if (isFileTreeSyncDisabledError(error51)) {
116495
+ stopFileTreeSyncForDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized).catch(() => {
116496
+ return;
116497
+ });
116498
+ return;
116499
+ }
116500
+ logSubscriptionWarn(`File tree checkpoint outbox failed for ${normalized}`, error51);
116501
+ }
116502
+ });
116503
+ const deltaOutboxRegistry = createWorkspaceFileTreeDeltaOutboxRegistry(session2.machineId, (normalized) => {
116504
+ const onSyncDisabled = () => stopFileTreeSyncForDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized);
116505
+ return createWorkspaceFileTreeDeltaSend(session2, normalized, { onSyncDisabled });
116506
+ }, {
116507
+ onError: (normalized, error51) => {
116508
+ if (isFileTreeSyncDisabledError(error51)) {
116509
+ stopFileTreeSyncForDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized).catch(() => {
116510
+ return;
116511
+ });
116512
+ return;
116513
+ }
116514
+ logSubscriptionWarn(`File tree delta outbox failed for ${normalized}`, error51);
116515
+ }
116431
116516
  });
116432
- const deltaOutboxRegistry = createWorkspaceFileTreeDeltaOutboxRegistry(session2.machineId, (normalized) => createWorkspaceFileTreeDeltaSend(session2, normalized));
116433
116517
  const ensureCoordinator = (workingDir, forceReconcile) => {
116434
116518
  const normalized = normalizeWorkingDirForLookup(workingDir);
116435
116519
  let coordinatorPromise = coordinators.get(normalized);
@@ -117699,14 +117783,47 @@ var init_task_delivery_processor = __esm(() => {
117699
117783
  init_task_delivery_logic();
117700
117784
  });
117701
117785
 
117786
+ // src/daemon/infrastructure/agent-operational/operational-signal-contract.ts
117787
+ function asChatroomId(chatroomId) {
117788
+ return chatroomId;
117789
+ }
117790
+ function buildSubscribeMachineOperationalSignalsSinceArgs(input) {
117791
+ return {
117792
+ sessionId: input.sessionId,
117793
+ machineId: input.machineId,
117794
+ chatroomId: asChatroomId(input.chatroomId),
117795
+ afterKey: input.afterKey,
117796
+ ...input.limit === undefined ? {} : { limit: input.limit }
117797
+ };
117798
+ }
117799
+ function buildListOperationalStatusForMachineSignalRangeArgs(input) {
117800
+ return {
117801
+ sessionId: input.sessionId,
117802
+ machineId: input.machineId,
117803
+ chatroomId: asChatroomId(input.chatroomId),
117804
+ afterSignalKey: input.afterSignalKey,
117805
+ throughSignalKey: input.throughSignalKey,
117806
+ ...input.limit === undefined ? {} : { limit: input.limit }
117807
+ };
117808
+ }
117809
+ function buildAckMachineOperationalSignalsArgs(input) {
117810
+ return {
117811
+ sessionId: input.sessionId,
117812
+ machineId: input.machineId,
117813
+ chatroomId: asChatroomId(input.chatroomId),
117814
+ throughSignalKey: input.throughSignalKey
117815
+ };
117816
+ }
117817
+
117702
117818
  // src/daemon/infrastructure/agent-operational/ack-machine-operational-signals.ts
117703
- async function ackMachineOperationalSignals(sessionDeps, machineId, throughSignalKey) {
117819
+ async function ackMachineOperationalSignals(sessionDeps, machineId, chatroomId, throughSignalKey) {
117704
117820
  while (true) {
117705
- const result = await sessionDeps.backend.mutation(api.machines.ackMachineOperationalSignals, {
117821
+ const result = await sessionDeps.backend.mutation(api.machines.ackMachineOperationalSignals, buildAckMachineOperationalSignalsArgs({
117706
117822
  sessionId: sessionDeps.sessionId,
117707
117823
  machineId,
117824
+ chatroomId,
117708
117825
  throughSignalKey
117709
- });
117826
+ }));
117710
117827
  if (!result.hasMore)
117711
117828
  return;
117712
117829
  if (result.deletedCount === 0) {
@@ -117789,12 +117906,13 @@ function waitForOperationalSignalPage(options, afterSignalKey) {
117789
117906
  settle2(() => reject(error51));
117790
117907
  return;
117791
117908
  }
117792
- unsubscribe = options.client.onUpdate(api.machines.subscribeMachineOperationalSignalsSince, {
117909
+ unsubscribe = options.client.onUpdate(api.machines.subscribeMachineOperationalSignalsSince, buildSubscribeMachineOperationalSignalsSinceArgs({
117793
117910
  sessionId: options.sessionId,
117794
117911
  machineId: options.machineId,
117912
+ chatroomId: options.chatroomId,
117795
117913
  afterKey: afterSignalKey,
117796
117914
  limit: options.signalPageLimit ?? DEFAULT_SIGNAL_PAGE_LIMIT
117797
- }, (result) => {
117915
+ }), (result) => {
117798
117916
  if (!result || typeof result !== "object")
117799
117917
  return;
117800
117918
  const page = result;
@@ -117826,13 +117944,14 @@ async function fetchRowsForSignalPage(options, page) {
117826
117944
  let afterSignalKey = page.afterSignalKey;
117827
117945
  while (true) {
117828
117946
  throwIfAborted(options.signal);
117829
- const result = await options.client.query(api.machines.listOperationalStatusForMachineSignalRange, {
117947
+ const result = await options.client.query(api.machines.listOperationalStatusForMachineSignalRange, buildListOperationalStatusForMachineSignalRangeArgs({
117830
117948
  sessionId: options.sessionId,
117831
117949
  machineId: options.machineId,
117950
+ chatroomId: options.chatroomId,
117832
117951
  afterSignalKey,
117833
117952
  throughSignalKey: page.highSignalKey,
117834
117953
  limit: options.operationalPageLimit ?? DEFAULT_OPERATIONAL_PAGE_LIMIT
117835
- });
117954
+ }));
117836
117955
  rows.push(...result.rows);
117837
117956
  removed.push(...result.removed);
117838
117957
  if (!result.hasMore || !result.nextSignalKey)
@@ -117845,6 +117964,7 @@ async function runOperationalInbox(options, onUpdate) {
117845
117964
  for await (const page of createOperationalSignalIterator(options)) {
117846
117965
  const hydrated = await fetchRowsForSignalPage(options, page);
117847
117966
  await onUpdate({
117967
+ chatroomId: options.chatroomId,
117848
117968
  signals: page.items,
117849
117969
  rows: hydrated.rows,
117850
117970
  removed: hydrated.removed,
@@ -118152,6 +118272,10 @@ async function bootstrapMachineAssignedTaskSnapshots(deps) {
118152
118272
  });
118153
118273
  const tasks = await fetchMachineAssignedTaskSnapshots(deps.sessionDeps, deps.machineId);
118154
118274
  deps.taskSnapshotState?.replace(tasks);
118275
+ const chatroomIds = [...new Set(tasks.map((task) => task.chatroomId))];
118276
+ if (chatroomIds.length > 0) {
118277
+ await deps.onDiscoveredChatrooms?.(chatroomIds);
118278
+ }
118155
118279
  if (!tasks.length)
118156
118280
  return;
118157
118281
  await processTasksUpdate(deps.runtime, deps.effectContext, deps.cooldown, deps.agentMgr, deps.sessionDeps, deps.machineId, "bootstrap", { snapshots: enrichSnapshotsWithOperational(tasks) });
@@ -118159,6 +118283,9 @@ async function bootstrapMachineAssignedTaskSnapshots(deps) {
118159
118283
  function isAbortError2(error51) {
118160
118284
  return error51 instanceof Error && error51.name === "AbortError";
118161
118285
  }
118286
+ function operationalScopeKey(machineId, chatroomId) {
118287
+ return JSON.stringify([machineId, chatroomId]);
118288
+ }
118162
118289
  async function runInboxLoopWithRestart(options, onUpdate, isStopped) {
118163
118290
  let backoffMs = INBOX_RESTART_INITIAL_MS;
118164
118291
  while (!isStopped()) {
@@ -118183,7 +118310,7 @@ async function runOperationalInboxLoopWithRestart(options, onUpdate, isStopped)
118183
118310
  } catch (error51) {
118184
118311
  if (isStopped() || isAbortError2(error51))
118185
118312
  return;
118186
- console.warn(`[OperationalInbox] loop error, restarting in ${backoffMs}ms:`, error51);
118313
+ console.warn(`[OperationalInbox room=${options.chatroomId}] loop error, restarting in ${backoffMs}ms:`, error51);
118187
118314
  await new Promise((resolve8) => setTimeout(resolve8, backoffMs));
118188
118315
  backoffMs = Math.min(backoffMs * 2, INBOX_RESTART_MAX_MS);
118189
118316
  }
@@ -118208,23 +118335,19 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
118208
118335
  query: (fn2, args2) => session2.backend.query(fn2, args2)
118209
118336
  }
118210
118337
  };
118211
- console.log(`[${formatTimestamp()}] \uD83D\uDCEC Starting task-inbox (machine-scoped signals)`);
118338
+ console.log(`[${formatTimestamp()}] \uD83D\uDCEC Starting task-inbox (chatroom-scoped operational signals)`);
118212
118339
  const inboxStore = createInboxStateStore(resolveInboxDbPath(session2.machineId));
118213
118340
  const persisted = inboxStore.get({
118214
118341
  inboxType: "task",
118215
118342
  scopeKey: session2.machineId
118216
118343
  });
118217
- const persistedOperational = inboxStore.get({
118218
- inboxType: "operational",
118219
- scopeKey: session2.machineId
118220
- });
118221
118344
  const serviceStartedAt = Date.now();
118222
- const persistedOperationalKey = persistedOperational?.state.afterSignalKey;
118223
- const initialOperationalKey = persistedOperationalKey ?? operationalSignalCursorAt(serviceStartedAt);
118224
118345
  const abort = new AbortController;
118225
118346
  let stopped = false;
118226
118347
  const taskSnapshotState = new MachineTaskSnapshotState;
118227
118348
  const agentOperationalReadModel = new AgentOperationalReadModel;
118349
+ const knownRoomIds = new Set;
118350
+ const roomWatchers = new Map;
118228
118351
  registerNativeDeliverySession({
118229
118352
  runtime: runtime4,
118230
118353
  effectContext: effectContext2,
@@ -118236,7 +118359,7 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
118236
118359
  lifecycleOutbox
118237
118360
  });
118238
118361
  const cooldown = new RecoveryCooldown;
118239
- let inboxUpdateInFlight = false;
118362
+ let inboxUpdatesInFlight = 0;
118240
118363
  let reconcileInFlight = false;
118241
118364
  const inboxOptions = {
118242
118365
  client: wsClient2,
@@ -118246,41 +118369,95 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
118246
118369
  initialAfterSignalKey: persisted?.state.afterSignalKey,
118247
118370
  signal: abort.signal
118248
118371
  };
118249
- const inboxHandler = async (update6) => {
118250
- inboxUpdateInFlight = true;
118251
- try {
118252
- await handleTaskInboxUpdate(update6, {
118253
- runtime: runtime4,
118254
- effectContext: effectContext2,
118255
- cooldown,
118256
- agentMgr,
118257
- sessionDeps,
118258
- machineId: session2.machineId,
118259
- taskSnapshotState
118260
- });
118261
- inboxStore.save({ inboxType: "task", scopeKey: session2.machineId }, { afterSignalKey: update6.throughSignalKey });
118262
- } finally {
118263
- inboxUpdateInFlight = false;
118264
- }
118265
- };
118266
118372
  const bootstrapSucceeded = yield* exports_Effect.tryPromise(async () => {
118267
118373
  const rows = await fetchMachineAgentOperationalStatus(sessionDeps, session2.machineId);
118268
118374
  agentOperationalReadModel.replace(rows);
118375
+ for (const row of rows)
118376
+ knownRoomIds.add(row.chatroomId);
118269
118377
  return true;
118270
118378
  }).pipe(exports_Effect.catchAll((error51) => {
118271
118379
  console.warn("[OperationalInbox] bootstrap failed:", error51);
118272
118380
  return exports_Effect.succeed(false);
118273
118381
  }));
118274
- if (persistedOperationalKey) {
118275
- ackMachineOperationalSignals(sessionDeps, session2.machineId, persistedOperationalKey).catch((error51) => console.warn("[OperationalInbox] startup signal cleanup failed:", error51));
118276
- } else if (bootstrapSucceeded) {
118382
+ const operationalHandler = async (update6) => {
118383
+ const chatroomId = update6.chatroomId;
118384
+ inboxUpdatesInFlight += 1;
118277
118385
  try {
118278
- inboxStore.save({ inboxType: "operational", scopeKey: session2.machineId }, { afterSignalKey: initialOperationalKey });
118279
- ackMachineOperationalSignals(sessionDeps, session2.machineId, initialOperationalKey).catch((error51) => console.warn("[OperationalInbox] startup signal cleanup failed:", error51));
118280
- } catch (error51) {
118281
- console.warn("[OperationalInbox] failed to persist bootstrap baseline:", error51);
118386
+ const changed = agentOperationalReadModel.applySignalPage(update6.rows, update6.removed);
118387
+ const snapshots = changed.flatMap(({ chatroomId: roomId, role }) => taskSnapshotState.listForRole(roomId, role));
118388
+ if (snapshots.length > 0) {
118389
+ await processTasksUpdate(runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "operational-status", { snapshots: enrichSnapshotsWithOperational(snapshots) });
118390
+ }
118391
+ inboxStore.save({
118392
+ inboxType: "operational",
118393
+ scopeKey: operationalScopeKey(session2.machineId, chatroomId)
118394
+ }, { afterSignalKey: update6.throughSignalKey });
118395
+ try {
118396
+ await ackMachineOperationalSignals(sessionDeps, session2.machineId, chatroomId, update6.throughSignalKey);
118397
+ } catch (error51) {
118398
+ console.warn(`[OperationalInbox room=${chatroomId}] signal cleanup failed:`, error51);
118399
+ }
118400
+ } finally {
118401
+ inboxUpdatesInFlight -= 1;
118282
118402
  }
118283
- }
118403
+ };
118404
+ const ensureOperationalInbox = (chatroomId) => {
118405
+ const existing = roomWatchers.get(chatroomId);
118406
+ if (existing)
118407
+ return existing.startPromise;
118408
+ const controller = new AbortController;
118409
+ const entry = {
118410
+ controller,
118411
+ startPromise: Promise.resolve()
118412
+ };
118413
+ roomWatchers.set(chatroomId, entry);
118414
+ entry.startPromise = (async () => {
118415
+ if (!knownRoomIds.has(chatroomId)) {
118416
+ try {
118417
+ const current = await fetchMachineAgentOperationalStatus(sessionDeps, session2.machineId);
118418
+ agentOperationalReadModel.replace(current);
118419
+ for (const row of current)
118420
+ knownRoomIds.add(row.chatroomId);
118421
+ } catch (error51) {
118422
+ console.warn(`[OperationalInbox room=${chatroomId}] operational hydration failed:`, error51);
118423
+ }
118424
+ }
118425
+ const roomKey = {
118426
+ inboxType: "operational",
118427
+ scopeKey: operationalScopeKey(session2.machineId, chatroomId)
118428
+ };
118429
+ const persistedRoom = inboxStore.get(roomKey);
118430
+ let initialCursor;
118431
+ if (persistedRoom) {
118432
+ initialCursor = persistedRoom.state.afterSignalKey;
118433
+ ackMachineOperationalSignals(sessionDeps, session2.machineId, chatroomId, initialCursor).catch((error51) => console.warn(`[OperationalInbox room=${chatroomId}] startup signal cleanup failed:`, error51));
118434
+ } else if (bootstrapSucceeded) {
118435
+ initialCursor = operationalSignalCursorAt(serviceStartedAt);
118436
+ try {
118437
+ inboxStore.save(roomKey, { afterSignalKey: initialCursor });
118438
+ ackMachineOperationalSignals(sessionDeps, session2.machineId, chatroomId, initialCursor).catch((error51) => console.warn(`[OperationalInbox room=${chatroomId}] startup signal cleanup failed:`, error51));
118439
+ } catch (error51) {
118440
+ console.warn(`[OperationalInbox room=${chatroomId}] failed to persist bootstrap baseline:`, error51);
118441
+ }
118442
+ } else {
118443
+ initialCursor = operationalSignalCursorAt(serviceStartedAt);
118444
+ }
118445
+ runOperationalInboxLoopWithRestart({
118446
+ client: wsClient2,
118447
+ sessionId: session2.sessionId,
118448
+ machineId: session2.machineId,
118449
+ chatroomId,
118450
+ serviceStartedAt,
118451
+ initialAfterSignalKey: initialCursor,
118452
+ signal: controller.signal
118453
+ }, operationalHandler, () => stopped);
118454
+ })();
118455
+ return entry.startPromise;
118456
+ };
118457
+ yield* exports_Effect.tryPromise(() => Promise.all([...knownRoomIds].map((chatroomId) => ensureOperationalInbox(chatroomId)))).pipe(exports_Effect.catchAll((error51) => {
118458
+ console.warn("[OperationalInbox] initial watcher start failed:", error51);
118459
+ return exports_Effect.void;
118460
+ }));
118284
118461
  yield* exports_Effect.tryPromise(() => bootstrapMachineAssignedTaskSnapshots({
118285
118462
  sessionDeps,
118286
118463
  runtime: runtime4,
@@ -118288,39 +118465,42 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
118288
118465
  cooldown,
118289
118466
  agentMgr,
118290
118467
  machineId: session2.machineId,
118291
- taskSnapshotState
118468
+ taskSnapshotState,
118469
+ onDiscoveredChatrooms: async (chatroomIds) => {
118470
+ await Promise.all(chatroomIds.map((chatroomId) => ensureOperationalInbox(chatroomId)));
118471
+ }
118292
118472
  })).pipe(exports_Effect.catchAll((error51) => {
118293
118473
  console.warn("[TaskInbox] bootstrap failed:", error51);
118294
118474
  return exports_Effect.void;
118295
118475
  }));
118296
- const operationalInboxOptions = {
118297
- client: wsClient2,
118298
- sessionId: session2.sessionId,
118299
- machineId: session2.machineId,
118300
- serviceStartedAt,
118301
- initialAfterSignalKey: initialOperationalKey,
118302
- signal: abort.signal
118303
- };
118304
- const operationalInboxHandler = async (update6) => {
118305
- inboxUpdateInFlight = true;
118476
+ const inboxHandler = async (update6) => {
118477
+ inboxUpdatesInFlight += 1;
118306
118478
  try {
118307
- const changed = agentOperationalReadModel.applySignalPage(update6.rows, update6.removed);
118308
- const snapshots = changed.flatMap(({ chatroomId, role }) => taskSnapshotState.listForRole(chatroomId, role));
118309
- if (snapshots.length > 0) {
118310
- await processTasksUpdate(runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "operational-status", { snapshots: enrichSnapshotsWithOperational(snapshots) });
118311
- }
118312
- inboxStore.save({ inboxType: "operational", scopeKey: session2.machineId }, { afterSignalKey: update6.throughSignalKey });
118313
- try {
118314
- await ackMachineOperationalSignals(sessionDeps, session2.machineId, update6.throughSignalKey);
118315
- } catch (error51) {
118316
- console.warn("[OperationalInbox] signal cleanup failed:", error51);
118479
+ const chatroomIds = [
118480
+ ...new Set([
118481
+ ...update6.snapshots.map((snapshot) => snapshot.chatroomId),
118482
+ ...update6.signals.map((signal) => signal.chatroomId)
118483
+ ])
118484
+ ];
118485
+ if (chatroomIds.length > 0) {
118486
+ await Promise.all(chatroomIds.map((chatroomId) => ensureOperationalInbox(chatroomId)));
118317
118487
  }
118488
+ await handleTaskInboxUpdate(update6, {
118489
+ runtime: runtime4,
118490
+ effectContext: effectContext2,
118491
+ cooldown,
118492
+ agentMgr,
118493
+ sessionDeps,
118494
+ machineId: session2.machineId,
118495
+ taskSnapshotState
118496
+ });
118497
+ inboxStore.save({ inboxType: "task", scopeKey: session2.machineId }, { afterSignalKey: update6.throughSignalKey });
118318
118498
  } finally {
118319
- inboxUpdateInFlight = false;
118499
+ inboxUpdatesInFlight -= 1;
118320
118500
  }
118321
118501
  };
118322
118502
  const reconcileTimer = setInterval(() => {
118323
- if (stopped || inboxUpdateInFlight || reconcileInFlight)
118503
+ if (stopped || inboxUpdatesInFlight > 0 || reconcileInFlight)
118324
118504
  return;
118325
118505
  reconcileInFlight = true;
118326
118506
  processTasksUpdate(runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "periodic-reconcile", { snapshots: enrichSnapshotsWithOperational(taskSnapshotState.listAll()) }).catch((error51) => {
@@ -118330,11 +118510,13 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
118330
118510
  });
118331
118511
  }, NATIVE_DELIVERY_RECONCILE_MS);
118332
118512
  runInboxLoopWithRestart(inboxOptions, inboxHandler, () => stopped);
118333
- runOperationalInboxLoopWithRestart(operationalInboxOptions, operationalInboxHandler, () => stopped);
118334
118513
  return {
118335
118514
  stop() {
118336
118515
  stopped = true;
118337
118516
  abort.abort();
118517
+ for (const watcher of roomWatchers.values()) {
118518
+ watcher.controller.abort();
118519
+ }
118338
118520
  clearInterval(reconcileTimer);
118339
118521
  unregisterNativeDeliverySession();
118340
118522
  inboxStore.close();
@@ -135552,4 +135734,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
135552
135734
  });
135553
135735
  program2.parse();
135554
135736
 
135555
- //# debugId=D6F1DCA6040634C164756E2164756E21
135737
+ //# debugId=962BD51641BEFD4F64756E2164756E21