@buildautomaton/cli 0.1.90 → 0.1.91

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
@@ -24236,6 +24236,7 @@ function maybeLogCodeNavCacheWorkerError(message) {
24236
24236
  var diagnosticSink, lastDiagnosticKey;
24237
24237
  var init_code_nav_cache_log = __esm({
24238
24238
  "../bridge/src/sqlite/code-nav-cache/code-nav-cache-log.ts"() {
24239
+ "use strict";
24239
24240
  init_log();
24240
24241
  init_sqlite_errors();
24241
24242
  init_sqlite_lock_path();
@@ -30449,7 +30450,7 @@ var {
30449
30450
  } = import_index.default;
30450
30451
 
30451
30452
  // src/cli-version.ts
30452
- var CLI_VERSION = "0.1.90".length > 0 ? "0.1.90" : "0.0.0-dev";
30453
+ var CLI_VERSION = "0.1.91".length > 0 ? "0.1.91" : "0.0.0-dev";
30453
30454
 
30454
30455
  // src/cli/defaults.ts
30455
30456
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
@@ -30801,29 +30802,50 @@ function forceAcpSubprocessDisconnect(child) {
30801
30802
  killChildProcessTree(child, "SIGKILL");
30802
30803
  }
30803
30804
 
30804
- // ../bridge/src/agents/local-agent-auth.ts
30805
- var LOCAL_AGENT_AUTH_ERROR_HINTS = {
30806
- "kiro-acp": [/not logged in/i, /kiro-cli\s+login/i, /log in with kiro-cli/i],
30807
- "cursor-cli": [/cursor_login/i, /authenticate.*cursor/i, /not logged in.*cursor/i, /run:\s*agent\s+login/i],
30808
- "codex-acp": [
30809
- /authentication failed/i,
30810
- /not authenticated/i,
30811
- /invalid.*api key/i,
30812
- /sign in.*openai/i,
30813
- /login.*openai/i,
30814
- /unauthorized/i
30815
- ],
30816
- "claude-code": [
30817
- /ANTHROPIC_API_KEY/i,
30818
- /not authenticated/i,
30819
- /authentication failed/i,
30820
- /claude\s+login/i,
30821
- /please run.*claude.*login/i
30822
- ]
30805
+ // ../bridge/src/agents/providers/claude-code/auth.ts
30806
+ var claudeCodeAuthErrorHints = [
30807
+ /ANTHROPIC_API_KEY/i,
30808
+ /not authenticated/i,
30809
+ /authentication failed/i,
30810
+ /claude\s+login/i,
30811
+ /please run.*claude.*login/i
30812
+ ];
30813
+
30814
+ // ../bridge/src/agents/providers/codex/auth.ts
30815
+ var codexAuthErrorHints = [
30816
+ /authentication failed/i,
30817
+ /not authenticated/i,
30818
+ /invalid.*api key/i,
30819
+ /sign in.*openai/i,
30820
+ /login.*openai/i,
30821
+ /unauthorized/i
30822
+ ];
30823
+
30824
+ // ../bridge/src/agents/providers/cursor/auth.ts
30825
+ var cursorAuthErrorHints = [
30826
+ /cursor_login/i,
30827
+ /authenticate.*cursor/i,
30828
+ /not logged in.*cursor/i,
30829
+ /run:\s*agent\s+login/i
30830
+ ];
30831
+
30832
+ // ../bridge/src/agents/providers/kiro/auth.ts
30833
+ var kiroAuthErrorHints = [
30834
+ /not logged in/i,
30835
+ /kiro-cli\s+login/i,
30836
+ /log in with kiro-cli/i
30837
+ ];
30838
+
30839
+ // ../bridge/src/agents/providers/auth.ts
30840
+ var AUTH_ERROR_HINTS = {
30841
+ "claude-code": claudeCodeAuthErrorHints,
30842
+ "codex-acp": codexAuthErrorHints,
30843
+ "cursor-cli": cursorAuthErrorHints,
30844
+ "kiro-acp": kiroAuthErrorHints
30823
30845
  };
30824
30846
  function localAgentErrorSuggestsAuth(agentType, errorText) {
30825
30847
  if (agentType == null || agentType === "" || errorText == null || !String(errorText).trim()) return false;
30826
- const hints = LOCAL_AGENT_AUTH_ERROR_HINTS[agentType];
30848
+ const hints = AUTH_ERROR_HINTS[agentType];
30827
30849
  if (!hints?.length) return false;
30828
30850
  return hints.some((re) => re.test(String(errorText)));
30829
30851
  }
@@ -36016,34 +36038,11 @@ function flattenSdkSessionNotificationParams(params) {
36016
36038
  return { sessionId: params.sessionId, ...params.update };
36017
36039
  }
36018
36040
 
36019
- // ../bridge/src/agents/acp/clients/kiro-sdk-ext-notifications.ts
36020
- function createKiroSdkExtNotificationHandler(options) {
36021
- const { onSessionUpdate } = options;
36022
- return async (method, params) => {
36023
- if (method === "_kiro.dev/metadata") {
36024
- const p = params && typeof params === "object" ? params : {};
36025
- const pct = p.contextUsagePercentage;
36026
- if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
36027
- onSessionUpdate({
36028
- sessionUpdate: "context_usage",
36029
- contextUsagePercentage: pct
36030
- });
36031
- return;
36032
- }
36033
- };
36034
- }
36035
-
36036
36041
  // ../bridge/src/agents/acp/clients/sdk/sdk-stdio-ext-notifications.ts
36037
36042
  var noopExtNotification = async () => {
36038
36043
  };
36039
- function createSdkStdioExtNotificationHandler(options) {
36040
- const { backendAgentType, onSessionUpdate } = options;
36041
- switch (backendAgentType) {
36042
- case "kiro-acp":
36043
- return createKiroSdkExtNotificationHandler({ onSessionUpdate });
36044
- default:
36045
- return noopExtNotification;
36046
- }
36044
+ function createSdkStdioExtNotificationHandler(_options) {
36045
+ return noopExtNotification;
36047
36046
  }
36048
36047
 
36049
36048
  // ../bridge/src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
@@ -36077,11 +36076,8 @@ function resolvePendingSdkStdioPermissionCancellations(pending2) {
36077
36076
 
36078
36077
  // ../bridge/src/agents/acp/clients/sdk/sdk-stdio-connection-client.ts
36079
36078
  function createSdkStdioConnectionClient(deps) {
36080
- const { backendAgentType, onSessionUpdate, onRequest, sessionCtx, pendingPermissionReplies } = deps;
36081
- const extNotification = createSdkStdioExtNotificationHandler({
36082
- backendAgentType,
36083
- onSessionUpdate
36084
- });
36079
+ const { onSessionUpdate, onRequest, sessionCtx, pendingPermissionReplies, createExtNotificationHandler } = deps;
36080
+ const extNotification = createExtNotificationHandler?.({ onSessionUpdate }) ?? createSdkStdioExtNotificationHandler({ onSessionUpdate });
36085
36081
  let permissionSeq = 0;
36086
36082
  return (_agent) => ({
36087
36083
  async requestPermission(params) {
@@ -36193,121 +36189,16 @@ function createSdkStdioSessionContext(options) {
36193
36189
  onAcpSessionEstablished: options.onAcpSessionEstablished,
36194
36190
  onAcpConfigOptionsUpdated: options.onAcpConfigOptionsUpdated,
36195
36191
  logDebug,
36196
- getStderrText: () => options.stderrCapture.getText()
36192
+ getStderrText: () => options.stderrCapture.getText(),
36193
+ afterSessionEstablished: options.afterSessionEstablished
36197
36194
  };
36198
36195
  }
36199
36196
 
36200
36197
  // ../bridge/src/agents/acp/clients/sdk/sdk-stdio-bootstrap-connection.ts
36201
36198
  import { Readable, Writable } from "node:stream";
36202
36199
 
36203
- // ../bridge/src/agents/acp/claude-acp-permission-from-session.ts
36204
- function flattenSelectOptions(options) {
36205
- if (options == null || options.length === 0) return [];
36206
- const first2 = options[0];
36207
- if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
36208
- return options.flatMap(
36209
- (g) => Array.isArray(g.options) ? g.options : []
36210
- );
36211
- }
36212
- return options;
36213
- }
36214
- function pickModeConfigOption(configOptions) {
36215
- if (configOptions == null || configOptions.length === 0) return null;
36216
- const byCategory = configOptions.find((o) => o.category === "mode");
36217
- if (byCategory) return byCategory;
36218
- return configOptions.find((o) => o.id === "mode") ?? null;
36219
- }
36220
- async function applyClaudePermissionFromAcpSession(params) {
36221
- const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
36222
- const desiredMode = getClaudePermissionModeFromAgentConfig(agentConfig);
36223
- if (desiredMode == null) return;
36224
- const modeOpt = pickModeConfigOption(configOptions ?? null);
36225
- if (modeOpt != null) {
36226
- const flat = flattenSelectOptions(modeOpt.options);
36227
- const allowed = flat.some((o) => o.value === desiredMode);
36228
- if (allowed && modeOpt.currentValue !== desiredMode) {
36229
- try {
36230
- logDebug2(
36231
- `[Agent] Claude Code: sending ACP session/set_config_option (permission mode) configId=${JSON.stringify(modeOpt.id)} value=${JSON.stringify(desiredMode)} was=${JSON.stringify(modeOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
36232
- );
36233
- await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
36234
- } catch (e) {
36235
- logDebug2(
36236
- `[Agent] Claude Code: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`
36237
- );
36238
- }
36239
- }
36240
- return;
36241
- }
36242
- if (modes?.availableModes?.length) {
36243
- const allowed = modes.availableModes.some((m) => m.id === desiredMode);
36244
- if (allowed && desiredMode !== modes.currentModeId) {
36245
- try {
36246
- logDebug2(
36247
- `[Agent] Claude Code: sending ACP session/set_mode (permission mode) modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
36248
- );
36249
- await setSessionMode({ sessionId, modeId: desiredMode });
36250
- } catch (e) {
36251
- logDebug2(`[Agent] Claude Code: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
36252
- }
36253
- }
36254
- }
36255
- }
36256
-
36257
- // ../bridge/src/agents/acp/codex-acp-permission-from-session.ts
36258
- function flattenSelectOptions2(options) {
36259
- if (options == null || options.length === 0) return [];
36260
- const first2 = options[0];
36261
- if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
36262
- return options.flatMap(
36263
- (g) => Array.isArray(g.options) ? g.options : []
36264
- );
36265
- }
36266
- return options;
36267
- }
36268
- function pickModeConfigOption2(configOptions) {
36269
- if (configOptions == null || configOptions.length === 0) return null;
36270
- const byCategory = configOptions.find((o) => o.category === "mode");
36271
- if (byCategory) return byCategory;
36272
- return configOptions.find((o) => o.id === "mode") ?? null;
36273
- }
36274
- async function applyCodexPermissionFromAcpSession(params) {
36275
- const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
36276
- const desiredMode = getCodexPermissionModeFromAgentConfig(agentConfig);
36277
- if (desiredMode == null) return;
36278
- const modeOpt = pickModeConfigOption2(configOptions ?? null);
36279
- if (modeOpt != null) {
36280
- const flat = flattenSelectOptions2(modeOpt.options);
36281
- const allowed = flat.some((o) => o.value === desiredMode);
36282
- if (allowed && modeOpt.currentValue !== desiredMode) {
36283
- try {
36284
- logDebug2(
36285
- `[Agent] Codex: sending ACP session/set_config_option (mode) configId=${JSON.stringify(modeOpt.id)} value=${JSON.stringify(desiredMode)} was=${JSON.stringify(modeOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
36286
- );
36287
- await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
36288
- } catch (e) {
36289
- logDebug2(`[Agent] Codex: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`);
36290
- }
36291
- }
36292
- return;
36293
- }
36294
- if (modes?.availableModes?.length) {
36295
- const allowed = modes.availableModes.some((m) => m.id === desiredMode);
36296
- if (allowed && desiredMode !== modes.currentModeId) {
36297
- try {
36298
- logDebug2(
36299
- `[Agent] Codex: sending ACP session/set_mode modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
36300
- );
36301
- await setSessionMode({ sessionId, modeId: desiredMode });
36302
- } catch (e) {
36303
- logDebug2(`[Agent] Codex: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
36304
- }
36305
- }
36306
- }
36307
- }
36308
-
36309
36200
  // ../bridge/src/agents/acp/apply-acp-model-from-agent-session.ts
36310
- function flattenSelectOptions3(options) {
36201
+ function flattenSelectOptions(options) {
36311
36202
  if (options == null || options.length === 0) return [];
36312
36203
  const first2 = options[0];
36313
36204
  if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
@@ -36332,7 +36223,7 @@ async function applyAcpModelFromAcpSession(params) {
36332
36223
  if (desired == null) return;
36333
36224
  const modelOpt = pickModelConfigOption(configOptions ?? null);
36334
36225
  if (modelOpt == null) return;
36335
- const flat = flattenSelectOptions3(modelOpt.options);
36226
+ const flat = flattenSelectOptions(modelOpt.options);
36336
36227
  const allowed = flat.some((o) => o.value === desired);
36337
36228
  if (!allowed) return;
36338
36229
  if (modelOpt.currentValue === desired) return;
@@ -36454,38 +36345,13 @@ async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
36454
36345
  configOptions: established.configOptions,
36455
36346
  modes: established.modes
36456
36347
  });
36457
- if (ctx.backendAgentType === "claude-code") {
36458
- const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
36459
- const configOptionsTyped = established.configOptions;
36460
- const modesTyped = established.modes;
36461
- await applyClaudePermissionFromAcpSession({
36462
- sessionId,
36463
- agentConfig: cfg,
36464
- configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
36465
- modes: modesTyped,
36466
- setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
36467
- },
36468
- setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
36469
- },
36470
- logDebug: ctx.logDebug
36471
- });
36472
- }
36473
- if (ctx.backendAgentType === "codex-acp") {
36474
- const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
36475
- const configOptionsTyped = established.configOptions;
36476
- const modesTyped = established.modes;
36477
- await applyCodexPermissionFromAcpSession({
36478
- sessionId,
36479
- agentConfig: cfg,
36480
- configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
36481
- modes: modesTyped,
36482
- setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
36483
- },
36484
- setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
36485
- },
36486
- logDebug: ctx.logDebug
36487
- });
36488
- }
36348
+ await ctx.afterSessionEstablished?.({
36349
+ sessionId,
36350
+ transport,
36351
+ ctx,
36352
+ configOptions: established.configOptions,
36353
+ modes: established.modes
36354
+ });
36489
36355
  const cfgAll = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
36490
36356
  const configOptionsForModel = established.configOptions;
36491
36357
  if (transport.setSessionConfigOption) {
@@ -36538,7 +36404,8 @@ async function bootstrapSdkStdioConnection(options) {
36538
36404
  onSessionUpdate: options.onSessionUpdate,
36539
36405
  onRequest: options.onRequest,
36540
36406
  sessionCtx: options.sessionCtx,
36541
- pendingPermissionReplies: options.pendingPermissionReplies
36407
+ pendingPermissionReplies: options.pendingPermissionReplies,
36408
+ createExtNotificationHandler: options.createExtNotificationHandler
36542
36409
  });
36543
36410
  const connection = new ClientSideConnection2(client, stream);
36544
36411
  connection.signal.addEventListener("abort", () => {
@@ -36638,7 +36505,9 @@ async function createSdkStdioAcpClient(options) {
36638
36505
  persistedAcpSessionId,
36639
36506
  onAcpSessionEstablished,
36640
36507
  onAcpConfigOptionsUpdated,
36641
- getActiveConfigOptions
36508
+ getActiveConfigOptions,
36509
+ afterSessionEstablished,
36510
+ createExtNotificationHandler
36642
36511
  } = options;
36643
36512
  const { child, stderrCapture } = spawnSdkStdioProcess({
36644
36513
  command,
@@ -36655,6 +36524,7 @@ async function createSdkStdioAcpClient(options) {
36655
36524
  onAcpSessionEstablished,
36656
36525
  onAcpConfigOptionsUpdated,
36657
36526
  onFileChange,
36527
+ afterSessionEstablished,
36658
36528
  stderrCapture
36659
36529
  });
36660
36530
  return new Promise((resolve39, reject) => {
@@ -36679,7 +36549,8 @@ async function createSdkStdioAcpClient(options) {
36679
36549
  onSessionUpdate,
36680
36550
  onRequest,
36681
36551
  pendingPermissionReplies,
36682
- protocolVersion: PROTOCOL_VERSION2
36552
+ protocolVersion: PROTOCOL_VERSION2,
36553
+ createExtNotificationHandler
36683
36554
  });
36684
36555
  init.settleResolve(
36685
36556
  resolve39,
@@ -38339,7 +38210,7 @@ async function cancelRun(ctx, runId) {
38339
38210
  }
38340
38211
 
38341
38212
  // ../bridge/src/agents/acp/ensure-acp-client.ts
38342
- import * as fs18 from "node:fs";
38213
+ import * as fs19 from "node:fs";
38343
38214
  import * as path29 from "node:path";
38344
38215
 
38345
38216
  // ../bridge/src/paths/session-layout-paths.ts
@@ -38367,14 +38238,86 @@ function errorMessage(err) {
38367
38238
  return String(err);
38368
38239
  }
38369
38240
 
38370
- // ../bridge/src/agents/acp/clients/claude-code-acp-client.ts
38371
- var claude_code_acp_client_exports = {};
38372
- __export(claude_code_acp_client_exports, {
38373
- BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE,
38374
- buildClaudeCodeAcpSpawnCommand: () => buildClaudeCodeAcpSpawnCommand,
38375
- createClaudeCodeAcpClient: () => createClaudeCodeAcpClient,
38376
- detectLocalAgentPresence: () => detectLocalAgentPresence
38377
- });
38241
+ // ../bridge/src/agents/providers/claude-code/apply-permission.ts
38242
+ function flattenSelectOptions2(options) {
38243
+ if (options == null || options.length === 0) return [];
38244
+ const first2 = options[0];
38245
+ if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
38246
+ return options.flatMap(
38247
+ (g) => Array.isArray(g.options) ? g.options : []
38248
+ );
38249
+ }
38250
+ return options;
38251
+ }
38252
+ function pickModeConfigOption(configOptions) {
38253
+ if (configOptions == null || configOptions.length === 0) return null;
38254
+ const byCategory = configOptions.find((o) => o.category === "mode");
38255
+ if (byCategory) return byCategory;
38256
+ return configOptions.find((o) => o.id === "mode") ?? null;
38257
+ }
38258
+ async function applyClaudePermissionFromAcpSession(params) {
38259
+ const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
38260
+ const desiredMode = getClaudePermissionModeFromAgentConfig(agentConfig);
38261
+ if (desiredMode == null) return;
38262
+ const modeOpt = pickModeConfigOption(configOptions ?? null);
38263
+ if (modeOpt != null) {
38264
+ const flat = flattenSelectOptions2(modeOpt.options);
38265
+ const allowed = flat.some((o) => o.value === desiredMode);
38266
+ if (allowed && modeOpt.currentValue !== desiredMode) {
38267
+ try {
38268
+ logDebug2(
38269
+ `[Agent] Claude Code: sending ACP session/set_config_option (permission mode) configId=${JSON.stringify(modeOpt.id)} value=${JSON.stringify(desiredMode)} was=${JSON.stringify(modeOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
38270
+ );
38271
+ await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
38272
+ } catch (e) {
38273
+ logDebug2(
38274
+ `[Agent] Claude Code: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`
38275
+ );
38276
+ }
38277
+ }
38278
+ return;
38279
+ }
38280
+ if (modes?.availableModes?.length) {
38281
+ const allowed = modes.availableModes.some((m) => m.id === desiredMode);
38282
+ if (allowed && desiredMode !== modes.currentModeId) {
38283
+ try {
38284
+ logDebug2(
38285
+ `[Agent] Claude Code: sending ACP session/set_mode (permission mode) modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
38286
+ );
38287
+ await setSessionMode({ sessionId, modeId: desiredMode });
38288
+ } catch (e) {
38289
+ logDebug2(`[Agent] Claude Code: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
38290
+ }
38291
+ }
38292
+ }
38293
+ }
38294
+
38295
+ // ../bridge/src/agents/providers/shared/wrap-permission-after-session.ts
38296
+ function wrapPermissionAfterSession(apply) {
38297
+ return async ({ sessionId, transport, ctx, configOptions, modes }) => {
38298
+ const raw = ctx.agentConfig;
38299
+ const agentConfig = raw != null && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
38300
+ await apply({
38301
+ sessionId,
38302
+ agentConfig,
38303
+ configOptions: configOptionsForPermission(
38304
+ ctx.getActiveConfigOptions,
38305
+ configOptions
38306
+ ),
38307
+ modes,
38308
+ setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
38309
+ },
38310
+ setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
38311
+ },
38312
+ logDebug: ctx.logDebug
38313
+ });
38314
+ };
38315
+ }
38316
+
38317
+ // ../bridge/src/agents/providers/claude-code/after-session.ts
38318
+ var applyClaudeCodeAfterSessionEstablished = wrapPermissionAfterSession(
38319
+ applyClaudePermissionFromAcpSession
38320
+ );
38378
38321
 
38379
38322
  // ../bridge/src/agents/acp/clients/detect-command-on-path.ts
38380
38323
  init_cli_process_interrupt();
@@ -38446,8 +38389,7 @@ async function execProbeShutdownAware(file2, args, timeoutMs) {
38446
38389
  }
38447
38390
  }
38448
38391
 
38449
- // ../bridge/src/agents/acp/clients/claude-code-acp-client.ts
38450
- var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
38392
+ // ../bridge/src/agents/providers/claude-code/client.ts
38451
38393
  var CLAUDE_ACP_ADAPTER_NPX_ARGS = ["--yes", "@agentclientprotocol/claude-agent-acp"];
38452
38394
  async function detectLocalAgentPresence() {
38453
38395
  return execProbeShutdownAware("npx", [...CLAUDE_ACP_ADAPTER_NPX_ARGS, "--help"], 8e3);
@@ -38466,58 +38408,230 @@ async function createClaudeCodeAcpClient(options) {
38466
38408
  });
38467
38409
  }
38468
38410
 
38469
- // ../bridge/src/agents/acp/clients/codex-acp-client.ts
38470
- var codex_acp_client_exports = {};
38471
- __export(codex_acp_client_exports, {
38472
- BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE2,
38473
- CODEX_ACP_PACKAGE: () => CODEX_ACP_PACKAGE,
38474
- DEFAULT_CODEX_ACP_COMMAND: () => DEFAULT_CODEX_ACP_COMMAND,
38475
- LEGACY_CODEX_ACP_PACKAGE: () => LEGACY_CODEX_ACP_PACKAGE,
38476
- buildCodexAcpSpawnCommand: () => buildCodexAcpSpawnCommand,
38477
- createCodexAcpClient: () => createCodexAcpClient,
38478
- detectLocalAgentPresence: () => detectLocalAgentPresence2,
38479
- isCodexAcpCommand: () => isCodexAcpCommand,
38480
- normalizeCodexAcpCommand: () => normalizeCodexAcpCommand
38481
- });
38482
- var BACKEND_LOCAL_AGENT_TYPE2 = "codex-acp";
38411
+ // ../bridge/src/agents/install/run-streaming-command.ts
38412
+ import { spawn as spawn2 } from "node:child_process";
38413
+ import * as readline from "node:readline";
38414
+ function runStreamingCommand(command, args, options) {
38415
+ return new Promise((resolve39, reject) => {
38416
+ const child = spawn2(command, args, {
38417
+ env: options.env,
38418
+ stdio: ["ignore", "pipe", "pipe"]
38419
+ });
38420
+ let settled = false;
38421
+ const timer = options.timeoutMs != null ? setTimeout(() => {
38422
+ child.kill("SIGKILL");
38423
+ if (!settled) {
38424
+ settled = true;
38425
+ reject(new Error(`Command timed out after ${options.timeoutMs}ms`));
38426
+ }
38427
+ }, options.timeoutMs) : null;
38428
+ const onLine = (line) => {
38429
+ if (line.length > 0) options.onLine?.(line);
38430
+ };
38431
+ if (child.stdout) {
38432
+ readline.createInterface({ input: child.stdout, crlfDelay: Infinity }).on("line", onLine);
38433
+ }
38434
+ if (child.stderr) {
38435
+ readline.createInterface({ input: child.stderr, crlfDelay: Infinity }).on("line", onLine);
38436
+ }
38437
+ child.on("error", (err) => {
38438
+ if (timer) clearTimeout(timer);
38439
+ if (!settled) {
38440
+ settled = true;
38441
+ reject(err);
38442
+ }
38443
+ });
38444
+ child.on("close", (code, signal) => {
38445
+ if (timer) clearTimeout(timer);
38446
+ if (!settled) {
38447
+ settled = true;
38448
+ resolve39({ code, signal });
38449
+ }
38450
+ });
38451
+ });
38452
+ }
38453
+
38454
+ // ../bridge/src/agents/install/commands/run-npm-global-install.ts
38455
+ async function runNpmGlobalInstall(packageName, env, options) {
38456
+ const result = await runStreamingCommand("npm", ["install", "-g", packageName], {
38457
+ env: bridgeAgentPathEnv(env),
38458
+ timeoutMs: options?.timeoutMs ?? 3e5,
38459
+ onLine: options?.onLine
38460
+ });
38461
+ if (result.code !== 0) {
38462
+ throw new Error(`npm install -g ${packageName} failed (exit ${result.code ?? "signal"})`);
38463
+ }
38464
+ }
38465
+
38466
+ // ../bridge/src/agents/providers/claude-code/install.ts
38467
+ var claudeCodeInstall = {
38468
+ detectCommand: "claude",
38469
+ tokenEnvVar: "ANTHROPIC_API_KEY",
38470
+ async run(ctx) {
38471
+ ctx.onProgress?.("Installing Anthropic Claude Code");
38472
+ await runNpmGlobalInstall(
38473
+ "@anthropic-ai/claude-code",
38474
+ { ...ctx.env, ANTHROPIC_API_KEY: ctx.authToken },
38475
+ { onLine: (line) => ctx.onProgress?.("Installing Anthropic Claude Code", line) }
38476
+ );
38477
+ }
38478
+ };
38479
+
38480
+ // ../bridge/src/agents/providers/claude-code/definition.ts
38481
+ var DEFAULT_COMMAND = ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"];
38482
+ var claudeCodeProvider = {
38483
+ type: "claude-code",
38484
+ displayName: "Claude Code",
38485
+ defaultCommand: DEFAULT_COMMAND,
38486
+ authErrorHints: claudeCodeAuthErrorHints,
38487
+ detectPresence: detectLocalAgentPresence,
38488
+ install: claudeCodeInstall,
38489
+ createClient: (options) => createClaudeCodeAcpClient({
38490
+ ...options,
38491
+ afterSessionEstablished: options.afterSessionEstablished ?? applyClaudeCodeAfterSessionEstablished
38492
+ }),
38493
+ buildSpawnCommand: (base, sessionMode) => buildClaudeCodeAcpSpawnCommand([...base], sessionMode)
38494
+ };
38495
+
38496
+ // ../bridge/src/agents/providers/codex/apply-permission.ts
38497
+ function flattenSelectOptions3(options) {
38498
+ if (options == null || options.length === 0) return [];
38499
+ const first2 = options[0];
38500
+ if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
38501
+ return options.flatMap(
38502
+ (g) => Array.isArray(g.options) ? g.options : []
38503
+ );
38504
+ }
38505
+ return options;
38506
+ }
38507
+ function pickModeConfigOption2(configOptions) {
38508
+ if (configOptions == null || configOptions.length === 0) return null;
38509
+ const byCategory = configOptions.find((o) => o.category === "mode");
38510
+ if (byCategory) return byCategory;
38511
+ return configOptions.find((o) => o.id === "mode") ?? null;
38512
+ }
38513
+ async function applyCodexPermissionFromAcpSession(params) {
38514
+ const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
38515
+ const desiredMode = getCodexPermissionModeFromAgentConfig(agentConfig);
38516
+ if (desiredMode == null) return;
38517
+ const modeOpt = pickModeConfigOption2(configOptions ?? null);
38518
+ if (modeOpt != null) {
38519
+ const flat = flattenSelectOptions3(modeOpt.options);
38520
+ const allowed = flat.some((o) => o.value === desiredMode);
38521
+ if (allowed && modeOpt.currentValue !== desiredMode) {
38522
+ try {
38523
+ logDebug2(
38524
+ `[Agent] Codex: sending ACP session/set_config_option (mode) configId=${JSON.stringify(modeOpt.id)} value=${JSON.stringify(desiredMode)} was=${JSON.stringify(modeOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
38525
+ );
38526
+ await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
38527
+ } catch (e) {
38528
+ logDebug2(`[Agent] Codex: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`);
38529
+ }
38530
+ }
38531
+ return;
38532
+ }
38533
+ if (modes?.availableModes?.length) {
38534
+ const allowed = modes.availableModes.some((m) => m.id === desiredMode);
38535
+ if (allowed && desiredMode !== modes.currentModeId) {
38536
+ try {
38537
+ logDebug2(
38538
+ `[Agent] Codex: sending ACP session/set_mode modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
38539
+ );
38540
+ await setSessionMode({ sessionId, modeId: desiredMode });
38541
+ } catch (e) {
38542
+ logDebug2(`[Agent] Codex: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
38543
+ }
38544
+ }
38545
+ }
38546
+ }
38547
+
38548
+ // ../bridge/src/agents/providers/codex/after-session.ts
38549
+ var applyCodexAfterSessionEstablished = wrapPermissionAfterSession(
38550
+ applyCodexPermissionFromAcpSession
38551
+ );
38552
+
38553
+ // ../bridge/src/agents/providers/codex/client.ts
38483
38554
  var CODEX_ACP_PACKAGE = "@agentclientprotocol/codex-acp";
38484
38555
  var LEGACY_CODEX_ACP_PACKAGE = "@zed-industries/codex-acp";
38485
38556
  async function detectLocalAgentPresence2() {
38486
38557
  return isCommandOnPath("codex");
38487
38558
  }
38488
38559
  var DEFAULT_CODEX_ACP_COMMAND = ["npx", "--yes", CODEX_ACP_PACKAGE];
38489
- function isCodexAcpCommand(command) {
38490
- return command.some(
38491
- (a) => a === CODEX_ACP_PACKAGE || a === LEGACY_CODEX_ACP_PACKAGE || a.includes("codex-acp")
38492
- );
38493
- }
38494
38560
  function normalizeCodexAcpCommand(command) {
38495
38561
  return command.map((a) => a === LEGACY_CODEX_ACP_PACKAGE ? CODEX_ACP_PACKAGE : a);
38496
38562
  }
38497
- function buildCodexAcpSpawnCommand(base, _sessionMode, _agentConfig) {
38498
- return normalizeCodexAcpCommand(base);
38563
+ function buildCodexAcpSpawnCommand(base, _sessionMode, _agentConfig) {
38564
+ return normalizeCodexAcpCommand(base);
38565
+ }
38566
+ async function createCodexAcpClient(options) {
38567
+ const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
38568
+ const command = buildCodexAcpSpawnCommand(base, options.sessionMode, options.agentConfig);
38569
+ return createSdkStdioAcpClient({
38570
+ ...options,
38571
+ command,
38572
+ /** Codex ACP can ignore `session/cancel`; mirror Claude Code's subprocess fallback. */
38573
+ killSubprocessAfterCancelMs: options.killSubprocessAfterCancelMs ?? 2500
38574
+ });
38575
+ }
38576
+
38577
+ // ../bridge/src/agents/providers/codex/install.ts
38578
+ var codexInstall = {
38579
+ detectCommand: "codex",
38580
+ tokenEnvVar: "OPENAI_API_KEY",
38581
+ async run(ctx) {
38582
+ ctx.onProgress?.("Installing Codex");
38583
+ await runNpmGlobalInstall(
38584
+ "@openai/codex",
38585
+ { ...ctx.env, OPENAI_API_KEY: ctx.authToken },
38586
+ { onLine: (line) => ctx.onProgress?.("Installing Codex", line) }
38587
+ );
38588
+ }
38589
+ };
38590
+
38591
+ // ../bridge/src/agents/providers/codex/definition.ts
38592
+ var codexProvider = {
38593
+ type: "codex-acp",
38594
+ displayName: "Codex",
38595
+ defaultCommand: DEFAULT_CODEX_ACP_COMMAND,
38596
+ authErrorHints: codexAuthErrorHints,
38597
+ detectPresence: detectLocalAgentPresence2,
38598
+ install: codexInstall,
38599
+ createClient: (options) => createCodexAcpClient({
38600
+ ...options,
38601
+ afterSessionEstablished: options.afterSessionEstablished ?? applyCodexAfterSessionEstablished
38602
+ }),
38603
+ buildSpawnCommand: (base, sessionMode, agentConfig) => buildCodexAcpSpawnCommand([...base], sessionMode, agentConfig)
38604
+ };
38605
+
38606
+ // ../bridge/src/agents/providers/cursor/cleanup-session-plans.ts
38607
+ import * as fs17 from "node:fs";
38608
+
38609
+ // ../bridge/src/paths/session-plans-paths.ts
38610
+ import * as os6 from "node:os";
38611
+ import * as path25 from "node:path";
38612
+ function getSessionPlansRootDir() {
38613
+ return path25.join(os6.homedir(), ".buildautomaton", "plans");
38614
+ }
38615
+ function sanitizeSessionPlansKey(sessionId) {
38616
+ const t = sessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
38617
+ return t || "session";
38499
38618
  }
38500
- async function createCodexAcpClient(options) {
38501
- const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
38502
- const command = buildCodexAcpSpawnCommand(base, options.sessionMode, options.agentConfig);
38503
- return createSdkStdioAcpClient({
38504
- ...options,
38505
- command,
38506
- /** Codex ACP can ignore `session/cancel`; mirror Claude Code's subprocess fallback. */
38507
- killSubprocessAfterCancelMs: options.killSubprocessAfterCancelMs ?? 2500
38508
- });
38619
+ function getSessionPlansDir(sessionId) {
38620
+ return path25.join(getSessionPlansRootDir(), sanitizeSessionPlansKey(sessionId));
38509
38621
  }
38510
38622
 
38511
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-client.ts
38512
- var cursor_acp_client_exports = {};
38513
- __export(cursor_acp_client_exports, {
38514
- BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
38515
- buildCursorAcpSpawnCommand: () => buildCursorAcpSpawnCommand,
38516
- createCursorAcpClient: () => createCursorAcpClient,
38517
- detectLocalAgentPresence: () => detectLocalAgentPresence3
38518
- });
38623
+ // ../bridge/src/agents/providers/cursor/cleanup-session-plans.ts
38624
+ function cleanupSessionPlans(sessionId) {
38625
+ const id = typeof sessionId === "string" ? sessionId.trim() : "";
38626
+ if (!id) return;
38627
+ const dir = getSessionPlansDir(id);
38628
+ try {
38629
+ fs17.rmSync(dir, { recursive: true, force: true });
38630
+ } catch {
38631
+ }
38632
+ }
38519
38633
 
38520
- // ../bridge/src/agents/acp/clients/cursor/cursor-spawn-command.ts
38634
+ // ../bridge/src/agents/providers/cursor/cursor-spawn-command.ts
38521
38635
  function buildCursorAcpSpawnCommand(base, sessionMode) {
38522
38636
  if (!sessionMode) return [...base];
38523
38637
  const m = sessionMode.trim();
@@ -38525,7 +38639,7 @@ function buildCursorAcpSpawnCommand(base, sessionMode) {
38525
38639
  return [...base, "--mode", m];
38526
38640
  }
38527
38641
 
38528
- // ../bridge/src/agents/acp/clients/cursor/create-cursor-acp-session-context.ts
38642
+ // ../bridge/src/agents/providers/cursor/create-cursor-acp-session-context.ts
38529
38643
  init_log();
38530
38644
  function createCursorAcpSessionContext(options) {
38531
38645
  const suppressLoadReplayRef = { value: false };
@@ -38544,14 +38658,15 @@ function createCursorAcpSessionContext(options) {
38544
38658
  onAcpConfigOptionsUpdated: options.onAcpConfigOptionsUpdated,
38545
38659
  logDebug,
38546
38660
  getStderrText: () => options.stderrCapture.getText(),
38547
- pendingPlanExecute: { value: false }
38661
+ pendingPlanExecute: { value: false },
38662
+ afterSessionEstablished: options.afterSessionEstablished
38548
38663
  };
38549
38664
  }
38550
38665
 
38551
- // ../bridge/src/agents/acp/clients/cursor/send-cursor-prompt-with-plan-continue.ts
38666
+ // ../bridge/src/agents/providers/cursor/send-cursor-prompt-with-plan-continue.ts
38552
38667
  init_log();
38553
38668
 
38554
- // ../bridge/src/agents/acp/clients/cursor/cursor-plan-continue.ts
38669
+ // ../bridge/src/agents/providers/cursor/cursor-plan-continue.ts
38555
38670
  var CURSOR_PLAN_CONTINUE_PROMPT = "The user accepted the plan. Implement it now. Do not wait for another approval unless the plan needs material changes.";
38556
38671
  function isAcceptedCreatePlanRpcResult(result) {
38557
38672
  if (result == null || typeof result !== "object" || Array.isArray(result)) return false;
@@ -38575,7 +38690,7 @@ async function switchCursorSessionToAgentMode(transport, sessionId) {
38575
38690
  }
38576
38691
  }
38577
38692
 
38578
- // ../bridge/src/agents/acp/clients/cursor/send-cursor-prompt-with-plan-continue.ts
38693
+ // ../bridge/src/agents/providers/cursor/send-cursor-prompt-with-plan-continue.ts
38579
38694
  async function sendCursorPromptWithPlanContinue(params) {
38580
38695
  const { transport, sessionCtx, sessionId, prompt, images } = params;
38581
38696
  const first2 = await sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt, images);
@@ -38590,7 +38705,7 @@ async function sendCursorPromptWithPlanContinue(params) {
38590
38705
  );
38591
38706
  }
38592
38707
 
38593
- // ../bridge/src/agents/acp/clients/cursor/cancel-pending-cursor-permission-requests.ts
38708
+ // ../bridge/src/agents/providers/cursor/cancel-pending-cursor-permission-requests.ts
38594
38709
  function cancelPendingCursorPermissionRequests(pendingRequests2, respond) {
38595
38710
  for (const [reqId, pending2] of [...pendingRequests2.entries()]) {
38596
38711
  if (pending2.method === "session/request_permission") {
@@ -38600,7 +38715,7 @@ function cancelPendingCursorPermissionRequests(pendingRequests2, respond) {
38600
38715
  }
38601
38716
  }
38602
38717
 
38603
- // ../bridge/src/agents/acp/clients/cursor/create-cursor-acp-handle.ts
38718
+ // ../bridge/src/agents/providers/cursor/create-cursor-acp-handle.ts
38604
38719
  function createCursorAcpHandle(options) {
38605
38720
  let teardownStarted = false;
38606
38721
  let cancelFallback = null;
@@ -38663,10 +38778,10 @@ function createCursorAcpHandle(options) {
38663
38778
  };
38664
38779
  }
38665
38780
 
38666
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-init.ts
38667
- import * as readline from "node:readline";
38781
+ // ../bridge/src/agents/providers/cursor/cursor-acp-init.ts
38782
+ import * as readline2 from "node:readline";
38668
38783
 
38669
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-cursor-create-plan.ts
38784
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-cursor-create-plan.ts
38670
38785
  function buildCursorCreatePlanToolCallUpdate(requestId, params) {
38671
38786
  const toolCallId = params.toolCallId ?? params.tool_call_id;
38672
38787
  if (typeof toolCallId !== "string" || !toolCallId.trim()) return null;
@@ -38701,7 +38816,7 @@ function queueCursorCreatePlanRequest(method, id, msg, deps) {
38701
38816
  deps.onRequest?.({ requestId, method, params });
38702
38817
  }
38703
38818
 
38704
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-cursor-task.ts
38819
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-cursor-task.ts
38705
38820
  function buildCursorTaskToolCallUpdate(params) {
38706
38821
  const toolCallId = params.toolCallId ?? params.tool_call_id;
38707
38822
  if (typeof toolCallId !== "string" || !toolCallId.trim()) return null;
@@ -38734,7 +38849,7 @@ function handleCursorIncomingCursorTask(id, msg, deps) {
38734
38849
  if (update) deps.onSessionUpdate?.(update);
38735
38850
  }
38736
38851
 
38737
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-cursor-methods.ts
38852
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-cursor-methods.ts
38738
38853
  var CURSOR_BRIDGE_METHODS = /* @__PURE__ */ new Set(["cursor/ask_question"]);
38739
38854
  var CURSOR_NOOP_METHODS = /* @__PURE__ */ new Set(["cursor/update_todos", "cursor/generate_image"]);
38740
38855
  function handleCursorIncomingCursorNotification(method, msg, onSessionUpdate) {
@@ -38770,7 +38885,7 @@ function handleCursorIncomingCursorMethods(method, id, msg, deps) {
38770
38885
  return false;
38771
38886
  }
38772
38887
 
38773
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-types.ts
38888
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-types.ts
38774
38889
  function parseIncomingJsonRpcRequestId(raw) {
38775
38890
  if (typeof raw === "number" && Number.isFinite(raw)) return raw;
38776
38891
  if (typeof raw === "string" && raw.length > 0) return raw;
@@ -38789,7 +38904,7 @@ function isCursorFsWriteMethod(method) {
38789
38904
  return lower.startsWith("fs/") && lower.includes("write");
38790
38905
  }
38791
38906
 
38792
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-fs-request.ts
38907
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-fs-request.ts
38793
38908
  function pathFromFsParams(params) {
38794
38909
  for (const key of ["path", "filePath", "file_path", "targetPath", "target_path"]) {
38795
38910
  const value = params[key];
@@ -38846,7 +38961,7 @@ function handleCursorIncomingFsRequest(method, id, msg, deps) {
38846
38961
  return false;
38847
38962
  }
38848
38963
 
38849
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-permission-request.ts
38964
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-permission-request.ts
38850
38965
  function handleCursorIncomingPermissionRequest(id, method, msg, deps) {
38851
38966
  const params = msg.params ?? {};
38852
38967
  if (deps.onRequest) {
@@ -38862,39 +38977,23 @@ function handleCursorIncomingPermissionRequest(id, method, msg, deps) {
38862
38977
  return true;
38863
38978
  }
38864
38979
 
38865
- // ../bridge/src/agents/acp/clients/cursor/write-create-plan-file.ts
38866
- import * as fs17 from "node:fs";
38980
+ // ../bridge/src/agents/providers/cursor/write-create-plan-file.ts
38981
+ import * as fs18 from "node:fs";
38867
38982
  import * as path26 from "node:path";
38868
38983
  import { pathToFileURL as pathToFileURL2 } from "node:url";
38869
-
38870
- // ../bridge/src/paths/session-plans-paths.ts
38871
- import * as os6 from "node:os";
38872
- import * as path25 from "node:path";
38873
- function getSessionPlansRootDir() {
38874
- return path25.join(os6.homedir(), ".buildautomaton", "plans");
38875
- }
38876
- function sanitizeSessionPlansKey(sessionId) {
38877
- const t = sessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
38878
- return t || "session";
38879
- }
38880
- function getSessionPlansDir(sessionId) {
38881
- return path25.join(getSessionPlansRootDir(), sanitizeSessionPlansKey(sessionId));
38882
- }
38883
-
38884
- // ../bridge/src/agents/acp/clients/cursor/write-create-plan-file.ts
38885
38984
  function sanitizePlanFileBase(toolCallId) {
38886
38985
  const t = toolCallId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 120);
38887
38986
  return t || "plan";
38888
38987
  }
38889
38988
  function writeCreatePlanFile(params) {
38890
38989
  const dir = getSessionPlansDir(params.cloudSessionId);
38891
- fs17.mkdirSync(dir, { recursive: true });
38990
+ fs18.mkdirSync(dir, { recursive: true });
38892
38991
  const filePath = path26.join(dir, `${sanitizePlanFileBase(params.toolCallId)}.md`);
38893
- fs17.writeFileSync(filePath, params.planMarkdown, "utf8");
38992
+ fs18.writeFileSync(filePath, params.planMarkdown, "utf8");
38894
38993
  return pathToFileURL2(filePath).href;
38895
38994
  }
38896
38995
 
38897
- // ../bridge/src/agents/acp/clients/cursor/enrich-create-plan-rpc-result.ts
38996
+ // ../bridge/src/agents/providers/cursor/enrich-create-plan-rpc-result.ts
38898
38997
  function asRecord2(v) {
38899
38998
  return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
38900
38999
  }
@@ -38923,7 +39022,7 @@ function enrichCreatePlanRpcResult(result, pendingParams, cloudSessionId) {
38923
39022
  return { outcome: { outcome: "accepted" } };
38924
39023
  }
38925
39024
 
38926
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-resolve-request.ts
39025
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-resolve-request.ts
38927
39026
  function resolveCursorIncomingRequest(pendingRequests2, respond, requestId, result, cloudSessionId, pendingPlanExecute) {
38928
39027
  const pending2 = pendingRequests2.get(requestId);
38929
39028
  let payload = result;
@@ -38950,7 +39049,7 @@ function formatSessionUpdateKindForLog(kind) {
38950
39049
  return kind.split("_").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
38951
39050
  }
38952
39051
 
38953
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-session-update.ts
39052
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-session-update.ts
38954
39053
  function handleCursorIncomingSessionUpdate(msg, deps) {
38955
39054
  const params = msg.params;
38956
39055
  const update = params?.update;
@@ -38971,7 +39070,7 @@ function handleCursorIncomingSessionUpdate(msg, deps) {
38971
39070
  return true;
38972
39071
  }
38973
39072
 
38974
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-parse.ts
39073
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-parse.ts
38975
39074
  function safeJsonParse(value) {
38976
39075
  try {
38977
39076
  const parsed = JSON.parse(value);
@@ -38981,7 +39080,7 @@ function safeJsonParse(value) {
38981
39080
  }
38982
39081
  }
38983
39082
 
38984
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-incoming-line-handler.ts
39083
+ // ../bridge/src/agents/providers/cursor/cursor-acp-incoming-line-handler.ts
38985
39084
  function createCursorAcpIncomingLineHandler(deps) {
38986
39085
  const respondDeps = {
38987
39086
  dbgFs: deps.dbgFs,
@@ -39037,7 +39136,7 @@ function createCursorAcpIncomingLineHandler(deps) {
39037
39136
  };
39038
39137
  }
39039
39138
 
39040
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-acp-transport.ts
39139
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-acp-transport.ts
39041
39140
  function createCursorJsonRpcAcpTransport(deps) {
39042
39141
  const { send, cancelSessionNotification, skipBrowserAuthenticate } = deps;
39043
39142
  return {
@@ -39055,12 +39154,12 @@ function createCursorJsonRpcAcpTransport(deps) {
39055
39154
  };
39056
39155
  }
39057
39156
 
39058
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-stdin-write.ts
39157
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-stdin-write.ts
39059
39158
  function writeJsonRpcLine(stdin, payload, callback) {
39060
39159
  stdin.write(JSON.stringify(payload) + "\n", callback);
39061
39160
  }
39062
39161
 
39063
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-inbound-respond.ts
39162
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-inbound-respond.ts
39064
39163
  function createCursorJsonRpcInboundRespond(stdin) {
39065
39164
  function respond(id, result) {
39066
39165
  writeJsonRpcLine(stdin, { jsonrpc: "2.0", id, result });
@@ -39081,7 +39180,7 @@ function createCursorJsonRpcInboundRespond(stdin) {
39081
39180
  return { respond, respondJsonRpcError, cancelSessionNotification };
39082
39181
  }
39083
39182
 
39084
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-outbound.ts
39183
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-outbound.ts
39085
39184
  function createCursorJsonRpcOutboundPending() {
39086
39185
  const pending2 = /* @__PURE__ */ new Map();
39087
39186
  let nextId = 1;
@@ -39107,7 +39206,7 @@ function createCursorJsonRpcOutboundPending() {
39107
39206
  return { allocateId, register, settleResponse, rejectOnWriteError };
39108
39207
  }
39109
39208
 
39110
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-wire.ts
39209
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-wire.ts
39111
39210
  function createCursorJsonRpcWriter(stdin) {
39112
39211
  const inbound = createCursorJsonRpcInboundRespond(stdin);
39113
39212
  const outbound = createCursorJsonRpcOutboundPending();
@@ -39129,7 +39228,7 @@ function createCursorJsonRpcWriter(stdin) {
39129
39228
  };
39130
39229
  }
39131
39230
 
39132
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-init.ts
39231
+ // ../bridge/src/agents/providers/cursor/cursor-acp-init.ts
39133
39232
  var CURSOR_ACP_CLIENT_INFO = {
39134
39233
  protocolVersion: 1,
39135
39234
  clientCapabilities: {
@@ -39149,7 +39248,7 @@ async function initCursorAcpWire(options) {
39149
39248
  settleResponse: wire.settleResponse,
39150
39249
  pendingRequests: pendingRequests2
39151
39250
  });
39152
- const rl = readline.createInterface({ input: options.child.stdout });
39251
+ const rl = readline2.createInterface({ input: options.child.stdout });
39153
39252
  rl.on("line", (line) => incoming.handleLine(line));
39154
39253
  const transport = createCursorJsonRpcAcpTransport({
39155
39254
  send: wire.send,
@@ -39160,11 +39259,11 @@ async function initCursorAcpWire(options) {
39160
39259
  return { wire, transport, established, incoming, pendingRequests: pendingRequests2 };
39161
39260
  }
39162
39261
 
39163
- // ../bridge/src/agents/acp/clients/cursor/spawn-cursor-acp-process.ts
39164
- import { spawn as spawn2 } from "node:child_process";
39262
+ // ../bridge/src/agents/providers/cursor/spawn-cursor-acp-process.ts
39263
+ import { spawn as spawn3 } from "node:child_process";
39165
39264
  function spawnCursorAcpProcess(options) {
39166
39265
  const isWindows = process.platform === "win32";
39167
- const child = spawn2(options.command[0], options.command.slice(1), {
39266
+ const child = spawn3(options.command[0], options.command.slice(1), {
39168
39267
  cwd: options.cwd,
39169
39268
  stdio: ["pipe", "pipe", "pipe"],
39170
39269
  env: bridgeInstalledAgentAuthProcessEnv(process.env),
@@ -39178,13 +39277,12 @@ function spawnCursorAcpProcess(options) {
39178
39277
  return { child, stderrCapture };
39179
39278
  }
39180
39279
 
39181
- // ../bridge/src/agents/acp/clients/cursor/cursor-local-agent.ts
39182
- var BACKEND_LOCAL_AGENT_TYPE3 = "cursor-cli";
39280
+ // ../bridge/src/agents/providers/cursor/cursor-local-agent.ts
39183
39281
  async function detectLocalAgentPresence3() {
39184
39282
  return isCommandOnPath("agent");
39185
39283
  }
39186
39284
 
39187
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-client.ts
39285
+ // ../bridge/src/agents/providers/cursor/cursor-acp-client.ts
39188
39286
  async function createCursorAcpClient(options) {
39189
39287
  const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
39190
39288
  const {
@@ -39196,7 +39294,8 @@ async function createCursorAcpClient(options) {
39196
39294
  persistedAcpSessionId,
39197
39295
  onAcpSessionEstablished,
39198
39296
  onAcpConfigOptionsUpdated,
39199
- onAgentSubprocessExit
39297
+ onAgentSubprocessExit,
39298
+ afterSessionEstablished
39200
39299
  } = options;
39201
39300
  const dbgFs = process.env.BUILDAUTOMATON_DEBUG_ACP_FS === "1";
39202
39301
  const spawnEnv = bridgeInstalledAgentAuthProcessEnv(process.env);
@@ -39217,6 +39316,7 @@ async function createCursorAcpClient(options) {
39217
39316
  onAcpSessionEstablished,
39218
39317
  onAcpConfigOptionsUpdated,
39219
39318
  onFileChange,
39319
+ afterSessionEstablished,
39220
39320
  stderrCapture
39221
39321
  });
39222
39322
  return new Promise((resolve39, reject) => {
@@ -39252,17 +39352,43 @@ async function createCursorAcpClient(options) {
39252
39352
  });
39253
39353
  }
39254
39354
 
39255
- // ../bridge/src/agents/acp/clients/kiro-acp-client.ts
39256
- var kiro_acp_client_exports = {};
39257
- __export(kiro_acp_client_exports, {
39258
- BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE4,
39259
- DEFAULT_KIRO_ACP_COMMAND: () => DEFAULT_KIRO_ACP_COMMAND,
39260
- buildKiroAcpSpawnCommand: () => buildKiroAcpSpawnCommand,
39261
- createKiroAcpClient: () => createKiroAcpClient,
39262
- detectLocalAgentPresence: () => detectLocalAgentPresence4,
39263
- isKiroAcpCommand: () => isKiroAcpCommand
39264
- });
39265
- var BACKEND_LOCAL_AGENT_TYPE4 = "kiro-acp";
39355
+ // ../bridge/src/agents/providers/cursor/install.ts
39356
+ var cursorInstall = {
39357
+ detectCommand: "agent",
39358
+ alternateDetectCommands: ["cursor-agent"],
39359
+ tokenEnvVar: "CURSOR_API_KEY",
39360
+ async run(ctx) {
39361
+ ctx.onProgress?.("Installing Cursor CLI");
39362
+ const result = await runStreamingCommand(
39363
+ "bash",
39364
+ ["-lc", "curl -fsSL https://cursor.com/install | bash"],
39365
+ {
39366
+ timeoutMs: 3e5,
39367
+ env: { ...bridgeAgentPathEnv(ctx.env), CURSOR_API_KEY: ctx.authToken },
39368
+ onLine: (line) => ctx.onProgress?.("Installing Cursor CLI", line)
39369
+ }
39370
+ );
39371
+ if (result.code !== 0) {
39372
+ throw new Error(`Cursor CLI install failed (exit ${result.code ?? "signal"})`);
39373
+ }
39374
+ }
39375
+ };
39376
+
39377
+ // ../bridge/src/agents/providers/cursor/definition.ts
39378
+ var cursorProvider = {
39379
+ type: "cursor-cli",
39380
+ displayName: "Cursor",
39381
+ defaultCommand: ["agent", "acp"],
39382
+ authErrorHints: cursorAuthErrorHints,
39383
+ detectPresence: detectLocalAgentPresence3,
39384
+ install: cursorInstall,
39385
+ createClient: createCursorAcpClient,
39386
+ buildSpawnCommand: (base, sessionMode) => buildCursorAcpSpawnCommand([...base], sessionMode),
39387
+ onPromptTurnFinished: cleanupSessionPlans,
39388
+ onSessionClosed: cleanupSessionPlans
39389
+ };
39390
+
39391
+ // ../bridge/src/agents/providers/kiro/client.ts
39266
39392
  async function detectLocalAgentPresence4() {
39267
39393
  return isCommandOnPath("kiro-cli");
39268
39394
  }
@@ -39283,80 +39409,108 @@ async function createKiroAcpClient(options) {
39283
39409
  return createSdkStdioAcpClient({ ...options, command });
39284
39410
  }
39285
39411
 
39286
- // ../bridge/src/agents/acp/resolve-agent-command.ts
39287
- var AGENT_TYPE_DEFAULT_COMMANDS = {
39288
- [BACKEND_LOCAL_AGENT_TYPE3]: ["agent", "acp"],
39289
- [BACKEND_LOCAL_AGENT_TYPE2]: [...DEFAULT_CODEX_ACP_COMMAND],
39290
- /** ACP stdio agent; `@anthropic-ai/claude-code` is the interactive CLI and does not speak ACP on stdout. */
39291
- [BACKEND_LOCAL_AGENT_TYPE]: ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"],
39292
- /** [Kiro CLI ACP](https://kiro.dev/docs/cli/acp/) — use full path to `kiro-cli` in PATH if the IDE cannot find it. */
39293
- [BACKEND_LOCAL_AGENT_TYPE4]: [...DEFAULT_KIRO_ACP_COMMAND]
39412
+ // ../bridge/src/agents/providers/kiro/ext-notifications.ts
39413
+ function createKiroSdkExtNotificationHandler(options) {
39414
+ const { onSessionUpdate } = options;
39415
+ return async (method, params) => {
39416
+ if (method === "_kiro.dev/metadata") {
39417
+ const p = params && typeof params === "object" ? params : {};
39418
+ const pct = p.contextUsagePercentage;
39419
+ if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
39420
+ onSessionUpdate({
39421
+ sessionUpdate: "context_usage",
39422
+ contextUsagePercentage: pct
39423
+ });
39424
+ return;
39425
+ }
39426
+ };
39427
+ }
39428
+
39429
+ // ../bridge/src/agents/providers/kiro/definition.ts
39430
+ var kiroProvider = {
39431
+ type: "kiro-acp",
39432
+ displayName: "Kiro",
39433
+ defaultCommand: DEFAULT_KIRO_ACP_COMMAND,
39434
+ authErrorHints: kiroAuthErrorHints,
39435
+ detectPresence: detectLocalAgentPresence4,
39436
+ createClient: (options) => createKiroAcpClient({
39437
+ ...options,
39438
+ createExtNotificationHandler: options.createExtNotificationHandler ?? createKiroSdkExtNotificationHandler
39439
+ }),
39440
+ buildSpawnCommand: (base, sessionMode) => buildKiroAcpSpawnCommand([...base], sessionMode)
39441
+ };
39442
+
39443
+ // ../bridge/src/agents/providers/opencode/install.ts
39444
+ var opencodeInstall = {
39445
+ detectCommand: "opencode",
39446
+ tokenEnvVar: "OPENCODE_API_KEY",
39447
+ async run(ctx) {
39448
+ ctx.onProgress?.("Installing OpenCode");
39449
+ await runNpmGlobalInstall(
39450
+ "opencode-ai",
39451
+ { ...ctx.env, OPENCODE_API_KEY: ctx.authToken },
39452
+ { onLine: (line) => ctx.onProgress?.("Installing OpenCode", line) }
39453
+ );
39454
+ }
39294
39455
  };
39295
- var AGENT_TYPE_DISPLAY_NAMES = {
39296
- [BACKEND_LOCAL_AGENT_TYPE3]: "Cursor",
39297
- [BACKEND_LOCAL_AGENT_TYPE2]: "Codex",
39298
- [BACKEND_LOCAL_AGENT_TYPE]: "Claude Code",
39299
- [BACKEND_LOCAL_AGENT_TYPE4]: "Kiro"
39456
+
39457
+ // ../bridge/src/agents/providers/opencode/definition.ts
39458
+ var opencodeProvider = {
39459
+ type: "opencode",
39460
+ displayName: "OpenCode",
39461
+ defaultCommand: [],
39462
+ authErrorHints: [],
39463
+ install: opencodeInstall,
39464
+ buildSpawnCommand: (base) => [...base]
39300
39465
  };
39301
- function getAgentTypeDisplayName(agentType) {
39302
- if (agentType == null || agentType === "") return "Unknown agent";
39303
- const known = AGENT_TYPE_DISPLAY_NAMES[agentType];
39304
- if (known) return known;
39305
- return agentType.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
39466
+
39467
+ // ../bridge/src/agents/providers/registry.ts
39468
+ var AGENT_PROVIDERS = [
39469
+ cursorProvider,
39470
+ codexProvider,
39471
+ kiroProvider,
39472
+ claudeCodeProvider,
39473
+ opencodeProvider
39474
+ ];
39475
+ var byType = new Map(AGENT_PROVIDERS.map((p) => [p.type, p]));
39476
+ function getAgentProvider(agentType) {
39477
+ if (agentType == null || agentType === "") return void 0;
39478
+ return byType.get(agentType);
39306
39479
  }
39307
- function useCursorAcp(agentType, command) {
39308
- if (agentType === BACKEND_LOCAL_AGENT_TYPE3) return true;
39309
- return command[0] === "agent" && command[1] === "acp";
39480
+ function listAutoDetectAgentProviders() {
39481
+ return AGENT_PROVIDERS.filter((p) => p.detectPresence != null);
39310
39482
  }
39311
- function useCodexAcp(agentType, command) {
39312
- if (agentType === BACKEND_LOCAL_AGENT_TYPE2) return true;
39313
- return isCodexAcpCommand(command);
39483
+ function notifyAgentProvidersSessionClosed(sessionId) {
39484
+ for (const p of AGENT_PROVIDERS) p.onSessionClosed?.(sessionId);
39314
39485
  }
39315
- function useKiroAcp(agentType, command) {
39316
- if (agentType === BACKEND_LOCAL_AGENT_TYPE4) return true;
39317
- return isKiroAcpCommand(command);
39486
+ function notifyAgentProvidersPromptTurnFinished(sessionId) {
39487
+ for (const p of AGENT_PROVIDERS) p.onPromptTurnFinished?.(sessionId);
39318
39488
  }
39489
+
39490
+ // ../bridge/src/agents/acp/resolve-agent-command.ts
39319
39491
  function resolveAgentCommand(preferredAgentType) {
39320
- if (!preferredAgentType) return null;
39321
- const command = AGENT_TYPE_DEFAULT_COMMANDS[preferredAgentType];
39322
- if (!command?.length) return null;
39323
- if (useCursorAcp(preferredAgentType, command)) {
39324
- return {
39325
- command,
39326
- label: preferredAgentType,
39327
- createClient: createCursorAcpClient,
39328
- spawnCommandForSession: (sessionMode, _agentConfig) => buildCursorAcpSpawnCommand(command, sessionMode)
39329
- };
39330
- }
39331
- if (useCodexAcp(preferredAgentType, command)) {
39332
- return {
39333
- command,
39334
- label: preferredAgentType,
39335
- createClient: createCodexAcpClient,
39336
- spawnCommandForSession: (sessionMode, agentConfig) => buildCodexAcpSpawnCommand(command, sessionMode, agentConfig)
39337
- };
39338
- }
39339
- if (useKiroAcp(preferredAgentType, command)) {
39340
- return {
39341
- command,
39342
- label: preferredAgentType,
39343
- createClient: createKiroAcpClient,
39344
- spawnCommandForSession: (sessionMode, _agentConfig) => buildKiroAcpSpawnCommand(command, sessionMode)
39345
- };
39346
- }
39492
+ const provider = getAgentProvider(preferredAgentType);
39493
+ if (!provider?.createClient || provider.defaultCommand.length === 0) return null;
39494
+ const command = [...provider.defaultCommand];
39347
39495
  return {
39348
39496
  command,
39349
- label: preferredAgentType,
39350
- createClient: createClaudeCodeAcpClient,
39351
- spawnCommandForSession: (sessionMode) => buildClaudeCodeAcpSpawnCommand(command, sessionMode)
39497
+ label: provider.type,
39498
+ createClient: provider.createClient,
39499
+ spawnCommandForSession: (sessionMode, agentConfig) => provider.buildSpawnCommand(command, sessionMode, agentConfig)
39352
39500
  };
39353
39501
  }
39502
+ function getAgentTypeDisplayName(agentType) {
39503
+ if (agentType == null || agentType === "") return "Unknown agent";
39504
+ const known = getAgentProvider(agentType)?.displayName;
39505
+ if (known) return known;
39506
+ return agentType.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
39507
+ }
39354
39508
 
39355
39509
  // ../bridge/src/agents/acp/session-file-change-path-kind.ts
39356
39510
  import { existsSync as existsSync4, statSync } from "node:fs";
39357
39511
 
39358
39512
  // ../bridge/src/git/git-exec.ts
39359
- import { execFile as execFile2, execFileSync as execFileSync2, spawn as spawn3 } from "node:child_process";
39513
+ import { execFile as execFile2, execFileSync as execFileSync2, spawn as spawn4 } from "node:child_process";
39360
39514
  import { promisify as promisify3 } from "node:util";
39361
39515
 
39362
39516
  // ../bridge/src/git/git-runtime.ts
@@ -40490,7 +40644,7 @@ async function ensureAcpClient(options) {
40490
40644
  if (!state.acpStartPromise) {
40491
40645
  let statOk = false;
40492
40646
  try {
40493
- const st = await fs18.promises.stat(targetSessionParentPath);
40647
+ const st = await fs19.promises.stat(targetSessionParentPath);
40494
40648
  statOk = st.isDirectory();
40495
40649
  if (!statOk) {
40496
40650
  state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
@@ -40962,18 +41116,6 @@ function reportPostTurnEnrichment(options) {
40962
41116
  });
40963
41117
  }
40964
41118
 
40965
- // ../bridge/src/agents/acp/clients/cursor/cleanup-session-plans.ts
40966
- import * as fs19 from "node:fs";
40967
- function cleanupSessionPlans(sessionId) {
40968
- const id = typeof sessionId === "string" ? sessionId.trim() : "";
40969
- if (!id) return;
40970
- const dir = getSessionPlansDir(id);
40971
- try {
40972
- fs19.rmSync(dir, { recursive: true, force: true });
40973
- } catch {
40974
- }
40975
- }
40976
-
40977
41119
  // ../bridge/src/agents/acp/prompts/finalize-and-send-prompt-result.ts
40978
41120
  async function finalizeAndSendPromptResult(params) {
40979
41121
  const {
@@ -40990,7 +41132,7 @@ async function finalizeAndSendPromptResult(params) {
40990
41132
  sendSessionUpdate,
40991
41133
  log: log2
40992
41134
  } = params;
40993
- cleanupSessionPlans(sessionId);
41135
+ notifyAgentProvidersPromptTurnFinished(sessionId);
40994
41136
  const planningTodosSubmit = isPlanningSession && plugin?.cloud?.maybeSubmitPlanningTodos ? await plugin.cloud.maybeSubmitPlanningTodos({
40995
41137
  sessionId,
40996
41138
  runId,
@@ -41714,7 +41856,7 @@ async function loadOrCreateE2eCertificates(directory) {
41714
41856
  }
41715
41857
 
41716
41858
  // ../bridge/src/e2ee/key-command.ts
41717
- import * as readline2 from "node:readline";
41859
+ import * as readline3 from "node:readline";
41718
41860
  function installE2eCertificateKeyCommand({
41719
41861
  log: log2,
41720
41862
  onOpenCertificate,
@@ -41725,7 +41867,7 @@ function installE2eCertificateKeyCommand({
41725
41867
  return () => {
41726
41868
  };
41727
41869
  }
41728
- readline2.emitKeypressEvents(process.stdin);
41870
+ readline3.emitKeypressEvents(process.stdin);
41729
41871
  process.stdin.setRawMode(true);
41730
41872
  process.stdin.resume();
41731
41873
  const onKeypress = (str, key) => {
@@ -41900,25 +42042,20 @@ import * as path36 from "node:path";
41900
42042
  // ../bridge/src/agents/detect-local-agent-types.ts
41901
42043
  init_yield_to_event_loop();
41902
42044
  init_cli_process_interrupt();
41903
- var LOCAL_AGENT_ACP_MODULES = [
41904
- cursor_acp_client_exports,
41905
- codex_acp_client_exports,
41906
- kiro_acp_client_exports,
41907
- claude_code_acp_client_exports
41908
- ];
41909
42045
  async function detectLocalAgentTypes() {
41910
42046
  try {
41911
42047
  if (isCliImmediateShutdownRequested()) return [];
42048
+ const providers = listAutoDetectAgentProviders();
41912
42049
  const out = [];
41913
- for (let i = 0; i < LOCAL_AGENT_ACP_MODULES.length; i++) {
42050
+ for (let i = 0; i < providers.length; i++) {
41914
42051
  if (isCliImmediateShutdownRequested()) return out;
41915
42052
  if (i > 0) {
41916
42053
  await yieldToEventLoop();
41917
42054
  if (isCliImmediateShutdownRequested()) return out;
41918
42055
  }
41919
- const mod = LOCAL_AGENT_ACP_MODULES[i];
42056
+ const provider = providers[i];
41920
42057
  try {
41921
- if (await mod.detectLocalAgentPresence()) out.push(mod.BACKEND_LOCAL_AGENT_TYPE);
42058
+ if (await provider.detectPresence?.()) out.push(provider.type);
41922
42059
  } catch {
41923
42060
  }
41924
42061
  }
@@ -42913,7 +43050,7 @@ function pipedStdoutStderrFor(attemptStdio) {
42913
43050
  }
42914
43051
 
42915
43052
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-piped-via-sh.ts
42916
- import { spawn as spawn4 } from "node:child_process";
43053
+ import { spawn as spawn5 } from "node:child_process";
42917
43054
  function trySpawnPipedViaSh(command, env, cwd, signal, lifecycle) {
42918
43055
  const attempts = [
42919
43056
  { stdio: [devNullReadFd(), "pipe", "pipe"], endStdin: false },
@@ -42937,9 +43074,9 @@ function trySpawnPipedViaSh(command, env, cwd, signal, lifecycle) {
42937
43074
  if (process.platform === "win32") {
42938
43075
  opts.windowsHide = true;
42939
43076
  const com = process.env.ComSpec || "cmd.exe";
42940
- proc = spawn4(com, ["/d", "/s", "/c", command], opts);
43077
+ proc = spawn5(com, ["/d", "/s", "/c", command], opts);
42941
43078
  } else {
42942
- proc = spawn4("/bin/sh", ["-c", command], opts);
43079
+ proc = spawn5("/bin/sh", ["-c", command], opts);
42943
43080
  }
42944
43081
  if (attempt.endStdin) {
42945
43082
  proc.stdin?.end();
@@ -42959,7 +43096,7 @@ function trySpawnPipedViaSh(command, env, cwd, signal, lifecycle) {
42959
43096
  }
42960
43097
 
42961
43098
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-shell-true-piped.ts
42962
- import { spawn as spawn5 } from "node:child_process";
43099
+ import { spawn as spawn6 } from "node:child_process";
42963
43100
  function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal, lifecycle) {
42964
43101
  try {
42965
43102
  const opts = mergePreviewEnvironmentSpawnOptions(
@@ -42975,7 +43112,7 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal, lifecycle)
42975
43112
  if (process.platform === "win32") {
42976
43113
  opts.windowsHide = true;
42977
43114
  }
42978
- return spawn5(command, opts);
43115
+ return spawn6(command, opts);
42979
43116
  } catch (e) {
42980
43117
  if (isSpawnEbadf(e)) return null;
42981
43118
  throw e;
@@ -42983,7 +43120,7 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal, lifecycle)
42983
43120
  }
42984
43121
 
42985
43122
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-merged-log-file.ts
42986
- import { spawn as spawn6 } from "node:child_process";
43123
+ import { spawn as spawn7 } from "node:child_process";
42987
43124
  import fs24 from "node:fs";
42988
43125
  import { tmpdir } from "node:os";
42989
43126
  import path37 from "node:path";
@@ -43001,7 +43138,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal, lifecycle) {
43001
43138
  try {
43002
43139
  let proc;
43003
43140
  if (process.platform === "win32") {
43004
- proc = spawn6(
43141
+ proc = spawn7(
43005
43142
  process.env.ComSpec || "cmd.exe",
43006
43143
  ["/d", "/s", "/c", command],
43007
43144
  mergePreviewEnvironmentSpawnOptions(
@@ -43010,7 +43147,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal, lifecycle) {
43010
43147
  )
43011
43148
  );
43012
43149
  } else {
43013
- proc = spawn6(
43150
+ proc = spawn7(
43014
43151
  "/bin/sh",
43015
43152
  ["-c", command],
43016
43153
  mergePreviewEnvironmentSpawnOptions({ env, cwd, stdio, ...signal ? { signal } : {} }, lifecycle)
@@ -43035,7 +43172,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal, lifecycle) {
43035
43172
  }
43036
43173
 
43037
43174
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
43038
- import { spawn as spawn7 } from "node:child_process";
43175
+ import { spawn as spawn8 } from "node:child_process";
43039
43176
  import fs25 from "node:fs";
43040
43177
  import { tmpdir as tmpdir2 } from "node:os";
43041
43178
  import path38 from "node:path";
@@ -43058,7 +43195,7 @@ cd ${shSingleQuote(cwd)}
43058
43195
  /bin/sh ${shSingleQuote(innerPath)} >>${shSingleQuote(logPath)} 2>&1
43059
43196
  `
43060
43197
  );
43061
- const proc = spawn7(
43198
+ const proc = spawn8(
43062
43199
  "/bin/sh",
43063
43200
  [runnerPath],
43064
43201
  mergePreviewEnvironmentSpawnOptions(
@@ -43092,7 +43229,7 @@ CD /D ${q(cwd)}\r
43092
43229
  ${command} >> ${q(logPath)} 2>&1\r
43093
43230
  `
43094
43231
  );
43095
- const proc = spawn7(
43232
+ const proc = spawn8(
43096
43233
  com,
43097
43234
  ["/d", "/s", "/c", q(runnerPath)],
43098
43235
  mergePreviewEnvironmentSpawnOptions(
@@ -43114,7 +43251,7 @@ ${command} >> ${q(logPath)} 2>&1\r
43114
43251
  }
43115
43252
 
43116
43253
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-inherit.ts
43117
- import { spawn as spawn8 } from "node:child_process";
43254
+ import { spawn as spawn9 } from "node:child_process";
43118
43255
  function trySpawnInheritStdio(command, env, cwd, signal, lifecycle) {
43119
43256
  const opts = mergePreviewEnvironmentSpawnOptions(
43120
43257
  {
@@ -43129,9 +43266,9 @@ function trySpawnInheritStdio(command, env, cwd, signal, lifecycle) {
43129
43266
  if (process.platform === "win32") {
43130
43267
  opts.windowsHide = true;
43131
43268
  const com = process.env.ComSpec || "cmd.exe";
43132
- proc = spawn8(com, ["/d", "/s", "/c", command], opts);
43269
+ proc = spawn9(com, ["/d", "/s", "/c", command], opts);
43133
43270
  } else {
43134
- proc = spawn8("/bin/sh", ["-c", command], opts);
43271
+ proc = spawn9("/bin/sh", ["-c", command], opts);
43135
43272
  }
43136
43273
  return { proc, pipedStdoutStderr: false };
43137
43274
  }
@@ -43606,7 +43743,7 @@ function createBridgeHeartbeatController(params) {
43606
43743
  }
43607
43744
 
43608
43745
  // ../bridge/src/cli/cli-version.ts
43609
- var CLI_VERSION2 = "0.1.90".length > 0 ? "0.1.90" : "0.0.0-dev";
43746
+ var CLI_VERSION2 = "0.1.91".length > 0 ? "0.1.91" : "0.0.0-dev";
43610
43747
 
43611
43748
  // ../bridge/src/connection/identify/send-bridge-identify.ts
43612
43749
  function sendBridgeIdentify(ws, params) {
@@ -43882,7 +44019,7 @@ var import_debug = __toESM(require_src(), 1);
43882
44019
  var import_promise_deferred = __toESM(require_dist2(), 1);
43883
44020
  var import_promise_deferred2 = __toESM(require_dist2(), 1);
43884
44021
  import { Buffer as Buffer2 } from "node:buffer";
43885
- import { spawn as spawn9 } from "child_process";
44022
+ import { spawn as spawn10 } from "child_process";
43886
44023
  import { normalize as normalize3 } from "node:path";
43887
44024
  import { EventEmitter } from "node:events";
43888
44025
  var __defProp2 = Object.defineProperty;
@@ -45270,7 +45407,7 @@ var init_git_executor_chain = __esm2({
45270
45407
  rejection = reason || rejection;
45271
45408
  }
45272
45409
  });
45273
- const spawned = spawn9(command, args, spawnOptions);
45410
+ const spawned = spawn10(command, args, spawnOptions);
45274
45411
  spawned.stdout.on(
45275
45412
  "data",
45276
45413
  onDataReceived(stdOut, "stdOut", logger, outputLogger.step("stdOut"))
@@ -48873,7 +49010,7 @@ import * as path43 from "node:path";
48873
49010
 
48874
49011
  // ../bridge/src/git/changes/lines/count-lines.ts
48875
49012
  import { createReadStream } from "node:fs";
48876
- import * as readline3 from "node:readline";
49013
+ import * as readline4 from "node:readline";
48877
49014
  function countLinesInText(text) {
48878
49015
  return splitTextIntoDiffLines(text).length;
48879
49016
  }
@@ -48882,7 +49019,7 @@ async function countTextFileLines(filePath) {
48882
49019
  const maxBytes = 512e3;
48883
49020
  let lines = 0;
48884
49021
  const stream = createReadStream(filePath, { encoding: "utf8" });
48885
- const rl = readline3.createInterface({ input: stream, crlfDelay: Infinity });
49022
+ const rl = readline4.createInterface({ input: stream, crlfDelay: Infinity });
48886
49023
  for await (const _line of rl) {
48887
49024
  lines += 1;
48888
49025
  bytes += Buffer.byteLength(String(_line), "utf8") + 1;
@@ -53534,159 +53671,24 @@ var handleInstalledAgentAuthSync = (msg) => {
53534
53671
  );
53535
53672
  };
53536
53673
 
53537
- // ../bridge/src/agents/install/run-streaming-command.ts
53538
- import { spawn as spawn10 } from "node:child_process";
53539
- import * as readline4 from "node:readline";
53540
- function runStreamingCommand(command, args, options) {
53541
- return new Promise((resolve39, reject) => {
53542
- const child = spawn10(command, args, {
53543
- env: options.env,
53544
- stdio: ["ignore", "pipe", "pipe"]
53545
- });
53546
- let settled = false;
53547
- const timer = options.timeoutMs != null ? setTimeout(() => {
53548
- child.kill("SIGKILL");
53549
- if (!settled) {
53550
- settled = true;
53551
- reject(new Error(`Command timed out after ${options.timeoutMs}ms`));
53552
- }
53553
- }, options.timeoutMs) : null;
53554
- const onLine = (line) => {
53555
- if (line.length > 0) options.onLine?.(line);
53556
- };
53557
- if (child.stdout) {
53558
- readline4.createInterface({ input: child.stdout, crlfDelay: Infinity }).on("line", onLine);
53559
- }
53560
- if (child.stderr) {
53561
- readline4.createInterface({ input: child.stderr, crlfDelay: Infinity }).on("line", onLine);
53562
- }
53563
- child.on("error", (err) => {
53564
- if (timer) clearTimeout(timer);
53565
- if (!settled) {
53566
- settled = true;
53567
- reject(err);
53568
- }
53569
- });
53570
- child.on("close", (code, signal) => {
53571
- if (timer) clearTimeout(timer);
53572
- if (!settled) {
53573
- settled = true;
53574
- resolve39({ code, signal });
53575
- }
53576
- });
53577
- });
53578
- }
53579
-
53580
- // ../bridge/src/agents/install/commands/run-npm-global-install.ts
53581
- async function runNpmGlobalInstall(packageName, env, options) {
53582
- const result = await runStreamingCommand("npm", ["install", "-g", packageName], {
53583
- env: bridgeAgentPathEnv(env),
53584
- timeoutMs: options?.timeoutMs ?? 3e5,
53585
- onLine: options?.onLine
53586
- });
53587
- if (result.code !== 0) {
53588
- throw new Error(`npm install -g ${packageName} failed (exit ${result.code ?? "signal"})`);
53589
- }
53590
- }
53591
-
53592
- // ../bridge/src/agents/install/commands/claude-code.ts
53593
- var claudeCodeInstallCommand = {
53594
- agentType: "claude-code",
53595
- detectCommand: "claude",
53596
- async install(ctx) {
53597
- ctx.onProgress?.("Installing Anthropic Claude Code");
53598
- await runNpmGlobalInstall(
53599
- "@anthropic-ai/claude-code",
53600
- { ...ctx.env, ANTHROPIC_API_KEY: ctx.authToken },
53601
- { onLine: (line) => ctx.onProgress?.("Installing Anthropic Claude Code", line) }
53602
- );
53603
- }
53604
- };
53605
-
53606
- // ../bridge/src/agents/install/commands/codex-acp.ts
53607
- var codexAcpInstallCommand = {
53608
- agentType: "codex-acp",
53609
- detectCommand: "codex",
53610
- async install(ctx) {
53611
- ctx.onProgress?.("Installing Codex");
53612
- await runNpmGlobalInstall(
53613
- "@openai/codex",
53614
- { ...ctx.env, OPENAI_API_KEY: ctx.authToken },
53615
- { onLine: (line) => ctx.onProgress?.("Installing Codex", line) }
53616
- );
53617
- }
53618
- };
53619
-
53620
- // ../bridge/src/agents/install/commands/cursor-cli.ts
53621
- var cursorCliInstallCommand = {
53622
- agentType: "cursor-cli",
53623
- detectCommand: "agent",
53624
- alternateDetectCommands: ["cursor-agent"],
53625
- async install(ctx) {
53626
- ctx.onProgress?.("Installing Cursor CLI");
53627
- const result = await runStreamingCommand(
53628
- "bash",
53629
- ["-lc", "curl -fsSL https://cursor.com/install | bash"],
53630
- {
53631
- timeoutMs: 3e5,
53632
- env: { ...bridgeAgentPathEnv(ctx.env), CURSOR_API_KEY: ctx.authToken },
53633
- onLine: (line) => ctx.onProgress?.("Installing Cursor CLI", line)
53634
- }
53635
- );
53636
- if (result.code !== 0) {
53637
- throw new Error(`Cursor CLI install failed (exit ${result.code ?? "signal"})`);
53638
- }
53639
- }
53640
- };
53641
-
53642
- // ../bridge/src/agents/install/commands/opencode.ts
53643
- var opencodeInstallCommand = {
53644
- agentType: "opencode",
53645
- detectCommand: "opencode",
53646
- async install(ctx) {
53647
- ctx.onProgress?.("Installing OpenCode");
53648
- await runNpmGlobalInstall(
53649
- "opencode-ai",
53650
- { ...ctx.env, OPENCODE_API_KEY: ctx.authToken },
53651
- { onLine: (line) => ctx.onProgress?.("Installing OpenCode", line) }
53652
- );
53653
- }
53654
- };
53655
-
53656
- // ../bridge/src/agents/install/commands/index.ts
53657
- var COMMANDS = [
53658
- claudeCodeInstallCommand,
53659
- codexAcpInstallCommand,
53660
- cursorCliInstallCommand,
53661
- opencodeInstallCommand
53662
- ];
53663
- var byType = new Map(COMMANDS.map((c) => [c.agentType, c]));
53664
- function getAgentInstallCommand(agentType) {
53665
- return byType.get(agentType);
53666
- }
53667
-
53668
53674
  // ../bridge/src/agents/install/install-local-agent.ts
53669
53675
  async function installLocalAgentOnBridge(params) {
53670
- const spec = INSTALLABLE_BRIDGE_AGENTS.find((a) => a.value === params.agentType);
53671
- if (!spec) return { success: false, error: `Unsupported agent type: ${params.agentType}` };
53672
- const command = getAgentInstallCommand(params.agentType);
53673
- if (!command) return { success: false, error: `No install command for ${params.agentType}` };
53674
- params.onProgress?.(`Configuring ${spec.label} credentials`);
53676
+ const provider = getAgentProvider(params.agentType);
53677
+ const install = provider?.install;
53678
+ if (!provider || !install) return { success: false, error: `Unsupported agent type: ${params.agentType}` };
53679
+ params.onProgress?.(`Configuring ${provider.displayName} credentials`);
53675
53680
  try {
53676
- await command.install({
53681
+ await install.run({
53677
53682
  authToken: params.authToken,
53678
53683
  onProgress: params.onProgress,
53679
- env: { ...process.env, [spec.tokenEnvVar]: params.authToken }
53684
+ env: { ...process.env, [install.tokenEnvVar]: params.authToken }
53680
53685
  });
53681
53686
  } catch (e) {
53682
53687
  const msg = e instanceof Error ? e.message : String(e);
53683
53688
  return { success: false, error: msg };
53684
53689
  }
53685
53690
  ensureBridgeAgentPathInProcessEnv();
53686
- const detectNames = [
53687
- command.detectCommand,
53688
- ...command.alternateDetectCommands ?? []
53689
- ];
53691
+ const detectNames = [install.detectCommand, ...install.alternateDetectCommands ?? []];
53690
53692
  let found = false;
53691
53693
  for (const name of detectNames) {
53692
53694
  if (await waitForCommandOnPath(name)) {
@@ -53695,7 +53697,7 @@ async function installLocalAgentOnBridge(params) {
53695
53697
  }
53696
53698
  }
53697
53699
  if (!found) {
53698
- return { success: false, error: `${command.detectCommand} not found on PATH after install` };
53700
+ return { success: false, error: `${install.detectCommand} not found on PATH after install` };
53699
53701
  }
53700
53702
  return { success: true };
53701
53703
  }
@@ -54853,7 +54855,7 @@ var handleRenameSessionBranchMessage = (msg, deps) => {
54853
54855
  var handleSessionArchivedMessage = (msg, deps) => {
54854
54856
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
54855
54857
  if (!sessionId) return;
54856
- cleanupSessionPlans(sessionId);
54858
+ notifyAgentProvidersSessionClosed(sessionId);
54857
54859
  void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
54858
54860
  };
54859
54861
 
@@ -54861,7 +54863,7 @@ var handleSessionArchivedMessage = (msg, deps) => {
54861
54863
  var handleSessionDiscardedMessage = (msg, deps) => {
54862
54864
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
54863
54865
  if (!sessionId) return;
54864
- cleanupSessionPlans(sessionId);
54866
+ notifyAgentProvidersSessionClosed(sessionId);
54865
54867
  void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
54866
54868
  };
54867
54869