@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/index.js CHANGED
@@ -26563,7 +26563,6 @@ async function delayMsUnlessShutdownRequested(ms) {
26563
26563
  var cliImmediateShutdownRequested, symbolIndexShutdownPromise;
26564
26564
  var init_cli_process_interrupt = __esm({
26565
26565
  "../bridge/src/cli/teardown/cli-process-interrupt.ts"() {
26566
- "use strict";
26567
26566
  cliImmediateShutdownRequested = false;
26568
26567
  symbolIndexShutdownPromise = null;
26569
26568
  }
@@ -27773,29 +27772,50 @@ function forceAcpSubprocessDisconnect(child) {
27773
27772
  killChildProcessTree(child, "SIGKILL");
27774
27773
  }
27775
27774
 
27776
- // ../bridge/src/agents/local-agent-auth.ts
27777
- var LOCAL_AGENT_AUTH_ERROR_HINTS = {
27778
- "kiro-acp": [/not logged in/i, /kiro-cli\s+login/i, /log in with kiro-cli/i],
27779
- "cursor-cli": [/cursor_login/i, /authenticate.*cursor/i, /not logged in.*cursor/i, /run:\s*agent\s+login/i],
27780
- "codex-acp": [
27781
- /authentication failed/i,
27782
- /not authenticated/i,
27783
- /invalid.*api key/i,
27784
- /sign in.*openai/i,
27785
- /login.*openai/i,
27786
- /unauthorized/i
27787
- ],
27788
- "claude-code": [
27789
- /ANTHROPIC_API_KEY/i,
27790
- /not authenticated/i,
27791
- /authentication failed/i,
27792
- /claude\s+login/i,
27793
- /please run.*claude.*login/i
27794
- ]
27775
+ // ../bridge/src/agents/providers/claude-code/auth.ts
27776
+ var claudeCodeAuthErrorHints = [
27777
+ /ANTHROPIC_API_KEY/i,
27778
+ /not authenticated/i,
27779
+ /authentication failed/i,
27780
+ /claude\s+login/i,
27781
+ /please run.*claude.*login/i
27782
+ ];
27783
+
27784
+ // ../bridge/src/agents/providers/codex/auth.ts
27785
+ var codexAuthErrorHints = [
27786
+ /authentication failed/i,
27787
+ /not authenticated/i,
27788
+ /invalid.*api key/i,
27789
+ /sign in.*openai/i,
27790
+ /login.*openai/i,
27791
+ /unauthorized/i
27792
+ ];
27793
+
27794
+ // ../bridge/src/agents/providers/cursor/auth.ts
27795
+ var cursorAuthErrorHints = [
27796
+ /cursor_login/i,
27797
+ /authenticate.*cursor/i,
27798
+ /not logged in.*cursor/i,
27799
+ /run:\s*agent\s+login/i
27800
+ ];
27801
+
27802
+ // ../bridge/src/agents/providers/kiro/auth.ts
27803
+ var kiroAuthErrorHints = [
27804
+ /not logged in/i,
27805
+ /kiro-cli\s+login/i,
27806
+ /log in with kiro-cli/i
27807
+ ];
27808
+
27809
+ // ../bridge/src/agents/providers/auth.ts
27810
+ var AUTH_ERROR_HINTS = {
27811
+ "claude-code": claudeCodeAuthErrorHints,
27812
+ "codex-acp": codexAuthErrorHints,
27813
+ "cursor-cli": cursorAuthErrorHints,
27814
+ "kiro-acp": kiroAuthErrorHints
27795
27815
  };
27796
27816
  function localAgentErrorSuggestsAuth(agentType, errorText) {
27797
27817
  if (agentType == null || agentType === "" || errorText == null || !String(errorText).trim()) return false;
27798
- const hints = LOCAL_AGENT_AUTH_ERROR_HINTS[agentType];
27818
+ const hints = AUTH_ERROR_HINTS[agentType];
27799
27819
  if (!hints?.length) return false;
27800
27820
  return hints.some((re) => re.test(String(errorText)));
27801
27821
  }
@@ -32988,34 +33008,11 @@ function flattenSdkSessionNotificationParams(params) {
32988
33008
  return { sessionId: params.sessionId, ...params.update };
32989
33009
  }
32990
33010
 
32991
- // ../bridge/src/agents/acp/clients/kiro-sdk-ext-notifications.ts
32992
- function createKiroSdkExtNotificationHandler(options) {
32993
- const { onSessionUpdate } = options;
32994
- return async (method, params) => {
32995
- if (method === "_kiro.dev/metadata") {
32996
- const p = params && typeof params === "object" ? params : {};
32997
- const pct = p.contextUsagePercentage;
32998
- if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
32999
- onSessionUpdate({
33000
- sessionUpdate: "context_usage",
33001
- contextUsagePercentage: pct
33002
- });
33003
- return;
33004
- }
33005
- };
33006
- }
33007
-
33008
33011
  // ../bridge/src/agents/acp/clients/sdk/sdk-stdio-ext-notifications.ts
33009
33012
  var noopExtNotification = async () => {
33010
33013
  };
33011
- function createSdkStdioExtNotificationHandler(options) {
33012
- const { backendAgentType, onSessionUpdate } = options;
33013
- switch (backendAgentType) {
33014
- case "kiro-acp":
33015
- return createKiroSdkExtNotificationHandler({ onSessionUpdate });
33016
- default:
33017
- return noopExtNotification;
33018
- }
33014
+ function createSdkStdioExtNotificationHandler(_options) {
33015
+ return noopExtNotification;
33019
33016
  }
33020
33017
 
33021
33018
  // ../bridge/src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
@@ -33049,11 +33046,8 @@ function resolvePendingSdkStdioPermissionCancellations(pending2) {
33049
33046
 
33050
33047
  // ../bridge/src/agents/acp/clients/sdk/sdk-stdio-connection-client.ts
33051
33048
  function createSdkStdioConnectionClient(deps) {
33052
- const { backendAgentType, onSessionUpdate, onRequest, sessionCtx, pendingPermissionReplies } = deps;
33053
- const extNotification = createSdkStdioExtNotificationHandler({
33054
- backendAgentType,
33055
- onSessionUpdate
33056
- });
33049
+ const { onSessionUpdate, onRequest, sessionCtx, pendingPermissionReplies, createExtNotificationHandler } = deps;
33050
+ const extNotification = createExtNotificationHandler?.({ onSessionUpdate }) ?? createSdkStdioExtNotificationHandler({ onSessionUpdate });
33057
33051
  let permissionSeq = 0;
33058
33052
  return (_agent) => ({
33059
33053
  async requestPermission(params) {
@@ -33165,121 +33159,16 @@ function createSdkStdioSessionContext(options) {
33165
33159
  onAcpSessionEstablished: options.onAcpSessionEstablished,
33166
33160
  onAcpConfigOptionsUpdated: options.onAcpConfigOptionsUpdated,
33167
33161
  logDebug,
33168
- getStderrText: () => options.stderrCapture.getText()
33162
+ getStderrText: () => options.stderrCapture.getText(),
33163
+ afterSessionEstablished: options.afterSessionEstablished
33169
33164
  };
33170
33165
  }
33171
33166
 
33172
33167
  // ../bridge/src/agents/acp/clients/sdk/sdk-stdio-bootstrap-connection.ts
33173
33168
  import { Readable, Writable } from "node:stream";
33174
33169
 
33175
- // ../bridge/src/agents/acp/claude-acp-permission-from-session.ts
33176
- function flattenSelectOptions(options) {
33177
- if (options == null || options.length === 0) return [];
33178
- const first2 = options[0];
33179
- if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
33180
- return options.flatMap(
33181
- (g) => Array.isArray(g.options) ? g.options : []
33182
- );
33183
- }
33184
- return options;
33185
- }
33186
- function pickModeConfigOption(configOptions) {
33187
- if (configOptions == null || configOptions.length === 0) return null;
33188
- const byCategory = configOptions.find((o) => o.category === "mode");
33189
- if (byCategory) return byCategory;
33190
- return configOptions.find((o) => o.id === "mode") ?? null;
33191
- }
33192
- async function applyClaudePermissionFromAcpSession(params) {
33193
- const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
33194
- const desiredMode = getClaudePermissionModeFromAgentConfig(agentConfig);
33195
- if (desiredMode == null) return;
33196
- const modeOpt = pickModeConfigOption(configOptions ?? null);
33197
- if (modeOpt != null) {
33198
- const flat = flattenSelectOptions(modeOpt.options);
33199
- const allowed = flat.some((o) => o.value === desiredMode);
33200
- if (allowed && modeOpt.currentValue !== desiredMode) {
33201
- try {
33202
- logDebug2(
33203
- `[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`
33204
- );
33205
- await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
33206
- } catch (e) {
33207
- logDebug2(
33208
- `[Agent] Claude Code: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`
33209
- );
33210
- }
33211
- }
33212
- return;
33213
- }
33214
- if (modes?.availableModes?.length) {
33215
- const allowed = modes.availableModes.some((m) => m.id === desiredMode);
33216
- if (allowed && desiredMode !== modes.currentModeId) {
33217
- try {
33218
- logDebug2(
33219
- `[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`
33220
- );
33221
- await setSessionMode({ sessionId, modeId: desiredMode });
33222
- } catch (e) {
33223
- logDebug2(`[Agent] Claude Code: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
33224
- }
33225
- }
33226
- }
33227
- }
33228
-
33229
- // ../bridge/src/agents/acp/codex-acp-permission-from-session.ts
33230
- function flattenSelectOptions2(options) {
33231
- if (options == null || options.length === 0) return [];
33232
- const first2 = options[0];
33233
- if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
33234
- return options.flatMap(
33235
- (g) => Array.isArray(g.options) ? g.options : []
33236
- );
33237
- }
33238
- return options;
33239
- }
33240
- function pickModeConfigOption2(configOptions) {
33241
- if (configOptions == null || configOptions.length === 0) return null;
33242
- const byCategory = configOptions.find((o) => o.category === "mode");
33243
- if (byCategory) return byCategory;
33244
- return configOptions.find((o) => o.id === "mode") ?? null;
33245
- }
33246
- async function applyCodexPermissionFromAcpSession(params) {
33247
- const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
33248
- const desiredMode = getCodexPermissionModeFromAgentConfig(agentConfig);
33249
- if (desiredMode == null) return;
33250
- const modeOpt = pickModeConfigOption2(configOptions ?? null);
33251
- if (modeOpt != null) {
33252
- const flat = flattenSelectOptions2(modeOpt.options);
33253
- const allowed = flat.some((o) => o.value === desiredMode);
33254
- if (allowed && modeOpt.currentValue !== desiredMode) {
33255
- try {
33256
- logDebug2(
33257
- `[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`
33258
- );
33259
- await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
33260
- } catch (e) {
33261
- logDebug2(`[Agent] Codex: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`);
33262
- }
33263
- }
33264
- return;
33265
- }
33266
- if (modes?.availableModes?.length) {
33267
- const allowed = modes.availableModes.some((m) => m.id === desiredMode);
33268
- if (allowed && desiredMode !== modes.currentModeId) {
33269
- try {
33270
- logDebug2(
33271
- `[Agent] Codex: sending ACP session/set_mode modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
33272
- );
33273
- await setSessionMode({ sessionId, modeId: desiredMode });
33274
- } catch (e) {
33275
- logDebug2(`[Agent] Codex: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
33276
- }
33277
- }
33278
- }
33279
- }
33280
-
33281
33170
  // ../bridge/src/agents/acp/apply-acp-model-from-agent-session.ts
33282
- function flattenSelectOptions3(options) {
33171
+ function flattenSelectOptions(options) {
33283
33172
  if (options == null || options.length === 0) return [];
33284
33173
  const first2 = options[0];
33285
33174
  if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
@@ -33304,7 +33193,7 @@ async function applyAcpModelFromAcpSession(params) {
33304
33193
  if (desired == null) return;
33305
33194
  const modelOpt = pickModelConfigOption(configOptions ?? null);
33306
33195
  if (modelOpt == null) return;
33307
- const flat = flattenSelectOptions3(modelOpt.options);
33196
+ const flat = flattenSelectOptions(modelOpt.options);
33308
33197
  const allowed = flat.some((o) => o.value === desired);
33309
33198
  if (!allowed) return;
33310
33199
  if (modelOpt.currentValue === desired) return;
@@ -33426,38 +33315,13 @@ async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
33426
33315
  configOptions: established.configOptions,
33427
33316
  modes: established.modes
33428
33317
  });
33429
- if (ctx.backendAgentType === "claude-code") {
33430
- const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
33431
- const configOptionsTyped = established.configOptions;
33432
- const modesTyped = established.modes;
33433
- await applyClaudePermissionFromAcpSession({
33434
- sessionId,
33435
- agentConfig: cfg,
33436
- configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
33437
- modes: modesTyped,
33438
- setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
33439
- },
33440
- setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
33441
- },
33442
- logDebug: ctx.logDebug
33443
- });
33444
- }
33445
- if (ctx.backendAgentType === "codex-acp") {
33446
- const cfg = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
33447
- const configOptionsTyped = established.configOptions;
33448
- const modesTyped = established.modes;
33449
- await applyCodexPermissionFromAcpSession({
33450
- sessionId,
33451
- agentConfig: cfg,
33452
- configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsTyped),
33453
- modes: modesTyped,
33454
- setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
33455
- },
33456
- setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
33457
- },
33458
- logDebug: ctx.logDebug
33459
- });
33460
- }
33318
+ await ctx.afterSessionEstablished?.({
33319
+ sessionId,
33320
+ transport,
33321
+ ctx,
33322
+ configOptions: established.configOptions,
33323
+ modes: established.modes
33324
+ });
33461
33325
  const cfgAll = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
33462
33326
  const configOptionsForModel = established.configOptions;
33463
33327
  if (transport.setSessionConfigOption) {
@@ -33510,7 +33374,8 @@ async function bootstrapSdkStdioConnection(options) {
33510
33374
  onSessionUpdate: options.onSessionUpdate,
33511
33375
  onRequest: options.onRequest,
33512
33376
  sessionCtx: options.sessionCtx,
33513
- pendingPermissionReplies: options.pendingPermissionReplies
33377
+ pendingPermissionReplies: options.pendingPermissionReplies,
33378
+ createExtNotificationHandler: options.createExtNotificationHandler
33514
33379
  });
33515
33380
  const connection = new ClientSideConnection2(client, stream);
33516
33381
  connection.signal.addEventListener("abort", () => {
@@ -33610,7 +33475,9 @@ async function createSdkStdioAcpClient(options) {
33610
33475
  persistedAcpSessionId,
33611
33476
  onAcpSessionEstablished,
33612
33477
  onAcpConfigOptionsUpdated,
33613
- getActiveConfigOptions
33478
+ getActiveConfigOptions,
33479
+ afterSessionEstablished,
33480
+ createExtNotificationHandler
33614
33481
  } = options;
33615
33482
  const { child, stderrCapture } = spawnSdkStdioProcess({
33616
33483
  command,
@@ -33627,6 +33494,7 @@ async function createSdkStdioAcpClient(options) {
33627
33494
  onAcpSessionEstablished,
33628
33495
  onAcpConfigOptionsUpdated,
33629
33496
  onFileChange,
33497
+ afterSessionEstablished,
33630
33498
  stderrCapture
33631
33499
  });
33632
33500
  return new Promise((resolve36, reject) => {
@@ -33651,7 +33519,8 @@ async function createSdkStdioAcpClient(options) {
33651
33519
  onSessionUpdate,
33652
33520
  onRequest,
33653
33521
  pendingPermissionReplies,
33654
- protocolVersion: PROTOCOL_VERSION2
33522
+ protocolVersion: PROTOCOL_VERSION2,
33523
+ createExtNotificationHandler
33655
33524
  });
33656
33525
  init.settleResolve(
33657
33526
  resolve36,
@@ -35311,7 +35180,7 @@ async function cancelRun(ctx, runId) {
35311
35180
  }
35312
35181
 
35313
35182
  // ../bridge/src/agents/acp/ensure-acp-client.ts
35314
- import * as fs18 from "node:fs";
35183
+ import * as fs19 from "node:fs";
35315
35184
  import * as path29 from "node:path";
35316
35185
 
35317
35186
  // ../bridge/src/paths/session-layout-paths.ts
@@ -35339,14 +35208,86 @@ function errorMessage(err) {
35339
35208
  return String(err);
35340
35209
  }
35341
35210
 
35342
- // ../bridge/src/agents/acp/clients/claude-code-acp-client.ts
35343
- var claude_code_acp_client_exports = {};
35344
- __export(claude_code_acp_client_exports, {
35345
- BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE,
35346
- buildClaudeCodeAcpSpawnCommand: () => buildClaudeCodeAcpSpawnCommand,
35347
- createClaudeCodeAcpClient: () => createClaudeCodeAcpClient,
35348
- detectLocalAgentPresence: () => detectLocalAgentPresence
35349
- });
35211
+ // ../bridge/src/agents/providers/claude-code/apply-permission.ts
35212
+ function flattenSelectOptions2(options) {
35213
+ if (options == null || options.length === 0) return [];
35214
+ const first2 = options[0];
35215
+ if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
35216
+ return options.flatMap(
35217
+ (g) => Array.isArray(g.options) ? g.options : []
35218
+ );
35219
+ }
35220
+ return options;
35221
+ }
35222
+ function pickModeConfigOption(configOptions) {
35223
+ if (configOptions == null || configOptions.length === 0) return null;
35224
+ const byCategory = configOptions.find((o) => o.category === "mode");
35225
+ if (byCategory) return byCategory;
35226
+ return configOptions.find((o) => o.id === "mode") ?? null;
35227
+ }
35228
+ async function applyClaudePermissionFromAcpSession(params) {
35229
+ const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
35230
+ const desiredMode = getClaudePermissionModeFromAgentConfig(agentConfig);
35231
+ if (desiredMode == null) return;
35232
+ const modeOpt = pickModeConfigOption(configOptions ?? null);
35233
+ if (modeOpt != null) {
35234
+ const flat = flattenSelectOptions2(modeOpt.options);
35235
+ const allowed = flat.some((o) => o.value === desiredMode);
35236
+ if (allowed && modeOpt.currentValue !== desiredMode) {
35237
+ try {
35238
+ logDebug2(
35239
+ `[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`
35240
+ );
35241
+ await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
35242
+ } catch (e) {
35243
+ logDebug2(
35244
+ `[Agent] Claude Code: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`
35245
+ );
35246
+ }
35247
+ }
35248
+ return;
35249
+ }
35250
+ if (modes?.availableModes?.length) {
35251
+ const allowed = modes.availableModes.some((m) => m.id === desiredMode);
35252
+ if (allowed && desiredMode !== modes.currentModeId) {
35253
+ try {
35254
+ logDebug2(
35255
+ `[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`
35256
+ );
35257
+ await setSessionMode({ sessionId, modeId: desiredMode });
35258
+ } catch (e) {
35259
+ logDebug2(`[Agent] Claude Code: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
35260
+ }
35261
+ }
35262
+ }
35263
+ }
35264
+
35265
+ // ../bridge/src/agents/providers/shared/wrap-permission-after-session.ts
35266
+ function wrapPermissionAfterSession(apply) {
35267
+ return async ({ sessionId, transport, ctx, configOptions, modes }) => {
35268
+ const raw = ctx.agentConfig;
35269
+ const agentConfig = raw != null && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
35270
+ await apply({
35271
+ sessionId,
35272
+ agentConfig,
35273
+ configOptions: configOptionsForPermission(
35274
+ ctx.getActiveConfigOptions,
35275
+ configOptions
35276
+ ),
35277
+ modes,
35278
+ setSessionConfigOption: transport.setSessionConfigOption ? (p) => transport.setSessionConfigOption(p) : async () => {
35279
+ },
35280
+ setSessionMode: transport.setSessionMode ? (p) => transport.setSessionMode(p) : async () => {
35281
+ },
35282
+ logDebug: ctx.logDebug
35283
+ });
35284
+ };
35285
+ }
35286
+
35287
+ // ../bridge/src/agents/providers/claude-code/after-session.ts
35288
+ var applyClaudeCodeAfterSessionEstablished = wrapPermissionAfterSession(
35289
+ applyClaudePermissionFromAcpSession
35290
+ );
35350
35291
 
35351
35292
  // ../bridge/src/agents/acp/clients/detect-command-on-path.ts
35352
35293
  init_cli_process_interrupt();
@@ -35418,8 +35359,7 @@ async function execProbeShutdownAware(file2, args, timeoutMs) {
35418
35359
  }
35419
35360
  }
35420
35361
 
35421
- // ../bridge/src/agents/acp/clients/claude-code-acp-client.ts
35422
- var BACKEND_LOCAL_AGENT_TYPE = "claude-code";
35362
+ // ../bridge/src/agents/providers/claude-code/client.ts
35423
35363
  var CLAUDE_ACP_ADAPTER_NPX_ARGS = ["--yes", "@agentclientprotocol/claude-agent-acp"];
35424
35364
  async function detectLocalAgentPresence() {
35425
35365
  return execProbeShutdownAware("npx", [...CLAUDE_ACP_ADAPTER_NPX_ARGS, "--help"], 8e3);
@@ -35438,58 +35378,230 @@ async function createClaudeCodeAcpClient(options) {
35438
35378
  });
35439
35379
  }
35440
35380
 
35441
- // ../bridge/src/agents/acp/clients/codex-acp-client.ts
35442
- var codex_acp_client_exports = {};
35443
- __export(codex_acp_client_exports, {
35444
- BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE2,
35445
- CODEX_ACP_PACKAGE: () => CODEX_ACP_PACKAGE,
35446
- DEFAULT_CODEX_ACP_COMMAND: () => DEFAULT_CODEX_ACP_COMMAND,
35447
- LEGACY_CODEX_ACP_PACKAGE: () => LEGACY_CODEX_ACP_PACKAGE,
35448
- buildCodexAcpSpawnCommand: () => buildCodexAcpSpawnCommand,
35449
- createCodexAcpClient: () => createCodexAcpClient,
35450
- detectLocalAgentPresence: () => detectLocalAgentPresence2,
35451
- isCodexAcpCommand: () => isCodexAcpCommand,
35452
- normalizeCodexAcpCommand: () => normalizeCodexAcpCommand
35453
- });
35454
- var BACKEND_LOCAL_AGENT_TYPE2 = "codex-acp";
35381
+ // ../bridge/src/agents/install/run-streaming-command.ts
35382
+ import { spawn as spawn2 } from "node:child_process";
35383
+ import * as readline from "node:readline";
35384
+ function runStreamingCommand(command, args, options) {
35385
+ return new Promise((resolve36, reject) => {
35386
+ const child = spawn2(command, args, {
35387
+ env: options.env,
35388
+ stdio: ["ignore", "pipe", "pipe"]
35389
+ });
35390
+ let settled = false;
35391
+ const timer = options.timeoutMs != null ? setTimeout(() => {
35392
+ child.kill("SIGKILL");
35393
+ if (!settled) {
35394
+ settled = true;
35395
+ reject(new Error(`Command timed out after ${options.timeoutMs}ms`));
35396
+ }
35397
+ }, options.timeoutMs) : null;
35398
+ const onLine = (line) => {
35399
+ if (line.length > 0) options.onLine?.(line);
35400
+ };
35401
+ if (child.stdout) {
35402
+ readline.createInterface({ input: child.stdout, crlfDelay: Infinity }).on("line", onLine);
35403
+ }
35404
+ if (child.stderr) {
35405
+ readline.createInterface({ input: child.stderr, crlfDelay: Infinity }).on("line", onLine);
35406
+ }
35407
+ child.on("error", (err) => {
35408
+ if (timer) clearTimeout(timer);
35409
+ if (!settled) {
35410
+ settled = true;
35411
+ reject(err);
35412
+ }
35413
+ });
35414
+ child.on("close", (code, signal) => {
35415
+ if (timer) clearTimeout(timer);
35416
+ if (!settled) {
35417
+ settled = true;
35418
+ resolve36({ code, signal });
35419
+ }
35420
+ });
35421
+ });
35422
+ }
35423
+
35424
+ // ../bridge/src/agents/install/commands/run-npm-global-install.ts
35425
+ async function runNpmGlobalInstall(packageName, env, options) {
35426
+ const result = await runStreamingCommand("npm", ["install", "-g", packageName], {
35427
+ env: bridgeAgentPathEnv(env),
35428
+ timeoutMs: options?.timeoutMs ?? 3e5,
35429
+ onLine: options?.onLine
35430
+ });
35431
+ if (result.code !== 0) {
35432
+ throw new Error(`npm install -g ${packageName} failed (exit ${result.code ?? "signal"})`);
35433
+ }
35434
+ }
35435
+
35436
+ // ../bridge/src/agents/providers/claude-code/install.ts
35437
+ var claudeCodeInstall = {
35438
+ detectCommand: "claude",
35439
+ tokenEnvVar: "ANTHROPIC_API_KEY",
35440
+ async run(ctx) {
35441
+ ctx.onProgress?.("Installing Anthropic Claude Code");
35442
+ await runNpmGlobalInstall(
35443
+ "@anthropic-ai/claude-code",
35444
+ { ...ctx.env, ANTHROPIC_API_KEY: ctx.authToken },
35445
+ { onLine: (line) => ctx.onProgress?.("Installing Anthropic Claude Code", line) }
35446
+ );
35447
+ }
35448
+ };
35449
+
35450
+ // ../bridge/src/agents/providers/claude-code/definition.ts
35451
+ var DEFAULT_COMMAND = ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"];
35452
+ var claudeCodeProvider = {
35453
+ type: "claude-code",
35454
+ displayName: "Claude Code",
35455
+ defaultCommand: DEFAULT_COMMAND,
35456
+ authErrorHints: claudeCodeAuthErrorHints,
35457
+ detectPresence: detectLocalAgentPresence,
35458
+ install: claudeCodeInstall,
35459
+ createClient: (options) => createClaudeCodeAcpClient({
35460
+ ...options,
35461
+ afterSessionEstablished: options.afterSessionEstablished ?? applyClaudeCodeAfterSessionEstablished
35462
+ }),
35463
+ buildSpawnCommand: (base, sessionMode) => buildClaudeCodeAcpSpawnCommand([...base], sessionMode)
35464
+ };
35465
+
35466
+ // ../bridge/src/agents/providers/codex/apply-permission.ts
35467
+ function flattenSelectOptions3(options) {
35468
+ if (options == null || options.length === 0) return [];
35469
+ const first2 = options[0];
35470
+ if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
35471
+ return options.flatMap(
35472
+ (g) => Array.isArray(g.options) ? g.options : []
35473
+ );
35474
+ }
35475
+ return options;
35476
+ }
35477
+ function pickModeConfigOption2(configOptions) {
35478
+ if (configOptions == null || configOptions.length === 0) return null;
35479
+ const byCategory = configOptions.find((o) => o.category === "mode");
35480
+ if (byCategory) return byCategory;
35481
+ return configOptions.find((o) => o.id === "mode") ?? null;
35482
+ }
35483
+ async function applyCodexPermissionFromAcpSession(params) {
35484
+ const { sessionId, agentConfig, configOptions, modes, setSessionConfigOption, setSessionMode, logDebug: logDebug2 } = params;
35485
+ const desiredMode = getCodexPermissionModeFromAgentConfig(agentConfig);
35486
+ if (desiredMode == null) return;
35487
+ const modeOpt = pickModeConfigOption2(configOptions ?? null);
35488
+ if (modeOpt != null) {
35489
+ const flat = flattenSelectOptions3(modeOpt.options);
35490
+ const allowed = flat.some((o) => o.value === desiredMode);
35491
+ if (allowed && modeOpt.currentValue !== desiredMode) {
35492
+ try {
35493
+ logDebug2(
35494
+ `[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`
35495
+ );
35496
+ await setSessionConfigOption({ sessionId, configId: modeOpt.id, value: desiredMode });
35497
+ } catch (e) {
35498
+ logDebug2(`[Agent] Codex: session/set_config_option failed: ${e instanceof Error ? e.message : String(e)}`);
35499
+ }
35500
+ }
35501
+ return;
35502
+ }
35503
+ if (modes?.availableModes?.length) {
35504
+ const allowed = modes.availableModes.some((m) => m.id === desiredMode);
35505
+ if (allowed && desiredMode !== modes.currentModeId) {
35506
+ try {
35507
+ logDebug2(
35508
+ `[Agent] Codex: sending ACP session/set_mode modeId=${JSON.stringify(desiredMode)} was=${JSON.stringify(modes.currentModeId ?? null)} sessionId=${sessionId.slice(0, 8)}\u2026`
35509
+ );
35510
+ await setSessionMode({ sessionId, modeId: desiredMode });
35511
+ } catch (e) {
35512
+ logDebug2(`[Agent] Codex: session/set_mode failed: ${e instanceof Error ? e.message : String(e)}`);
35513
+ }
35514
+ }
35515
+ }
35516
+ }
35517
+
35518
+ // ../bridge/src/agents/providers/codex/after-session.ts
35519
+ var applyCodexAfterSessionEstablished = wrapPermissionAfterSession(
35520
+ applyCodexPermissionFromAcpSession
35521
+ );
35522
+
35523
+ // ../bridge/src/agents/providers/codex/client.ts
35455
35524
  var CODEX_ACP_PACKAGE = "@agentclientprotocol/codex-acp";
35456
35525
  var LEGACY_CODEX_ACP_PACKAGE = "@zed-industries/codex-acp";
35457
35526
  async function detectLocalAgentPresence2() {
35458
35527
  return isCommandOnPath("codex");
35459
35528
  }
35460
35529
  var DEFAULT_CODEX_ACP_COMMAND = ["npx", "--yes", CODEX_ACP_PACKAGE];
35461
- function isCodexAcpCommand(command) {
35462
- return command.some(
35463
- (a) => a === CODEX_ACP_PACKAGE || a === LEGACY_CODEX_ACP_PACKAGE || a.includes("codex-acp")
35464
- );
35465
- }
35466
35530
  function normalizeCodexAcpCommand(command) {
35467
35531
  return command.map((a) => a === LEGACY_CODEX_ACP_PACKAGE ? CODEX_ACP_PACKAGE : a);
35468
35532
  }
35469
- function buildCodexAcpSpawnCommand(base, _sessionMode, _agentConfig) {
35470
- return normalizeCodexAcpCommand(base);
35533
+ function buildCodexAcpSpawnCommand(base, _sessionMode, _agentConfig) {
35534
+ return normalizeCodexAcpCommand(base);
35535
+ }
35536
+ async function createCodexAcpClient(options) {
35537
+ const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
35538
+ const command = buildCodexAcpSpawnCommand(base, options.sessionMode, options.agentConfig);
35539
+ return createSdkStdioAcpClient({
35540
+ ...options,
35541
+ command,
35542
+ /** Codex ACP can ignore `session/cancel`; mirror Claude Code's subprocess fallback. */
35543
+ killSubprocessAfterCancelMs: options.killSubprocessAfterCancelMs ?? 2500
35544
+ });
35545
+ }
35546
+
35547
+ // ../bridge/src/agents/providers/codex/install.ts
35548
+ var codexInstall = {
35549
+ detectCommand: "codex",
35550
+ tokenEnvVar: "OPENAI_API_KEY",
35551
+ async run(ctx) {
35552
+ ctx.onProgress?.("Installing Codex");
35553
+ await runNpmGlobalInstall(
35554
+ "@openai/codex",
35555
+ { ...ctx.env, OPENAI_API_KEY: ctx.authToken },
35556
+ { onLine: (line) => ctx.onProgress?.("Installing Codex", line) }
35557
+ );
35558
+ }
35559
+ };
35560
+
35561
+ // ../bridge/src/agents/providers/codex/definition.ts
35562
+ var codexProvider = {
35563
+ type: "codex-acp",
35564
+ displayName: "Codex",
35565
+ defaultCommand: DEFAULT_CODEX_ACP_COMMAND,
35566
+ authErrorHints: codexAuthErrorHints,
35567
+ detectPresence: detectLocalAgentPresence2,
35568
+ install: codexInstall,
35569
+ createClient: (options) => createCodexAcpClient({
35570
+ ...options,
35571
+ afterSessionEstablished: options.afterSessionEstablished ?? applyCodexAfterSessionEstablished
35572
+ }),
35573
+ buildSpawnCommand: (base, sessionMode, agentConfig) => buildCodexAcpSpawnCommand([...base], sessionMode, agentConfig)
35574
+ };
35575
+
35576
+ // ../bridge/src/agents/providers/cursor/cleanup-session-plans.ts
35577
+ import * as fs17 from "node:fs";
35578
+
35579
+ // ../bridge/src/paths/session-plans-paths.ts
35580
+ import * as os6 from "node:os";
35581
+ import * as path25 from "node:path";
35582
+ function getSessionPlansRootDir() {
35583
+ return path25.join(os6.homedir(), ".buildautomaton", "plans");
35584
+ }
35585
+ function sanitizeSessionPlansKey(sessionId) {
35586
+ const t = sessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
35587
+ return t || "session";
35471
35588
  }
35472
- async function createCodexAcpClient(options) {
35473
- const base = options.command?.length && options.command.some((a) => a.includes("codex-acp")) ? options.command : [...DEFAULT_CODEX_ACP_COMMAND];
35474
- const command = buildCodexAcpSpawnCommand(base, options.sessionMode, options.agentConfig);
35475
- return createSdkStdioAcpClient({
35476
- ...options,
35477
- command,
35478
- /** Codex ACP can ignore `session/cancel`; mirror Claude Code's subprocess fallback. */
35479
- killSubprocessAfterCancelMs: options.killSubprocessAfterCancelMs ?? 2500
35480
- });
35589
+ function getSessionPlansDir(sessionId) {
35590
+ return path25.join(getSessionPlansRootDir(), sanitizeSessionPlansKey(sessionId));
35481
35591
  }
35482
35592
 
35483
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-client.ts
35484
- var cursor_acp_client_exports = {};
35485
- __export(cursor_acp_client_exports, {
35486
- BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE3,
35487
- buildCursorAcpSpawnCommand: () => buildCursorAcpSpawnCommand,
35488
- createCursorAcpClient: () => createCursorAcpClient,
35489
- detectLocalAgentPresence: () => detectLocalAgentPresence3
35490
- });
35593
+ // ../bridge/src/agents/providers/cursor/cleanup-session-plans.ts
35594
+ function cleanupSessionPlans(sessionId) {
35595
+ const id = typeof sessionId === "string" ? sessionId.trim() : "";
35596
+ if (!id) return;
35597
+ const dir = getSessionPlansDir(id);
35598
+ try {
35599
+ fs17.rmSync(dir, { recursive: true, force: true });
35600
+ } catch {
35601
+ }
35602
+ }
35491
35603
 
35492
- // ../bridge/src/agents/acp/clients/cursor/cursor-spawn-command.ts
35604
+ // ../bridge/src/agents/providers/cursor/cursor-spawn-command.ts
35493
35605
  function buildCursorAcpSpawnCommand(base, sessionMode) {
35494
35606
  if (!sessionMode) return [...base];
35495
35607
  const m = sessionMode.trim();
@@ -35497,7 +35609,7 @@ function buildCursorAcpSpawnCommand(base, sessionMode) {
35497
35609
  return [...base, "--mode", m];
35498
35610
  }
35499
35611
 
35500
- // ../bridge/src/agents/acp/clients/cursor/create-cursor-acp-session-context.ts
35612
+ // ../bridge/src/agents/providers/cursor/create-cursor-acp-session-context.ts
35501
35613
  init_log();
35502
35614
  function createCursorAcpSessionContext(options) {
35503
35615
  const suppressLoadReplayRef = { value: false };
@@ -35516,14 +35628,15 @@ function createCursorAcpSessionContext(options) {
35516
35628
  onAcpConfigOptionsUpdated: options.onAcpConfigOptionsUpdated,
35517
35629
  logDebug,
35518
35630
  getStderrText: () => options.stderrCapture.getText(),
35519
- pendingPlanExecute: { value: false }
35631
+ pendingPlanExecute: { value: false },
35632
+ afterSessionEstablished: options.afterSessionEstablished
35520
35633
  };
35521
35634
  }
35522
35635
 
35523
- // ../bridge/src/agents/acp/clients/cursor/send-cursor-prompt-with-plan-continue.ts
35636
+ // ../bridge/src/agents/providers/cursor/send-cursor-prompt-with-plan-continue.ts
35524
35637
  init_log();
35525
35638
 
35526
- // ../bridge/src/agents/acp/clients/cursor/cursor-plan-continue.ts
35639
+ // ../bridge/src/agents/providers/cursor/cursor-plan-continue.ts
35527
35640
  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.";
35528
35641
  function isAcceptedCreatePlanRpcResult(result) {
35529
35642
  if (result == null || typeof result !== "object" || Array.isArray(result)) return false;
@@ -35547,7 +35660,7 @@ async function switchCursorSessionToAgentMode(transport, sessionId) {
35547
35660
  }
35548
35661
  }
35549
35662
 
35550
- // ../bridge/src/agents/acp/clients/cursor/send-cursor-prompt-with-plan-continue.ts
35663
+ // ../bridge/src/agents/providers/cursor/send-cursor-prompt-with-plan-continue.ts
35551
35664
  async function sendCursorPromptWithPlanContinue(params) {
35552
35665
  const { transport, sessionCtx, sessionId, prompt, images } = params;
35553
35666
  const first2 = await sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt, images);
@@ -35562,7 +35675,7 @@ async function sendCursorPromptWithPlanContinue(params) {
35562
35675
  );
35563
35676
  }
35564
35677
 
35565
- // ../bridge/src/agents/acp/clients/cursor/cancel-pending-cursor-permission-requests.ts
35678
+ // ../bridge/src/agents/providers/cursor/cancel-pending-cursor-permission-requests.ts
35566
35679
  function cancelPendingCursorPermissionRequests(pendingRequests2, respond) {
35567
35680
  for (const [reqId, pending2] of [...pendingRequests2.entries()]) {
35568
35681
  if (pending2.method === "session/request_permission") {
@@ -35572,7 +35685,7 @@ function cancelPendingCursorPermissionRequests(pendingRequests2, respond) {
35572
35685
  }
35573
35686
  }
35574
35687
 
35575
- // ../bridge/src/agents/acp/clients/cursor/create-cursor-acp-handle.ts
35688
+ // ../bridge/src/agents/providers/cursor/create-cursor-acp-handle.ts
35576
35689
  function createCursorAcpHandle(options) {
35577
35690
  let teardownStarted = false;
35578
35691
  let cancelFallback = null;
@@ -35635,10 +35748,10 @@ function createCursorAcpHandle(options) {
35635
35748
  };
35636
35749
  }
35637
35750
 
35638
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-init.ts
35639
- import * as readline from "node:readline";
35751
+ // ../bridge/src/agents/providers/cursor/cursor-acp-init.ts
35752
+ import * as readline2 from "node:readline";
35640
35753
 
35641
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-cursor-create-plan.ts
35754
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-cursor-create-plan.ts
35642
35755
  function buildCursorCreatePlanToolCallUpdate(requestId, params) {
35643
35756
  const toolCallId = params.toolCallId ?? params.tool_call_id;
35644
35757
  if (typeof toolCallId !== "string" || !toolCallId.trim()) return null;
@@ -35673,7 +35786,7 @@ function queueCursorCreatePlanRequest(method, id, msg, deps) {
35673
35786
  deps.onRequest?.({ requestId, method, params });
35674
35787
  }
35675
35788
 
35676
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-cursor-task.ts
35789
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-cursor-task.ts
35677
35790
  function buildCursorTaskToolCallUpdate(params) {
35678
35791
  const toolCallId = params.toolCallId ?? params.tool_call_id;
35679
35792
  if (typeof toolCallId !== "string" || !toolCallId.trim()) return null;
@@ -35706,7 +35819,7 @@ function handleCursorIncomingCursorTask(id, msg, deps) {
35706
35819
  if (update) deps.onSessionUpdate?.(update);
35707
35820
  }
35708
35821
 
35709
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-cursor-methods.ts
35822
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-cursor-methods.ts
35710
35823
  var CURSOR_BRIDGE_METHODS = /* @__PURE__ */ new Set(["cursor/ask_question"]);
35711
35824
  var CURSOR_NOOP_METHODS = /* @__PURE__ */ new Set(["cursor/update_todos", "cursor/generate_image"]);
35712
35825
  function handleCursorIncomingCursorNotification(method, msg, onSessionUpdate) {
@@ -35742,7 +35855,7 @@ function handleCursorIncomingCursorMethods(method, id, msg, deps) {
35742
35855
  return false;
35743
35856
  }
35744
35857
 
35745
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-types.ts
35858
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-types.ts
35746
35859
  function parseIncomingJsonRpcRequestId(raw) {
35747
35860
  if (typeof raw === "number" && Number.isFinite(raw)) return raw;
35748
35861
  if (typeof raw === "string" && raw.length > 0) return raw;
@@ -35761,7 +35874,7 @@ function isCursorFsWriteMethod(method) {
35761
35874
  return lower.startsWith("fs/") && lower.includes("write");
35762
35875
  }
35763
35876
 
35764
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-fs-request.ts
35877
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-fs-request.ts
35765
35878
  function pathFromFsParams(params) {
35766
35879
  for (const key of ["path", "filePath", "file_path", "targetPath", "target_path"]) {
35767
35880
  const value = params[key];
@@ -35818,7 +35931,7 @@ function handleCursorIncomingFsRequest(method, id, msg, deps) {
35818
35931
  return false;
35819
35932
  }
35820
35933
 
35821
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-permission-request.ts
35934
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-permission-request.ts
35822
35935
  function handleCursorIncomingPermissionRequest(id, method, msg, deps) {
35823
35936
  const params = msg.params ?? {};
35824
35937
  if (deps.onRequest) {
@@ -35834,39 +35947,23 @@ function handleCursorIncomingPermissionRequest(id, method, msg, deps) {
35834
35947
  return true;
35835
35948
  }
35836
35949
 
35837
- // ../bridge/src/agents/acp/clients/cursor/write-create-plan-file.ts
35838
- import * as fs17 from "node:fs";
35950
+ // ../bridge/src/agents/providers/cursor/write-create-plan-file.ts
35951
+ import * as fs18 from "node:fs";
35839
35952
  import * as path26 from "node:path";
35840
35953
  import { pathToFileURL as pathToFileURL2 } from "node:url";
35841
-
35842
- // ../bridge/src/paths/session-plans-paths.ts
35843
- import * as os6 from "node:os";
35844
- import * as path25 from "node:path";
35845
- function getSessionPlansRootDir() {
35846
- return path25.join(os6.homedir(), ".buildautomaton", "plans");
35847
- }
35848
- function sanitizeSessionPlansKey(sessionId) {
35849
- const t = sessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
35850
- return t || "session";
35851
- }
35852
- function getSessionPlansDir(sessionId) {
35853
- return path25.join(getSessionPlansRootDir(), sanitizeSessionPlansKey(sessionId));
35854
- }
35855
-
35856
- // ../bridge/src/agents/acp/clients/cursor/write-create-plan-file.ts
35857
35954
  function sanitizePlanFileBase(toolCallId) {
35858
35955
  const t = toolCallId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 120);
35859
35956
  return t || "plan";
35860
35957
  }
35861
35958
  function writeCreatePlanFile(params) {
35862
35959
  const dir = getSessionPlansDir(params.cloudSessionId);
35863
- fs17.mkdirSync(dir, { recursive: true });
35960
+ fs18.mkdirSync(dir, { recursive: true });
35864
35961
  const filePath = path26.join(dir, `${sanitizePlanFileBase(params.toolCallId)}.md`);
35865
- fs17.writeFileSync(filePath, params.planMarkdown, "utf8");
35962
+ fs18.writeFileSync(filePath, params.planMarkdown, "utf8");
35866
35963
  return pathToFileURL2(filePath).href;
35867
35964
  }
35868
35965
 
35869
- // ../bridge/src/agents/acp/clients/cursor/enrich-create-plan-rpc-result.ts
35966
+ // ../bridge/src/agents/providers/cursor/enrich-create-plan-rpc-result.ts
35870
35967
  function asRecord2(v) {
35871
35968
  return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
35872
35969
  }
@@ -35895,7 +35992,7 @@ function enrichCreatePlanRpcResult(result, pendingParams, cloudSessionId) {
35895
35992
  return { outcome: { outcome: "accepted" } };
35896
35993
  }
35897
35994
 
35898
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-resolve-request.ts
35995
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-resolve-request.ts
35899
35996
  function resolveCursorIncomingRequest(pendingRequests2, respond, requestId, result, cloudSessionId, pendingPlanExecute) {
35900
35997
  const pending2 = pendingRequests2.get(requestId);
35901
35998
  let payload = result;
@@ -35922,7 +36019,7 @@ function formatSessionUpdateKindForLog(kind) {
35922
36019
  return kind.split("_").filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
35923
36020
  }
35924
36021
 
35925
- // ../bridge/src/agents/acp/clients/cursor/cursor-incoming-session-update.ts
36022
+ // ../bridge/src/agents/providers/cursor/cursor-incoming-session-update.ts
35926
36023
  function handleCursorIncomingSessionUpdate(msg, deps) {
35927
36024
  const params = msg.params;
35928
36025
  const update = params?.update;
@@ -35943,7 +36040,7 @@ function handleCursorIncomingSessionUpdate(msg, deps) {
35943
36040
  return true;
35944
36041
  }
35945
36042
 
35946
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-parse.ts
36043
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-parse.ts
35947
36044
  function safeJsonParse(value) {
35948
36045
  try {
35949
36046
  const parsed = JSON.parse(value);
@@ -35953,7 +36050,7 @@ function safeJsonParse(value) {
35953
36050
  }
35954
36051
  }
35955
36052
 
35956
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-incoming-line-handler.ts
36053
+ // ../bridge/src/agents/providers/cursor/cursor-acp-incoming-line-handler.ts
35957
36054
  function createCursorAcpIncomingLineHandler(deps) {
35958
36055
  const respondDeps = {
35959
36056
  dbgFs: deps.dbgFs,
@@ -36009,7 +36106,7 @@ function createCursorAcpIncomingLineHandler(deps) {
36009
36106
  };
36010
36107
  }
36011
36108
 
36012
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-acp-transport.ts
36109
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-acp-transport.ts
36013
36110
  function createCursorJsonRpcAcpTransport(deps) {
36014
36111
  const { send, cancelSessionNotification, skipBrowserAuthenticate } = deps;
36015
36112
  return {
@@ -36027,12 +36124,12 @@ function createCursorJsonRpcAcpTransport(deps) {
36027
36124
  };
36028
36125
  }
36029
36126
 
36030
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-stdin-write.ts
36127
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-stdin-write.ts
36031
36128
  function writeJsonRpcLine(stdin, payload, callback) {
36032
36129
  stdin.write(JSON.stringify(payload) + "\n", callback);
36033
36130
  }
36034
36131
 
36035
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-inbound-respond.ts
36132
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-inbound-respond.ts
36036
36133
  function createCursorJsonRpcInboundRespond(stdin) {
36037
36134
  function respond(id, result) {
36038
36135
  writeJsonRpcLine(stdin, { jsonrpc: "2.0", id, result });
@@ -36053,7 +36150,7 @@ function createCursorJsonRpcInboundRespond(stdin) {
36053
36150
  return { respond, respondJsonRpcError, cancelSessionNotification };
36054
36151
  }
36055
36152
 
36056
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-outbound.ts
36153
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-outbound.ts
36057
36154
  function createCursorJsonRpcOutboundPending() {
36058
36155
  const pending2 = /* @__PURE__ */ new Map();
36059
36156
  let nextId = 1;
@@ -36079,7 +36176,7 @@ function createCursorJsonRpcOutboundPending() {
36079
36176
  return { allocateId, register, settleResponse, rejectOnWriteError };
36080
36177
  }
36081
36178
 
36082
- // ../bridge/src/agents/acp/clients/cursor/cursor-json-rpc-wire.ts
36179
+ // ../bridge/src/agents/providers/cursor/cursor-json-rpc-wire.ts
36083
36180
  function createCursorJsonRpcWriter(stdin) {
36084
36181
  const inbound = createCursorJsonRpcInboundRespond(stdin);
36085
36182
  const outbound = createCursorJsonRpcOutboundPending();
@@ -36101,7 +36198,7 @@ function createCursorJsonRpcWriter(stdin) {
36101
36198
  };
36102
36199
  }
36103
36200
 
36104
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-init.ts
36201
+ // ../bridge/src/agents/providers/cursor/cursor-acp-init.ts
36105
36202
  var CURSOR_ACP_CLIENT_INFO = {
36106
36203
  protocolVersion: 1,
36107
36204
  clientCapabilities: {
@@ -36121,7 +36218,7 @@ async function initCursorAcpWire(options) {
36121
36218
  settleResponse: wire.settleResponse,
36122
36219
  pendingRequests: pendingRequests2
36123
36220
  });
36124
- const rl = readline.createInterface({ input: options.child.stdout });
36221
+ const rl = readline2.createInterface({ input: options.child.stdout });
36125
36222
  rl.on("line", (line) => incoming.handleLine(line));
36126
36223
  const transport = createCursorJsonRpcAcpTransport({
36127
36224
  send: wire.send,
@@ -36132,11 +36229,11 @@ async function initCursorAcpWire(options) {
36132
36229
  return { wire, transport, established, incoming, pendingRequests: pendingRequests2 };
36133
36230
  }
36134
36231
 
36135
- // ../bridge/src/agents/acp/clients/cursor/spawn-cursor-acp-process.ts
36136
- import { spawn as spawn2 } from "node:child_process";
36232
+ // ../bridge/src/agents/providers/cursor/spawn-cursor-acp-process.ts
36233
+ import { spawn as spawn3 } from "node:child_process";
36137
36234
  function spawnCursorAcpProcess(options) {
36138
36235
  const isWindows = process.platform === "win32";
36139
- const child = spawn2(options.command[0], options.command.slice(1), {
36236
+ const child = spawn3(options.command[0], options.command.slice(1), {
36140
36237
  cwd: options.cwd,
36141
36238
  stdio: ["pipe", "pipe", "pipe"],
36142
36239
  env: bridgeInstalledAgentAuthProcessEnv(process.env),
@@ -36150,13 +36247,12 @@ function spawnCursorAcpProcess(options) {
36150
36247
  return { child, stderrCapture };
36151
36248
  }
36152
36249
 
36153
- // ../bridge/src/agents/acp/clients/cursor/cursor-local-agent.ts
36154
- var BACKEND_LOCAL_AGENT_TYPE3 = "cursor-cli";
36250
+ // ../bridge/src/agents/providers/cursor/cursor-local-agent.ts
36155
36251
  async function detectLocalAgentPresence3() {
36156
36252
  return isCommandOnPath("agent");
36157
36253
  }
36158
36254
 
36159
- // ../bridge/src/agents/acp/clients/cursor/cursor-acp-client.ts
36255
+ // ../bridge/src/agents/providers/cursor/cursor-acp-client.ts
36160
36256
  async function createCursorAcpClient(options) {
36161
36257
  const command = buildCursorAcpSpawnCommand(options.command, options.sessionMode);
36162
36258
  const {
@@ -36168,7 +36264,8 @@ async function createCursorAcpClient(options) {
36168
36264
  persistedAcpSessionId,
36169
36265
  onAcpSessionEstablished,
36170
36266
  onAcpConfigOptionsUpdated,
36171
- onAgentSubprocessExit
36267
+ onAgentSubprocessExit,
36268
+ afterSessionEstablished
36172
36269
  } = options;
36173
36270
  const dbgFs = process.env.BUILDAUTOMATON_DEBUG_ACP_FS === "1";
36174
36271
  const spawnEnv = bridgeInstalledAgentAuthProcessEnv(process.env);
@@ -36189,6 +36286,7 @@ async function createCursorAcpClient(options) {
36189
36286
  onAcpSessionEstablished,
36190
36287
  onAcpConfigOptionsUpdated,
36191
36288
  onFileChange,
36289
+ afterSessionEstablished,
36192
36290
  stderrCapture
36193
36291
  });
36194
36292
  return new Promise((resolve36, reject) => {
@@ -36224,17 +36322,43 @@ async function createCursorAcpClient(options) {
36224
36322
  });
36225
36323
  }
36226
36324
 
36227
- // ../bridge/src/agents/acp/clients/kiro-acp-client.ts
36228
- var kiro_acp_client_exports = {};
36229
- __export(kiro_acp_client_exports, {
36230
- BACKEND_LOCAL_AGENT_TYPE: () => BACKEND_LOCAL_AGENT_TYPE4,
36231
- DEFAULT_KIRO_ACP_COMMAND: () => DEFAULT_KIRO_ACP_COMMAND,
36232
- buildKiroAcpSpawnCommand: () => buildKiroAcpSpawnCommand,
36233
- createKiroAcpClient: () => createKiroAcpClient,
36234
- detectLocalAgentPresence: () => detectLocalAgentPresence4,
36235
- isKiroAcpCommand: () => isKiroAcpCommand
36236
- });
36237
- var BACKEND_LOCAL_AGENT_TYPE4 = "kiro-acp";
36325
+ // ../bridge/src/agents/providers/cursor/install.ts
36326
+ var cursorInstall = {
36327
+ detectCommand: "agent",
36328
+ alternateDetectCommands: ["cursor-agent"],
36329
+ tokenEnvVar: "CURSOR_API_KEY",
36330
+ async run(ctx) {
36331
+ ctx.onProgress?.("Installing Cursor CLI");
36332
+ const result = await runStreamingCommand(
36333
+ "bash",
36334
+ ["-lc", "curl -fsSL https://cursor.com/install | bash"],
36335
+ {
36336
+ timeoutMs: 3e5,
36337
+ env: { ...bridgeAgentPathEnv(ctx.env), CURSOR_API_KEY: ctx.authToken },
36338
+ onLine: (line) => ctx.onProgress?.("Installing Cursor CLI", line)
36339
+ }
36340
+ );
36341
+ if (result.code !== 0) {
36342
+ throw new Error(`Cursor CLI install failed (exit ${result.code ?? "signal"})`);
36343
+ }
36344
+ }
36345
+ };
36346
+
36347
+ // ../bridge/src/agents/providers/cursor/definition.ts
36348
+ var cursorProvider = {
36349
+ type: "cursor-cli",
36350
+ displayName: "Cursor",
36351
+ defaultCommand: ["agent", "acp"],
36352
+ authErrorHints: cursorAuthErrorHints,
36353
+ detectPresence: detectLocalAgentPresence3,
36354
+ install: cursorInstall,
36355
+ createClient: createCursorAcpClient,
36356
+ buildSpawnCommand: (base, sessionMode) => buildCursorAcpSpawnCommand([...base], sessionMode),
36357
+ onPromptTurnFinished: cleanupSessionPlans,
36358
+ onSessionClosed: cleanupSessionPlans
36359
+ };
36360
+
36361
+ // ../bridge/src/agents/providers/kiro/client.ts
36238
36362
  async function detectLocalAgentPresence4() {
36239
36363
  return isCommandOnPath("kiro-cli");
36240
36364
  }
@@ -36255,80 +36379,108 @@ async function createKiroAcpClient(options) {
36255
36379
  return createSdkStdioAcpClient({ ...options, command });
36256
36380
  }
36257
36381
 
36258
- // ../bridge/src/agents/acp/resolve-agent-command.ts
36259
- var AGENT_TYPE_DEFAULT_COMMANDS = {
36260
- [BACKEND_LOCAL_AGENT_TYPE3]: ["agent", "acp"],
36261
- [BACKEND_LOCAL_AGENT_TYPE2]: [...DEFAULT_CODEX_ACP_COMMAND],
36262
- /** ACP stdio agent; `@anthropic-ai/claude-code` is the interactive CLI and does not speak ACP on stdout. */
36263
- [BACKEND_LOCAL_AGENT_TYPE]: ["npx", "--yes", "@agentclientprotocol/claude-agent-acp"],
36264
- /** [Kiro CLI ACP](https://kiro.dev/docs/cli/acp/) — use full path to `kiro-cli` in PATH if the IDE cannot find it. */
36265
- [BACKEND_LOCAL_AGENT_TYPE4]: [...DEFAULT_KIRO_ACP_COMMAND]
36382
+ // ../bridge/src/agents/providers/kiro/ext-notifications.ts
36383
+ function createKiroSdkExtNotificationHandler(options) {
36384
+ const { onSessionUpdate } = options;
36385
+ return async (method, params) => {
36386
+ if (method === "_kiro.dev/metadata") {
36387
+ const p = params && typeof params === "object" ? params : {};
36388
+ const pct = p.contextUsagePercentage;
36389
+ if (typeof pct !== "number" || !Number.isFinite(pct) || !onSessionUpdate) return;
36390
+ onSessionUpdate({
36391
+ sessionUpdate: "context_usage",
36392
+ contextUsagePercentage: pct
36393
+ });
36394
+ return;
36395
+ }
36396
+ };
36397
+ }
36398
+
36399
+ // ../bridge/src/agents/providers/kiro/definition.ts
36400
+ var kiroProvider = {
36401
+ type: "kiro-acp",
36402
+ displayName: "Kiro",
36403
+ defaultCommand: DEFAULT_KIRO_ACP_COMMAND,
36404
+ authErrorHints: kiroAuthErrorHints,
36405
+ detectPresence: detectLocalAgentPresence4,
36406
+ createClient: (options) => createKiroAcpClient({
36407
+ ...options,
36408
+ createExtNotificationHandler: options.createExtNotificationHandler ?? createKiroSdkExtNotificationHandler
36409
+ }),
36410
+ buildSpawnCommand: (base, sessionMode) => buildKiroAcpSpawnCommand([...base], sessionMode)
36411
+ };
36412
+
36413
+ // ../bridge/src/agents/providers/opencode/install.ts
36414
+ var opencodeInstall = {
36415
+ detectCommand: "opencode",
36416
+ tokenEnvVar: "OPENCODE_API_KEY",
36417
+ async run(ctx) {
36418
+ ctx.onProgress?.("Installing OpenCode");
36419
+ await runNpmGlobalInstall(
36420
+ "opencode-ai",
36421
+ { ...ctx.env, OPENCODE_API_KEY: ctx.authToken },
36422
+ { onLine: (line) => ctx.onProgress?.("Installing OpenCode", line) }
36423
+ );
36424
+ }
36266
36425
  };
36267
- var AGENT_TYPE_DISPLAY_NAMES = {
36268
- [BACKEND_LOCAL_AGENT_TYPE3]: "Cursor",
36269
- [BACKEND_LOCAL_AGENT_TYPE2]: "Codex",
36270
- [BACKEND_LOCAL_AGENT_TYPE]: "Claude Code",
36271
- [BACKEND_LOCAL_AGENT_TYPE4]: "Kiro"
36426
+
36427
+ // ../bridge/src/agents/providers/opencode/definition.ts
36428
+ var opencodeProvider = {
36429
+ type: "opencode",
36430
+ displayName: "OpenCode",
36431
+ defaultCommand: [],
36432
+ authErrorHints: [],
36433
+ install: opencodeInstall,
36434
+ buildSpawnCommand: (base) => [...base]
36272
36435
  };
36273
- function getAgentTypeDisplayName(agentType) {
36274
- if (agentType == null || agentType === "") return "Unknown agent";
36275
- const known = AGENT_TYPE_DISPLAY_NAMES[agentType];
36276
- if (known) return known;
36277
- return agentType.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
36436
+
36437
+ // ../bridge/src/agents/providers/registry.ts
36438
+ var AGENT_PROVIDERS = [
36439
+ cursorProvider,
36440
+ codexProvider,
36441
+ kiroProvider,
36442
+ claudeCodeProvider,
36443
+ opencodeProvider
36444
+ ];
36445
+ var byType = new Map(AGENT_PROVIDERS.map((p) => [p.type, p]));
36446
+ function getAgentProvider(agentType) {
36447
+ if (agentType == null || agentType === "") return void 0;
36448
+ return byType.get(agentType);
36278
36449
  }
36279
- function useCursorAcp(agentType, command) {
36280
- if (agentType === BACKEND_LOCAL_AGENT_TYPE3) return true;
36281
- return command[0] === "agent" && command[1] === "acp";
36450
+ function listAutoDetectAgentProviders() {
36451
+ return AGENT_PROVIDERS.filter((p) => p.detectPresence != null);
36282
36452
  }
36283
- function useCodexAcp(agentType, command) {
36284
- if (agentType === BACKEND_LOCAL_AGENT_TYPE2) return true;
36285
- return isCodexAcpCommand(command);
36453
+ function notifyAgentProvidersSessionClosed(sessionId) {
36454
+ for (const p of AGENT_PROVIDERS) p.onSessionClosed?.(sessionId);
36286
36455
  }
36287
- function useKiroAcp(agentType, command) {
36288
- if (agentType === BACKEND_LOCAL_AGENT_TYPE4) return true;
36289
- return isKiroAcpCommand(command);
36456
+ function notifyAgentProvidersPromptTurnFinished(sessionId) {
36457
+ for (const p of AGENT_PROVIDERS) p.onPromptTurnFinished?.(sessionId);
36290
36458
  }
36459
+
36460
+ // ../bridge/src/agents/acp/resolve-agent-command.ts
36291
36461
  function resolveAgentCommand(preferredAgentType) {
36292
- if (!preferredAgentType) return null;
36293
- const command = AGENT_TYPE_DEFAULT_COMMANDS[preferredAgentType];
36294
- if (!command?.length) return null;
36295
- if (useCursorAcp(preferredAgentType, command)) {
36296
- return {
36297
- command,
36298
- label: preferredAgentType,
36299
- createClient: createCursorAcpClient,
36300
- spawnCommandForSession: (sessionMode, _agentConfig) => buildCursorAcpSpawnCommand(command, sessionMode)
36301
- };
36302
- }
36303
- if (useCodexAcp(preferredAgentType, command)) {
36304
- return {
36305
- command,
36306
- label: preferredAgentType,
36307
- createClient: createCodexAcpClient,
36308
- spawnCommandForSession: (sessionMode, agentConfig) => buildCodexAcpSpawnCommand(command, sessionMode, agentConfig)
36309
- };
36310
- }
36311
- if (useKiroAcp(preferredAgentType, command)) {
36312
- return {
36313
- command,
36314
- label: preferredAgentType,
36315
- createClient: createKiroAcpClient,
36316
- spawnCommandForSession: (sessionMode, _agentConfig) => buildKiroAcpSpawnCommand(command, sessionMode)
36317
- };
36318
- }
36462
+ const provider = getAgentProvider(preferredAgentType);
36463
+ if (!provider?.createClient || provider.defaultCommand.length === 0) return null;
36464
+ const command = [...provider.defaultCommand];
36319
36465
  return {
36320
36466
  command,
36321
- label: preferredAgentType,
36322
- createClient: createClaudeCodeAcpClient,
36323
- spawnCommandForSession: (sessionMode) => buildClaudeCodeAcpSpawnCommand(command, sessionMode)
36467
+ label: provider.type,
36468
+ createClient: provider.createClient,
36469
+ spawnCommandForSession: (sessionMode, agentConfig) => provider.buildSpawnCommand(command, sessionMode, agentConfig)
36324
36470
  };
36325
36471
  }
36472
+ function getAgentTypeDisplayName(agentType) {
36473
+ if (agentType == null || agentType === "") return "Unknown agent";
36474
+ const known = getAgentProvider(agentType)?.displayName;
36475
+ if (known) return known;
36476
+ return agentType.split(/[-_]/).filter(Boolean).map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase()).join(" ");
36477
+ }
36326
36478
 
36327
36479
  // ../bridge/src/agents/acp/session-file-change-path-kind.ts
36328
36480
  import { existsSync as existsSync4, statSync } from "node:fs";
36329
36481
 
36330
36482
  // ../bridge/src/git/git-exec.ts
36331
- import { execFile as execFile2, execFileSync as execFileSync2, spawn as spawn3 } from "node:child_process";
36483
+ import { execFile as execFile2, execFileSync as execFileSync2, spawn as spawn4 } from "node:child_process";
36332
36484
  import { promisify as promisify3 } from "node:util";
36333
36485
 
36334
36486
  // ../bridge/src/git/git-runtime.ts
@@ -37462,7 +37614,7 @@ async function ensureAcpClient(options) {
37462
37614
  if (!state.acpStartPromise) {
37463
37615
  let statOk = false;
37464
37616
  try {
37465
- const st = await fs18.promises.stat(targetSessionParentPath);
37617
+ const st = await fs19.promises.stat(targetSessionParentPath);
37466
37618
  statOk = st.isDirectory();
37467
37619
  if (!statOk) {
37468
37620
  state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
@@ -37934,18 +38086,6 @@ function reportPostTurnEnrichment(options) {
37934
38086
  });
37935
38087
  }
37936
38088
 
37937
- // ../bridge/src/agents/acp/clients/cursor/cleanup-session-plans.ts
37938
- import * as fs19 from "node:fs";
37939
- function cleanupSessionPlans(sessionId) {
37940
- const id = typeof sessionId === "string" ? sessionId.trim() : "";
37941
- if (!id) return;
37942
- const dir = getSessionPlansDir(id);
37943
- try {
37944
- fs19.rmSync(dir, { recursive: true, force: true });
37945
- } catch {
37946
- }
37947
- }
37948
-
37949
38089
  // ../bridge/src/agents/acp/prompts/finalize-and-send-prompt-result.ts
37950
38090
  async function finalizeAndSendPromptResult(params) {
37951
38091
  const {
@@ -37962,7 +38102,7 @@ async function finalizeAndSendPromptResult(params) {
37962
38102
  sendSessionUpdate,
37963
38103
  log: log2
37964
38104
  } = params;
37965
- cleanupSessionPlans(sessionId);
38105
+ notifyAgentProvidersPromptTurnFinished(sessionId);
37966
38106
  const planningTodosSubmit = isPlanningSession && plugin?.cloud?.maybeSubmitPlanningTodos ? await plugin.cloud.maybeSubmitPlanningTodos({
37967
38107
  sessionId,
37968
38108
  runId,
@@ -38506,7 +38646,7 @@ function decryptCliE2eeMessageField(payload, field, e2ee) {
38506
38646
  }
38507
38647
 
38508
38648
  // ../bridge/src/e2ee/key-command.ts
38509
- import * as readline2 from "node:readline";
38649
+ import * as readline3 from "node:readline";
38510
38650
  function installE2eCertificateKeyCommand({
38511
38651
  log: log2,
38512
38652
  onOpenCertificate,
@@ -38517,7 +38657,7 @@ function installE2eCertificateKeyCommand({
38517
38657
  return () => {
38518
38658
  };
38519
38659
  }
38520
- readline2.emitKeypressEvents(process.stdin);
38660
+ readline3.emitKeypressEvents(process.stdin);
38521
38661
  process.stdin.setRawMode(true);
38522
38662
  process.stdin.resume();
38523
38663
  const onKeypress = (str, key) => {
@@ -38692,25 +38832,20 @@ import * as path35 from "node:path";
38692
38832
  // ../bridge/src/agents/detect-local-agent-types.ts
38693
38833
  init_yield_to_event_loop();
38694
38834
  init_cli_process_interrupt();
38695
- var LOCAL_AGENT_ACP_MODULES = [
38696
- cursor_acp_client_exports,
38697
- codex_acp_client_exports,
38698
- kiro_acp_client_exports,
38699
- claude_code_acp_client_exports
38700
- ];
38701
38835
  async function detectLocalAgentTypes() {
38702
38836
  try {
38703
38837
  if (isCliImmediateShutdownRequested()) return [];
38838
+ const providers = listAutoDetectAgentProviders();
38704
38839
  const out = [];
38705
- for (let i = 0; i < LOCAL_AGENT_ACP_MODULES.length; i++) {
38840
+ for (let i = 0; i < providers.length; i++) {
38706
38841
  if (isCliImmediateShutdownRequested()) return out;
38707
38842
  if (i > 0) {
38708
38843
  await yieldToEventLoop();
38709
38844
  if (isCliImmediateShutdownRequested()) return out;
38710
38845
  }
38711
- const mod = LOCAL_AGENT_ACP_MODULES[i];
38846
+ const provider = providers[i];
38712
38847
  try {
38713
- if (await mod.detectLocalAgentPresence()) out.push(mod.BACKEND_LOCAL_AGENT_TYPE);
38848
+ if (await provider.detectPresence?.()) out.push(provider.type);
38714
38849
  } catch {
38715
38850
  }
38716
38851
  }
@@ -39705,7 +39840,7 @@ function pipedStdoutStderrFor(attemptStdio) {
39705
39840
  }
39706
39841
 
39707
39842
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-piped-via-sh.ts
39708
- import { spawn as spawn4 } from "node:child_process";
39843
+ import { spawn as spawn5 } from "node:child_process";
39709
39844
  function trySpawnPipedViaSh(command, env, cwd, signal, lifecycle) {
39710
39845
  const attempts = [
39711
39846
  { stdio: [devNullReadFd(), "pipe", "pipe"], endStdin: false },
@@ -39729,9 +39864,9 @@ function trySpawnPipedViaSh(command, env, cwd, signal, lifecycle) {
39729
39864
  if (process.platform === "win32") {
39730
39865
  opts.windowsHide = true;
39731
39866
  const com = process.env.ComSpec || "cmd.exe";
39732
- proc = spawn4(com, ["/d", "/s", "/c", command], opts);
39867
+ proc = spawn5(com, ["/d", "/s", "/c", command], opts);
39733
39868
  } else {
39734
- proc = spawn4("/bin/sh", ["-c", command], opts);
39869
+ proc = spawn5("/bin/sh", ["-c", command], opts);
39735
39870
  }
39736
39871
  if (attempt.endStdin) {
39737
39872
  proc.stdin?.end();
@@ -39751,7 +39886,7 @@ function trySpawnPipedViaSh(command, env, cwd, signal, lifecycle) {
39751
39886
  }
39752
39887
 
39753
39888
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-shell-true-piped.ts
39754
- import { spawn as spawn5 } from "node:child_process";
39889
+ import { spawn as spawn6 } from "node:child_process";
39755
39890
  function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal, lifecycle) {
39756
39891
  try {
39757
39892
  const opts = mergePreviewEnvironmentSpawnOptions(
@@ -39767,7 +39902,7 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal, lifecycle)
39767
39902
  if (process.platform === "win32") {
39768
39903
  opts.windowsHide = true;
39769
39904
  }
39770
- return spawn5(command, opts);
39905
+ return spawn6(command, opts);
39771
39906
  } catch (e) {
39772
39907
  if (isSpawnEbadf(e)) return null;
39773
39908
  throw e;
@@ -39775,7 +39910,7 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal, lifecycle)
39775
39910
  }
39776
39911
 
39777
39912
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-merged-log-file.ts
39778
- import { spawn as spawn6 } from "node:child_process";
39913
+ import { spawn as spawn7 } from "node:child_process";
39779
39914
  import fs23 from "node:fs";
39780
39915
  import { tmpdir } from "node:os";
39781
39916
  import path36 from "node:path";
@@ -39793,7 +39928,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal, lifecycle) {
39793
39928
  try {
39794
39929
  let proc;
39795
39930
  if (process.platform === "win32") {
39796
- proc = spawn6(
39931
+ proc = spawn7(
39797
39932
  process.env.ComSpec || "cmd.exe",
39798
39933
  ["/d", "/s", "/c", command],
39799
39934
  mergePreviewEnvironmentSpawnOptions(
@@ -39802,7 +39937,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal, lifecycle) {
39802
39937
  )
39803
39938
  );
39804
39939
  } else {
39805
- proc = spawn6(
39940
+ proc = spawn7(
39806
39941
  "/bin/sh",
39807
39942
  ["-c", command],
39808
39943
  mergePreviewEnvironmentSpawnOptions({ env, cwd, stdio, ...signal ? { signal } : {} }, lifecycle)
@@ -39827,7 +39962,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal, lifecycle) {
39827
39962
  }
39828
39963
 
39829
39964
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
39830
- import { spawn as spawn7 } from "node:child_process";
39965
+ import { spawn as spawn8 } from "node:child_process";
39831
39966
  import fs24 from "node:fs";
39832
39967
  import { tmpdir as tmpdir2 } from "node:os";
39833
39968
  import path37 from "node:path";
@@ -39850,7 +39985,7 @@ cd ${shSingleQuote(cwd)}
39850
39985
  /bin/sh ${shSingleQuote(innerPath)} >>${shSingleQuote(logPath)} 2>&1
39851
39986
  `
39852
39987
  );
39853
- const proc = spawn7(
39988
+ const proc = spawn8(
39854
39989
  "/bin/sh",
39855
39990
  [runnerPath],
39856
39991
  mergePreviewEnvironmentSpawnOptions(
@@ -39884,7 +40019,7 @@ CD /D ${q(cwd)}\r
39884
40019
  ${command} >> ${q(logPath)} 2>&1\r
39885
40020
  `
39886
40021
  );
39887
- const proc = spawn7(
40022
+ const proc = spawn8(
39888
40023
  com,
39889
40024
  ["/d", "/s", "/c", q(runnerPath)],
39890
40025
  mergePreviewEnvironmentSpawnOptions(
@@ -39906,7 +40041,7 @@ ${command} >> ${q(logPath)} 2>&1\r
39906
40041
  }
39907
40042
 
39908
40043
  // ../bridge/src/preview-environments/manager/shell-spawn/try-spawn-inherit.ts
39909
- import { spawn as spawn8 } from "node:child_process";
40044
+ import { spawn as spawn9 } from "node:child_process";
39910
40045
  function trySpawnInheritStdio(command, env, cwd, signal, lifecycle) {
39911
40046
  const opts = mergePreviewEnvironmentSpawnOptions(
39912
40047
  {
@@ -39921,9 +40056,9 @@ function trySpawnInheritStdio(command, env, cwd, signal, lifecycle) {
39921
40056
  if (process.platform === "win32") {
39922
40057
  opts.windowsHide = true;
39923
40058
  const com = process.env.ComSpec || "cmd.exe";
39924
- proc = spawn8(com, ["/d", "/s", "/c", command], opts);
40059
+ proc = spawn9(com, ["/d", "/s", "/c", command], opts);
39925
40060
  } else {
39926
- proc = spawn8("/bin/sh", ["-c", command], opts);
40061
+ proc = spawn9("/bin/sh", ["-c", command], opts);
39927
40062
  }
39928
40063
  return { proc, pipedStdoutStderr: false };
39929
40064
  }
@@ -40398,7 +40533,7 @@ function createBridgeHeartbeatController(params) {
40398
40533
  }
40399
40534
 
40400
40535
  // ../bridge/src/cli/cli-version.ts
40401
- var CLI_VERSION = "0.1.90".length > 0 ? "0.1.90" : "0.0.0-dev";
40536
+ var CLI_VERSION = "0.1.91".length > 0 ? "0.1.91" : "0.0.0-dev";
40402
40537
 
40403
40538
  // ../bridge/src/connection/identify/send-bridge-identify.ts
40404
40539
  function sendBridgeIdentify(ws, params) {
@@ -40674,7 +40809,7 @@ var import_debug = __toESM(require_src(), 1);
40674
40809
  var import_promise_deferred = __toESM(require_dist2(), 1);
40675
40810
  var import_promise_deferred2 = __toESM(require_dist2(), 1);
40676
40811
  import { Buffer as Buffer2 } from "node:buffer";
40677
- import { spawn as spawn9 } from "child_process";
40812
+ import { spawn as spawn10 } from "child_process";
40678
40813
  import { normalize as normalize3 } from "node:path";
40679
40814
  import { EventEmitter } from "node:events";
40680
40815
  var __defProp2 = Object.defineProperty;
@@ -42062,7 +42197,7 @@ var init_git_executor_chain = __esm2({
42062
42197
  rejection = reason || rejection;
42063
42198
  }
42064
42199
  });
42065
- const spawned = spawn9(command, args, spawnOptions);
42200
+ const spawned = spawn10(command, args, spawnOptions);
42066
42201
  spawned.stdout.on(
42067
42202
  "data",
42068
42203
  onDataReceived(stdOut, "stdOut", logger, outputLogger.step("stdOut"))
@@ -45665,7 +45800,7 @@ import * as path42 from "node:path";
45665
45800
 
45666
45801
  // ../bridge/src/git/changes/lines/count-lines.ts
45667
45802
  import { createReadStream } from "node:fs";
45668
- import * as readline3 from "node:readline";
45803
+ import * as readline4 from "node:readline";
45669
45804
  function countLinesInText(text) {
45670
45805
  return splitTextIntoDiffLines(text).length;
45671
45806
  }
@@ -45674,7 +45809,7 @@ async function countTextFileLines(filePath) {
45674
45809
  const maxBytes = 512e3;
45675
45810
  let lines = 0;
45676
45811
  const stream = createReadStream(filePath, { encoding: "utf8" });
45677
- const rl = readline3.createInterface({ input: stream, crlfDelay: Infinity });
45812
+ const rl = readline4.createInterface({ input: stream, crlfDelay: Infinity });
45678
45813
  for await (const _line of rl) {
45679
45814
  lines += 1;
45680
45815
  bytes += Buffer.byteLength(String(_line), "utf8") + 1;
@@ -50326,159 +50461,24 @@ var handleInstalledAgentAuthSync = (msg) => {
50326
50461
  );
50327
50462
  };
50328
50463
 
50329
- // ../bridge/src/agents/install/run-streaming-command.ts
50330
- import { spawn as spawn10 } from "node:child_process";
50331
- import * as readline4 from "node:readline";
50332
- function runStreamingCommand(command, args, options) {
50333
- return new Promise((resolve36, reject) => {
50334
- const child = spawn10(command, args, {
50335
- env: options.env,
50336
- stdio: ["ignore", "pipe", "pipe"]
50337
- });
50338
- let settled = false;
50339
- const timer = options.timeoutMs != null ? setTimeout(() => {
50340
- child.kill("SIGKILL");
50341
- if (!settled) {
50342
- settled = true;
50343
- reject(new Error(`Command timed out after ${options.timeoutMs}ms`));
50344
- }
50345
- }, options.timeoutMs) : null;
50346
- const onLine = (line) => {
50347
- if (line.length > 0) options.onLine?.(line);
50348
- };
50349
- if (child.stdout) {
50350
- readline4.createInterface({ input: child.stdout, crlfDelay: Infinity }).on("line", onLine);
50351
- }
50352
- if (child.stderr) {
50353
- readline4.createInterface({ input: child.stderr, crlfDelay: Infinity }).on("line", onLine);
50354
- }
50355
- child.on("error", (err) => {
50356
- if (timer) clearTimeout(timer);
50357
- if (!settled) {
50358
- settled = true;
50359
- reject(err);
50360
- }
50361
- });
50362
- child.on("close", (code, signal) => {
50363
- if (timer) clearTimeout(timer);
50364
- if (!settled) {
50365
- settled = true;
50366
- resolve36({ code, signal });
50367
- }
50368
- });
50369
- });
50370
- }
50371
-
50372
- // ../bridge/src/agents/install/commands/run-npm-global-install.ts
50373
- async function runNpmGlobalInstall(packageName, env, options) {
50374
- const result = await runStreamingCommand("npm", ["install", "-g", packageName], {
50375
- env: bridgeAgentPathEnv(env),
50376
- timeoutMs: options?.timeoutMs ?? 3e5,
50377
- onLine: options?.onLine
50378
- });
50379
- if (result.code !== 0) {
50380
- throw new Error(`npm install -g ${packageName} failed (exit ${result.code ?? "signal"})`);
50381
- }
50382
- }
50383
-
50384
- // ../bridge/src/agents/install/commands/claude-code.ts
50385
- var claudeCodeInstallCommand = {
50386
- agentType: "claude-code",
50387
- detectCommand: "claude",
50388
- async install(ctx) {
50389
- ctx.onProgress?.("Installing Anthropic Claude Code");
50390
- await runNpmGlobalInstall(
50391
- "@anthropic-ai/claude-code",
50392
- { ...ctx.env, ANTHROPIC_API_KEY: ctx.authToken },
50393
- { onLine: (line) => ctx.onProgress?.("Installing Anthropic Claude Code", line) }
50394
- );
50395
- }
50396
- };
50397
-
50398
- // ../bridge/src/agents/install/commands/codex-acp.ts
50399
- var codexAcpInstallCommand = {
50400
- agentType: "codex-acp",
50401
- detectCommand: "codex",
50402
- async install(ctx) {
50403
- ctx.onProgress?.("Installing Codex");
50404
- await runNpmGlobalInstall(
50405
- "@openai/codex",
50406
- { ...ctx.env, OPENAI_API_KEY: ctx.authToken },
50407
- { onLine: (line) => ctx.onProgress?.("Installing Codex", line) }
50408
- );
50409
- }
50410
- };
50411
-
50412
- // ../bridge/src/agents/install/commands/cursor-cli.ts
50413
- var cursorCliInstallCommand = {
50414
- agentType: "cursor-cli",
50415
- detectCommand: "agent",
50416
- alternateDetectCommands: ["cursor-agent"],
50417
- async install(ctx) {
50418
- ctx.onProgress?.("Installing Cursor CLI");
50419
- const result = await runStreamingCommand(
50420
- "bash",
50421
- ["-lc", "curl -fsSL https://cursor.com/install | bash"],
50422
- {
50423
- timeoutMs: 3e5,
50424
- env: { ...bridgeAgentPathEnv(ctx.env), CURSOR_API_KEY: ctx.authToken },
50425
- onLine: (line) => ctx.onProgress?.("Installing Cursor CLI", line)
50426
- }
50427
- );
50428
- if (result.code !== 0) {
50429
- throw new Error(`Cursor CLI install failed (exit ${result.code ?? "signal"})`);
50430
- }
50431
- }
50432
- };
50433
-
50434
- // ../bridge/src/agents/install/commands/opencode.ts
50435
- var opencodeInstallCommand = {
50436
- agentType: "opencode",
50437
- detectCommand: "opencode",
50438
- async install(ctx) {
50439
- ctx.onProgress?.("Installing OpenCode");
50440
- await runNpmGlobalInstall(
50441
- "opencode-ai",
50442
- { ...ctx.env, OPENCODE_API_KEY: ctx.authToken },
50443
- { onLine: (line) => ctx.onProgress?.("Installing OpenCode", line) }
50444
- );
50445
- }
50446
- };
50447
-
50448
- // ../bridge/src/agents/install/commands/index.ts
50449
- var COMMANDS = [
50450
- claudeCodeInstallCommand,
50451
- codexAcpInstallCommand,
50452
- cursorCliInstallCommand,
50453
- opencodeInstallCommand
50454
- ];
50455
- var byType = new Map(COMMANDS.map((c) => [c.agentType, c]));
50456
- function getAgentInstallCommand(agentType) {
50457
- return byType.get(agentType);
50458
- }
50459
-
50460
50464
  // ../bridge/src/agents/install/install-local-agent.ts
50461
50465
  async function installLocalAgentOnBridge(params) {
50462
- const spec = INSTALLABLE_BRIDGE_AGENTS.find((a) => a.value === params.agentType);
50463
- if (!spec) return { success: false, error: `Unsupported agent type: ${params.agentType}` };
50464
- const command = getAgentInstallCommand(params.agentType);
50465
- if (!command) return { success: false, error: `No install command for ${params.agentType}` };
50466
- params.onProgress?.(`Configuring ${spec.label} credentials`);
50466
+ const provider = getAgentProvider(params.agentType);
50467
+ const install = provider?.install;
50468
+ if (!provider || !install) return { success: false, error: `Unsupported agent type: ${params.agentType}` };
50469
+ params.onProgress?.(`Configuring ${provider.displayName} credentials`);
50467
50470
  try {
50468
- await command.install({
50471
+ await install.run({
50469
50472
  authToken: params.authToken,
50470
50473
  onProgress: params.onProgress,
50471
- env: { ...process.env, [spec.tokenEnvVar]: params.authToken }
50474
+ env: { ...process.env, [install.tokenEnvVar]: params.authToken }
50472
50475
  });
50473
50476
  } catch (e) {
50474
50477
  const msg = e instanceof Error ? e.message : String(e);
50475
50478
  return { success: false, error: msg };
50476
50479
  }
50477
50480
  ensureBridgeAgentPathInProcessEnv();
50478
- const detectNames = [
50479
- command.detectCommand,
50480
- ...command.alternateDetectCommands ?? []
50481
- ];
50481
+ const detectNames = [install.detectCommand, ...install.alternateDetectCommands ?? []];
50482
50482
  let found = false;
50483
50483
  for (const name of detectNames) {
50484
50484
  if (await waitForCommandOnPath(name)) {
@@ -50487,7 +50487,7 @@ async function installLocalAgentOnBridge(params) {
50487
50487
  }
50488
50488
  }
50489
50489
  if (!found) {
50490
- return { success: false, error: `${command.detectCommand} not found on PATH after install` };
50490
+ return { success: false, error: `${install.detectCommand} not found on PATH after install` };
50491
50491
  }
50492
50492
  return { success: true };
50493
50493
  }
@@ -51645,7 +51645,7 @@ var handleRenameSessionBranchMessage = (msg, deps) => {
51645
51645
  var handleSessionArchivedMessage = (msg, deps) => {
51646
51646
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
51647
51647
  if (!sessionId) return;
51648
- cleanupSessionPlans(sessionId);
51648
+ notifyAgentProvidersSessionClosed(sessionId);
51649
51649
  void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
51650
51650
  };
51651
51651
 
@@ -51653,7 +51653,7 @@ var handleSessionArchivedMessage = (msg, deps) => {
51653
51653
  var handleSessionDiscardedMessage = (msg, deps) => {
51654
51654
  const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
51655
51655
  if (!sessionId) return;
51656
- cleanupSessionPlans(sessionId);
51656
+ notifyAgentProvidersSessionClosed(sessionId);
51657
51657
  void deps.sessionWorktreeManager.removeSessionWorktrees(sessionId);
51658
51658
  };
51659
51659
 
@@ -53458,7 +53458,7 @@ function createPendingAuthOnMessage(params) {
53458
53458
  }
53459
53459
 
53460
53460
  // src/cli-version.ts
53461
- var CLI_VERSION2 = "0.1.90".length > 0 ? "0.1.90" : "0.0.0-dev";
53461
+ var CLI_VERSION2 = "0.1.91".length > 0 ? "0.1.91" : "0.0.0-dev";
53462
53462
 
53463
53463
  // src/auth/pending/pending-auth-on-open.ts
53464
53464
  function createPendingAuthOnOpen(params) {