chatroom-cli 1.98.7 → 1.99.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
@@ -83515,6 +83515,321 @@ function harnessCapabilitiesFingerprint(harnesses, versions) {
83515
83515
  return `${h}::${v3}`;
83516
83516
  }
83517
83517
 
83518
+ // src/daemon/infrastructure/outbox/lib/durable-fifo-queue-schema.ts
83519
+ var DURABLE_FIFO_QUEUE_MIGRATIONS;
83520
+ var init_durable_fifo_queue_schema = __esm(() => {
83521
+ DURABLE_FIFO_QUEUE_MIGRATIONS = [
83522
+ `CREATE TABLE IF NOT EXISTS schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`,
83523
+ `CREATE TABLE IF NOT EXISTS fifo_outbox_entries (id INTEGER PRIMARY KEY AUTOINCREMENT, delivery_key TEXT NOT NULL, payload_json TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
83524
+ `CREATE INDEX IF NOT EXISTS idx_fifo_outbox_pending ON fifo_outbox_entries(delivery_key, status, id)`
83525
+ ];
83526
+ });
83527
+
83528
+ // src/daemon/infrastructure/outbox/lib/durable-fifo-queue-store.ts
83529
+ import { DatabaseSync } from "node:sqlite";
83530
+ import { mkdirSync as mkdirSync4 } from "node:fs";
83531
+ import { dirname as dirname9 } from "node:path";
83532
+ function openDurableFifoQueueStore(dbPath) {
83533
+ mkdirSync4(dirname9(dbPath), { recursive: true });
83534
+ const db = new DatabaseSync(dbPath);
83535
+ for (const sql of DURABLE_FIFO_QUEUE_MIGRATIONS)
83536
+ db.exec(sql);
83537
+ db.prepare("UPDATE fifo_outbox_entries SET status='pending', updated_at=? WHERE status='in_flight'").run(Date.now());
83538
+ return {
83539
+ enqueue: (key, payloadJson) => {
83540
+ const now = Date.now();
83541
+ return Number(db.prepare("INSERT INTO fifo_outbox_entries(delivery_key,payload_json,created_at,updated_at) VALUES(?,?,?,?) RETURNING id").get(key, payloadJson, now, now).id);
83542
+ },
83543
+ claimNextBatch: (key, limit) => db.prepare("UPDATE fifo_outbox_entries SET status='in_flight', attempts=attempts+1, updated_at=? WHERE id IN (SELECT id FROM fifo_outbox_entries WHERE delivery_key=? AND status='pending' ORDER BY id LIMIT ?) RETURNING id, delivery_key as deliveryKey, payload_json as payloadJson, attempts").all(Date.now(), key, limit),
83544
+ markDone: (id3) => {
83545
+ db.prepare("DELETE FROM fifo_outbox_entries WHERE id=?").run(id3);
83546
+ },
83547
+ markPending: (id3) => {
83548
+ db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=NULL, updated_at=? WHERE id=?").run(Date.now(), id3);
83549
+ },
83550
+ updatePayload: (id3, payloadJson) => {
83551
+ db.prepare("UPDATE fifo_outbox_entries SET payload_json=?, updated_at=? WHERE id=?").run(payloadJson, Date.now(), id3);
83552
+ },
83553
+ markPendingRetry: (id3, error) => {
83554
+ db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=?, updated_at=? WHERE id=?").run(String(error), Date.now(), id3);
83555
+ },
83556
+ listPendingForRecovery: (key) => db.prepare("SELECT id, delivery_key as deliveryKey, payload_json as payloadJson, attempts FROM fifo_outbox_entries WHERE delivery_key=? AND status IN ('pending','in_flight') ORDER BY id").all(key),
83557
+ close: () => db.close()
83558
+ };
83559
+ }
83560
+ var init_durable_fifo_queue_store = __esm(() => {
83561
+ init_durable_fifo_queue_schema();
83562
+ });
83563
+
83564
+ // src/daemon/infrastructure/outbox/lib/outbox-retry-backoff.ts
83565
+ function computeExponentialRetryDelayMs(attempt, retryDelayMs, maxRetryDelayMs) {
83566
+ const exponent = Math.min(Math.max(0, attempt), MAX_RETRY_EXPONENT);
83567
+ return Math.min(retryDelayMs * 2 ** exponent, maxRetryDelayMs);
83568
+ }
83569
+ var MAX_RETRY_EXPONENT = 20;
83570
+
83571
+ // src/daemon/infrastructure/outbox/lib/fifo-batched-outbox.ts
83572
+ function createFifoBatchedOutbox(o) {
83573
+ const waiters = new Map;
83574
+ let running3;
83575
+ let stopped = false;
83576
+ let retryTimer;
83577
+ let retryAttempt = 0;
83578
+ const retryDelay = () => computeExponentialRetryDelayMs(retryAttempt++, o.retryDelayMs ?? 500, o.maxRetryDelayMs ?? 5000);
83579
+ const scheduleRetry = () => {
83580
+ if (!stopped && !retryTimer) {
83581
+ retryTimer = setTimeout(() => {
83582
+ retryTimer = undefined;
83583
+ drain().catch(() => {
83584
+ return;
83585
+ });
83586
+ }, retryDelay());
83587
+ retryTimer.unref?.();
83588
+ }
83589
+ };
83590
+ const drain = async () => {
83591
+ if (running3)
83592
+ return running3;
83593
+ running3 = (async () => {
83594
+ while (true) {
83595
+ const rows = o.store.claimNextBatch(o.deliveryKey, o.batchSize);
83596
+ if (!rows.length)
83597
+ break;
83598
+ try {
83599
+ const results = await o.send(rows.map((r) => o.deserialize(r.payloadJson)));
83600
+ let hasRetry = false;
83601
+ for (let i2 = 0;i2 < results.length; i2++) {
83602
+ const item = o.deserialize(rows[i2].payloadJson);
83603
+ const outcome = o.classifyOutcome?.(results[i2], item) ?? { kind: "success" };
83604
+ if (outcome.kind === "retry") {
83605
+ o.store.updatePayload(rows[i2].id, o.serialize(outcome.item));
83606
+ o.store.markPending(rows[i2].id);
83607
+ hasRetry = true;
83608
+ continue;
83609
+ }
83610
+ o.store.markDone(rows[i2].id);
83611
+ waiters.get(rows[i2].id)?.resolve(results[i2]);
83612
+ waiters.delete(rows[i2].id);
83613
+ }
83614
+ for (let i2 = results.length;i2 < rows.length; i2++)
83615
+ o.store.markPending(rows[i2].id);
83616
+ if (hasRetry) {
83617
+ scheduleRetry();
83618
+ break;
83619
+ }
83620
+ retryAttempt = 0;
83621
+ } catch (e) {
83622
+ o.onError?.(e);
83623
+ for (const r of rows)
83624
+ o.store.markPendingRetry(r.id, e);
83625
+ scheduleRetry();
83626
+ break;
83627
+ }
83628
+ }
83629
+ })().finally(() => {
83630
+ running3 = undefined;
83631
+ });
83632
+ return running3;
83633
+ };
83634
+ const enqueue = (item) => {
83635
+ if (stopped)
83636
+ return Promise.reject(new Error("Outbox is stopped"));
83637
+ const id3 = o.store.enqueue(o.deliveryKey, o.serialize(item));
83638
+ const p = new Promise((resolve4, reject) => waiters.set(id3, { resolve: resolve4, reject }));
83639
+ drain().catch(() => {
83640
+ return;
83641
+ });
83642
+ return p;
83643
+ };
83644
+ const flushNow = async () => {
83645
+ while (o.store.listPendingForRecovery(o.deliveryKey).length) {
83646
+ await drain();
83647
+ }
83648
+ };
83649
+ const stop4 = async () => {
83650
+ if (stopped)
83651
+ return;
83652
+ if (retryTimer)
83653
+ clearTimeout(retryTimer);
83654
+ retryTimer = undefined;
83655
+ await flushNow();
83656
+ stopped = true;
83657
+ };
83658
+ return { enqueue, flushNow, stop: stop4 };
83659
+ }
83660
+ var init_fifo_batched_outbox = () => {};
83661
+
83662
+ // src/daemon/infrastructure/outbox/lib/keyed-fifo-batched-outbox-registry.ts
83663
+ function createKeyedFifoBatchedOutboxRegistry(o) {
83664
+ const boxes = new Map;
83665
+ const get13 = (key) => {
83666
+ let b = boxes.get(key);
83667
+ if (!b) {
83668
+ b = createFifoBatchedOutbox({
83669
+ batchSize: o.batchSize,
83670
+ send: o.createSend(key),
83671
+ store: o.store,
83672
+ deliveryKey: key,
83673
+ serialize: o.serialize,
83674
+ deserialize: o.deserialize,
83675
+ retryDelayMs: o.retryDelayMs,
83676
+ maxRetryDelayMs: o.maxRetryDelayMs,
83677
+ onError: (e) => o.onError?.(key, e),
83678
+ classifyOutcome: o.classifyOutcome
83679
+ });
83680
+ boxes.set(key, b);
83681
+ }
83682
+ return b;
83683
+ };
83684
+ const stop4 = async (k) => {
83685
+ const b = boxes.get(k);
83686
+ if (b) {
83687
+ await b.stop();
83688
+ boxes.delete(k);
83689
+ }
83690
+ };
83691
+ return {
83692
+ enqueue: (k, i2) => get13(k).enqueue(i2),
83693
+ flushNow: async (k) => {
83694
+ if (k)
83695
+ await get13(k).flushNow();
83696
+ else
83697
+ for (const b of boxes.values())
83698
+ await b.flushNow();
83699
+ },
83700
+ stop: stop4,
83701
+ stopAll: async () => {
83702
+ for (const k of [...boxes.keys()])
83703
+ await stop4(k);
83704
+ o.store.close();
83705
+ }
83706
+ };
83707
+ }
83708
+ var init_keyed_fifo_batched_outbox_registry = __esm(() => {
83709
+ init_fifo_batched_outbox();
83710
+ });
83711
+
83712
+ // src/daemon/infrastructure/outbox/outbox-db-path.ts
83713
+ import { homedir as homedir5 } from "node:os";
83714
+ import { join as join17 } from "node:path";
83715
+ function resolveOutboxDbPath(machineId, kind) {
83716
+ return join17(homedir5(), ".chatroom", "daemon", machineId, `outbox-${kind}.sqlite`);
83717
+ }
83718
+ var init_outbox_db_path = () => {};
83719
+
83720
+ // src/daemon/domain/entities/agent-lifecycle-fact.ts
83721
+ function buildExitedLifecycleFact(auditArgs, emittedAt) {
83722
+ const { sessionId: _sessionId, machineId: _machineId, ...fields } = auditArgs;
83723
+ return {
83724
+ kind: "exited",
83725
+ ...fields,
83726
+ revisionKey: buildAgentLifecycleRevisionKey("exited", {
83727
+ chatroomId: auditArgs.chatroomId,
83728
+ role: auditArgs.role,
83729
+ pid: auditArgs.pid,
83730
+ emittedAt
83731
+ }),
83732
+ emittedAt
83733
+ };
83734
+ }
83735
+ function normalizeAgentLifecycleFact(raw) {
83736
+ if (!raw || typeof raw !== "object") {
83737
+ throw new Error("Invalid agent lifecycle fact");
83738
+ }
83739
+ const value = raw;
83740
+ const { sessionId: _sessionId, machineId: _machineId, ...rest } = value;
83741
+ const kind = rest.kind;
83742
+ if (kind === "cleared_all_pids") {
83743
+ return {
83744
+ kind: "cleared_all_pids",
83745
+ revisionKey: String(rest.revisionKey),
83746
+ emittedAt: Number(rest.emittedAt)
83747
+ };
83748
+ }
83749
+ if (kind === "spawned" || kind === "exited") {
83750
+ return rest;
83751
+ }
83752
+ throw new Error(`Unknown agent lifecycle fact kind: ${String(kind)}`);
83753
+ }
83754
+ function agentLifecycleDeliveryKey(machineId, fact) {
83755
+ if (fact.kind === "cleared_all_pids")
83756
+ return `${machineId}:__machine__`;
83757
+ return `${machineId}:${fact.chatroomId}:${fact.role.toLowerCase()}`;
83758
+ }
83759
+ function buildAgentLifecycleRevisionKey(prefix, parts2) {
83760
+ return `${prefix}:${Object.entries(parts2).filter(([, v3]) => v3 !== undefined).map(([k, v3]) => `${k}=${v3}`).join(":")}`;
83761
+ }
83762
+
83763
+ // src/daemon/infrastructure/outbox/agent-lifecycle-outbox.ts
83764
+ function createAgentLifecycleOutboxRegistry(machineId, createSend, options) {
83765
+ const store = openDurableFifoQueueStore(resolveOutboxDbPath(machineId, "agent-lifecycle"));
83766
+ return createKeyedFifoBatchedOutboxRegistry({
83767
+ store,
83768
+ batchSize: AGENT_LIFECYCLE_OUTBOX_BATCH_SIZE,
83769
+ createSend: (key) => async (facts) => {
83770
+ const results = [];
83771
+ for (const fact of facts)
83772
+ results.push(await createSend(key)(fact));
83773
+ return results;
83774
+ },
83775
+ serialize: JSON.stringify,
83776
+ deserialize: (serialized) => normalizeAgentLifecycleFact(JSON.parse(serialized)),
83777
+ retryDelayMs: 500,
83778
+ maxRetryDelayMs: 5 * 60000,
83779
+ onError: options?.onError,
83780
+ classifyOutcome: () => ({ kind: "success" })
83781
+ });
83782
+ }
83783
+ function agentLifecycleKey(machineId, fact) {
83784
+ return agentLifecycleDeliveryKey(machineId, fact);
83785
+ }
83786
+ var AGENT_LIFECYCLE_OUTBOX_BATCH_SIZE = 1;
83787
+ var init_agent_lifecycle_outbox = __esm(() => {
83788
+ init_durable_fifo_queue_store();
83789
+ init_keyed_fifo_batched_outbox_registry();
83790
+ init_outbox_db_path();
83791
+ });
83792
+
83793
+ // src/daemon/infrastructure/outbox/agent-lifecycle-send.ts
83794
+ function toConvexLifecycleFact(fact) {
83795
+ const normalized = normalizeAgentLifecycleFact(fact);
83796
+ if (normalized.kind === "cleared_all_pids")
83797
+ return normalized;
83798
+ return {
83799
+ ...normalized,
83800
+ chatroomId: normalized.chatroomId
83801
+ };
83802
+ }
83803
+ function createAgentLifecycleSend(session2) {
83804
+ return async (fact) => {
83805
+ const args2 = {
83806
+ sessionId: session2.sessionId,
83807
+ machineId: session2.machineId,
83808
+ fact: toConvexLifecycleFact(fact)
83809
+ };
83810
+ return await session2.backend.mutation(api.machines.projectAgentLifecycleFact, args2);
83811
+ };
83812
+ }
83813
+ var init_agent_lifecycle_send = __esm(() => {
83814
+ init_api3();
83815
+ });
83816
+
83817
+ // src/daemon/entry/agent-lifecycle-outbox-runtime.ts
83818
+ function createAgentLifecycleOutboxForSession(args2) {
83819
+ return createAgentLifecycleOutboxRegistry(args2.machineId, () => createAgentLifecycleSend({
83820
+ sessionId: args2.sessionId,
83821
+ machineId: args2.machineId,
83822
+ backend: args2.backend
83823
+ }));
83824
+ }
83825
+ function enqueueAgentLifecycleFact(registry2, machineId, fact) {
83826
+ return registry2.enqueue(agentLifecycleKey(machineId, fact), fact);
83827
+ }
83828
+ var init_agent_lifecycle_outbox_runtime = __esm(() => {
83829
+ init_agent_lifecycle_outbox();
83830
+ init_agent_lifecycle_send();
83831
+ });
83832
+
83518
83833
  // src/daemon/entry/daemon-services.ts
83519
83834
  function DaemonMutableStateServiceLive(init2) {
83520
83835
  return exports_Layer.effect(DaemonMutableStateService, exports_Effect.gen(function* () {
@@ -83526,7 +83841,10 @@ function DaemonMutableStateServiceLive(init2) {
83526
83841
  };
83527
83842
  }));
83528
83843
  }
83529
- var DaemonMachineService, DaemonMachineServiceLive = (ops) => exports_Layer.succeed(DaemonMachineService, {
83844
+ var AgentLifecycleOutboxService, AgentLifecycleOutboxServiceLive = (registry2, machineId) => exports_Layer.succeed(AgentLifecycleOutboxService, {
83845
+ enqueue: (fact) => exports_Effect.promise(() => enqueueAgentLifecycleFact(registry2, machineId, fact)),
83846
+ stopAll: () => exports_Effect.promise(() => registry2.stopAll())
83847
+ }), DaemonMachineService, DaemonMachineServiceLive = (ops) => exports_Layer.succeed(DaemonMachineService, {
83530
83848
  clearAgentPid: (machineId, chatroomId, role) => exports_Effect.promise(() => ops.clearAgentPid(machineId, chatroomId, role)),
83531
83849
  persistAgentPid: (machineId, chatroomId, role, pid, harness) => exports_Effect.promise(() => ops.persistAgentPid(machineId, chatroomId, role, pid, harness)),
83532
83850
  listAgentEntries: (machineId) => exports_Effect.promise(() => ops.listAgentEntries(machineId)),
@@ -83550,6 +83868,9 @@ var DaemonMachineService, DaemonMachineServiceLive = (ops) => exports_Layer.succ
83550
83868
  }), DaemonSessionService, DaemonMutableStateService;
83551
83869
  var init_daemon_services = __esm(() => {
83552
83870
  init_esm();
83871
+ init_agent_lifecycle_outbox_runtime();
83872
+ AgentLifecycleOutboxService = class AgentLifecycleOutboxService extends exports_Context.Tag("AgentLifecycleOutboxService")() {
83873
+ };
83553
83874
  DaemonMachineService = class DaemonMachineService extends exports_Context.Tag("DaemonMachineService")() {
83554
83875
  };
83555
83876
  DaemonSpawningService = class DaemonSpawningService extends exports_Context.Tag("DaemonSpawningService")() {
@@ -83572,7 +83893,7 @@ function daemonSessionToLayers(init2) {
83572
83893
  return exports_Layer.mergeAll(BackendServiceLive({
83573
83894
  mutation: (e, a) => init2.backend.mutation(e, a),
83574
83895
  query: (e, a) => init2.backend.query(e, a)
83575
- }), ProcessServiceLive, ClockServiceLive, FsServiceLive, DaemonMachineServiceLive(init2.machine), DaemonSpawningServiceLive(init2.spawning), DaemonAgentProcessManagerServiceLive(init2.agentProcessManager), DaemonMutableStateServiceLive({
83896
+ }), ProcessServiceLive, ClockServiceLive, FsServiceLive, DaemonMachineServiceLive(init2.machine), AgentLifecycleOutboxServiceLive(init2.agentLifecycleOutbox, init2.machineId), DaemonSpawningServiceLive(init2.spawning), DaemonAgentProcessManagerServiceLive(init2.agentProcessManager), DaemonMutableStateServiceLive({
83576
83897
  lastPushedGitState: init2.lastPushedGitState,
83577
83898
  lastPushedModels: init2.lastPushedModels,
83578
83899
  lastPushedHarnessFingerprint: init2.lastPushedHarnessFingerprint,
@@ -83696,10 +84017,18 @@ var init_register_listeners = __esm(() => {
83696
84017
 
83697
84018
  // src/daemon/entry/handlers/daemon-restart-cleanup.ts
83698
84019
  var clearStaleSpawnedPidsEffect = () => exports_Effect.gen(function* () {
83699
- const backend2 = yield* BackendService;
84020
+ const outbox = yield* AgentLifecycleOutboxService;
83700
84021
  const session2 = yield* DaemonSessionService;
83701
- const result = yield* backend2.mutation(api.machines.clearAllSpawnedPids, { sessionId: session2.sessionId, machineId: session2.machineId });
83702
- return result.clearedCount;
84022
+ const emittedAt = Date.now();
84023
+ const result = yield* outbox.enqueue({
84024
+ kind: "cleared_all_pids",
84025
+ revisionKey: buildAgentLifecycleRevisionKey("cleared_all", {
84026
+ machineId: session2.machineId,
84027
+ emittedAt
84028
+ }),
84029
+ emittedAt
84030
+ });
84031
+ return result.clearedCount ?? 0;
83703
84032
  }), reapOrphanCommandRunsEffect = () => exports_Effect.gen(function* () {
83704
84033
  const backend2 = yield* BackendService;
83705
84034
  const session2 = yield* DaemonSessionService;
@@ -83737,26 +84066,26 @@ import { createHash as createHash2 } from "node:crypto";
83737
84066
  import {
83738
84067
  appendFileSync,
83739
84068
  existsSync as existsSync6,
83740
- mkdirSync as mkdirSync4,
84069
+ mkdirSync as mkdirSync5,
83741
84070
  readFileSync as readFileSync8,
83742
84071
  renameSync,
83743
84072
  unlinkSync,
83744
84073
  writeFileSync as writeFileSync3
83745
84074
  } from "node:fs";
83746
- import { homedir as homedir5 } from "node:os";
83747
- import { join as join17 } from "node:path";
84075
+ import { homedir as homedir6 } from "node:os";
84076
+ import { join as join18 } from "node:path";
83748
84077
  function getUrlHash() {
83749
84078
  const url2 = getConvexUrl();
83750
84079
  return createHash2("sha256").update(url2).digest("hex").substring(0, 8);
83751
84080
  }
83752
84081
  function getChildPidsFilePath() {
83753
- const dir = join17(homedir5(), ".chatroom");
83754
- return join17(dir, `daemon-children-${getUrlHash()}.pids`);
84082
+ const dir = join18(homedir6(), ".chatroom");
84083
+ return join18(dir, `daemon-children-${getUrlHash()}.pids`);
83755
84084
  }
83756
84085
  function ensureChatroomDir2() {
83757
- const dir = join17(homedir5(), ".chatroom");
84086
+ const dir = join18(homedir6(), ".chatroom");
83758
84087
  if (!existsSync6(dir)) {
83759
- mkdirSync4(dir, { recursive: true, mode: 448 });
84088
+ mkdirSync5(dir, { recursive: true, mode: 448 });
83760
84089
  }
83761
84090
  }
83762
84091
  function readPids() {
@@ -83869,7 +84198,7 @@ var init_orphan_tracker = __esm(() => {
83869
84198
  // src/daemon/entry/handlers/process/output-store.ts
83870
84199
  import { appendFile as appendFile2, mkdir as mkdir8, readFile as readFile6, rm as rm2 } from "node:fs/promises";
83871
84200
  import { tmpdir } from "node:os";
83872
- import { join as join18 } from "node:path";
84201
+ import { join as join19 } from "node:path";
83873
84202
 
83874
84203
  class TempFileOutputStore {
83875
84204
  state;
@@ -83932,7 +84261,7 @@ function createOutputStore(runId) {
83932
84261
  if (!RUN_ID_RE.test(runId)) {
83933
84262
  throw new Error(`Invalid runId: ${runId}`);
83934
84263
  }
83935
- const filePath = join18(TEMP_DIR, `${runId}.log`);
84264
+ const filePath = join19(TEMP_DIR, `${runId}.log`);
83936
84265
  return new TempFileOutputStore(filePath);
83937
84266
  }
83938
84267
  async function ensureTempDir() {
@@ -83946,7 +84275,7 @@ async function cleanOrphanTempFiles() {
83946
84275
  var TAIL_WINDOW_BYTES, TEMP_DIR, RUN_ID_RE, MAX_TAIL_LINES_V2 = 50;
83947
84276
  var init_output_store = __esm(() => {
83948
84277
  TAIL_WINDOW_BYTES = 32 * 1024;
83949
- TEMP_DIR = join18(tmpdir(), "chatroom-cli", "runs");
84278
+ TEMP_DIR = join19(tmpdir(), "chatroom-cli", "runs");
83950
84279
  RUN_ID_RE = /^[a-z0-9]+$/i;
83951
84280
  });
83952
84281
 
@@ -84014,74 +84343,6 @@ async function logDaemonAuditEvent(logEvent, event) {
84014
84343
  });
84015
84344
  }
84016
84345
 
84017
- // src/daemon/infrastructure/inbox/task-snapshot-state.ts
84018
- function snapshotKey(taskId, role) {
84019
- return `${taskId}:${role.toLowerCase()}`;
84020
- }
84021
-
84022
- class MachineTaskSnapshotState {
84023
- snapshots = new Map;
84024
- replace(snapshots) {
84025
- this.snapshots.clear();
84026
- this.upsert(snapshots);
84027
- }
84028
- applySignalPage(signals, snapshots) {
84029
- const snapshotsByKey = new Map(snapshots.map((snapshot) => [
84030
- snapshotKey(snapshot.taskId, snapshot.agentConfig.role),
84031
- snapshot
84032
- ]));
84033
- for (const signal of signals) {
84034
- const key = snapshotKey(signal.taskId, signal.targetRole);
84035
- const snapshot = snapshotsByKey.get(key);
84036
- if (snapshot) {
84037
- this.snapshots.set(key, snapshot);
84038
- } else {
84039
- this.snapshots.delete(key);
84040
- }
84041
- }
84042
- }
84043
- listForRole(chatroomId, role) {
84044
- const roleLower = role.toLowerCase();
84045
- return [...this.snapshots.values()].filter((snapshot) => snapshot.chatroomId === chatroomId && snapshot.agentConfig.role.toLowerCase() === roleLower);
84046
- }
84047
- listAll() {
84048
- return [...this.snapshots.values()];
84049
- }
84050
- setDesiredState(chatroomId, role, desiredState) {
84051
- const roleLower = role.toLowerCase();
84052
- for (const [key, snapshot] of this.snapshots) {
84053
- if (snapshot.chatroomId !== chatroomId || snapshot.agentConfig.role.toLowerCase() !== roleLower) {
84054
- continue;
84055
- }
84056
- this.snapshots.set(key, {
84057
- ...snapshot,
84058
- agentConfig: { ...snapshot.agentConfig, desiredState }
84059
- });
84060
- }
84061
- }
84062
- upsert(snapshots) {
84063
- for (const snapshot of snapshots) {
84064
- this.snapshots.set(snapshotKey(snapshot.taskId, snapshot.agentConfig.role), snapshot);
84065
- }
84066
- }
84067
- }
84068
-
84069
- // src/daemon/entry/native-delivery/native-delivery-session-registry.ts
84070
- function registerNativeDeliverySession(ctx) {
84071
- registered = {
84072
- ...ctx,
84073
- taskSnapshotState: ctx.taskSnapshotState ?? new MachineTaskSnapshotState
84074
- };
84075
- }
84076
- function unregisterNativeDeliverySession() {
84077
- registered = null;
84078
- }
84079
- function getNativeDeliverySession() {
84080
- return registered;
84081
- }
84082
- var registered = null;
84083
- var init_native_delivery_session_registry = () => {};
84084
-
84085
84346
  // ../../services/backend/config/reliability.ts
84086
84347
  var HARNESS_SESSION_READY_TIMEOUT_MS = 5000, DAEMON_HEARTBEAT_INTERVAL_MS, DAEMON_HEARTBEAT_TTL_MS, AGENT_REQUEST_DEADLINE_MS = 120000, OBSERVED_FULL_PUSH_INTERVAL_MS, OBSERVED_SYNC_RECONCILE_MS, WORKSPACE_RECENCY_WINDOW_MS, WORKSPACE_LIST_RECONCILE_MS, CONNECTION_CLOSE_REQUEST_TTL_MS, ENHANCER_TERMINAL_JOB_RETENTION_MS;
84087
84348
  var init_reliability = __esm(() => {
@@ -98811,8 +99072,6 @@ var init_assigned_task_snapshot_contract = __esm(() => {
98811
99072
  assignedTo: exports_external.string().optional(),
98812
99073
  lastSeenAction: exports_external.string().nullable().optional(),
98813
99074
  lastStatus: exports_external.string().nullable().optional(),
98814
- spawnedAgentPid: exports_external.number().optional(),
98815
- desiredState: agentDesiredStateSchema.optional(),
98816
99075
  sessionAugmentation: sessionAugmentationSchema.optional()
98817
99076
  };
98818
99077
  assignedTaskSignalSchema = exports_external.object(assignedTaskSignalBootstrapFields);
@@ -98889,13 +99148,99 @@ function getNativeDeliveryLedger() {
98889
99148
  }
98890
99149
  var sharedLedger;
98891
99150
 
99151
+ // src/daemon/infrastructure/agent-operational/agent-operational-read-model.ts
99152
+ function isOperationalDesiredRunning(row) {
99153
+ return row?.operationalState === "running" || row?.operationalState === "starting";
99154
+ }
99155
+
99156
+ class AgentOperationalReadModel {
99157
+ rows = new Map;
99158
+ replace(rows) {
99159
+ const changed = [];
99160
+ const nextKeys = new Set;
99161
+ for (const row of rows) {
99162
+ const key = roleKey(row.chatroomId, row.role);
99163
+ nextKeys.add(key);
99164
+ const prev = this.rows.get(key);
99165
+ if (!prev || prev.revisionKey !== row.revisionKey)
99166
+ changed.push({ chatroomId: row.chatroomId, role: row.role });
99167
+ this.rows.set(key, row);
99168
+ }
99169
+ for (const [key, prev] of this.rows) {
99170
+ if (!nextKeys.has(key)) {
99171
+ changed.push({ chatroomId: prev.chatroomId, role: prev.role });
99172
+ this.rows.delete(key);
99173
+ }
99174
+ }
99175
+ return changed;
99176
+ }
99177
+ get(chatroomId, role) {
99178
+ return this.rows.get(roleKey(chatroomId, role));
99179
+ }
99180
+ }
99181
+ var roleKey = (chatroomId, role) => `${chatroomId}:${role.toLowerCase()}`;
99182
+
99183
+ // src/daemon/infrastructure/inbox/task-snapshot-state.ts
99184
+ function snapshotKey(taskId, role) {
99185
+ return `${taskId}:${role.toLowerCase()}`;
99186
+ }
99187
+
99188
+ class MachineTaskSnapshotState {
99189
+ snapshots = new Map;
99190
+ replace(snapshots) {
99191
+ this.snapshots.clear();
99192
+ this.upsert(snapshots);
99193
+ }
99194
+ applySignalPage(signals, snapshots) {
99195
+ const snapshotsByKey = new Map(snapshots.map((snapshot) => [
99196
+ snapshotKey(snapshot.taskId, snapshot.agentConfig.role),
99197
+ snapshot
99198
+ ]));
99199
+ for (const signal of signals) {
99200
+ const key = snapshotKey(signal.taskId, signal.targetRole);
99201
+ const snapshot = snapshotsByKey.get(key);
99202
+ if (snapshot) {
99203
+ this.snapshots.set(key, snapshot);
99204
+ } else {
99205
+ this.snapshots.delete(key);
99206
+ }
99207
+ }
99208
+ }
99209
+ listForRole(chatroomId, role) {
99210
+ const roleLower = role.toLowerCase();
99211
+ return [...this.snapshots.values()].filter((snapshot) => snapshot.chatroomId === chatroomId && snapshot.agentConfig.role.toLowerCase() === roleLower);
99212
+ }
99213
+ listAll() {
99214
+ return [...this.snapshots.values()];
99215
+ }
99216
+ upsert(snapshots) {
99217
+ for (const snapshot of snapshots) {
99218
+ this.snapshots.set(snapshotKey(snapshot.taskId, snapshot.agentConfig.role), snapshot);
99219
+ }
99220
+ }
99221
+ }
99222
+
99223
+ // src/daemon/entry/native-delivery/native-delivery-session-registry.ts
99224
+ function registerNativeDeliverySession(ctx) {
99225
+ registered = {
99226
+ ...ctx,
99227
+ taskSnapshotState: ctx.taskSnapshotState ?? new MachineTaskSnapshotState,
99228
+ agentOperationalReadModel: ctx.agentOperationalReadModel ?? new AgentOperationalReadModel
99229
+ };
99230
+ }
99231
+ function unregisterNativeDeliverySession() {
99232
+ registered = null;
99233
+ }
99234
+ function getNativeDeliverySession() {
99235
+ return registered;
99236
+ }
99237
+ var registered = null;
99238
+ var init_native_delivery_session_registry = () => {};
99239
+
98892
99240
  // src/daemon/domain/entities/assigned-task.ts
98893
99241
  function isDeliverableTaskStatus(status3) {
98894
99242
  return status3 === "pending" || status3 === "acknowledged";
98895
99243
  }
98896
- function isAgentDesiredRunning(desiredState) {
98897
- return desiredState === "running";
98898
- }
98899
99244
  var init_assigned_task = () => {};
98900
99245
 
98901
99246
  // src/daemon/domain/usecase/check-agent-slot.ts
@@ -98925,8 +99270,9 @@ function explainAgentReadyForNativeDeliveryBlock(task, slot) {
98925
99270
  if (!isNativeHarness(agentConfig.agentHarness)) {
98926
99271
  return `not_native_harness (harness=${agentConfig.agentHarness})`;
98927
99272
  }
98928
- if (!isAgentDesiredRunning(agentConfig.desiredState)) {
98929
- return `desired_state_not_running (desiredState=${agentConfig.desiredState})`;
99273
+ const operational = getNativeDeliverySession()?.agentOperationalReadModel?.get(task.chatroomId, agentConfig.role);
99274
+ if (!isOperationalDesiredRunning(operational)) {
99275
+ return `operational_state_not_running (state=${operational?.operationalState ?? "missing"})`;
98930
99276
  }
98931
99277
  if (!slot) {
98932
99278
  return agentConfig.spawnedAgentPid == null ? "spawned_pid_missing" : `slot_missing (expectedPid=${agentConfig.spawnedAgentPid})`;
@@ -98954,6 +99300,7 @@ function isDeliverableNativeTaskStatus(status3) {
98954
99300
  }
98955
99301
  var init_native_ready_invariant = __esm(() => {
98956
99302
  init_types();
99303
+ init_native_delivery_session_registry();
98957
99304
  init_assigned_task();
98958
99305
  init_check_agent_slot();
98959
99306
  });
@@ -99466,20 +99813,20 @@ function mapAssignedTaskSnapshotList(rows) {
99466
99813
  }
99467
99814
 
99468
99815
  // src/daemon/entry/restart-orchestrator-in-flight.ts
99469
- function roleKey(chatroomId, role) {
99816
+ function roleKey2(chatroomId, role) {
99470
99817
  return `${chatroomId}:${role.toLowerCase()}`;
99471
99818
  }
99472
99819
  function markRestartOrchestratorInFlight(chatroomId, role, correlationId) {
99473
- inFlight.set(roleKey(chatroomId, role), correlationId);
99820
+ inFlight.set(roleKey2(chatroomId, role), correlationId);
99474
99821
  }
99475
99822
  function clearRestartOrchestratorInFlight(chatroomId, role, correlationId) {
99476
- const key = roleKey(chatroomId, role);
99823
+ const key = roleKey2(chatroomId, role);
99477
99824
  if (correlationId !== undefined && inFlight.get(key) !== correlationId)
99478
99825
  return;
99479
99826
  inFlight.delete(key);
99480
99827
  }
99481
99828
  function isRestartOrchestratorInFlight(chatroomId, role) {
99482
- return inFlight.has(roleKey(chatroomId, role));
99829
+ return inFlight.has(roleKey2(chatroomId, role));
99483
99830
  }
99484
99831
  function filterSnapshotsExcludingRestartInFlight(snapshots) {
99485
99832
  return snapshots.filter((row) => !isRestartOrchestratorInFlight(row.chatroomId, row.agentConfig.role));
@@ -99490,7 +99837,7 @@ var init_restart_orchestrator_in_flight = __esm(() => {
99490
99837
  });
99491
99838
 
99492
99839
  // src/daemon/entry/role-delivery-state.ts
99493
- function roleKey2(chatroomId, role) {
99840
+ function roleKey3(chatroomId, role) {
99494
99841
  return `${chatroomId}:${role.toLowerCase()}`;
99495
99842
  }
99496
99843
 
@@ -99499,10 +99846,10 @@ class RoleDeliveryState {
99499
99846
  inFlight = new Set;
99500
99847
  nativeNudgeFailures = new Map;
99501
99848
  getGeneration(chatroomId, role) {
99502
- return this.generation.get(roleKey2(chatroomId, role)) ?? 0;
99849
+ return this.generation.get(roleKey3(chatroomId, role)) ?? 0;
99503
99850
  }
99504
99851
  resetDeliveryState(chatroomId, role) {
99505
- const key = roleKey2(chatroomId, role);
99852
+ const key = roleKey3(chatroomId, role);
99506
99853
  const next4 = (this.generation.get(key) ?? 0) + 1;
99507
99854
  this.generation.set(key, next4);
99508
99855
  this.inFlight.delete(key);
@@ -99510,26 +99857,26 @@ class RoleDeliveryState {
99510
99857
  return next4;
99511
99858
  }
99512
99859
  tryAcquireDelivery(chatroomId, role) {
99513
- const key = roleKey2(chatroomId, role);
99860
+ const key = roleKey3(chatroomId, role);
99514
99861
  if (this.inFlight.has(key))
99515
99862
  return false;
99516
99863
  this.inFlight.add(key);
99517
99864
  return true;
99518
99865
  }
99519
99866
  releaseDelivery(chatroomId, role) {
99520
- this.inFlight.delete(roleKey2(chatroomId, role));
99867
+ this.inFlight.delete(roleKey3(chatroomId, role));
99521
99868
  }
99522
99869
  recordNativeNudgeFailure(chatroomId, role) {
99523
- const key = roleKey2(chatroomId, role);
99870
+ const key = roleKey3(chatroomId, role);
99524
99871
  const count3 = (this.nativeNudgeFailures.get(key) ?? 0) + 1;
99525
99872
  this.nativeNudgeFailures.set(key, count3);
99526
99873
  return count3;
99527
99874
  }
99528
99875
  clearNativeNudgeFailures(chatroomId, role) {
99529
- this.nativeNudgeFailures.delete(roleKey2(chatroomId, role));
99876
+ this.nativeNudgeFailures.delete(roleKey3(chatroomId, role));
99530
99877
  }
99531
99878
  getNativeNudgeFailures(chatroomId, role) {
99532
- return this.nativeNudgeFailures.get(roleKey2(chatroomId, role)) ?? 0;
99879
+ return this.nativeNudgeFailures.get(roleKey3(chatroomId, role)) ?? 0;
99533
99880
  }
99534
99881
  }
99535
99882
  function getRoleDeliveryState() {
@@ -99916,8 +100263,6 @@ function createStartAgentDeps(agentMgr, session2) {
99916
100263
  return {
99917
100264
  agentProcessManager: {
99918
100265
  ensureRunning: async (args2) => {
99919
- const taskSnapshotState = getNativeDeliverySession()?.taskSnapshotState;
99920
- taskSnapshotState?.setDesiredState(args2.chatroomId, args2.role, "running");
99921
100266
  const result = await exports_Effect.runPromise(agentMgr.ensureRunning({
99922
100267
  chatroomId: args2.chatroomId,
99923
100268
  role: args2.role,
@@ -99927,9 +100272,7 @@ function createStartAgentDeps(agentMgr, session2) {
99927
100272
  reason: args2.reason,
99928
100273
  wantResume: args2.wantResume
99929
100274
  }));
99930
- if (!result.success) {
99931
- taskSnapshotState?.setDesiredState(args2.chatroomId, args2.role, "stopped");
99932
- }
100275
+ if (!result.success) {}
99933
100276
  return result;
99934
100277
  }
99935
100278
  },
@@ -100052,7 +100395,6 @@ function createRecoverAgentStateDeps(agentMgr, session2) {
100052
100395
  var init_agent_control_bridge = __esm(() => {
100053
100396
  init_esm();
100054
100397
  init_api3();
100055
- init_native_delivery_session_registry();
100056
100398
  init_restart_orchestrator();
100057
100399
  });
100058
100400
 
@@ -100188,9 +100530,9 @@ var init_daemon_process_scan = __esm(() => {
100188
100530
 
100189
100531
  // src/commands/machine/pid.ts
100190
100532
  import { createHash as createHash3 } from "node:crypto";
100191
- import { existsSync as existsSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync5 } from "node:fs";
100192
- import { homedir as homedir6 } from "node:os";
100193
- import { join as join19 } from "node:path";
100533
+ import { existsSync as existsSync8, readFileSync as readFileSync10, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync6 } from "node:fs";
100534
+ import { homedir as homedir7 } from "node:os";
100535
+ import { join as join20 } from "node:path";
100194
100536
  function getUrlHash2() {
100195
100537
  const url3 = getConvexUrl();
100196
100538
  return createHash3("sha256").update(url3).digest("hex").substring(0, 8);
@@ -100200,11 +100542,11 @@ function getPidFileName() {
100200
100542
  }
100201
100543
  function ensureChatroomDir3() {
100202
100544
  if (!existsSync8(CHATROOM_DIR4)) {
100203
- mkdirSync5(CHATROOM_DIR4, { recursive: true, mode: 448 });
100545
+ mkdirSync6(CHATROOM_DIR4, { recursive: true, mode: 448 });
100204
100546
  }
100205
100547
  }
100206
100548
  function getPidFilePath() {
100207
- return join19(CHATROOM_DIR4, getPidFileName());
100549
+ return join20(CHATROOM_DIR4, getPidFileName());
100208
100550
  }
100209
100551
  function isProcessRunning(pid) {
100210
100552
  try {
@@ -100350,7 +100692,7 @@ var CHATROOM_DIR4, LOCK_RETRY_INTERVAL_MS = 500, LOCK_RETRY_MAX_WAIT_MS = 15000,
100350
100692
  var init_pid = __esm(() => {
100351
100693
  init_daemon_process_scan();
100352
100694
  init_client2();
100353
- CHATROOM_DIR4 = join19(homedir6(), ".chatroom");
100695
+ CHATROOM_DIR4 = join20(homedir7(), ".chatroom");
100354
100696
  });
100355
100697
 
100356
100698
  // src/infrastructure/machine/crash-loop-tracker.ts
@@ -102096,9 +102438,8 @@ class AgentProcessManager {
102096
102438
  console.log(` ⚠️ ${failureLog}: ${err.message}`);
102097
102439
  this.queueExitRetry({ role, args: exitArgs });
102098
102440
  });
102099
- this.deps.backend.mutation(api.daemon.agentEvents.agentExited, exitArgs).catch((err) => {
102100
- console.log(` ⚠️ Failed to apply agent exit state: ${err.message}`);
102101
- });
102441
+ const emittedAt = this.deps.clock.now();
102442
+ this.deps.lifecycleOutbox.enqueue(buildExitedLifecycleFact(exitArgs, emittedAt)).catch((err) => console.log(` ⚠️ Failed to enqueue agent exited lifecycle fact: ${err.message}`));
102102
102443
  }
102103
102444
  async clearAgentPidQuietly(chatroomId, role) {
102104
102445
  try {
@@ -102502,28 +102843,23 @@ class AgentProcessManager {
102502
102843
  }).catch((err) => {
102503
102844
  console.log(` ⚠️ Failed to record agent.started event: ${err.message}`);
102504
102845
  });
102505
- this.deps.backend.mutation(api.daemon.agentEvents.agentStarted, {
102506
- sessionId: this.deps.sessionId,
102507
- machineId: this.deps.machineId,
102846
+ const emittedAt = this.deps.clock.now();
102847
+ this.deps.lifecycleOutbox.enqueue({
102848
+ kind: "spawned",
102508
102849
  chatroomId: opts.chatroomId,
102509
102850
  role: opts.role,
102510
102851
  pid,
102511
102852
  model: opts.model,
102512
102853
  reason: opts.reason,
102513
- ...spawnResult.harnessSessionId ? { harnessSessionId: spawnResult.harnessSessionId } : {}
102514
- }).catch((err) => {
102515
- console.log(` ⚠️ Failed to apply agent.started state: ${err.message}`);
102516
- });
102517
- this.deps.backend.mutation(api.machines.updateSpawnedAgent, {
102518
- sessionId: this.deps.sessionId,
102519
- machineId: this.deps.machineId,
102520
- chatroomId: opts.chatroomId,
102521
- role: opts.role,
102522
- pid,
102523
- model: opts.model
102524
- }).catch((err) => {
102525
- console.log(` ⚠️ Failed to update PID in backend: ${err.message}`);
102526
- });
102854
+ ...spawnResult.harnessSessionId ? { harnessSessionId: spawnResult.harnessSessionId } : {},
102855
+ revisionKey: buildAgentLifecycleRevisionKey("spawned", {
102856
+ chatroomId: opts.chatroomId,
102857
+ role: opts.role,
102858
+ pid,
102859
+ emittedAt
102860
+ }),
102861
+ emittedAt
102862
+ }).catch((err) => console.log(` ⚠️ Failed to enqueue agent spawned lifecycle fact: ${err.message}`));
102527
102863
  }
102528
102864
  registerSpawnCallbacks(slot, opts, spawnResult, pid) {
102529
102865
  if (spawnResult.onLogLine) {
@@ -102878,6 +103214,11 @@ function assembleDaemonSessionInit(args2) {
102878
103214
  } = args2;
102879
103215
  deps.backend.mutation = (endpoint, args3) => client4.mutation(endpoint, args3);
102880
103216
  deps.backend.query = (endpoint, args3) => client4.query(endpoint, args3);
103217
+ const agentLifecycleOutbox = createAgentLifecycleOutboxForSession({
103218
+ sessionId: typedSessionId,
103219
+ machineId,
103220
+ backend: deps.backend
103221
+ });
102881
103222
  deps.agentProcessManager = new AgentProcessManager({
102882
103223
  logEvent: activeLogEvent ?? (async () => {
102883
103224
  return;
@@ -102893,7 +103234,8 @@ function assembleDaemonSessionInit(args2) {
102893
103234
  persistence: deps.machine,
102894
103235
  spawning: deps.spawning,
102895
103236
  crashLoop: new CrashLoopTracker,
102896
- convexUrl
103237
+ convexUrl,
103238
+ lifecycleOutbox: { enqueue: (fact) => enqueueAgentLifecycleFact(agentLifecycleOutbox, machineId, fact) }
102897
103239
  });
102898
103240
  return {
102899
103241
  client: client4,
@@ -102906,6 +103248,7 @@ function assembleDaemonSessionInit(args2) {
102906
103248
  machine: deps.machine,
102907
103249
  spawning: deps.spawning,
102908
103250
  agentProcessManager: deps.agentProcessManager,
103251
+ agentLifecycleOutbox,
102909
103252
  events: new DaemonEventBus,
102910
103253
  agentServices,
102911
103254
  lastPushedGitState: new Map,
@@ -103138,6 +103481,8 @@ var init_init_daemon = __esm(() => {
103138
103481
  init_daemon_startup_log();
103139
103482
  init_orphan_tracker();
103140
103483
  init_output_store();
103484
+ init_agent_lifecycle_outbox_runtime();
103485
+ init_agent_lifecycle_outbox_runtime();
103141
103486
  init_state_recovery();
103142
103487
  init_pid();
103143
103488
  init_storage();
@@ -105768,6 +106113,14 @@ var init_workspace_cache = __esm(() => {
105768
106113
 
105769
106114
  // src/daemon/infrastructure/git/run-command.ts
105770
106115
  import { spawn as spawn4 } from "node:child_process";
106116
+ function enqueueGit(cwd, task) {
106117
+ const tail = gitQueues.get(cwd) ?? Promise.resolve();
106118
+ const run3 = tail.then(task, task);
106119
+ gitQueues.set(cwd, run3.catch(() => {
106120
+ return;
106121
+ }));
106122
+ return run3;
106123
+ }
105771
106124
  function runCommandSpawn(command, args2, cwd, options) {
105772
106125
  const successExitCodes = options?.successExitCodes ?? [0];
105773
106126
  return new Promise((resolve4) => {
@@ -105813,7 +106166,7 @@ function runCommandSpawn(command, args2, cwd, options) {
105813
106166
  });
105814
106167
  }
105815
106168
  function runGit(args2, cwd, options) {
105816
- return runCommandSpawn("git", args2, cwd, options);
106169
+ return enqueueGit(cwd, () => runCommandSpawn("git", options?.readOnly ? ["--no-optional-locks", ...args2] : args2, cwd, options));
105817
106170
  }
105818
106171
  function runGh(args2, cwd, options) {
105819
106172
  return runCommandSpawn("gh", args2, cwd, {
@@ -105821,7 +106174,7 @@ function runGh(args2, cwd, options) {
105821
106174
  env: { ...process.env, NO_COLOR: "1" }
105822
106175
  });
105823
106176
  }
105824
- var DEFAULT_GIT_ENV;
106177
+ var DEFAULT_GIT_ENV, gitQueues;
105825
106178
  var init_run_command = __esm(() => {
105826
106179
  DEFAULT_GIT_ENV = {
105827
106180
  ...process.env,
@@ -105829,6 +106182,7 @@ var init_run_command = __esm(() => {
105829
106182
  GIT_PAGER: "cat",
105830
106183
  NO_COLOR: "1"
105831
106184
  };
106185
+ gitQueues = new Map;
105832
106186
  });
105833
106187
 
105834
106188
  // src/daemon/infrastructure/git/types.ts
@@ -105838,6 +106192,9 @@ function makeGitStateKey(machineId, workingDir) {
105838
106192
  var FULL_DIFF_MAX_BYTES = 500000, COMMITS_PER_PAGE = 20;
105839
106193
 
105840
106194
  // src/daemon/infrastructure/git/git-reader.ts
106195
+ function runGit2(args2, cwd, options) {
106196
+ return runGit(cwd ? args2 : args2, cwd, { ...options, readOnly: true });
106197
+ }
105841
106198
  function repoArgs(repoSlug) {
105842
106199
  return repoSlug ? ["--repo", repoSlug] : [];
105843
106200
  }
@@ -105854,14 +106211,14 @@ function isEmptyRepo(stderr) {
105854
106211
  return stderr.includes("does not have any commits yet") || stderr.includes("no commits yet") || stderr.includes("ambiguous argument 'HEAD'") || stderr.includes("unknown revision or path");
105855
106212
  }
105856
106213
  async function listUntrackedFiles(workingDir) {
105857
- const result = await runGit(["ls-files", "--others", "--exclude-standard"], workingDir);
106214
+ const result = await runGit2(["ls-files", "--others", "--exclude-standard"], workingDir);
105858
106215
  if ("error" in result)
105859
106216
  return [];
105860
106217
  return result.stdout.split(`
105861
106218
  `).map((line) => line.trim()).filter(Boolean);
105862
106219
  }
105863
106220
  async function getUntrackedFileDiff(workingDir, filePath) {
105864
- const result = await runGit(["diff", "--no-index", "--", NULL_DEVICE, filePath], workingDir, {
106221
+ const result = await runGit2(["diff", "--no-index", "--", NULL_DEVICE, filePath], workingDir, {
105865
106222
  successExitCodes: [0, 1]
105866
106223
  });
105867
106224
  if ("error" in result)
@@ -105922,7 +106279,7 @@ function truncateDiffContent(raw) {
105922
106279
  return { status: "available", content: raw, truncated: false };
105923
106280
  }
105924
106281
  async function runTrackedHeadDiff(workingDir, args2, options) {
105925
- const result = await runGit(args2, workingDir, options);
106282
+ const result = await runGit2(args2, workingDir, options);
105926
106283
  if ("error" in result) {
105927
106284
  const errMsg = result.error.message;
105928
106285
  if (isEmptyRepo(errMsg))
@@ -105951,13 +106308,13 @@ function classifyError(errMessage) {
105951
106308
  return { status: "error", message: errMessage.trim() };
105952
106309
  }
105953
106310
  async function isGitRepo(workingDir) {
105954
- const result = await runGit(["rev-parse", "--git-dir"], workingDir);
106311
+ const result = await runGit2(["rev-parse", "--git-dir"], workingDir);
105955
106312
  if ("error" in result)
105956
106313
  return false;
105957
106314
  return result.stdout.trim().length > 0;
105958
106315
  }
105959
106316
  async function getBranch(workingDir) {
105960
- const result = await runGit(["rev-parse", "--abbrev-ref", "HEAD"], workingDir);
106317
+ const result = await runGit2(["rev-parse", "--abbrev-ref", "HEAD"], workingDir);
105961
106318
  if ("error" in result) {
105962
106319
  const errMsg = result.error.message;
105963
106320
  if (errMsg.includes("unknown revision") || errMsg.includes("No such file or directory") || errMsg.includes("does not have any commits")) {
@@ -105972,7 +106329,7 @@ async function getBranch(workingDir) {
105972
106329
  return { status: "available", branch };
105973
106330
  }
105974
106331
  async function isDirty(workingDir) {
105975
- const result = await runGit(["status", "--porcelain"], workingDir);
106332
+ const result = await runGit2(["status", "--porcelain"], workingDir);
105976
106333
  if ("error" in result)
105977
106334
  return false;
105978
106335
  return result.stdout.trim().length > 0;
@@ -106042,7 +106399,7 @@ async function getRecentCommits(workingDir, count3 = 20, skip = 0) {
106042
106399
  if (skip > 0)
106043
106400
  logArgs.push(`--skip=${skip}`);
106044
106401
  logArgs.push(`--format=${format4}`);
106045
- const result = await runGit(logArgs, workingDir);
106402
+ const result = await runGit2(logArgs, workingDir);
106046
106403
  if ("error" in result) {
106047
106404
  return [];
106048
106405
  }
@@ -106064,7 +106421,7 @@ async function getRecentCommits(workingDir, count3 = 20, skip = 0) {
106064
106421
  return commits;
106065
106422
  }
106066
106423
  async function getCommitDetail(workingDir, sha) {
106067
- const result = await runGit(["show", sha, "--format=", "--stat", "-p"], workingDir);
106424
+ const result = await runGit2(["show", sha, "--format=", "--stat", "-p"], workingDir);
106068
106425
  if ("error" in result) {
106069
106426
  const errMsg = result.error.message;
106070
106427
  const classified = classifyError(errMsg);
@@ -106085,7 +106442,7 @@ async function getCommitDetail(workingDir, sha) {
106085
106442
  }
106086
106443
  async function getCommitMetadata(workingDir, sha) {
106087
106444
  const format4 = "%s%x1f%b%x1f%an%x1f%aI";
106088
- const result = await runGit(["log", "-1", `--format=${format4}`, sha], workingDir);
106445
+ const result = await runGit2(["log", "-1", `--format=${format4}`, sha], workingDir);
106089
106446
  if ("error" in result)
106090
106447
  return null;
106091
106448
  const output = result.stdout.trim();
@@ -106111,7 +106468,7 @@ function parseRepoSlug(remoteUrl) {
106111
106468
  return null;
106112
106469
  }
106113
106470
  async function getOriginRepoSlug(cwd) {
106114
- const result = await runGit(["remote", "get-url", "origin"], cwd);
106471
+ const result = await runGit2(["remote", "get-url", "origin"], cwd);
106115
106472
  if ("error" in result)
106116
106473
  return null;
106117
106474
  const url3 = result.stdout.trim();
@@ -106248,7 +106605,7 @@ async function getPRCommits(cwd, prNumber) {
106248
106605
  }
106249
106606
  }
106250
106607
  async function getRemotes(cwd) {
106251
- const result = await runGit(["remote", "-v"], cwd);
106608
+ const result = await runGit2(["remote", "-v"], cwd);
106252
106609
  if ("error" in result)
106253
106610
  return [];
106254
106611
  if (!result.stdout.trim())
@@ -106272,14 +106629,14 @@ async function getRemotes(cwd) {
106272
106629
  return remotes;
106273
106630
  }
106274
106631
  async function getCommitsAhead(workingDir) {
106275
- const result = await runGit(["rev-list", "--count", "@{upstream}..HEAD"], workingDir);
106632
+ const result = await runGit2(["rev-list", "--count", "@{upstream}..HEAD"], workingDir);
106276
106633
  if ("error" in result)
106277
106634
  return 0;
106278
106635
  const count3 = parseInt(result.stdout.trim(), 10);
106279
106636
  return Number.isNaN(count3) ? 0 : count3;
106280
106637
  }
106281
106638
  async function getCommitsBehind(workingDir) {
106282
- const result = await runGit(["rev-list", "--count", "HEAD..@{upstream}"], workingDir);
106639
+ const result = await runGit2(["rev-list", "--count", "HEAD..@{upstream}"], workingDir);
106283
106640
  if ("error" in result)
106284
106641
  return 0;
106285
106642
  const count3 = parseInt(result.stdout.trim(), 10);
@@ -106373,16 +106730,12 @@ class GitStatePipeline {
106373
106730
  const results = new Map(preCollected);
106374
106731
  if (this.fields.length === 0)
106375
106732
  return results;
106376
- const entries2 = await Promise.all(this.fields.filter((f) => !results.has(f.key)).map(async (field) => {
106733
+ for (const field of this.fields.filter((f) => !results.has(f.key))) {
106377
106734
  try {
106378
- const raw = await field.collect(workingDir);
106379
- return { key: field.key, raw };
106735
+ results.set(field.key, await field.collect(workingDir));
106380
106736
  } catch {
106381
- return { key: field.key, raw: field.defaultValue };
106737
+ results.set(field.key, field.defaultValue);
106382
106738
  }
106383
- }));
106384
- for (const { key, raw } of entries2) {
106385
- results.set(key, raw);
106386
106739
  }
106387
106740
  return results;
106388
106741
  }
@@ -107547,16 +107900,16 @@ var init_jsonc = __esm(() => {
107547
107900
 
107548
107901
  // src/infrastructure/services/workspace/workspace-resolver.ts
107549
107902
  import { readFile as readFile7, readdir, stat as stat3 } from "node:fs/promises";
107550
- import { join as join20, basename, resolve as resolve4 } from "node:path";
107903
+ import { join as join21, basename, resolve as resolve4 } from "node:path";
107551
107904
  async function resolveGlobPatternStar(rootDir, cleaned) {
107552
- const parentDir = join20(rootDir, cleaned.slice(0, -2));
107905
+ const parentDir = join21(rootDir, cleaned.slice(0, -2));
107553
107906
  try {
107554
107907
  const entries2 = await readdir(parentDir, { withFileTypes: true });
107555
107908
  const dirs = [];
107556
107909
  for (const entry of entries2) {
107557
107910
  if (!entry.isDirectory())
107558
107911
  continue;
107559
- const dirPath = join20(parentDir, entry.name);
107912
+ const dirPath = join21(parentDir, entry.name);
107560
107913
  if (resolve4(dirPath).startsWith(resolve4(rootDir))) {
107561
107914
  dirs.push(dirPath);
107562
107915
  }
@@ -107567,7 +107920,7 @@ async function resolveGlobPatternStar(rootDir, cleaned) {
107567
107920
  }
107568
107921
  }
107569
107922
  async function resolveLiteralPath(rootDir, cleaned) {
107570
- const dir = join20(rootDir, cleaned);
107923
+ const dir = join21(rootDir, cleaned);
107571
107924
  try {
107572
107925
  if (!resolve4(dir).startsWith(resolve4(rootDir)))
107573
107926
  return [];
@@ -107587,7 +107940,7 @@ async function resolveGlobPattern(rootDir, pattern) {
107587
107940
  }
107588
107941
  async function readPackageJson(dir) {
107589
107942
  try {
107590
- const content = await readFile7(join20(dir, "package.json"), "utf-8");
107943
+ const content = await readFile7(join21(dir, "package.json"), "utf-8");
107591
107944
  const pkg = JSON.parse(content);
107592
107945
  return {
107593
107946
  name: pkg.name || basename(dir),
@@ -107599,7 +107952,7 @@ async function readPackageJson(dir) {
107599
107952
  }
107600
107953
  async function readPnpmWorkspacePatterns(rootDir) {
107601
107954
  try {
107602
- const content = await readFile7(join20(rootDir, "pnpm-workspace.yaml"), "utf-8");
107955
+ const content = await readFile7(join21(rootDir, "pnpm-workspace.yaml"), "utf-8");
107603
107956
  const patterns = [];
107604
107957
  let inPackages = false;
107605
107958
  for (const line of content.split(`
@@ -107626,7 +107979,7 @@ async function readPnpmWorkspacePatterns(rootDir) {
107626
107979
  }
107627
107980
  async function readPackageJsonWorkspacePatterns(rootDir) {
107628
107981
  try {
107629
- const content = await readFile7(join20(rootDir, "package.json"), "utf-8");
107982
+ const content = await readFile7(join21(rootDir, "package.json"), "utf-8");
107630
107983
  const pkg = JSON.parse(content);
107631
107984
  if (!pkg.workspaces)
107632
107985
  return [];
@@ -107707,11 +108060,11 @@ var MAX_NAME_LENGTH = 256;
107707
108060
 
107708
108061
  // src/infrastructure/services/workspace/command-discovery.ts
107709
108062
  import { access as access2, readFile as readFile8 } from "node:fs/promises";
107710
- import { join as join21, relative, basename as basename2 } from "node:path";
108063
+ import { join as join22, relative, basename as basename2 } from "node:path";
107711
108064
  async function detectPackageManager(workingDir) {
107712
108065
  for (const { file: file2, manager } of LOCKFILE_MAP) {
107713
108066
  try {
107714
- await access2(join21(workingDir, file2));
108067
+ await access2(join22(workingDir, file2));
107715
108068
  return manager;
107716
108069
  } catch {}
107717
108070
  }
@@ -107780,7 +108133,7 @@ function collectRootScriptCommands(scripts, pm, scriptPrefix, rootSw) {
107780
108133
  }
107781
108134
  async function readRootPackageJson(workingDir, pm, scriptPrefix) {
107782
108135
  let rootPackageName = basename2(workingDir);
107783
- const pkg = await readJsonFile(join21(workingDir, "package.json"), "root package.json");
108136
+ const pkg = await readJsonFile(join22(workingDir, "package.json"), "root package.json");
107784
108137
  if (!pkg)
107785
108138
  return { commands: [], rootPackageName };
107786
108139
  if (pkg.name)
@@ -107796,7 +108149,7 @@ async function readRootPackageJson(workingDir, pm, scriptPrefix) {
107796
108149
  }
107797
108150
  async function readTurboJson(workingDir, _turboPrefix, _rootSubWorkspace) {
107798
108151
  const turboTaskNames = [];
107799
- const turbo = await readJsonFile(join21(workingDir, "turbo.json"), "turbo.json");
108152
+ const turbo = await readJsonFile(join22(workingDir, "turbo.json"), "turbo.json");
107800
108153
  if (!turbo?.tasks || typeof turbo.tasks !== "object")
107801
108154
  return turboTaskNames;
107802
108155
  for (const taskName of Object.keys(turbo.tasks)) {
@@ -107809,7 +108162,7 @@ async function readTurboJson(workingDir, _turboPrefix, _rootSubWorkspace) {
107809
108162
  async function readDenoJson(workingDir) {
107810
108163
  const commands = [];
107811
108164
  for (const fileName of ["deno.json", "deno.jsonc"]) {
107812
- const deno = await readJsonFile(join21(workingDir, fileName), fileName);
108165
+ const deno = await readJsonFile(join22(workingDir, fileName), fileName);
107813
108166
  if (!deno?.tasks || typeof deno.tasks !== "object")
107814
108167
  continue;
107815
108168
  const pkgName = deno.name ?? basename2(workingDir);
@@ -107832,7 +108185,7 @@ async function readMakefile(workingDir) {
107832
108185
  const commands = [];
107833
108186
  for (const fileName of ["Makefile", "makefile"]) {
107834
108187
  try {
107835
- const content = await readFile8(join21(workingDir, fileName), "utf-8");
108188
+ const content = await readFile8(join22(workingDir, fileName), "utf-8");
107836
108189
  const targets = parseMakefileTargets(content);
107837
108190
  if (targets.length === 0)
107838
108191
  continue;
@@ -110038,7 +110391,7 @@ var init_assert_registered_working_dir = __esm(() => {
110038
110391
 
110039
110392
  // src/infrastructure/services/workspace/workspace-path-security.ts
110040
110393
  import { realpath } from "node:fs/promises";
110041
- import { dirname as dirname9, isAbsolute, relative as relative2, resolve as resolve5, sep } from "node:path";
110394
+ import { dirname as dirname10, isAbsolute, relative as relative2, resolve as resolve5, sep } from "node:path";
110042
110395
  import { gunzipSync } from "node:zlib";
110043
110396
  function validateRelativePathSegments(filePath) {
110044
110397
  if (filePath.includes("\x00"))
@@ -110066,7 +110419,7 @@ function assertContained(workspaceRoot, targetPath) {
110066
110419
  return { ok: true };
110067
110420
  }
110068
110421
  async function resolveNonExistentTarget(workspaceRoot, candidate) {
110069
- let current = dirname9(candidate);
110422
+ let current = dirname10(candidate);
110070
110423
  for (;; ) {
110071
110424
  try {
110072
110425
  const ancestorReal = await realpath(current);
@@ -110084,7 +110437,7 @@ async function resolveNonExistentTarget(workspaceRoot, candidate) {
110084
110437
  if (code2 !== "ENOENT") {
110085
110438
  return { ok: false, error: "Invalid file path" };
110086
110439
  }
110087
- const parent = dirname9(current);
110440
+ const parent = dirname10(current);
110088
110441
  if (parent === current) {
110089
110442
  return { ok: false, error: "Path escapes workspace" };
110090
110443
  }
@@ -110895,16 +111248,16 @@ var require_ignore = __commonJS((exports, module) => {
110895
111248
  // src/infrastructure/services/workspace/workspace-ignore.ts
110896
111249
  import { promises as fsPromises } from "node:fs";
110897
111250
  import { readFile as readFile10 } from "node:fs/promises";
110898
- import { homedir as homedir7 } from "node:os";
111251
+ import { homedir as homedir8 } from "node:os";
110899
111252
  import path3 from "node:path";
110900
111253
  function normalizeRelativePath(relativePath) {
110901
111254
  return relativePath.replace(/\\/g, "/").replace(/^\.?\//, "").replace(/\/+$/, "");
110902
111255
  }
110903
111256
  function expandUserPath(filePath) {
110904
111257
  if (filePath === "~")
110905
- return homedir7();
111258
+ return homedir8();
110906
111259
  if (filePath.startsWith("~/"))
110907
- return path3.join(homedir7(), filePath.slice(2));
111260
+ return path3.join(homedir8(), filePath.slice(2));
110908
111261
  return filePath;
110909
111262
  }
110910
111263
  function readExcludesFileFromGitconfig(content) {
@@ -110935,11 +111288,11 @@ async function readGitconfigExcludesFilePath(configPath) {
110935
111288
  return path3.isAbsolute(raw) ? expandUserPath(raw) : path3.resolve(path3.dirname(configPath), raw);
110936
111289
  }
110937
111290
  async function resolveGitExtraExcludeFilePaths(rootDir) {
110938
- const globalConfig2 = process.env.GIT_CONFIG_GLOBAL?.length ? process.env.GIT_CONFIG_GLOBAL : path3.join(homedir7(), ".gitconfig");
111291
+ const globalConfig2 = process.env.GIT_CONFIG_GLOBAL?.length ? process.env.GIT_CONFIG_GLOBAL : path3.join(homedir8(), ".gitconfig");
110939
111292
  const localConfig = path3.join(rootDir, ".git", "config");
110940
111293
  let excludesFile = await readGitconfigExcludesFilePath(localConfig) ?? await readGitconfigExcludesFilePath(globalConfig2);
110941
111294
  if (!excludesFile) {
110942
- excludesFile = path3.join(process.env.XDG_CONFIG_HOME?.length ? process.env.XDG_CONFIG_HOME : path3.join(homedir7(), ".config"), "git", "ignore");
111295
+ excludesFile = path3.join(process.env.XDG_CONFIG_HOME?.length ? process.env.XDG_CONFIG_HOME : path3.join(homedir8(), ".config"), "git", "ignore");
110943
111296
  }
110944
111297
  const candidates = [excludesFile, path3.join(rootDir, ".git", "info", "exclude")];
110945
111298
  const existing = [];
@@ -111391,7 +111744,8 @@ function porcelainUntrackedDeletedEvents(args2) {
111391
111744
  }
111392
111745
  async function readGitHead(workTree) {
111393
111746
  const result = await runGit(["rev-parse", "HEAD"], workTree, {
111394
- timeout: GIT_POLL_TIMEOUT_MS
111747
+ timeout: GIT_POLL_TIMEOUT_MS,
111748
+ readOnly: true
111395
111749
  });
111396
111750
  if ("error" in result) {
111397
111751
  if (isEmptyRepoHeadError(result.error))
@@ -111415,7 +111769,10 @@ async function readGitPorcelainStatus(node) {
111415
111769
  const args2 = ["status", "--porcelain=v1", "-z", "-uall", "--"];
111416
111770
  if (node.pathspec.length > 0)
111417
111771
  args2.push(...node.pathspec);
111418
- const result = await runGit(args2, node.workTree, { timeout: GIT_POLL_TIMEOUT_MS });
111772
+ const result = await runGit(args2, node.workTree, {
111773
+ timeout: GIT_POLL_TIMEOUT_MS,
111774
+ readOnly: true
111775
+ });
111419
111776
  if ("error" in result) {
111420
111777
  throw new GitWorkspaceCommandError({
111421
111778
  operation: "readGitPorcelainStatus",
@@ -111553,35 +111910,31 @@ function createGitWorkspaceChangeSource(options) {
111553
111910
  let needsReconcile = false;
111554
111911
  let tickHadFailure = false;
111555
111912
  let maxNodeFailures = 0;
111556
- const results = await Promise.allSettled(nodes.map(async (node) => {
111557
- const prev = state.get(node.workTree) ?? {
111558
- prevEntries: [],
111559
- prevHead: { head: null },
111560
- baselineEstablished: false
111561
- };
111562
- const result = await pollGitWorkspaceNode({
111563
- options,
111564
- node,
111565
- prev
111566
- });
111567
- allEvents.push(...result.events);
111568
- if (result.needsReconcile)
111569
- needsReconcile = true;
111570
- state.set(node.workTree, result.nextState);
111571
- nodeFailureCounts.set(node.workTree, 0);
111572
- return node;
111573
- }));
111574
- for (let i2 = 0;i2 < results.length; i2++) {
111575
- const result = results[i2];
111576
- const node = nodes[i2];
111577
- if (!node || result.status === "fulfilled")
111578
- continue;
111579
- tickHadFailure = true;
111580
- options.onError?.(result.reason);
111581
- const prevFailures = nodeFailureCounts.get(node.workTree) ?? 0;
111582
- const nextFailures = prevFailures + 1;
111583
- nodeFailureCounts.set(node.workTree, nextFailures);
111584
- maxNodeFailures = Math.max(maxNodeFailures, nextFailures);
111913
+ for (const node of nodes) {
111914
+ try {
111915
+ const prev = state.get(node.workTree) ?? {
111916
+ prevEntries: [],
111917
+ prevHead: { head: null },
111918
+ baselineEstablished: false
111919
+ };
111920
+ const result = await pollGitWorkspaceNode({
111921
+ options,
111922
+ node,
111923
+ prev
111924
+ });
111925
+ allEvents.push(...result.events);
111926
+ if (result.needsReconcile)
111927
+ needsReconcile = true;
111928
+ state.set(node.workTree, result.nextState);
111929
+ nodeFailureCounts.set(node.workTree, 0);
111930
+ } catch (reason) {
111931
+ tickHadFailure = true;
111932
+ options.onError?.(reason);
111933
+ const prevFailures = nodeFailureCounts.get(node.workTree) ?? 0;
111934
+ const nextFailures = prevFailures + 1;
111935
+ nodeFailureCounts.set(node.workTree, nextFailures);
111936
+ maxNodeFailures = Math.max(maxNodeFailures, nextFailures);
111937
+ }
111585
111938
  }
111586
111939
  if (tickHadFailure) {
111587
111940
  consecutiveFailureTicks += 1;
@@ -111639,7 +111992,7 @@ function createGitWorkspaceChangeSource(options) {
111639
111992
  }
111640
111993
  };
111641
111994
  }
111642
- var DEFAULT_POLL_INTERVAL_MS = 1000, MAX_BACKOFF_MS = 30000, PERSISTENT_FAILURE_THRESHOLD = 3;
111995
+ var DEFAULT_POLL_INTERVAL_MS = 3000, MAX_BACKOFF_MS = 30000, PERSISTENT_FAILURE_THRESHOLD = 3;
111643
111996
  var init_git_workspace_change_source = __esm(() => {
111644
111997
  init_git_workspace_porcelain();
111645
111998
  });
@@ -112068,9 +112421,9 @@ class NodeFsHandler {
112068
112421
  if (this.fsw.closed) {
112069
112422
  return;
112070
112423
  }
112071
- const dirname11 = sp.dirname(file2);
112424
+ const dirname12 = sp.dirname(file2);
112072
112425
  const basename4 = sp.basename(file2);
112073
- const parent = this.fsw._getWatchedDir(dirname11);
112426
+ const parent = this.fsw._getWatchedDir(dirname12);
112074
112427
  let prevStats = stats;
112075
112428
  if (parent.has(basename4))
112076
112429
  return;
@@ -112097,7 +112450,7 @@ class NodeFsHandler {
112097
112450
  prevStats = newStats2;
112098
112451
  }
112099
112452
  } catch (error51) {
112100
- this.fsw._remove(dirname11, basename4);
112453
+ this.fsw._remove(dirname12, basename4);
112101
112454
  }
112102
112455
  } else if (parent.has(basename4)) {
112103
112456
  const at = newStats.atimeMs;
@@ -113486,8 +113839,8 @@ function diffPathIndexes(previous, next4) {
113486
113839
  // src/infrastructure/services/workspace/workspace-sync-state.ts
113487
113840
  import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
113488
113841
  import * as fs11 from "node:fs/promises";
113489
- import { homedir as homedir8 } from "node:os";
113490
- import { join as join24 } from "node:path";
113842
+ import { homedir as homedir9 } from "node:os";
113843
+ import { join as join25 } from "node:path";
113491
113844
  function workspaceKeyFor(workingDir) {
113492
113845
  const normalized = normalizeWorkingDirForLookup(workingDir);
113493
113846
  return createHash7("sha256").update(normalized).digest("hex").slice(0, 16);
@@ -113501,10 +113854,10 @@ function buildPathIndex(entries2) {
113501
113854
  }
113502
113855
  function manifestPath(machineId, workingDir) {
113503
113856
  const key = workspaceKeyFor(workingDir);
113504
- return join24(SYNC_STATE_DIR, machineId, key, "manifest.json");
113857
+ return join25(SYNC_STATE_DIR, machineId, key, "manifest.json");
113505
113858
  }
113506
113859
  async function ensureDir(filePath) {
113507
- await fs11.mkdir(join24(filePath, ".."), { recursive: true, mode: 448 });
113860
+ await fs11.mkdir(join25(filePath, ".."), { recursive: true, mode: 448 });
113508
113861
  }
113509
113862
  async function loadWorkspaceSyncManifest(machineId, workingDir) {
113510
113863
  try {
@@ -113564,7 +113917,7 @@ function entriesFromPathIndex(paths) {
113564
113917
  }
113565
113918
  var SYNC_STATE_VERSION = "2", SYNC_STATE_DIR;
113566
113919
  var init_workspace_sync_state = __esm(() => {
113567
- SYNC_STATE_DIR = join24(homedir8(), ".chatroom", "sync-state");
113920
+ SYNC_STATE_DIR = join25(homedir9(), ".chatroom", "sync-state");
113568
113921
  });
113569
113922
 
113570
113923
  // src/infrastructure/services/workspace/workspace-file-tree-coordinator.ts
@@ -113941,12 +114294,12 @@ var init_durable_coalescing_state_schema = __esm(() => {
113941
114294
  });
113942
114295
 
113943
114296
  // src/daemon/infrastructure/outbox/lib/durable-coalescing-state-store.ts
113944
- import { mkdirSync as mkdirSync6 } from "node:fs";
113945
- import { dirname as dirname12 } from "node:path";
113946
- import { DatabaseSync } from "node:sqlite";
114297
+ import { mkdirSync as mkdirSync7 } from "node:fs";
114298
+ import { dirname as dirname13 } from "node:path";
114299
+ import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
113947
114300
  function openDurableCoalescingStateStore(path8) {
113948
- mkdirSync6(dirname12(path8), { recursive: true });
113949
- const db = new DatabaseSync(path8);
114301
+ mkdirSync7(dirname13(path8), { recursive: true });
114302
+ const db = new DatabaseSync2(path8);
113950
114303
  for (const sql of DURABLE_COALESCING_STATE_MIGRATIONS)
113951
114304
  db.exec(sql);
113952
114305
  db.prepare("UPDATE coalescing_outbox_entries SET status='pending' WHERE status='in_flight'").run();
@@ -113963,13 +114316,6 @@ var init_durable_coalescing_state_store = __esm(() => {
113963
114316
  init_durable_coalescing_state_schema();
113964
114317
  });
113965
114318
 
113966
- // src/daemon/infrastructure/outbox/lib/outbox-retry-backoff.ts
113967
- function computeExponentialRetryDelayMs(attempt, retryDelayMs, maxRetryDelayMs) {
113968
- const exponent = Math.min(Math.max(0, attempt), MAX_RETRY_EXPONENT);
113969
- return Math.min(retryDelayMs * 2 ** exponent, maxRetryDelayMs);
113970
- }
113971
- var MAX_RETRY_EXPONENT = 20;
113972
-
113973
114319
  // src/daemon/infrastructure/outbox/lib/coalescing-state-outbox.ts
113974
114320
  function createCoalescingStateOutbox(options) {
113975
114321
  const durable = [options.store, options.deliveryKey, options.serialize, options.deserialize];
@@ -114146,14 +114492,6 @@ var init_keyed_coalescing_state_outbox_registry = __esm(() => {
114146
114492
  init_coalescing_state_outbox();
114147
114493
  });
114148
114494
 
114149
- // src/daemon/infrastructure/outbox/outbox-db-path.ts
114150
- import { homedir as homedir9 } from "node:os";
114151
- import { join as join25 } from "node:path";
114152
- function resolveOutboxDbPath(machineId, kind) {
114153
- return join25(homedir9(), ".chatroom", "daemon", machineId, `outbox-${kind}.sqlite`);
114154
- }
114155
- var init_outbox_db_path = () => {};
114156
-
114157
114495
  // src/daemon/infrastructure/outbox/workspace-file-tree-checkpoint-outbox.ts
114158
114496
  function createWorkspaceFileTreeCheckpointOutboxRegistry(machineId, createSend, options) {
114159
114497
  return createKeyedCoalescingStateOutboxRegistry({
@@ -114175,193 +114513,6 @@ var init_workspace_file_tree_checkpoint_outbox = __esm(() => {
114175
114513
  WORKSPACE_FILE_TREE_CHECKPOINT_OUTBOX_MAX_RETRY_DELAY_MS = 5 * 60000;
114176
114514
  });
114177
114515
 
114178
- // src/daemon/infrastructure/outbox/lib/durable-fifo-queue-schema.ts
114179
- var DURABLE_FIFO_QUEUE_MIGRATIONS;
114180
- var init_durable_fifo_queue_schema = __esm(() => {
114181
- DURABLE_FIFO_QUEUE_MIGRATIONS = [
114182
- `CREATE TABLE IF NOT EXISTS schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`,
114183
- `CREATE TABLE IF NOT EXISTS fifo_outbox_entries (id INTEGER PRIMARY KEY AUTOINCREMENT, delivery_key TEXT NOT NULL, payload_json TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
114184
- `CREATE INDEX IF NOT EXISTS idx_fifo_outbox_pending ON fifo_outbox_entries(delivery_key, status, id)`
114185
- ];
114186
- });
114187
-
114188
- // src/daemon/infrastructure/outbox/lib/durable-fifo-queue-store.ts
114189
- import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
114190
- import { mkdirSync as mkdirSync7 } from "node:fs";
114191
- import { dirname as dirname13 } from "node:path";
114192
- function openDurableFifoQueueStore(dbPath) {
114193
- mkdirSync7(dirname13(dbPath), { recursive: true });
114194
- const db = new DatabaseSync2(dbPath);
114195
- for (const sql of DURABLE_FIFO_QUEUE_MIGRATIONS)
114196
- db.exec(sql);
114197
- db.prepare("UPDATE fifo_outbox_entries SET status='pending', updated_at=? WHERE status='in_flight'").run(Date.now());
114198
- return {
114199
- enqueue: (key, payloadJson) => {
114200
- const now = Date.now();
114201
- return Number(db.prepare("INSERT INTO fifo_outbox_entries(delivery_key,payload_json,created_at,updated_at) VALUES(?,?,?,?) RETURNING id").get(key, payloadJson, now, now).id);
114202
- },
114203
- claimNextBatch: (key, limit) => db.prepare("UPDATE fifo_outbox_entries SET status='in_flight', attempts=attempts+1, updated_at=? WHERE id IN (SELECT id FROM fifo_outbox_entries WHERE delivery_key=? AND status='pending' ORDER BY id LIMIT ?) RETURNING id, delivery_key as deliveryKey, payload_json as payloadJson, attempts").all(Date.now(), key, limit),
114204
- markDone: (id3) => {
114205
- db.prepare("DELETE FROM fifo_outbox_entries WHERE id=?").run(id3);
114206
- },
114207
- markPending: (id3) => {
114208
- db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=NULL, updated_at=? WHERE id=?").run(Date.now(), id3);
114209
- },
114210
- updatePayload: (id3, payloadJson) => {
114211
- db.prepare("UPDATE fifo_outbox_entries SET payload_json=?, updated_at=? WHERE id=?").run(payloadJson, Date.now(), id3);
114212
- },
114213
- markPendingRetry: (id3, error51) => {
114214
- db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=?, updated_at=? WHERE id=?").run(String(error51), Date.now(), id3);
114215
- },
114216
- listPendingForRecovery: (key) => db.prepare("SELECT id, delivery_key as deliveryKey, payload_json as payloadJson, attempts FROM fifo_outbox_entries WHERE delivery_key=? AND status IN ('pending','in_flight') ORDER BY id").all(key),
114217
- close: () => db.close()
114218
- };
114219
- }
114220
- var init_durable_fifo_queue_store = __esm(() => {
114221
- init_durable_fifo_queue_schema();
114222
- });
114223
-
114224
- // src/daemon/infrastructure/outbox/lib/fifo-batched-outbox.ts
114225
- function createFifoBatchedOutbox(o) {
114226
- const waiters = new Map;
114227
- let running3;
114228
- let stopped = false;
114229
- let retryTimer;
114230
- let retryAttempt = 0;
114231
- const retryDelay = () => computeExponentialRetryDelayMs(retryAttempt++, o.retryDelayMs ?? 500, o.maxRetryDelayMs ?? 5000);
114232
- const scheduleRetry = () => {
114233
- if (!stopped && !retryTimer) {
114234
- retryTimer = setTimeout(() => {
114235
- retryTimer = undefined;
114236
- drain2().catch(() => {
114237
- return;
114238
- });
114239
- }, retryDelay());
114240
- retryTimer.unref?.();
114241
- }
114242
- };
114243
- const drain2 = async () => {
114244
- if (running3)
114245
- return running3;
114246
- running3 = (async () => {
114247
- while (true) {
114248
- const rows = o.store.claimNextBatch(o.deliveryKey, o.batchSize);
114249
- if (!rows.length)
114250
- break;
114251
- try {
114252
- const results = await o.send(rows.map((r) => o.deserialize(r.payloadJson)));
114253
- let hasRetry = false;
114254
- for (let i2 = 0;i2 < results.length; i2++) {
114255
- const item = o.deserialize(rows[i2].payloadJson);
114256
- const outcome = o.classifyOutcome?.(results[i2], item) ?? { kind: "success" };
114257
- if (outcome.kind === "retry") {
114258
- o.store.updatePayload(rows[i2].id, o.serialize(outcome.item));
114259
- o.store.markPending(rows[i2].id);
114260
- hasRetry = true;
114261
- continue;
114262
- }
114263
- o.store.markDone(rows[i2].id);
114264
- waiters.get(rows[i2].id)?.resolve(results[i2]);
114265
- waiters.delete(rows[i2].id);
114266
- }
114267
- for (let i2 = results.length;i2 < rows.length; i2++)
114268
- o.store.markPending(rows[i2].id);
114269
- if (hasRetry) {
114270
- scheduleRetry();
114271
- break;
114272
- }
114273
- retryAttempt = 0;
114274
- } catch (e) {
114275
- o.onError?.(e);
114276
- for (const r of rows)
114277
- o.store.markPendingRetry(r.id, e);
114278
- scheduleRetry();
114279
- break;
114280
- }
114281
- }
114282
- })().finally(() => {
114283
- running3 = undefined;
114284
- });
114285
- return running3;
114286
- };
114287
- const enqueue = (item) => {
114288
- if (stopped)
114289
- return Promise.reject(new Error("Outbox is stopped"));
114290
- const id3 = o.store.enqueue(o.deliveryKey, o.serialize(item));
114291
- const p = new Promise((resolve8, reject) => waiters.set(id3, { resolve: resolve8, reject }));
114292
- drain2().catch(() => {
114293
- return;
114294
- });
114295
- return p;
114296
- };
114297
- const flushNow = async () => {
114298
- while (o.store.listPendingForRecovery(o.deliveryKey).length) {
114299
- await drain2();
114300
- }
114301
- };
114302
- const stop4 = async () => {
114303
- if (stopped)
114304
- return;
114305
- if (retryTimer)
114306
- clearTimeout(retryTimer);
114307
- retryTimer = undefined;
114308
- await flushNow();
114309
- stopped = true;
114310
- };
114311
- return { enqueue, flushNow, stop: stop4 };
114312
- }
114313
- var init_fifo_batched_outbox = () => {};
114314
-
114315
- // src/daemon/infrastructure/outbox/lib/keyed-fifo-batched-outbox-registry.ts
114316
- function createKeyedFifoBatchedOutboxRegistry(o) {
114317
- const boxes = new Map;
114318
- const get13 = (key) => {
114319
- let b = boxes.get(key);
114320
- if (!b) {
114321
- b = createFifoBatchedOutbox({
114322
- batchSize: o.batchSize,
114323
- send: o.createSend(key),
114324
- store: o.store,
114325
- deliveryKey: key,
114326
- serialize: o.serialize,
114327
- deserialize: o.deserialize,
114328
- retryDelayMs: o.retryDelayMs,
114329
- maxRetryDelayMs: o.maxRetryDelayMs,
114330
- onError: (e) => o.onError?.(key, e),
114331
- classifyOutcome: o.classifyOutcome
114332
- });
114333
- boxes.set(key, b);
114334
- }
114335
- return b;
114336
- };
114337
- const stop4 = async (k) => {
114338
- const b = boxes.get(k);
114339
- if (b) {
114340
- await b.stop();
114341
- boxes.delete(k);
114342
- }
114343
- };
114344
- return {
114345
- enqueue: (k, i2) => get13(k).enqueue(i2),
114346
- flushNow: async (k) => {
114347
- if (k)
114348
- await get13(k).flushNow();
114349
- else
114350
- for (const b of boxes.values())
114351
- await b.flushNow();
114352
- },
114353
- stop: stop4,
114354
- stopAll: async () => {
114355
- for (const k of [...boxes.keys()])
114356
- await stop4(k);
114357
- o.store.close();
114358
- }
114359
- };
114360
- }
114361
- var init_keyed_fifo_batched_outbox_registry = __esm(() => {
114362
- init_fifo_batched_outbox();
114363
- });
114364
-
114365
114516
  // src/daemon/infrastructure/outbox/workspace-file-tree-delta-outbox.ts
114366
114517
  function createWorkspaceFileTreeDeltaOutboxRegistry(machineId, createSend, options) {
114367
114518
  const store = openDurableFifoQueueStore(resolveOutboxDbPath(machineId, "file-tree-delta"));
@@ -114396,6 +114547,8 @@ var init_workspace_file_tree_delta_outbox = __esm(() => {
114396
114547
  var init_outbox = __esm(() => {
114397
114548
  init_workspace_file_tree_checkpoint_outbox();
114398
114549
  init_workspace_file_tree_delta_outbox();
114550
+ init_agent_lifecycle_outbox();
114551
+ init_agent_lifecycle_send();
114399
114552
  });
114400
114553
 
114401
114554
  // ../../services/backend/src/domain/workspace-file-tree/types.ts
@@ -115804,7 +115957,8 @@ var init_command_run_subscription = __esm(() => {
115804
115957
  // src/daemon/entry/task-delivery/task-delivery-logic.ts
115805
115958
  function isPendingAliveRunningTask(task) {
115806
115959
  const { agentConfig, status: status3 } = task;
115807
- return status3 === "pending" && agentConfig.spawnedAgentPid != null && isAgentDesiredRunning(agentConfig.desiredState);
115960
+ const op = getNativeDeliverySession()?.agentOperationalReadModel?.get(task.chatroomId, agentConfig.role);
115961
+ return status3 === "pending" && (agentConfig.spawnedAgentPid != null || op?.isAlive === true) && isOperationalDesiredRunning(op);
115808
115962
  }
115809
115963
  function isSlotUnavailableForPid(slot, pid, isPidAlive, now = Date.now()) {
115810
115964
  if (!slot) {
@@ -115847,7 +116001,8 @@ function isNativeAgentSlotDown(task, health, now = Date.now()) {
115847
116001
  function isNativeActiveTaskAgentDown(task, health, now) {
115848
116002
  if (!isNativeHarness(task.agentConfig.agentHarness))
115849
116003
  return false;
115850
- if (!isAgentDesiredRunning(task.agentConfig.desiredState))
116004
+ const op = getNativeDeliverySession()?.agentOperationalReadModel?.get(task.chatroomId, task.agentConfig.role);
116005
+ if (!isOperationalDesiredRunning(op))
115851
116006
  return false;
115852
116007
  if (!isNativeRevivableTaskStatus(task))
115853
116008
  return false;
@@ -115871,7 +116026,8 @@ function isNativePendingTaskNeedingWake(task) {
115871
116026
  return false;
115872
116027
  if (task.status !== "pending")
115873
116028
  return false;
115874
- if (isAgentDesiredRunning(task.agentConfig.desiredState))
116029
+ const op = getNativeDeliverySession()?.agentOperationalReadModel?.get(task.chatroomId, task.agentConfig.role);
116030
+ if (isOperationalDesiredRunning(op))
115875
116031
  return false;
115876
116032
  return Boolean(task.agentConfig.workingDir);
115877
116033
  }
@@ -115947,10 +116103,10 @@ function listTasksReadyForNudge(tasks, now, cooldown, getSlot) {
115947
116103
  }
115948
116104
  var PENDING_IDLE_NUDGE_MS = 15000, NUDGE_COOLDOWN_MS = 60000;
115949
116105
  var init_task_delivery_logic = __esm(() => {
115950
- init_assigned_task();
115951
116106
  init_check_agent_slot();
115952
116107
  init_predicates();
115953
116108
  init_agent_process_manager();
116109
+ init_native_delivery_session_registry();
115954
116110
  init_native_ready_invariant();
115955
116111
  init_native_task_injector_logic();
115956
116112
  });
@@ -116050,7 +116206,7 @@ function runNativeWakeEffect(task, runtime4, effectContext2, agentMgr) {
116050
116206
  if (!ctx)
116051
116207
  return;
116052
116208
  const { chatroomId, agentConfig, role, workingDir, wantResume } = ctx;
116053
- console.log(`[TaskMonitor] native wake ${role}@${chatroomId} — desiredState=stopped with pending task ${task.taskId}`);
116209
+ console.log(`[TaskMonitor] native wake ${role}@${chatroomId} — operational_state=stopped with pending task ${task.taskId}`);
116054
116210
  exports_Runtime.runFork(runtime4)(exports_Effect.gen(function* () {
116055
116211
  yield* agentMgr.ensureRunning({
116056
116212
  chatroomId,
@@ -116152,6 +116308,31 @@ var init_task_delivery_processor = __esm(() => {
116152
116308
  init_task_delivery_logic();
116153
116309
  });
116154
116310
 
116311
+ // src/daemon/infrastructure/agent-operational/enrich-snapshot-with-operational.ts
116312
+ function enrichSnapshotWithOperational(snapshot) {
116313
+ const op = getNativeDeliverySession()?.agentOperationalReadModel?.get(snapshot.chatroomId, snapshot.agentConfig.role);
116314
+ if (!op)
116315
+ return snapshot;
116316
+ return { ...snapshot, agentConfig: { ...snapshot.agentConfig, desiredState: isOperationalDesiredRunning(op) ? "running" : "stopped" } };
116317
+ }
116318
+ function enrichSnapshotsWithOperational(snapshots) {
116319
+ return snapshots.map(enrichSnapshotWithOperational);
116320
+ }
116321
+ var init_enrich_snapshot_with_operational = __esm(() => {
116322
+ init_native_delivery_session_registry();
116323
+ });
116324
+
116325
+ // src/daemon/infrastructure/agent-operational/subscribe-machine-agent-operational-status.ts
116326
+ function subscribeMachineAgentOperationalStatus(client4, options, onRows) {
116327
+ return client4.onUpdate(api.machines.subscribeMachineAgentOperationalStatus, { sessionId: options.sessionId, machineId: options.machineId }, (result) => {
116328
+ if (Array.isArray(result))
116329
+ onRows(result);
116330
+ });
116331
+ }
116332
+ var init_subscribe_machine_agent_operational_status = __esm(() => {
116333
+ init_api3();
116334
+ });
116335
+
116155
116336
  // src/daemon/infrastructure/inbox/fetch-machine-assigned-task-snapshots.ts
116156
116337
  async function fetchMachineAssignedTaskSnapshots(sessionDeps, machineId) {
116157
116338
  const result = await sessionDeps.backend.query(api.machines.listMachineAssignedTaskSnapshots, {
@@ -116321,11 +116502,12 @@ async function handleTaskInboxUpdate(update6, deps) {
116321
116502
  taskSnapshotState?.applySignalPage(update6.signals, update6.snapshots);
116322
116503
  if (update6.snapshots.length === 0)
116323
116504
  return;
116324
- await processTasksUpdate(deps.runtime, deps.effectContext, deps.cooldown, deps.agentMgr, deps.sessionDeps, deps.machineId, "inbox-signal", { snapshots: update6.snapshots });
116505
+ await processTasksUpdate(deps.runtime, deps.effectContext, deps.cooldown, deps.agentMgr, deps.sessionDeps, deps.machineId, "inbox-signal", { snapshots: enrichSnapshotsWithOperational(update6.snapshots) });
116325
116506
  }
116326
116507
  var init_task_inbox_delivery = __esm(() => {
116327
116508
  init_native_delivery_session_registry();
116328
116509
  init_task_delivery_processor();
116510
+ init_enrich_snapshot_with_operational();
116329
116511
  });
116330
116512
 
116331
116513
  // src/daemon/infrastructure/inbox/task.ts
@@ -116435,6 +116617,10 @@ var init_task = __esm(() => {
116435
116617
 
116436
116618
  // src/daemon/entry/task-inbox-runtime.ts
116437
116619
  async function bootstrapMachineAssignedTaskSnapshots(deps) {
116620
+ await deps.sessionDeps.backend.mutation(api.machines.backfillAgentOperationalStatusForMachine, {
116621
+ sessionId: deps.sessionDeps.sessionId,
116622
+ machineId: deps.machineId
116623
+ });
116438
116624
  await deps.sessionDeps.backend.mutation(api.machines.syncMachineAssignedTaskSnapshotsMutation, {
116439
116625
  sessionId: deps.sessionDeps.sessionId,
116440
116626
  machineId: deps.machineId
@@ -116443,7 +116629,7 @@ async function bootstrapMachineAssignedTaskSnapshots(deps) {
116443
116629
  deps.taskSnapshotState?.replace(tasks);
116444
116630
  if (!tasks.length)
116445
116631
  return;
116446
- await processTasksUpdate(deps.runtime, deps.effectContext, deps.cooldown, deps.agentMgr, deps.sessionDeps, deps.machineId, "bootstrap", { snapshots: tasks });
116632
+ await processTasksUpdate(deps.runtime, deps.effectContext, deps.cooldown, deps.agentMgr, deps.sessionDeps, deps.machineId, "bootstrap", { snapshots: enrichSnapshotsWithOperational(tasks) });
116447
116633
  }
116448
116634
  function isAbortError(error51) {
116449
116635
  return error51 instanceof Error && error51.name === "AbortError";
@@ -116487,13 +116673,15 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
116487
116673
  const abort = new AbortController;
116488
116674
  let stopped = false;
116489
116675
  const taskSnapshotState = new MachineTaskSnapshotState;
116676
+ const agentOperationalReadModel = new AgentOperationalReadModel;
116490
116677
  registerNativeDeliverySession({
116491
116678
  runtime: runtime4,
116492
116679
  effectContext: effectContext2,
116493
116680
  agentMgr,
116494
116681
  sessionDeps,
116495
116682
  machineId: session2.machineId,
116496
- taskSnapshotState
116683
+ taskSnapshotState,
116684
+ agentOperationalReadModel
116497
116685
  });
116498
116686
  const cooldown = new RecoveryCooldown;
116499
116687
  let inboxUpdateInFlight = false;
@@ -116535,11 +116723,24 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
116535
116723
  console.warn("[TaskInbox] bootstrap failed:", error51);
116536
116724
  return exports_Effect.void;
116537
116725
  }));
116726
+ const unsubscribeOperational = subscribeMachineAgentOperationalStatus(wsClient2, {
116727
+ sessionId: session2.sessionId,
116728
+ machineId: session2.machineId,
116729
+ signal: abort.signal
116730
+ }, (rows) => {
116731
+ if (stopped)
116732
+ return;
116733
+ const changed = agentOperationalReadModel.replace(rows);
116734
+ const snapshots = changed.flatMap(({ chatroomId, role }) => taskSnapshotState.listForRole(chatroomId, role));
116735
+ if (snapshots.length === 0)
116736
+ return;
116737
+ processTasksUpdate(runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "operational-status", { snapshots: enrichSnapshotsWithOperational(snapshots) }).catch((error51) => console.warn("[TaskInbox] operational-status reconcile failed:", error51));
116738
+ }) ?? (() => {});
116538
116739
  const reconcileTimer = setInterval(() => {
116539
116740
  if (stopped || inboxUpdateInFlight || reconcileInFlight)
116540
116741
  return;
116541
116742
  reconcileInFlight = true;
116542
- processTasksUpdate(runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "periodic-reconcile", { snapshots: taskSnapshotState.listAll() }).catch((error51) => {
116743
+ processTasksUpdate(runtime4, effectContext2, cooldown, agentMgr, sessionDeps, session2.machineId, "periodic-reconcile", { snapshots: enrichSnapshotsWithOperational(taskSnapshotState.listAll()) }).catch((error51) => {
116543
116744
  console.warn("[TaskInbox] local delivery reconciliation failed:", error51);
116544
116745
  }).finally(() => {
116545
116746
  reconcileInFlight = false;
@@ -116549,6 +116750,7 @@ var NATIVE_DELIVERY_RECONCILE_MS = 1e4, INBOX_RESTART_INITIAL_MS = 1000, INBOX_R
116549
116750
  return {
116550
116751
  stop() {
116551
116752
  stopped = true;
116753
+ unsubscribeOperational();
116552
116754
  abort.abort();
116553
116755
  clearInterval(reconcileTimer);
116554
116756
  unregisterNativeDeliverySession();
@@ -116563,6 +116765,8 @@ var init_task_inbox_runtime = __esm(() => {
116563
116765
  init_native_delivery_session_registry();
116564
116766
  init_task_delivery_processor();
116565
116767
  init_task_delivery_logic();
116768
+ init_enrich_snapshot_with_operational();
116769
+ init_subscribe_machine_agent_operational_status();
116566
116770
  init_fetch_machine_assigned_task_snapshots();
116567
116771
  init_inbox();
116568
116772
  init_task_inbox_delivery();
@@ -117020,6 +117224,9 @@ function createDaemonRuntime(deps) {
117020
117224
  shutdownWatchdog.unref?.();
117021
117225
  if (heartbeatTimer)
117022
117226
  clearInterval(heartbeatTimer);
117227
+ await deps.agentLifecycleOutbox?.stopAll().catch(() => {
117228
+ return;
117229
+ });
117023
117230
  stopWorkers();
117024
117231
  await withTimeout2(exports_Effect.runPromise(exports_Effect.gen(function* () {
117025
117232
  const effectContext2 = yield* exports_Effect.context();
@@ -132841,7 +133048,11 @@ async function startDaemon() {
132841
133048
  console.log(`[daemon] Local web UI: http://127.0.0.1:${localWeb.port}/`);
132842
133049
  const layers = daemonSessionToLayers(init2);
132843
133050
  startBackgroundMachineCapabilitiesDiscovery(createStartBackgroundCapabilitiesDiscoveryDeps(layers));
132844
- const runtime4 = createDaemonRuntime({ wsClient: wsClient2, layers });
133051
+ const runtime4 = createDaemonRuntime({
133052
+ wsClient: wsClient2,
133053
+ layers,
133054
+ agentLifecycleOutbox: init2.agentLifecycleOutbox
133055
+ });
132845
133056
  try {
132846
133057
  await runtime4.run();
132847
133058
  } finally {
@@ -134086,4 +134297,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
134086
134297
  });
134087
134298
  program2.parse();
134088
134299
 
134089
- //# debugId=D3E73C85EB221DCE64756E2164756E21
134300
+ //# debugId=D5DF842800E395EE64756E2164756E21