@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/index.js CHANGED
@@ -22148,6 +22148,284 @@ function sendWsMessage(ws, payload) {
22148
22148
  }
22149
22149
  }
22150
22150
 
22151
+ // ../types/dist/index.js
22152
+ init_zod();
22153
+ init_zod();
22154
+ init_zod();
22155
+ init_zod();
22156
+ init_zod();
22157
+ init_zod();
22158
+ init_zod();
22159
+ init_zod();
22160
+ init_zod();
22161
+ init_zod();
22162
+ init_zod();
22163
+ init_zod();
22164
+ var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
22165
+ var WorkItemProgressSchema = external_exports.object({
22166
+ remainingCriteria: external_exports.array(external_exports.string()).default([]),
22167
+ openQuestions: external_exports.array(external_exports.string()).default([]),
22168
+ assignedTo: external_exports.enum(["agent", "human-product", "human-expert"]).optional()
22169
+ });
22170
+ var ChangeSchema = external_exports.object({
22171
+ id: external_exports.string(),
22172
+ description: external_exports.string(),
22173
+ buildingBlockId: external_exports.string(),
22174
+ buildingBlockType: external_exports.enum(["function", "workflow", "connector", "ui-component", "app-fragment", "application", "project"]),
22175
+ action: external_exports.enum(["create", "update", "split", "combine"])
22176
+ });
22177
+ var CompletionCriterionSchema = external_exports.object({
22178
+ id: external_exports.string(),
22179
+ description: external_exports.string(),
22180
+ type: external_exports.enum(["write-code", "write-tests", "verify-tests", "other"]),
22181
+ verified: external_exports.boolean().default(false)
22182
+ });
22183
+ var WorkItemPrioritySchema = external_exports.enum(["low", "medium", "high", "critical"]);
22184
+ var IterationPhaseSchema = external_exports.enum(["analysis", "implementation", "verify", "reprioritize", "completed"]);
22185
+ var WorkItemDependencySchema = external_exports.object({
22186
+ type: external_exports.enum(["work-item"]),
22187
+ id: external_exports.string()
22188
+ });
22189
+ var WorkItemSchema = external_exports.object({
22190
+ id: external_exports.string(),
22191
+ sessionId: external_exports.string().optional(),
22192
+ summary: external_exports.string().optional(),
22193
+ description: external_exports.string(),
22194
+ status: WorkItemStatusSchema,
22195
+ buildingBlockId: external_exports.string().optional(),
22196
+ buildingBlockType: external_exports.enum(["function", "workflow", "connector", "ui-component", "app-fragment", "application", "project"]),
22197
+ changes: external_exports.array(ChangeSchema).default([]),
22198
+ completionCriteria: external_exports.array(CompletionCriterionSchema).default([]),
22199
+ priority: WorkItemPrioritySchema.default("medium"),
22200
+ dependencies: external_exports.array(WorkItemDependencySchema).default([]),
22201
+ assignedToUserId: external_exports.string().optional()
22202
+ });
22203
+ var UserWorkspaceProfileSchema = external_exports.object({
22204
+ id: external_exports.string(),
22205
+ workspaceId: external_exports.string(),
22206
+ userId: external_exports.string(),
22207
+ roleDescription: external_exports.string().optional(),
22208
+ expertiseAreas: external_exports.array(external_exports.string()),
22209
+ preferences: external_exports.record(external_exports.unknown()).optional(),
22210
+ learnings: external_exports.array(external_exports.string())
22211
+ });
22212
+ var WorkspaceOwnerInfoSchema = external_exports.object({
22213
+ ownerId: external_exports.string(),
22214
+ ownerName: external_exports.string().optional(),
22215
+ ownerEmail: external_exports.string().optional(),
22216
+ ownerProfilePictureUrl: external_exports.string().optional()
22217
+ });
22218
+ var WorkspaceRuntimeEntrySchema = external_exports.object({
22219
+ workspaceId: external_exports.string(),
22220
+ path: external_exports.string(),
22221
+ name: external_exports.string().optional(),
22222
+ owner: WorkspaceOwnerInfoSchema.optional(),
22223
+ isOwner: external_exports.boolean().optional()
22224
+ });
22225
+ var ProjectContextSchema = external_exports.object({
22226
+ projectId: external_exports.string(),
22227
+ context: external_exports.record(external_exports.unknown()).default({}),
22228
+ updatedAt: external_exports.string()
22229
+ });
22230
+ var WebSocketMessageTypeSchema = external_exports.enum([
22231
+ "plan-update",
22232
+ "work-item-update",
22233
+ "work-item-added",
22234
+ "work-item-removed",
22235
+ "project-processing-start",
22236
+ "project-processing-update",
22237
+ "project-processing-complete",
22238
+ "project-processing-error",
22239
+ "file-tool-request",
22240
+ "file-tool-response",
22241
+ "file-generated"
22242
+ ]);
22243
+ var WebSocketMessageSchema = external_exports.object({
22244
+ type: WebSocketMessageTypeSchema,
22245
+ contextId: external_exports.string().optional(),
22246
+ data: external_exports.any().optional(),
22247
+ error: external_exports.string().optional()
22248
+ });
22249
+ var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
22250
+ var CheckpointSummarySchema = external_exports.object({
22251
+ id: external_exports.string(),
22252
+ kind: CheckpointKindSchema,
22253
+ /** ISO date for daily (YYYY-MM-DD), ISO week for weekly, null for overall */
22254
+ periodKey: external_exports.string().nullable(),
22255
+ summary: external_exports.string(),
22256
+ createdAt: external_exports.string(),
22257
+ updatedAt: external_exports.string()
22258
+ });
22259
+ var ThreadMetaSchema = external_exports.object({
22260
+ threadId: external_exports.string(),
22261
+ workspaceId: external_exports.string(),
22262
+ /** External source (e.g. slack, discord); null if internal-only */
22263
+ externalSource: external_exports.string().nullable(),
22264
+ /** Id in the external system (e.g. channel_id + thread_ts) */
22265
+ externalId: external_exports.string().nullable(),
22266
+ title: external_exports.string().optional(),
22267
+ createdAt: external_exports.string(),
22268
+ updatedAt: external_exports.string()
22269
+ });
22270
+ var ThreadMessageSchema = external_exports.object({
22271
+ messageId: external_exports.string(),
22272
+ threadId: external_exports.string(),
22273
+ /** Role: user, assistant, system */
22274
+ role: external_exports.enum(["user", "assistant", "system"]),
22275
+ content: external_exports.string(),
22276
+ /** Optional reference to a ContentItem (e.g. doc, Notion page) */
22277
+ contentItemId: external_exports.string().nullable(),
22278
+ /** External message id if synced from external chat */
22279
+ externalId: external_exports.string().nullable(),
22280
+ createdAt: external_exports.string(),
22281
+ updatedAt: external_exports.string()
22282
+ });
22283
+ var ThreadCheckpointSummarySchema = CheckpointSummarySchema.extend({
22284
+ threadId: external_exports.string()
22285
+ });
22286
+ var ContentSourceSchema = external_exports.enum(["notion", "doc", "slack_thread", "other"]);
22287
+ var ContentItemMetaSchema = external_exports.object({
22288
+ contentId: external_exports.string(),
22289
+ workspaceId: external_exports.string(),
22290
+ source: ContentSourceSchema,
22291
+ /** Id in the external system (e.g. Notion page id, doc url) */
22292
+ externalId: external_exports.string(),
22293
+ /** If source is slack_thread, points to Thread DO id */
22294
+ threadId: external_exports.string().nullable(),
22295
+ title: external_exports.string().optional(),
22296
+ createdAt: external_exports.string(),
22297
+ updatedAt: external_exports.string()
22298
+ });
22299
+ var ContentStorageRefSchema = external_exports.object({
22300
+ storageKey: external_exports.string(),
22301
+ /** Optional: mime type or format hint */
22302
+ contentType: external_exports.string().optional()
22303
+ });
22304
+ var ContentCheckpointSummarySchema = CheckpointSummarySchema.extend({
22305
+ contentId: external_exports.string()
22306
+ });
22307
+ var StoryMetaSchema = external_exports.object({
22308
+ storyId: external_exports.string(),
22309
+ workspaceId: external_exports.string(),
22310
+ title: external_exports.string(),
22311
+ /** feature | bug | epic */
22312
+ kind: external_exports.enum(["feature", "bug", "epic"]).default("feature"),
22313
+ createdAt: external_exports.string(),
22314
+ updatedAt: external_exports.string()
22315
+ });
22316
+ var StoryContentItemRefSchema = external_exports.object({
22317
+ id: external_exports.string(),
22318
+ storyId: external_exports.string(),
22319
+ contentItemId: external_exports.string(),
22320
+ /** Snapshot summary when added to story (or updated) */
22321
+ summary: external_exports.string(),
22322
+ orderIndex: external_exports.number().default(0),
22323
+ createdAt: external_exports.string(),
22324
+ updatedAt: external_exports.string()
22325
+ });
22326
+ var StoryCheckpointSummarySchema = CheckpointSummarySchema.extend({
22327
+ storyId: external_exports.string()
22328
+ });
22329
+ var SessionMetaSchema = external_exports.object({
22330
+ sessionId: external_exports.string(),
22331
+ workspaceId: external_exports.string(),
22332
+ title: external_exports.string().optional(),
22333
+ createdAt: external_exports.string(),
22334
+ updatedAt: external_exports.string()
22335
+ });
22336
+ var SessionPromptSchema = external_exports.object({
22337
+ id: external_exports.string(),
22338
+ sessionId: external_exports.string(),
22339
+ /** text | resource */
22340
+ type: external_exports.enum(["text", "resource"]).default("text"),
22341
+ text: external_exports.string().optional(),
22342
+ resourceUri: external_exports.string().optional(),
22343
+ createdAt: external_exports.string()
22344
+ });
22345
+ var SessionResponseSchema = external_exports.object({
22346
+ id: external_exports.string(),
22347
+ sessionId: external_exports.string(),
22348
+ promptId: external_exports.string(),
22349
+ /** message | completion */
22350
+ kind: external_exports.enum(["message", "completion"]),
22351
+ content: external_exports.string().optional(),
22352
+ /** For completion: stopReason etc. */
22353
+ stopReason: external_exports.string().optional(),
22354
+ createdAt: external_exports.string()
22355
+ });
22356
+ var SessionToolCallSchema = external_exports.object({
22357
+ id: external_exports.string(),
22358
+ sessionId: external_exports.string(),
22359
+ promptId: external_exports.string(),
22360
+ name: external_exports.string(),
22361
+ params: external_exports.record(external_exports.unknown()).optional(),
22362
+ result: external_exports.record(external_exports.unknown()).optional(),
22363
+ createdAt: external_exports.string()
22364
+ });
22365
+ var SessionThreadRefSchema = external_exports.object({
22366
+ sessionId: external_exports.string(),
22367
+ threadId: external_exports.string(),
22368
+ addedAt: external_exports.string()
22369
+ });
22370
+ var ArtifactMetaSchema = external_exports.object({
22371
+ artifactId: external_exports.string(),
22372
+ workspaceId: external_exports.string(),
22373
+ /** Slug for permalink: /workspaces/:wid/artifacts/:slug */
22374
+ permalinkSlug: external_exports.string(),
22375
+ title: external_exports.string(),
22376
+ /** e.g. summary_report, build_log */
22377
+ type: external_exports.string().default("report"),
22378
+ /** Optional session that produced this artifact */
22379
+ sessionId: external_exports.string().nullable(),
22380
+ createdAt: external_exports.string(),
22381
+ updatedAt: external_exports.string()
22382
+ });
22383
+ var TemplateMetaSchema = external_exports.object({
22384
+ templateId: external_exports.string(),
22385
+ workspaceId: external_exports.string(),
22386
+ name: external_exports.string(),
22387
+ /** e.g. summary_report, build_log */
22388
+ artifactType: external_exports.string().optional(),
22389
+ createdAt: external_exports.string(),
22390
+ updatedAt: external_exports.string()
22391
+ });
22392
+ var GitRepoMetaSchema = external_exports.object({
22393
+ /** Stable id for the repo (e.g. hash of normalized canonical URL). Used for DO idFromName. */
22394
+ repoId: external_exports.string(),
22395
+ /** Canonical external URL (e.g. https://github.com/org/repo). Normalize before storing. */
22396
+ canonicalUrl: external_exports.string().url(),
22397
+ /** Optional workspace this repo was first linked in. */
22398
+ workspaceId: external_exports.string().nullable(),
22399
+ displayName: external_exports.string().optional(),
22400
+ createdAt: external_exports.string(),
22401
+ updatedAt: external_exports.string()
22402
+ });
22403
+ var LOCAL_AGENT_AUTH_ERROR_HINTS = {
22404
+ "kiro-acp": [/not logged in/i, /kiro-cli\s+login/i, /log in with kiro-cli/i],
22405
+ "cursor-cli": [/cursor_login/i, /authenticate.*cursor/i, /not logged in.*cursor/i, /run:\s*agent\s+login/i],
22406
+ "codex-acp": [
22407
+ /authentication failed/i,
22408
+ /not authenticated/i,
22409
+ /invalid.*api key/i,
22410
+ /sign in.*openai/i,
22411
+ /login.*openai/i,
22412
+ /unauthorized/i
22413
+ ],
22414
+ "claude-code": [
22415
+ /ANTHROPIC_API_KEY/i,
22416
+ /not authenticated/i,
22417
+ /authentication failed/i,
22418
+ /claude\s+login/i,
22419
+ /please run.*claude.*login/i
22420
+ ]
22421
+ };
22422
+ function localAgentErrorSuggestsAuth(agentType, errorText) {
22423
+ if (agentType == null || agentType === "" || errorText == null || !String(errorText).trim()) return false;
22424
+ const hints = LOCAL_AGENT_AUTH_ERROR_HINTS[agentType];
22425
+ if (!hints?.length) return false;
22426
+ return hints.some((re) => re.test(String(errorText)));
22427
+ }
22428
+
22151
22429
  // src/acp/clients/sdk-stdio-acp-client.ts
22152
22430
  import { spawn } from "node:child_process";
22153
22431
  import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
@@ -22228,6 +22506,83 @@ function toDisplayPathRelativeToCwd(cwd, absolutePath) {
22228
22506
  return rel.split(path2.sep).join("/");
22229
22507
  }
22230
22508
 
22509
+ // src/acp/clients/agent-stderr-capture.ts
22510
+ var STDERR_CAPTURE_MAX = 48e3;
22511
+ function createStderrCapture(child) {
22512
+ const chunks = [];
22513
+ let total = 0;
22514
+ return {
22515
+ append(chunk) {
22516
+ try {
22517
+ process.stderr.write(chunk);
22518
+ } catch {
22519
+ }
22520
+ if (total >= STDERR_CAPTURE_MAX) return;
22521
+ const n = Math.min(chunk.length, STDERR_CAPTURE_MAX - total);
22522
+ if (n <= 0) return;
22523
+ chunks.push(n === chunk.length ? chunk : chunk.subarray(0, n));
22524
+ total += n;
22525
+ },
22526
+ getText() {
22527
+ return Buffer.concat(chunks).toString("utf8").trim();
22528
+ }
22529
+ };
22530
+ }
22531
+ function formatJsonRpcStyleError(err) {
22532
+ if (err instanceof Error) return err.message;
22533
+ if (err != null && typeof err === "object") {
22534
+ const o = err;
22535
+ const msg = typeof o.message === "string" ? o.message : null;
22536
+ const code = o.code != null ? String(o.code) : "";
22537
+ if (msg) return code ? `[${code}] ${msg}` : msg;
22538
+ }
22539
+ if (typeof err === "string") return err;
22540
+ try {
22541
+ return JSON.stringify(err);
22542
+ } catch {
22543
+ return String(err);
22544
+ }
22545
+ }
22546
+ function mergeErrorWithStderr(primary, stderrText) {
22547
+ const s = stderrText.trim();
22548
+ const p = (primary ?? "").trim();
22549
+ if (!s) return p;
22550
+ if (!p) return s;
22551
+ if (p.includes(s) || s.includes(p)) return p.length >= s.length ? p : s;
22552
+ return `${p}
22553
+ ${s}`;
22554
+ }
22555
+
22556
+ // src/acp/clients/kiro-sdk-ext-notifications.ts
22557
+ function createKiroSdkExtNotificationHandler(options) {
22558
+ const { onSessionUpdate } = options;
22559
+ return async (method, params) => {
22560
+ if (method === "_kiro.dev/metadata") {
22561
+ const p = params && typeof params === "object" ? params : {};
22562
+ const pct = p.contextUsagePercentage;
22563
+ if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
22564
+ onSessionUpdate({
22565
+ sessionUpdate: "context_usage",
22566
+ contextUsagePercentage: pct
22567
+ });
22568
+ return;
22569
+ }
22570
+ };
22571
+ }
22572
+
22573
+ // src/acp/clients/sdk-stdio-ext-notifications.ts
22574
+ var noopExtNotification = async () => {
22575
+ };
22576
+ function createSdkStdioExtNotificationHandler(options) {
22577
+ const { backendAgentType, onSessionUpdate } = options;
22578
+ switch (backendAgentType) {
22579
+ case "kiro-acp":
22580
+ return createKiroSdkExtNotificationHandler({ onSessionUpdate });
22581
+ default:
22582
+ return noopExtNotification;
22583
+ }
22584
+ }
22585
+
22231
22586
  // src/acp/clients/sdk-stdio-acp-client.ts
22232
22587
  function formatSpawnError(err, command) {
22233
22588
  if (err.code === "ENOENT") {
@@ -22235,14 +22590,6 @@ function formatSpawnError(err, command) {
22235
22590
  }
22236
22591
  return err.message || String(err);
22237
22592
  }
22238
- function toErrorMessage(err) {
22239
- if (err instanceof Error) return err.message;
22240
- if (err != null && typeof err === "object" && "message" in err)
22241
- return String(err.message);
22242
- if (typeof err === "string") return err;
22243
- if (err != null && typeof err === "object") return JSON.stringify(err);
22244
- return String(err);
22245
- }
22246
22593
  function sliceFileContentRange(content, line, limit) {
22247
22594
  if (line == null && limit == null) return content;
22248
22595
  const lines = content.split("\n");
@@ -22258,7 +22605,9 @@ async function createSdkStdioAcpClient(options) {
22258
22605
  const {
22259
22606
  command,
22260
22607
  cwd = getBridgeWorkspaceDirectory(),
22608
+ backendAgentType,
22261
22609
  onSessionUpdate,
22610
+ onRequest,
22262
22611
  onFileChange,
22263
22612
  killSubprocessAfterCancelMs,
22264
22613
  onAgentSubprocessExit
@@ -22266,30 +22615,67 @@ async function createSdkStdioAcpClient(options) {
22266
22615
  const isWindows = process.platform === "win32";
22267
22616
  const child = spawn(command[0], command.slice(1), {
22268
22617
  cwd,
22269
- stdio: ["pipe", "pipe", "inherit"],
22618
+ stdio: ["pipe", "pipe", "pipe"],
22270
22619
  env: process.env,
22271
22620
  shell: isWindows
22272
22621
  });
22622
+ const stderrCapture = createStderrCapture(child);
22273
22623
  child.once("close", (code, signal) => {
22274
22624
  onAgentSubprocessExit?.({ code, signal });
22275
22625
  });
22276
22626
  return new Promise((resolve14, reject) => {
22627
+ let initSettled = false;
22628
+ const settleReject = (err) => {
22629
+ if (initSettled) return;
22630
+ initSettled = true;
22631
+ try {
22632
+ child.kill();
22633
+ } catch {
22634
+ }
22635
+ reject(err);
22636
+ };
22637
+ const settleResolve = (handle) => {
22638
+ if (initSettled) return;
22639
+ initSettled = true;
22640
+ resolve14(handle);
22641
+ };
22277
22642
  child.on("error", (err) => {
22278
- child.kill();
22279
- reject(new Error(formatSpawnError(err, command[0])));
22643
+ settleReject(new Error(formatSpawnError(err, command[0])));
22644
+ });
22645
+ child.stderr?.on("data", (chunk) => {
22646
+ stderrCapture.append(chunk);
22647
+ if (initSettled) return;
22648
+ const stderrText = stderrCapture.getText();
22649
+ if (backendAgentType && stderrText.trim() && localAgentErrorSuggestsAuth(backendAgentType, stderrText)) {
22650
+ settleReject(new Error(stderrText.trim()));
22651
+ }
22280
22652
  });
22281
22653
  (async () => {
22282
22654
  try {
22283
22655
  const writable = Writable.toWeb(child.stdin);
22284
22656
  const readable = Readable.toWeb(child.stdout);
22285
22657
  const stream = ndJsonStream2(writable, readable);
22658
+ const extNotification = createSdkStdioExtNotificationHandler({
22659
+ backendAgentType,
22660
+ onSessionUpdate
22661
+ });
22662
+ let permissionSeq = 0;
22663
+ const pendingPermissionResolvers = /* @__PURE__ */ new Map();
22286
22664
  const client = (_agent) => ({
22287
22665
  async requestPermission(params) {
22288
- const opt = params?.options?.[0];
22289
- if (opt && typeof opt.optionId === "string") {
22290
- return { outcome: { outcome: "selected", optionId: opt.optionId } };
22666
+ const requestId = `perm-${++permissionSeq}`;
22667
+ const paramsRecord = params != null && typeof params === "object" ? params : {};
22668
+ try {
22669
+ onRequest?.({
22670
+ requestId,
22671
+ method: "session/request_permission",
22672
+ params: paramsRecord
22673
+ });
22674
+ } catch {
22291
22675
  }
22292
- return { outcome: { outcome: "cancelled" } };
22676
+ return await new Promise((resolve15) => {
22677
+ pendingPermissionResolvers.set(requestId, resolve15);
22678
+ });
22293
22679
  },
22294
22680
  async readTextFile(params) {
22295
22681
  const abs = resolveSafePathUnderCwd(cwd, params.path);
@@ -22321,6 +22707,9 @@ async function createSdkStdioAcpClient(options) {
22321
22707
  },
22322
22708
  async sessionUpdate(params) {
22323
22709
  onSessionUpdate?.(bridgePayloadFromSdkSessionNotification(params));
22710
+ },
22711
+ async extNotification(method, params) {
22712
+ await extNotification(method, params);
22324
22713
  }
22325
22714
  });
22326
22715
  const connection = new ClientSideConnection2(client, stream);
@@ -22336,7 +22725,7 @@ async function createSdkStdioAcpClient(options) {
22336
22725
  });
22337
22726
  const newSessionRes = await connection.newSession({ cwd, mcpServers: [] });
22338
22727
  const sessionId = newSessionRes.sessionId;
22339
- resolve14({
22728
+ settleResolve({
22340
22729
  sessionId,
22341
22730
  async sendPrompt(prompt, _options) {
22342
22731
  try {
@@ -22344,22 +22733,59 @@ async function createSdkStdioAcpClient(options) {
22344
22733
  sessionId,
22345
22734
  prompt: [{ type: "text", text: prompt }]
22346
22735
  });
22736
+ await new Promise((r2) => setImmediate(r2));
22347
22737
  const r = response;
22348
- const cancelled = (r?.stopReason ?? "").toLowerCase() === "cancelled";
22738
+ const stopReason = (r?.stopReason ?? "").toLowerCase();
22739
+ const cancelled = stopReason === "cancelled";
22740
+ const refusal = stopReason === "refusal";
22741
+ const stderrAfter = stderrCapture.getText();
22742
+ const agentType = backendAgentType ?? null;
22743
+ const stderrEvaluated = Boolean(stderrAfter && agentType);
22744
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
22745
+ if (cancelled) {
22746
+ return {
22747
+ success: false,
22748
+ stopReason: r?.stopReason,
22749
+ output: r?.output,
22750
+ error: mergeErrorWithStderr("Stopped by user", stderrAfter)
22751
+ };
22752
+ }
22753
+ if (refusal) {
22754
+ return {
22755
+ success: false,
22756
+ stopReason: r?.stopReason,
22757
+ output: r?.output,
22758
+ error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
22759
+ };
22760
+ }
22761
+ if (stderrSuggestsAuth) {
22762
+ return {
22763
+ success: false,
22764
+ stopReason: r?.stopReason,
22765
+ output: r?.output,
22766
+ error: stderrAfter
22767
+ };
22768
+ }
22349
22769
  return {
22350
- success: !cancelled,
22770
+ success: true,
22351
22771
  stopReason: r?.stopReason,
22352
- output: r?.output,
22353
- ...cancelled ? { error: "Stopped by user" } : {}
22772
+ output: r?.output
22354
22773
  };
22355
22774
  } catch (err) {
22775
+ await new Promise((r) => setImmediate(r));
22776
+ const stderrAfter = stderrCapture.getText();
22777
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
22356
22778
  return {
22357
22779
  success: false,
22358
- error: err instanceof Error ? err.message : String(err)
22780
+ error: merged
22359
22781
  };
22360
22782
  }
22361
22783
  },
22362
22784
  async cancel() {
22785
+ for (const [id, resolve15] of [...pendingPermissionResolvers.entries()]) {
22786
+ pendingPermissionResolvers.delete(id);
22787
+ resolve15({ outcome: { outcome: "cancelled" } });
22788
+ }
22363
22789
  try {
22364
22790
  await connection.cancel({ sessionId });
22365
22791
  } catch {
@@ -22373,15 +22799,25 @@ async function createSdkStdioAcpClient(options) {
22373
22799
  t.unref?.();
22374
22800
  }
22375
22801
  },
22376
- resolveRequest() {
22802
+ resolveRequest(requestId, result) {
22803
+ const resolve15 = pendingPermissionResolvers.get(requestId);
22804
+ if (!resolve15) return;
22805
+ pendingPermissionResolvers.delete(requestId);
22806
+ resolve15(result);
22377
22807
  },
22378
22808
  disconnect() {
22379
22809
  child.kill();
22380
22810
  }
22381
22811
  });
22382
22812
  } catch (err) {
22383
- child.kill();
22384
- reject(new Error(toErrorMessage(err)));
22813
+ if (initSettled) return;
22814
+ try {
22815
+ child.kill();
22816
+ } catch {
22817
+ }
22818
+ const stderrText = stderrCapture.getText();
22819
+ const base = formatJsonRpcStyleError(err);
22820
+ settleReject(new Error(mergeErrorWithStderr(base, stderrText)));
22385
22821
  }
22386
22822
  })();
22387
22823
  });
@@ -27993,11 +28429,20 @@ async function sendPromptToAgent(options) {
27993
28429
  promptId,
27994
28430
  sessionId,
27995
28431
  runId,
28432
+ agentType,
27996
28433
  agentCwd,
27997
28434
  sendResult,
27998
28435
  sendSessionUpdate,
27999
28436
  log: log2
28000
28437
  } = options;
28438
+ function augmentAuthFields(errorText) {
28439
+ const err = errorText ?? "";
28440
+ const at = agentType ?? null;
28441
+ const evaluated = Boolean(at && err.trim());
28442
+ const suggestsAuth = evaluated && at ? localAgentErrorSuggestsAuth(at, err) : false;
28443
+ if (!suggestsAuth || !agentType) return {};
28444
+ return { agentAuthRequired: true, agentType };
28445
+ }
28001
28446
  try {
28002
28447
  const result = await handle.sendPrompt(promptText, {});
28003
28448
  if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
@@ -28009,12 +28454,14 @@ async function sendPromptToAgent(options) {
28009
28454
  log: log2
28010
28455
  });
28011
28456
  }
28457
+ const errStr = typeof result.error === "string" ? result.error : void 0;
28012
28458
  sendResult({
28013
28459
  type: "prompt_result",
28014
28460
  id: promptId,
28015
28461
  ...sessionId ? { sessionId } : {},
28016
28462
  ...runId ? { runId } : {},
28017
- ...result
28463
+ ...result,
28464
+ ...augmentAuthFields(errStr)
28018
28465
  });
28019
28466
  if (!result.success) {
28020
28467
  log2(`[Agent] ${result.error ?? "Error"}`);
@@ -28028,7 +28475,8 @@ async function sendPromptToAgent(options) {
28028
28475
  ...sessionId ? { sessionId } : {},
28029
28476
  ...runId ? { runId } : {},
28030
28477
  success: false,
28031
- error: errMsg
28478
+ error: errMsg,
28479
+ ...augmentAuthFields(errMsg)
28032
28480
  });
28033
28481
  }
28034
28482
  }
@@ -28047,22 +28495,42 @@ function errorMessage(err) {
28047
28495
  return String(err);
28048
28496
  }
28049
28497
 
28050
- // src/acp/clients/codex-acp-client.ts
28051
- var DEFAULT_CODEX_ACP_COMMAND = ["npx", "--yes", "@zed-industries/codex-acp"];
28052
- function isCodexAcpCommand(command) {
28053
- const i = command.indexOf("@zed-industries/codex-acp");
28054
- return i >= 0 && (i === 0 || command[i - 1] === "npx" || command[i - 1] === "bunx");
28055
- }
28056
- function buildCodexAcpSpawnCommand(base, _sessionMode) {
28057
- return [...base];
28058
- }
28059
- async function createCodexAcpClient(options) {
28060
- const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
28061
- const command = buildCodexAcpSpawnCommand(base, options.sessionMode);
28062
- return createSdkStdioAcpClient({ ...options, command });
28498
+ // src/acp/clients/claude-code-acp-client.ts
28499
+ var claude_code_acp_client_exports = {};
28500
+ __export(claude_code_acp_client_exports, {
28501
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE,
28502
+ buildClaudeCodeAcpSpawnCommand: () => buildClaudeCodeAcpSpawnCommand,
28503
+ createClaudeCodeAcpClient: () => createClaudeCodeAcpClient,
28504
+ detectLocalAgentPresence: () => detectLocalAgentPresence
28505
+ });
28506
+ import { execFile as execFile4 } from "node:child_process";
28507
+ import { promisify as promisify4 } from "node:util";
28508
+
28509
+ // src/acp/clients/detect-command-on-path.ts
28510
+ import { execFile as execFile3 } from "node:child_process";
28511
+ import { promisify as promisify3 } from "node:util";
28512
+ var execFileAsync3 = promisify3(execFile3);
28513
+ async function isCommandOnPath(command, timeoutMs = 4e3) {
28514
+ try {
28515
+ await execFileAsync3("which", [command], { timeout: timeoutMs });
28516
+ return true;
28517
+ } catch {
28518
+ return false;
28519
+ }
28063
28520
  }
28064
28521
 
28065
28522
  // src/acp/clients/claude-code-acp-client.ts
28523
+ var execFileAsync4 = promisify4(execFile4);
28524
+ var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
28525
+ async function detectLocalAgentPresence() {
28526
+ if (await isCommandOnPath("claude")) return true;
28527
+ try {
28528
+ await execFileAsync4("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], { timeout: 25e3 });
28529
+ return true;
28530
+ } catch {
28531
+ return false;
28532
+ }
28533
+ }
28066
28534
  function buildClaudeCodeAcpSpawnCommand(base, sessionMode) {
28067
28535
  if (!sessionMode) return [...base];
28068
28536
  const m = sessionMode.trim();
@@ -28079,7 +28547,42 @@ async function createClaudeCodeAcpClient(options) {
28079
28547
  });
28080
28548
  }
28081
28549
 
28550
+ // src/acp/clients/codex-acp-client.ts
28551
+ var codex_acp_client_exports = {};
28552
+ __export(codex_acp_client_exports, {
28553
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE2,
28554
+ DEFAULT_CODEX_ACP_COMMAND: () => DEFAULT_CODEX_ACP_COMMAND,
28555
+ buildCodexAcpSpawnCommand: () => buildCodexAcpSpawnCommand,
28556
+ createCodexAcpClient: () => createCodexAcpClient,
28557
+ detectLocalAgentPresence: () => detectLocalAgentPresence2,
28558
+ isCodexAcpCommand: () => isCodexAcpCommand
28559
+ });
28560
+ var BACKEND_LOCAL_AGENT_TYPE2 = "codex-acp";
28561
+ async function detectLocalAgentPresence2() {
28562
+ return isCommandOnPath("codex");
28563
+ }
28564
+ var DEFAULT_CODEX_ACP_COMMAND = ["npx", "--yes", "@zed-industries/codex-acp"];
28565
+ function isCodexAcpCommand(command) {
28566
+ const i = command.indexOf("@zed-industries/codex-acp");
28567
+ return i >= 0 && (i === 0 || command[i - 1] === "npx" || command[i - 1] === "bunx");
28568
+ }
28569
+ function buildCodexAcpSpawnCommand(base, _sessionMode) {
28570
+ return [...base];
28571
+ }
28572
+ async function createCodexAcpClient(options) {
28573
+ const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
28574
+ const command = buildCodexAcpSpawnCommand(base, options.sessionMode);
28575
+ return createSdkStdioAcpClient({ ...options, command });
28576
+ }
28577
+
28082
28578
  // src/acp/clients/cursor-acp-client.ts
28579
+ var cursor_acp_client_exports = {};
28580
+ __export(cursor_acp_client_exports, {
28581
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
28582
+ buildCursorAcpSpawnCommand: () => buildCursorAcpSpawnCommand,
28583
+ createCursorAcpClient: () => createCursorAcpClient,
28584
+ detectLocalAgentPresence: () => detectLocalAgentPresence3
28585
+ });
28083
28586
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
28084
28587
  import { dirname as dirname2 } from "node:path";
28085
28588
  import { spawn as spawn4 } from "node:child_process";
@@ -28130,15 +28633,23 @@ function buildCursorAcpSpawnCommand(base, sessionMode) {
28130
28633
  }
28131
28634
  async function createCursorAcpClient(options) {
28132
28635
  const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
28133
- const { cwd = getBridgeWorkspaceDirectory(), onSessionUpdate, onRequest, onFileChange } = options;
28636
+ const {
28637
+ cwd = getBridgeWorkspaceDirectory(),
28638
+ backendAgentType,
28639
+ onSessionUpdate,
28640
+ onRequest,
28641
+ onFileChange
28642
+ } = options;
28134
28643
  const dbgFs = process.env.BUILDAMATON_DEBUG_ACP_FS === "1";
28135
28644
  const isWindows = process.platform === "win32";
28136
28645
  const child = spawn4(command[0], command.slice(1), {
28137
28646
  cwd,
28138
- stdio: ["pipe", "pipe", "inherit"],
28647
+ stdio: ["pipe", "pipe", "pipe"],
28139
28648
  env: process.env,
28140
28649
  shell: isWindows
28141
28650
  });
28651
+ const stderrCapture = createStderrCapture(child);
28652
+ child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
28142
28653
  return new Promise((resolve14, reject) => {
28143
28654
  child.on("error", (err) => {
28144
28655
  child.kill();
@@ -28205,7 +28716,13 @@ async function createCursorAcpClient(options) {
28205
28716
  return;
28206
28717
  }
28207
28718
  if (method === "session/request_permission" && typeof id === "number") {
28208
- respond(id, { outcome: { outcome: "selected", optionId: "allow-once" } });
28719
+ const params = msg.params ?? {};
28720
+ pendingRequests.set(id, { method, params });
28721
+ onRequest?.({
28722
+ requestId: String(id),
28723
+ method,
28724
+ params
28725
+ });
28209
28726
  return;
28210
28727
  }
28211
28728
  if (typeof id === "number" && method) {
@@ -28302,8 +28819,15 @@ async function createCursorAcpClient(options) {
28302
28819
  return new Promise((res, rej) => {
28303
28820
  child.stdin.write(line, (err) => err ? rej(err) : res());
28304
28821
  });
28822
+ }, cancelPendingPermissionRequests2 = function() {
28823
+ for (const [reqId, pending2] of [...pendingRequests.entries()]) {
28824
+ if (pending2.method === "session/request_permission") {
28825
+ respond(reqId, { outcome: { outcome: "cancelled" } });
28826
+ pendingRequests.delete(reqId);
28827
+ }
28828
+ }
28305
28829
  };
28306
- var sendSessionCancelNotification = sendSessionCancelNotification2;
28830
+ var sendSessionCancelNotification = sendSessionCancelNotification2, cancelPendingPermissionRequests = cancelPendingPermissionRequests2;
28307
28831
  await send("initialize", {
28308
28832
  protocolVersion: 1,
28309
28833
  clientCapabilities: { fs: { readTextFile: true, writeTextFile: true }, terminal: false },
@@ -28322,20 +28846,56 @@ async function createCursorAcpClient(options) {
28322
28846
  sessionId,
28323
28847
  prompt: [{ type: "text", text: prompt }]
28324
28848
  });
28849
+ await new Promise((r) => setImmediate(r));
28325
28850
  const output = (result?.output ?? promptOutputBuffer) || void 0;
28326
- const cancelled = (result?.stopReason ?? "").toLowerCase() === "cancelled";
28851
+ const stopReason = (result?.stopReason ?? "").toLowerCase();
28852
+ const cancelled = stopReason === "cancelled";
28853
+ const refusal = stopReason === "refusal";
28854
+ const stderrAfter = stderrCapture.getText();
28855
+ const agentType = backendAgentType ?? null;
28856
+ const stderrEvaluated = Boolean(stderrAfter && agentType);
28857
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
28858
+ if (cancelled) {
28859
+ return {
28860
+ success: false,
28861
+ stopReason: result?.stopReason,
28862
+ output: output || void 0,
28863
+ error: mergeErrorWithStderr("Stopped by user", stderrAfter)
28864
+ };
28865
+ }
28866
+ if (refusal) {
28867
+ return {
28868
+ success: false,
28869
+ stopReason: result?.stopReason,
28870
+ output: output || void 0,
28871
+ error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
28872
+ };
28873
+ }
28874
+ if (stderrSuggestsAuth) {
28875
+ return {
28876
+ success: false,
28877
+ stopReason: result?.stopReason,
28878
+ output: output || void 0,
28879
+ error: stderrAfter
28880
+ };
28881
+ }
28327
28882
  return {
28328
- success: !cancelled,
28883
+ success: true,
28329
28884
  stopReason: result?.stopReason,
28330
- output: output || void 0,
28331
- ...cancelled ? { error: "Stopped by user" } : {}
28885
+ output: output || void 0
28332
28886
  };
28333
28887
  } catch (err) {
28334
- const message = err != null && typeof err === "object" && "message" in err ? String(err.message) : String(err);
28335
- return { success: false, error: message };
28888
+ await new Promise((r) => setImmediate(r));
28889
+ const stderrAfter = stderrCapture.getText();
28890
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
28891
+ return {
28892
+ success: false,
28893
+ error: merged
28894
+ };
28336
28895
  }
28337
28896
  },
28338
28897
  async cancel() {
28898
+ cancelPendingPermissionRequests2();
28339
28899
  await sendSessionCancelNotification2();
28340
28900
  },
28341
28901
  resolveRequest(requestId, result) {
@@ -28351,23 +28911,62 @@ async function createCursorAcpClient(options) {
28351
28911
  });
28352
28912
  } catch (err) {
28353
28913
  child.kill();
28354
- reject(err);
28914
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrCapture.getText());
28915
+ reject(merged ? new Error(merged) : err instanceof Error ? err : new Error(String(err)));
28355
28916
  }
28356
28917
  })();
28357
28918
  });
28358
28919
  }
28920
+ var BACKEND_LOCAL_AGENT_TYPE3 = "cursor-cli";
28921
+ async function detectLocalAgentPresence3() {
28922
+ return isCommandOnPath("agent");
28923
+ }
28924
+
28925
+ // src/acp/clients/kiro-acp-client.ts
28926
+ var kiro_acp_client_exports = {};
28927
+ __export(kiro_acp_client_exports, {
28928
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE4,
28929
+ DEFAULT_KIRO_ACP_COMMAND: () => DEFAULT_KIRO_ACP_COMMAND,
28930
+ buildKiroAcpSpawnCommand: () => buildKiroAcpSpawnCommand,
28931
+ createKiroAcpClient: () => createKiroAcpClient,
28932
+ detectLocalAgentPresence: () => detectLocalAgentPresence4,
28933
+ isKiroAcpCommand: () => isKiroAcpCommand
28934
+ });
28935
+ var BACKEND_LOCAL_AGENT_TYPE4 = "kiro-acp";
28936
+ async function detectLocalAgentPresence4() {
28937
+ return isCommandOnPath("kiro-cli");
28938
+ }
28939
+ var DEFAULT_KIRO_ACP_COMMAND = ["kiro-cli", "acp"];
28940
+ function isKiroAcpCommand(command) {
28941
+ if (command.length < 2) return false;
28942
+ if (command[command.length - 1] !== "acp") return false;
28943
+ return command.slice(0, -1).some(
28944
+ (a) => a === "kiro-cli" || /[/\\]kiro-cli(\.exe)?$/i.test(a)
28945
+ );
28946
+ }
28947
+ function buildKiroAcpSpawnCommand(base, _sessionMode) {
28948
+ return [...base];
28949
+ }
28950
+ async function createKiroAcpClient(options) {
28951
+ const base = options.command?.length && isKiroAcpCommand(options.command) ? options.command : [...DEFAULT_KIRO_ACP_COMMAND];
28952
+ const command = buildKiroAcpSpawnCommand(base, options.sessionMode);
28953
+ return createSdkStdioAcpClient({ ...options, command });
28954
+ }
28359
28955
 
28360
28956
  // src/acp/resolve-agent-command.ts
28361
28957
  var AGENT_TYPE_DEFAULT_COMMANDS = {
28362
- "cursor-cli": ["agent", "acp"],
28363
- "codex-acp": [...DEFAULT_CODEX_ACP_COMMAND],
28958
+ [BACKEND_LOCAL_AGENT_TYPE3]: ["agent", "acp"],
28959
+ [BACKEND_LOCAL_AGENT_TYPE2]: [...DEFAULT_CODEX_ACP_COMMAND],
28364
28960
  /** ACP stdio agent; `@anthropic-ai/claude-code` is the interactive CLI and does not speak ACP on stdout. */
28365
- "claude-code": ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"]
28961
+ [BACKEND_LOCAL_AGENT_TYPE]: ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"],
28962
+ /** [Kiro CLI ACP](https://kiro.dev/docs/cli/acp/) — use full path to `kiro-cli` in PATH if the IDE cannot find it. */
28963
+ [BACKEND_LOCAL_AGENT_TYPE4]: [...DEFAULT_KIRO_ACP_COMMAND]
28366
28964
  };
28367
28965
  var AGENT_TYPE_DISPLAY_NAMES = {
28368
- "cursor-cli": "Cursor",
28369
- "codex-acp": "Codex",
28370
- "claude-code": "Claude Code"
28966
+ [BACKEND_LOCAL_AGENT_TYPE3]: "Cursor",
28967
+ [BACKEND_LOCAL_AGENT_TYPE2]: "Codex",
28968
+ [BACKEND_LOCAL_AGENT_TYPE]: "Claude Code",
28969
+ [BACKEND_LOCAL_AGENT_TYPE4]: "Kiro"
28371
28970
  };
28372
28971
  function getAgentTypeDisplayName(agentType) {
28373
28972
  if (agentType == null || agentType === "") return "Unknown agent";
@@ -28376,13 +28975,17 @@ function getAgentTypeDisplayName(agentType) {
28376
28975
  return agentType.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
28377
28976
  }
28378
28977
  function useCursorAcp(agentType, command) {
28379
- if (agentType === "cursor-cli") return true;
28978
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE3) return true;
28380
28979
  return command[0] === "agent" && command[1] === "acp";
28381
28980
  }
28382
28981
  function useCodexAcp(agentType, command) {
28383
- if (agentType === "codex-acp") return true;
28982
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE2) return true;
28384
28983
  return isCodexAcpCommand(command);
28385
28984
  }
28985
+ function useKiroAcp(agentType, command) {
28986
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE4) return true;
28987
+ return isKiroAcpCommand(command);
28988
+ }
28386
28989
  function resolveAgentCommand(preferredAgentType) {
28387
28990
  if (!preferredAgentType) return null;
28388
28991
  const command = AGENT_TYPE_DEFAULT_COMMANDS[preferredAgentType];
@@ -28403,6 +29006,14 @@ function resolveAgentCommand(preferredAgentType) {
28403
29006
  spawnCommandForSession: (sessionMode) => buildCodexAcpSpawnCommand(command, sessionMode)
28404
29007
  };
28405
29008
  }
29009
+ if (useKiroAcp(preferredAgentType, command)) {
29010
+ return {
29011
+ command,
29012
+ label: preferredAgentType,
29013
+ createClient: createKiroAcpClient,
29014
+ spawnCommandForSession: (sessionMode) => buildKiroAcpSpawnCommand(command, sessionMode)
29015
+ };
29016
+ }
28406
29017
  return {
28407
29018
  command,
28408
29019
  label: preferredAgentType,
@@ -28577,14 +29188,16 @@ function createBridgeOnRequest(opts) {
28577
29188
  const sessionId = routing.sessionId;
28578
29189
  const sendReq = getSendRequest();
28579
29190
  if (!runId || !sendReq) return;
29191
+ const kind = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
29192
+ const sessionUpdate = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
28580
29193
  try {
28581
29194
  sendReq({
28582
29195
  type: "session_update",
28583
29196
  ...sessionId ? { sessionId } : {},
28584
29197
  runId,
28585
- kind: request.method === "cursor/create_plan" ? "plan" : "question",
29198
+ kind,
28586
29199
  payload: {
28587
- sessionUpdate: request.method === "cursor/create_plan" ? "plan" : "question",
29200
+ sessionUpdate,
28588
29201
  requestId: request.requestId,
28589
29202
  method: request.method,
28590
29203
  params: request.params
@@ -29019,6 +29632,9 @@ function createBridgeOnSessionUpdate(opts) {
29019
29632
  pathTracker.accumulatedPathsByToolKey.delete(toolKey);
29020
29633
  }
29021
29634
  if (runId && send) {
29635
+ if (updateKind === "permission") {
29636
+ return;
29637
+ }
29022
29638
  try {
29023
29639
  send({
29024
29640
  type: "session_update",
@@ -29106,6 +29722,7 @@ async function ensureAcpClient(options) {
29106
29722
  command: resolved.command,
29107
29723
  sessionMode: mode,
29108
29724
  cwd: targetCwd,
29725
+ backendAgentType: preferredAgentType,
29109
29726
  onAgentSubprocessExit: () => {
29110
29727
  state.acpHandle = null;
29111
29728
  state.acpStartPromise = null;
@@ -29186,17 +29803,24 @@ async function createAcpManager(options) {
29186
29803
  log: log2
29187
29804
  });
29188
29805
  if (!handle) {
29806
+ const errMsg = state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app.";
29807
+ const evaluated = Boolean(preferredForPrompt && errMsg.trim());
29808
+ const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
29809
+ const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
29189
29810
  sendResult({
29190
29811
  type: "prompt_result",
29191
29812
  id: promptId,
29192
29813
  ...sessionId ? { sessionId } : {},
29193
29814
  ...runId ? { runId } : {},
29194
29815
  success: false,
29195
- error: state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app."
29816
+ error: errMsg,
29817
+ ...auth
29196
29818
  });
29197
29819
  return;
29198
29820
  }
29199
- if (promptRouting.sessionId !== sessionId || promptRouting.runId !== runId) return;
29821
+ if (promptRouting.sessionId !== sessionId || promptRouting.runId !== runId) {
29822
+ return;
29823
+ }
29200
29824
  if (runId && pendingCancelRunId === runId) {
29201
29825
  pendingCancelRunId = void 0;
29202
29826
  try {
@@ -29220,6 +29844,7 @@ async function createAcpManager(options) {
29220
29844
  promptId,
29221
29845
  sessionId,
29222
29846
  runId,
29847
+ agentType: preferredForPrompt,
29223
29848
  agentCwd: cwd,
29224
29849
  sendResult,
29225
29850
  sendSessionUpdate,
@@ -29317,8 +29942,8 @@ var handleAgentConfigMessage = (msg, deps) => {
29317
29942
 
29318
29943
  // src/acp/from-bridge/handle-bridge-prompt.ts
29319
29944
  import * as path11 from "node:path";
29320
- import { execFile as execFile3 } from "node:child_process";
29321
- import { promisify as promisify3 } from "node:util";
29945
+ import { execFile as execFile5 } from "node:child_process";
29946
+ import { promisify as promisify5 } from "node:util";
29322
29947
 
29323
29948
  // src/git/bridge-queue-key.ts
29324
29949
  import * as path10 from "node:path";
@@ -29376,10 +30001,10 @@ async function resolveBridgeQueueBindFields(options) {
29376
30001
  }
29377
30002
 
29378
30003
  // src/acp/from-bridge/handle-bridge-prompt.ts
29379
- var execFileAsync3 = promisify3(execFile3);
30004
+ var execFileAsync5 = promisify5(execFile5);
29380
30005
  async function readGitBranch(cwd) {
29381
30006
  try {
29382
- const { stdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
30007
+ const { stdout } = await execFileAsync5("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
29383
30008
  const b = stdout.trim();
29384
30009
  return b || null;
29385
30010
  } catch {
@@ -31813,48 +32438,19 @@ function createOnBridgeIdentified(opts) {
31813
32438
  };
31814
32439
  }
31815
32440
 
31816
- // src/dev-servers/detect-local-agent-types.ts
31817
- import { execFile as execFile4 } from "node:child_process";
31818
- import { promisify as promisify4 } from "node:util";
31819
- var execFileAsync4 = promisify4(execFile4);
31820
- var CHECKS = {
31821
- "cursor-cli": async () => {
31822
- try {
31823
- await execFileAsync4("which", ["agent"], { timeout: 4e3 });
31824
- return true;
31825
- } catch {
31826
- return false;
31827
- }
31828
- },
31829
- "codex-acp": async () => {
31830
- try {
31831
- await execFileAsync4("which", ["codex"], { timeout: 4e3 });
31832
- return true;
31833
- } catch {
31834
- return false;
31835
- }
31836
- },
31837
- /** Bridge spawns `@agentclientprotocol/claude-agent-acp` via npx; detection is “Claude toolchain likely present”. */
31838
- "claude-code": async () => {
31839
- try {
31840
- await execFileAsync4("which", ["claude"], { timeout: 4e3 });
31841
- return true;
31842
- } catch {
31843
- try {
31844
- await execFileAsync4("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], { timeout: 25e3 });
31845
- return true;
31846
- } catch {
31847
- return false;
31848
- }
31849
- }
31850
- }
31851
- };
32441
+ // src/acp/detect-local-agent-types.ts
32442
+ var LOCAL_AGENT_ACP_MODULES = [
32443
+ cursor_acp_client_exports,
32444
+ codex_acp_client_exports,
32445
+ kiro_acp_client_exports,
32446
+ claude_code_acp_client_exports
32447
+ ];
31852
32448
  async function detectLocalAgentTypes() {
31853
32449
  try {
31854
32450
  const out = [];
31855
- for (const [type, check2] of Object.entries(CHECKS)) {
32451
+ for (const mod of LOCAL_AGENT_ACP_MODULES) {
31856
32452
  try {
31857
- if (await check2()) out.push(type);
32453
+ if (await mod.detectLocalAgentPresence()) out.push(mod.BACKEND_LOCAL_AGENT_TYPE);
31858
32454
  } catch {
31859
32455
  }
31860
32456
  }