@buildautomaton/cli 0.1.19 → 0.1.20

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
@@ -2240,7 +2240,7 @@ var require_websocket = __commonJS({
2240
2240
  var http = __require("http");
2241
2241
  var net = __require("net");
2242
2242
  var tls = __require("tls");
2243
- var { randomBytes: randomBytes2, createHash: createHash2 } = __require("crypto");
2243
+ var { randomBytes: randomBytes2, createHash } = __require("crypto");
2244
2244
  var { Duplex, Readable: Readable2 } = __require("stream");
2245
2245
  var { URL: URL2 } = __require("url");
2246
2246
  var PerMessageDeflate = require_permessage_deflate();
@@ -2900,7 +2900,7 @@ var require_websocket = __commonJS({
2900
2900
  abortHandshake(websocket, socket, "Invalid Upgrade header");
2901
2901
  return;
2902
2902
  }
2903
- const digest = createHash2("sha1").update(key + GUID).digest("base64");
2903
+ const digest = createHash("sha1").update(key + GUID).digest("base64");
2904
2904
  if (res.headers["sec-websocket-accept"] !== digest) {
2905
2905
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
2906
2906
  return;
@@ -3267,7 +3267,7 @@ var require_websocket_server = __commonJS({
3267
3267
  var EventEmitter2 = __require("events");
3268
3268
  var http = __require("http");
3269
3269
  var { Duplex } = __require("stream");
3270
- var { createHash: createHash2 } = __require("crypto");
3270
+ var { createHash } = __require("crypto");
3271
3271
  var extension = require_extension();
3272
3272
  var PerMessageDeflate = require_permessage_deflate();
3273
3273
  var subprotocol = require_subprotocol();
@@ -3568,7 +3568,7 @@ var require_websocket_server = __commonJS({
3568
3568
  );
3569
3569
  }
3570
3570
  if (this._state > RUNNING) return abortHandshake(socket, 503);
3571
- const digest = createHash2("sha1").update(key + GUID).digest("base64");
3571
+ const digest = createHash("sha1").update(key + GUID).digest("base64");
3572
3572
  const headers = [
3573
3573
  "HTTP/1.1 101 Switching Protocols",
3574
3574
  "Upgrade: websocket",
@@ -20943,8 +20943,8 @@ var init_acp = __esm({
20943
20943
  this.#requestHandler = requestHandler;
20944
20944
  this.#notificationHandler = notificationHandler;
20945
20945
  this.#stream = stream;
20946
- this.#closedPromise = new Promise((resolve17) => {
20947
- this.#abortController.signal.addEventListener("abort", () => resolve17());
20946
+ this.#closedPromise = new Promise((resolve16) => {
20947
+ this.#abortController.signal.addEventListener("abort", () => resolve16());
20948
20948
  });
20949
20949
  this.#receive();
20950
20950
  }
@@ -21093,8 +21093,8 @@ var init_acp = __esm({
21093
21093
  }
21094
21094
  async sendRequest(method, params) {
21095
21095
  const id = this.#nextRequestId++;
21096
- const responsePromise = new Promise((resolve17, reject) => {
21097
- this.#pendingResponses.set(id, { resolve: resolve17, reject });
21096
+ const responsePromise = new Promise((resolve16, reject) => {
21097
+ this.#pendingResponses.set(id, { resolve: resolve16, reject });
21098
21098
  });
21099
21099
  await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
21100
21100
  return responsePromise;
@@ -21669,7 +21669,7 @@ var require_has_flag = __commonJS({
21669
21669
  var require_supports_color = __commonJS({
21670
21670
  "../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
21671
21671
  "use strict";
21672
- var os6 = __require("os");
21672
+ var os7 = __require("os");
21673
21673
  var tty = __require("tty");
21674
21674
  var hasFlag = require_has_flag();
21675
21675
  var { env } = process;
@@ -21717,7 +21717,7 @@ var require_supports_color = __commonJS({
21717
21717
  return min;
21718
21718
  }
21719
21719
  if (process.platform === "win32") {
21720
- const osRelease = os6.release().split(".");
21720
+ const osRelease = os7.release().split(".");
21721
21721
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
21722
21722
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
21723
21723
  }
@@ -22413,7 +22413,7 @@ async function createSdkStdioAcpClient(options) {
22413
22413
  child.once("close", (code, signal) => {
22414
22414
  onAgentSubprocessExit?.({ code, signal });
22415
22415
  });
22416
- return new Promise((resolve17, reject) => {
22416
+ return new Promise((resolve16, reject) => {
22417
22417
  let initSettled = false;
22418
22418
  const settleReject = (err) => {
22419
22419
  if (initSettled) return;
@@ -22427,7 +22427,7 @@ async function createSdkStdioAcpClient(options) {
22427
22427
  const settleResolve = (handle) => {
22428
22428
  if (initSettled) return;
22429
22429
  initSettled = true;
22430
- resolve17(handle);
22430
+ resolve16(handle);
22431
22431
  };
22432
22432
  child.on("error", (err) => {
22433
22433
  settleReject(new Error(formatSpawnError(err, command[0])));
@@ -22463,8 +22463,8 @@ async function createSdkStdioAcpClient(options) {
22463
22463
  });
22464
22464
  } catch {
22465
22465
  }
22466
- return await new Promise((resolve18) => {
22467
- pendingPermissionResolvers.set(requestId, resolve18);
22466
+ return await new Promise((resolve17) => {
22467
+ pendingPermissionResolvers.set(requestId, resolve17);
22468
22468
  });
22469
22469
  },
22470
22470
  async readTextFile(params) {
@@ -22572,9 +22572,9 @@ async function createSdkStdioAcpClient(options) {
22572
22572
  }
22573
22573
  },
22574
22574
  async cancel() {
22575
- for (const [id, resolve18] of [...pendingPermissionResolvers.entries()]) {
22575
+ for (const [id, resolve17] of [...pendingPermissionResolvers.entries()]) {
22576
22576
  pendingPermissionResolvers.delete(id);
22577
- resolve18({ outcome: { outcome: "cancelled" } });
22577
+ resolve17({ outcome: { outcome: "cancelled" } });
22578
22578
  }
22579
22579
  try {
22580
22580
  await connection.cancel({ sessionId });
@@ -22590,10 +22590,10 @@ async function createSdkStdioAcpClient(options) {
22590
22590
  }
22591
22591
  },
22592
22592
  resolveRequest(requestId, result) {
22593
- const resolve18 = pendingPermissionResolvers.get(requestId);
22594
- if (!resolve18) return;
22593
+ const resolve17 = pendingPermissionResolvers.get(requestId);
22594
+ if (!resolve17) return;
22595
22595
  pendingPermissionResolvers.delete(requestId);
22596
- resolve18(result);
22596
+ resolve17(result);
22597
22597
  },
22598
22598
  disconnect() {
22599
22599
  child.kill();
@@ -22700,7 +22700,7 @@ async function proxyToLocal(request) {
22700
22700
  };
22701
22701
  const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
22702
22702
  for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
22703
- const once = await new Promise((resolve17) => {
22703
+ const once = await new Promise((resolve16) => {
22704
22704
  const req = mod.request(opts, (res) => {
22705
22705
  const chunks = [];
22706
22706
  res.on("data", (c) => chunks.push(c));
@@ -22711,7 +22711,7 @@ async function proxyToLocal(request) {
22711
22711
  if (typeof v === "string") headers[k] = v;
22712
22712
  else if (Array.isArray(v) && v[0]) headers[k] = v[0];
22713
22713
  }
22714
- resolve17({
22714
+ resolve16({
22715
22715
  id: request.id,
22716
22716
  statusCode: res.statusCode ?? 0,
22717
22717
  headers,
@@ -22720,7 +22720,7 @@ async function proxyToLocal(request) {
22720
22720
  });
22721
22721
  });
22722
22722
  req.on("error", (err) => {
22723
- resolve17({
22723
+ resolve16({
22724
22724
  id: request.id,
22725
22725
  statusCode: 0,
22726
22726
  headers: {},
@@ -23041,7 +23041,7 @@ function installBridgeProcessResilience() {
23041
23041
  }
23042
23042
 
23043
23043
  // src/cli-version.ts
23044
- var CLI_VERSION = "0.1.19".length > 0 ? "0.1.19" : "0.0.0-dev";
23044
+ var CLI_VERSION = "0.1.20".length > 0 ? "0.1.20" : "0.0.0-dev";
23045
23045
 
23046
23046
  // ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
23047
23047
  import process7 from "node:process";
@@ -23476,14 +23476,14 @@ var baseOpen = async (options) => {
23476
23476
  }
23477
23477
  const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
23478
23478
  if (options.wait) {
23479
- return new Promise((resolve17, reject) => {
23479
+ return new Promise((resolve16, reject) => {
23480
23480
  subprocess.once("error", reject);
23481
23481
  subprocess.once("close", (exitCode) => {
23482
23482
  if (!options.allowNonzeroExitCode && exitCode > 0) {
23483
23483
  reject(new Error(`Exited with code ${exitCode}`));
23484
23484
  return;
23485
23485
  }
23486
- resolve17(subprocess);
23486
+ resolve16(subprocess);
23487
23487
  });
23488
23488
  });
23489
23489
  }
@@ -23779,8 +23779,8 @@ function runPendingAuth(options) {
23779
23779
  let hasOpenedBrowser = false;
23780
23780
  let resolved = false;
23781
23781
  let resolveAuth;
23782
- const authPromise = new Promise((resolve17) => {
23783
- resolveAuth = resolve17;
23782
+ const authPromise = new Promise((resolve16) => {
23783
+ resolveAuth = resolve16;
23784
23784
  });
23785
23785
  let reconnectAttempt = 0;
23786
23786
  const signInQuiet = createEmptyReconnectQuietSlot();
@@ -23902,7 +23902,7 @@ function runPendingAuth(options) {
23902
23902
  async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
23903
23903
  const say = log2 ?? logImmediate;
23904
23904
  say("Cleaning up connections\u2026");
23905
- await new Promise((resolve17) => setImmediate(resolve17));
23905
+ await new Promise((resolve16) => setImmediate(resolve16));
23906
23906
  state.closedByUser = true;
23907
23907
  clearReconnectQuietTimer(state.mainQuiet);
23908
23908
  clearReconnectQuietTimer(state.firehoseQuiet);
@@ -28779,18 +28779,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
28779
28779
  }
28780
28780
  }
28781
28781
 
28782
- // ../types/dist/index.js
28783
- init_zod();
28784
- init_zod();
28785
- init_zod();
28786
- init_zod();
28787
- init_zod();
28788
- init_zod();
28789
- init_zod();
28790
- init_zod();
28791
- init_zod();
28792
- init_zod();
28793
- init_zod();
28782
+ // ../types/src/work-items.ts
28794
28783
  init_zod();
28795
28784
  var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
28796
28785
  var WorkItemProgressSchema = external_exports.object({
@@ -28831,6 +28820,9 @@ var WorkItemSchema = external_exports.object({
28831
28820
  dependencies: external_exports.array(WorkItemDependencySchema).default([]),
28832
28821
  assignedToUserId: external_exports.string().optional()
28833
28822
  });
28823
+
28824
+ // ../types/src/user-profiles.ts
28825
+ init_zod();
28834
28826
  var UserWorkspaceProfileSchema = external_exports.object({
28835
28827
  id: external_exports.string(),
28836
28828
  workspaceId: external_exports.string(),
@@ -28840,6 +28832,9 @@ var UserWorkspaceProfileSchema = external_exports.object({
28840
28832
  preferences: external_exports.record(external_exports.unknown()).optional(),
28841
28833
  learnings: external_exports.array(external_exports.string())
28842
28834
  });
28835
+
28836
+ // ../types/src/runtime.ts
28837
+ init_zod();
28843
28838
  var WorkspaceOwnerInfoSchema = external_exports.object({
28844
28839
  ownerId: external_exports.string(),
28845
28840
  ownerName: external_exports.string().optional(),
@@ -28853,6 +28848,9 @@ var WorkspaceRuntimeEntrySchema = external_exports.object({
28853
28848
  owner: WorkspaceOwnerInfoSchema.optional(),
28854
28849
  isOwner: external_exports.boolean().optional()
28855
28850
  });
28851
+
28852
+ // ../types/src/agent.ts
28853
+ init_zod();
28856
28854
  var ProjectContextSchema = external_exports.object({
28857
28855
  projectId: external_exports.string(),
28858
28856
  context: external_exports.record(external_exports.unknown()).default({}),
@@ -28877,6 +28875,9 @@ var WebSocketMessageSchema = external_exports.object({
28877
28875
  data: external_exports.any().optional(),
28878
28876
  error: external_exports.string().optional()
28879
28877
  });
28878
+
28879
+ // ../types/src/checkpoints.ts
28880
+ init_zod();
28880
28881
  var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
28881
28882
  var CheckpointSummarySchema = external_exports.object({
28882
28883
  id: external_exports.string(),
@@ -28887,6 +28888,9 @@ var CheckpointSummarySchema = external_exports.object({
28887
28888
  createdAt: external_exports.string(),
28888
28889
  updatedAt: external_exports.string()
28889
28890
  });
28891
+
28892
+ // ../types/src/threads.ts
28893
+ init_zod();
28890
28894
  var ThreadMetaSchema = external_exports.object({
28891
28895
  threadId: external_exports.string(),
28892
28896
  workspaceId: external_exports.string(),
@@ -28914,6 +28918,9 @@ var ThreadMessageSchema = external_exports.object({
28914
28918
  var ThreadCheckpointSummarySchema = CheckpointSummarySchema.extend({
28915
28919
  threadId: external_exports.string()
28916
28920
  });
28921
+
28922
+ // ../types/src/content-items.ts
28923
+ init_zod();
28917
28924
  var ContentSourceSchema = external_exports.enum(["notion", "doc", "slack_thread", "other"]);
28918
28925
  var ContentItemMetaSchema = external_exports.object({
28919
28926
  contentId: external_exports.string(),
@@ -28935,6 +28942,9 @@ var ContentStorageRefSchema = external_exports.object({
28935
28942
  var ContentCheckpointSummarySchema = CheckpointSummarySchema.extend({
28936
28943
  contentId: external_exports.string()
28937
28944
  });
28945
+
28946
+ // ../types/src/stories.ts
28947
+ init_zod();
28938
28948
  var StoryMetaSchema = external_exports.object({
28939
28949
  storyId: external_exports.string(),
28940
28950
  workspaceId: external_exports.string(),
@@ -28957,6 +28967,9 @@ var StoryContentItemRefSchema = external_exports.object({
28957
28967
  var StoryCheckpointSummarySchema = CheckpointSummarySchema.extend({
28958
28968
  storyId: external_exports.string()
28959
28969
  });
28970
+
28971
+ // ../types/src/sessions.ts
28972
+ init_zod();
28960
28973
  var BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID = "__builtin_change_summary__";
28961
28974
  var SessionMetaSchema = external_exports.object({
28962
28975
  sessionId: external_exports.string(),
@@ -28999,6 +29012,8 @@ var SessionThreadRefSchema = external_exports.object({
28999
29012
  threadId: external_exports.string(),
29000
29013
  addedAt: external_exports.string()
29001
29014
  });
29015
+
29016
+ // ../types/src/change-summary-path.ts
29002
29017
  function normalizeRepoRelativePath(p) {
29003
29018
  let t = p.trim().replace(/\\/g, "/");
29004
29019
  while (t.startsWith("./")) t = t.slice(2);
@@ -29015,6 +29030,8 @@ function resolveChangeSummaryPathAgainstAllowed(rawPath, allowed) {
29015
29030
  }
29016
29031
  return null;
29017
29032
  }
29033
+
29034
+ // ../types/src/parse-change-summary-json.ts
29018
29035
  function clampSummaryToAtMostTwoLines(summary) {
29019
29036
  const lines = summary.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
29020
29037
  return lines.slice(0, 2).join("\n");
@@ -29057,6 +29074,8 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
29057
29074
  }
29058
29075
  return rows;
29059
29076
  }
29077
+
29078
+ // ../types/src/build-change-summary-prompt.ts
29060
29079
  var PATCH_PREVIEW_MAX = 12e3;
29061
29080
  function clip(s, max) {
29062
29081
  if (s.length <= max) return s;
@@ -29114,6 +29133,8 @@ function buildSessionChangeSummaryPrompt(files) {
29114
29133
  }
29115
29134
  return lines.join("\n");
29116
29135
  }
29136
+
29137
+ // ../types/src/dedupe-session-file-changes-by-path.ts
29117
29138
  function defaultRichness(c) {
29118
29139
  const patch = typeof c.patchContent === "string" ? c.patchContent.length : 0;
29119
29140
  const nt = typeof c.newText === "string" ? c.newText.length : 0;
@@ -29131,6 +29152,9 @@ function dedupeSessionFileChangesByPath(items, richness = (item) => defaultRichn
29131
29152
  }
29132
29153
  return Array.from(byPath.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v);
29133
29154
  }
29155
+
29156
+ // ../types/src/artifacts.ts
29157
+ init_zod();
29134
29158
  var ArtifactMetaSchema = external_exports.object({
29135
29159
  artifactId: external_exports.string(),
29136
29160
  workspaceId: external_exports.string(),
@@ -29144,6 +29168,9 @@ var ArtifactMetaSchema = external_exports.object({
29144
29168
  createdAt: external_exports.string(),
29145
29169
  updatedAt: external_exports.string()
29146
29170
  });
29171
+
29172
+ // ../types/src/templates.ts
29173
+ init_zod();
29147
29174
  var TemplateMetaSchema = external_exports.object({
29148
29175
  templateId: external_exports.string(),
29149
29176
  workspaceId: external_exports.string(),
@@ -29153,6 +29180,9 @@ var TemplateMetaSchema = external_exports.object({
29153
29180
  createdAt: external_exports.string(),
29154
29181
  updatedAt: external_exports.string()
29155
29182
  });
29183
+
29184
+ // ../types/src/git-repos.ts
29185
+ init_zod();
29156
29186
  var GitRepoMetaSchema = external_exports.object({
29157
29187
  /** Stable id for the repo (e.g. hash of normalized canonical URL). Used for DO idFromName. */
29158
29188
  repoId: external_exports.string(),
@@ -29513,7 +29543,7 @@ async function createCursorAcpClient(options) {
29513
29543
  });
29514
29544
  const stderrCapture = createStderrCapture(child);
29515
29545
  child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
29516
- return new Promise((resolve17, reject) => {
29546
+ return new Promise((resolve16, reject) => {
29517
29547
  child.on("error", (err) => {
29518
29548
  child.kill();
29519
29549
  reject(new Error(formatSpawnError2(err, command[0])));
@@ -29700,7 +29730,7 @@ async function createCursorAcpClient(options) {
29700
29730
  const newResult = await send("session/new", { cwd, mcpServers: [] });
29701
29731
  const sessionId = newResult?.sessionId ?? "";
29702
29732
  if (!sessionId) throw new Error("Cursor ACP session/new did not return sessionId");
29703
- resolve17({
29733
+ resolve16({
29704
29734
  sessionId,
29705
29735
  async sendPrompt(prompt, _options) {
29706
29736
  promptOutputBuffer = "";
@@ -31852,7 +31882,7 @@ import path21 from "node:path";
31852
31882
 
31853
31883
  // src/runtime/yield-to-event-loop.ts
31854
31884
  function yieldToEventLoop() {
31855
- return new Promise((resolve17) => setImmediate(resolve17));
31885
+ return new Promise((resolve16) => setImmediate(resolve16));
31856
31886
  }
31857
31887
 
31858
31888
  // src/files/index/walk-workspace-tree.ts
@@ -32214,15 +32244,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
32214
32244
 
32215
32245
  // src/dev-servers/process/terminate-child-process.ts
32216
32246
  async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
32217
- const exited = new Promise((resolve17) => {
32218
- proc.once("exit", () => resolve17());
32247
+ const exited = new Promise((resolve16) => {
32248
+ proc.once("exit", () => resolve16());
32219
32249
  });
32220
32250
  log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
32221
32251
  try {
32222
32252
  proc.kill("SIGTERM");
32223
32253
  } catch {
32224
32254
  }
32225
- await Promise.race([exited, new Promise((resolve17) => setTimeout(resolve17, graceMs))]);
32255
+ await Promise.race([exited, new Promise((resolve16) => setTimeout(resolve16, graceMs))]);
32226
32256
  }
32227
32257
  function forceKillChild(proc, log2, shortId, graceMs) {
32228
32258
  log2(
@@ -33473,6 +33503,7 @@ var API_TO_BRIDGE_MESSAGE_TYPES = [
33473
33503
  "dev_servers_config",
33474
33504
  "server_control",
33475
33505
  "agent_config",
33506
+ "prompt_queue_state",
33476
33507
  "prompt",
33477
33508
  "session_git_request",
33478
33509
  "rename_session_branch",
@@ -33552,6 +33583,173 @@ var handleAgentConfigMessage = (msg, deps) => {
33552
33583
  // src/agents/acp/from-bridge/handle-bridge-prompt.ts
33553
33584
  import * as path29 from "node:path";
33554
33585
 
33586
+ // src/prompt-turn-queue/client-report.ts
33587
+ function sendPromptQueueClientReport(ws, queues) {
33588
+ if (!ws) return false;
33589
+ sendWsMessage(ws, { type: "prompt_queue_client_report", queues });
33590
+ return true;
33591
+ }
33592
+
33593
+ // src/prompt-turn-queue/disk-store.ts
33594
+ import fs27 from "node:fs";
33595
+
33596
+ // src/prompt-turn-queue/paths.ts
33597
+ import crypto3 from "node:crypto";
33598
+ import fs26 from "node:fs";
33599
+ import path28 from "node:path";
33600
+ import os6 from "node:os";
33601
+ var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
33602
+ function queueStateFileSlug(queueKey) {
33603
+ if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
33604
+ return crypto3.createHash("sha256").update(queueKey, "utf8").digest("hex");
33605
+ }
33606
+ function getPromptQueuesDirectory() {
33607
+ const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
33608
+ if (override) return path28.resolve(override);
33609
+ return path28.join(os6.homedir(), ".buildautomaton", "queues");
33610
+ }
33611
+ function ensurePromptQueuesDirectory() {
33612
+ const dir = getPromptQueuesDirectory();
33613
+ if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
33614
+ }
33615
+ function queueStateFilePath(queueKey) {
33616
+ return path28.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
33617
+ }
33618
+
33619
+ // src/prompt-turn-queue/disk-store.ts
33620
+ function parsePersistedQueueFile(raw) {
33621
+ try {
33622
+ const o = JSON.parse(raw);
33623
+ const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
33624
+ if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
33625
+ return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
33626
+ } catch {
33627
+ return null;
33628
+ }
33629
+ }
33630
+ function readPersistedQueue(queueKey) {
33631
+ const p = queueStateFilePath(queueKey);
33632
+ try {
33633
+ return parsePersistedQueueFile(fs27.readFileSync(p, "utf8"));
33634
+ } catch {
33635
+ return null;
33636
+ }
33637
+ }
33638
+ function writePersistedQueue(file2) {
33639
+ ensurePromptQueuesDirectory();
33640
+ const p = queueStateFilePath(file2.queueKey);
33641
+ fs27.writeFileSync(p, JSON.stringify(file2, null, 2), "utf8");
33642
+ }
33643
+ function mergeServerQueueSnapshot(queueKey, serverTurns) {
33644
+ const prev = readPersistedQueue(queueKey);
33645
+ const turns = [];
33646
+ for (const raw of serverTurns) {
33647
+ if (!raw || typeof raw !== "object") continue;
33648
+ const o = raw;
33649
+ const turnId = typeof o.turnId === "string" ? o.turnId : "";
33650
+ const sessionId = typeof o.sessionId === "string" ? o.sessionId : "";
33651
+ const turnOrd = typeof o.turnOrd === "number" ? o.turnOrd : Number(o.turnOrd) || 0;
33652
+ const serverState = o.serverState;
33653
+ const lastClientState = o.lastClientState ?? null;
33654
+ const payload = o.payload && typeof o.payload === "object" ? o.payload : {};
33655
+ if (!turnId || !sessionId) continue;
33656
+ if (serverState !== "queued" && serverState !== "stopping" && serverState !== "discarded") continue;
33657
+ const old = prev?.turns.find((t) => t.turnId === turnId);
33658
+ const mergedClient = old?.lastClientState === "running" && lastClientState == null ? "running" : lastClientState;
33659
+ turns.push({
33660
+ turnId,
33661
+ sessionId,
33662
+ turnOrd,
33663
+ serverState,
33664
+ lastClientState: mergedClient,
33665
+ payload
33666
+ });
33667
+ }
33668
+ turns.sort((a, b) => a.turnOrd - b.turnOrd);
33669
+ return { queueKey, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), turns };
33670
+ }
33671
+
33672
+ // src/prompt-turn-queue/runner.ts
33673
+ var runIdToQueueKey = /* @__PURE__ */ new Map();
33674
+ function pickNextRunnableTurn(turns) {
33675
+ for (const t of turns) {
33676
+ if (t.serverState === "discarded" || t.serverState === "stopping") continue;
33677
+ if (t.serverState !== "queued") continue;
33678
+ if (t.lastClientState === "running" || t.lastClientState === "stopped" || t.lastClientState === "failed") continue;
33679
+ return t;
33680
+ }
33681
+ return null;
33682
+ }
33683
+ function hasRunningTurn(turns) {
33684
+ return turns.some((t) => t.lastClientState === "running");
33685
+ }
33686
+ function dispatchLocalPrompt(next, deps) {
33687
+ const pl = next.payload;
33688
+ const msg = {
33689
+ type: "prompt",
33690
+ sessionId: next.sessionId,
33691
+ runId: next.turnId,
33692
+ prompt: pl.prompt,
33693
+ mode: typeof pl.mode === "string" ? pl.mode : "agent",
33694
+ isNewSession: pl.isNewSession === true,
33695
+ ...typeof pl.followUpCatalogPromptId === "string" ? { followUpCatalogPromptId: pl.followUpCatalogPromptId } : {},
33696
+ ...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
33697
+ ...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
33698
+ ...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {}
33699
+ };
33700
+ handleBridgePrompt(msg, deps);
33701
+ }
33702
+ function applyPromptQueueStateFromServer(msg, deps) {
33703
+ const raw = msg.queues;
33704
+ if (!raw || typeof raw !== "object") return;
33705
+ const getWs = deps.getWs;
33706
+ for (const [queueKey, serverTurns] of Object.entries(raw)) {
33707
+ if (!Array.isArray(serverTurns)) continue;
33708
+ const file2 = mergeServerQueueSnapshot(queueKey, serverTurns);
33709
+ writePersistedQueue(file2);
33710
+ }
33711
+ const report = {};
33712
+ const startedThisTick = /* @__PURE__ */ new Set();
33713
+ for (const [queueKey, serverTurns] of Object.entries(raw)) {
33714
+ if (!Array.isArray(serverTurns)) continue;
33715
+ const file2 = readPersistedQueue(queueKey);
33716
+ if (!file2) continue;
33717
+ if (hasRunningTurn(file2.turns)) continue;
33718
+ const next = pickNextRunnableTurn(file2.turns);
33719
+ if (!next) continue;
33720
+ next.lastClientState = "running";
33721
+ writePersistedQueue(file2);
33722
+ runIdToQueueKey.set(next.turnId, queueKey);
33723
+ startedThisTick.add(next.turnId);
33724
+ report[queueKey] = [{ turnId: next.turnId, clientState: "running" }];
33725
+ }
33726
+ if (Object.keys(report).length > 0) {
33727
+ sendPromptQueueClientReport(getWs(), report);
33728
+ }
33729
+ for (const [queueKey, serverTurns] of Object.entries(raw)) {
33730
+ if (!Array.isArray(serverTurns)) continue;
33731
+ const file2 = readPersistedQueue(queueKey);
33732
+ if (!file2) continue;
33733
+ const running = file2.turns.find((t) => t.lastClientState === "running");
33734
+ if (!running || !startedThisTick.has(running.turnId)) continue;
33735
+ if (runIdToQueueKey.get(running.turnId) !== queueKey) continue;
33736
+ dispatchLocalPrompt(running, deps);
33737
+ }
33738
+ }
33739
+ function finalizePromptTurnOnBridge(getWs, runId, success2) {
33740
+ if (!runId) return;
33741
+ const queueKey = runIdToQueueKey.get(runId);
33742
+ runIdToQueueKey.delete(runId);
33743
+ if (!queueKey) return;
33744
+ const f = readPersistedQueue(queueKey);
33745
+ if (!f) return;
33746
+ const t = f.turns.find((x) => x.turnId === runId);
33747
+ if (!t) return;
33748
+ t.lastClientState = success2 ? "stopped" : "failed";
33749
+ writePersistedQueue(f);
33750
+ sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: runId, clientState: t.lastClientState }] });
33751
+ }
33752
+
33555
33753
  // src/agents/acp/from-bridge/bridge-prompt-wiring.ts
33556
33754
  function createBridgePromptSenders(deps, getWs) {
33557
33755
  const sendBridgeMessage = (message, encryptedFields = []) => {
@@ -33565,6 +33763,9 @@ function createBridgePromptSenders(deps, getWs) {
33565
33763
  const skipEncryptForChangeSummaryFollowUp = result.type === "prompt_result" && result.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
33566
33764
  const encryptedFields = result.type === "prompt_result" && !skipEncryptForChangeSummaryFollowUp ? ["output", "error"] : [];
33567
33765
  sendBridgeMessage(result, encryptedFields);
33766
+ if (result.type === "prompt_result") {
33767
+ finalizePromptTurnOnBridge(getWs, typeof result.runId === "string" ? result.runId : void 0, result.success === true);
33768
+ }
33568
33769
  };
33569
33770
  const sendSessionUpdate = (payload) => {
33570
33771
  const s = getWs();
@@ -33589,63 +33790,6 @@ function createBridgePromptSenders(deps, getWs) {
33589
33790
  // src/agents/acp/from-bridge/bridge-prompt-preamble.ts
33590
33791
  import { execFile as execFile10 } from "node:child_process";
33591
33792
  import { promisify as promisify10 } from "node:util";
33592
-
33593
- // src/git/bridge-queue-key.ts
33594
- import * as path28 from "node:path";
33595
- import { createHash } from "node:crypto";
33596
- function normalizeCanonicalGitUrl(url2) {
33597
- let s = url2.trim();
33598
- if (!s) return s;
33599
- if (s.toLowerCase().endsWith(".git")) {
33600
- s = s.slice(0, -4);
33601
- }
33602
- s = s.replace(/\/+$/, "");
33603
- const httpsMatch = /^(https?):\/\/([^/]+)(\/.*)?$/i.exec(s);
33604
- if (httpsMatch) {
33605
- const host = httpsMatch[2].toLowerCase();
33606
- const p = httpsMatch[3] ?? "";
33607
- s = `${httpsMatch[1].toLowerCase()}://${host}${p}`;
33608
- } else {
33609
- const sshMatch = /^git@([^:]+):(.+)$/i.exec(s);
33610
- if (sshMatch) {
33611
- const host = sshMatch[1].toLowerCase();
33612
- s = `git@${host}:${sshMatch[2]}`;
33613
- }
33614
- }
33615
- return s;
33616
- }
33617
- function canonicalUrlToRepoIdSync(url2) {
33618
- const normalized = normalizeCanonicalGitUrl(url2);
33619
- return createHash("sha256").update(normalized).digest("hex").slice(0, 32);
33620
- }
33621
- function fallbackRepoIdFromPath(absPath) {
33622
- return createHash("sha256").update(path28.resolve(absPath)).digest("hex").slice(0, 32);
33623
- }
33624
- async function resolveBridgeQueueBindFields(options) {
33625
- const { effectiveCwd, worktreePaths, primaryRepoRoots, log: log2 } = options;
33626
- const cwdAbs = worktreePaths.length > 0 ? path28.resolve(worktreePaths[0]) : path28.resolve(effectiveCwd);
33627
- if (!primaryRepoRoots.length) {
33628
- log2("[Bridge service] Prompt queue bind skipped: no Git repository roots under the working directory.");
33629
- return null;
33630
- }
33631
- let primaryRoot = primaryRepoRoots[0];
33632
- let remote = await getRemoteOriginUrl(primaryRoot);
33633
- if (!remote) {
33634
- for (const r of primaryRepoRoots.slice(1)) {
33635
- const u = await getRemoteOriginUrl(r);
33636
- if (u) {
33637
- primaryRoot = r;
33638
- remote = u;
33639
- break;
33640
- }
33641
- }
33642
- }
33643
- const repoId = remote ? canonicalUrlToRepoIdSync(remote) : fallbackRepoIdFromPath(primaryRoot);
33644
- const canonicalQueueKey = `repo:${repoId}::cwd:${cwdAbs}`;
33645
- return { canonicalQueueKey, repoId, cwdAbs };
33646
- }
33647
-
33648
- // src/agents/acp/from-bridge/bridge-prompt-preamble.ts
33649
33793
  var execFileAsync9 = promisify10(execFile10);
33650
33794
  async function readGitBranch(cwd) {
33651
33795
  try {
@@ -33665,23 +33809,6 @@ async function runBridgePromptPreamble(params) {
33665
33809
  fallbackCwd: effectiveCwd,
33666
33810
  log: log2
33667
33811
  });
33668
- if (s && sessionId) {
33669
- const bind = await resolveBridgeQueueBindFields({
33670
- effectiveCwd,
33671
- worktreePaths,
33672
- primaryRepoRoots: repoRoots,
33673
- log: log2
33674
- });
33675
- if (bind) {
33676
- sendWsMessage(s, {
33677
- type: "bridge_queue_bind",
33678
- sessionId,
33679
- canonicalQueueKey: bind.canonicalQueueKey,
33680
- repoId: bind.repoId,
33681
- cwdAbs: bind.cwdAbs
33682
- });
33683
- }
33684
- }
33685
33812
  if (s && sessionId) {
33686
33813
  const cliGitBranch = await readGitBranch(effectiveCwd);
33687
33814
  const usesWt = sessionWorktreeManager.usesWorktreeSession(sessionId);
@@ -33899,6 +34026,11 @@ var handlePromptMessage = (msg, deps) => {
33899
34026
  handleBridgePrompt(msg, deps);
33900
34027
  };
33901
34028
 
34029
+ // src/bridge/routing/handlers/prompt-queue-state.ts
34030
+ var handlePromptQueueStateMessage = (msg, deps) => {
34031
+ applyPromptQueueStateFromServer(msg, deps);
34032
+ };
34033
+
33902
34034
  // src/agents/acp/from-bridge/handle-bridge-cancel-run.ts
33903
34035
  async function handleBridgeCancelRun(msg, { log: log2, acpManager, getWs }) {
33904
34036
  const runId = msg.runId;
@@ -33918,6 +34050,7 @@ async function handleBridgeCancelRun(msg, { log: log2, acpManager, getWs }) {
33918
34050
  error: "Stopped by user",
33919
34051
  stopReason: "no_local_run"
33920
34052
  });
34053
+ finalizePromptTurnOnBridge(getWs, runId, false);
33921
34054
  }
33922
34055
 
33923
34056
  // src/bridge/routing/handlers/cancel-run.ts
@@ -33961,7 +34094,7 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
33961
34094
  };
33962
34095
 
33963
34096
  // src/files/list-dir.ts
33964
- import fs26 from "node:fs";
34097
+ import fs28 from "node:fs";
33965
34098
  import path31 from "node:path";
33966
34099
 
33967
34100
  // src/files/ensure-under-cwd.ts
@@ -33983,7 +34116,7 @@ async function listDirAsync(relativePath) {
33983
34116
  return { error: "Path is outside working directory" };
33984
34117
  }
33985
34118
  try {
33986
- const names = await fs26.promises.readdir(resolved, { withFileTypes: true });
34119
+ const names = await fs28.promises.readdir(resolved, { withFileTypes: true });
33987
34120
  const visible = names.filter((d) => !d.name.startsWith("."));
33988
34121
  const entries = [];
33989
34122
  for (let i = 0; i < visible.length; i++) {
@@ -33996,7 +34129,7 @@ async function listDirAsync(relativePath) {
33996
34129
  let isDir = d.isDirectory();
33997
34130
  if (d.isSymbolicLink()) {
33998
34131
  try {
33999
- const targetStat = await fs26.promises.stat(fullPath);
34132
+ const targetStat = await fs28.promises.stat(fullPath);
34000
34133
  isDir = targetStat.isDirectory();
34001
34134
  } catch {
34002
34135
  isDir = false;
@@ -34021,25 +34154,25 @@ async function listDirAsync(relativePath) {
34021
34154
  }
34022
34155
 
34023
34156
  // src/files/read-file.ts
34024
- import fs27 from "node:fs";
34157
+ import fs29 from "node:fs";
34025
34158
  import { StringDecoder } from "node:string_decoder";
34026
34159
  function resolveFilePath(relativePath) {
34027
34160
  const resolved = ensureUnderCwd(relativePath, getBridgeWorkspaceDirectory());
34028
34161
  if (!resolved) return { error: "Path is outside working directory" };
34029
34162
  let real;
34030
34163
  try {
34031
- real = fs27.realpathSync(resolved);
34164
+ real = fs29.realpathSync(resolved);
34032
34165
  } catch {
34033
34166
  real = resolved;
34034
34167
  }
34035
- const stat2 = fs27.statSync(real);
34168
+ const stat2 = fs29.statSync(real);
34036
34169
  if (!stat2.isFile()) return { error: "Not a file" };
34037
34170
  return real;
34038
34171
  }
34039
34172
  var LINE_CHUNK_SIZE = 64 * 1024;
34040
34173
  function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
34041
- const fileSize = fs27.statSync(filePath).size;
34042
- const fd = fs27.openSync(filePath, "r");
34174
+ const fileSize = fs29.statSync(filePath).size;
34175
+ const fd = fs29.openSync(filePath, "r");
34043
34176
  const bufSize = 64 * 1024;
34044
34177
  const buf = Buffer.alloc(bufSize);
34045
34178
  const decoder = new StringDecoder("utf8");
@@ -34052,7 +34185,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
34052
34185
  let line0Accum = "";
34053
34186
  try {
34054
34187
  let bytesRead;
34055
- while (!done && (bytesRead = fs27.readSync(fd, buf, 0, bufSize, null)) > 0) {
34188
+ while (!done && (bytesRead = fs29.readSync(fd, buf, 0, bufSize, null)) > 0) {
34056
34189
  const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
34057
34190
  partial2 = "";
34058
34191
  let lineStart = 0;
@@ -34187,7 +34320,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
34187
34320
  }
34188
34321
  return { content: resultLines.join("\n"), size: fileSize };
34189
34322
  } finally {
34190
- fs27.closeSync(fd);
34323
+ fs29.closeSync(fd);
34191
34324
  }
34192
34325
  }
34193
34326
  function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
@@ -34198,8 +34331,8 @@ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize =
34198
34331
  if (hasRange) {
34199
34332
  return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
34200
34333
  }
34201
- const stat2 = fs27.statSync(result);
34202
- const raw = fs27.readFileSync(result, "utf8");
34334
+ const stat2 = fs29.statSync(result);
34335
+ const raw = fs29.readFileSync(result, "utf8");
34203
34336
  const lines = raw.split(/\r?\n/);
34204
34337
  return { content: raw, totalLines: lines.length, size: stat2.size };
34205
34338
  } catch (err) {
@@ -34317,7 +34450,7 @@ function handleSkillLayoutRequest(msg, deps) {
34317
34450
  }
34318
34451
 
34319
34452
  // src/skills/install-remote-skills.ts
34320
- import fs28 from "node:fs";
34453
+ import fs30 from "node:fs";
34321
34454
  import path32 from "node:path";
34322
34455
  function installRemoteSkills(cwd, targetDir, items) {
34323
34456
  const installed2 = [];
@@ -34333,11 +34466,11 @@ function installRemoteSkills(cwd, targetDir, items) {
34333
34466
  for (const f of item.files) {
34334
34467
  if (typeof f.path !== "string" || !f.text && !f.base64) continue;
34335
34468
  const dest = path32.join(skillDir, f.path);
34336
- fs28.mkdirSync(path32.dirname(dest), { recursive: true });
34469
+ fs30.mkdirSync(path32.dirname(dest), { recursive: true });
34337
34470
  if (f.text !== void 0) {
34338
- fs28.writeFileSync(dest, f.text, "utf8");
34471
+ fs30.writeFileSync(dest, f.text, "utf8");
34339
34472
  } else if (f.base64) {
34340
- fs28.writeFileSync(dest, Buffer.from(f.base64, "base64"));
34473
+ fs30.writeFileSync(dest, Buffer.from(f.base64, "base64"));
34341
34474
  }
34342
34475
  }
34343
34476
  installed2.push({
@@ -34487,7 +34620,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
34487
34620
  };
34488
34621
 
34489
34622
  // src/bridge/routing/handlers/revert-turn-snapshot.ts
34490
- import * as fs29 from "node:fs";
34623
+ import * as fs31 from "node:fs";
34491
34624
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
34492
34625
  const id = typeof msg.id === "string" ? msg.id : "";
34493
34626
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -34499,7 +34632,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
34499
34632
  if (!s) return;
34500
34633
  const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ?? getBridgeWorkspaceDirectory();
34501
34634
  const file2 = snapshotFilePath(agentBase, turnId);
34502
- if (!fs29.existsSync(file2)) {
34635
+ if (!fs31.existsSync(file2)) {
34503
34636
  sendWsMessage(s, {
34504
34637
  type: "revert_turn_snapshot_result",
34505
34638
  id,
@@ -34557,6 +34690,9 @@ function dispatchBridgeMessage(msg, deps) {
34557
34690
  case "agent_config":
34558
34691
  handleAgentConfigMessage(msg, deps);
34559
34692
  break;
34693
+ case "prompt_queue_state":
34694
+ handlePromptQueueStateMessage(msg, deps);
34695
+ break;
34560
34696
  case "prompt":
34561
34697
  handlePromptMessage(msg, deps);
34562
34698
  break;