@buildautomaton/cli 0.1.72 → 0.1.74

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/cli.js CHANGED
@@ -11850,8 +11850,8 @@ var init_task_queue_types = __esm({
11850
11850
  });
11851
11851
 
11852
11852
  // src/code-nav/symbol-index/scheduler/task-queue-store.ts
11853
- function setSymbolIndexWorkerRunning(running) {
11854
- symbolIndexWorkerRunning = running;
11853
+ function setSymbolIndexWorkerRunning(running2) {
11854
+ symbolIndexWorkerRunning = running2;
11855
11855
  }
11856
11856
  function taskMatchesCurrentPending(task) {
11857
11857
  const current = pendingSymbolIndexTasks.get(symbolIndexTaskKey(task.parentPath, task.filePath));
@@ -31064,7 +31064,7 @@ var {
31064
31064
  } = import_index.default;
31065
31065
 
31066
31066
  // src/cli-version.ts
31067
- var CLI_VERSION = "0.1.72".length > 0 ? "0.1.72" : "0.0.0-dev";
31067
+ var CLI_VERSION = "0.1.74".length > 0 ? "0.1.74" : "0.0.0-dev";
31068
31068
 
31069
31069
  // src/cli/defaults.ts
31070
31070
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
@@ -35985,12 +35985,32 @@ function attachSdkStdioStderrAuthWatch(options) {
35985
35985
 
35986
35986
  // src/agents/acp/clients/sdk/spawn-sdk-stdio-process.ts
35987
35987
  import { spawn } from "node:child_process";
35988
+
35989
+ // src/agents/acp/clients/bridge-installed-agent-auth-env.ts
35990
+ var authEnv = /* @__PURE__ */ new Map();
35991
+ function setBridgeInstalledAgentAuthEnv(entries) {
35992
+ authEnv.clear();
35993
+ for (const entry of entries) {
35994
+ const envVar = typeof entry.envVar === "string" ? entry.envVar.trim() : "";
35995
+ const token = typeof entry.token === "string" ? entry.token.trim() : "";
35996
+ if (envVar && token) authEnv.set(envVar, token);
35997
+ }
35998
+ }
35999
+ function bridgeInstalledAgentAuthProcessEnv(base = process.env) {
36000
+ if (authEnv.size === 0) return base;
36001
+ return { ...base, ...Object.fromEntries(authEnv) };
36002
+ }
36003
+ function cursorAgentUsesApiKeyAuth(env = process.env) {
36004
+ return Boolean(env.CURSOR_API_KEY?.trim() || env.CURSOR_AUTH_TOKEN?.trim());
36005
+ }
36006
+
36007
+ // src/agents/acp/clients/sdk/spawn-sdk-stdio-process.ts
35988
36008
  function spawnSdkStdioProcess(options) {
35989
36009
  const isWindows = process.platform === "win32";
35990
36010
  const child = spawn(options.command[0], options.command.slice(1), {
35991
36011
  cwd: options.cwd,
35992
36012
  stdio: ["pipe", "pipe", "pipe"],
35993
- env: process.env,
36013
+ env: bridgeInstalledAgentAuthProcessEnv(process.env),
35994
36014
  shell: isWindows
35995
36015
  });
35996
36016
  const stderrCapture = createStderrCapture(child);
@@ -36450,10 +36470,11 @@ function createCursorAcpIncomingLineHandler(deps) {
36450
36470
 
36451
36471
  // src/agents/acp/clients/cursor/cursor-json-rpc-acp-transport.ts
36452
36472
  function createCursorJsonRpcAcpTransport(deps) {
36453
- const { send, cancelSessionNotification } = deps;
36473
+ const { send, cancelSessionNotification, skipBrowserAuthenticate } = deps;
36454
36474
  return {
36455
36475
  initialize: (request) => send("initialize", request),
36456
36476
  afterInitialize: async () => {
36477
+ if (skipBrowserAuthenticate) return;
36457
36478
  await send("authenticate", { methodId: "cursor_login" });
36458
36479
  },
36459
36480
  resumeSession: (p) => send("session/resume", p),
@@ -36562,7 +36583,8 @@ async function initCursorAcpWire(options) {
36562
36583
  rl.on("line", (line) => incoming.handleLine(line));
36563
36584
  const transport = createCursorJsonRpcAcpTransport({
36564
36585
  send: wire.send,
36565
- cancelSessionNotification: wire.cancelSessionNotification
36586
+ cancelSessionNotification: wire.cancelSessionNotification,
36587
+ skipBrowserAuthenticate: options.skipBrowserAuthenticate
36566
36588
  });
36567
36589
  const established = await bootstrapAcpWireSession(transport, options.sessionCtx, CURSOR_ACP_CLIENT_INFO);
36568
36590
  return { wire, transport, established, incoming, pendingRequests: pendingRequests2 };
@@ -36575,7 +36597,7 @@ function spawnCursorAcpProcess(options) {
36575
36597
  const child = spawn2(options.command[0], options.command.slice(1), {
36576
36598
  cwd: options.cwd,
36577
36599
  stdio: ["pipe", "pipe", "pipe"],
36578
- env: process.env,
36600
+ env: bridgeInstalledAgentAuthProcessEnv(process.env),
36579
36601
  shell: isWindows
36580
36602
  });
36581
36603
  const stderrCapture = createStderrCapture(child);
@@ -36607,11 +36629,13 @@ async function createCursorAcpClient(options) {
36607
36629
  onAgentSubprocessExit
36608
36630
  } = options;
36609
36631
  const dbgFs = process.env.BUILDAUTOMATON_DEBUG_ACP_FS === "1";
36632
+ const spawnEnv = bridgeInstalledAgentAuthProcessEnv(process.env);
36610
36633
  const { child, stderrCapture } = spawnCursorAcpProcess({
36611
36634
  command,
36612
36635
  cwd,
36613
36636
  onAgentSubprocessExit
36614
36637
  });
36638
+ const skipBrowserAuthenticate = cursorAgentUsesApiKeyAuth(spawnEnv);
36615
36639
  const sessionCtx = createCursorAcpSessionContext({
36616
36640
  cwd,
36617
36641
  mcpServers: options.mcpServers,
@@ -36634,6 +36658,7 @@ async function createCursorAcpClient(options) {
36634
36658
  const { wire, transport, established, incoming, pendingRequests: pendingRequests2 } = await initCursorAcpWire({
36635
36659
  child,
36636
36660
  sessionCtx,
36661
+ skipBrowserAuthenticate,
36637
36662
  incomingDeps: { dbgFs, sessionCtx, onSessionUpdate, onRequest }
36638
36663
  });
36639
36664
  resolve37(
@@ -37480,6 +37505,7 @@ function extractSessionUpdateMessageText(params) {
37480
37505
  }
37481
37506
 
37482
37507
  // src/agents/planning/planning-session-turn-buffer.ts
37508
+ var MAX_PLANNING_BUFFER_CHARS = 512 * 1024;
37483
37509
  var buffersByRunId = /* @__PURE__ */ new Map();
37484
37510
  function registerPlanningSessionTurn(runId) {
37485
37511
  buffersByRunId.set(runId, { messageBuffer: "" });
@@ -37497,7 +37523,10 @@ function capturePlanningSessionUpdate(params) {
37497
37523
  });
37498
37524
  if (bucket !== "message") return false;
37499
37525
  const text = extractSessionUpdateMessageText(params.payload);
37500
- if (text) state.messageBuffer += text;
37526
+ if (text && state.messageBuffer.length < MAX_PLANNING_BUFFER_CHARS) {
37527
+ const room = MAX_PLANNING_BUFFER_CHARS - state.messageBuffer.length;
37528
+ state.messageBuffer += room >= text.length ? text : text.slice(0, room);
37529
+ }
37501
37530
  return true;
37502
37531
  }
37503
37532
  function getPlanningSessionTurnOutput(runId) {
@@ -39391,11 +39420,30 @@ function closeHttpServer(server) {
39391
39420
  }
39392
39421
 
39393
39422
  // src/mcp/bridge-access/read-json-body.ts
39423
+ var MAX_JSON_BODY_BYTES = 1024 * 1024;
39424
+ var RequestBodyTooLargeError = class extends Error {
39425
+ constructor() {
39426
+ super(`Request body exceeds ${MAX_JSON_BODY_BYTES} bytes`);
39427
+ }
39428
+ };
39394
39429
  function readJsonBody(req) {
39395
39430
  return new Promise((resolve37, reject) => {
39396
39431
  const chunks = [];
39397
- req.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
39432
+ let total = 0;
39433
+ let tooLarge = false;
39434
+ req.on("data", (chunk) => {
39435
+ if (tooLarge) return;
39436
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
39437
+ total += buf.length;
39438
+ if (total > MAX_JSON_BODY_BYTES) {
39439
+ tooLarge = true;
39440
+ reject(new RequestBodyTooLargeError());
39441
+ return;
39442
+ }
39443
+ chunks.push(buf);
39444
+ });
39398
39445
  req.on("end", () => {
39446
+ if (tooLarge) return;
39399
39447
  try {
39400
39448
  const raw = Buffer.concat(chunks).toString("utf8").trim();
39401
39449
  if (!raw) {
@@ -39452,7 +39500,7 @@ function createBridgeAccessRequestHandler(registry2) {
39452
39500
  sendJsonResponse(res, 404, { ok: false, error: "Not found" });
39453
39501
  } catch (err) {
39454
39502
  const message = err instanceof Error ? err.message : String(err);
39455
- sendJsonResponse(res, 500, { ok: false, error: message });
39503
+ sendJsonResponse(res, err instanceof RequestBodyTooLargeError ? 413 : 500, { ok: false, error: message });
39456
39504
  }
39457
39505
  })();
39458
39506
  };
@@ -49962,7 +50010,7 @@ init_yield_to_event_loop();
49962
50010
 
49963
50011
  // src/files/read/types.ts
49964
50012
  var LINE_CHUNK_SIZE = 64 * 1024;
49965
- var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
50013
+ var READ_RANGE_YIELD_EVERY_BYTES = 64 * 1024;
49966
50014
 
49967
50015
  // src/files/read/guess-mime-type.ts
49968
50016
  var MIME_BY_EXT = {
@@ -51554,6 +51602,7 @@ function buildBridgeUrl(apiUrl, workspaceId, authToken) {
51554
51602
  var API_TO_BRIDGE_MESSAGE_TYPES = [
51555
51603
  "auth_token",
51556
51604
  "bridge_identified",
51605
+ "installed_agent_auth_sync",
51557
51606
  "ha",
51558
51607
  "preview_environments_config",
51559
51608
  "preview_environment_control",
@@ -51642,6 +51691,16 @@ var handleBridgeIdentified = (msg, deps) => {
51642
51691
  });
51643
51692
  };
51644
51693
 
51694
+ // src/routing/handlers/installed-agent-auth-sync.ts
51695
+ var handleInstalledAgentAuthSync = (msg) => {
51696
+ const entries = Array.isArray(msg.entries) ? msg.entries : [];
51697
+ setBridgeInstalledAgentAuthEnv(
51698
+ entries.filter(
51699
+ (e) => e != null && typeof e === "object" && typeof e.envVar === "string" && typeof e.token === "string"
51700
+ )
51701
+ );
51702
+ };
51703
+
51645
51704
  // src/connection/heartbeat/ack.ts
51646
51705
  var handleBridgeHeartbeatAck = (msg, deps) => {
51647
51706
  const raw = msg.s;
@@ -51658,6 +51717,9 @@ function dispatchBridgeConnectionMessage(msg, deps) {
51658
51717
  case "bridge_identified":
51659
51718
  handleBridgeIdentified(msg, deps);
51660
51719
  break;
51720
+ case "installed_agent_auth_sync":
51721
+ handleInstalledAgentAuthSync(msg, deps);
51722
+ break;
51661
51723
  case "ha":
51662
51724
  handleBridgeHeartbeatAck(msg, deps);
51663
51725
  break;
@@ -51754,16 +51816,8 @@ var handleAgentConfigMessage = (msg, deps) => {
51754
51816
  handleBridgeAgentConfig(msg, deps);
51755
51817
  };
51756
51818
 
51757
- // src/prompt-turn-queue/client-report.ts
51758
- function sendPromptQueueClientReport(ws, queues) {
51759
- if (!ws) return false;
51760
- const wireQueues = {};
51761
- for (const [queueKey, rows] of Object.entries(queues)) {
51762
- wireQueues[queueKey] = rows.map((r) => ({ turnId: r.turnId, clientState: r.cliState }));
51763
- }
51764
- sendWsMessage(ws, { type: "prompt_queue_client_report", queues: wireQueues });
51765
- return true;
51766
- }
51819
+ // src/prompt-turn-queue/runner/dispatch-started-prompt-queue-runs.ts
51820
+ init_yield_to_event_loop();
51767
51821
 
51768
51822
  // src/prompt-turn-queue/disk-store.ts
51769
51823
  init_cli_database();
@@ -51855,23 +51909,6 @@ function dispatchLocalPrompt(next, deps) {
51855
51909
  handleBridgePrompt(msg, deps);
51856
51910
  }
51857
51911
 
51858
- // src/prompt-turn-queue/runner/queue-selection.ts
51859
- function pickNextRunnableTurn(turns) {
51860
- for (const t of turns) {
51861
- if (t.bridgeServerState === "discarded" || t.bridgeServerState === "stopping") continue;
51862
- if (t.bridgeServerState === "cancel_requested") continue;
51863
- if (!isRunnableBridgePromptTurnServerState(t.bridgeServerState)) continue;
51864
- if (t.lastCliState === "running" || t.lastCliState === "stopped" || t.lastCliState === "failed" || t.lastCliState === "cancelled") {
51865
- continue;
51866
- }
51867
- return t;
51868
- }
51869
- return null;
51870
- }
51871
- function hasRunningTurn(turns) {
51872
- return turns.some((t) => t.lastCliState === "running");
51873
- }
51874
-
51875
51912
  // src/prompt-turn-queue/runner/run-id-queue-key-map.ts
51876
51913
  var runIdToQueueKey = /* @__PURE__ */ new Map();
51877
51914
  function getRunIdQueueKey(runId) {
@@ -51886,11 +51923,123 @@ function deleteRunIdQueueKey(runId) {
51886
51923
  return queueKey;
51887
51924
  }
51888
51925
  function syncRunningTurnQueueKeys(turns, queueKey) {
51889
- for (const running of turns.filter((t) => t.lastCliState === "running")) {
51890
- runIdToQueueKey.set(running.turnId, queueKey);
51926
+ for (const running2 of turns.filter((t) => t.lastCliState === "running")) {
51927
+ runIdToQueueKey.set(running2.turnId, queueKey);
51928
+ }
51929
+ }
51930
+
51931
+ // src/prompt-turn-queue/runner/dispatch-started-prompt-queue-runs.ts
51932
+ async function dispatchStartedPromptQueueRuns(entries, started, deps) {
51933
+ for (const [queueKey] of entries) {
51934
+ const file2 = await readPersistedQueue(queueKey);
51935
+ const running2 = file2?.turns.find((turn) => turn.lastCliState === "running");
51936
+ if (running2 && started.has(running2.turnId) && getRunIdQueueKey(running2.turnId) === queueKey) {
51937
+ dispatchLocalPrompt(running2, deps);
51938
+ }
51939
+ await yieldToEventLoop();
51940
+ }
51941
+ }
51942
+
51943
+ // src/prompt-turn-queue/runner/handle-prompt-queue-cancellations.ts
51944
+ init_yield_to_event_loop();
51945
+
51946
+ // src/prompt-turn-queue/client-report.ts
51947
+ function sendPromptQueueClientReport(ws, queues) {
51948
+ if (!ws) return false;
51949
+ const wireQueues = {};
51950
+ for (const [queueKey, rows] of Object.entries(queues)) {
51951
+ wireQueues[queueKey] = rows.map((r) => ({ turnId: r.turnId, clientState: r.cliState }));
51952
+ }
51953
+ sendWsMessage(ws, { type: "prompt_queue_client_report", queues: wireQueues });
51954
+ return true;
51955
+ }
51956
+
51957
+ // src/prompt-turn-queue/runner/finalize-prompt-turn-on-bridge.ts
51958
+ async function finalizePromptTurnOnBridge(getWs, runId, success2, opts) {
51959
+ if (!runId) return false;
51960
+ const queueKey = deleteRunIdQueueKey(runId);
51961
+ if (!queueKey) return false;
51962
+ const f = await readPersistedQueue(queueKey);
51963
+ if (!f) return false;
51964
+ const t = f.turns.find((x) => x.turnId === runId);
51965
+ if (!t) return false;
51966
+ t.lastCliState = opts?.terminalCliState ?? (success2 ? "stopped" : "failed");
51967
+ await writePersistedQueue(f);
51968
+ sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: runId, cliState: t.lastCliState }] });
51969
+ return true;
51970
+ }
51971
+
51972
+ // src/prompt-turn-queue/runner/handle-prompt-queue-cancellations.ts
51973
+ async function handlePromptQueueCancellations(entries, deps) {
51974
+ for (const [queueKey] of entries) {
51975
+ const file2 = await readPersistedQueue(queueKey);
51976
+ const turn = file2?.turns.find((row) => row.bridgeServerState === "cancel_requested" && row.lastCliState === "running");
51977
+ if (!turn) {
51978
+ await yieldToEventLoop();
51979
+ continue;
51980
+ }
51981
+ deps.log(`[Queue] Cancellation request received for turn ${turn.turnId.slice(0, 8)}\u2026`);
51982
+ if (await deps.acpManager.cancelRun(turn.turnId)) {
51983
+ await yieldToEventLoop();
51984
+ continue;
51985
+ }
51986
+ deps.log(`[Queue] cancel_requested for ${turn.turnId.slice(0, 8)}\u2026 with no local run; marking cancelled.`);
51987
+ await finalizePromptTurnOnBridge(deps.getWs, turn.turnId, false, { terminalCliState: "cancelled" });
51988
+ const ws = deps.getWs();
51989
+ if (ws && turn.sessionId) {
51990
+ sendWsMessage(ws, {
51991
+ type: "prompt_result",
51992
+ sessionId: turn.sessionId,
51993
+ runId: turn.turnId,
51994
+ success: false,
51995
+ error: "Stopped by user",
51996
+ stopReason: "cancelled"
51997
+ });
51998
+ }
51999
+ await yieldToEventLoop();
51891
52000
  }
51892
52001
  }
51893
52002
 
52003
+ // src/prompt-turn-queue/runner/persist-prompt-queue-snapshot.ts
52004
+ init_yield_to_event_loop();
52005
+ async function persistPromptQueueSnapshot(entries) {
52006
+ for (const [queueKey, serverTurns] of entries) {
52007
+ const file2 = await mergeBridgeServerQueueSnapshot(queueKey, serverTurns);
52008
+ await writePersistedQueue(file2);
52009
+ await yieldToEventLoop();
52010
+ }
52011
+ for (const [queueKey] of entries) {
52012
+ const file2 = await readPersistedQueue(queueKey);
52013
+ if (file2) syncRunningTurnQueueKeys(file2.turns, queueKey);
52014
+ await yieldToEventLoop();
52015
+ }
52016
+ }
52017
+
52018
+ // src/prompt-turn-queue/runner/prompt-queue-snapshot-types.ts
52019
+ function promptQueueSnapshotEntries(queues) {
52020
+ return Object.entries(queues).filter((entry) => Array.isArray(entry[1]));
52021
+ }
52022
+
52023
+ // src/prompt-turn-queue/runner/start-prompt-queue-runs.ts
52024
+ init_yield_to_event_loop();
52025
+
52026
+ // src/prompt-turn-queue/runner/queue-selection.ts
52027
+ function pickNextRunnableTurn(turns) {
52028
+ for (const t of turns) {
52029
+ if (t.bridgeServerState === "discarded" || t.bridgeServerState === "stopping") continue;
52030
+ if (t.bridgeServerState === "cancel_requested") continue;
52031
+ if (!isRunnableBridgePromptTurnServerState(t.bridgeServerState)) continue;
52032
+ if (t.lastCliState === "running" || t.lastCliState === "stopped" || t.lastCliState === "failed" || t.lastCliState === "cancelled") {
52033
+ continue;
52034
+ }
52035
+ return t;
52036
+ }
52037
+ return null;
52038
+ }
52039
+ function hasRunningTurn(turns) {
52040
+ return turns.some((t) => t.lastCliState === "running");
52041
+ }
52042
+
51894
52043
  // src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
51895
52044
  import fs59 from "node:fs";
51896
52045
 
@@ -52008,96 +52157,41 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
52008
52157
  return res.ok;
52009
52158
  }
52010
52159
 
52011
- // src/prompt-turn-queue/runner/finalize-prompt-turn-on-bridge.ts
52012
- async function finalizePromptTurnOnBridge(getWs, runId, success2, opts) {
52013
- if (!runId) return false;
52014
- const queueKey = deleteRunIdQueueKey(runId);
52015
- if (!queueKey) return false;
52016
- const f = await readPersistedQueue(queueKey);
52017
- if (!f) return false;
52018
- const t = f.turns.find((x) => x.turnId === runId);
52019
- if (!t) return false;
52020
- t.lastCliState = opts?.terminalCliState ?? (success2 ? "stopped" : "failed");
52021
- await writePersistedQueue(f);
52022
- sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: runId, cliState: t.lastCliState }] });
52023
- return true;
52024
- }
52025
-
52026
- // src/prompt-turn-queue/runner/apply-prompt-queue-state-from-server.ts
52027
- async function applyPromptQueueStateFromServer(msg, deps) {
52028
- const raw = msg.queues;
52029
- if (!raw || typeof raw !== "object") return;
52030
- const getWs = deps.getWs;
52031
- for (const [queueKey, serverTurns] of Object.entries(raw)) {
52032
- if (!Array.isArray(serverTurns)) continue;
52033
- const file2 = await mergeBridgeServerQueueSnapshot(queueKey, serverTurns);
52034
- await writePersistedQueue(file2);
52035
- }
52036
- for (const [queueKey, serverTurns] of Object.entries(raw)) {
52037
- if (!Array.isArray(serverTurns)) continue;
52038
- const file2 = await readPersistedQueue(queueKey);
52039
- if (!file2) continue;
52040
- syncRunningTurnQueueKeys(file2.turns, queueKey);
52041
- }
52042
- for (const [queueKey, serverTurns] of Object.entries(raw)) {
52043
- if (!Array.isArray(serverTurns)) continue;
52044
- const file2 = await readPersistedQueue(queueKey);
52045
- if (!file2) continue;
52046
- const cancelRow = file2.turns.find((t) => t.bridgeServerState === "cancel_requested" && t.lastCliState === "running");
52047
- if (cancelRow) {
52048
- const localCancelHandled = await deps.acpManager.cancelRun(cancelRow.turnId);
52049
- if (!localCancelHandled) {
52050
- deps.log(
52051
- `[Queue] bridge server cancel_requested for ${cancelRow.turnId.slice(0, 8)}\u2026 but no local agent run is active (e.g. after CLI restart); marking cancelled and notifying bridge.`
52052
- );
52053
- await finalizePromptTurnOnBridge(deps.getWs, cancelRow.turnId, false, { terminalCliState: "cancelled" });
52054
- const ws = deps.getWs();
52055
- if (ws && cancelRow.sessionId) {
52056
- sendWsMessage(ws, {
52057
- type: "prompt_result",
52058
- sessionId: cancelRow.sessionId,
52059
- runId: cancelRow.turnId,
52060
- success: false,
52061
- error: "Stopped by user",
52062
- stopReason: "cancelled"
52063
- });
52064
- }
52065
- }
52066
- }
52067
- }
52160
+ // src/prompt-turn-queue/runner/start-prompt-queue-runs.ts
52161
+ async function startPromptQueueRuns(entries, deps) {
52068
52162
  const report = {};
52069
- const startedThisTick = /* @__PURE__ */ new Set();
52070
- for (const [queueKey, serverTurns] of Object.entries(raw)) {
52071
- if (!Array.isArray(serverTurns)) continue;
52163
+ const started = /* @__PURE__ */ new Set();
52164
+ for (const [queueKey] of entries) {
52072
52165
  const file2 = await readPersistedQueue(queueKey);
52073
- if (!file2) continue;
52074
- if (hasRunningTurn(file2.turns)) continue;
52166
+ if (!file2 || hasRunningTurn(file2.turns)) continue;
52075
52167
  const next = pickNextRunnableTurn(file2.turns);
52076
52168
  if (!next) continue;
52077
52169
  if (!await runLocalRevertBeforeQueuedPrompt(next, deps)) {
52078
52170
  next.lastCliState = "failed";
52079
52171
  await writePersistedQueue(file2);
52080
- sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: next.turnId, cliState: "failed" }] });
52172
+ sendPromptQueueClientReport(deps.getWs(), { [queueKey]: [{ turnId: next.turnId, cliState: "failed" }] });
52081
52173
  continue;
52082
52174
  }
52083
52175
  next.lastCliState = "running";
52084
52176
  await writePersistedQueue(file2);
52085
52177
  setRunIdQueueKey(next.turnId, queueKey);
52086
- startedThisTick.add(next.turnId);
52178
+ started.add(next.turnId);
52087
52179
  report[queueKey] = [{ turnId: next.turnId, cliState: "running" }];
52180
+ await yieldToEventLoop();
52088
52181
  }
52089
- if (Object.keys(report).length > 0) {
52090
- sendPromptQueueClientReport(getWs(), report);
52091
- }
52092
- for (const [queueKey, serverTurns] of Object.entries(raw)) {
52093
- if (!Array.isArray(serverTurns)) continue;
52094
- const file2 = await readPersistedQueue(queueKey);
52095
- if (!file2) continue;
52096
- const running = file2.turns.find((t) => t.lastCliState === "running");
52097
- if (!running || !startedThisTick.has(running.turnId)) continue;
52098
- if (getRunIdQueueKey(running.turnId) !== queueKey) continue;
52099
- dispatchLocalPrompt(running, deps);
52100
- }
52182
+ if (Object.keys(report).length) sendPromptQueueClientReport(deps.getWs(), report);
52183
+ return started;
52184
+ }
52185
+
52186
+ // src/prompt-turn-queue/runner/apply-prompt-queue-state-from-server.ts
52187
+ async function applyPromptQueueStateFromServer(msg, deps) {
52188
+ const raw = msg.queues;
52189
+ if (!raw || typeof raw !== "object") return;
52190
+ const entries = promptQueueSnapshotEntries(raw);
52191
+ await persistPromptQueueSnapshot(entries);
52192
+ await handlePromptQueueCancellations(entries, deps);
52193
+ const started = await startPromptQueueRuns(entries, deps);
52194
+ await dispatchStartedPromptQueueRuns(entries, started, deps);
52101
52195
  }
52102
52196
 
52103
52197
  // src/agents/acp/from-bridge/bridge-prompt-wiring.ts
@@ -52363,10 +52457,34 @@ var handlePromptMessage = (msg, deps) => {
52363
52457
  handleBridgePrompt(msg, deps);
52364
52458
  };
52365
52459
 
52460
+ // src/prompt-turn-queue/runner/serial-prompt-queue-work.ts
52461
+ var running = false;
52462
+ var latestWork = null;
52463
+ async function drain() {
52464
+ while (latestWork) {
52465
+ const work = latestWork;
52466
+ latestWork = null;
52467
+ await work();
52468
+ }
52469
+ }
52470
+ function enqueueLatestPromptQueueStateWork(work) {
52471
+ latestWork = work;
52472
+ if (running) return;
52473
+ running = true;
52474
+ void drain().finally(() => {
52475
+ running = false;
52476
+ if (latestWork) enqueueLatestPromptQueueStateWork(latestWork);
52477
+ });
52478
+ }
52479
+
52366
52480
  // src/routing/handlers/prompt-queue-state.ts
52367
52481
  var handlePromptQueueStateMessage = (msg, deps) => {
52368
- void applyPromptQueueStateFromServer(msg, deps).catch((err) => {
52369
- deps.log(`[Queue] applyPromptQueueStateFromServer failed: ${err instanceof Error ? err.message : String(err)}`);
52482
+ enqueueLatestPromptQueueStateWork(async () => {
52483
+ try {
52484
+ await applyPromptQueueStateFromServer(msg, deps);
52485
+ } catch (err) {
52486
+ deps.log(`[Queue] applyPromptQueueStateFromServer failed: ${err instanceof Error ? err.message : String(err)}`);
52487
+ }
52370
52488
  });
52371
52489
  };
52372
52490
 
@@ -53512,6 +53630,7 @@ function dispatchBridgeMessage(msg, deps) {
53512
53630
  switch (msg.type) {
53513
53631
  case "auth_token":
53514
53632
  case "bridge_identified":
53633
+ case "installed_agent_auth_sync":
53515
53634
  case "ha":
53516
53635
  dispatchBridgeConnectionMessage(msg, deps);
53517
53636
  break;