@buildautomaton/cli 0.1.6 → 0.1.8

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
@@ -30318,6 +30318,284 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
30318
30318
  say("Shutdown complete.");
30319
30319
  }
30320
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)));
30597
+ }
30598
+
30321
30599
  // src/git/session-git-queue.ts
30322
30600
  import { execFile as execFile2 } from "node:child_process";
30323
30601
  import { readFile, stat } from "node:fs/promises";
@@ -30520,11 +30798,20 @@ async function sendPromptToAgent(options) {
30520
30798
  promptId,
30521
30799
  sessionId,
30522
30800
  runId,
30801
+ agentType,
30523
30802
  agentCwd,
30524
30803
  sendResult,
30525
30804
  sendSessionUpdate,
30526
30805
  log: log2
30527
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
+ }
30528
30815
  try {
30529
30816
  const result = await handle.sendPrompt(promptText, {});
30530
30817
  if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
@@ -30536,12 +30823,14 @@ async function sendPromptToAgent(options) {
30536
30823
  log: log2
30537
30824
  });
30538
30825
  }
30826
+ const errStr = typeof result.error === "string" ? result.error : void 0;
30539
30827
  sendResult({
30540
30828
  type: "prompt_result",
30541
30829
  id: promptId,
30542
30830
  ...sessionId ? { sessionId } : {},
30543
30831
  ...runId ? { runId } : {},
30544
- ...result
30832
+ ...result,
30833
+ ...augmentAuthFields(errStr)
30545
30834
  });
30546
30835
  if (!result.success) {
30547
30836
  log2(`[Agent] ${result.error ?? "Error"}`);
@@ -30555,7 +30844,8 @@ async function sendPromptToAgent(options) {
30555
30844
  ...sessionId ? { sessionId } : {},
30556
30845
  ...runId ? { runId } : {},
30557
30846
  success: false,
30558
- error: errMsg
30847
+ error: errMsg,
30848
+ ...augmentAuthFields(errMsg)
30559
30849
  });
30560
30850
  }
30561
30851
  }
@@ -30574,6 +30864,30 @@ function errorMessage(err) {
30574
30864
  return String(err);
30575
30865
  }
30576
30866
 
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
+
30577
30891
  // src/acp/clients/sdk-stdio-acp-client.ts
30578
30892
  import { spawn as spawn2 } from "node:child_process";
30579
30893
  import { mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
@@ -30644,6 +30958,83 @@ function toDisplayPathRelativeToCwd(cwd, absolutePath) {
30644
30958
  return rel.split(path6.sep).join("/");
30645
30959
  }
30646
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
+
30647
31038
  // src/acp/clients/sdk-stdio-acp-client.ts
30648
31039
  function formatSpawnError(err, command) {
30649
31040
  if (err.code === "ENOENT") {
@@ -30651,14 +31042,6 @@ function formatSpawnError(err, command) {
30651
31042
  }
30652
31043
  return err.message || String(err);
30653
31044
  }
30654
- function toErrorMessage(err) {
30655
- if (err instanceof Error) return err.message;
30656
- if (err != null && typeof err === "object" && "message" in err)
30657
- return String(err.message);
30658
- if (typeof err === "string") return err;
30659
- if (err != null && typeof err === "object") return JSON.stringify(err);
30660
- return String(err);
30661
- }
30662
31045
  function sliceFileContentRange(content, line, limit) {
30663
31046
  if (line == null && limit == null) return content;
30664
31047
  const lines = content.split("\n");
@@ -30674,7 +31057,9 @@ async function createSdkStdioAcpClient(options) {
30674
31057
  const {
30675
31058
  command,
30676
31059
  cwd = getBridgeWorkspaceDirectory(),
31060
+ backendAgentType,
30677
31061
  onSessionUpdate,
31062
+ onRequest,
30678
31063
  onFileChange,
30679
31064
  killSubprocessAfterCancelMs,
30680
31065
  onAgentSubprocessExit
@@ -30682,30 +31067,67 @@ async function createSdkStdioAcpClient(options) {
30682
31067
  const isWindows = process.platform === "win32";
30683
31068
  const child = spawn2(command[0], command.slice(1), {
30684
31069
  cwd,
30685
- stdio: ["pipe", "pipe", "inherit"],
31070
+ stdio: ["pipe", "pipe", "pipe"],
30686
31071
  env: process.env,
30687
31072
  shell: isWindows
30688
31073
  });
31074
+ const stderrCapture = createStderrCapture(child);
30689
31075
  child.once("close", (code, signal) => {
30690
31076
  onAgentSubprocessExit?.({ code, signal });
30691
31077
  });
30692
31078
  return new Promise((resolve15, reject) => {
31079
+ let initSettled = false;
31080
+ const settleReject = (err) => {
31081
+ if (initSettled) return;
31082
+ initSettled = true;
31083
+ try {
31084
+ child.kill();
31085
+ } catch {
31086
+ }
31087
+ reject(err);
31088
+ };
31089
+ const settleResolve = (handle) => {
31090
+ if (initSettled) return;
31091
+ initSettled = true;
31092
+ resolve15(handle);
31093
+ };
30693
31094
  child.on("error", (err) => {
30694
- child.kill();
30695
- reject(new Error(formatSpawnError(err, command[0])));
31095
+ settleReject(new Error(formatSpawnError(err, command[0])));
31096
+ });
31097
+ child.stderr?.on("data", (chunk) => {
31098
+ stderrCapture.append(chunk);
31099
+ if (initSettled) return;
31100
+ const stderrText = stderrCapture.getText();
31101
+ if (backendAgentType && stderrText.trim() && localAgentErrorSuggestsAuth(backendAgentType, stderrText)) {
31102
+ settleReject(new Error(stderrText.trim()));
31103
+ }
30696
31104
  });
30697
31105
  (async () => {
30698
31106
  try {
30699
31107
  const writable = Writable.toWeb(child.stdin);
30700
31108
  const readable = Readable.toWeb(child.stdout);
30701
31109
  const stream = ndJsonStream2(writable, readable);
31110
+ const extNotification = createSdkStdioExtNotificationHandler({
31111
+ backendAgentType,
31112
+ onSessionUpdate
31113
+ });
31114
+ let permissionSeq = 0;
31115
+ const pendingPermissionResolvers = /* @__PURE__ */ new Map();
30702
31116
  const client = (_agent) => ({
30703
31117
  async requestPermission(params) {
30704
- const opt = params?.options?.[0];
30705
- if (opt && typeof opt.optionId === "string") {
30706
- return { outcome: { outcome: "selected", optionId: opt.optionId } };
31118
+ const requestId = `perm-${++permissionSeq}`;
31119
+ const paramsRecord = params != null && typeof params === "object" ? params : {};
31120
+ try {
31121
+ onRequest?.({
31122
+ requestId,
31123
+ method: "session/request_permission",
31124
+ params: paramsRecord
31125
+ });
31126
+ } catch {
30707
31127
  }
30708
- return { outcome: { outcome: "cancelled" } };
31128
+ return await new Promise((resolve16) => {
31129
+ pendingPermissionResolvers.set(requestId, resolve16);
31130
+ });
30709
31131
  },
30710
31132
  async readTextFile(params) {
30711
31133
  const abs = resolveSafePathUnderCwd(cwd, params.path);
@@ -30737,6 +31159,9 @@ async function createSdkStdioAcpClient(options) {
30737
31159
  },
30738
31160
  async sessionUpdate(params) {
30739
31161
  onSessionUpdate?.(bridgePayloadFromSdkSessionNotification(params));
31162
+ },
31163
+ async extNotification(method, params) {
31164
+ await extNotification(method, params);
30740
31165
  }
30741
31166
  });
30742
31167
  const connection = new ClientSideConnection2(client, stream);
@@ -30752,7 +31177,7 @@ async function createSdkStdioAcpClient(options) {
30752
31177
  });
30753
31178
  const newSessionRes = await connection.newSession({ cwd, mcpServers: [] });
30754
31179
  const sessionId = newSessionRes.sessionId;
30755
- resolve15({
31180
+ settleResolve({
30756
31181
  sessionId,
30757
31182
  async sendPrompt(prompt, _options) {
30758
31183
  try {
@@ -30760,22 +31185,59 @@ async function createSdkStdioAcpClient(options) {
30760
31185
  sessionId,
30761
31186
  prompt: [{ type: "text", text: prompt }]
30762
31187
  });
31188
+ await new Promise((r2) => setImmediate(r2));
30763
31189
  const r = response;
30764
- const cancelled = (r?.stopReason ?? "").toLowerCase() === "cancelled";
31190
+ const stopReason = (r?.stopReason ?? "").toLowerCase();
31191
+ const cancelled = stopReason === "cancelled";
31192
+ const refusal = stopReason === "refusal";
31193
+ const stderrAfter = stderrCapture.getText();
31194
+ const agentType = backendAgentType ?? null;
31195
+ const stderrEvaluated = Boolean(stderrAfter && agentType);
31196
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
31197
+ if (cancelled) {
31198
+ return {
31199
+ success: false,
31200
+ stopReason: r?.stopReason,
31201
+ output: r?.output,
31202
+ error: mergeErrorWithStderr("Stopped by user", stderrAfter)
31203
+ };
31204
+ }
31205
+ if (refusal) {
31206
+ return {
31207
+ success: false,
31208
+ stopReason: r?.stopReason,
31209
+ output: r?.output,
31210
+ error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
31211
+ };
31212
+ }
31213
+ if (stderrSuggestsAuth) {
31214
+ return {
31215
+ success: false,
31216
+ stopReason: r?.stopReason,
31217
+ output: r?.output,
31218
+ error: stderrAfter
31219
+ };
31220
+ }
30765
31221
  return {
30766
- success: !cancelled,
31222
+ success: true,
30767
31223
  stopReason: r?.stopReason,
30768
- output: r?.output,
30769
- ...cancelled ? { error: "Stopped by user" } : {}
31224
+ output: r?.output
30770
31225
  };
30771
31226
  } catch (err) {
31227
+ await new Promise((r) => setImmediate(r));
31228
+ const stderrAfter = stderrCapture.getText();
31229
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
30772
31230
  return {
30773
31231
  success: false,
30774
- error: err instanceof Error ? err.message : String(err)
31232
+ error: merged
30775
31233
  };
30776
31234
  }
30777
31235
  },
30778
31236
  async cancel() {
31237
+ for (const [id, resolve16] of [...pendingPermissionResolvers.entries()]) {
31238
+ pendingPermissionResolvers.delete(id);
31239
+ resolve16({ outcome: { outcome: "cancelled" } });
31240
+ }
30779
31241
  try {
30780
31242
  await connection.cancel({ sessionId });
30781
31243
  } catch {
@@ -30789,36 +31251,42 @@ async function createSdkStdioAcpClient(options) {
30789
31251
  t.unref?.();
30790
31252
  }
30791
31253
  },
30792
- resolveRequest() {
31254
+ resolveRequest(requestId, result) {
31255
+ const resolve16 = pendingPermissionResolvers.get(requestId);
31256
+ if (!resolve16) return;
31257
+ pendingPermissionResolvers.delete(requestId);
31258
+ resolve16(result);
30793
31259
  },
30794
31260
  disconnect() {
30795
31261
  child.kill();
30796
31262
  }
30797
31263
  });
30798
31264
  } catch (err) {
30799
- child.kill();
30800
- reject(new Error(toErrorMessage(err)));
31265
+ if (initSettled) return;
31266
+ try {
31267
+ child.kill();
31268
+ } catch {
31269
+ }
31270
+ const stderrText = stderrCapture.getText();
31271
+ const base = formatJsonRpcStyleError(err);
31272
+ settleReject(new Error(mergeErrorWithStderr(base, stderrText)));
30801
31273
  }
30802
31274
  })();
30803
31275
  });
30804
31276
  }
30805
31277
 
30806
- // src/acp/clients/codex-acp-client.ts
30807
- var DEFAULT_CODEX_ACP_COMMAND = ["npx", "--yes", "@zed-industries/codex-acp"];
30808
- function isCodexAcpCommand(command) {
30809
- const i = command.indexOf("@zed-industries/codex-acp");
30810
- return i >= 0 && (i === 0 || command[i - 1] === "npx" || command[i - 1] === "bunx");
30811
- }
30812
- function buildCodexAcpSpawnCommand(base, _sessionMode) {
30813
- return [...base];
30814
- }
30815
- async function createCodexAcpClient(options) {
30816
- const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
30817
- const command = buildCodexAcpSpawnCommand(base, options.sessionMode);
30818
- return createSdkStdioAcpClient({ ...options, command });
30819
- }
30820
-
30821
31278
  // src/acp/clients/claude-code-acp-client.ts
31279
+ var execFileAsync4 = promisify4(execFile4);
31280
+ var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
31281
+ async function detectLocalAgentPresence() {
31282
+ if (await isCommandOnPath("claude")) return true;
31283
+ try {
31284
+ await execFileAsync4("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], { timeout: 25e3 });
31285
+ return true;
31286
+ } catch {
31287
+ return false;
31288
+ }
31289
+ }
30822
31290
  function buildClaudeCodeAcpSpawnCommand(base, sessionMode) {
30823
31291
  if (!sessionMode) return [...base];
30824
31292
  const m = sessionMode.trim();
@@ -30835,7 +31303,42 @@ async function createClaudeCodeAcpClient(options) {
30835
31303
  });
30836
31304
  }
30837
31305
 
31306
+ // src/acp/clients/codex-acp-client.ts
31307
+ var codex_acp_client_exports = {};
31308
+ __export(codex_acp_client_exports, {
31309
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE2,
31310
+ DEFAULT_CODEX_ACP_COMMAND: () => DEFAULT_CODEX_ACP_COMMAND,
31311
+ buildCodexAcpSpawnCommand: () => buildCodexAcpSpawnCommand,
31312
+ createCodexAcpClient: () => createCodexAcpClient,
31313
+ detectLocalAgentPresence: () => detectLocalAgentPresence2,
31314
+ isCodexAcpCommand: () => isCodexAcpCommand
31315
+ });
31316
+ var BACKEND_LOCAL_AGENT_TYPE2 = "codex-acp";
31317
+ async function detectLocalAgentPresence2() {
31318
+ return isCommandOnPath("codex");
31319
+ }
31320
+ var DEFAULT_CODEX_ACP_COMMAND = ["npx", "--yes", "@zed-industries/codex-acp"];
31321
+ function isCodexAcpCommand(command) {
31322
+ const i = command.indexOf("@zed-industries/codex-acp");
31323
+ return i >= 0 && (i === 0 || command[i - 1] === "npx" || command[i - 1] === "bunx");
31324
+ }
31325
+ function buildCodexAcpSpawnCommand(base, _sessionMode) {
31326
+ return [...base];
31327
+ }
31328
+ async function createCodexAcpClient(options) {
31329
+ const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
31330
+ const command = buildCodexAcpSpawnCommand(base, options.sessionMode);
31331
+ return createSdkStdioAcpClient({ ...options, command });
31332
+ }
31333
+
30838
31334
  // src/acp/clients/cursor-acp-client.ts
31335
+ var cursor_acp_client_exports = {};
31336
+ __export(cursor_acp_client_exports, {
31337
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
31338
+ buildCursorAcpSpawnCommand: () => buildCursorAcpSpawnCommand,
31339
+ createCursorAcpClient: () => createCursorAcpClient,
31340
+ detectLocalAgentPresence: () => detectLocalAgentPresence3
31341
+ });
30839
31342
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
30840
31343
  import { dirname as dirname2 } from "node:path";
30841
31344
  import { spawn as spawn3 } from "node:child_process";
@@ -30886,15 +31389,23 @@ function buildCursorAcpSpawnCommand(base, sessionMode) {
30886
31389
  }
30887
31390
  async function createCursorAcpClient(options) {
30888
31391
  const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
30889
- const { cwd = getBridgeWorkspaceDirectory(), onSessionUpdate, onRequest, onFileChange } = options;
31392
+ const {
31393
+ cwd = getBridgeWorkspaceDirectory(),
31394
+ backendAgentType,
31395
+ onSessionUpdate,
31396
+ onRequest,
31397
+ onFileChange
31398
+ } = options;
30890
31399
  const dbgFs = process.env.BUILDAMATON_DEBUG_ACP_FS === "1";
30891
31400
  const isWindows = process.platform === "win32";
30892
31401
  const child = spawn3(command[0], command.slice(1), {
30893
31402
  cwd,
30894
- stdio: ["pipe", "pipe", "inherit"],
31403
+ stdio: ["pipe", "pipe", "pipe"],
30895
31404
  env: process.env,
30896
31405
  shell: isWindows
30897
31406
  });
31407
+ const stderrCapture = createStderrCapture(child);
31408
+ child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
30898
31409
  return new Promise((resolve15, reject) => {
30899
31410
  child.on("error", (err) => {
30900
31411
  child.kill();
@@ -30961,7 +31472,13 @@ async function createCursorAcpClient(options) {
30961
31472
  return;
30962
31473
  }
30963
31474
  if (method === "session/request_permission" && typeof id === "number") {
30964
- respond(id, { outcome: { outcome: "selected", optionId: "allow-once" } });
31475
+ const params = msg.params ?? {};
31476
+ pendingRequests.set(id, { method, params });
31477
+ onRequest?.({
31478
+ requestId: String(id),
31479
+ method,
31480
+ params
31481
+ });
30965
31482
  return;
30966
31483
  }
30967
31484
  if (typeof id === "number" && method) {
@@ -31058,8 +31575,15 @@ async function createCursorAcpClient(options) {
31058
31575
  return new Promise((res, rej) => {
31059
31576
  child.stdin.write(line, (err) => err ? rej(err) : res());
31060
31577
  });
31578
+ }, cancelPendingPermissionRequests2 = function() {
31579
+ for (const [reqId, pending2] of [...pendingRequests.entries()]) {
31580
+ if (pending2.method === "session/request_permission") {
31581
+ respond(reqId, { outcome: { outcome: "cancelled" } });
31582
+ pendingRequests.delete(reqId);
31583
+ }
31584
+ }
31061
31585
  };
31062
- var sendSessionCancelNotification = sendSessionCancelNotification2;
31586
+ var sendSessionCancelNotification = sendSessionCancelNotification2, cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
31063
31587
  await send("initialize", {
31064
31588
  protocolVersion: 1,
31065
31589
  clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: false },
@@ -31078,20 +31602,56 @@ async function createCursorAcpClient(options) {
31078
31602
  sessionId,
31079
31603
  prompt: [{ type: "text", text: prompt }]
31080
31604
  });
31605
+ await new Promise((r) => setImmediate(r));
31081
31606
  const output = (result?.output ?? promptOutputBuffer) || void 0;
31082
- const cancelled = (result?.stopReason ?? "").toLowerCase() === "cancelled";
31607
+ const stopReason = (result?.stopReason ?? "").toLowerCase();
31608
+ const cancelled = stopReason === "cancelled";
31609
+ const refusal = stopReason === "refusal";
31610
+ const stderrAfter = stderrCapture.getText();
31611
+ const agentType = backendAgentType ?? null;
31612
+ const stderrEvaluated = Boolean(stderrAfter && agentType);
31613
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
31614
+ if (cancelled) {
31615
+ return {
31616
+ success: false,
31617
+ stopReason: result?.stopReason,
31618
+ output: output || void 0,
31619
+ error: mergeErrorWithStderr("Stopped by user", stderrAfter)
31620
+ };
31621
+ }
31622
+ if (refusal) {
31623
+ return {
31624
+ success: false,
31625
+ stopReason: result?.stopReason,
31626
+ output: output || void 0,
31627
+ error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
31628
+ };
31629
+ }
31630
+ if (stderrSuggestsAuth) {
31631
+ return {
31632
+ success: false,
31633
+ stopReason: result?.stopReason,
31634
+ output: output || void 0,
31635
+ error: stderrAfter
31636
+ };
31637
+ }
31083
31638
  return {
31084
- success: !cancelled,
31639
+ success: true,
31085
31640
  stopReason: result?.stopReason,
31086
- output: output || void 0,
31087
- ...cancelled ? { error: "Stopped by user" } : {}
31641
+ output: output || void 0
31088
31642
  };
31089
31643
  } catch (err) {
31090
- const message = err != null && typeof err === "object" && "message" in err ? String(err.message) : String(err);
31091
- return { success: false, error: message };
31644
+ await new Promise((r) => setImmediate(r));
31645
+ const stderrAfter = stderrCapture.getText();
31646
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
31647
+ return {
31648
+ success: false,
31649
+ error: merged
31650
+ };
31092
31651
  }
31093
31652
  },
31094
31653
  async cancel() {
31654
+ cancelPendingPermissionRequests2();
31095
31655
  await sendSessionCancelNotification2();
31096
31656
  },
31097
31657
  resolveRequest(requestId, result) {
@@ -31107,23 +31667,62 @@ async function createCursorAcpClient(options) {
31107
31667
  });
31108
31668
  } catch (err) {
31109
31669
  child.kill();
31110
- reject(err);
31670
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrCapture.getText());
31671
+ reject(merged ? new Error(merged) : err instanceof Error ? err : new Error(String(err)));
31111
31672
  }
31112
31673
  })();
31113
31674
  });
31114
31675
  }
31676
+ var BACKEND_LOCAL_AGENT_TYPE3 = "cursor-cli";
31677
+ async function detectLocalAgentPresence3() {
31678
+ return isCommandOnPath("agent");
31679
+ }
31680
+
31681
+ // src/acp/clients/kiro-acp-client.ts
31682
+ var kiro_acp_client_exports = {};
31683
+ __export(kiro_acp_client_exports, {
31684
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE4,
31685
+ DEFAULT_KIRO_ACP_COMMAND: () => DEFAULT_KIRO_ACP_COMMAND,
31686
+ buildKiroAcpSpawnCommand: () => buildKiroAcpSpawnCommand,
31687
+ createKiroAcpClient: () => createKiroAcpClient,
31688
+ detectLocalAgentPresence: () => detectLocalAgentPresence4,
31689
+ isKiroAcpCommand: () => isKiroAcpCommand
31690
+ });
31691
+ var BACKEND_LOCAL_AGENT_TYPE4 = "kiro-acp";
31692
+ async function detectLocalAgentPresence4() {
31693
+ return isCommandOnPath("kiro-cli");
31694
+ }
31695
+ var DEFAULT_KIRO_ACP_COMMAND = ["kiro-cli", "acp"];
31696
+ function isKiroAcpCommand(command) {
31697
+ if (command.length < 2) return false;
31698
+ if (command[command.length - 1] !== "acp") return false;
31699
+ return command.slice(0, -1).some(
31700
+ (a) => a === "kiro-cli" || /[/\\]kiro-cli(\.exe)?$/i.test(a)
31701
+ );
31702
+ }
31703
+ function buildKiroAcpSpawnCommand(base, _sessionMode) {
31704
+ return [...base];
31705
+ }
31706
+ async function createKiroAcpClient(options) {
31707
+ const base = options.command?.length && isKiroAcpCommand(options.command) ? options.command : [...DEFAULT_KIRO_ACP_COMMAND];
31708
+ const command = buildKiroAcpSpawnCommand(base, options.sessionMode);
31709
+ return createSdkStdioAcpClient({ ...options, command });
31710
+ }
31115
31711
 
31116
31712
  // src/acp/resolve-agent-command.ts
31117
31713
  var AGENT_TYPE_DEFAULT_COMMANDS = {
31118
- "cursor-cli": ["agent", "acp"],
31119
- "codex-acp": [...DEFAULT_CODEX_ACP_COMMAND],
31714
+ [BACKEND_LOCAL_AGENT_TYPE3]: ["agent", "acp"],
31715
+ [BACKEND_LOCAL_AGENT_TYPE2]: [...DEFAULT_CODEX_ACP_COMMAND],
31120
31716
  /** ACP stdio agent; `@anthropic-ai/claude-code` is the interactive CLI and does not speak ACP on stdout. */
31121
- "claude-code": ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"]
31717
+ [BACKEND_LOCAL_AGENT_TYPE]: ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"],
31718
+ /** [Kiro CLI ACP](https://kiro.dev/docs/cli/acp/) — use full path to `kiro-cli` in PATH if the IDE cannot find it. */
31719
+ [BACKEND_LOCAL_AGENT_TYPE4]: [...DEFAULT_KIRO_ACP_COMMAND]
31122
31720
  };
31123
31721
  var AGENT_TYPE_DISPLAY_NAMES = {
31124
- "cursor-cli": "Cursor",
31125
- "codex-acp": "Codex",
31126
- "claude-code": "Claude Code"
31722
+ [BACKEND_LOCAL_AGENT_TYPE3]: "Cursor",
31723
+ [BACKEND_LOCAL_AGENT_TYPE2]: "Codex",
31724
+ [BACKEND_LOCAL_AGENT_TYPE]: "Claude Code",
31725
+ [BACKEND_LOCAL_AGENT_TYPE4]: "Kiro"
31127
31726
  };
31128
31727
  function getAgentTypeDisplayName(agentType) {
31129
31728
  if (agentType == null || agentType === "") return "Unknown agent";
@@ -31132,13 +31731,17 @@ function getAgentTypeDisplayName(agentType) {
31132
31731
  return agentType.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
31133
31732
  }
31134
31733
  function useCursorAcp(agentType, command) {
31135
- if (agentType === "cursor-cli") return true;
31734
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE3) return true;
31136
31735
  return command[0] === "agent" && command[1] === "acp";
31137
31736
  }
31138
31737
  function useCodexAcp(agentType, command) {
31139
- if (agentType === "codex-acp") return true;
31738
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE2) return true;
31140
31739
  return isCodexAcpCommand(command);
31141
31740
  }
31741
+ function useKiroAcp(agentType, command) {
31742
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE4) return true;
31743
+ return isKiroAcpCommand(command);
31744
+ }
31142
31745
  function resolveAgentCommand(preferredAgentType) {
31143
31746
  if (!preferredAgentType) return null;
31144
31747
  const command = AGENT_TYPE_DEFAULT_COMMANDS[preferredAgentType];
@@ -31159,6 +31762,14 @@ function resolveAgentCommand(preferredAgentType) {
31159
31762
  spawnCommandForSession: (sessionMode) => buildCodexAcpSpawnCommand(command, sessionMode)
31160
31763
  };
31161
31764
  }
31765
+ if (useKiroAcp(preferredAgentType, command)) {
31766
+ return {
31767
+ command,
31768
+ label: preferredAgentType,
31769
+ createClient: createKiroAcpClient,
31770
+ spawnCommandForSession: (sessionMode) => buildKiroAcpSpawnCommand(command, sessionMode)
31771
+ };
31772
+ }
31162
31773
  return {
31163
31774
  command,
31164
31775
  label: preferredAgentType,
@@ -31333,14 +31944,16 @@ function createBridgeOnRequest(opts) {
31333
31944
  const sessionId = routing.sessionId;
31334
31945
  const sendReq = getSendRequest();
31335
31946
  if (!runId || !sendReq) return;
31947
+ const kind = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
31948
+ const sessionUpdate = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
31336
31949
  try {
31337
31950
  sendReq({
31338
31951
  type: "session_update",
31339
31952
  ...sessionId ? { sessionId } : {},
31340
31953
  runId,
31341
- kind: request.method === "cursor/create_plan" ? "plan" : "question",
31954
+ kind,
31342
31955
  payload: {
31343
- sessionUpdate: request.method === "cursor/create_plan" ? "plan" : "question",
31956
+ sessionUpdate,
31344
31957
  requestId: request.requestId,
31345
31958
  method: request.method,
31346
31959
  params: request.params
@@ -31775,6 +32388,9 @@ function createBridgeOnSessionUpdate(opts) {
31775
32388
  pathTracker.accumulatedPathsByToolKey.delete(toolKey);
31776
32389
  }
31777
32390
  if (runId && send) {
32391
+ if (updateKind === "permission") {
32392
+ return;
32393
+ }
31778
32394
  try {
31779
32395
  send({
31780
32396
  type: "session_update",
@@ -31862,6 +32478,7 @@ async function ensureAcpClient(options) {
31862
32478
  command: resolved.command,
31863
32479
  sessionMode: mode,
31864
32480
  cwd: targetCwd,
32481
+ backendAgentType: preferredAgentType,
31865
32482
  onAgentSubprocessExit: () => {
31866
32483
  state.acpHandle = null;
31867
32484
  state.acpStartPromise = null;
@@ -31942,17 +32559,24 @@ async function createAcpManager(options) {
31942
32559
  log: log2
31943
32560
  });
31944
32561
  if (!handle) {
32562
+ const errMsg = state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app.";
32563
+ const evaluated = Boolean(preferredForPrompt && errMsg.trim());
32564
+ const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
32565
+ const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
31945
32566
  sendResult({
31946
32567
  type: "prompt_result",
31947
32568
  id: promptId,
31948
32569
  ...sessionId ? { sessionId } : {},
31949
32570
  ...runId ? { runId } : {},
31950
32571
  success: false,
31951
- error: state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app."
32572
+ error: errMsg,
32573
+ ...auth
31952
32574
  });
31953
32575
  return;
31954
32576
  }
31955
- if (promptRouting.sessionId !== sessionId || promptRouting.runId !== runId) return;
32577
+ if (promptRouting.sessionId !== sessionId || promptRouting.runId !== runId) {
32578
+ return;
32579
+ }
31956
32580
  if (runId && pendingCancelRunId === runId) {
31957
32581
  pendingCancelRunId = void 0;
31958
32582
  try {
@@ -31976,6 +32600,7 @@ async function createAcpManager(options) {
31976
32600
  promptId,
31977
32601
  sessionId,
31978
32602
  runId,
32603
+ agentType: preferredForPrompt,
31979
32604
  agentCwd: cwd,
31980
32605
  sendResult,
31981
32606
  sendSessionUpdate,
@@ -32073,8 +32698,8 @@ var handleAgentConfigMessage = (msg, deps) => {
32073
32698
 
32074
32699
  // src/acp/from-bridge/handle-bridge-prompt.ts
32075
32700
  import * as path11 from "node:path";
32076
- import { execFile as execFile3 } from "node:child_process";
32077
- import { promisify as promisify3 } from "node:util";
32701
+ import { execFile as execFile5 } from "node:child_process";
32702
+ import { promisify as promisify5 } from "node:util";
32078
32703
 
32079
32704
  // src/git/bridge-queue-key.ts
32080
32705
  import * as path10 from "node:path";
@@ -32132,10 +32757,10 @@ async function resolveBridgeQueueBindFields(options) {
32132
32757
  }
32133
32758
 
32134
32759
  // src/acp/from-bridge/handle-bridge-prompt.ts
32135
- var execFileAsync3 = promisify3(execFile3);
32760
+ var execFileAsync5 = promisify5(execFile5);
32136
32761
  async function readGitBranch(cwd) {
32137
32762
  try {
32138
- const { stdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
32763
+ const { stdout } = await execFileAsync5("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
32139
32764
  const b = stdout.trim();
32140
32765
  return b || null;
32141
32766
  } catch {
@@ -34850,48 +35475,19 @@ function createOnBridgeIdentified(opts) {
34850
35475
  };
34851
35476
  }
34852
35477
 
34853
- // src/dev-servers/detect-local-agent-types.ts
34854
- import { execFile as execFile4 } from "node:child_process";
34855
- import { promisify as promisify4 } from "node:util";
34856
- var execFileAsync4 = promisify4(execFile4);
34857
- var CHECKS = {
34858
- "cursor-cli": async () => {
34859
- try {
34860
- await execFileAsync4("which", ["agent"], { timeout: 4e3 });
34861
- return true;
34862
- } catch {
34863
- return false;
34864
- }
34865
- },
34866
- "codex-acp": async () => {
34867
- try {
34868
- await execFileAsync4("which", ["codex"], { timeout: 4e3 });
34869
- return true;
34870
- } catch {
34871
- return false;
34872
- }
34873
- },
34874
- /** Bridge spawns `@agentclientprotocol/claude-agent-acp` via npx; detection is “Claude toolchain likely present”. */
34875
- "claude-code": async () => {
34876
- try {
34877
- await execFileAsync4("which", ["claude"], { timeout: 4e3 });
34878
- return true;
34879
- } catch {
34880
- try {
34881
- await execFileAsync4("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], { timeout: 25e3 });
34882
- return true;
34883
- } catch {
34884
- return false;
34885
- }
34886
- }
34887
- }
34888
- };
35478
+ // src/acp/detect-local-agent-types.ts
35479
+ var LOCAL_AGENT_ACP_MODULES = [
35480
+ cursor_acp_client_exports,
35481
+ codex_acp_client_exports,
35482
+ kiro_acp_client_exports,
35483
+ claude_code_acp_client_exports
35484
+ ];
34889
35485
  async function detectLocalAgentTypes() {
34890
35486
  try {
34891
35487
  const out = [];
34892
- for (const [type, check2] of Object.entries(CHECKS)) {
35488
+ for (const mod of LOCAL_AGENT_ACP_MODULES) {
34893
35489
  try {
34894
- if (await check2()) out.push(type);
35490
+ if (await mod.detectLocalAgentPresence()) out.push(mod.BACKEND_LOCAL_AGENT_TYPE);
34895
35491
  } catch {
34896
35492
  }
34897
35493
  }