chatroom-cli 1.111.0 → 1.113.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
@@ -28823,7 +28823,7 @@ function normalizeAgentLifecycleFact(raw) {
28823
28823
  emittedAt: Number(rest.emittedAt)
28824
28824
  };
28825
28825
  }
28826
- if (kind === "spawned" || kind === "exited" || kind === "activity") {
28826
+ if (kind === "spawned" || kind === "exited" || kind === "activity" || kind === "turn_failed") {
28827
28827
  return rest;
28828
28828
  }
28829
28829
  throw new Error(`Unknown agent lifecycle fact kind: ${String(kind)}`);
@@ -30154,11 +30154,10 @@ class AgentProcessManager {
30154
30154
  wantResume: slot?.wantResume
30155
30155
  });
30156
30156
  const completionStatus = opts.completion?.status ?? "completed";
30157
- console.log(`[AgentProcessManager] lifecycle.turn.${completionStatus === "completed" ? "completed" : "terminal"}: role=${opts.role} pid=${opts.pid} harness=${opts.harness} status=${completionStatus}${opts.completion ? ` source=${opts.completion.source}` : ""}`);
30157
+ console.log(`[AgentProcessManager] lifecycle.turn.${completionStatus === "completed" ? "completed" : "failed"}: role=${opts.role} pid=${opts.pid} harness=${opts.harness} status=${completionStatus} completion=${JSON.stringify(opts.completion ?? { status: "completed" })}`);
30158
30158
  if (capabilities.supportsNativeIntegration) {
30159
- if (completionStatus !== "completed") {
30159
+ if (completionStatus === "process_exited") {
30160
30160
  setNativeTurnPhase(slot, defaultNativeTurnPhase());
30161
- console.warn(`[AgentProcessManager] Native turn did not complete successfully for ${opts.role}: ${completionStatus}`);
30162
30161
  return;
30163
30162
  }
30164
30163
  this.maybeEmitProviderUnavailable(opts.chatroomId, opts.role, slot);
@@ -30168,11 +30167,25 @@ class AgentProcessManager {
30168
30167
  pid: opts.pid,
30169
30168
  harness: opts.harness,
30170
30169
  slot,
30171
- eventId: `${opts.pid}:${++this.agentTurnEndedSequence}`
30170
+ eventId: `${opts.pid}:${++this.agentTurnEndedSequence}`,
30171
+ completion: opts.completion ?? {
30172
+ turnId: `${opts.pid}:${this.agentTurnEndedSequence}`,
30173
+ status: "completed",
30174
+ source: "agent-process-manager.agent-end"
30175
+ }
30172
30176
  };
30173
- await Promise.all([...this.agentTurnEndedHandlers].map((handler) => handler(event)));
30177
+ const dispositions = await Promise.all([...this.agentTurnEndedHandlers].map((handler) => handler(event)));
30178
+ const held = dispositions.find((disposition) => disposition?.kind === "hold-slot");
30179
+ if (held?.kind === "hold-slot") {
30180
+ console.warn(`[AgentProcessManager] Native turn slot held after ${completionStatus}: role=${opts.role} pid=${opts.pid} reason=${held.reason}`);
30181
+ return;
30182
+ }
30183
+ if (completionStatus !== "completed" && !dispositions.some((disposition) => disposition?.kind === "release-slot")) {
30184
+ console.warn(`[AgentProcessManager] Native turn slot held: no task-service disposition returned role=${opts.role} pid=${opts.pid} status=${completionStatus}`);
30185
+ return;
30186
+ }
30174
30187
  setNativeTurnPhase(slot, defaultNativeTurnPhase());
30175
- console.log(`[AgentProcessManager] ✅ Native agent_end completed for ${opts.role}`);
30188
+ console.log(`[AgentProcessManager] Native agent_end disposition accepted: role=${opts.role} status=${completionStatus} disposition=release-slot`);
30176
30189
  return;
30177
30190
  }
30178
30191
  const result = await handleTurnCompleted({
@@ -31875,7 +31888,7 @@ function decideNextDelivery(tasks, context5) {
31875
31888
  return { kind: "wait", taskId: task.taskId, reason: "slot_stopping" };
31876
31889
  }
31877
31890
  const coldSession = context5.snapshotRequestsNativeColdSession(task);
31878
- const startAllowed = blockReason.startsWith("slot_missing") || blockReason.startsWith("slot_not_running");
31891
+ const startAllowed = blockReason.startsWith("slot_missing") || blockReason.startsWith("slot_not_running") || blockReason.startsWith("spawned_pid_missing");
31879
31892
  if (startAllowed && !coldSession && task.status === "pending" && isSlotIdle(context5.slot?.state ?? "idle") && task.agentConfig.workingDir) {
31880
31893
  return { kind: "start-agent", taskId: task.taskId };
31881
31894
  }
@@ -32255,7 +32268,41 @@ class NativeDeliveryService {
32255
32268
  });
32256
32269
  }
32257
32270
  async handleAgentTurnEnded(event) {
32271
+ const completion = event.completion;
32272
+ if (completion && completion.status !== "completed") {
32273
+ const activeTask = this.deps.agentTaskState.get({
32274
+ chatroomId: event.chatroomId,
32275
+ role: event.role
32276
+ });
32277
+ const errorDetail = completion.error;
32278
+ console.error(`[NativeDelivery:turn-failed] chatroom=${event.chatroomId} role=${event.role} task=${activeTask?.taskId ?? "none"} turn=${completion.turnId} status=${completion.status} source=${completion.source} error=${errorDetail ?? "none"}`);
32279
+ const fact = {
32280
+ kind: "turn_failed",
32281
+ chatroomId: event.chatroomId,
32282
+ role: event.role,
32283
+ ...activeTask?.taskId ? { taskId: activeTask.taskId } : {},
32284
+ ...event.slot.harnessSessionId ? { harnessSessionId: event.slot.harnessSessionId } : {},
32285
+ turnId: completion.turnId,
32286
+ status: completion.status,
32287
+ source: completion.source,
32288
+ ...errorDetail ? { error: errorDetail } : {},
32289
+ revisionKey: buildAgentLifecycleRevisionKey("turn_failed", {
32290
+ chatroomId: event.chatroomId,
32291
+ role: event.role,
32292
+ turnId: completion.turnId
32293
+ }),
32294
+ emittedAt: Date.now()
32295
+ };
32296
+ try {
32297
+ await this.deps.lifecycleOutbox.enqueue(fact);
32298
+ } catch (error) {
32299
+ console.error(`[NativeDelivery:turn-failed-outbox-error] chatroom=${event.chatroomId} role=${event.role} turn=${completion.turnId} error=${error instanceof Error ? error.stack ?? error.message : String(error)}`);
32300
+ return { kind: "hold-slot", reason: "turn-failed-outbox-enqueue-failed" };
32301
+ }
32302
+ return { kind: "release-slot" };
32303
+ }
32258
32304
  this.scheduleRoleDelivery(event.chatroomId, event.role);
32305
+ return { kind: "release-slot" };
32259
32306
  }
32260
32307
  scheduleRoleDelivery(chatroomId, role) {
32261
32308
  setTimeout(() => {
@@ -47341,7 +47388,7 @@ class MachineTaskSnapshotState {
47341
47388
  function asChatroomId(chatroomId) {
47342
47389
  return chatroomId;
47343
47390
  }
47344
- function buildSubscribeTaskStatusSignalsSinceArgs(input) {
47391
+ function buildSubscribeTaskDeliverySignalsSinceArgs(input) {
47345
47392
  return {
47346
47393
  sessionId: input.sessionId,
47347
47394
  machineId: input.machineId,
@@ -47350,7 +47397,7 @@ function buildSubscribeTaskStatusSignalsSinceArgs(input) {
47350
47397
  ...input.limit === undefined ? {} : { limit: input.limit }
47351
47398
  };
47352
47399
  }
47353
- function buildListTasksForMachineSignalRangeArgs(input) {
47400
+ function buildListTasksForMachineTaskDeliverySignalRangeArgs(input) {
47354
47401
  return {
47355
47402
  sessionId: input.sessionId,
47356
47403
  machineId: input.machineId,
@@ -47400,7 +47447,7 @@ function waitForTaskSignalPage(options, afterSignalKey) {
47400
47447
  settle(() => reject(error51));
47401
47448
  return;
47402
47449
  }
47403
- unsubscribe = options.client.onUpdate(api.messageList.subscribeTaskStatusSignalsSince, buildSubscribeTaskStatusSignalsSinceArgs({
47450
+ unsubscribe = options.client.onUpdate(api.taskDelivery.subscribeTaskDeliverySignalsSince, buildSubscribeTaskDeliverySignalsSinceArgs({
47404
47451
  sessionId: options.sessionId,
47405
47452
  machineId: options.machineId,
47406
47453
  chatroomId: options.chatroomId,
@@ -47437,7 +47484,7 @@ async function fetchSnapshotsForSignalPage(options, page) {
47437
47484
  let afterSignalKey = page.afterSignalKey;
47438
47485
  while (true) {
47439
47486
  throwIfAborted(options.signal);
47440
- const result = await options.client.query(api.tasks.listTasksForMachineSignalRange, buildListTasksForMachineSignalRangeArgs({
47487
+ const result = await options.client.query(api.taskDelivery.listTasksForMachineTaskDeliverySignalRange, buildListTasksForMachineTaskDeliverySignalRangeArgs({
47441
47488
  sessionId: options.sessionId,
47442
47489
  machineId: options.machineId,
47443
47490
  chatroomId: options.chatroomId,
@@ -104587,7 +104634,7 @@ function toConvexLifecycleFact(fact) {
104587
104634
  return {
104588
104635
  ...normalized,
104589
104636
  chatroomId: normalized.chatroomId,
104590
- ...normalized.kind === "activity" && normalized.taskId ? { taskId: normalized.taskId } : {}
104637
+ ...(normalized.kind === "activity" || normalized.kind === "turn_failed") && normalized.taskId ? { taskId: normalized.taskId } : {}
104591
104638
  };
104592
104639
  }
104593
104640
  function createAgentLifecycleSend(session2) {
@@ -118005,56 +118052,112 @@ async function refreshTaskInboxRoomMembership() {
118005
118052
  }
118006
118053
  var refreshRoomMembership = null;
118007
118054
 
118008
- // src/daemon/infrastructure/agent-operational/operational-signal-contract.ts
118009
- function asChatroomId2(chatroomId) {
118010
- return chatroomId;
118055
+ // src/daemon/infrastructure/agent-operational/operational-signal-feeds.ts
118056
+ function chatroomId(value) {
118057
+ return value;
118011
118058
  }
118012
- function buildSubscribeMachineOperationalSignalsSinceArgs(input) {
118059
+ function signalPage(result) {
118060
+ if (!result || typeof result !== "object")
118061
+ return null;
118062
+ const page = result;
118063
+ if (!page.items?.length || !page.highKey)
118064
+ return null;
118065
+ return {
118066
+ items: page.items,
118067
+ afterSignalKey: "",
118068
+ highSignalKey: page.highKey
118069
+ };
118070
+ }
118071
+ function createFeed(input) {
118072
+ return input;
118073
+ }
118074
+ function subscribeArgs(input) {
118013
118075
  return {
118014
118076
  sessionId: input.sessionId,
118015
118077
  machineId: input.machineId,
118016
- chatroomId: asChatroomId2(input.chatroomId),
118078
+ chatroomId: chatroomId(input.chatroomId),
118017
118079
  afterKey: input.afterKey,
118018
- ...input.limit === undefined ? {} : { limit: input.limit }
118080
+ limit: input.limit
118019
118081
  };
118020
118082
  }
118021
- function buildListOperationalStatusForMachineSignalRangeArgs(input) {
118083
+ function rangeArgs(input) {
118022
118084
  return {
118023
118085
  sessionId: input.sessionId,
118024
118086
  machineId: input.machineId,
118025
- chatroomId: asChatroomId2(input.chatroomId),
118087
+ chatroomId: chatroomId(input.chatroomId),
118026
118088
  afterSignalKey: input.afterSignalKey,
118027
118089
  throughSignalKey: input.throughSignalKey,
118028
- ...input.limit === undefined ? {} : { limit: input.limit }
118090
+ limit: input.limit
118029
118091
  };
118030
118092
  }
118031
- function buildAckMachineOperationalSignalsArgs(input) {
118093
+ function ackArgs(input) {
118032
118094
  return {
118033
118095
  sessionId: input.sessionId,
118034
118096
  machineId: input.machineId,
118035
- chatroomId: asChatroomId2(input.chatroomId),
118097
+ chatroomId: chatroomId(input.chatroomId),
118036
118098
  throughSignalKey: input.throughSignalKey
118037
118099
  };
118038
118100
  }
118101
+ var createMachineFeed = (config4) => createFeed({
118102
+ kind: config4.kind,
118103
+ subscribe: (client4, input, onResult, onError3) => client4.onUpdate(config4.subscribe, subscribeArgs(input), (result) => {
118104
+ const page = signalPage(result);
118105
+ onResult(page ? { ...page, afterSignalKey: input.afterKey } : result);
118106
+ }, onError3),
118107
+ hydrate: async (client4, input) => await client4.query(config4.hydrate, rangeArgs(input)),
118108
+ acknowledge: async (sessionDeps, input) => await sessionDeps.backend.mutation(config4.acknowledge, ackArgs({
118109
+ ...input,
118110
+ sessionId: sessionDeps.sessionId
118111
+ }))
118112
+ }), operationalSignalFeeds;
118113
+ var init_operational_signal_feeds = __esm(() => {
118114
+ init_api3();
118115
+ operationalSignalFeeds = {
118116
+ "agent-operational": createMachineFeed({
118117
+ kind: "agent-operational",
118118
+ subscribe: api.machines.subscribeMachineAgentOperationalSignalsSince,
118119
+ hydrate: api.machines.listMachineAgentOperationalStatusForSignalRange,
118120
+ acknowledge: api.machines.ackMachineAgentOperationalSignals
118121
+ }),
118122
+ connectivity: createMachineFeed({
118123
+ kind: "connectivity",
118124
+ subscribe: api.machines.subscribeMachineConnectivitySignalsSince,
118125
+ hydrate: api.machines.listMachineConnectivityStatusForSignalRange,
118126
+ acknowledge: api.machines.ackMachineConnectivitySignals
118127
+ }),
118128
+ "agent-stop": createMachineFeed({
118129
+ kind: "agent-stop",
118130
+ subscribe: api.machines.subscribeMachineAgentStopSignalsSince,
118131
+ hydrate: api.machines.listMachineAgentStopStatusForSignalRange,
118132
+ acknowledge: api.machines.ackMachineAgentStopSignals
118133
+ }),
118134
+ "agent-removal": createMachineFeed({
118135
+ kind: "agent-removal",
118136
+ subscribe: api.machines.subscribeMachineAgentRemovalSignalsSince,
118137
+ hydrate: api.machines.listMachineAgentRemovalStatusForSignalRange,
118138
+ acknowledge: api.machines.ackMachineAgentRemovalSignals
118139
+ })
118140
+ };
118141
+ });
118039
118142
 
118040
118143
  // src/daemon/infrastructure/agent-operational/ack-machine-operational-signals.ts
118041
- async function ackMachineOperationalSignals(sessionDeps, machineId, chatroomId, throughSignalKey) {
118144
+ async function ackMachineSignal(sessionDeps, machineId, chatroomId2, throughSignalKey, kind) {
118145
+ const feed = operationalSignalFeeds[kind];
118042
118146
  while (true) {
118043
- const result = await sessionDeps.backend.mutation(api.machines.ackMachineOperationalSignals, buildAckMachineOperationalSignalsArgs({
118044
- sessionId: sessionDeps.sessionId,
118147
+ const result = await feed.acknowledge(sessionDeps, {
118045
118148
  machineId,
118046
- chatroomId,
118149
+ chatroomId: chatroomId2,
118047
118150
  throughSignalKey
118048
- }));
118151
+ });
118049
118152
  if (!result.hasMore)
118050
118153
  return;
118051
118154
  if (result.deletedCount === 0) {
118052
- throw new Error("Operational signal ack reported more work without progress");
118155
+ throw new Error(`${kind} signal ack reported more work without progress`);
118053
118156
  }
118054
118157
  }
118055
118158
  }
118056
118159
  var init_ack_machine_operational_signals = __esm(() => {
118057
- init_api3();
118160
+ init_operational_signal_feeds();
118058
118161
  });
118059
118162
 
118060
118163
  // src/daemon/infrastructure/agent-operational/agent-operational-read-model.ts
@@ -118097,11 +118200,11 @@ class AgentOperationalReadModel {
118097
118200
  }
118098
118201
  return changed;
118099
118202
  }
118100
- get(chatroomId, role) {
118101
- return this.rows.get(roleKey3(chatroomId, role));
118203
+ get(chatroomId2, role) {
118204
+ return this.rows.get(roleKey3(chatroomId2, role));
118102
118205
  }
118103
118206
  }
118104
- var roleKey3 = (chatroomId, role) => `${chatroomId}:${role.toLowerCase()}`;
118207
+ var roleKey3 = (chatroomId2, role) => `${chatroomId2}:${role.toLowerCase()}`;
118105
118208
 
118106
118209
  // src/daemon/infrastructure/agent-operational/fetch-machine-agent-operational-status.ts
118107
118210
  async function fetchMachineAgentOperationalStatus(sessionDeps, machineId) {
@@ -118128,6 +118231,9 @@ function throwIfAborted2(signal) {
118128
118231
  if (signal?.aborted)
118129
118232
  throw abortError2();
118130
118233
  }
118234
+ function feedFor(options) {
118235
+ return options.feed ?? operationalSignalFeeds["agent-operational"];
118236
+ }
118131
118237
  function waitForOperationalSignalPage(options, afterSignalKey) {
118132
118238
  return new Promise((resolve8, reject) => {
118133
118239
  let unsubscribe;
@@ -118154,25 +118260,17 @@ function waitForOperationalSignalPage(options, afterSignalKey) {
118154
118260
  settle2(() => reject(error51));
118155
118261
  return;
118156
118262
  }
118157
- unsubscribe = options.client.onUpdate(api.machines.subscribeMachineOperationalSignalsSince, buildSubscribeMachineOperationalSignalsSinceArgs({
118263
+ unsubscribe = feedFor(options).subscribe(options.client, {
118158
118264
  sessionId: options.sessionId,
118159
118265
  machineId: options.machineId,
118160
118266
  chatroomId: options.chatroomId,
118161
118267
  afterKey: afterSignalKey,
118162
118268
  limit: options.signalPageLimit ?? DEFAULT_SIGNAL_PAGE_LIMIT2
118163
- }), (result) => {
118164
- if (!result || typeof result !== "object")
118165
- return;
118269
+ }, (result) => {
118166
118270
  const page = result;
118167
- const items = page.items;
118168
- const highKey = page.highKey;
118169
- if (!items?.length || !highKey)
118271
+ if (!page)
118170
118272
  return;
118171
- settle2(() => resolve8({
118172
- items,
118173
- afterSignalKey,
118174
- highSignalKey: highKey
118175
- }));
118273
+ settle2(() => resolve8(page));
118176
118274
  }, (error51) => {
118177
118275
  settle2(() => reject(error51));
118178
118276
  });
@@ -118192,14 +118290,14 @@ async function fetchRowsForSignalPage(options, page) {
118192
118290
  let afterSignalKey = page.afterSignalKey;
118193
118291
  while (true) {
118194
118292
  throwIfAborted2(options.signal);
118195
- const result = await options.client.query(api.machines.listOperationalStatusForMachineSignalRange, buildListOperationalStatusForMachineSignalRangeArgs({
118293
+ const result = await feedFor(options).hydrate(options.client, {
118196
118294
  sessionId: options.sessionId,
118197
118295
  machineId: options.machineId,
118198
118296
  chatroomId: options.chatroomId,
118199
118297
  afterSignalKey,
118200
118298
  throughSignalKey: page.highSignalKey,
118201
118299
  limit: options.operationalPageLimit ?? DEFAULT_OPERATIONAL_PAGE_LIMIT
118202
- }));
118300
+ });
118203
118301
  rows.push(...result.rows);
118204
118302
  removed.push(...result.removed);
118205
118303
  if (!result.hasMore || !result.nextSignalKey)
@@ -118223,15 +118321,15 @@ async function runOperationalInbox(options, onUpdate) {
118223
118321
  }
118224
118322
  var DEFAULT_SIGNAL_PAGE_LIMIT2 = 100, DEFAULT_OPERATIONAL_PAGE_LIMIT = 500;
118225
118323
  var init_operational_inbox = __esm(() => {
118226
- init_api3();
118324
+ init_operational_signal_feeds();
118227
118325
  });
118228
118326
 
118229
118327
  // src/daemon/entry/task-inbox-runtime.ts
118230
118328
  function isAbortError2(error51) {
118231
118329
  return error51 instanceof Error && error51.name === "AbortError";
118232
118330
  }
118233
- function roomScopeKey(machineId, chatroomId) {
118234
- return JSON.stringify([machineId, chatroomId]);
118331
+ function roomScopeKey(machineId, chatroomId2) {
118332
+ return JSON.stringify([machineId, chatroomId2]);
118235
118333
  }
118236
118334
  async function runOperationalInboxLoopWithRestart(options, onUpdate, isStopped) {
118237
118335
  let backoffMs = INBOX_RESTART_INITIAL_MS;
@@ -118302,8 +118400,8 @@ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInbo
118302
118400
  console.warn("[OperationalInbox] bootstrap failed:", error51);
118303
118401
  return exports_Effect.succeed(false);
118304
118402
  }));
118305
- const operationalHandler = async (update6) => {
118306
- const chatroomId = update6.chatroomId;
118403
+ const operationalHandler = async (kind, update6) => {
118404
+ const chatroomId2 = update6.chatroomId;
118307
118405
  const changed = agentOperationalReadModel.applySignalPage(update6.rows, update6.removed);
118308
118406
  await Promise.all(changed.map(({ chatroomId: roomId, role }) => nativeDelivery.requestReconcile({
118309
118407
  chatroomId: roomId,
@@ -118311,17 +118409,17 @@ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInbo
118311
118409
  source: "operational-signal"
118312
118410
  })));
118313
118411
  inboxStore.save({
118314
- inboxType: "operational",
118315
- scopeKey: roomScopeKey(session2.machineId, chatroomId)
118412
+ inboxType: `operational:${kind}`,
118413
+ scopeKey: roomScopeKey(session2.machineId, chatroomId2)
118316
118414
  }, { afterSignalKey: update6.throughSignalKey });
118317
118415
  try {
118318
- await ackMachineOperationalSignals(sessionDeps, session2.machineId, chatroomId, update6.throughSignalKey);
118416
+ await ackMachineSignal(sessionDeps, session2.machineId, chatroomId2, update6.throughSignalKey, kind);
118319
118417
  } catch (error51) {
118320
- console.warn(`[OperationalInbox room=${chatroomId}] signal cleanup failed:`, error51);
118418
+ console.warn(`[OperationalInbox kind=${kind} room=${chatroomId2}] signal cleanup failed:`, error51);
118321
118419
  }
118322
118420
  };
118323
- const ensureRoomInboxes = (chatroomId) => {
118324
- const existing = roomWatchers.get(chatroomId);
118421
+ const ensureRoomInboxes = (chatroomId2) => {
118422
+ const existing = roomWatchers.get(chatroomId2);
118325
118423
  if (existing)
118326
118424
  return existing.startPromise;
118327
118425
  const controller = new AbortController;
@@ -118329,48 +118427,48 @@ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInbo
118329
118427
  controller,
118330
118428
  startPromise: Promise.resolve()
118331
118429
  };
118332
- roomWatchers.set(chatroomId, entry);
118430
+ roomWatchers.set(chatroomId2, entry);
118333
118431
  entry.startPromise = (async () => {
118334
- if (!knownRoomIds.has(chatroomId)) {
118432
+ if (!knownRoomIds.has(chatroomId2)) {
118335
118433
  try {
118336
118434
  const current = await fetchMachineAgentOperationalStatus(sessionDeps, session2.machineId);
118337
118435
  agentOperationalReadModel.replace(current);
118338
118436
  for (const row of current)
118339
118437
  knownRoomIds.add(row.chatroomId);
118340
118438
  } catch (error51) {
118341
- console.warn(`[OperationalInbox room=${chatroomId}] operational hydration failed:`, error51);
118439
+ console.warn(`[OperationalInbox room=${chatroomId2}] operational hydration failed:`, error51);
118342
118440
  }
118343
118441
  }
118344
- const operationalRoomKey = {
118345
- inboxType: "operational",
118346
- scopeKey: roomScopeKey(session2.machineId, chatroomId)
118347
- };
118348
- const persistedOperationalRoom = inboxStore.get(operationalRoomKey);
118349
- let operationalCursor;
118350
- if (persistedOperationalRoom) {
118351
- operationalCursor = persistedOperationalRoom.state.afterSignalKey;
118352
- ackMachineOperationalSignals(sessionDeps, session2.machineId, chatroomId, operationalCursor).catch((error51) => console.warn(`[OperationalInbox room=${chatroomId}] startup signal cleanup failed:`, error51));
118353
- } else if (bootstrapSucceeded) {
118354
- operationalCursor = operationalSignalCursorAt(serviceStartedAt);
118355
- try {
118356
- inboxStore.save(operationalRoomKey, { afterSignalKey: operationalCursor });
118357
- ackMachineOperationalSignals(sessionDeps, session2.machineId, chatroomId, operationalCursor).catch((error51) => console.warn(`[OperationalInbox room=${chatroomId}] startup signal cleanup failed:`, error51));
118358
- } catch (error51) {
118359
- console.warn(`[OperationalInbox room=${chatroomId}] failed to persist bootstrap baseline:`, error51);
118442
+ await Promise.all(["agent-operational", "connectivity", "agent-stop", "agent-removal"].map(async (kind) => {
118443
+ const operationalRoomKey = {
118444
+ inboxType: `operational:${kind}`,
118445
+ scopeKey: roomScopeKey(session2.machineId, chatroomId2)
118446
+ };
118447
+ const persistedRoom = inboxStore.get(operationalRoomKey);
118448
+ let cursor = persistedRoom?.state.afterSignalKey;
118449
+ if (!cursor) {
118450
+ cursor = operationalSignalCursorAt(serviceStartedAt);
118451
+ try {
118452
+ inboxStore.save(operationalRoomKey, { afterSignalKey: cursor });
118453
+ } catch (error51) {
118454
+ console.warn(`[OperationalInbox kind=${kind} room=${chatroomId2}] failed to persist bootstrap baseline:`, error51);
118455
+ }
118360
118456
  }
118361
- } else {
118362
- operationalCursor = operationalSignalCursorAt(serviceStartedAt);
118363
- }
118364
- runOperationalInboxLoopWithRestart({
118365
- client: wsClient2,
118366
- sessionId: session2.sessionId,
118367
- machineId: session2.machineId,
118368
- chatroomId,
118369
- serviceStartedAt,
118370
- initialAfterSignalKey: operationalCursor,
118371
- signal: controller.signal
118372
- }, operationalHandler, () => stopped);
118373
- await session2.taskService.registerTaskChatroom(chatroomId);
118457
+ if (persistedRoom || bootstrapSucceeded) {
118458
+ ackMachineSignal(sessionDeps, session2.machineId, chatroomId2, cursor, kind).catch((error51) => console.warn(`[OperationalInbox kind=${kind} room=${chatroomId2}] startup signal cleanup failed:`, error51));
118459
+ }
118460
+ runOperationalInboxLoopWithRestart({
118461
+ client: wsClient2,
118462
+ sessionId: session2.sessionId,
118463
+ machineId: session2.machineId,
118464
+ chatroomId: chatroomId2,
118465
+ feed: operationalSignalFeeds[kind],
118466
+ serviceStartedAt,
118467
+ initialAfterSignalKey: cursor,
118468
+ signal: controller.signal
118469
+ }, (update6) => operationalHandler(kind, update6), () => stopped);
118470
+ }));
118471
+ await session2.taskService.registerTaskChatroom(chatroomId2);
118374
118472
  })();
118375
118473
  return entry.startPromise;
118376
118474
  };
@@ -118386,22 +118484,22 @@ var INBOX_RESTART_INITIAL_MS = 1000, INBOX_RESTART_MAX_MS = 30000, startTaskInbo
118386
118484
  ...new Set((workspaces ?? []).map((workspace) => workspace.chatroomId))
118387
118485
  ];
118388
118486
  const activeChatroomIds = new Set(chatroomIds);
118389
- for (const [chatroomId, watcher] of roomWatchers) {
118390
- if (activeChatroomIds.has(chatroomId))
118487
+ for (const [chatroomId2, watcher] of roomWatchers) {
118488
+ if (activeChatroomIds.has(chatroomId2))
118391
118489
  continue;
118392
118490
  watcher.controller.abort();
118393
- session2.taskService.unregisterTaskChatroom(chatroomId);
118394
- roomWatchers.delete(chatroomId);
118395
- knownRoomIds.delete(chatroomId);
118491
+ session2.taskService.unregisterTaskChatroom(chatroomId2);
118492
+ roomWatchers.delete(chatroomId2);
118493
+ knownRoomIds.delete(chatroomId2);
118396
118494
  }
118397
- await Promise.all(chatroomIds.map((chatroomId) => ensureRoomInboxes(chatroomId)));
118495
+ await Promise.all(chatroomIds.map((chatroomId2) => ensureRoomInboxes(chatroomId2)));
118398
118496
  } catch (error51) {
118399
118497
  console.warn("[TaskInbox] room membership refresh failed:", error51);
118400
118498
  }
118401
118499
  };
118402
118500
  registerTaskInboxRoomMembershipRefresh(refreshRoomMembership2);
118403
118501
  yield* exports_Effect.promise(refreshRoomMembership2);
118404
- yield* exports_Effect.tryPromise(() => Promise.all([...knownRoomIds].map((chatroomId) => ensureRoomInboxes(chatroomId)))).pipe(exports_Effect.catchAll((error51) => {
118502
+ yield* exports_Effect.tryPromise(() => Promise.all([...knownRoomIds].map((chatroomId2) => ensureRoomInboxes(chatroomId2)))).pipe(exports_Effect.catchAll((error51) => {
118405
118503
  console.warn("[OperationalInbox] initial watcher start failed:", error51);
118406
118504
  return exports_Effect.void;
118407
118505
  }));
@@ -118428,6 +118526,7 @@ var init_task_inbox_runtime = __esm(() => {
118428
118526
  init_ack_machine_operational_signals();
118429
118527
  init_fetch_machine_agent_operational_status();
118430
118528
  init_operational_inbox();
118529
+ init_operational_signal_feeds();
118431
118530
  init_inbox();
118432
118531
  init_service_interfaces();
118433
118532
  });
@@ -118773,11 +118872,11 @@ var init_on_daemon_shutdown = __esm(() => {
118773
118872
  console.log(`[${formatTimestamp()}] Stopping ${activeAgents.length} agent(s) locally...`);
118774
118873
  let totalStopped = 0;
118775
118874
  let totalFailed = 0;
118776
- yield* exports_Effect.all(activeAgents.map(({ chatroomId, role }) => exports_Effect.promise(() => agentPm.stopAgent({ chatroomId, role, reason: "daemon.shutdown" })).pipe(exports_Effect.tap(() => exports_Effect.sync(() => {
118875
+ yield* exports_Effect.all(activeAgents.map(({ chatroomId: chatroomId2, role }) => exports_Effect.promise(() => agentPm.stopAgent({ chatroomId: chatroomId2, role, reason: "daemon.shutdown" })).pipe(exports_Effect.tap(() => exports_Effect.sync(() => {
118777
118876
  totalStopped += 1;
118778
118877
  })), exports_Effect.catchAll((e) => exports_Effect.sync(() => {
118779
118878
  totalFailed += 1;
118780
- console.log(` ⚠️ Failed to stop ${role}@${chatroomId}: ${e.message}`);
118879
+ console.log(` ⚠️ Failed to stop ${role}@${chatroomId2}: ${e.message}`);
118781
118880
  })))), { concurrency: "unbounded" });
118782
118881
  if (totalFailed > 0) {
118783
118882
  console.log(`[${formatTimestamp()}] Shutdown stops: ${totalStopped} stopped, ${totalFailed} failed`);
@@ -119599,15 +119698,15 @@ function startEnhancerJobSubscriber2(deps, onEvent) {
119599
119698
  const onError3 = (err) => {
119600
119699
  console.warn(`[daemon] enhancer-job subscriber error: ${err instanceof Error ? err.message : String(err)}`);
119601
119700
  };
119602
- const watchChatroom = (chatroomId) => {
119603
- if (watchers.has(chatroomId) || stopped)
119701
+ const watchChatroom = (chatroomId2) => {
119702
+ if (watchers.has(chatroomId2) || stopped)
119604
119703
  return;
119605
119704
  const unsub = deps.wsClient.onUpdate(api.daemon.enhancer.index.pendingForChatroom, {
119606
119705
  sessionId: deps.sessionId,
119607
119706
  machineId: deps.machineId,
119608
- chatroomId
119707
+ chatroomId: chatroomId2
119609
119708
  }, onPendingJobs, onError3);
119610
- watchers.set(chatroomId, unsub);
119709
+ watchers.set(chatroomId2, unsub);
119611
119710
  };
119612
119711
  const refreshChatrooms = async () => {
119613
119712
  if (refreshInFlight)
@@ -120092,10 +120191,10 @@ function queryEventStream(db, input) {
120092
120191
  payload: JSON.parse(row.payload_json)
120093
120192
  }));
120094
120193
  }
120095
- function queryAfterId(db, afterId = 0, limit = 100, source, chatroomId, role, harness, fromTimestamp, toTimestamp) {
120194
+ function queryAfterId(db, afterId = 0, limit = 100, source, chatroomId2, role, harness, fromTimestamp, toTimestamp) {
120096
120195
  const filters = [
120097
120196
  source ? "AND source = ?" : "",
120098
- chatroomId ? "AND json_extract(metadata_json, '$.chatroomId') = ?" : "",
120197
+ chatroomId2 ? "AND json_extract(metadata_json, '$.chatroomId') = ?" : "",
120099
120198
  role ? "AND json_extract(metadata_json, '$.role') = ?" : "",
120100
120199
  harness ? "AND (json_extract(metadata_json, '$.harness') = ? OR source = ?)" : "",
120101
120200
  fromTimestamp !== undefined ? "AND timestamp >= ?" : "",
@@ -120104,7 +120203,7 @@ function queryAfterId(db, afterId = 0, limit = 100, source, chatroomId, role, ha
120104
120203
  const values3 = [
120105
120204
  afterId,
120106
120205
  ...source ? [source] : [],
120107
- ...chatroomId ? [chatroomId] : [],
120206
+ ...chatroomId2 ? [chatroomId2] : [],
120108
120207
  ...role ? [role] : [],
120109
120208
  ...harness ? [harness, `harness:${harness}`] : [],
120110
120209
  ...fromTimestamp !== undefined ? [fromTimestamp] : [],
@@ -120114,11 +120213,11 @@ function queryAfterId(db, afterId = 0, limit = 100, source, chatroomId, role, ha
120114
120213
  const rows = db.prepare(`SELECT * FROM log_entries WHERE id > ? ${filters} ORDER BY id ASC LIMIT ?`).all(...values3);
120115
120214
  return rows.map(map19);
120116
120215
  }
120117
- function queryHistory(db, beforeId, limit = 100, source, chatroomId, role, harness, fromTimestamp, toTimestamp) {
120216
+ function queryHistory(db, beforeId, limit = 100, source, chatroomId2, role, harness, fromTimestamp, toTimestamp) {
120118
120217
  const filters = [
120119
120218
  beforeId ? "AND id < ?" : "",
120120
120219
  source ? "AND source = ?" : "",
120121
- chatroomId ? "AND json_extract(metadata_json, '$.chatroomId') = ?" : "",
120220
+ chatroomId2 ? "AND json_extract(metadata_json, '$.chatroomId') = ?" : "",
120122
120221
  role ? "AND json_extract(metadata_json, '$.role') = ?" : "",
120123
120222
  harness ? "AND (json_extract(metadata_json, '$.harness') = ? OR source = ?)" : "",
120124
120223
  fromTimestamp !== undefined ? "AND timestamp >= ?" : "",
@@ -120127,7 +120226,7 @@ function queryHistory(db, beforeId, limit = 100, source, chatroomId, role, harne
120127
120226
  const values3 = [
120128
120227
  ...beforeId ? [beforeId] : [],
120129
120228
  ...source ? [source] : [],
120130
- ...chatroomId ? [chatroomId] : [],
120229
+ ...chatroomId2 ? [chatroomId2] : [],
120131
120230
  ...role ? [role] : [],
120132
120231
  ...harness ? [harness, `harness:${harness}`] : [],
120133
120232
  ...fromTimestamp !== undefined ? [fromTimestamp] : [],
@@ -120137,9 +120236,9 @@ function queryHistory(db, beforeId, limit = 100, source, chatroomId, role, harne
120137
120236
  const rows = db.prepare(`SELECT * FROM log_entries WHERE 1=1 ${filters} ORDER BY id DESC LIMIT ?`).all(...values3);
120138
120237
  return rows.map(map19).reverse();
120139
120238
  }
120140
- function listLogDimensions(db, chatroomId, limit = 100) {
120239
+ function listLogDimensions(db, chatroomId2, limit = 100) {
120141
120240
  const clamped = clamp4(limit);
120142
- const values3 = (sql) => db.prepare(sql).all(chatroomId, clamped).map((r) => r.v);
120241
+ const values3 = (sql) => db.prepare(sql).all(chatroomId2, clamped).map((r) => r.v);
120143
120242
  const roles = values3("SELECT DISTINCT json_extract(metadata_json, '$.role') AS v FROM log_entries WHERE json_extract(metadata_json, '$.chatroomId') = ? AND json_extract(metadata_json, '$.role') IS NOT NULL ORDER BY v LIMIT ?");
120144
120243
  const meta3 = values3("SELECT DISTINCT json_extract(metadata_json, '$.harness') AS v FROM log_entries WHERE json_extract(metadata_json, '$.chatroomId') = ? AND json_extract(metadata_json, '$.harness') IS NOT NULL ORDER BY v LIMIT ?");
120145
120244
  const source = values3("SELECT DISTINCT substr(source, 9) AS v FROM log_entries WHERE json_extract(metadata_json, '$.chatroomId') = ? AND source LIKE 'harness:%' ORDER BY v LIMIT ?");
@@ -120323,17 +120422,17 @@ var init_persistence = __esm(() => {
120323
120422
  // src/daemon/infrastructure/repository/log-repository.ts
120324
120423
  function createLogRepository(db) {
120325
120424
  return {
120326
- queryAfterId(afterId = 0, limit = 100, source, chatroomId, role, harness, fromTimestamp, toTimestamp) {
120327
- return queryAfterId(db, afterId, limit, source, chatroomId, role, harness, fromTimestamp, toTimestamp);
120425
+ queryAfterId(afterId = 0, limit = 100, source, chatroomId2, role, harness, fromTimestamp, toTimestamp) {
120426
+ return queryAfterId(db, afterId, limit, source, chatroomId2, role, harness, fromTimestamp, toTimestamp);
120328
120427
  },
120329
- queryHistory(beforeId, limit = 100, source, chatroomId, role, harness, fromTimestamp, toTimestamp) {
120330
- return queryHistory(db, beforeId, limit, source, chatroomId, role, harness, fromTimestamp, toTimestamp);
120428
+ queryHistory(beforeId, limit = 100, source, chatroomId2, role, harness, fromTimestamp, toTimestamp) {
120429
+ return queryHistory(db, beforeId, limit, source, chatroomId2, role, harness, fromTimestamp, toTimestamp);
120331
120430
  },
120332
120431
  listSources(limit = 100) {
120333
120432
  return listDistinctSources(db, limit);
120334
120433
  },
120335
- listDimensions(chatroomId, limit = 100) {
120336
- return listLogDimensions(db, chatroomId, limit);
120434
+ listDimensions(chatroomId2, limit = 100) {
120435
+ return listLogDimensions(db, chatroomId2, limit);
120337
120436
  },
120338
120437
  writeChatroomEvent(event) {
120339
120438
  return appendChatroomEvent(db, event);
@@ -134145,8 +134244,8 @@ function listLogHistory(reader, input) {
134145
134244
  const entries2 = input.afterId !== undefined ? reader.queryAfterId(input.afterId, limit, input.source, input.chatroomId, input.role, input.harness, input.fromTimestamp, input.toTimestamp) : reader.queryHistory(input.beforeId, limit, input.source, input.chatroomId, input.role, input.harness, input.fromTimestamp, input.toTimestamp);
134146
134245
  return { entries: entries2 };
134147
134246
  }
134148
- function listLogDimensions2(reader, chatroomId, limit = 100) {
134149
- return reader.listDimensions ? reader.listDimensions(chatroomId, limit) : { roles: [], harnesses: [] };
134247
+ function listLogDimensions2(reader, chatroomId2, limit = 100) {
134248
+ return reader.listDimensions ? reader.listDimensions(chatroomId2, limit) : { roles: [], harnesses: [] };
134150
134249
  }
134151
134250
  function listLogSources(reader, limit = 100) {
134152
134251
  return { sources: reader.listSources(limit) };
@@ -135364,7 +135463,7 @@ handoffCommandGroup.option("--chatroom-id <id>", "Chatroom identifier").option("
135364
135463
  console.error(`error: required option '${flag} <...>' not specified`);
135365
135464
  process.exit(1);
135366
135465
  }
135367
- const { chatroomId, role, nextRole } = options;
135466
+ const { chatroomId: chatroomId2, role, nextRole } = options;
135368
135467
  await maybeRequireAuth();
135369
135468
  const { decode: decode6 } = await Promise.resolve().then(() => exports_decode);
135370
135469
  const stdinContent = await readStdin();
@@ -135383,7 +135482,7 @@ handoffCommandGroup.option("--chatroom-id <id>", "Chatroom identifier").option("
135383
135482
  process.exit(1);
135384
135483
  }
135385
135484
  const { handoff: handoff2 } = await Promise.resolve().then(() => (init_handoff(), exports_handoff));
135386
- await handoff2(chatroomId, {
135485
+ await handoff2(chatroomId2, {
135387
135486
  role,
135388
135487
  message,
135389
135488
  nextRole
@@ -135707,18 +135806,18 @@ registerChatroomRoleCommand(program2, {
135707
135806
  name: "get-system-prompt",
135708
135807
  description: "Fetch the system prompt for your role in a chatroom",
135709
135808
  maybeRequireAuth,
135710
- run: async (chatroomId, { role }) => {
135809
+ run: async (chatroomId2, { role }) => {
135711
135810
  const { getSystemPrompt: getSystemPrompt2 } = await Promise.resolve().then(() => (init_get_system_prompt(), exports_get_system_prompt));
135712
- await getSystemPrompt2(chatroomId, { role });
135811
+ await getSystemPrompt2(chatroomId2, { role });
135713
135812
  }
135714
135813
  });
135715
135814
  registerChatroomRoleCommand(program2, {
135716
135815
  name: "get-role-guidance",
135717
135816
  description: "Fetch role-specific operating-model guidance for your role in a chatroom",
135718
135817
  maybeRequireAuth,
135719
- run: async (chatroomId, { role }) => {
135818
+ run: async (chatroomId2, { role }) => {
135720
135819
  const { getRoleGuidance: getRoleGuidance2 } = await Promise.resolve().then(() => (init_get_role_guidance(), exports_get_role_guidance));
135721
- await getRoleGuidance2(chatroomId, { role });
135820
+ await getRoleGuidance2(chatroomId2, { role });
135722
135821
  }
135723
135822
  });
135724
135823
  var telegramCommand = program2.command("telegram").description("Telegram integration commands");
@@ -135753,9 +135852,9 @@ opencodeCommand.command("install").description("Install chatroom as an OpenCode
135753
135852
  });
135754
135853
  program2.hook("preAction", async (_thisCommand, actionCommand) => {
135755
135854
  const opts = actionCommand.opts();
135756
- const chatroomId = opts["chatroomId"];
135855
+ const chatroomId2 = opts["chatroomId"];
135757
135856
  const role = opts["role"];
135758
- if (!chatroomId || !role)
135857
+ if (!chatroomId2 || !role)
135759
135858
  return;
135760
135859
  const { getSessionId: getSessionId2 } = await Promise.resolve().then(() => (init_storage(), exports_storage));
135761
135860
  const { getConvexClient: getConvexClient2 } = await Promise.resolve().then(() => (init_client2(), exports_client));
@@ -135764,8 +135863,8 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
135764
135863
  if (!sessionId)
135765
135864
  return;
135766
135865
  const client4 = await getConvexClient2();
135767
- sendLifecycleHeartbeat2(client4, { sessionId, chatroomId, role });
135866
+ sendLifecycleHeartbeat2(client4, { sessionId, chatroomId: chatroomId2, role });
135768
135867
  });
135769
135868
  program2.parse();
135770
135869
 
135771
- //# debugId=F48EA5F0861EF1C964756E2164756E21
135870
+ //# debugId=2166B04C5CAC31EC64756E2164756E21