@buildautomaton/cli 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -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,6 +31057,7 @@ async function createSdkStdioAcpClient(options) {
30674
31057
  const {
30675
31058
  command,
30676
31059
  cwd = getBridgeWorkspaceDirectory(),
31060
+ backendAgentType,
30677
31061
  onSessionUpdate,
30678
31062
  onFileChange,
30679
31063
  killSubprocessAfterCancelMs,
@@ -30682,23 +31066,50 @@ async function createSdkStdioAcpClient(options) {
30682
31066
  const isWindows = process.platform === "win32";
30683
31067
  const child = spawn2(command[0], command.slice(1), {
30684
31068
  cwd,
30685
- stdio: ["pipe", "pipe", "inherit"],
31069
+ stdio: ["pipe", "pipe", "pipe"],
30686
31070
  env: process.env,
30687
31071
  shell: isWindows
30688
31072
  });
31073
+ const stderrCapture = createStderrCapture(child);
30689
31074
  child.once("close", (code, signal) => {
30690
31075
  onAgentSubprocessExit?.({ code, signal });
30691
31076
  });
30692
31077
  return new Promise((resolve15, reject) => {
31078
+ let initSettled = false;
31079
+ const settleReject = (err) => {
31080
+ if (initSettled) return;
31081
+ initSettled = true;
31082
+ try {
31083
+ child.kill();
31084
+ } catch {
31085
+ }
31086
+ reject(err);
31087
+ };
31088
+ const settleResolve = (handle) => {
31089
+ if (initSettled) return;
31090
+ initSettled = true;
31091
+ resolve15(handle);
31092
+ };
30693
31093
  child.on("error", (err) => {
30694
- child.kill();
30695
- reject(new Error(formatSpawnError(err, command[0])));
31094
+ settleReject(new Error(formatSpawnError(err, command[0])));
31095
+ });
31096
+ child.stderr?.on("data", (chunk) => {
31097
+ stderrCapture.append(chunk);
31098
+ if (initSettled) return;
31099
+ const stderrText = stderrCapture.getText();
31100
+ if (backendAgentType && stderrText.trim() && localAgentErrorSuggestsAuth(backendAgentType, stderrText)) {
31101
+ settleReject(new Error(stderrText.trim()));
31102
+ }
30696
31103
  });
30697
31104
  (async () => {
30698
31105
  try {
30699
31106
  const writable = Writable.toWeb(child.stdin);
30700
31107
  const readable = Readable.toWeb(child.stdout);
30701
31108
  const stream = ndJsonStream2(writable, readable);
31109
+ const extNotification = createSdkStdioExtNotificationHandler({
31110
+ backendAgentType,
31111
+ onSessionUpdate
31112
+ });
30702
31113
  const client = (_agent) => ({
30703
31114
  async requestPermission(params) {
30704
31115
  const opt = params?.options?.[0];
@@ -30737,6 +31148,9 @@ async function createSdkStdioAcpClient(options) {
30737
31148
  },
30738
31149
  async sessionUpdate(params) {
30739
31150
  onSessionUpdate?.(bridgePayloadFromSdkSessionNotification(params));
31151
+ },
31152
+ async extNotification(method, params) {
31153
+ await extNotification(method, params);
30740
31154
  }
30741
31155
  });
30742
31156
  const connection = new ClientSideConnection2(client, stream);
@@ -30752,7 +31166,7 @@ async function createSdkStdioAcpClient(options) {
30752
31166
  });
30753
31167
  const newSessionRes = await connection.newSession({ cwd, mcpServers: [] });
30754
31168
  const sessionId = newSessionRes.sessionId;
30755
- resolve15({
31169
+ settleResolve({
30756
31170
  sessionId,
30757
31171
  async sendPrompt(prompt, _options) {
30758
31172
  try {
@@ -30760,18 +31174,51 @@ async function createSdkStdioAcpClient(options) {
30760
31174
  sessionId,
30761
31175
  prompt: [{ type: "text", text: prompt }]
30762
31176
  });
31177
+ await new Promise((r2) => setImmediate(r2));
30763
31178
  const r = response;
30764
- const cancelled = (r?.stopReason ?? "").toLowerCase() === "cancelled";
31179
+ const stopReason = (r?.stopReason ?? "").toLowerCase();
31180
+ const cancelled = stopReason === "cancelled";
31181
+ const refusal = stopReason === "refusal";
31182
+ const stderrAfter = stderrCapture.getText();
31183
+ const agentType = backendAgentType ?? null;
31184
+ const stderrEvaluated = Boolean(stderrAfter && agentType);
31185
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
31186
+ if (cancelled) {
31187
+ return {
31188
+ success: false,
31189
+ stopReason: r?.stopReason,
31190
+ output: r?.output,
31191
+ error: mergeErrorWithStderr("Stopped by user", stderrAfter)
31192
+ };
31193
+ }
31194
+ if (refusal) {
31195
+ return {
31196
+ success: false,
31197
+ stopReason: r?.stopReason,
31198
+ output: r?.output,
31199
+ error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
31200
+ };
31201
+ }
31202
+ if (stderrSuggestsAuth) {
31203
+ return {
31204
+ success: false,
31205
+ stopReason: r?.stopReason,
31206
+ output: r?.output,
31207
+ error: stderrAfter
31208
+ };
31209
+ }
30765
31210
  return {
30766
- success: !cancelled,
31211
+ success: true,
30767
31212
  stopReason: r?.stopReason,
30768
- output: r?.output,
30769
- ...cancelled ? { error: "Stopped by user" } : {}
31213
+ output: r?.output
30770
31214
  };
30771
31215
  } catch (err) {
31216
+ await new Promise((r) => setImmediate(r));
31217
+ const stderrAfter = stderrCapture.getText();
31218
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
30772
31219
  return {
30773
31220
  success: false,
30774
- error: err instanceof Error ? err.message : String(err)
31221
+ error: merged
30775
31222
  };
30776
31223
  }
30777
31224
  },
@@ -30796,29 +31243,31 @@ async function createSdkStdioAcpClient(options) {
30796
31243
  }
30797
31244
  });
30798
31245
  } catch (err) {
30799
- child.kill();
30800
- reject(new Error(toErrorMessage(err)));
31246
+ if (initSettled) return;
31247
+ try {
31248
+ child.kill();
31249
+ } catch {
31250
+ }
31251
+ const stderrText = stderrCapture.getText();
31252
+ const base = formatJsonRpcStyleError(err);
31253
+ settleReject(new Error(mergeErrorWithStderr(base, stderrText)));
30801
31254
  }
30802
31255
  })();
30803
31256
  });
30804
31257
  }
30805
31258
 
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
31259
  // src/acp/clients/claude-code-acp-client.ts
31260
+ var execFileAsync4 = promisify4(execFile4);
31261
+ var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
31262
+ async function detectLocalAgentPresence() {
31263
+ if (await isCommandOnPath("claude")) return true;
31264
+ try {
31265
+ await execFileAsync4("npx", ["--yes", "@anthropic-ai/claude-code", "--version"], { timeout: 25e3 });
31266
+ return true;
31267
+ } catch {
31268
+ return false;
31269
+ }
31270
+ }
30822
31271
  function buildClaudeCodeAcpSpawnCommand(base, sessionMode) {
30823
31272
  if (!sessionMode) return [...base];
30824
31273
  const m = sessionMode.trim();
@@ -30835,7 +31284,42 @@ async function createClaudeCodeAcpClient(options) {
30835
31284
  });
30836
31285
  }
30837
31286
 
31287
+ // src/acp/clients/codex-acp-client.ts
31288
+ var codex_acp_client_exports = {};
31289
+ __export(codex_acp_client_exports, {
31290
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE2,
31291
+ DEFAULT_CODEX_ACP_COMMAND: () => DEFAULT_CODEX_ACP_COMMAND,
31292
+ buildCodexAcpSpawnCommand: () => buildCodexAcpSpawnCommand,
31293
+ createCodexAcpClient: () => createCodexAcpClient,
31294
+ detectLocalAgentPresence: () => detectLocalAgentPresence2,
31295
+ isCodexAcpCommand: () => isCodexAcpCommand
31296
+ });
31297
+ var BACKEND_LOCAL_AGENT_TYPE2 = "codex-acp";
31298
+ async function detectLocalAgentPresence2() {
31299
+ return isCommandOnPath("codex");
31300
+ }
31301
+ var DEFAULT_CODEX_ACP_COMMAND = ["npx", "--yes", "@zed-industries/codex-acp"];
31302
+ function isCodexAcpCommand(command) {
31303
+ const i = command.indexOf("@zed-industries/codex-acp");
31304
+ return i >= 0 && (i === 0 || command[i - 1] === "npx" || command[i - 1] === "bunx");
31305
+ }
31306
+ function buildCodexAcpSpawnCommand(base, _sessionMode) {
31307
+ return [...base];
31308
+ }
31309
+ async function createCodexAcpClient(options) {
31310
+ const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
31311
+ const command = buildCodexAcpSpawnCommand(base, options.sessionMode);
31312
+ return createSdkStdioAcpClient({ ...options, command });
31313
+ }
31314
+
30838
31315
  // src/acp/clients/cursor-acp-client.ts
31316
+ var cursor_acp_client_exports = {};
31317
+ __export(cursor_acp_client_exports, {
31318
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
31319
+ buildCursorAcpSpawnCommand: () => buildCursorAcpSpawnCommand,
31320
+ createCursorAcpClient: () => createCursorAcpClient,
31321
+ detectLocalAgentPresence: () => detectLocalAgentPresence3
31322
+ });
30839
31323
  import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "node:fs";
30840
31324
  import { dirname as dirname2 } from "node:path";
30841
31325
  import { spawn as spawn3 } from "node:child_process";
@@ -30886,15 +31370,23 @@ function buildCursorAcpSpawnCommand(base, sessionMode) {
30886
31370
  }
30887
31371
  async function createCursorAcpClient(options) {
30888
31372
  const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
30889
- const { cwd = getBridgeWorkspaceDirectory(), onSessionUpdate, onRequest, onFileChange } = options;
31373
+ const {
31374
+ cwd = getBridgeWorkspaceDirectory(),
31375
+ backendAgentType,
31376
+ onSessionUpdate,
31377
+ onRequest,
31378
+ onFileChange
31379
+ } = options;
30890
31380
  const dbgFs = process.env.BUILDAMATON_DEBUG_ACP_FS === "1";
30891
31381
  const isWindows = process.platform === "win32";
30892
31382
  const child = spawn3(command[0], command.slice(1), {
30893
31383
  cwd,
30894
- stdio: ["pipe", "pipe", "inherit"],
31384
+ stdio: ["pipe", "pipe", "pipe"],
30895
31385
  env: process.env,
30896
31386
  shell: isWindows
30897
31387
  });
31388
+ const stderrCapture = createStderrCapture(child);
31389
+ child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
30898
31390
  return new Promise((resolve15, reject) => {
30899
31391
  child.on("error", (err) => {
30900
31392
  child.kill();
@@ -31078,17 +31570,52 @@ async function createCursorAcpClient(options) {
31078
31570
  sessionId,
31079
31571
  prompt: [{ type: "text", text: prompt }]
31080
31572
  });
31573
+ await new Promise((r) => setImmediate(r));
31081
31574
  const output = (result?.output ?? promptOutputBuffer) || void 0;
31082
- const cancelled = (result?.stopReason ?? "").toLowerCase() === "cancelled";
31575
+ const stopReason = (result?.stopReason ?? "").toLowerCase();
31576
+ const cancelled = stopReason === "cancelled";
31577
+ const refusal = stopReason === "refusal";
31578
+ const stderrAfter = stderrCapture.getText();
31579
+ const agentType = backendAgentType ?? null;
31580
+ const stderrEvaluated = Boolean(stderrAfter && agentType);
31581
+ const stderrSuggestsAuth = stderrEvaluated ? localAgentErrorSuggestsAuth(agentType, stderrAfter) : false;
31582
+ if (cancelled) {
31583
+ return {
31584
+ success: false,
31585
+ stopReason: result?.stopReason,
31586
+ output: output || void 0,
31587
+ error: mergeErrorWithStderr("Stopped by user", stderrAfter)
31588
+ };
31589
+ }
31590
+ if (refusal) {
31591
+ return {
31592
+ success: false,
31593
+ stopReason: result?.stopReason,
31594
+ output: output || void 0,
31595
+ error: mergeErrorWithStderr("The agent refused the request.", stderrAfter)
31596
+ };
31597
+ }
31598
+ if (stderrSuggestsAuth) {
31599
+ return {
31600
+ success: false,
31601
+ stopReason: result?.stopReason,
31602
+ output: output || void 0,
31603
+ error: stderrAfter
31604
+ };
31605
+ }
31083
31606
  return {
31084
- success: !cancelled,
31607
+ success: true,
31085
31608
  stopReason: result?.stopReason,
31086
- output: output || void 0,
31087
- ...cancelled ? { error: "Stopped by user" } : {}
31609
+ output: output || void 0
31088
31610
  };
31089
31611
  } catch (err) {
31090
- const message = err != null && typeof err === "object" && "message" in err ? String(err.message) : String(err);
31091
- return { success: false, error: message };
31612
+ await new Promise((r) => setImmediate(r));
31613
+ const stderrAfter = stderrCapture.getText();
31614
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrAfter);
31615
+ return {
31616
+ success: false,
31617
+ error: merged
31618
+ };
31092
31619
  }
31093
31620
  },
31094
31621
  async cancel() {
@@ -31107,23 +31634,62 @@ async function createCursorAcpClient(options) {
31107
31634
  });
31108
31635
  } catch (err) {
31109
31636
  child.kill();
31110
- reject(err);
31637
+ const merged = mergeErrorWithStderr(formatJsonRpcStyleError(err), stderrCapture.getText());
31638
+ reject(merged ? new Error(merged) : err instanceof Error ? err : new Error(String(err)));
31111
31639
  }
31112
31640
  })();
31113
31641
  });
31114
31642
  }
31643
+ var BACKEND_LOCAL_AGENT_TYPE3 = "cursor-cli";
31644
+ async function detectLocalAgentPresence3() {
31645
+ return isCommandOnPath("agent");
31646
+ }
31647
+
31648
+ // src/acp/clients/kiro-acp-client.ts
31649
+ var kiro_acp_client_exports = {};
31650
+ __export(kiro_acp_client_exports, {
31651
+ BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE4,
31652
+ DEFAULT_KIRO_ACP_COMMAND: () => DEFAULT_KIRO_ACP_COMMAND,
31653
+ buildKiroAcpSpawnCommand: () => buildKiroAcpSpawnCommand,
31654
+ createKiroAcpClient: () => createKiroAcpClient,
31655
+ detectLocalAgentPresence: () => detectLocalAgentPresence4,
31656
+ isKiroAcpCommand: () => isKiroAcpCommand
31657
+ });
31658
+ var BACKEND_LOCAL_AGENT_TYPE4 = "kiro-acp";
31659
+ async function detectLocalAgentPresence4() {
31660
+ return isCommandOnPath("kiro-cli");
31661
+ }
31662
+ var DEFAULT_KIRO_ACP_COMMAND = ["kiro-cli", "acp"];
31663
+ function isKiroAcpCommand(command) {
31664
+ if (command.length < 2) return false;
31665
+ if (command[command.length - 1] !== "acp") return false;
31666
+ return command.slice(0, -1).some(
31667
+ (a) => a === "kiro-cli" || /[/\\]kiro-cli(\.exe)?$/i.test(a)
31668
+ );
31669
+ }
31670
+ function buildKiroAcpSpawnCommand(base, _sessionMode) {
31671
+ return [...base];
31672
+ }
31673
+ async function createKiroAcpClient(options) {
31674
+ const base = options.command?.length && isKiroAcpCommand(options.command) ? options.command : [...DEFAULT_KIRO_ACP_COMMAND];
31675
+ const command = buildKiroAcpSpawnCommand(base, options.sessionMode);
31676
+ return createSdkStdioAcpClient({ ...options, command });
31677
+ }
31115
31678
 
31116
31679
  // src/acp/resolve-agent-command.ts
31117
31680
  var AGENT_TYPE_DEFAULT_COMMANDS = {
31118
- "cursor-cli": ["agent", "acp"],
31119
- "codex-acp": [...DEFAULT_CODEX_ACP_COMMAND],
31681
+ [BACKEND_LOCAL_AGENT_TYPE3]: ["agent", "acp"],
31682
+ [BACKEND_LOCAL_AGENT_TYPE2]: [...DEFAULT_CODEX_ACP_COMMAND],
31120
31683
  /** 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"]
31684
+ [BACKEND_LOCAL_AGENT_TYPE]: ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"],
31685
+ /** [Kiro CLI ACP](https://kiro.dev/docs/cli/acp/) — use full path to `kiro-cli` in PATH if the IDE cannot find it. */
31686
+ [BACKEND_LOCAL_AGENT_TYPE4]: [...DEFAULT_KIRO_ACP_COMMAND]
31122
31687
  };
31123
31688
  var AGENT_TYPE_DISPLAY_NAMES = {
31124
- "cursor-cli": "Cursor",
31125
- "codex-acp": "Codex",
31126
- "claude-code": "Claude Code"
31689
+ [BACKEND_LOCAL_AGENT_TYPE3]: "Cursor",
31690
+ [BACKEND_LOCAL_AGENT_TYPE2]: "Codex",
31691
+ [BACKEND_LOCAL_AGENT_TYPE]: "Claude Code",
31692
+ [BACKEND_LOCAL_AGENT_TYPE4]: "Kiro"
31127
31693
  };
31128
31694
  function getAgentTypeDisplayName(agentType) {
31129
31695
  if (agentType == null || agentType === "") return "Unknown agent";
@@ -31132,13 +31698,17 @@ function getAgentTypeDisplayName(agentType) {
31132
31698
  return agentType.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
31133
31699
  }
31134
31700
  function useCursorAcp(agentType, command) {
31135
- if (agentType === "cursor-cli") return true;
31701
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE3) return true;
31136
31702
  return command[0] === "agent" && command[1] === "acp";
31137
31703
  }
31138
31704
  function useCodexAcp(agentType, command) {
31139
- if (agentType === "codex-acp") return true;
31705
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE2) return true;
31140
31706
  return isCodexAcpCommand(command);
31141
31707
  }
31708
+ function useKiroAcp(agentType, command) {
31709
+ if (agentType === BACKEND_LOCAL_AGENT_TYPE4) return true;
31710
+ return isKiroAcpCommand(command);
31711
+ }
31142
31712
  function resolveAgentCommand(preferredAgentType) {
31143
31713
  if (!preferredAgentType) return null;
31144
31714
  const command = AGENT_TYPE_DEFAULT_COMMANDS[preferredAgentType];
@@ -31159,6 +31729,14 @@ function resolveAgentCommand(preferredAgentType) {
31159
31729
  spawnCommandForSession: (sessionMode) => buildCodexAcpSpawnCommand(command, sessionMode)
31160
31730
  };
31161
31731
  }
31732
+ if (useKiroAcp(preferredAgentType, command)) {
31733
+ return {
31734
+ command,
31735
+ label: preferredAgentType,
31736
+ createClient: createKiroAcpClient,
31737
+ spawnCommandForSession: (sessionMode) => buildKiroAcpSpawnCommand(command, sessionMode)
31738
+ };
31739
+ }
31162
31740
  return {
31163
31741
  command,
31164
31742
  label: preferredAgentType,
@@ -31862,6 +32440,7 @@ async function ensureAcpClient(options) {
31862
32440
  command: resolved.command,
31863
32441
  sessionMode: mode,
31864
32442
  cwd: targetCwd,
32443
+ backendAgentType: preferredAgentType,
31865
32444
  onAgentSubprocessExit: () => {
31866
32445
  state.acpHandle = null;
31867
32446
  state.acpStartPromise = null;
@@ -31942,17 +32521,24 @@ async function createAcpManager(options) {
31942
32521
  log: log2
31943
32522
  });
31944
32523
  if (!handle) {
32524
+ const errMsg = state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app.";
32525
+ const evaluated = Boolean(preferredForPrompt && errMsg.trim());
32526
+ const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
32527
+ const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
31945
32528
  sendResult({
31946
32529
  type: "prompt_result",
31947
32530
  id: promptId,
31948
32531
  ...sessionId ? { sessionId } : {},
31949
32532
  ...runId ? { runId } : {},
31950
32533
  success: false,
31951
- error: state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app."
32534
+ error: errMsg,
32535
+ ...auth
31952
32536
  });
31953
32537
  return;
31954
32538
  }
31955
- if (promptRouting.sessionId !== sessionId || promptRouting.runId !== runId) return;
32539
+ if (promptRouting.sessionId !== sessionId || promptRouting.runId !== runId) {
32540
+ return;
32541
+ }
31956
32542
  if (runId && pendingCancelRunId === runId) {
31957
32543
  pendingCancelRunId = void 0;
31958
32544
  try {
@@ -31976,6 +32562,7 @@ async function createAcpManager(options) {
31976
32562
  promptId,
31977
32563
  sessionId,
31978
32564
  runId,
32565
+ agentType: preferredForPrompt,
31979
32566
  agentCwd: cwd,
31980
32567
  sendResult,
31981
32568
  sendSessionUpdate,
@@ -32073,8 +32660,8 @@ var handleAgentConfigMessage = (msg, deps) => {
32073
32660
 
32074
32661
  // src/acp/from-bridge/handle-bridge-prompt.ts
32075
32662
  import * as path11 from "node:path";
32076
- import { execFile as execFile3 } from "node:child_process";
32077
- import { promisify as promisify3 } from "node:util";
32663
+ import { execFile as execFile5 } from "node:child_process";
32664
+ import { promisify as promisify5 } from "node:util";
32078
32665
 
32079
32666
  // src/git/bridge-queue-key.ts
32080
32667
  import * as path10 from "node:path";
@@ -32132,10 +32719,10 @@ async function resolveBridgeQueueBindFields(options) {
32132
32719
  }
32133
32720
 
32134
32721
  // src/acp/from-bridge/handle-bridge-prompt.ts
32135
- var execFileAsync3 = promisify3(execFile3);
32722
+ var execFileAsync5 = promisify5(execFile5);
32136
32723
  async function readGitBranch(cwd) {
32137
32724
  try {
32138
- const { stdout } = await execFileAsync3("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
32725
+ const { stdout } = await execFileAsync5("git", ["branch", "--show-current"], { cwd, maxBuffer: 64 * 1024 });
32139
32726
  const b = stdout.trim();
32140
32727
  return b || null;
32141
32728
  } catch {
@@ -34850,48 +35437,19 @@ function createOnBridgeIdentified(opts) {
34850
35437
  };
34851
35438
  }
34852
35439
 
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
- };
35440
+ // src/acp/detect-local-agent-types.ts
35441
+ var LOCAL_AGENT_ACP_MODULES = [
35442
+ cursor_acp_client_exports,
35443
+ codex_acp_client_exports,
35444
+ kiro_acp_client_exports,
35445
+ claude_code_acp_client_exports
35446
+ ];
34889
35447
  async function detectLocalAgentTypes() {
34890
35448
  try {
34891
35449
  const out = [];
34892
- for (const [type, check2] of Object.entries(CHECKS)) {
35450
+ for (const mod of LOCAL_AGENT_ACP_MODULES) {
34893
35451
  try {
34894
- if (await check2()) out.push(type);
35452
+ if (await mod.detectLocalAgentPresence()) out.push(mod.BACKEND_LOCAL_AGENT_TYPE);
34895
35453
  } catch {
34896
35454
  }
34897
35455
  }