@buildautomaton/cli 0.1.5 → 0.1.6

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
@@ -974,7 +974,7 @@ var require_command = __commonJS({
974
974
  var EventEmitter2 = __require("node:events").EventEmitter;
975
975
  var childProcess = __require("node:child_process");
976
976
  var path25 = __require("node:path");
977
- var fs22 = __require("node:fs");
977
+ var fs21 = __require("node:fs");
978
978
  var process2 = __require("node:process");
979
979
  var { Argument: Argument2, humanReadableArgName } = require_argument();
980
980
  var { CommanderError: CommanderError2 } = require_error();
@@ -1907,10 +1907,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
1907
1907
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1908
1908
  function findFile(baseDir, baseName) {
1909
1909
  const localBin = path25.resolve(baseDir, baseName);
1910
- if (fs22.existsSync(localBin)) return localBin;
1910
+ if (fs21.existsSync(localBin)) return localBin;
1911
1911
  if (sourceExt.includes(path25.extname(baseName))) return void 0;
1912
1912
  const foundExt = sourceExt.find(
1913
- (ext) => fs22.existsSync(`${localBin}${ext}`)
1913
+ (ext) => fs21.existsSync(`${localBin}${ext}`)
1914
1914
  );
1915
1915
  if (foundExt) return `${localBin}${foundExt}`;
1916
1916
  return void 0;
@@ -1922,7 +1922,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1922
1922
  if (this._scriptPath) {
1923
1923
  let resolvedScriptPath;
1924
1924
  try {
1925
- resolvedScriptPath = fs22.realpathSync(this._scriptPath);
1925
+ resolvedScriptPath = fs21.realpathSync(this._scriptPath);
1926
1926
  } catch (err) {
1927
1927
  resolvedScriptPath = this._scriptPath;
1928
1928
  }
@@ -7426,12 +7426,12 @@ var require_src2 = __commonJS({
7426
7426
  function check2(path25, isFile, isDirectory) {
7427
7427
  log2(`checking %s`, path25);
7428
7428
  try {
7429
- const stat = fs_1.statSync(path25);
7430
- if (stat.isFile() && isFile) {
7429
+ const stat2 = fs_1.statSync(path25);
7430
+ if (stat2.isFile() && isFile) {
7431
7431
  log2(`[OK] path represents a file`);
7432
7432
  return true;
7433
7433
  }
7434
- if (stat.isDirectory() && isDirectory) {
7434
+ if (stat2.isDirectory() && isDirectory) {
7435
7435
  log2(`[OK] path represents a directory`);
7436
7436
  return true;
7437
7437
  }
@@ -25047,7 +25047,7 @@ var init_acp = __esm({
25047
25047
  });
25048
25048
 
25049
25049
  // src/cli.ts
25050
- import * as fs21 from "node:fs";
25050
+ import * as fs20 from "node:fs";
25051
25051
  import * as path24 from "node:path";
25052
25052
 
25053
25053
  // ../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/esm.mjs
@@ -25179,13 +25179,31 @@ var wrapper_default = import_websocket.default;
25179
25179
 
25180
25180
  // src/bridge/connection/create-ws-bridge.ts
25181
25181
  import https from "node:https";
25182
+
25183
+ // src/net/apply-cli-outbound-network-prefs.ts
25184
+ import dns from "node:dns";
25185
+ var applied = false;
25186
+ function applyCliOutboundNetworkPreferences() {
25187
+ if (applied) return;
25188
+ applied = true;
25189
+ try {
25190
+ dns.setDefaultResultOrder("ipv4first");
25191
+ } catch {
25192
+ }
25193
+ }
25194
+
25195
+ // src/bridge/connection/create-ws-bridge.ts
25182
25196
  var BRIDGE_AUTH_ERROR_HEADER = "x-bridge-auth-error";
25183
25197
  var BRIDGE_AUTH_ERROR_TOKEN_INVALID = "token_invalid";
25184
25198
  function createWsBridge(options) {
25185
25199
  const { url: url2, onMessage, onOpen, onClose, onError: onError2, onAuthInvalid, clientPingIntervalMs } = options;
25186
- const wsOptions = {};
25200
+ applyCliOutboundNetworkPreferences();
25201
+ const wsOptions = {
25202
+ perMessageDeflate: false,
25203
+ family: 4
25204
+ };
25187
25205
  if (url2.startsWith("wss://")) {
25188
- wsOptions.agent = new https.Agent({ rejectUnauthorized: false });
25206
+ wsOptions.agent = new https.Agent({ rejectUnauthorized: false, family: 4 });
25189
25207
  }
25190
25208
  const ws = new wrapper_default(url2, wsOptions);
25191
25209
  let clientPingTimer = null;
@@ -25408,7 +25426,7 @@ function beginMainBridgeDeferredDisconnect(state, code, reason, log2, willReconn
25408
25426
  });
25409
25427
  }
25410
25428
  function clearMainBridgeReconnectQuietOnOpen(state, log2) {
25411
- clearReconnectQuietOnSuccessfulConnection(state.mainQuiet, log2, "[Bridge service] Reconnected.");
25429
+ clearReconnectQuietOnSuccessfulConnection(state.mainQuiet, log2, "Bridge connection restored.");
25412
25430
  }
25413
25431
  function scheduleMainBridgeReconnect(state, connect, log2) {
25414
25432
  if (state.closedByUser || state.currentWs != null) return;
@@ -25445,7 +25463,7 @@ function clearFirehoseReconnectQuietOnOpen(ctx, log2) {
25445
25463
  clearReconnectQuietOnSuccessfulConnection(
25446
25464
  ctx.firehoseQuiet,
25447
25465
  log2,
25448
- `${PROXY_AND_LOG_SERVICE_LABEL} Reconnected.`
25466
+ "Preview tunnel restored (local HTTP proxy and dev logs)."
25449
25467
  );
25450
25468
  }
25451
25469
 
@@ -30256,34 +30274,31 @@ function reportGitRepos(getWs, log2) {
30256
30274
 
30257
30275
  // src/bridge/connection/close-bridge-connection.ts
30258
30276
  async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
30259
- log2?.("Shutting down\u2026");
30277
+ const say = log2 ?? logImmediate;
30278
+ say("Cleaning up connections\u2026");
30260
30279
  await new Promise((resolve15) => setImmediate(resolve15));
30261
- if (devServerManager) {
30262
- log2?.("Requesting dev server processes to stop\u2026");
30263
- await devServerManager.shutdownAllGraceful();
30264
- }
30265
30280
  state.closedByUser = true;
30266
30281
  clearReconnectQuietTimer(state.mainQuiet);
30267
30282
  clearReconnectQuietTimer(state.firehoseQuiet);
30268
30283
  if (state.reconnectTimeout != null) {
30269
- log2?.("Cancelling reconnect timer\u2026");
30284
+ say("Cancelling bridge reconnect timer\u2026");
30270
30285
  clearTimeout(state.reconnectTimeout);
30271
30286
  state.reconnectTimeout = null;
30272
30287
  }
30273
30288
  if (state.firehoseReconnectTimeout != null) {
30274
- log2?.("[Proxy and log service] Cancelling reconnect timer\u2026");
30289
+ say("Cancelling preview tunnel reconnect timer\u2026");
30275
30290
  clearTimeout(state.firehoseReconnectTimeout);
30276
30291
  state.firehoseReconnectTimeout = null;
30277
30292
  }
30278
30293
  if (state.firehoseHandle) {
30279
- log2?.("[Proxy and log service] Closing connection (CLI shutdown)\u2026");
30294
+ say("Closing preview tunnel (local HTTP proxy and dev logs)\u2026");
30280
30295
  state.firehoseHandle.close();
30281
30296
  state.firehoseHandle = null;
30282
30297
  }
30283
- log2?.("Disconnecting local agents (ACP)\u2026");
30298
+ say("Disconnecting local agent\u2026");
30284
30299
  acpManager.disconnect();
30285
30300
  if (state.currentWs) {
30286
- log2?.("[Bridge service] Closing connection (CLI shutdown)\u2026");
30301
+ say("Closing bridge connection to the cloud\u2026");
30287
30302
  state.currentWs.removeAllListeners();
30288
30303
  const wsState = state.currentWs.readyState;
30289
30304
  if (wsState === 1 || wsState === 2) {
@@ -30296,12 +30311,17 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
30296
30311
  }
30297
30312
  state.currentWs = null;
30298
30313
  }
30314
+ if (devServerManager) {
30315
+ say("Stopping local dev server processes\u2026");
30316
+ await devServerManager.shutdownAllGraceful();
30317
+ }
30318
+ say("Shutdown complete.");
30299
30319
  }
30300
30320
 
30301
30321
  // src/git/session-git-queue.ts
30302
30322
  import { execFile as execFile2 } from "node:child_process";
30323
+ import { readFile, stat } from "node:fs/promises";
30303
30324
  import { promisify as promisify2 } from "node:util";
30304
- import * as fs4 from "node:fs";
30305
30325
  import * as path5 from "node:path";
30306
30326
 
30307
30327
  // src/git/pre-turn-snapshot.ts
@@ -30416,11 +30436,11 @@ function snapshotFilePath(agentCwd, runId) {
30416
30436
  // src/git/session-git-queue.ts
30417
30437
  var execFileAsync2 = promisify2(execFile2);
30418
30438
  var MAX_FULL_FILE_TEXT_BYTES = 512 * 1024;
30419
- function readWorkspaceFileAsUtf8(absPath) {
30439
+ async function readWorkspaceFileAsUtf8(absPath) {
30420
30440
  try {
30421
- const st = fs4.statSync(absPath);
30441
+ const st = await stat(absPath);
30422
30442
  if (!st.isFile() || st.size > MAX_FULL_FILE_TEXT_BYTES) return void 0;
30423
- return fs4.readFileSync(absPath, "utf8");
30443
+ return await readFile(absPath, "utf8");
30424
30444
  } catch {
30425
30445
  return void 0;
30426
30446
  }
@@ -30430,7 +30450,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
30430
30450
  const filePath = snapshotFilePath(agentCwd, runId);
30431
30451
  let data;
30432
30452
  try {
30433
- const raw = fs4.readFileSync(filePath, "utf8");
30453
+ const raw = await readFile(filePath, "utf8");
30434
30454
  data = JSON.parse(raw);
30435
30455
  } catch (e) {
30436
30456
  log2(
@@ -30474,7 +30494,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
30474
30494
  if (!patchContent.trim()) continue;
30475
30495
  const displayPath = multiRepo ? `${slug}/${rel}` : rel;
30476
30496
  const absFile = path5.join(repo.path, rel);
30477
- const newText = readWorkspaceFileAsUtf8(absFile);
30497
+ const newText = await readWorkspaceFileAsUtf8(absFile);
30478
30498
  sendSessionUpdate({
30479
30499
  type: "session_file_change",
30480
30500
  sessionId,
@@ -30529,7 +30549,6 @@ async function sendPromptToAgent(options) {
30529
30549
  } catch (err) {
30530
30550
  const errMsg = err instanceof Error ? err.message : String(err);
30531
30551
  log2(`[Agent] Send failed: ${errMsg}`);
30532
- if (err instanceof Error && err.stack) log2(`[Agent] ${err.stack}`);
30533
30552
  sendResult({
30534
30553
  type: "prompt_result",
30535
30554
  id: promptId,
@@ -30542,7 +30561,7 @@ async function sendPromptToAgent(options) {
30542
30561
  }
30543
30562
 
30544
30563
  // src/acp/ensure-acp-client.ts
30545
- import * as fs5 from "node:fs";
30564
+ import * as fs4 from "node:fs";
30546
30565
  import * as path9 from "node:path";
30547
30566
 
30548
30567
  // src/error-message.ts
@@ -30555,9 +30574,77 @@ function errorMessage(err) {
30555
30574
  return String(err);
30556
30575
  }
30557
30576
 
30558
- // src/acp/clients/acp-client.ts
30577
+ // src/acp/clients/sdk-stdio-acp-client.ts
30559
30578
  import { spawn as spawn2 } from "node:child_process";
30579
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
30580
+ import { dirname } from "node:path";
30560
30581
  import { Readable, Writable } from "node:stream";
30582
+
30583
+ // src/files/diff/unified-diff.ts
30584
+ function computeLineDiff(oldText, newText) {
30585
+ const oldLines = oldText.split("\n");
30586
+ const newLines = newText.split("\n");
30587
+ const m = oldLines.length;
30588
+ const n = newLines.length;
30589
+ const dp = Array(m + 1);
30590
+ for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
30591
+ for (let i2 = 1; i2 <= m; i2++) {
30592
+ for (let j2 = 1; j2 <= n; j2++) {
30593
+ if (oldLines[i2 - 1] === newLines[j2 - 1]) {
30594
+ dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
30595
+ } else {
30596
+ dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
30597
+ }
30598
+ }
30599
+ }
30600
+ const result = [];
30601
+ let i = m;
30602
+ let j = n;
30603
+ while (i > 0 || j > 0) {
30604
+ if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
30605
+ result.unshift({ type: "context", line: oldLines[i - 1] });
30606
+ i--;
30607
+ j--;
30608
+ } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
30609
+ result.unshift({ type: "add", line: newLines[j - 1] });
30610
+ j--;
30611
+ } else {
30612
+ result.unshift({ type: "remove", line: oldLines[i - 1] });
30613
+ i--;
30614
+ }
30615
+ }
30616
+ return result;
30617
+ }
30618
+ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
30619
+ const lines = computeLineDiff(oldText, newText);
30620
+ const out = [`--- ${filePath}`, `+++ ${filePath}`];
30621
+ for (const d of lines) {
30622
+ if (d.type === "add") out.push(`+${d.line}`);
30623
+ else if (d.type === "remove") out.push(`-${d.line}`);
30624
+ else out.push(` ${d.line}`);
30625
+ }
30626
+ return out.join("\n");
30627
+ }
30628
+
30629
+ // src/acp/safe-fs-path.ts
30630
+ import * as path6 from "node:path";
30631
+ function resolveSafePathUnderCwd(cwd, filePath) {
30632
+ const trimmed2 = filePath.trim();
30633
+ if (!trimmed2) return null;
30634
+ const normalizedCwd = path6.resolve(cwd);
30635
+ const resolved = path6.isAbsolute(trimmed2) ? path6.normalize(trimmed2) : path6.resolve(normalizedCwd, trimmed2);
30636
+ const rel = path6.relative(normalizedCwd, resolved);
30637
+ if (rel.startsWith("..") || path6.isAbsolute(rel)) return null;
30638
+ return resolved;
30639
+ }
30640
+ function toDisplayPathRelativeToCwd(cwd, absolutePath) {
30641
+ const normalizedCwd = path6.resolve(cwd);
30642
+ const rel = path6.relative(normalizedCwd, path6.resolve(absolutePath));
30643
+ if (!rel || rel === "") return path6.basename(absolutePath);
30644
+ return rel.split(path6.sep).join("/");
30645
+ }
30646
+
30647
+ // src/acp/clients/sdk-stdio-acp-client.ts
30561
30648
  function formatSpawnError(err, command) {
30562
30649
  if (err.code === "ENOENT") {
30563
30650
  return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
@@ -30572,9 +30659,26 @@ function toErrorMessage(err) {
30572
30659
  if (err != null && typeof err === "object") return JSON.stringify(err);
30573
30660
  return String(err);
30574
30661
  }
30575
- async function createAcpClient(options) {
30576
- const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
30577
- const { command, cwd = getBridgeWorkspaceDirectory(), onSessionUpdate } = options;
30662
+ function sliceFileContentRange(content, line, limit) {
30663
+ if (line == null && limit == null) return content;
30664
+ const lines = content.split("\n");
30665
+ const start = line != null && line > 0 ? line - 1 : 0;
30666
+ const end = limit != null && limit > 0 ? start + limit : lines.length;
30667
+ return lines.slice(start, end).join("\n");
30668
+ }
30669
+ function bridgePayloadFromSdkSessionNotification(params) {
30670
+ return { sessionId: params.sessionId, ...params.update };
30671
+ }
30672
+ async function createSdkStdioAcpClient(options) {
30673
+ const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
30674
+ const {
30675
+ command,
30676
+ cwd = getBridgeWorkspaceDirectory(),
30677
+ onSessionUpdate,
30678
+ onFileChange,
30679
+ killSubprocessAfterCancelMs,
30680
+ onAgentSubprocessExit
30681
+ } = options;
30578
30682
  const isWindows = process.platform === "win32";
30579
30683
  const child = spawn2(command[0], command.slice(1), {
30580
30684
  cwd,
@@ -30582,6 +30686,9 @@ async function createAcpClient(options) {
30582
30686
  env: process.env,
30583
30687
  shell: isWindows
30584
30688
  });
30689
+ child.once("close", (code, signal) => {
30690
+ onAgentSubprocessExit?.({ code, signal });
30691
+ });
30585
30692
  return new Promise((resolve15, reject) => {
30586
30693
  child.on("error", (err) => {
30587
30694
  child.kill();
@@ -30593,11 +30700,43 @@ async function createAcpClient(options) {
30593
30700
  const readable = Readable.toWeb(child.stdout);
30594
30701
  const stream = ndJsonStream2(writable, readable);
30595
30702
  const client = (_agent) => ({
30596
- async requestPermission(_params) {
30597
- return { outcome: "approved" };
30703
+ async requestPermission(params) {
30704
+ const opt = params?.options?.[0];
30705
+ if (opt && typeof opt.optionId === "string") {
30706
+ return { outcome: { outcome: "selected", optionId: opt.optionId } };
30707
+ }
30708
+ return { outcome: { outcome: "cancelled" } };
30709
+ },
30710
+ async readTextFile(params) {
30711
+ const abs = resolveSafePathUnderCwd(cwd, params.path);
30712
+ if (!abs) throw new Error("Invalid or disallowed path");
30713
+ try {
30714
+ let content = readFileSync2(abs, "utf8");
30715
+ content = sliceFileContentRange(content, params.line, params.limit);
30716
+ return { content };
30717
+ } catch (e) {
30718
+ if (e.code === "ENOENT") return { content: "" };
30719
+ throw e;
30720
+ }
30721
+ },
30722
+ async writeTextFile(params) {
30723
+ const abs = resolveSafePathUnderCwd(cwd, params.path);
30724
+ if (!abs) throw new Error("Invalid or disallowed path");
30725
+ let oldText = "";
30726
+ try {
30727
+ oldText = readFileSync2(abs, "utf8");
30728
+ } catch (e) {
30729
+ if (e.code !== "ENOENT") throw e;
30730
+ }
30731
+ mkdirSync2(dirname(abs), { recursive: true });
30732
+ writeFileSync2(abs, params.content, "utf8");
30733
+ const displayPath = toDisplayPathRelativeToCwd(cwd, abs);
30734
+ const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, params.content);
30735
+ onFileChange?.({ path: displayPath, oldText, newText: params.content, patchContent });
30736
+ return {};
30598
30737
  },
30599
30738
  async sessionUpdate(params) {
30600
- onSessionUpdate?.(params);
30739
+ onSessionUpdate?.(bridgePayloadFromSdkSessionNotification(params));
30601
30740
  }
30602
30741
  });
30603
30742
  const connection = new ClientSideConnection2(client, stream);
@@ -30605,11 +30744,13 @@ async function createAcpClient(options) {
30605
30744
  child.kill();
30606
30745
  });
30607
30746
  await connection.initialize({
30608
- protocolVersion: "0.1.0",
30609
- capabilities: {},
30747
+ protocolVersion: PROTOCOL_VERSION2,
30748
+ clientCapabilities: {
30749
+ fs: { readTextFile: true, writeTextFile: true }
30750
+ },
30610
30751
  clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
30611
30752
  });
30612
- const newSessionRes = await connection.newSession({ workingDirectory: cwd });
30753
+ const newSessionRes = await connection.newSession({ cwd, mcpServers: [] });
30613
30754
  const sessionId = newSessionRes.sessionId;
30614
30755
  resolve15({
30615
30756
  sessionId,
@@ -30617,7 +30758,7 @@ async function createAcpClient(options) {
30617
30758
  try {
30618
30759
  const response = await connection.prompt({
30619
30760
  sessionId,
30620
- prompt: { type: "text", text: prompt }
30761
+ prompt: [{ type: "text", text: prompt }]
30621
30762
  });
30622
30763
  const r = response;
30623
30764
  const cancelled = (r?.stopReason ?? "").toLowerCase() === "cancelled";
@@ -30635,9 +30776,17 @@ async function createAcpClient(options) {
30635
30776
  }
30636
30777
  },
30637
30778
  async cancel() {
30638
- const conn = connection;
30639
- if (typeof conn.cancel === "function") {
30640
- await conn.cancel({ sessionId });
30779
+ try {
30780
+ await connection.cancel({ sessionId });
30781
+ } catch {
30782
+ }
30783
+ if (killSubprocessAfterCancelMs != null && killSubprocessAfterCancelMs >= 0) {
30784
+ const t = setTimeout(() => {
30785
+ if (child.exitCode == null && child.signalCode == null) {
30786
+ child.kill("SIGTERM");
30787
+ }
30788
+ }, killSubprocessAfterCancelMs);
30789
+ t.unref?.();
30641
30790
  }
30642
30791
  },
30643
30792
  resolveRequest() {
@@ -30660,81 +30809,38 @@ function isCodexAcpCommand(command) {
30660
30809
  const i = command.indexOf("@zed-industries/codex-acp");
30661
30810
  return i >= 0 && (i === 0 || command[i - 1] === "npx" || command[i - 1] === "bunx");
30662
30811
  }
30812
+ function buildCodexAcpSpawnCommand(base, _sessionMode) {
30813
+ return [...base];
30814
+ }
30663
30815
  async function createCodexAcpClient(options) {
30664
- const command = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
30665
- return createAcpClient({ ...options, command });
30816
+ const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
30817
+ const command = buildCodexAcpSpawnCommand(base, options.sessionMode);
30818
+ return createSdkStdioAcpClient({ ...options, command });
30819
+ }
30820
+
30821
+ // src/acp/clients/claude-code-acp-client.ts
30822
+ function buildClaudeCodeAcpSpawnCommand(base, sessionMode) {
30823
+ if (!sessionMode) return [...base];
30824
+ const m = sessionMode.trim();
30825
+ if (m === "plan") return [...base, "--permission-mode", "plan"];
30826
+ return [...base];
30827
+ }
30828
+ async function createClaudeCodeAcpClient(options) {
30829
+ const command = buildClaudeCodeAcpSpawnCommand(options.command, options.sessionMode);
30830
+ return createSdkStdioAcpClient({
30831
+ ...options,
30832
+ command,
30833
+ /** Claude-based agents sometimes ignore `session/cancel`; unblocks stop / stuck prompt. */
30834
+ killSubprocessAfterCancelMs: options.killSubprocessAfterCancelMs ?? 1e3
30835
+ });
30666
30836
  }
30667
30837
 
30668
30838
  // src/acp/clients/cursor-acp-client.ts
30669
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
30670
- import { dirname } from "node:path";
30839
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
30840
+ import { dirname as dirname2 } from "node:path";
30671
30841
  import { spawn as spawn3 } from "node:child_process";
30672
30842
  import * as readline from "node:readline";
30673
30843
 
30674
- // src/acp/safe-fs-path.ts
30675
- import * as path6 from "node:path";
30676
- function resolveSafePathUnderCwd(cwd, filePath) {
30677
- const trimmed2 = filePath.trim();
30678
- if (!trimmed2) return null;
30679
- const normalizedCwd = path6.resolve(cwd);
30680
- const resolved = path6.isAbsolute(trimmed2) ? path6.normalize(trimmed2) : path6.resolve(normalizedCwd, trimmed2);
30681
- const rel = path6.relative(normalizedCwd, resolved);
30682
- if (rel.startsWith("..") || path6.isAbsolute(rel)) return null;
30683
- return resolved;
30684
- }
30685
- function toDisplayPathRelativeToCwd(cwd, absolutePath) {
30686
- const normalizedCwd = path6.resolve(cwd);
30687
- const rel = path6.relative(normalizedCwd, path6.resolve(absolutePath));
30688
- if (!rel || rel === "") return path6.basename(absolutePath);
30689
- return rel.split(path6.sep).join("/");
30690
- }
30691
-
30692
- // src/files/diff/unified-diff.ts
30693
- function computeLineDiff(oldText, newText) {
30694
- const oldLines = oldText.split("\n");
30695
- const newLines = newText.split("\n");
30696
- const m = oldLines.length;
30697
- const n = newLines.length;
30698
- const dp = Array(m + 1);
30699
- for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
30700
- for (let i2 = 1; i2 <= m; i2++) {
30701
- for (let j2 = 1; j2 <= n; j2++) {
30702
- if (oldLines[i2 - 1] === newLines[j2 - 1]) {
30703
- dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
30704
- } else {
30705
- dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
30706
- }
30707
- }
30708
- }
30709
- const result = [];
30710
- let i = m;
30711
- let j = n;
30712
- while (i > 0 || j > 0) {
30713
- if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
30714
- result.unshift({ type: "context", line: oldLines[i - 1] });
30715
- i--;
30716
- j--;
30717
- } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
30718
- result.unshift({ type: "add", line: newLines[j - 1] });
30719
- j--;
30720
- } else {
30721
- result.unshift({ type: "remove", line: oldLines[i - 1] });
30722
- i--;
30723
- }
30724
- }
30725
- return result;
30726
- }
30727
- function editSnippetToUnifiedDiff(filePath, oldText, newText) {
30728
- const lines = computeLineDiff(oldText, newText);
30729
- const out = [`--- ${filePath}`, `+++ ${filePath}`];
30730
- for (const d of lines) {
30731
- if (d.type === "add") out.push(`+${d.line}`);
30732
- else if (d.type === "remove") out.push(`-${d.line}`);
30733
- else out.push(` ${d.line}`);
30734
- }
30735
- return out.join("\n");
30736
- }
30737
-
30738
30844
  // src/acp/format-session-update-kind-for-log.ts
30739
30845
  var SESSION_UPDATE_KIND_LABELS = {
30740
30846
  tool_call: "Tool call",
@@ -30772,8 +30878,15 @@ function sliceLinesByRange(content, line, limit) {
30772
30878
  const end = limit != null && limit > 0 ? start + limit : lines.length;
30773
30879
  return lines.slice(start, end).join("\n");
30774
30880
  }
30881
+ function buildCursorAcpSpawnCommand(base, sessionMode) {
30882
+ if (!sessionMode) return [...base];
30883
+ const m = sessionMode.trim();
30884
+ if (m !== "ask" && m !== "plan") return [...base];
30885
+ return [...base, "--mode", m];
30886
+ }
30775
30887
  async function createCursorAcpClient(options) {
30776
- const { command, cwd = getBridgeWorkspaceDirectory(), onSessionUpdate, onRequest, onFileChange } = options;
30888
+ const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
30889
+ const { cwd = getBridgeWorkspaceDirectory(), onSessionUpdate, onRequest, onFileChange } = options;
30777
30890
  const dbgFs = process.env.BUILDAMATON_DEBUG_ACP_FS === "1";
30778
30891
  const isWindows = process.platform === "win32";
30779
30892
  const child = spawn3(command[0], command.slice(1), {
@@ -30905,8 +31018,8 @@ async function createCursorAcpClient(options) {
30905
31018
  }
30906
31019
  }
30907
31020
  try {
30908
- mkdirSync2(dirname(abs), { recursive: true });
30909
- writeFileSync2(abs, newText, "utf8");
31021
+ mkdirSync3(dirname2(abs), { recursive: true });
31022
+ writeFileSync3(abs, newText, "utf8");
30910
31023
  } catch (e) {
30911
31024
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
30912
31025
  return;
@@ -31004,8 +31117,20 @@ async function createCursorAcpClient(options) {
31004
31117
  var AGENT_TYPE_DEFAULT_COMMANDS = {
31005
31118
  "cursor-cli": ["agent", "acp"],
31006
31119
  "codex-acp": [...DEFAULT_CODEX_ACP_COMMAND],
31007
- "claude-code": ["npx", "--yes", "@anthropic-ai/claude-code"]
31120
+ /** ACP stdio agent; `@anthropic-ai/claude-code` is the interactive CLI and does not speak ACP on stdout. */
31121
+ "claude-code": ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"]
31122
+ };
31123
+ var AGENT_TYPE_DISPLAY_NAMES = {
31124
+ "cursor-cli": "Cursor",
31125
+ "codex-acp": "Codex",
31126
+ "claude-code": "Claude Code"
31008
31127
  };
31128
+ function getAgentTypeDisplayName(agentType) {
31129
+ if (agentType == null || agentType === "") return "Unknown agent";
31130
+ const known = AGENT_TYPE_DISPLAY_NAMES[agentType];
31131
+ if (known) return known;
31132
+ return agentType.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
31133
+ }
31009
31134
  function useCursorAcp(agentType, command) {
31010
31135
  if (agentType === "cursor-cli") return true;
31011
31136
  return command[0] === "agent" && command[1] === "acp";
@@ -31018,14 +31143,33 @@ function resolveAgentCommand(preferredAgentType) {
31018
31143
  if (!preferredAgentType) return null;
31019
31144
  const command = AGENT_TYPE_DEFAULT_COMMANDS[preferredAgentType];
31020
31145
  if (!command?.length) return null;
31021
- const createClient = useCursorAcp(preferredAgentType, command) ? createCursorAcpClient : useCodexAcp(preferredAgentType, command) ? createCodexAcpClient : createAcpClient;
31022
- const label = preferredAgentType;
31023
- return { command, label, createClient };
31146
+ if (useCursorAcp(preferredAgentType, command)) {
31147
+ return {
31148
+ command,
31149
+ label: preferredAgentType,
31150
+ createClient: createCursorAcpClient,
31151
+ spawnCommandForSession: (sessionMode) => buildCursorAcpSpawnCommand(command, sessionMode)
31152
+ };
31153
+ }
31154
+ if (useCodexAcp(preferredAgentType, command)) {
31155
+ return {
31156
+ command,
31157
+ label: preferredAgentType,
31158
+ createClient: createCodexAcpClient,
31159
+ spawnCommandForSession: (sessionMode) => buildCodexAcpSpawnCommand(command, sessionMode)
31160
+ };
31161
+ }
31162
+ return {
31163
+ command,
31164
+ label: preferredAgentType,
31165
+ createClient: createClaudeCodeAcpClient,
31166
+ spawnCommandForSession: (sessionMode) => buildClaudeCodeAcpSpawnCommand(command, sessionMode)
31167
+ };
31024
31168
  }
31025
31169
 
31026
31170
  // src/acp/session-file-change-path-kind.ts
31027
31171
  import { execFileSync as execFileSync3 } from "node:child_process";
31028
- import { existsSync, statSync as statSync2 } from "node:fs";
31172
+ import { existsSync, statSync } from "node:fs";
31029
31173
 
31030
31174
  // src/git/get-git-repo-root-sync.ts
31031
31175
  import { execFileSync } from "node:child_process";
@@ -31134,7 +31278,7 @@ function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
31134
31278
  const abs = tryWorkspaceDisplayToAbs(cwd, displayPath);
31135
31279
  if (abs && existsSync(abs)) {
31136
31280
  try {
31137
- if (statSync2(abs).isDirectory()) {
31281
+ if (statSync(abs).isDirectory()) {
31138
31282
  return { isDirectory: true, directoryRemoved: false };
31139
31283
  }
31140
31284
  return { isDirectory: false, directoryRemoved: false };
@@ -31680,7 +31824,8 @@ async function ensureAcpClient(options) {
31680
31824
  state.lastAcpStartError = "No agent type: ensure the app sends agentType on prompts or agent_config for this bridge.";
31681
31825
  return null;
31682
31826
  }
31683
- const agentKey = `${resolved.label}::${resolved.command.join("\0")}`;
31827
+ const fullCmd = resolved.spawnCommandForSession(mode);
31828
+ const agentKey = `${resolved.label}::${fullCmd.join("\0")}`;
31684
31829
  if (state.acpHandle && state.acpAgentKey !== agentKey) {
31685
31830
  try {
31686
31831
  state.acpHandle.disconnect();
@@ -31694,7 +31839,7 @@ async function ensureAcpClient(options) {
31694
31839
  if (!state.acpStartPromise) {
31695
31840
  let statOk = false;
31696
31841
  try {
31697
- const st = fs5.statSync(targetCwd);
31842
+ const st = fs4.statSync(targetCwd);
31698
31843
  statOk = st.isDirectory();
31699
31844
  if (!statOk) {
31700
31845
  state.lastAcpStartError = `Agent cwd is not a directory: ${targetCwd}`;
@@ -31707,8 +31852,6 @@ async function ensureAcpClient(options) {
31707
31852
  if (!statOk) {
31708
31853
  return null;
31709
31854
  }
31710
- const modeFlag = mode && ["ask", "plan"].includes(mode) ? ["--mode", mode] : [];
31711
- const fullCmd = [...resolved.command, ...modeFlag];
31712
31855
  const hooks = buildAcpSessionBridgeHooks({
31713
31856
  routing,
31714
31857
  getSendSessionUpdate: () => sendSessionUpdate,
@@ -31716,8 +31859,15 @@ async function ensureAcpClient(options) {
31716
31859
  log: log2
31717
31860
  });
31718
31861
  state.acpStartPromise = resolved.createClient({
31719
- command: fullCmd,
31862
+ command: resolved.command,
31863
+ sessionMode: mode,
31720
31864
  cwd: targetCwd,
31865
+ onAgentSubprocessExit: () => {
31866
+ state.acpHandle = null;
31867
+ state.acpStartPromise = null;
31868
+ state.acpAgentKey = null;
31869
+ state.lastAcpStartError = "Agent subprocess exited";
31870
+ },
31721
31871
  ...hooks
31722
31872
  }).then((h) => {
31723
31873
  state.lastAcpStartError = null;
@@ -31755,6 +31905,14 @@ async function createAcpManager(options) {
31755
31905
  backendFallbackAgentType = agentType;
31756
31906
  }
31757
31907
  }
31908
+ function logPromptReceivedFromBridge(opts) {
31909
+ const { agentType, mode } = opts;
31910
+ const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
31911
+ const modeLabel = typeof mode === "string" && mode.trim() !== "" ? mode.trim() : "not set";
31912
+ log2(
31913
+ `[Agent] Prompt received (${getAgentTypeDisplayName(preferredForPrompt)}, mode: ${modeLabel})`
31914
+ );
31915
+ }
31758
31916
  function handlePrompt(opts) {
31759
31917
  const {
31760
31918
  promptText,
@@ -31835,6 +31993,7 @@ async function createAcpManager(options) {
31835
31993
  if (promptRouting.runId !== runId) return false;
31836
31994
  const handle = state.acpHandle;
31837
31995
  if (handle?.cancel) {
31996
+ log2("[Agent] Stop requested");
31838
31997
  try {
31839
31998
  await handle.cancel();
31840
31999
  return true;
@@ -31843,6 +32002,7 @@ async function createAcpManager(options) {
31843
32002
  return false;
31844
32003
  }
31845
32004
  }
32005
+ log2("[Agent] Stop requested (agent still starting)");
31846
32006
  pendingCancelRunId = runId;
31847
32007
  return true;
31848
32008
  }
@@ -31855,7 +32015,14 @@ async function createAcpManager(options) {
31855
32015
  state.acpStartPromise = null;
31856
32016
  state.acpAgentKey = null;
31857
32017
  }
31858
- return { setPreferredAgentType, handlePrompt, cancelRun, resolveRequest, disconnect };
32018
+ return {
32019
+ setPreferredAgentType,
32020
+ logPromptReceivedFromBridge,
32021
+ handlePrompt,
32022
+ cancelRun,
32023
+ resolveRequest,
32024
+ disconnect
32025
+ };
31859
32026
  }
31860
32027
 
31861
32028
  // src/bridge/routing/handlers/auth-token.ts
@@ -31990,6 +32157,8 @@ function handleBridgePrompt(msg, deps) {
31990
32157
  const sessionWorktreesEnabled = msg.sessionWorktreesEnabled === true;
31991
32158
  const agentType = typeof msg.agentType === "string" && msg.agentType.trim() ? msg.agentType.trim() : void 0;
31992
32159
  const runId = typeof msg.runId === "string" ? msg.runId : void 0;
32160
+ const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
32161
+ acpManager.logPromptReceivedFromBridge({ agentType, mode });
31993
32162
  const sendResult = (result) => {
31994
32163
  const s = getWs();
31995
32164
  if (s) sendWsMessage(s, result);
@@ -32052,7 +32221,7 @@ function handleBridgePrompt(msg, deps) {
32052
32221
  promptId: msg.id,
32053
32222
  sessionId,
32054
32223
  runId,
32055
- mode: msg.mode,
32224
+ mode,
32056
32225
  agentType,
32057
32226
  cwd: effectiveCwd,
32058
32227
  sendResult,
@@ -32296,7 +32465,7 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
32296
32465
  };
32297
32466
 
32298
32467
  // src/files/list-dir.ts
32299
- import fs6 from "node:fs";
32468
+ import fs5 from "node:fs";
32300
32469
  import path13 from "node:path";
32301
32470
 
32302
32471
  // src/files/ensure-under-cwd.ts
@@ -32317,14 +32486,14 @@ function listDir(relativePath) {
32317
32486
  return { error: "Path is outside working directory" };
32318
32487
  }
32319
32488
  try {
32320
- const names = fs6.readdirSync(resolved, { withFileTypes: true });
32489
+ const names = fs5.readdirSync(resolved, { withFileTypes: true });
32321
32490
  const entries = names.filter((d) => !d.name.startsWith(".")).map((d) => {
32322
32491
  const entryPath = path13.join(relativePath || ".", d.name).replace(/\\/g, "/");
32323
32492
  const fullPath = path13.join(resolved, d.name);
32324
32493
  let isDir = d.isDirectory();
32325
32494
  if (d.isSymbolicLink()) {
32326
32495
  try {
32327
- const targetStat = fs6.statSync(fullPath);
32496
+ const targetStat = fs5.statSync(fullPath);
32328
32497
  isDir = targetStat.isDirectory();
32329
32498
  } catch {
32330
32499
  isDir = false;
@@ -32348,25 +32517,25 @@ function listDir(relativePath) {
32348
32517
  }
32349
32518
 
32350
32519
  // src/files/read-file.ts
32351
- import fs7 from "node:fs";
32520
+ import fs6 from "node:fs";
32352
32521
  import { StringDecoder } from "node:string_decoder";
32353
32522
  function resolveFilePath(relativePath) {
32354
32523
  const resolved = ensureUnderCwd(relativePath, getBridgeWorkspaceDirectory());
32355
32524
  if (!resolved) return { error: "Path is outside working directory" };
32356
32525
  let real;
32357
32526
  try {
32358
- real = fs7.realpathSync(resolved);
32527
+ real = fs6.realpathSync(resolved);
32359
32528
  } catch {
32360
32529
  real = resolved;
32361
32530
  }
32362
- const stat = fs7.statSync(real);
32363
- if (!stat.isFile()) return { error: "Not a file" };
32531
+ const stat2 = fs6.statSync(real);
32532
+ if (!stat2.isFile()) return { error: "Not a file" };
32364
32533
  return real;
32365
32534
  }
32366
32535
  var LINE_CHUNK_SIZE = 64 * 1024;
32367
32536
  function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
32368
- const fileSize = fs7.statSync(filePath).size;
32369
- const fd = fs7.openSync(filePath, "r");
32537
+ const fileSize = fs6.statSync(filePath).size;
32538
+ const fd = fs6.openSync(filePath, "r");
32370
32539
  const bufSize = 64 * 1024;
32371
32540
  const buf = Buffer.alloc(bufSize);
32372
32541
  const decoder = new StringDecoder("utf8");
@@ -32379,7 +32548,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
32379
32548
  let line0Accum = "";
32380
32549
  try {
32381
32550
  let bytesRead;
32382
- while (!done && (bytesRead = fs7.readSync(fd, buf, 0, bufSize, null)) > 0) {
32551
+ while (!done && (bytesRead = fs6.readSync(fd, buf, 0, bufSize, null)) > 0) {
32383
32552
  const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
32384
32553
  partial2 = "";
32385
32554
  let lineStart = 0;
@@ -32514,10 +32683,10 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
32514
32683
  }
32515
32684
  return { content: resultLines.join("\n"), size: fileSize };
32516
32685
  } finally {
32517
- fs7.closeSync(fd);
32686
+ fs6.closeSync(fd);
32518
32687
  }
32519
32688
  }
32520
- function readFile(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
32689
+ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
32521
32690
  try {
32522
32691
  const result = resolveFilePath(relativePath);
32523
32692
  if (typeof result === "object") return result;
@@ -32525,17 +32694,17 @@ function readFile(relativePath, startLine, endLine, lineOffset, lineChunkSize =
32525
32694
  if (hasRange) {
32526
32695
  return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
32527
32696
  }
32528
- const stat = fs7.statSync(result);
32529
- const raw = fs7.readFileSync(result, "utf8");
32697
+ const stat2 = fs6.statSync(result);
32698
+ const raw = fs6.readFileSync(result, "utf8");
32530
32699
  const lines = raw.split(/\r?\n/);
32531
- return { content: raw, totalLines: lines.length, size: stat.size };
32700
+ return { content: raw, totalLines: lines.length, size: stat2.size };
32532
32701
  } catch (err) {
32533
32702
  return { error: err instanceof Error ? err.message : String(err) };
32534
32703
  }
32535
32704
  }
32536
32705
 
32537
32706
  // src/files/file-index.ts
32538
- import fs8 from "node:fs";
32707
+ import fs7 from "node:fs";
32539
32708
  import path14 from "node:path";
32540
32709
  import os2 from "node:os";
32541
32710
  import crypto2 from "node:crypto";
@@ -32582,23 +32751,23 @@ function binarySearch(arr, x) {
32582
32751
  function walkDir(dir, baseDir, out) {
32583
32752
  let names;
32584
32753
  try {
32585
- names = fs8.readdirSync(dir);
32754
+ names = fs7.readdirSync(dir);
32586
32755
  } catch {
32587
32756
  return;
32588
32757
  }
32589
32758
  for (const name of names) {
32590
32759
  if (name.startsWith(".")) continue;
32591
32760
  const full = path14.join(dir, name);
32592
- let stat;
32761
+ let stat2;
32593
32762
  try {
32594
- stat = fs8.statSync(full);
32763
+ stat2 = fs7.statSync(full);
32595
32764
  } catch {
32596
32765
  continue;
32597
32766
  }
32598
32767
  const relative4 = path14.relative(baseDir, full).replace(/\\/g, "/");
32599
- if (stat.isDirectory()) {
32768
+ if (stat2.isDirectory()) {
32600
32769
  walkDir(full, baseDir, out);
32601
- } else if (stat.isFile()) {
32770
+ } else if (stat2.isFile()) {
32602
32771
  out.push(relative4);
32603
32772
  }
32604
32773
  }
@@ -32622,8 +32791,8 @@ function buildFileIndex(cwd) {
32622
32791
  const data = { version: INDEX_VERSION, paths, trigramIndex };
32623
32792
  const indexPath = getIndexPath(resolved);
32624
32793
  try {
32625
- if (!fs8.existsSync(INDEX_DIR)) fs8.mkdirSync(INDEX_DIR, { recursive: true });
32626
- fs8.writeFileSync(indexPath, JSON.stringify(data), "utf8");
32794
+ if (!fs7.existsSync(INDEX_DIR)) fs7.mkdirSync(INDEX_DIR, { recursive: true });
32795
+ fs7.writeFileSync(indexPath, JSON.stringify(data), "utf8");
32627
32796
  } catch (e) {
32628
32797
  console.error("[file-index] Failed to write index:", e);
32629
32798
  }
@@ -32633,7 +32802,7 @@ function loadFileIndex(cwd) {
32633
32802
  const resolved = path14.resolve(cwd);
32634
32803
  const indexPath = getIndexPath(resolved);
32635
32804
  try {
32636
- const raw = fs8.readFileSync(indexPath, "utf8");
32805
+ const raw = fs7.readFileSync(indexPath, "utf8");
32637
32806
  const parsed = JSON.parse(raw);
32638
32807
  if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
32639
32808
  const obj = parsed;
@@ -32737,7 +32906,7 @@ function handleFileBrowserRequest(msg, socket) {
32737
32906
  const endLine = typeof msg.endLine === "number" ? msg.endLine : void 0;
32738
32907
  const lineOffset = typeof msg.lineOffset === "number" ? msg.lineOffset : void 0;
32739
32908
  const lineChunkSize = typeof msg.lineChunkSize === "number" ? msg.lineChunkSize : void 0;
32740
- const result = readFile(reqPath, startLine, endLine, lineOffset, lineChunkSize);
32909
+ const result = readFile2(reqPath, startLine, endLine, lineOffset, lineChunkSize);
32741
32910
  if ("error" in result) {
32742
32911
  sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
32743
32912
  } else {
@@ -32772,7 +32941,7 @@ function handleFileBrowserSearchMessage(msg, { getWs }) {
32772
32941
  }
32773
32942
 
32774
32943
  // src/skills/discover-local-agent-skills.ts
32775
- import fs9 from "node:fs";
32944
+ import fs8 from "node:fs";
32776
32945
  import path15 from "node:path";
32777
32946
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
32778
32947
  function discoverLocalSkills(cwd) {
@@ -32780,22 +32949,22 @@ function discoverLocalSkills(cwd) {
32780
32949
  const seenKeys = /* @__PURE__ */ new Set();
32781
32950
  for (const rel of SKILL_DISCOVERY_ROOTS) {
32782
32951
  const base = path15.join(cwd, rel);
32783
- if (!fs9.existsSync(base) || !fs9.statSync(base).isDirectory()) continue;
32952
+ if (!fs8.existsSync(base) || !fs8.statSync(base).isDirectory()) continue;
32784
32953
  let entries = [];
32785
32954
  try {
32786
- entries = fs9.readdirSync(base);
32955
+ entries = fs8.readdirSync(base);
32787
32956
  } catch {
32788
32957
  continue;
32789
32958
  }
32790
32959
  for (const name of entries) {
32791
32960
  const dir = path15.join(base, name);
32792
32961
  try {
32793
- if (!fs9.statSync(dir).isDirectory()) continue;
32962
+ if (!fs8.statSync(dir).isDirectory()) continue;
32794
32963
  } catch {
32795
32964
  continue;
32796
32965
  }
32797
32966
  const skillMd = path15.join(dir, "SKILL.md");
32798
- if (!fs9.existsSync(skillMd)) continue;
32967
+ if (!fs8.existsSync(skillMd)) continue;
32799
32968
  const key = `${rel}/${name}`;
32800
32969
  if (seenKeys.has(key)) continue;
32801
32970
  seenKeys.add(key);
@@ -32808,10 +32977,10 @@ function discoverSkillLayoutRoots(cwd) {
32808
32977
  const roots = [];
32809
32978
  for (const rel of SKILL_DISCOVERY_ROOTS) {
32810
32979
  const base = path15.join(cwd, rel);
32811
- if (!fs9.existsSync(base) || !fs9.statSync(base).isDirectory()) continue;
32980
+ if (!fs8.existsSync(base) || !fs8.statSync(base).isDirectory()) continue;
32812
32981
  let entries = [];
32813
32982
  try {
32814
- entries = fs9.readdirSync(base);
32983
+ entries = fs8.readdirSync(base);
32815
32984
  } catch {
32816
32985
  continue;
32817
32986
  }
@@ -32819,11 +32988,11 @@ function discoverSkillLayoutRoots(cwd) {
32819
32988
  for (const name of entries) {
32820
32989
  const dir = path15.join(base, name);
32821
32990
  try {
32822
- if (!fs9.statSync(dir).isDirectory()) continue;
32991
+ if (!fs8.statSync(dir).isDirectory()) continue;
32823
32992
  } catch {
32824
32993
  continue;
32825
32994
  }
32826
- if (!fs9.existsSync(path15.join(dir, "SKILL.md"))) continue;
32995
+ if (!fs8.existsSync(path15.join(dir, "SKILL.md"))) continue;
32827
32996
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
32828
32997
  skills2.push({ name, relPath });
32829
32998
  }
@@ -32843,7 +33012,7 @@ function handleSkillLayoutRequest(msg, deps) {
32843
33012
  }
32844
33013
 
32845
33014
  // src/skills/install-remote-skills.ts
32846
- import fs10 from "node:fs";
33015
+ import fs9 from "node:fs";
32847
33016
  import path16 from "node:path";
32848
33017
  function installRemoteSkills(cwd, targetDir, items) {
32849
33018
  const installed = [];
@@ -32859,11 +33028,11 @@ function installRemoteSkills(cwd, targetDir, items) {
32859
33028
  for (const f of item.files) {
32860
33029
  if (typeof f.path !== "string" || !f.text && !f.base64) continue;
32861
33030
  const dest = path16.join(skillDir, f.path);
32862
- fs10.mkdirSync(path16.dirname(dest), { recursive: true });
33031
+ fs9.mkdirSync(path16.dirname(dest), { recursive: true });
32863
33032
  if (f.text !== void 0) {
32864
- fs10.writeFileSync(dest, f.text, "utf8");
33033
+ fs9.writeFileSync(dest, f.text, "utf8");
32865
33034
  } else if (f.base64) {
32866
- fs10.writeFileSync(dest, Buffer.from(f.base64, "base64"));
33035
+ fs9.writeFileSync(dest, Buffer.from(f.base64, "base64"));
32867
33036
  }
32868
33037
  }
32869
33038
  installed.push({
@@ -32957,7 +33126,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
32957
33126
  };
32958
33127
 
32959
33128
  // src/bridge/routing/handlers/revert-turn-snapshot.ts
32960
- import * as fs11 from "node:fs";
33129
+ import * as fs10 from "node:fs";
32961
33130
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
32962
33131
  const id = typeof msg.id === "string" ? msg.id : "";
32963
33132
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -32969,7 +33138,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
32969
33138
  if (!s) return;
32970
33139
  const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ?? getBridgeWorkspaceDirectory();
32971
33140
  const file2 = snapshotFilePath(agentBase, turnId);
32972
- if (!fs11.existsSync(file2)) {
33141
+ if (!fs10.existsSync(file2)) {
32973
33142
  sendWsMessage(s, {
32974
33143
  type: "revert_turn_snapshot_result",
32975
33144
  id,
@@ -33070,25 +33239,12 @@ function dispatchBridgeMessage(msg, deps) {
33070
33239
  }
33071
33240
 
33072
33241
  // src/bridge/routing/handle-bridge-message.ts
33073
- var DEFERRED_INBOUND_TYPES = /* @__PURE__ */ new Set([
33074
- "server_control",
33075
- "prompt",
33076
- "install_skills",
33077
- "refresh_local_skills",
33078
- "dev_servers_config"
33079
- ]);
33080
33242
  function handleBridgeMessage(data, deps) {
33081
33243
  const msg = data;
33082
- const socket = deps.getWs();
33083
- if (!socket) return;
33084
- const type = msg.type;
33085
- if (typeof type === "string" && DEFERRED_INBOUND_TYPES.has(type)) {
33086
- setImmediate(() => {
33087
- dispatchBridgeMessage(msg, deps);
33088
- });
33089
- return;
33090
- }
33091
- dispatchBridgeMessage(msg, deps);
33244
+ if (!deps.getWs()) return;
33245
+ setImmediate(() => {
33246
+ dispatchBridgeMessage(msg, deps);
33247
+ });
33092
33248
  }
33093
33249
 
33094
33250
  // src/worktrees/session-worktree-manager.ts
@@ -33096,7 +33252,7 @@ import * as path20 from "node:path";
33096
33252
  import os4 from "node:os";
33097
33253
 
33098
33254
  // src/worktrees/prepare-new-session-worktrees.ts
33099
- import * as fs13 from "node:fs";
33255
+ import * as fs12 from "node:fs";
33100
33256
  import * as path18 from "node:path";
33101
33257
 
33102
33258
  // src/git/worktree-add.ts
@@ -33106,7 +33262,7 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
33106
33262
  }
33107
33263
 
33108
33264
  // src/worktrees/worktree-layout-file.ts
33109
- import * as fs12 from "node:fs";
33265
+ import * as fs11 from "node:fs";
33110
33266
  import * as path17 from "node:path";
33111
33267
  import os3 from "node:os";
33112
33268
  var LAYOUT_FILENAME = "worktree-launcher-layout.json";
@@ -33123,8 +33279,8 @@ function normalizeLoadedLayout(raw) {
33123
33279
  function loadWorktreeLayout() {
33124
33280
  try {
33125
33281
  const p = defaultWorktreeLayoutPath();
33126
- if (!fs12.existsSync(p)) return { launcherCwds: [] };
33127
- const raw = JSON.parse(fs12.readFileSync(p, "utf8"));
33282
+ if (!fs11.existsSync(p)) return { launcherCwds: [] };
33283
+ const raw = JSON.parse(fs11.readFileSync(p, "utf8"));
33128
33284
  return normalizeLoadedLayout(raw);
33129
33285
  } catch {
33130
33286
  return { launcherCwds: [] };
@@ -33133,8 +33289,8 @@ function loadWorktreeLayout() {
33133
33289
  function saveWorktreeLayout(layout) {
33134
33290
  try {
33135
33291
  const dir = path17.dirname(defaultWorktreeLayoutPath());
33136
- fs12.mkdirSync(dir, { recursive: true });
33137
- fs12.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
33292
+ fs11.mkdirSync(dir, { recursive: true });
33293
+ fs11.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
33138
33294
  } catch {
33139
33295
  }
33140
33296
  }
@@ -33171,13 +33327,13 @@ async function prepareNewSessionWorktrees(options) {
33171
33327
  }
33172
33328
  const branch = `session-${sessionId}`;
33173
33329
  const worktreePaths = [];
33174
- fs13.mkdirSync(agentMirrorRoot, { recursive: true });
33330
+ fs12.mkdirSync(agentMirrorRoot, { recursive: true });
33175
33331
  for (const repo of repos) {
33176
33332
  let rel = path18.relative(launcherResolved, repo.absolutePath);
33177
33333
  if (rel.startsWith("..") || path18.isAbsolute(rel)) continue;
33178
33334
  const relNorm = rel === "" ? "." : rel;
33179
33335
  const wtPath = path18.join(agentMirrorRoot, relNorm, sessionId);
33180
- fs13.mkdirSync(path18.dirname(wtPath), { recursive: true });
33336
+ fs12.mkdirSync(path18.dirname(wtPath), { recursive: true });
33181
33337
  try {
33182
33338
  await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
33183
33339
  log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}).`);
@@ -33214,18 +33370,18 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
33214
33370
  }
33215
33371
 
33216
33372
  // src/worktrees/remove-session-worktrees.ts
33217
- import * as fs16 from "node:fs";
33373
+ import * as fs15 from "node:fs";
33218
33374
 
33219
33375
  // src/git/worktree-remove.ts
33220
- import * as fs15 from "node:fs";
33376
+ import * as fs14 from "node:fs";
33221
33377
 
33222
33378
  // src/git/resolve-main-repo-from-git-file.ts
33223
- import * as fs14 from "node:fs";
33379
+ import * as fs13 from "node:fs";
33224
33380
  import * as path19 from "node:path";
33225
33381
  function resolveMainRepoFromWorktreeGitFile(wt) {
33226
33382
  const gitDirFile = path19.join(wt, ".git");
33227
- if (!fs14.existsSync(gitDirFile) || !fs14.statSync(gitDirFile).isFile()) return "";
33228
- const first2 = fs14.readFileSync(gitDirFile, "utf8").trim();
33383
+ if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
33384
+ const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
33229
33385
  const m = first2.match(/^gitdir:\s*(.+)$/im);
33230
33386
  if (!m) return "";
33231
33387
  const gitWorktreePath = path19.resolve(wt, m[1].trim());
@@ -33239,7 +33395,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
33239
33395
  if (mainRepo) {
33240
33396
  await simpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
33241
33397
  } else {
33242
- fs15.rmSync(worktreePath, { recursive: true, force: true });
33398
+ fs14.rmSync(worktreePath, { recursive: true, force: true });
33243
33399
  }
33244
33400
  }
33245
33401
 
@@ -33252,7 +33408,7 @@ async function removeSessionWorktrees(paths, log2) {
33252
33408
  } catch (e) {
33253
33409
  log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
33254
33410
  try {
33255
- fs16.rmSync(wt, { recursive: true, force: true });
33411
+ fs15.rmSync(wt, { recursive: true, force: true });
33256
33412
  } catch {
33257
33413
  }
33258
33414
  }
@@ -33524,7 +33680,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
33524
33680
  }
33525
33681
 
33526
33682
  // src/dev-servers/process/wire-dev-server-child-process.ts
33527
- import fs17 from "node:fs";
33683
+ import fs16 from "node:fs";
33528
33684
 
33529
33685
  // src/dev-servers/manager/forward-pipe.ts
33530
33686
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -33560,7 +33716,7 @@ function wireDevServerChildProcess(d) {
33560
33716
  d.setPollInterval(void 0);
33561
33717
  return;
33562
33718
  }
33563
- fs17.readFile(d.mergedLogPath, (err, buf) => {
33719
+ fs16.readFile(d.mergedLogPath, (err, buf) => {
33564
33720
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
33565
33721
  if (buf.length <= d.mergedReadPos.value) return;
33566
33722
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -33598,7 +33754,7 @@ ${errTail}` : ""}`);
33598
33754
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
33599
33755
  };
33600
33756
  if (mergedPath) {
33601
- fs17.readFile(mergedPath, (err, buf) => {
33757
+ fs16.readFile(mergedPath, (err, buf) => {
33602
33758
  if (!err && buf.length > d.mergedReadPos.value) {
33603
33759
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
33604
33760
  if (chunk.length > 0) {
@@ -33700,13 +33856,13 @@ function parseDevServerDefs(servers) {
33700
33856
  }
33701
33857
 
33702
33858
  // src/dev-servers/manager/shell-spawn/utils.ts
33703
- import fs18 from "node:fs";
33859
+ import fs17 from "node:fs";
33704
33860
  function isSpawnEbadf(e) {
33705
33861
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
33706
33862
  }
33707
33863
  function rmDirQuiet(dir) {
33708
33864
  try {
33709
- fs18.rmSync(dir, { recursive: true, force: true });
33865
+ fs17.rmSync(dir, { recursive: true, force: true });
33710
33866
  } catch {
33711
33867
  }
33712
33868
  }
@@ -33714,7 +33870,7 @@ var cachedDevNullReadFd;
33714
33870
  function devNullReadFd() {
33715
33871
  if (cachedDevNullReadFd === void 0) {
33716
33872
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
33717
- cachedDevNullReadFd = fs18.openSync(devPath, "r");
33873
+ cachedDevNullReadFd = fs17.openSync(devPath, "r");
33718
33874
  }
33719
33875
  return cachedDevNullReadFd;
33720
33876
  }
@@ -33788,15 +33944,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
33788
33944
 
33789
33945
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
33790
33946
  import { spawn as spawn7 } from "node:child_process";
33791
- import fs19 from "node:fs";
33947
+ import fs18 from "node:fs";
33792
33948
  import { tmpdir } from "node:os";
33793
33949
  import path22 from "node:path";
33794
33950
  function trySpawnMergedLogFile(command, env, cwd, signal) {
33795
- const tmpRoot = fs19.mkdtempSync(path22.join(tmpdir(), "ba-devsrv-log-"));
33951
+ const tmpRoot = fs18.mkdtempSync(path22.join(tmpdir(), "ba-devsrv-log-"));
33796
33952
  const logPath = path22.join(tmpRoot, "combined.log");
33797
33953
  let logFd;
33798
33954
  try {
33799
- logFd = fs19.openSync(logPath, "a");
33955
+ logFd = fs18.openSync(logPath, "a");
33800
33956
  } catch {
33801
33957
  rmDirQuiet(tmpRoot);
33802
33958
  return null;
@@ -33815,7 +33971,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33815
33971
  } else {
33816
33972
  proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
33817
33973
  }
33818
- fs19.closeSync(logFd);
33974
+ fs18.closeSync(logFd);
33819
33975
  return {
33820
33976
  proc,
33821
33977
  pipedStdoutStderr: true,
@@ -33824,7 +33980,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33824
33980
  };
33825
33981
  } catch (e) {
33826
33982
  try {
33827
- fs19.closeSync(logFd);
33983
+ fs18.closeSync(logFd);
33828
33984
  } catch {
33829
33985
  }
33830
33986
  rmDirQuiet(tmpRoot);
@@ -33835,22 +33991,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33835
33991
 
33836
33992
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
33837
33993
  import { spawn as spawn8 } from "node:child_process";
33838
- import fs20 from "node:fs";
33994
+ import fs19 from "node:fs";
33839
33995
  import { tmpdir as tmpdir2 } from "node:os";
33840
33996
  import path23 from "node:path";
33841
33997
  function shSingleQuote(s) {
33842
33998
  return `'${s.replace(/'/g, `'\\''`)}'`;
33843
33999
  }
33844
34000
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
33845
- const tmpRoot = fs20.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
34001
+ const tmpRoot = fs19.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
33846
34002
  const logPath = path23.join(tmpRoot, "combined.log");
33847
34003
  const innerPath = path23.join(tmpRoot, "_cmd.sh");
33848
34004
  const runnerPath = path23.join(tmpRoot, "_run.sh");
33849
34005
  try {
33850
- fs20.writeFileSync(innerPath, `#!/bin/sh
34006
+ fs19.writeFileSync(innerPath, `#!/bin/sh
33851
34007
  ${command}
33852
34008
  `);
33853
- fs20.writeFileSync(
34009
+ fs19.writeFileSync(
33854
34010
  runnerPath,
33855
34011
  `#!/bin/sh
33856
34012
  cd ${shSingleQuote(cwd)}
@@ -33876,13 +34032,13 @@ cd ${shSingleQuote(cwd)}
33876
34032
  }
33877
34033
  }
33878
34034
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
33879
- const tmpRoot = fs20.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
34035
+ const tmpRoot = fs19.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
33880
34036
  const logPath = path23.join(tmpRoot, "combined.log");
33881
34037
  const runnerPath = path23.join(tmpRoot, "_run.bat");
33882
34038
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
33883
34039
  const com = process.env.ComSpec || "cmd.exe";
33884
34040
  try {
33885
- fs20.writeFileSync(
34041
+ fs19.writeFileSync(
33886
34042
  runnerPath,
33887
34043
  `@ECHO OFF\r
33888
34044
  CD /D ${q(cwd)}\r
@@ -34236,7 +34392,9 @@ var DevServerManager = class {
34236
34392
  async shutdownAllGraceful() {
34237
34393
  const pairs = [...this.processes.entries()];
34238
34394
  if (pairs.length === 0) return;
34239
- this.log(`[dev-server] Stopping ${pairs.length} dev server process(es) (bridge shutting down)\u2026`);
34395
+ this.log(
34396
+ `[dev-server] Stopping ${pairs.length} local dev server process${pairs.length === 1 ? "" : "es"}\u2026`
34397
+ );
34240
34398
  await Promise.all(pairs.map(([serverId, proc]) => this.gracefulTerminateOrUnknown(serverId, proc)));
34241
34399
  }
34242
34400
  async gracefulTerminateOrUnknown(serverId, proc) {
@@ -34510,9 +34668,10 @@ var FIREHOSE_CLIENT_PING_MS = 25e3;
34510
34668
  function connectFirehose(options) {
34511
34669
  const { firehoseServerUrl, workspaceId, bridgeName, proxyPorts, log: log2, devServerManager, onOpen, onClose } = options;
34512
34670
  const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
34513
- const wsOptions = { perMessageDeflate: false };
34671
+ applyCliOutboundNetworkPreferences();
34672
+ const wsOptions = { perMessageDeflate: false, family: 4 };
34514
34673
  if (wsUrl.startsWith("wss://")) {
34515
- wsOptions.agent = new https2.Agent({ rejectUnauthorized: false });
34674
+ wsOptions.agent = new https2.Agent({ rejectUnauthorized: false, family: 4 });
34516
34675
  }
34517
34676
  const ws = new wrapper_default(wsUrl, wsOptions);
34518
34677
  let clientPingTimer = null;
@@ -34548,16 +34707,14 @@ function connectFirehose(options) {
34548
34707
  sendWsMessage(ws, { type: "identify", workspaceId, bridgeName, proxyPorts });
34549
34708
  });
34550
34709
  ws.on("message", (raw) => {
34551
- setImmediate(() => {
34552
- if (Buffer.isBuffer(raw) && tryConsumeBinaryProxyBody(raw, deps)) {
34553
- return;
34554
- }
34555
- try {
34556
- const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
34557
- dispatchFirehoseJsonMessage(JSON.parse(text), deps);
34558
- } catch {
34559
- }
34560
- });
34710
+ if (Buffer.isBuffer(raw) && tryConsumeBinaryProxyBody(raw, deps)) {
34711
+ return;
34712
+ }
34713
+ try {
34714
+ const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
34715
+ dispatchFirehoseJsonMessage(JSON.parse(text), deps);
34716
+ } catch {
34717
+ }
34561
34718
  });
34562
34719
  ws.on("close", (code, reason) => {
34563
34720
  clearClientPing();
@@ -34603,6 +34760,9 @@ function createOnBridgeIdentified(opts) {
34603
34760
  function attachFirehose(params) {
34604
34761
  state.lastFirehoseParams = params;
34605
34762
  clearFirehoseReconnectTimer();
34763
+ if (state.firehoseReconnectAttempt === 0) {
34764
+ logFn("Connecting to preview tunnel (local HTTP proxy and dev logs)\u2026");
34765
+ }
34606
34766
  state.firehoseGeneration += 1;
34607
34767
  const myGen = state.firehoseGeneration;
34608
34768
  if (state.firehoseHandle) {
@@ -34621,8 +34781,8 @@ function createOnBridgeIdentified(opts) {
34621
34781
  clearFirehoseReconnectQuietOnOpen({ firehoseQuiet: state.firehoseQuiet }, logFn);
34622
34782
  const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
34623
34783
  state.firehoseReconnectAttempt = 0;
34624
- if (logOpenAsFirehoseReconnect) {
34625
- logFn("[Proxy and log service] reconnected.");
34784
+ if (!logOpenAsFirehoseReconnect) {
34785
+ logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
34626
34786
  }
34627
34787
  },
34628
34788
  onClose: (code, reason) => {
@@ -34711,6 +34871,7 @@ var CHECKS = {
34711
34871
  return false;
34712
34872
  }
34713
34873
  },
34874
+ /** Bridge spawns `@agentclientprotocol/claude-agent-acp` via npx; detection is “Claude toolchain likely present”. */
34714
34875
  "claude-code": async () => {
34715
34876
  try {
34716
34877
  await execFileAsync4("which", ["claude"], { timeout: 4e3 });
@@ -34820,8 +34981,8 @@ async function createBridgeConnection(options) {
34820
34981
  clearMainBridgeReconnectQuietOnOpen(state, logFn);
34821
34982
  state.reconnectAttempt = 0;
34822
34983
  state.logBridgeOpenAsReconnect = false;
34823
- if (logOpenAsPostRefreshReconnect) {
34824
- logFn("[Bridge service] reconnected.");
34984
+ if (!logOpenAsPostRefreshReconnect) {
34985
+ logFn("Connected to bridge service.");
34825
34986
  }
34826
34987
  const socket = getWs();
34827
34988
  if (socket) {
@@ -34860,6 +35021,9 @@ async function createBridgeConnection(options) {
34860
35021
  clearTimeout(state.reconnectTimeout);
34861
35022
  state.reconnectTimeout = null;
34862
35023
  }
35024
+ if (state.reconnectAttempt === 0) {
35025
+ logFn("Connecting to bridge service\u2026");
35026
+ }
34863
35027
  const prev = state.currentWs;
34864
35028
  if (prev) {
34865
35029
  prev.removeAllListeners();
@@ -34932,15 +35096,17 @@ async function runBridge(options) {
34932
35096
  onAuth: (_auth) => {
34933
35097
  }
34934
35098
  });
34935
- const onSignal2 = (signal) => {
34936
- logImmediate(`Received ${signal}; shutting down\u2026`);
35099
+ const onSignal2 = (kind) => {
35100
+ logImmediate(
35101
+ kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
35102
+ );
34937
35103
  setImmediate(() => {
34938
35104
  handle2.close();
34939
35105
  process.exit(0);
34940
35106
  });
34941
35107
  };
34942
- const onSigInt2 = () => onSignal2("SIGINT");
34943
- const onSigTerm2 = () => onSignal2("SIGTERM");
35108
+ const onSigInt2 = () => onSignal2("interrupt");
35109
+ const onSigTerm2 = () => onSignal2("stop");
34944
35110
  process.on("SIGINT", onSigInt2);
34945
35111
  process.on("SIGTERM", onSigTerm2);
34946
35112
  const auth = await handle2.authPromise;
@@ -34989,16 +35155,18 @@ async function runBridge(options) {
34989
35155
  });
34990
35156
  }
34991
35157
  });
34992
- const onSignal = (signal) => {
34993
- logImmediate(`Received ${signal}; shutting down\u2026`);
35158
+ const onSignal = (kind) => {
35159
+ logImmediate(
35160
+ kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
35161
+ );
34994
35162
  setImmediate(() => {
34995
35163
  void handle.close().then(() => {
34996
35164
  process.exit(0);
34997
35165
  });
34998
35166
  });
34999
35167
  };
35000
- const onSigInt = () => onSignal("SIGINT");
35001
- const onSigTerm = () => onSignal("SIGTERM");
35168
+ const onSigInt = () => onSignal("interrupt");
35169
+ const onSigTerm = () => onSignal("stop");
35002
35170
  process.on("SIGINT", onSigInt);
35003
35171
  process.on("SIGTERM", onSigTerm);
35004
35172
  }
@@ -35029,7 +35197,7 @@ async function main() {
35029
35197
  if (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim()) {
35030
35198
  const resolvedCwd = path24.resolve(process.cwd(), opts.cwd.trim());
35031
35199
  try {
35032
- const st = fs21.statSync(resolvedCwd);
35200
+ const st = fs20.statSync(resolvedCwd);
35033
35201
  if (!st.isDirectory()) {
35034
35202
  console.error(`--cwd is not a directory: ${resolvedCwd}`);
35035
35203
  process.exit(1);