@buildautomaton/cli 0.1.5 → 0.1.7

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,295 @@ 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.");
30319
+ }
30320
+
30321
+ // ../types/dist/index.js
30322
+ init_zod();
30323
+ init_zod();
30324
+ init_zod();
30325
+ init_zod();
30326
+ init_zod();
30327
+ init_zod();
30328
+ init_zod();
30329
+ init_zod();
30330
+ init_zod();
30331
+ init_zod();
30332
+ init_zod();
30333
+ init_zod();
30334
+ var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
30335
+ var WorkItemProgressSchema = external_exports.object({
30336
+ remainingCriteria: external_exports.array(external_exports.string()).default([]),
30337
+ openQuestions: external_exports.array(external_exports.string()).default([]),
30338
+ assignedTo: external_exports.enum(["agent", "human-product", "human-expert"]).optional()
30339
+ });
30340
+ var ChangeSchema = external_exports.object({
30341
+ id: external_exports.string(),
30342
+ description: external_exports.string(),
30343
+ buildingBlockId: external_exports.string(),
30344
+ buildingBlockType: external_exports.enum(["function", "workflow", "connector", "ui-component", "app-fragment", "application", "project"]),
30345
+ action: external_exports.enum(["create", "update", "split", "combine"])
30346
+ });
30347
+ var CompletionCriterionSchema = external_exports.object({
30348
+ id: external_exports.string(),
30349
+ description: external_exports.string(),
30350
+ type: external_exports.enum(["write-code", "write-tests", "verify-tests", "other"]),
30351
+ verified: external_exports.boolean().default(false)
30352
+ });
30353
+ var WorkItemPrioritySchema = external_exports.enum(["low", "medium", "high", "critical"]);
30354
+ var IterationPhaseSchema = external_exports.enum(["analysis", "implementation", "verify", "reprioritize", "completed"]);
30355
+ var WorkItemDependencySchema = external_exports.object({
30356
+ type: external_exports.enum(["work-item"]),
30357
+ id: external_exports.string()
30358
+ });
30359
+ var WorkItemSchema = external_exports.object({
30360
+ id: external_exports.string(),
30361
+ sessionId: external_exports.string().optional(),
30362
+ summary: external_exports.string().optional(),
30363
+ description: external_exports.string(),
30364
+ status: WorkItemStatusSchema,
30365
+ buildingBlockId: external_exports.string().optional(),
30366
+ buildingBlockType: external_exports.enum(["function", "workflow", "connector", "ui-component", "app-fragment", "application", "project"]),
30367
+ changes: external_exports.array(ChangeSchema).default([]),
30368
+ completionCriteria: external_exports.array(CompletionCriterionSchema).default([]),
30369
+ priority: WorkItemPrioritySchema.default("medium"),
30370
+ dependencies: external_exports.array(WorkItemDependencySchema).default([]),
30371
+ assignedToUserId: external_exports.string().optional()
30372
+ });
30373
+ var UserWorkspaceProfileSchema = external_exports.object({
30374
+ id: external_exports.string(),
30375
+ workspaceId: external_exports.string(),
30376
+ userId: external_exports.string(),
30377
+ roleDescription: external_exports.string().optional(),
30378
+ expertiseAreas: external_exports.array(external_exports.string()),
30379
+ preferences: external_exports.record(external_exports.unknown()).optional(),
30380
+ learnings: external_exports.array(external_exports.string())
30381
+ });
30382
+ var WorkspaceOwnerInfoSchema = external_exports.object({
30383
+ ownerId: external_exports.string(),
30384
+ ownerName: external_exports.string().optional(),
30385
+ ownerEmail: external_exports.string().optional(),
30386
+ ownerProfilePictureUrl: external_exports.string().optional()
30387
+ });
30388
+ var WorkspaceRuntimeEntrySchema = external_exports.object({
30389
+ workspaceId: external_exports.string(),
30390
+ path: external_exports.string(),
30391
+ name: external_exports.string().optional(),
30392
+ owner: WorkspaceOwnerInfoSchema.optional(),
30393
+ isOwner: external_exports.boolean().optional()
30394
+ });
30395
+ var ProjectContextSchema = external_exports.object({
30396
+ projectId: external_exports.string(),
30397
+ context: external_exports.record(external_exports.unknown()).default({}),
30398
+ updatedAt: external_exports.string()
30399
+ });
30400
+ var WebSocketMessageTypeSchema = external_exports.enum([
30401
+ "plan-update",
30402
+ "work-item-update",
30403
+ "work-item-added",
30404
+ "work-item-removed",
30405
+ "project-processing-start",
30406
+ "project-processing-update",
30407
+ "project-processing-complete",
30408
+ "project-processing-error",
30409
+ "file-tool-request",
30410
+ "file-tool-response",
30411
+ "file-generated"
30412
+ ]);
30413
+ var WebSocketMessageSchema = external_exports.object({
30414
+ type: WebSocketMessageTypeSchema,
30415
+ contextId: external_exports.string().optional(),
30416
+ data: external_exports.any().optional(),
30417
+ error: external_exports.string().optional()
30418
+ });
30419
+ var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
30420
+ var CheckpointSummarySchema = external_exports.object({
30421
+ id: external_exports.string(),
30422
+ kind: CheckpointKindSchema,
30423
+ /** ISO date for daily (YYYY-MM-DD), ISO week for weekly, null for overall */
30424
+ periodKey: external_exports.string().nullable(),
30425
+ summary: external_exports.string(),
30426
+ createdAt: external_exports.string(),
30427
+ updatedAt: external_exports.string()
30428
+ });
30429
+ var ThreadMetaSchema = external_exports.object({
30430
+ threadId: external_exports.string(),
30431
+ workspaceId: external_exports.string(),
30432
+ /** External source (e.g. slack, discord); null if internal-only */
30433
+ externalSource: external_exports.string().nullable(),
30434
+ /** Id in the external system (e.g. channel_id + thread_ts) */
30435
+ externalId: external_exports.string().nullable(),
30436
+ title: external_exports.string().optional(),
30437
+ createdAt: external_exports.string(),
30438
+ updatedAt: external_exports.string()
30439
+ });
30440
+ var ThreadMessageSchema = external_exports.object({
30441
+ messageId: external_exports.string(),
30442
+ threadId: external_exports.string(),
30443
+ /** Role: user, assistant, system */
30444
+ role: external_exports.enum(["user", "assistant", "system"]),
30445
+ content: external_exports.string(),
30446
+ /** Optional reference to a ContentItem (e.g. doc, Notion page) */
30447
+ contentItemId: external_exports.string().nullable(),
30448
+ /** External message id if synced from external chat */
30449
+ externalId: external_exports.string().nullable(),
30450
+ createdAt: external_exports.string(),
30451
+ updatedAt: external_exports.string()
30452
+ });
30453
+ var ThreadCheckpointSummarySchema = CheckpointSummarySchema.extend({
30454
+ threadId: external_exports.string()
30455
+ });
30456
+ var ContentSourceSchema = external_exports.enum(["notion", "doc", "slack_thread", "other"]);
30457
+ var ContentItemMetaSchema = external_exports.object({
30458
+ contentId: external_exports.string(),
30459
+ workspaceId: external_exports.string(),
30460
+ source: ContentSourceSchema,
30461
+ /** Id in the external system (e.g. Notion page id, doc url) */
30462
+ externalId: external_exports.string(),
30463
+ /** If source is slack_thread, points to Thread DO id */
30464
+ threadId: external_exports.string().nullable(),
30465
+ title: external_exports.string().optional(),
30466
+ createdAt: external_exports.string(),
30467
+ updatedAt: external_exports.string()
30468
+ });
30469
+ var ContentStorageRefSchema = external_exports.object({
30470
+ storageKey: external_exports.string(),
30471
+ /** Optional: mime type or format hint */
30472
+ contentType: external_exports.string().optional()
30473
+ });
30474
+ var ContentCheckpointSummarySchema = CheckpointSummarySchema.extend({
30475
+ contentId: external_exports.string()
30476
+ });
30477
+ var StoryMetaSchema = external_exports.object({
30478
+ storyId: external_exports.string(),
30479
+ workspaceId: external_exports.string(),
30480
+ title: external_exports.string(),
30481
+ /** feature | bug | epic */
30482
+ kind: external_exports.enum(["feature", "bug", "epic"]).default("feature"),
30483
+ createdAt: external_exports.string(),
30484
+ updatedAt: external_exports.string()
30485
+ });
30486
+ var StoryContentItemRefSchema = external_exports.object({
30487
+ id: external_exports.string(),
30488
+ storyId: external_exports.string(),
30489
+ contentItemId: external_exports.string(),
30490
+ /** Snapshot summary when added to story (or updated) */
30491
+ summary: external_exports.string(),
30492
+ orderIndex: external_exports.number().default(0),
30493
+ createdAt: external_exports.string(),
30494
+ updatedAt: external_exports.string()
30495
+ });
30496
+ var StoryCheckpointSummarySchema = CheckpointSummarySchema.extend({
30497
+ storyId: external_exports.string()
30498
+ });
30499
+ var SessionMetaSchema = external_exports.object({
30500
+ sessionId: external_exports.string(),
30501
+ workspaceId: external_exports.string(),
30502
+ title: external_exports.string().optional(),
30503
+ createdAt: external_exports.string(),
30504
+ updatedAt: external_exports.string()
30505
+ });
30506
+ var SessionPromptSchema = external_exports.object({
30507
+ id: external_exports.string(),
30508
+ sessionId: external_exports.string(),
30509
+ /** text | resource */
30510
+ type: external_exports.enum(["text", "resource"]).default("text"),
30511
+ text: external_exports.string().optional(),
30512
+ resourceUri: external_exports.string().optional(),
30513
+ createdAt: external_exports.string()
30514
+ });
30515
+ var SessionResponseSchema = external_exports.object({
30516
+ id: external_exports.string(),
30517
+ sessionId: external_exports.string(),
30518
+ promptId: external_exports.string(),
30519
+ /** message | completion */
30520
+ kind: external_exports.enum(["message", "completion"]),
30521
+ content: external_exports.string().optional(),
30522
+ /** For completion: stopReason etc. */
30523
+ stopReason: external_exports.string().optional(),
30524
+ createdAt: external_exports.string()
30525
+ });
30526
+ var SessionToolCallSchema = external_exports.object({
30527
+ id: external_exports.string(),
30528
+ sessionId: external_exports.string(),
30529
+ promptId: external_exports.string(),
30530
+ name: external_exports.string(),
30531
+ params: external_exports.record(external_exports.unknown()).optional(),
30532
+ result: external_exports.record(external_exports.unknown()).optional(),
30533
+ createdAt: external_exports.string()
30534
+ });
30535
+ var SessionThreadRefSchema = external_exports.object({
30536
+ sessionId: external_exports.string(),
30537
+ threadId: external_exports.string(),
30538
+ addedAt: external_exports.string()
30539
+ });
30540
+ var ArtifactMetaSchema = external_exports.object({
30541
+ artifactId: external_exports.string(),
30542
+ workspaceId: external_exports.string(),
30543
+ /** Slug for permalink: /workspaces/:wid/artifacts/:slug */
30544
+ permalinkSlug: external_exports.string(),
30545
+ title: external_exports.string(),
30546
+ /** e.g. summary_report, build_log */
30547
+ type: external_exports.string().default("report"),
30548
+ /** Optional session that produced this artifact */
30549
+ sessionId: external_exports.string().nullable(),
30550
+ createdAt: external_exports.string(),
30551
+ updatedAt: external_exports.string()
30552
+ });
30553
+ var TemplateMetaSchema = external_exports.object({
30554
+ templateId: external_exports.string(),
30555
+ workspaceId: external_exports.string(),
30556
+ name: external_exports.string(),
30557
+ /** e.g. summary_report, build_log */
30558
+ artifactType: external_exports.string().optional(),
30559
+ createdAt: external_exports.string(),
30560
+ updatedAt: external_exports.string()
30561
+ });
30562
+ var GitRepoMetaSchema = external_exports.object({
30563
+ /** Stable id for the repo (e.g. hash of normalized canonical URL). Used for DO idFromName. */
30564
+ repoId: external_exports.string(),
30565
+ /** Canonical external URL (e.g. https://github.com/org/repo). Normalize before storing. */
30566
+ canonicalUrl: external_exports.string().url(),
30567
+ /** Optional workspace this repo was first linked in. */
30568
+ workspaceId: external_exports.string().nullable(),
30569
+ displayName: external_exports.string().optional(),
30570
+ createdAt: external_exports.string(),
30571
+ updatedAt: external_exports.string()
30572
+ });
30573
+ var LOCAL_AGENT_AUTH_ERROR_HINTS = {
30574
+ "kiro-acp": [/not logged in/i, /kiro-cli\s+login/i, /log in with kiro-cli/i],
30575
+ "cursor-cli": [/cursor_login/i, /authenticate.*cursor/i, /not logged in.*cursor/i, /run:\s*agent\s+login/i],
30576
+ "codex-acp": [
30577
+ /authentication failed/i,
30578
+ /not authenticated/i,
30579
+ /invalid.*api key/i,
30580
+ /sign in.*openai/i,
30581
+ /login.*openai/i,
30582
+ /unauthorized/i
30583
+ ],
30584
+ "claude-code": [
30585
+ /ANTHROPIC_API_KEY/i,
30586
+ /not authenticated/i,
30587
+ /authentication failed/i,
30588
+ /claude\s+login/i,
30589
+ /please run.*claude.*login/i
30590
+ ]
30591
+ };
30592
+ function localAgentErrorSuggestsAuth(agentType, errorText) {
30593
+ if (agentType == null || agentType === "" || errorText == null || !String(errorText).trim()) return false;
30594
+ const hints = LOCAL_AGENT_AUTH_ERROR_HINTS[agentType];
30595
+ if (!hints?.length) return false;
30596
+ return hints.some((re) => re.test(String(errorText)));
30299
30597
  }
30300
30598
 
30301
30599
  // src/git/session-git-queue.ts
30302
30600
  import { execFile as execFile2 } from "node:child_process";
30601
+ import { readFile, stat } from "node:fs/promises";
30303
30602
  import { promisify as promisify2 } from "node:util";
30304
- import * as fs4 from "node:fs";
30305
30603
  import * as path5 from "node:path";
30306
30604
 
30307
30605
  // src/git/pre-turn-snapshot.ts
@@ -30416,11 +30714,11 @@ function snapshotFilePath(agentCwd, runId) {
30416
30714
  // src/git/session-git-queue.ts
30417
30715
  var execFileAsync2 = promisify2(execFile2);
30418
30716
  var MAX_FULL_FILE_TEXT_BYTES = 512 * 1024;
30419
- function readWorkspaceFileAsUtf8(absPath) {
30717
+ async function readWorkspaceFileAsUtf8(absPath) {
30420
30718
  try {
30421
- const st = fs4.statSync(absPath);
30719
+ const st = await stat(absPath);
30422
30720
  if (!st.isFile() || st.size > MAX_FULL_FILE_TEXT_BYTES) return void 0;
30423
- return fs4.readFileSync(absPath, "utf8");
30721
+ return await readFile(absPath, "utf8");
30424
30722
  } catch {
30425
30723
  return void 0;
30426
30724
  }
@@ -30430,7 +30728,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
30430
30728
  const filePath = snapshotFilePath(agentCwd, runId);
30431
30729
  let data;
30432
30730
  try {
30433
- const raw = fs4.readFileSync(filePath, "utf8");
30731
+ const raw = await readFile(filePath, "utf8");
30434
30732
  data = JSON.parse(raw);
30435
30733
  } catch (e) {
30436
30734
  log2(
@@ -30474,7 +30772,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
30474
30772
  if (!patchContent.trim()) continue;
30475
30773
  const displayPath = multiRepo ? `${slug}/${rel}` : rel;
30476
30774
  const absFile = path5.join(repo.path, rel);
30477
- const newText = readWorkspaceFileAsUtf8(absFile);
30775
+ const newText = await readWorkspaceFileAsUtf8(absFile);
30478
30776
  sendSessionUpdate({
30479
30777
  type: "session_file_change",
30480
30778
  sessionId,
@@ -30500,11 +30798,20 @@ async function sendPromptToAgent(options) {
30500
30798
  promptId,
30501
30799
  sessionId,
30502
30800
  runId,
30801
+ agentType,
30503
30802
  agentCwd,
30504
30803
  sendResult,
30505
30804
  sendSessionUpdate,
30506
30805
  log: log2
30507
30806
  } = options;
30807
+ function augmentAuthFields(errorText) {
30808
+ const err = errorText ?? "";
30809
+ const at = agentType ?? null;
30810
+ const evaluated = Boolean(at && err.trim());
30811
+ const suggestsAuth = evaluated && at ? localAgentErrorSuggestsAuth(at, err) : false;
30812
+ if (!suggestsAuth || !agentType) return {};
30813
+ return { agentAuthRequired: true, agentType };
30814
+ }
30508
30815
  try {
30509
30816
  const result = await handle.sendPrompt(promptText, {});
30510
30817
  if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
@@ -30516,12 +30823,14 @@ async function sendPromptToAgent(options) {
30516
30823
  log: log2
30517
30824
  });
30518
30825
  }
30826
+ const errStr = typeof result.error === "string" ? result.error : void 0;
30519
30827
  sendResult({
30520
30828
  type: "prompt_result",
30521
30829
  id: promptId,
30522
30830
  ...sessionId ? { sessionId } : {},
30523
30831
  ...runId ? { runId } : {},
30524
- ...result
30832
+ ...result,
30833
+ ...augmentAuthFields(errStr)
30525
30834
  });
30526
30835
  if (!result.success) {
30527
30836
  log2(`[Agent] ${result.error ?? "Error"}`);
@@ -30529,20 +30838,20 @@ async function sendPromptToAgent(options) {
30529
30838
  } catch (err) {
30530
30839
  const errMsg = err instanceof Error ? err.message : String(err);
30531
30840
  log2(`[Agent] Send failed: ${errMsg}`);
30532
- if (err instanceof Error && err.stack) log2(`[Agent] ${err.stack}`);
30533
30841
  sendResult({
30534
30842
  type: "prompt_result",
30535
30843
  id: promptId,
30536
30844
  ...sessionId ? { sessionId } : {},
30537
30845
  ...runId ? { runId } : {},
30538
30846
  success: false,
30539
- error: errMsg
30847
+ error: errMsg,
30848
+ ...augmentAuthFields(errMsg)
30540
30849
  });
30541
30850
  }
30542
30851
  }
30543
30852
 
30544
30853
  // src/acp/ensure-acp-client.ts
30545
- import * as fs5 from "node:fs";
30854
+ import * as fs4 from "node:fs";
30546
30855
  import * as path9 from "node:path";
30547
30856
 
30548
30857
  // src/error-message.ts
@@ -30555,49 +30864,293 @@ function errorMessage(err) {
30555
30864
  return String(err);
30556
30865
  }
30557
30866
 
30558
- // src/acp/clients/acp-client.ts
30867
+ // src/acp/clients/claude-code-acp-client.ts
30868
+ var claude_code_acp_client_exports = {};
30869
+ __export(claude_code_acp_client_exports, {
30870
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE,
30871
+ buildClaudeCodeAcpSpawnCommand: () => buildClaudeCodeAcpSpawnCommand,
30872
+ createClaudeCodeAcpClient: () => createClaudeCodeAcpClient,
30873
+ detectLocalAgentPresence: () => detectLocalAgentPresence
30874
+ });
30875
+ import { execFile as execFile4 } from "node:child_process";
30876
+ import { promisify as promisify4 } from "node:util";
30877
+
30878
+ // src/acp/clients/detect-command-on-path.ts
30879
+ import { execFile as execFile3 } from "node:child_process";
30880
+ import { promisify as promisify3 } from "node:util";
30881
+ var execFileAsync3 = promisify3(execFile3);
30882
+ async function isCommandOnPath(command, timeoutMs = 4e3) {
30883
+ try {
30884
+ await execFileAsync3("which", [command], { timeout: timeoutMs });
30885
+ return true;
30886
+ } catch {
30887
+ return false;
30888
+ }
30889
+ }
30890
+
30891
+ // src/acp/clients/sdk-stdio-acp-client.ts
30559
30892
  import { spawn as spawn2 } from "node:child_process";
30893
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
30894
+ import { dirname } from "node:path";
30560
30895
  import { Readable, Writable } from "node:stream";
30896
+
30897
+ // src/files/diff/unified-diff.ts
30898
+ function computeLineDiff(oldText, newText) {
30899
+ const oldLines = oldText.split("\n");
30900
+ const newLines = newText.split("\n");
30901
+ const m = oldLines.length;
30902
+ const n = newLines.length;
30903
+ const dp = Array(m + 1);
30904
+ for (let i2 = 0; i2 <= m; i2++) dp[i2] = Array(n + 1).fill(0);
30905
+ for (let i2 = 1; i2 <= m; i2++) {
30906
+ for (let j2 = 1; j2 <= n; j2++) {
30907
+ if (oldLines[i2 - 1] === newLines[j2 - 1]) {
30908
+ dp[i2][j2] = dp[i2 - 1][j2 - 1] + 1;
30909
+ } else {
30910
+ dp[i2][j2] = Math.max(dp[i2 - 1][j2], dp[i2][j2 - 1]);
30911
+ }
30912
+ }
30913
+ }
30914
+ const result = [];
30915
+ let i = m;
30916
+ let j = n;
30917
+ while (i > 0 || j > 0) {
30918
+ if (i > 0 && j > 0 && oldLines[i - 1] === newLines[j - 1]) {
30919
+ result.unshift({ type: "context", line: oldLines[i - 1] });
30920
+ i--;
30921
+ j--;
30922
+ } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {
30923
+ result.unshift({ type: "add", line: newLines[j - 1] });
30924
+ j--;
30925
+ } else {
30926
+ result.unshift({ type: "remove", line: oldLines[i - 1] });
30927
+ i--;
30928
+ }
30929
+ }
30930
+ return result;
30931
+ }
30932
+ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
30933
+ const lines = computeLineDiff(oldText, newText);
30934
+ const out = [`--- ${filePath}`, `+++ ${filePath}`];
30935
+ for (const d of lines) {
30936
+ if (d.type === "add") out.push(`+${d.line}`);
30937
+ else if (d.type === "remove") out.push(`-${d.line}`);
30938
+ else out.push(` ${d.line}`);
30939
+ }
30940
+ return out.join("\n");
30941
+ }
30942
+
30943
+ // src/acp/safe-fs-path.ts
30944
+ import * as path6 from "node:path";
30945
+ function resolveSafePathUnderCwd(cwd, filePath) {
30946
+ const trimmed2 = filePath.trim();
30947
+ if (!trimmed2) return null;
30948
+ const normalizedCwd = path6.resolve(cwd);
30949
+ const resolved = path6.isAbsolute(trimmed2) ? path6.normalize(trimmed2) : path6.resolve(normalizedCwd, trimmed2);
30950
+ const rel = path6.relative(normalizedCwd, resolved);
30951
+ if (rel.startsWith("..") || path6.isAbsolute(rel)) return null;
30952
+ return resolved;
30953
+ }
30954
+ function toDisplayPathRelativeToCwd(cwd, absolutePath) {
30955
+ const normalizedCwd = path6.resolve(cwd);
30956
+ const rel = path6.relative(normalizedCwd, path6.resolve(absolutePath));
30957
+ if (!rel || rel === "") return path6.basename(absolutePath);
30958
+ return rel.split(path6.sep).join("/");
30959
+ }
30960
+
30961
+ // src/acp/clients/agent-stderr-capture.ts
30962
+ var STDERR_CAPTURE_MAX = 48e3;
30963
+ function createStderrCapture(child) {
30964
+ const chunks = [];
30965
+ let total = 0;
30966
+ return {
30967
+ append(chunk) {
30968
+ try {
30969
+ process.stderr.write(chunk);
30970
+ } catch {
30971
+ }
30972
+ if (total >= STDERR_CAPTURE_MAX) return;
30973
+ const n = Math.min(chunk.length, STDERR_CAPTURE_MAX - total);
30974
+ if (n <= 0) return;
30975
+ chunks.push(n === chunk.length ? chunk : chunk.subarray(0, n));
30976
+ total += n;
30977
+ },
30978
+ getText() {
30979
+ return Buffer.concat(chunks).toString("utf8").trim();
30980
+ }
30981
+ };
30982
+ }
30983
+ function formatJsonRpcStyleError(err) {
30984
+ if (err instanceof Error) return err.message;
30985
+ if (err != null && typeof err === "object") {
30986
+ const o = err;
30987
+ const msg = typeof o.message === "string" ? o.message : null;
30988
+ const code = o.code != null ? String(o.code) : "";
30989
+ if (msg) return code ? `[${code}] ${msg}` : msg;
30990
+ }
30991
+ if (typeof err === "string") return err;
30992
+ try {
30993
+ return JSON.stringify(err);
30994
+ } catch {
30995
+ return String(err);
30996
+ }
30997
+ }
30998
+ function mergeErrorWithStderr(primary, stderrText) {
30999
+ const s = stderrText.trim();
31000
+ const p = (primary ?? "").trim();
31001
+ if (!s) return p;
31002
+ if (!p) return s;
31003
+ if (p.includes(s) || s.includes(p)) return p.length >= s.length ? p : s;
31004
+ return `${p}
31005
+ ${s}`;
31006
+ }
31007
+
31008
+ // src/acp/clients/kiro-sdk-ext-notifications.ts
31009
+ function createKiroSdkExtNotificationHandler(options) {
31010
+ const { onSessionUpdate } = options;
31011
+ return async (method, params) => {
31012
+ if (method === "_kiro.dev/metadata") {
31013
+ const p = params && typeof params === "object" ? params : {};
31014
+ const pct = p.contextUsagePercentage;
31015
+ if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
31016
+ onSessionUpdate({
31017
+ sessionUpdate: "context_usage",
31018
+ contextUsagePercentage: pct
31019
+ });
31020
+ return;
31021
+ }
31022
+ };
31023
+ }
31024
+
31025
+ // src/acp/clients/sdk-stdio-ext-notifications.ts
31026
+ var noopExtNotification = async () => {
31027
+ };
31028
+ function createSdkStdioExtNotificationHandler(options) {
31029
+ const { backendAgentType, onSessionUpdate } = options;
31030
+ switch (backendAgentType) {
31031
+ case "kiro-acp":
31032
+ return createKiroSdkExtNotificationHandler({ onSessionUpdate });
31033
+ default:
31034
+ return noopExtNotification;
31035
+ }
31036
+ }
31037
+
31038
+ // src/acp/clients/sdk-stdio-acp-client.ts
30561
31039
  function formatSpawnError(err, command) {
30562
31040
  if (err.code === "ENOENT") {
30563
31041
  return `Command "${command}" not found. Install the agent (e.g. Cursor CLI) or add it to PATH.`;
30564
31042
  }
30565
31043
  return err.message || String(err);
30566
31044
  }
30567
- function toErrorMessage(err) {
30568
- if (err instanceof Error) return err.message;
30569
- if (err != null && typeof err === "object" && "message" in err)
30570
- return String(err.message);
30571
- if (typeof err === "string") return err;
30572
- if (err != null && typeof err === "object") return JSON.stringify(err);
30573
- return String(err);
31045
+ function sliceFileContentRange(content, line, limit) {
31046
+ if (line == null && limit == null) return content;
31047
+ const lines = content.split("\n");
31048
+ const start = line != null && line > 0 ? line - 1 : 0;
31049
+ const end = limit != null && limit > 0 ? start + limit : lines.length;
31050
+ return lines.slice(start, end).join("\n");
31051
+ }
31052
+ function bridgePayloadFromSdkSessionNotification(params) {
31053
+ return { sessionId: params.sessionId, ...params.update };
30574
31054
  }
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;
31055
+ async function createSdkStdioAcpClient(options) {
31056
+ const { ClientSideConnection: ClientSideConnection2, ndJsonStream: ndJsonStream2, PROTOCOL_VERSION: PROTOCOL_VERSION2 } = await Promise.resolve().then(() => (init_acp(), acp_exports));
31057
+ const {
31058
+ command,
31059
+ cwd = getBridgeWorkspaceDirectory(),
31060
+ backendAgentType,
31061
+ onSessionUpdate,
31062
+ onFileChange,
31063
+ killSubprocessAfterCancelMs,
31064
+ onAgentSubprocessExit
31065
+ } = options;
30578
31066
  const isWindows = process.platform === "win32";
30579
31067
  const child = spawn2(command[0], command.slice(1), {
30580
31068
  cwd,
30581
- stdio: ["pipe", "pipe", "inherit"],
31069
+ stdio: ["pipe", "pipe", "pipe"],
30582
31070
  env: process.env,
30583
31071
  shell: isWindows
30584
31072
  });
31073
+ const stderrCapture = createStderrCapture(child);
31074
+ child.once("close", (code, signal) => {
31075
+ onAgentSubprocessExit?.({ code, signal });
31076
+ });
30585
31077
  return new Promise((resolve15, reject) => {
31078
+ let initSettled = false;
31079
+ const settleReject = (err) => {
31080
+ if (initSettled) return;
31081
+ initSettled = true;
31082
+ try {
31083
+ child.kill();
31084
+ } catch {
31085
+ }
31086
+ reject(err);
31087
+ };
31088
+ const settleResolve = (handle) => {
31089
+ if (initSettled) return;
31090
+ initSettled = true;
31091
+ resolve15(handle);
31092
+ };
30586
31093
  child.on("error", (err) => {
30587
- child.kill();
30588
- reject(new Error(formatSpawnError(err, command[0])));
31094
+ settleReject(new Error(formatSpawnError(err, command[0])));
31095
+ });
31096
+ child.stderr?.on("data", (chunk) => {
31097
+ stderrCapture.append(chunk);
31098
+ if (initSettled) return;
31099
+ const stderrText = stderrCapture.getText();
31100
+ if (backendAgentType && stderrText.trim() && localAgentErrorSuggestsAuth(backendAgentType, stderrText)) {
31101
+ settleReject(new Error(stderrText.trim()));
31102
+ }
30589
31103
  });
30590
31104
  (async () => {
30591
31105
  try {
30592
31106
  const writable = Writable.toWeb(child.stdin);
30593
31107
  const readable = Readable.toWeb(child.stdout);
30594
31108
  const stream = ndJsonStream2(writable, readable);
31109
+ const extNotification = createSdkStdioExtNotificationHandler({
31110
+ backendAgentType,
31111
+ onSessionUpdate
31112
+ });
30595
31113
  const client = (_agent) => ({
30596
- async requestPermission(_params) {
30597
- return { outcome: "approved" };
31114
+ async requestPermission(params) {
31115
+ const opt = params?.options?.[0];
31116
+ if (opt && typeof opt.optionId === "string") {
31117
+ return { outcome: { outcome: "selected", optionId: opt.optionId } };
31118
+ }
31119
+ return { outcome: { outcome: "cancelled" } };
31120
+ },
31121
+ async readTextFile(params) {
31122
+ const abs = resolveSafePathUnderCwd(cwd, params.path);
31123
+ if (!abs) throw new Error("Invalid or disallowed path");
31124
+ try {
31125
+ let content = readFileSync2(abs, "utf8");
31126
+ content = sliceFileContentRange(content, params.line, params.limit);
31127
+ return { content };
31128
+ } catch (e) {
31129
+ if (e.code === "ENOENT") return { content: "" };
31130
+ throw e;
31131
+ }
31132
+ },
31133
+ async writeTextFile(params) {
31134
+ const abs = resolveSafePathUnderCwd(cwd, params.path);
31135
+ if (!abs) throw new Error("Invalid or disallowed path");
31136
+ let oldText = "";
31137
+ try {
31138
+ oldText = readFileSync2(abs, "utf8");
31139
+ } catch (e) {
31140
+ if (e.code !== "ENOENT") throw e;
31141
+ }
31142
+ mkdirSync2(dirname(abs), { recursive: true });
31143
+ writeFileSync2(abs, params.content, "utf8");
31144
+ const displayPath = toDisplayPathRelativeToCwd(cwd, abs);
31145
+ const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, params.content);
31146
+ onFileChange?.({ path: displayPath, oldText, newText: params.content, patchContent });
31147
+ return {};
30598
31148
  },
30599
31149
  async sessionUpdate(params) {
30600
- onSessionUpdate?.(params);
31150
+ onSessionUpdate?.(bridgePayloadFromSdkSessionNotification(params));
31151
+ },
31152
+ async extNotification(method, params) {
31153
+ await extNotification(method, params);
30601
31154
  }
30602
31155
  });
30603
31156
  const connection = new ClientSideConnection2(client, stream);
@@ -30605,39 +31158,82 @@ async function createAcpClient(options) {
30605
31158
  child.kill();
30606
31159
  });
30607
31160
  await connection.initialize({
30608
- protocolVersion: "0.1.0",
30609
- capabilities: {},
31161
+ protocolVersion: PROTOCOL_VERSION2,
31162
+ clientCapabilities: {
31163
+ fs: { readTextFile: true, writeTextFile: true }
31164
+ },
30610
31165
  clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
30611
31166
  });
30612
- const newSessionRes = await connection.newSession({ workingDirectory: cwd });
31167
+ const newSessionRes = await connection.newSession({ cwd, mcpServers: [] });
30613
31168
  const sessionId = newSessionRes.sessionId;
30614
- resolve15({
31169
+ settleResolve({
30615
31170
  sessionId,
30616
31171
  async sendPrompt(prompt, _options) {
30617
31172
  try {
30618
31173
  const response = await connection.prompt({
30619
31174
  sessionId,
30620
- prompt: { type: "text", text: prompt }
31175
+ prompt: [{ type: "text", text: prompt }]
30621
31176
  });
31177
+ await new Promise((r2) => setImmediate(r2));
30622
31178
  const r = response;
30623
- const cancelled = (r?.stopReason ?? "").toLowerCase() === "cancelled";
31179
+ const stopReason = (r?.stopReason ?? "").toLowerCase();
31180
+ const cancelled = stopReason === "cancelled";
31181
+ const refusal = stopReason === "refusal";
31182
+ const stderrAfter = stderrCapture.getText();
31183
+ const agentType = backendAgentType ?? null;
31184
+ const stderrEvaluated = Boolean(stderrAfter && agentType);
31185
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
31186
+ if (cancelled) {
31187
+ return {
31188
+ success: false,
31189
+ stopReason: r?.stopReason,
31190
+ output: r?.output,
31191
+ error: mergeErrorWithStderr("Stopped by user", stderrAfter)
31192
+ };
31193
+ }
31194
+ if (refusal) {
31195
+ return {
31196
+ success: false,
31197
+ stopReason: r?.stopReason,
31198
+ output: r?.output,
31199
+ error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
31200
+ };
31201
+ }
31202
+ if (stderrSuggestsAuth) {
31203
+ return {
31204
+ success: false,
31205
+ stopReason: r?.stopReason,
31206
+ output: r?.output,
31207
+ error: stderrAfter
31208
+ };
31209
+ }
30624
31210
  return {
30625
- success: !cancelled,
31211
+ success: true,
30626
31212
  stopReason: r?.stopReason,
30627
- output: r?.output,
30628
- ...cancelled ? { error: "Stopped by user" } : {}
31213
+ output: r?.output
30629
31214
  };
30630
31215
  } catch (err) {
31216
+ await new Promise((r) => setImmediate(r));
31217
+ const stderrAfter = stderrCapture.getText();
31218
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
30631
31219
  return {
30632
31220
  success: false,
30633
- error: err instanceof Error ? err.message : String(err)
31221
+ error: merged
30634
31222
  };
30635
31223
  }
30636
31224
  },
30637
31225
  async cancel() {
30638
- const conn = connection;
30639
- if (typeof conn.cancel === "function") {
30640
- await conn.cancel({ sessionId });
31226
+ try {
31227
+ await connection.cancel({ sessionId });
31228
+ } catch {
31229
+ }
31230
+ if (killSubprocessAfterCancelMs != null && killSubprocessAfterCancelMs >= 0) {
31231
+ const t = setTimeout(() => {
31232
+ if (child.exitCode == null && child.signalCode == null) {
31233
+ child.kill("SIGTERM");
31234
+ }
31235
+ }, killSubprocessAfterCancelMs);
31236
+ t.unref?.();
30641
31237
  }
30642
31238
  },
30643
31239
  resolveRequest() {
@@ -30647,94 +31243,88 @@ async function createAcpClient(options) {
30647
31243
  }
30648
31244
  });
30649
31245
  } catch (err) {
30650
- child.kill();
30651
- reject(new Error(toErrorMessage(err)));
31246
+ if (initSettled) return;
31247
+ try {
31248
+ child.kill();
31249
+ } catch {
31250
+ }
31251
+ const stderrText = stderrCapture.getText();
31252
+ const base = formatJsonRpcStyleError(err);
31253
+ settleReject(new Error(mergeErrorWithStderr(base, stderrText)));
30652
31254
  }
30653
31255
  })();
30654
31256
  });
30655
31257
  }
30656
31258
 
31259
+ // src/acp/clients/claude-code-acp-client.ts
31260
+ var execFileAsync4 = promisify4(execFile4);
31261
+ var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
31262
+ async function detectLocalAgentPresence() {
31263
+ if (await isCommandOnPath("claude")) return true;
31264
+ try {
31265
+ await execFileAsync4("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], { timeout: 25e3 });
31266
+ return true;
31267
+ } catch {
31268
+ return false;
31269
+ }
31270
+ }
31271
+ function buildClaudeCodeAcpSpawnCommand(base, sessionMode) {
31272
+ if (!sessionMode) return [...base];
31273
+ const m = sessionMode.trim();
31274
+ if (m === "plan") return [...base, "--permission-mode", "plan"];
31275
+ return [...base];
31276
+ }
31277
+ async function createClaudeCodeAcpClient(options) {
31278
+ const command = buildClaudeCodeAcpSpawnCommand(options.command, options.sessionMode);
31279
+ return createSdkStdioAcpClient({
31280
+ ...options,
31281
+ command,
31282
+ /** Claude-based agents sometimes ignore `session/cancel`; unblocks stop / stuck prompt. */
31283
+ killSubprocessAfterCancelMs: options.killSubprocessAfterCancelMs ?? 1e3
31284
+ });
31285
+ }
31286
+
30657
31287
  // src/acp/clients/codex-acp-client.ts
31288
+ var codex_acp_client_exports = {};
31289
+ __export(codex_acp_client_exports, {
31290
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE2,
31291
+ DEFAULT_CODEX_ACP_COMMAND: () => DEFAULT_CODEX_ACP_COMMAND,
31292
+ buildCodexAcpSpawnCommand: () => buildCodexAcpSpawnCommand,
31293
+ createCodexAcpClient: () => createCodexAcpClient,
31294
+ detectLocalAgentPresence: () => detectLocalAgentPresence2,
31295
+ isCodexAcpCommand: () => isCodexAcpCommand
31296
+ });
31297
+ var BACKEND_LOCAL_AGENT_TYPE2 = "codex-acp";
31298
+ async function detectLocalAgentPresence2() {
31299
+ return isCommandOnPath("codex");
31300
+ }
30658
31301
  var DEFAULT_CODEX_ACP_COMMAND = ["npx", "--yes", "@zed-industries/codex-acp"];
30659
31302
  function isCodexAcpCommand(command) {
30660
31303
  const i = command.indexOf("@zed-industries/codex-acp");
30661
31304
  return i >= 0 && (i === 0 || command[i - 1] === "npx" || command[i - 1] === "bunx");
30662
31305
  }
31306
+ function buildCodexAcpSpawnCommand(base, _sessionMode) {
31307
+ return [...base];
31308
+ }
30663
31309
  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 });
31310
+ const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
31311
+ const command = buildCodexAcpSpawnCommand(base, options.sessionMode);
31312
+ return createSdkStdioAcpClient({ ...options, command });
30666
31313
  }
30667
31314
 
30668
31315
  // 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";
31316
+ var cursor_acp_client_exports = {};
31317
+ __export(cursor_acp_client_exports, {
31318
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
31319
+ buildCursorAcpSpawnCommand: () => buildCursorAcpSpawnCommand,
31320
+ createCursorAcpClient: () => createCursorAcpClient,
31321
+ detectLocalAgentPresence: () => detectLocalAgentPresence3
31322
+ });
31323
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
31324
+ import { dirname as dirname2 } from "node:path";
30671
31325
  import { spawn as spawn3 } from "node:child_process";
30672
31326
  import * as readline from "node:readline";
30673
31327
 
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
31328
  // src/acp/format-session-update-kind-for-log.ts
30739
31329
  var SESSION_UPDATE_KIND_LABELS = {
30740
31330
  tool_call: "Tool call",
@@ -30772,16 +31362,31 @@ function sliceLinesByRange(content, line, limit) {
30772
31362
  const end = limit != null && limit > 0 ? start + limit : lines.length;
30773
31363
  return lines.slice(start, end).join("\n");
30774
31364
  }
31365
+ function buildCursorAcpSpawnCommand(base, sessionMode) {
31366
+ if (!sessionMode) return [...base];
31367
+ const m = sessionMode.trim();
31368
+ if (m !== "ask" && m !== "plan") return [...base];
31369
+ return [...base, "--mode", m];
31370
+ }
30775
31371
  async function createCursorAcpClient(options) {
30776
- const { command, cwd = getBridgeWorkspaceDirectory(), onSessionUpdate, onRequest, onFileChange } = options;
31372
+ const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
31373
+ const {
31374
+ cwd = getBridgeWorkspaceDirectory(),
31375
+ backendAgentType,
31376
+ onSessionUpdate,
31377
+ onRequest,
31378
+ onFileChange
31379
+ } = options;
30777
31380
  const dbgFs = process.env.BUILDAMATON_DEBUG_ACP_FS === "1";
30778
31381
  const isWindows = process.platform === "win32";
30779
31382
  const child = spawn3(command[0], command.slice(1), {
30780
31383
  cwd,
30781
- stdio: ["pipe", "pipe", "inherit"],
31384
+ stdio: ["pipe", "pipe", "pipe"],
30782
31385
  env: process.env,
30783
31386
  shell: isWindows
30784
31387
  });
31388
+ const stderrCapture = createStderrCapture(child);
31389
+ child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
30785
31390
  return new Promise((resolve15, reject) => {
30786
31391
  child.on("error", (err) => {
30787
31392
  child.kill();
@@ -30905,8 +31510,8 @@ async function createCursorAcpClient(options) {
30905
31510
  }
30906
31511
  }
30907
31512
  try {
30908
- mkdirSync2(dirname(abs), { recursive: true });
30909
- writeFileSync2(abs, newText, "utf8");
31513
+ mkdirSync3(dirname2(abs), { recursive: true });
31514
+ writeFileSync3(abs, newText, "utf8");
30910
31515
  } catch (e) {
30911
31516
  respondJsonRpcError(id, -32e3, e instanceof Error ? e.message : String(e));
30912
31517
  return;
@@ -30965,17 +31570,52 @@ async function createCursorAcpClient(options) {
30965
31570
  sessionId,
30966
31571
  prompt: [{ type: "text", text: prompt }]
30967
31572
  });
31573
+ await new Promise((r) => setImmediate(r));
30968
31574
  const output = (result?.output ?? promptOutputBuffer) || void 0;
30969
- const cancelled = (result?.stopReason ?? "").toLowerCase() === "cancelled";
31575
+ const stopReason = (result?.stopReason ?? "").toLowerCase();
31576
+ const cancelled = stopReason === "cancelled";
31577
+ const refusal = stopReason === "refusal";
31578
+ const stderrAfter = stderrCapture.getText();
31579
+ const agentType = backendAgentType ?? null;
31580
+ const stderrEvaluated = Boolean(stderrAfter && agentType);
31581
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
31582
+ if (cancelled) {
31583
+ return {
31584
+ success: false,
31585
+ stopReason: result?.stopReason,
31586
+ output: output || void 0,
31587
+ error: mergeErrorWithStderr("Stopped by user", stderrAfter)
31588
+ };
31589
+ }
31590
+ if (refusal) {
31591
+ return {
31592
+ success: false,
31593
+ stopReason: result?.stopReason,
31594
+ output: output || void 0,
31595
+ error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
31596
+ };
31597
+ }
31598
+ if (stderrSuggestsAuth) {
31599
+ return {
31600
+ success: false,
31601
+ stopReason: result?.stopReason,
31602
+ output: output || void 0,
31603
+ error: stderrAfter
31604
+ };
31605
+ }
30970
31606
  return {
30971
- success: !cancelled,
31607
+ success: true,
30972
31608
  stopReason: result?.stopReason,
30973
- output: output || void 0,
30974
- ...cancelled ? { error: "Stopped by user" } : {}
31609
+ output: output || void 0
30975
31610
  };
30976
31611
  } catch (err) {
30977
- const message = err != null && typeof err === "object" && "message" in err ? String(err.message) : String(err);
30978
- return { success: false, error: message };
31612
+ await new Promise((r) => setImmediate(r));
31613
+ const stderrAfter = stderrCapture.getText();
31614
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
31615
+ return {
31616
+ success: false,
31617
+ error: merged
31618
+ };
30979
31619
  }
30980
31620
  },
30981
31621
  async cancel() {
@@ -30994,38 +31634,120 @@ async function createCursorAcpClient(options) {
30994
31634
  });
30995
31635
  } catch (err) {
30996
31636
  child.kill();
30997
- reject(err);
31637
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrCapture.getText());
31638
+ reject(merged ? new Error(merged) : err instanceof Error ? err : new Error(String(err)));
30998
31639
  }
30999
31640
  })();
31000
31641
  });
31001
31642
  }
31643
+ var BACKEND_LOCAL_AGENT_TYPE3 = "cursor-cli";
31644
+ async function detectLocalAgentPresence3() {
31645
+ return isCommandOnPath("agent");
31646
+ }
31647
+
31648
+ // src/acp/clients/kiro-acp-client.ts
31649
+ var kiro_acp_client_exports = {};
31650
+ __export(kiro_acp_client_exports, {
31651
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE4,
31652
+ DEFAULT_KIRO_ACP_COMMAND: () => DEFAULT_KIRO_ACP_COMMAND,
31653
+ buildKiroAcpSpawnCommand: () => buildKiroAcpSpawnCommand,
31654
+ createKiroAcpClient: () => createKiroAcpClient,
31655
+ detectLocalAgentPresence: () => detectLocalAgentPresence4,
31656
+ isKiroAcpCommand: () => isKiroAcpCommand
31657
+ });
31658
+ var BACKEND_LOCAL_AGENT_TYPE4 = "kiro-acp";
31659
+ async function detectLocalAgentPresence4() {
31660
+ return isCommandOnPath("kiro-cli");
31661
+ }
31662
+ var DEFAULT_KIRO_ACP_COMMAND = ["kiro-cli", "acp"];
31663
+ function isKiroAcpCommand(command) {
31664
+ if (command.length < 2) return false;
31665
+ if (command[command.length - 1] !== "acp") return false;
31666
+ return command.slice(0, -1).some(
31667
+ (a) => a === "kiro-cli" || /[/\\]kiro-cli(\.exe)?$/i.test(a)
31668
+ );
31669
+ }
31670
+ function buildKiroAcpSpawnCommand(base, _sessionMode) {
31671
+ return [...base];
31672
+ }
31673
+ async function createKiroAcpClient(options) {
31674
+ const base = options.command?.length && isKiroAcpCommand(options.command) ? options.command : [...DEFAULT_KIRO_ACP_COMMAND];
31675
+ const command = buildKiroAcpSpawnCommand(base, options.sessionMode);
31676
+ return createSdkStdioAcpClient({ ...options, command });
31677
+ }
31002
31678
 
31003
31679
  // src/acp/resolve-agent-command.ts
31004
31680
  var AGENT_TYPE_DEFAULT_COMMANDS = {
31005
- "cursor-cli": ["agent", "acp"],
31006
- "codex-acp": [...DEFAULT_CODEX_ACP_COMMAND],
31007
- "claude-code": ["npx", "--yes", "@anthropic-ai/claude-code"]
31681
+ [BACKEND_LOCAL_AGENT_TYPE3]: ["agent", "acp"],
31682
+ [BACKEND_LOCAL_AGENT_TYPE2]: [...DEFAULT_CODEX_ACP_COMMAND],
31683
+ /** ACP stdio agent; `@anthropic-ai/claude-code` is the interactive CLI and does not speak ACP on stdout. */
31684
+ [BACKEND_LOCAL_AGENT_TYPE]: ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"],
31685
+ /** [Kiro CLI ACP](https://kiro.dev/docs/cli/acp/) — use full path to `kiro-cli` in PATH if the IDE cannot find it. */
31686
+ [BACKEND_LOCAL_AGENT_TYPE4]: [...DEFAULT_KIRO_ACP_COMMAND]
31008
31687
  };
31688
+ var AGENT_TYPE_DISPLAY_NAMES = {
31689
+ [BACKEND_LOCAL_AGENT_TYPE3]: "Cursor",
31690
+ [BACKEND_LOCAL_AGENT_TYPE2]: "Codex",
31691
+ [BACKEND_LOCAL_AGENT_TYPE]: "Claude Code",
31692
+ [BACKEND_LOCAL_AGENT_TYPE4]: "Kiro"
31693
+ };
31694
+ function getAgentTypeDisplayName(agentType) {
31695
+ if (agentType == null || agentType === "") return "Unknown agent";
31696
+ const known = AGENT_TYPE_DISPLAY_NAMES[agentType];
31697
+ if (known) return known;
31698
+ return agentType.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
31699
+ }
31009
31700
  function useCursorAcp(agentType, command) {
31010
- if (agentType === "cursor-cli") return true;
31701
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE3) return true;
31011
31702
  return command[0] === "agent" && command[1] === "acp";
31012
31703
  }
31013
31704
  function useCodexAcp(agentType, command) {
31014
- if (agentType === "codex-acp") return true;
31705
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE2) return true;
31015
31706
  return isCodexAcpCommand(command);
31016
31707
  }
31708
+ function useKiroAcp(agentType, command) {
31709
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE4) return true;
31710
+ return isKiroAcpCommand(command);
31711
+ }
31017
31712
  function resolveAgentCommand(preferredAgentType) {
31018
31713
  if (!preferredAgentType) return null;
31019
31714
  const command = AGENT_TYPE_DEFAULT_COMMANDS[preferredAgentType];
31020
31715
  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 };
31716
+ if (useCursorAcp(preferredAgentType, command)) {
31717
+ return {
31718
+ command,
31719
+ label: preferredAgentType,
31720
+ createClient: createCursorAcpClient,
31721
+ spawnCommandForSession: (sessionMode) => buildCursorAcpSpawnCommand(command, sessionMode)
31722
+ };
31723
+ }
31724
+ if (useCodexAcp(preferredAgentType, command)) {
31725
+ return {
31726
+ command,
31727
+ label: preferredAgentType,
31728
+ createClient: createCodexAcpClient,
31729
+ spawnCommandForSession: (sessionMode) => buildCodexAcpSpawnCommand(command, sessionMode)
31730
+ };
31731
+ }
31732
+ if (useKiroAcp(preferredAgentType, command)) {
31733
+ return {
31734
+ command,
31735
+ label: preferredAgentType,
31736
+ createClient: createKiroAcpClient,
31737
+ spawnCommandForSession: (sessionMode) => buildKiroAcpSpawnCommand(command, sessionMode)
31738
+ };
31739
+ }
31740
+ return {
31741
+ command,
31742
+ label: preferredAgentType,
31743
+ createClient: createClaudeCodeAcpClient,
31744
+ spawnCommandForSession: (sessionMode) => buildClaudeCodeAcpSpawnCommand(command, sessionMode)
31745
+ };
31024
31746
  }
31025
31747
 
31026
31748
  // src/acp/session-file-change-path-kind.ts
31027
31749
  import { execFileSync as execFileSync3 } from "node:child_process";
31028
- import { existsSync, statSync as statSync2 } from "node:fs";
31750
+ import { existsSync, statSync } from "node:fs";
31029
31751
 
31030
31752
  // src/git/get-git-repo-root-sync.ts
31031
31753
  import { execFileSync } from "node:child_process";
@@ -31134,7 +31856,7 @@ function getSessionFileChangeDirectoryFlags(cwd, displayPath) {
31134
31856
  const abs = tryWorkspaceDisplayToAbs(cwd, displayPath);
31135
31857
  if (abs && existsSync(abs)) {
31136
31858
  try {
31137
- if (statSync2(abs).isDirectory()) {
31859
+ if (statSync(abs).isDirectory()) {
31138
31860
  return { isDirectory: true, directoryRemoved: false };
31139
31861
  }
31140
31862
  return { isDirectory: false, directoryRemoved: false };
@@ -31680,7 +32402,8 @@ async function ensureAcpClient(options) {
31680
32402
  state.lastAcpStartError = "No agent type: ensure the app sends agentType on prompts or agent_config for this bridge.";
31681
32403
  return null;
31682
32404
  }
31683
- const agentKey = `${resolved.label}::${resolved.command.join("\0")}`;
32405
+ const fullCmd = resolved.spawnCommandForSession(mode);
32406
+ const agentKey = `${resolved.label}::${fullCmd.join("\0")}`;
31684
32407
  if (state.acpHandle && state.acpAgentKey !== agentKey) {
31685
32408
  try {
31686
32409
  state.acpHandle.disconnect();
@@ -31694,7 +32417,7 @@ async function ensureAcpClient(options) {
31694
32417
  if (!state.acpStartPromise) {
31695
32418
  let statOk = false;
31696
32419
  try {
31697
- const st = fs5.statSync(targetCwd);
32420
+ const st = fs4.statSync(targetCwd);
31698
32421
  statOk = st.isDirectory();
31699
32422
  if (!statOk) {
31700
32423
  state.lastAcpStartError = `Agent cwd is not a directory: ${targetCwd}`;
@@ -31707,8 +32430,6 @@ async function ensureAcpClient(options) {
31707
32430
  if (!statOk) {
31708
32431
  return null;
31709
32432
  }
31710
- const modeFlag = mode && ["ask", "plan"].includes(mode) ? ["--mode", mode] : [];
31711
- const fullCmd = [...resolved.command, ...modeFlag];
31712
32433
  const hooks = buildAcpSessionBridgeHooks({
31713
32434
  routing,
31714
32435
  getSendSessionUpdate: () => sendSessionUpdate,
@@ -31716,8 +32437,16 @@ async function ensureAcpClient(options) {
31716
32437
  log: log2
31717
32438
  });
31718
32439
  state.acpStartPromise = resolved.createClient({
31719
- command: fullCmd,
32440
+ command: resolved.command,
32441
+ sessionMode: mode,
31720
32442
  cwd: targetCwd,
32443
+ backendAgentType: preferredAgentType,
32444
+ onAgentSubprocessExit: () => {
32445
+ state.acpHandle = null;
32446
+ state.acpStartPromise = null;
32447
+ state.acpAgentKey = null;
32448
+ state.lastAcpStartError = "Agent subprocess exited";
32449
+ },
31721
32450
  ...hooks
31722
32451
  }).then((h) => {
31723
32452
  state.lastAcpStartError = null;
@@ -31755,6 +32484,14 @@ async function createAcpManager(options) {
31755
32484
  backendFallbackAgentType = agentType;
31756
32485
  }
31757
32486
  }
32487
+ function logPromptReceivedFromBridge(opts) {
32488
+ const { agentType, mode } = opts;
32489
+ const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
32490
+ const modeLabel = typeof mode === "string" && mode.trim() !== "" ? mode.trim() : "not set";
32491
+ log2(
32492
+ `[Agent] Prompt received (${getAgentTypeDisplayName(preferredForPrompt)}, mode: ${modeLabel})`
32493
+ );
32494
+ }
31758
32495
  function handlePrompt(opts) {
31759
32496
  const {
31760
32497
  promptText,
@@ -31784,17 +32521,24 @@ async function createAcpManager(options) {
31784
32521
  log: log2
31785
32522
  });
31786
32523
  if (!handle) {
32524
+ const errMsg = state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app.";
32525
+ const evaluated = Boolean(preferredForPrompt && errMsg.trim());
32526
+ const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
32527
+ const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
31787
32528
  sendResult({
31788
32529
  type: "prompt_result",
31789
32530
  id: promptId,
31790
32531
  ...sessionId ? { sessionId } : {},
31791
32532
  ...runId ? { runId } : {},
31792
32533
  success: false,
31793
- error: state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app."
32534
+ error: errMsg,
32535
+ ...auth
31794
32536
  });
31795
32537
  return;
31796
32538
  }
31797
- if (promptRouting.sessionId !== sessionId || promptRouting.runId !== runId) return;
32539
+ if (promptRouting.sessionId !== sessionId || promptRouting.runId !== runId) {
32540
+ return;
32541
+ }
31798
32542
  if (runId && pendingCancelRunId === runId) {
31799
32543
  pendingCancelRunId = void 0;
31800
32544
  try {
@@ -31818,6 +32562,7 @@ async function createAcpManager(options) {
31818
32562
  promptId,
31819
32563
  sessionId,
31820
32564
  runId,
32565
+ agentType: preferredForPrompt,
31821
32566
  agentCwd: cwd,
31822
32567
  sendResult,
31823
32568
  sendSessionUpdate,
@@ -31835,6 +32580,7 @@ async function createAcpManager(options) {
31835
32580
  if (promptRouting.runId !== runId) return false;
31836
32581
  const handle = state.acpHandle;
31837
32582
  if (handle?.cancel) {
32583
+ log2("[Agent] Stop requested");
31838
32584
  try {
31839
32585
  await handle.cancel();
31840
32586
  return true;
@@ -31843,6 +32589,7 @@ async function createAcpManager(options) {
31843
32589
  return false;
31844
32590
  }
31845
32591
  }
32592
+ log2("[Agent] Stop requested (agent still starting)");
31846
32593
  pendingCancelRunId = runId;
31847
32594
  return true;
31848
32595
  }
@@ -31855,7 +32602,14 @@ async function createAcpManager(options) {
31855
32602
  state.acpStartPromise = null;
31856
32603
  state.acpAgentKey = null;
31857
32604
  }
31858
- return { setPreferredAgentType, handlePrompt, cancelRun, resolveRequest, disconnect };
32605
+ return {
32606
+ setPreferredAgentType,
32607
+ logPromptReceivedFromBridge,
32608
+ handlePrompt,
32609
+ cancelRun,
32610
+ resolveRequest,
32611
+ disconnect
32612
+ };
31859
32613
  }
31860
32614
 
31861
32615
  // src/bridge/routing/handlers/auth-token.ts
@@ -31906,8 +32660,8 @@ var handleAgentConfigMessage = (msg, deps) => {
31906
32660
 
31907
32661
  // src/acp/from-bridge/handle-bridge-prompt.ts
31908
32662
  import * as path11 from "node:path";
31909
- import { execFile as execFile3 } from "node:child_process";
31910
- import { promisify as promisify3 } from "node:util";
32663
+ import { execFile as execFile5 } from "node:child_process";
32664
+ import { promisify as promisify5 } from "node:util";
31911
32665
 
31912
32666
  // src/git/bridge-queue-key.ts
31913
32667
  import * as path10 from "node:path";
@@ -31965,10 +32719,10 @@ async function resolveBridgeQueueBindFields(options) {
31965
32719
  }
31966
32720
 
31967
32721
  // src/acp/from-bridge/handle-bridge-prompt.ts
31968
- var execFileAsync3 = promisify3(execFile3);
32722
+ var execFileAsync5 = promisify5(execFile5);
31969
32723
  async function readGitBranch(cwd) {
31970
32724
  try {
31971
- const { stdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
32725
+ const { stdout } = await execFileAsync5("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
31972
32726
  const b = stdout.trim();
31973
32727
  return b || null;
31974
32728
  } catch {
@@ -31990,6 +32744,8 @@ function handleBridgePrompt(msg, deps) {
31990
32744
  const sessionWorktreesEnabled = msg.sessionWorktreesEnabled === true;
31991
32745
  const agentType = typeof msg.agentType === "string" && msg.agentType.trim() ? msg.agentType.trim() : void 0;
31992
32746
  const runId = typeof msg.runId === "string" ? msg.runId : void 0;
32747
+ const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
32748
+ acpManager.logPromptReceivedFromBridge({ agentType, mode });
31993
32749
  const sendResult = (result) => {
31994
32750
  const s = getWs();
31995
32751
  if (s) sendWsMessage(s, result);
@@ -32052,7 +32808,7 @@ function handleBridgePrompt(msg, deps) {
32052
32808
  promptId: msg.id,
32053
32809
  sessionId,
32054
32810
  runId,
32055
- mode: msg.mode,
32811
+ mode,
32056
32812
  agentType,
32057
32813
  cwd: effectiveCwd,
32058
32814
  sendResult,
@@ -32296,7 +33052,7 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
32296
33052
  };
32297
33053
 
32298
33054
  // src/files/list-dir.ts
32299
- import fs6 from "node:fs";
33055
+ import fs5 from "node:fs";
32300
33056
  import path13 from "node:path";
32301
33057
 
32302
33058
  // src/files/ensure-under-cwd.ts
@@ -32317,14 +33073,14 @@ function listDir(relativePath) {
32317
33073
  return { error: "Path is outside working directory" };
32318
33074
  }
32319
33075
  try {
32320
- const names = fs6.readdirSync(resolved, { withFileTypes: true });
33076
+ const names = fs5.readdirSync(resolved, { withFileTypes: true });
32321
33077
  const entries = names.filter((d) => !d.name.startsWith(".")).map((d) => {
32322
33078
  const entryPath = path13.join(relativePath || ".", d.name).replace(/\\/g, "/");
32323
33079
  const fullPath = path13.join(resolved, d.name);
32324
33080
  let isDir = d.isDirectory();
32325
33081
  if (d.isSymbolicLink()) {
32326
33082
  try {
32327
- const targetStat = fs6.statSync(fullPath);
33083
+ const targetStat = fs5.statSync(fullPath);
32328
33084
  isDir = targetStat.isDirectory();
32329
33085
  } catch {
32330
33086
  isDir = false;
@@ -32348,25 +33104,25 @@ function listDir(relativePath) {
32348
33104
  }
32349
33105
 
32350
33106
  // src/files/read-file.ts
32351
- import fs7 from "node:fs";
33107
+ import fs6 from "node:fs";
32352
33108
  import { StringDecoder } from "node:string_decoder";
32353
33109
  function resolveFilePath(relativePath) {
32354
33110
  const resolved = ensureUnderCwd(relativePath, getBridgeWorkspaceDirectory());
32355
33111
  if (!resolved) return { error: "Path is outside working directory" };
32356
33112
  let real;
32357
33113
  try {
32358
- real = fs7.realpathSync(resolved);
33114
+ real = fs6.realpathSync(resolved);
32359
33115
  } catch {
32360
33116
  real = resolved;
32361
33117
  }
32362
- const stat = fs7.statSync(real);
32363
- if (!stat.isFile()) return { error: "Not a file" };
33118
+ const stat2 = fs6.statSync(real);
33119
+ if (!stat2.isFile()) return { error: "Not a file" };
32364
33120
  return real;
32365
33121
  }
32366
33122
  var LINE_CHUNK_SIZE = 64 * 1024;
32367
33123
  function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
32368
- const fileSize = fs7.statSync(filePath).size;
32369
- const fd = fs7.openSync(filePath, "r");
33124
+ const fileSize = fs6.statSync(filePath).size;
33125
+ const fd = fs6.openSync(filePath, "r");
32370
33126
  const bufSize = 64 * 1024;
32371
33127
  const buf = Buffer.alloc(bufSize);
32372
33128
  const decoder = new StringDecoder("utf8");
@@ -32379,7 +33135,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
32379
33135
  let line0Accum = "";
32380
33136
  try {
32381
33137
  let bytesRead;
32382
- while (!done && (bytesRead = fs7.readSync(fd, buf, 0, bufSize, null)) > 0) {
33138
+ while (!done && (bytesRead = fs6.readSync(fd, buf, 0, bufSize, null)) > 0) {
32383
33139
  const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
32384
33140
  partial2 = "";
32385
33141
  let lineStart = 0;
@@ -32514,10 +33270,10 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
32514
33270
  }
32515
33271
  return { content: resultLines.join("\n"), size: fileSize };
32516
33272
  } finally {
32517
- fs7.closeSync(fd);
33273
+ fs6.closeSync(fd);
32518
33274
  }
32519
33275
  }
32520
- function readFile(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
33276
+ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
32521
33277
  try {
32522
33278
  const result = resolveFilePath(relativePath);
32523
33279
  if (typeof result === "object") return result;
@@ -32525,17 +33281,17 @@ function readFile(relativePath, startLine, endLine, lineOffset, lineChunkSize =
32525
33281
  if (hasRange) {
32526
33282
  return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
32527
33283
  }
32528
- const stat = fs7.statSync(result);
32529
- const raw = fs7.readFileSync(result, "utf8");
33284
+ const stat2 = fs6.statSync(result);
33285
+ const raw = fs6.readFileSync(result, "utf8");
32530
33286
  const lines = raw.split(/\r?\n/);
32531
- return { content: raw, totalLines: lines.length, size: stat.size };
33287
+ return { content: raw, totalLines: lines.length, size: stat2.size };
32532
33288
  } catch (err) {
32533
33289
  return { error: err instanceof Error ? err.message : String(err) };
32534
33290
  }
32535
33291
  }
32536
33292
 
32537
33293
  // src/files/file-index.ts
32538
- import fs8 from "node:fs";
33294
+ import fs7 from "node:fs";
32539
33295
  import path14 from "node:path";
32540
33296
  import os2 from "node:os";
32541
33297
  import crypto2 from "node:crypto";
@@ -32582,23 +33338,23 @@ function binarySearch(arr, x) {
32582
33338
  function walkDir(dir, baseDir, out) {
32583
33339
  let names;
32584
33340
  try {
32585
- names = fs8.readdirSync(dir);
33341
+ names = fs7.readdirSync(dir);
32586
33342
  } catch {
32587
33343
  return;
32588
33344
  }
32589
33345
  for (const name of names) {
32590
33346
  if (name.startsWith(".")) continue;
32591
33347
  const full = path14.join(dir, name);
32592
- let stat;
33348
+ let stat2;
32593
33349
  try {
32594
- stat = fs8.statSync(full);
33350
+ stat2 = fs7.statSync(full);
32595
33351
  } catch {
32596
33352
  continue;
32597
33353
  }
32598
33354
  const relative4 = path14.relative(baseDir, full).replace(/\\/g, "/");
32599
- if (stat.isDirectory()) {
33355
+ if (stat2.isDirectory()) {
32600
33356
  walkDir(full, baseDir, out);
32601
- } else if (stat.isFile()) {
33357
+ } else if (stat2.isFile()) {
32602
33358
  out.push(relative4);
32603
33359
  }
32604
33360
  }
@@ -32622,8 +33378,8 @@ function buildFileIndex(cwd) {
32622
33378
  const data = { version: INDEX_VERSION, paths, trigramIndex };
32623
33379
  const indexPath = getIndexPath(resolved);
32624
33380
  try {
32625
- if (!fs8.existsSync(INDEX_DIR)) fs8.mkdirSync(INDEX_DIR, { recursive: true });
32626
- fs8.writeFileSync(indexPath, JSON.stringify(data), "utf8");
33381
+ if (!fs7.existsSync(INDEX_DIR)) fs7.mkdirSync(INDEX_DIR, { recursive: true });
33382
+ fs7.writeFileSync(indexPath, JSON.stringify(data), "utf8");
32627
33383
  } catch (e) {
32628
33384
  console.error("[file-index] Failed to write index:", e);
32629
33385
  }
@@ -32633,7 +33389,7 @@ function loadFileIndex(cwd) {
32633
33389
  const resolved = path14.resolve(cwd);
32634
33390
  const indexPath = getIndexPath(resolved);
32635
33391
  try {
32636
- const raw = fs8.readFileSync(indexPath, "utf8");
33392
+ const raw = fs7.readFileSync(indexPath, "utf8");
32637
33393
  const parsed = JSON.parse(raw);
32638
33394
  if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
32639
33395
  const obj = parsed;
@@ -32737,7 +33493,7 @@ function handleFileBrowserRequest(msg, socket) {
32737
33493
  const endLine = typeof msg.endLine === "number" ? msg.endLine : void 0;
32738
33494
  const lineOffset = typeof msg.lineOffset === "number" ? msg.lineOffset : void 0;
32739
33495
  const lineChunkSize = typeof msg.lineChunkSize === "number" ? msg.lineChunkSize : void 0;
32740
- const result = readFile(reqPath, startLine, endLine, lineOffset, lineChunkSize);
33496
+ const result = readFile2(reqPath, startLine, endLine, lineOffset, lineChunkSize);
32741
33497
  if ("error" in result) {
32742
33498
  sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
32743
33499
  } else {
@@ -32772,7 +33528,7 @@ function handleFileBrowserSearchMessage(msg, { getWs }) {
32772
33528
  }
32773
33529
 
32774
33530
  // src/skills/discover-local-agent-skills.ts
32775
- import fs9 from "node:fs";
33531
+ import fs8 from "node:fs";
32776
33532
  import path15 from "node:path";
32777
33533
  var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
32778
33534
  function discoverLocalSkills(cwd) {
@@ -32780,22 +33536,22 @@ function discoverLocalSkills(cwd) {
32780
33536
  const seenKeys = /* @__PURE__ */ new Set();
32781
33537
  for (const rel of SKILL_DISCOVERY_ROOTS) {
32782
33538
  const base = path15.join(cwd, rel);
32783
- if (!fs9.existsSync(base) || !fs9.statSync(base).isDirectory()) continue;
33539
+ if (!fs8.existsSync(base) || !fs8.statSync(base).isDirectory()) continue;
32784
33540
  let entries = [];
32785
33541
  try {
32786
- entries = fs9.readdirSync(base);
33542
+ entries = fs8.readdirSync(base);
32787
33543
  } catch {
32788
33544
  continue;
32789
33545
  }
32790
33546
  for (const name of entries) {
32791
33547
  const dir = path15.join(base, name);
32792
33548
  try {
32793
- if (!fs9.statSync(dir).isDirectory()) continue;
33549
+ if (!fs8.statSync(dir).isDirectory()) continue;
32794
33550
  } catch {
32795
33551
  continue;
32796
33552
  }
32797
33553
  const skillMd = path15.join(dir, "SKILL.md");
32798
- if (!fs9.existsSync(skillMd)) continue;
33554
+ if (!fs8.existsSync(skillMd)) continue;
32799
33555
  const key = `${rel}/${name}`;
32800
33556
  if (seenKeys.has(key)) continue;
32801
33557
  seenKeys.add(key);
@@ -32808,10 +33564,10 @@ function discoverSkillLayoutRoots(cwd) {
32808
33564
  const roots = [];
32809
33565
  for (const rel of SKILL_DISCOVERY_ROOTS) {
32810
33566
  const base = path15.join(cwd, rel);
32811
- if (!fs9.existsSync(base) || !fs9.statSync(base).isDirectory()) continue;
33567
+ if (!fs8.existsSync(base) || !fs8.statSync(base).isDirectory()) continue;
32812
33568
  let entries = [];
32813
33569
  try {
32814
- entries = fs9.readdirSync(base);
33570
+ entries = fs8.readdirSync(base);
32815
33571
  } catch {
32816
33572
  continue;
32817
33573
  }
@@ -32819,11 +33575,11 @@ function discoverSkillLayoutRoots(cwd) {
32819
33575
  for (const name of entries) {
32820
33576
  const dir = path15.join(base, name);
32821
33577
  try {
32822
- if (!fs9.statSync(dir).isDirectory()) continue;
33578
+ if (!fs8.statSync(dir).isDirectory()) continue;
32823
33579
  } catch {
32824
33580
  continue;
32825
33581
  }
32826
- if (!fs9.existsSync(path15.join(dir, "SKILL.md"))) continue;
33582
+ if (!fs8.existsSync(path15.join(dir, "SKILL.md"))) continue;
32827
33583
  const relPath = `${rel}/${name}`.replace(/\\/g, "/");
32828
33584
  skills2.push({ name, relPath });
32829
33585
  }
@@ -32843,7 +33599,7 @@ function handleSkillLayoutRequest(msg, deps) {
32843
33599
  }
32844
33600
 
32845
33601
  // src/skills/install-remote-skills.ts
32846
- import fs10 from "node:fs";
33602
+ import fs9 from "node:fs";
32847
33603
  import path16 from "node:path";
32848
33604
  function installRemoteSkills(cwd, targetDir, items) {
32849
33605
  const installed = [];
@@ -32859,11 +33615,11 @@ function installRemoteSkills(cwd, targetDir, items) {
32859
33615
  for (const f of item.files) {
32860
33616
  if (typeof f.path !== "string" || !f.text && !f.base64) continue;
32861
33617
  const dest = path16.join(skillDir, f.path);
32862
- fs10.mkdirSync(path16.dirname(dest), { recursive: true });
33618
+ fs9.mkdirSync(path16.dirname(dest), { recursive: true });
32863
33619
  if (f.text !== void 0) {
32864
- fs10.writeFileSync(dest, f.text, "utf8");
33620
+ fs9.writeFileSync(dest, f.text, "utf8");
32865
33621
  } else if (f.base64) {
32866
- fs10.writeFileSync(dest, Buffer.from(f.base64, "base64"));
33622
+ fs9.writeFileSync(dest, Buffer.from(f.base64, "base64"));
32867
33623
  }
32868
33624
  }
32869
33625
  installed.push({
@@ -32957,7 +33713,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
32957
33713
  };
32958
33714
 
32959
33715
  // src/bridge/routing/handlers/revert-turn-snapshot.ts
32960
- import * as fs11 from "node:fs";
33716
+ import * as fs10 from "node:fs";
32961
33717
  var handleRevertTurnSnapshotMessage = (msg, deps) => {
32962
33718
  const id = typeof msg.id === "string" ? msg.id : "";
32963
33719
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
@@ -32969,7 +33725,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
32969
33725
  if (!s) return;
32970
33726
  const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ?? getBridgeWorkspaceDirectory();
32971
33727
  const file2 = snapshotFilePath(agentBase, turnId);
32972
- if (!fs11.existsSync(file2)) {
33728
+ if (!fs10.existsSync(file2)) {
32973
33729
  sendWsMessage(s, {
32974
33730
  type: "revert_turn_snapshot_result",
32975
33731
  id,
@@ -33070,25 +33826,12 @@ function dispatchBridgeMessage(msg, deps) {
33070
33826
  }
33071
33827
 
33072
33828
  // 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
33829
  function handleBridgeMessage(data, deps) {
33081
33830
  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);
33831
+ if (!deps.getWs()) return;
33832
+ setImmediate(() => {
33833
+ dispatchBridgeMessage(msg, deps);
33834
+ });
33092
33835
  }
33093
33836
 
33094
33837
  // src/worktrees/session-worktree-manager.ts
@@ -33096,7 +33839,7 @@ import * as path20 from "node:path";
33096
33839
  import os4 from "node:os";
33097
33840
 
33098
33841
  // src/worktrees/prepare-new-session-worktrees.ts
33099
- import * as fs13 from "node:fs";
33842
+ import * as fs12 from "node:fs";
33100
33843
  import * as path18 from "node:path";
33101
33844
 
33102
33845
  // src/git/worktree-add.ts
@@ -33106,7 +33849,7 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
33106
33849
  }
33107
33850
 
33108
33851
  // src/worktrees/worktree-layout-file.ts
33109
- import * as fs12 from "node:fs";
33852
+ import * as fs11 from "node:fs";
33110
33853
  import * as path17 from "node:path";
33111
33854
  import os3 from "node:os";
33112
33855
  var LAYOUT_FILENAME = "worktree-launcher-layout.json";
@@ -33123,8 +33866,8 @@ function normalizeLoadedLayout(raw) {
33123
33866
  function loadWorktreeLayout() {
33124
33867
  try {
33125
33868
  const p = defaultWorktreeLayoutPath();
33126
- if (!fs12.existsSync(p)) return { launcherCwds: [] };
33127
- const raw = JSON.parse(fs12.readFileSync(p, "utf8"));
33869
+ if (!fs11.existsSync(p)) return { launcherCwds: [] };
33870
+ const raw = JSON.parse(fs11.readFileSync(p, "utf8"));
33128
33871
  return normalizeLoadedLayout(raw);
33129
33872
  } catch {
33130
33873
  return { launcherCwds: [] };
@@ -33133,8 +33876,8 @@ function loadWorktreeLayout() {
33133
33876
  function saveWorktreeLayout(layout) {
33134
33877
  try {
33135
33878
  const dir = path17.dirname(defaultWorktreeLayoutPath());
33136
- fs12.mkdirSync(dir, { recursive: true });
33137
- fs12.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
33879
+ fs11.mkdirSync(dir, { recursive: true });
33880
+ fs11.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
33138
33881
  } catch {
33139
33882
  }
33140
33883
  }
@@ -33171,13 +33914,13 @@ async function prepareNewSessionWorktrees(options) {
33171
33914
  }
33172
33915
  const branch = `session-${sessionId}`;
33173
33916
  const worktreePaths = [];
33174
- fs13.mkdirSync(agentMirrorRoot, { recursive: true });
33917
+ fs12.mkdirSync(agentMirrorRoot, { recursive: true });
33175
33918
  for (const repo of repos) {
33176
33919
  let rel = path18.relative(launcherResolved, repo.absolutePath);
33177
33920
  if (rel.startsWith("..") || path18.isAbsolute(rel)) continue;
33178
33921
  const relNorm = rel === "" ? "." : rel;
33179
33922
  const wtPath = path18.join(agentMirrorRoot, relNorm, sessionId);
33180
- fs13.mkdirSync(path18.dirname(wtPath), { recursive: true });
33923
+ fs12.mkdirSync(path18.dirname(wtPath), { recursive: true });
33181
33924
  try {
33182
33925
  await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
33183
33926
  log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}).`);
@@ -33214,18 +33957,18 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
33214
33957
  }
33215
33958
 
33216
33959
  // src/worktrees/remove-session-worktrees.ts
33217
- import * as fs16 from "node:fs";
33960
+ import * as fs15 from "node:fs";
33218
33961
 
33219
33962
  // src/git/worktree-remove.ts
33220
- import * as fs15 from "node:fs";
33963
+ import * as fs14 from "node:fs";
33221
33964
 
33222
33965
  // src/git/resolve-main-repo-from-git-file.ts
33223
- import * as fs14 from "node:fs";
33966
+ import * as fs13 from "node:fs";
33224
33967
  import * as path19 from "node:path";
33225
33968
  function resolveMainRepoFromWorktreeGitFile(wt) {
33226
33969
  const gitDirFile = path19.join(wt, ".git");
33227
- if (!fs14.existsSync(gitDirFile) || !fs14.statSync(gitDirFile).isFile()) return "";
33228
- const first2 = fs14.readFileSync(gitDirFile, "utf8").trim();
33970
+ if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
33971
+ const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
33229
33972
  const m = first2.match(/^gitdir:\s*(.+)$/im);
33230
33973
  if (!m) return "";
33231
33974
  const gitWorktreePath = path19.resolve(wt, m[1].trim());
@@ -33239,7 +33982,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
33239
33982
  if (mainRepo) {
33240
33983
  await simpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
33241
33984
  } else {
33242
- fs15.rmSync(worktreePath, { recursive: true, force: true });
33985
+ fs14.rmSync(worktreePath, { recursive: true, force: true });
33243
33986
  }
33244
33987
  }
33245
33988
 
@@ -33252,7 +33995,7 @@ async function removeSessionWorktrees(paths, log2) {
33252
33995
  } catch (e) {
33253
33996
  log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
33254
33997
  try {
33255
- fs16.rmSync(wt, { recursive: true, force: true });
33998
+ fs15.rmSync(wt, { recursive: true, force: true });
33256
33999
  } catch {
33257
34000
  }
33258
34001
  }
@@ -33524,7 +34267,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
33524
34267
  }
33525
34268
 
33526
34269
  // src/dev-servers/process/wire-dev-server-child-process.ts
33527
- import fs17 from "node:fs";
34270
+ import fs16 from "node:fs";
33528
34271
 
33529
34272
  // src/dev-servers/manager/forward-pipe.ts
33530
34273
  function forwardChildPipe(childReadable, terminal, onData) {
@@ -33560,7 +34303,7 @@ function wireDevServerChildProcess(d) {
33560
34303
  d.setPollInterval(void 0);
33561
34304
  return;
33562
34305
  }
33563
- fs17.readFile(d.mergedLogPath, (err, buf) => {
34306
+ fs16.readFile(d.mergedLogPath, (err, buf) => {
33564
34307
  if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
33565
34308
  if (buf.length <= d.mergedReadPos.value) return;
33566
34309
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
@@ -33598,7 +34341,7 @@ ${errTail}` : ""}`);
33598
34341
  d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
33599
34342
  };
33600
34343
  if (mergedPath) {
33601
- fs17.readFile(mergedPath, (err, buf) => {
34344
+ fs16.readFile(mergedPath, (err, buf) => {
33602
34345
  if (!err && buf.length > d.mergedReadPos.value) {
33603
34346
  const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
33604
34347
  if (chunk.length > 0) {
@@ -33700,13 +34443,13 @@ function parseDevServerDefs(servers) {
33700
34443
  }
33701
34444
 
33702
34445
  // src/dev-servers/manager/shell-spawn/utils.ts
33703
- import fs18 from "node:fs";
34446
+ import fs17 from "node:fs";
33704
34447
  function isSpawnEbadf(e) {
33705
34448
  return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
33706
34449
  }
33707
34450
  function rmDirQuiet(dir) {
33708
34451
  try {
33709
- fs18.rmSync(dir, { recursive: true, force: true });
34452
+ fs17.rmSync(dir, { recursive: true, force: true });
33710
34453
  } catch {
33711
34454
  }
33712
34455
  }
@@ -33714,7 +34457,7 @@ var cachedDevNullReadFd;
33714
34457
  function devNullReadFd() {
33715
34458
  if (cachedDevNullReadFd === void 0) {
33716
34459
  const devPath = process.platform === "win32" ? "nul" : "/dev/null";
33717
- cachedDevNullReadFd = fs18.openSync(devPath, "r");
34460
+ cachedDevNullReadFd = fs17.openSync(devPath, "r");
33718
34461
  }
33719
34462
  return cachedDevNullReadFd;
33720
34463
  }
@@ -33788,15 +34531,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
33788
34531
 
33789
34532
  // src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
33790
34533
  import { spawn as spawn7 } from "node:child_process";
33791
- import fs19 from "node:fs";
34534
+ import fs18 from "node:fs";
33792
34535
  import { tmpdir } from "node:os";
33793
34536
  import path22 from "node:path";
33794
34537
  function trySpawnMergedLogFile(command, env, cwd, signal) {
33795
- const tmpRoot = fs19.mkdtempSync(path22.join(tmpdir(), "ba-devsrv-log-"));
34538
+ const tmpRoot = fs18.mkdtempSync(path22.join(tmpdir(), "ba-devsrv-log-"));
33796
34539
  const logPath = path22.join(tmpRoot, "combined.log");
33797
34540
  let logFd;
33798
34541
  try {
33799
- logFd = fs19.openSync(logPath, "a");
34542
+ logFd = fs18.openSync(logPath, "a");
33800
34543
  } catch {
33801
34544
  rmDirQuiet(tmpRoot);
33802
34545
  return null;
@@ -33815,7 +34558,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33815
34558
  } else {
33816
34559
  proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
33817
34560
  }
33818
- fs19.closeSync(logFd);
34561
+ fs18.closeSync(logFd);
33819
34562
  return {
33820
34563
  proc,
33821
34564
  pipedStdoutStderr: true,
@@ -33824,7 +34567,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33824
34567
  };
33825
34568
  } catch (e) {
33826
34569
  try {
33827
- fs19.closeSync(logFd);
34570
+ fs18.closeSync(logFd);
33828
34571
  } catch {
33829
34572
  }
33830
34573
  rmDirQuiet(tmpRoot);
@@ -33835,22 +34578,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
33835
34578
 
33836
34579
  // src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
33837
34580
  import { spawn as spawn8 } from "node:child_process";
33838
- import fs20 from "node:fs";
34581
+ import fs19 from "node:fs";
33839
34582
  import { tmpdir as tmpdir2 } from "node:os";
33840
34583
  import path23 from "node:path";
33841
34584
  function shSingleQuote(s) {
33842
34585
  return `'${s.replace(/'/g, `'\\''`)}'`;
33843
34586
  }
33844
34587
  function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
33845
- const tmpRoot = fs20.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
34588
+ const tmpRoot = fs19.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
33846
34589
  const logPath = path23.join(tmpRoot, "combined.log");
33847
34590
  const innerPath = path23.join(tmpRoot, "_cmd.sh");
33848
34591
  const runnerPath = path23.join(tmpRoot, "_run.sh");
33849
34592
  try {
33850
- fs20.writeFileSync(innerPath, `#!/bin/sh
34593
+ fs19.writeFileSync(innerPath, `#!/bin/sh
33851
34594
  ${command}
33852
34595
  `);
33853
- fs20.writeFileSync(
34596
+ fs19.writeFileSync(
33854
34597
  runnerPath,
33855
34598
  `#!/bin/sh
33856
34599
  cd ${shSingleQuote(cwd)}
@@ -33876,13 +34619,13 @@ cd ${shSingleQuote(cwd)}
33876
34619
  }
33877
34620
  }
33878
34621
  function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
33879
- const tmpRoot = fs20.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
34622
+ const tmpRoot = fs19.mkdtempSync(path23.join(tmpdir2(), "ba-devsrv-sh-"));
33880
34623
  const logPath = path23.join(tmpRoot, "combined.log");
33881
34624
  const runnerPath = path23.join(tmpRoot, "_run.bat");
33882
34625
  const q = (p) => `"${p.replace(/"/g, '""')}"`;
33883
34626
  const com = process.env.ComSpec || "cmd.exe";
33884
34627
  try {
33885
- fs20.writeFileSync(
34628
+ fs19.writeFileSync(
33886
34629
  runnerPath,
33887
34630
  `@ECHO OFF\r
33888
34631
  CD /D ${q(cwd)}\r
@@ -34236,7 +34979,9 @@ var DevServerManager = class {
34236
34979
  async shutdownAllGraceful() {
34237
34980
  const pairs = [...this.processes.entries()];
34238
34981
  if (pairs.length === 0) return;
34239
- this.log(`[dev-server] Stopping ${pairs.length} dev server process(es) (bridge shutting down)\u2026`);
34982
+ this.log(
34983
+ `[dev-server] Stopping ${pairs.length} local dev server process${pairs.length === 1 ? "" : "es"}\u2026`
34984
+ );
34240
34985
  await Promise.all(pairs.map(([serverId, proc]) => this.gracefulTerminateOrUnknown(serverId, proc)));
34241
34986
  }
34242
34987
  async gracefulTerminateOrUnknown(serverId, proc) {
@@ -34510,9 +35255,10 @@ var FIREHOSE_CLIENT_PING_MS = 25e3;
34510
35255
  function connectFirehose(options) {
34511
35256
  const { firehoseServerUrl, workspaceId, bridgeName, proxyPorts, log: log2, devServerManager, onOpen, onClose } = options;
34512
35257
  const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
34513
- const wsOptions = { perMessageDeflate: false };
35258
+ applyCliOutboundNetworkPreferences();
35259
+ const wsOptions = { perMessageDeflate: false, family: 4 };
34514
35260
  if (wsUrl.startsWith("wss://")) {
34515
- wsOptions.agent = new https2.Agent({ rejectUnauthorized: false });
35261
+ wsOptions.agent = new https2.Agent({ rejectUnauthorized: false, family: 4 });
34516
35262
  }
34517
35263
  const ws = new wrapper_default(wsUrl, wsOptions);
34518
35264
  let clientPingTimer = null;
@@ -34548,16 +35294,14 @@ function connectFirehose(options) {
34548
35294
  sendWsMessage(ws, { type: "identify", workspaceId, bridgeName, proxyPorts });
34549
35295
  });
34550
35296
  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
- });
35297
+ if (Buffer.isBuffer(raw) && tryConsumeBinaryProxyBody(raw, deps)) {
35298
+ return;
35299
+ }
35300
+ try {
35301
+ const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
35302
+ dispatchFirehoseJsonMessage(JSON.parse(text), deps);
35303
+ } catch {
35304
+ }
34561
35305
  });
34562
35306
  ws.on("close", (code, reason) => {
34563
35307
  clearClientPing();
@@ -34603,6 +35347,9 @@ function createOnBridgeIdentified(opts) {
34603
35347
  function attachFirehose(params) {
34604
35348
  state.lastFirehoseParams = params;
34605
35349
  clearFirehoseReconnectTimer();
35350
+ if (state.firehoseReconnectAttempt === 0) {
35351
+ logFn("Connecting to preview tunnel (local HTTP proxy and dev logs)\u2026");
35352
+ }
34606
35353
  state.firehoseGeneration += 1;
34607
35354
  const myGen = state.firehoseGeneration;
34608
35355
  if (state.firehoseHandle) {
@@ -34621,8 +35368,8 @@ function createOnBridgeIdentified(opts) {
34621
35368
  clearFirehoseReconnectQuietOnOpen({ firehoseQuiet: state.firehoseQuiet }, logFn);
34622
35369
  const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
34623
35370
  state.firehoseReconnectAttempt = 0;
34624
- if (logOpenAsFirehoseReconnect) {
34625
- logFn("[Proxy and log service] reconnected.");
35371
+ if (!logOpenAsFirehoseReconnect) {
35372
+ logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
34626
35373
  }
34627
35374
  },
34628
35375
  onClose: (code, reason) => {
@@ -34690,47 +35437,19 @@ function createOnBridgeIdentified(opts) {
34690
35437
  };
34691
35438
  }
34692
35439
 
34693
- // src/dev-servers/detect-local-agent-types.ts
34694
- import { execFile as execFile4 } from "node:child_process";
34695
- import { promisify as promisify4 } from "node:util";
34696
- var execFileAsync4 = promisify4(execFile4);
34697
- var CHECKS = {
34698
- "cursor-cli": async () => {
34699
- try {
34700
- await execFileAsync4("which", ["agent"], { timeout: 4e3 });
34701
- return true;
34702
- } catch {
34703
- return false;
34704
- }
34705
- },
34706
- "codex-acp": async () => {
34707
- try {
34708
- await execFileAsync4("which", ["codex"], { timeout: 4e3 });
34709
- return true;
34710
- } catch {
34711
- return false;
34712
- }
34713
- },
34714
- "claude-code": async () => {
34715
- try {
34716
- await execFileAsync4("which", ["claude"], { timeout: 4e3 });
34717
- return true;
34718
- } catch {
34719
- try {
34720
- await execFileAsync4("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], { timeout: 25e3 });
34721
- return true;
34722
- } catch {
34723
- return false;
34724
- }
34725
- }
34726
- }
34727
- };
35440
+ // src/acp/detect-local-agent-types.ts
35441
+ var LOCAL_AGENT_ACP_MODULES = [
35442
+ cursor_acp_client_exports,
35443
+ codex_acp_client_exports,
35444
+ kiro_acp_client_exports,
35445
+ claude_code_acp_client_exports
35446
+ ];
34728
35447
  async function detectLocalAgentTypes() {
34729
35448
  try {
34730
35449
  const out = [];
34731
- for (const [type, check2] of Object.entries(CHECKS)) {
35450
+ for (const mod of LOCAL_AGENT_ACP_MODULES) {
34732
35451
  try {
34733
- if (await check2()) out.push(type);
35452
+ if (await mod.detectLocalAgentPresence()) out.push(mod.BACKEND_LOCAL_AGENT_TYPE);
34734
35453
  } catch {
34735
35454
  }
34736
35455
  }
@@ -34820,8 +35539,8 @@ async function createBridgeConnection(options) {
34820
35539
  clearMainBridgeReconnectQuietOnOpen(state, logFn);
34821
35540
  state.reconnectAttempt = 0;
34822
35541
  state.logBridgeOpenAsReconnect = false;
34823
- if (logOpenAsPostRefreshReconnect) {
34824
- logFn("[Bridge service] reconnected.");
35542
+ if (!logOpenAsPostRefreshReconnect) {
35543
+ logFn("Connected to bridge service.");
34825
35544
  }
34826
35545
  const socket = getWs();
34827
35546
  if (socket) {
@@ -34860,6 +35579,9 @@ async function createBridgeConnection(options) {
34860
35579
  clearTimeout(state.reconnectTimeout);
34861
35580
  state.reconnectTimeout = null;
34862
35581
  }
35582
+ if (state.reconnectAttempt === 0) {
35583
+ logFn("Connecting to bridge service\u2026");
35584
+ }
34863
35585
  const prev = state.currentWs;
34864
35586
  if (prev) {
34865
35587
  prev.removeAllListeners();
@@ -34932,15 +35654,17 @@ async function runBridge(options) {
34932
35654
  onAuth: (_auth) => {
34933
35655
  }
34934
35656
  });
34935
- const onSignal2 = (signal) => {
34936
- logImmediate(`Received ${signal}; shutting down\u2026`);
35657
+ const onSignal2 = (kind) => {
35658
+ logImmediate(
35659
+ kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
35660
+ );
34937
35661
  setImmediate(() => {
34938
35662
  handle2.close();
34939
35663
  process.exit(0);
34940
35664
  });
34941
35665
  };
34942
- const onSigInt2 = () => onSignal2("SIGINT");
34943
- const onSigTerm2 = () => onSignal2("SIGTERM");
35666
+ const onSigInt2 = () => onSignal2("interrupt");
35667
+ const onSigTerm2 = () => onSignal2("stop");
34944
35668
  process.on("SIGINT", onSigInt2);
34945
35669
  process.on("SIGTERM", onSigTerm2);
34946
35670
  const auth = await handle2.authPromise;
@@ -34989,16 +35713,18 @@ async function runBridge(options) {
34989
35713
  });
34990
35714
  }
34991
35715
  });
34992
- const onSignal = (signal) => {
34993
- logImmediate(`Received ${signal}; shutting down\u2026`);
35716
+ const onSignal = (kind) => {
35717
+ logImmediate(
35718
+ kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
35719
+ );
34994
35720
  setImmediate(() => {
34995
35721
  void handle.close().then(() => {
34996
35722
  process.exit(0);
34997
35723
  });
34998
35724
  });
34999
35725
  };
35000
- const onSigInt = () => onSignal("SIGINT");
35001
- const onSigTerm = () => onSignal("SIGTERM");
35726
+ const onSigInt = () => onSignal("interrupt");
35727
+ const onSigTerm = () => onSignal("stop");
35002
35728
  process.on("SIGINT", onSigInt);
35003
35729
  process.on("SIGTERM", onSigTerm);
35004
35730
  }
@@ -35029,7 +35755,7 @@ async function main() {
35029
35755
  if (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim()) {
35030
35756
  const resolvedCwd = path24.resolve(process.cwd(), opts.cwd.trim());
35031
35757
  try {
35032
- const st = fs21.statSync(resolvedCwd);
35758
+ const st = fs20.statSync(resolvedCwd);
35033
35759
  if (!st.isDirectory()) {
35034
35760
  console.error(`--cwd is not a directory: ${resolvedCwd}`);
35035
35761
  process.exit(1);