@buildautomaton/cli 0.1.45 → 0.1.46

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
@@ -5233,7 +5233,7 @@ var require_websocket = __commonJS({
5233
5233
  "use strict";
5234
5234
  var EventEmitter2 = __require("events");
5235
5235
  var https2 = __require("https");
5236
- var http = __require("http");
5236
+ var http2 = __require("http");
5237
5237
  var net = __require("net");
5238
5238
  var tls = __require("tls");
5239
5239
  var { randomBytes: randomBytes3, createHash: createHash3 } = __require("crypto");
@@ -5767,7 +5767,7 @@ var require_websocket = __commonJS({
5767
5767
  }
5768
5768
  const defaultPort = isSecure ? 443 : 80;
5769
5769
  const key = randomBytes3(16).toString("base64");
5770
- const request = isSecure ? https2.request : http.request;
5770
+ const request = isSecure ? https2.request : http2.request;
5771
5771
  const protocolSet = /* @__PURE__ */ new Set();
5772
5772
  let perMessageDeflate;
5773
5773
  opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
@@ -6261,7 +6261,7 @@ var require_websocket_server = __commonJS({
6261
6261
  "../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js"(exports, module) {
6262
6262
  "use strict";
6263
6263
  var EventEmitter2 = __require("events");
6264
- var http = __require("http");
6264
+ var http2 = __require("http");
6265
6265
  var { Duplex } = __require("stream");
6266
6266
  var { createHash: createHash3 } = __require("crypto");
6267
6267
  var extension = require_extension();
@@ -6336,8 +6336,8 @@ var require_websocket_server = __commonJS({
6336
6336
  );
6337
6337
  }
6338
6338
  if (options.port != null) {
6339
- this._server = http.createServer((req, res) => {
6340
- const body = http.STATUS_CODES[426];
6339
+ this._server = http2.createServer((req, res) => {
6340
+ const body = http2.STATUS_CODES[426];
6341
6341
  res.writeHead(426, {
6342
6342
  "Content-Length": body.length,
6343
6343
  "Content-Type": "text/plain"
@@ -6624,7 +6624,7 @@ var require_websocket_server = __commonJS({
6624
6624
  this.destroy();
6625
6625
  }
6626
6626
  function abortHandshake(socket, code, message, headers) {
6627
- message = message || http.STATUS_CODES[code];
6627
+ message = message || http2.STATUS_CODES[code];
6628
6628
  headers = {
6629
6629
  Connection: "close",
6630
6630
  "Content-Type": "text/html",
@@ -6633,7 +6633,7 @@ var require_websocket_server = __commonJS({
6633
6633
  };
6634
6634
  socket.once("finish", socket.destroy);
6635
6635
  socket.end(
6636
- `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r
6636
+ `HTTP/1.1 ${code} ${http2.STATUS_CODES[code]}\r
6637
6637
  ` + Object.keys(headers).map((h) => `${h}: ${headers[h]}`).join("\r\n") + "\r\n\r\n" + message
6638
6638
  );
6639
6639
  }
@@ -25174,7 +25174,7 @@ var {
25174
25174
  } = import_index.default;
25175
25175
 
25176
25176
  // src/cli-version.ts
25177
- var CLI_VERSION = "0.1.45".length > 0 ? "0.1.45" : "0.0.0-dev";
25177
+ var CLI_VERSION = "0.1.46".length > 0 ? "0.1.46" : "0.0.0-dev";
25178
25178
 
25179
25179
  // src/cli/defaults.ts
25180
25180
  var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
@@ -27479,6 +27479,7 @@ var AcpPromptRoutingRegistry = class {
27479
27479
  function createAcpManagerContext(options) {
27480
27480
  return {
27481
27481
  log: options.log,
27482
+ getBridgeAccessPort: options.getBridgeAccessPort,
27482
27483
  reportAgentCapabilities: options.reportAgentCapabilities,
27483
27484
  backendFallbackAgentType: null,
27484
27485
  acpAgents: /* @__PURE__ */ new Map(),
@@ -28751,7 +28752,7 @@ function createSdkStdioSessionContext(options) {
28751
28752
  return {
28752
28753
  cwd: options.cwd,
28753
28754
  onFileChange: options.onFileChange,
28754
- mcpServers: [],
28755
+ mcpServers: options.mcpServers ?? [],
28755
28756
  persistedAcpSessionId: options.persistedAcpSessionId,
28756
28757
  agentLabel: "ACP",
28757
28758
  suppressLoadReplay: suppressLoadReplayRef,
@@ -29194,6 +29195,7 @@ async function createSdkStdioAcpClient(options) {
29194
29195
  });
29195
29196
  const sessionCtx = createSdkStdioSessionContext({
29196
29197
  cwd,
29198
+ mcpServers: options.mcpServers,
29197
29199
  persistedAcpSessionId,
29198
29200
  backendAgentType,
29199
29201
  agentConfig,
@@ -29325,7 +29327,7 @@ function createCursorAcpSessionContext(options) {
29325
29327
  return {
29326
29328
  cwd: options.cwd,
29327
29329
  onFileChange: options.onFileChange,
29328
- mcpServers: [],
29330
+ mcpServers: options.mcpServers ?? [],
29329
29331
  persistedAcpSessionId: options.persistedAcpSessionId,
29330
29332
  agentLabel: "Cursor",
29331
29333
  suppressLoadReplay: suppressLoadReplayRef,
@@ -29751,6 +29753,7 @@ async function createCursorAcpClient(options) {
29751
29753
  });
29752
29754
  const sessionCtx = createCursorAcpSessionContext({
29753
29755
  cwd,
29756
+ mcpServers: options.mcpServers,
29754
29757
  persistedAcpSessionId,
29755
29758
  backendAgentType,
29756
29759
  agentConfig: options.agentConfig,
@@ -30709,6 +30712,30 @@ function computeAcpAgentKey(preferredAgentType, mode, agentConfig) {
30709
30712
  return `${resolved.label}::${fullCmd.join("\0")}${cacheConfig}`;
30710
30713
  }
30711
30714
 
30715
+ // src/mcp/bridge-mcp-constants.ts
30716
+ var BRIDGE_MCP_SERVER_NAME = "buildautomaton-bridge";
30717
+
30718
+ // src/mcp/resolve-bridge-mcp-server-path.ts
30719
+ import { dirname as dirname4, join as join3 } from "node:path";
30720
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
30721
+ function resolveBridgeMcpServerScriptPath() {
30722
+ const cliDir = dirname4(fileURLToPath4(import.meta.url));
30723
+ return join3(cliDir, "bridge-mcp-server.js");
30724
+ }
30725
+
30726
+ // src/mcp/build-acp-mcp-servers.ts
30727
+ function buildAcpMcpServers(bridgeAccessPort) {
30728
+ if (!Number.isFinite(bridgeAccessPort) || bridgeAccessPort <= 0) return [];
30729
+ return [
30730
+ {
30731
+ name: BRIDGE_MCP_SERVER_NAME,
30732
+ command: process.execPath,
30733
+ args: [resolveBridgeMcpServerScriptPath(), String(bridgeAccessPort)],
30734
+ env: []
30735
+ }
30736
+ ];
30737
+ }
30738
+
30712
30739
  // src/agents/acp/ensure-acp-client.ts
30713
30740
  function invalidateAcpClientState(state) {
30714
30741
  state.clientEpoch += 1;
@@ -30740,11 +30767,13 @@ async function ensureAcpClient(options) {
30740
30767
  sessionParentPath,
30741
30768
  resolveRouting,
30742
30769
  cloudSessionId,
30770
+ bridgeAccessPort,
30743
30771
  reportAgentCapabilities,
30744
30772
  sendSessionUpdate,
30745
30773
  sendRequest,
30746
30774
  log: log2
30747
30775
  } = options;
30776
+ const mcpServers = buildAcpMcpServers(bridgeAccessPort ?? 0);
30748
30777
  state.latestAgentConfigForBridgeHooks = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
30749
30778
  const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
30750
30779
  if (state.acpStartPromise && !state.acpHandle) {
@@ -30860,7 +30889,8 @@ async function ensureAcpClient(options) {
30860
30889
  state.lastAcpStartError = "Agent subprocess exited";
30861
30890
  },
30862
30891
  ...hooks,
30863
- cwd: targetSessionParentPath
30892
+ cwd: targetSessionParentPath,
30893
+ mcpServers
30864
30894
  }).then(async (h) => {
30865
30895
  if (spawnEpoch !== state.clientEpoch || isCliImmediateShutdownRequested()) {
30866
30896
  try {
@@ -35841,7 +35871,7 @@ async function putEncryptedChangeSummaryRows(params) {
35841
35871
  return { path: path46, summary: JSON.stringify(enc) };
35842
35872
  });
35843
35873
  const res = await fetch(
35844
- `${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
35874
+ `${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
35845
35875
  {
35846
35876
  method: "PUT",
35847
35877
  headers: {
@@ -35980,8 +36010,8 @@ async function fetchSessionAttachmentPayloadsForAgent(params) {
35980
36010
  for (const a of attachments) {
35981
36011
  const id = typeof a.attachmentId === "string" ? a.attachmentId.trim() : "";
35982
36012
  if (!id) continue;
35983
- const metaUrl = `${base}/api/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/meta`;
35984
- const blobUrl = `${base}/api/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/blob`;
36013
+ const metaUrl = `${base}/internal/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/meta`;
36014
+ const blobUrl = `${base}/internal/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/blob`;
35985
36015
  const metaRes = await fetch(metaUrl, { headers: { Authorization: `Bearer ${token}` } });
35986
36016
  if (!metaRes.ok) {
35987
36017
  const t = await metaRes.text().catch(() => "");
@@ -36029,6 +36059,106 @@ async function fetchSessionAttachmentPayloadsForAgent(params) {
36029
36059
  return { ok: true, images: out };
36030
36060
  }
36031
36061
 
36062
+ // src/agents/acp/build-forked-session-agent-prompt.ts
36063
+ function buildForkedSessionAgentPrompt(userPrompt, childSessionId, parentSessionId) {
36064
+ const childRef = childSessionId.trim();
36065
+ const parentRef = parentSessionId.trim();
36066
+ return [
36067
+ "You are working in a new session that was forked from a prior session.",
36068
+ `This forked session id: ${childRef}`,
36069
+ `Parent session id: ${parentRef}`,
36070
+ "",
36071
+ "The parent session history is available through MCP tools on the buildautomaton-bridge server:",
36072
+ "- list_parent_session_prompts \u2014 list each user prompt / turn in the parent session",
36073
+ "- get_parent_session_turn_transcript \u2014 full transcript for one turn (including tool calls); requires turnId",
36074
+ "",
36075
+ "When calling these tools, always pass this forked session id as sessionId (not the parent session id).",
36076
+ "",
36077
+ "Use these tools when you need prior context instead of guessing.",
36078
+ "",
36079
+ "User request:",
36080
+ userPrompt.trim()
36081
+ ].join("\n");
36082
+ }
36083
+
36084
+ // src/mcp/tools/session-history/fetch-parent-session-cloud.ts
36085
+ function internalApiBase(cloudApiBaseUrl) {
36086
+ return cloudApiBaseUrl.replace(/\/+$/, "");
36087
+ }
36088
+ async function fetchCloudSessionMeta(params) {
36089
+ const token = params.getCloudAccessToken();
36090
+ if (!token) return { ok: false, error: "Missing cloud access token." };
36091
+ const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.sessionId)}/meta`;
36092
+ const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
36093
+ if (!res.ok) {
36094
+ const t = await res.text().catch(() => "");
36095
+ return { ok: false, error: `Session meta fetch failed (${res.status}): ${t.slice(0, 200)}` };
36096
+ }
36097
+ const data = await res.json().catch(() => null);
36098
+ if (!data) return { ok: false, error: "Invalid session meta response." };
36099
+ return { ok: true, data };
36100
+ }
36101
+ async function fetchCloudParentSessionPrompts(params) {
36102
+ const token = params.getCloudAccessToken();
36103
+ if (!token) return { ok: false, error: "Missing cloud access token." };
36104
+ const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/prompts`;
36105
+ const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
36106
+ if (!res.ok) {
36107
+ const t = await res.text().catch(() => "");
36108
+ return { ok: false, error: `Parent prompts fetch failed (${res.status}): ${t.slice(0, 200)}` };
36109
+ }
36110
+ const data = await res.json().catch(() => null);
36111
+ if (!data) return { ok: false, error: "Invalid parent prompts response." };
36112
+ return { ok: true, data };
36113
+ }
36114
+ async function fetchCloudParentTurnTranscript(params) {
36115
+ const token = params.getCloudAccessToken();
36116
+ if (!token) return { ok: false, error: "Missing cloud access token." };
36117
+ const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/turns/${encodeURIComponent(params.turnId)}/transcript`;
36118
+ const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
36119
+ if (!res.ok) {
36120
+ const t = await res.text().catch(() => "");
36121
+ return { ok: false, error: `Transcript fetch failed (${res.status}): ${t.slice(0, 200)}` };
36122
+ }
36123
+ const data = await res.json().catch(() => null);
36124
+ const rows = Array.isArray(data?.transcript) ? data.transcript : [];
36125
+ const lines = rows.map((row) => {
36126
+ const kind = typeof row.kind === "string" ? row.kind : "event";
36127
+ const payload = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload ?? "");
36128
+ return `[${kind}] ${payload}`;
36129
+ });
36130
+ return { ok: true, text: lines.join("\n") };
36131
+ }
36132
+ async function resolveParentSessionIdForChild(params) {
36133
+ const meta = await fetchCloudSessionMeta({
36134
+ sessionId: params.childSessionId,
36135
+ cloudApiBaseUrl: params.cloudApiBaseUrl,
36136
+ getCloudAccessToken: params.getCloudAccessToken
36137
+ });
36138
+ if (!meta.ok) return meta;
36139
+ const parent = meta.data.parentSessionId?.trim() ?? "";
36140
+ if (!parent) {
36141
+ return {
36142
+ ok: false,
36143
+ error: `Session ${params.childSessionId} has no parent session history. It was not forked from another session (no parent_session_id). Pass the forked child session id as sessionId, not the parent session id.`
36144
+ };
36145
+ }
36146
+ return { ok: true, parentSessionId: parent };
36147
+ }
36148
+
36149
+ // src/agents/acp/enrich-forked-session-prompt-for-agent.ts
36150
+ async function enrichForkedSessionPromptForAgent(params) {
36151
+ const meta = await fetchCloudSessionMeta({
36152
+ sessionId: params.sessionId,
36153
+ cloudApiBaseUrl: params.cloudApiBaseUrl,
36154
+ getCloudAccessToken: params.getCloudAccessToken
36155
+ });
36156
+ if (!meta.ok) return params.promptText;
36157
+ const parentSessionId = meta.data.parentSessionId?.trim() ?? "";
36158
+ if (!parentSessionId) return params.promptText;
36159
+ return buildForkedSessionAgentPrompt(params.promptText, params.sessionId, parentSessionId);
36160
+ }
36161
+
36032
36162
  // src/agents/acp/send-prompt-to-agent.ts
36033
36163
  async function sendPromptToAgent(options) {
36034
36164
  const {
@@ -36050,6 +36180,15 @@ async function sendPromptToAgent(options) {
36050
36180
  attachments
36051
36181
  } = options;
36052
36182
  try {
36183
+ let agentPromptText = promptText;
36184
+ if (sessionId && cloudApiBaseUrl && getCloudAccessToken) {
36185
+ agentPromptText = await enrichForkedSessionPromptForAgent({
36186
+ sessionId,
36187
+ promptText,
36188
+ cloudApiBaseUrl,
36189
+ getCloudAccessToken
36190
+ });
36191
+ }
36053
36192
  let sendOpts = {};
36054
36193
  if (attachments && attachments.length > 0) {
36055
36194
  if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
@@ -36088,7 +36227,7 @@ async function sendPromptToAgent(options) {
36088
36227
  }
36089
36228
  sendOpts = { images: resolved.images };
36090
36229
  }
36091
- const result = await handle.sendPrompt(promptText, sendOpts);
36230
+ const result = await handle.sendPrompt(agentPromptText, sendOpts);
36092
36231
  if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
36093
36232
  await collectTurnGitDiffFromPreTurnSnapshot({
36094
36233
  sessionId,
@@ -36212,6 +36351,7 @@ function handlePrompt(ctx, opts) {
36212
36351
  sessionParentPath,
36213
36352
  resolveRouting: () => ctx.promptRouting.resolveRouting(activeAcpSessionAgentKey),
36214
36353
  cloudSessionId: sessionId,
36354
+ bridgeAccessPort: ctx.getBridgeAccessPort(),
36215
36355
  sendSessionUpdate,
36216
36356
  sendRequest: sendSessionUpdate,
36217
36357
  log: ctx.log,
@@ -36298,6 +36438,7 @@ function logPromptReceivedFromBridge(ctx, opts) {
36298
36438
  async function createAcpManager(options) {
36299
36439
  const ctx = createAcpManagerContext({
36300
36440
  log: options.log,
36441
+ getBridgeAccessPort: options.getBridgeAccessPort,
36301
36442
  reportAgentCapabilities: options.reportAgentCapabilities
36302
36443
  });
36303
36444
  return {
@@ -41950,6 +42091,232 @@ async function warmupAgentCapabilitiesOnConnect(params) {
41950
42091
  })();
41951
42092
  }
41952
42093
 
42094
+ // src/mcp/tools/session-history/fork-session-mcp-tools.ts
42095
+ var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
42096
+ var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
42097
+ var SESSION_ID_SCHEMA = {
42098
+ type: "string",
42099
+ description: "Id of this forked (child) session \u2014 not the parent session id. Required on every tool call."
42100
+ };
42101
+ var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
42102
+ {
42103
+ name: LIST_PARENT_SESSION_PROMPTS_TOOL,
42104
+ description: "List user prompts (main turns) from the parent session a fork was created from. Requires sessionId. Returns an error if the session has no parent history (not a fork).",
42105
+ inputSchema: {
42106
+ type: "object",
42107
+ properties: { sessionId: SESSION_ID_SCHEMA },
42108
+ required: ["sessionId"],
42109
+ additionalProperties: false
42110
+ }
42111
+ },
42112
+ {
42113
+ name: GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL,
42114
+ description: "Full transcript for one parent-session turn, including tool calls and agent messages. Requires sessionId and turnId. Returns an error if the session has no parent history (not a fork).",
42115
+ inputSchema: {
42116
+ type: "object",
42117
+ properties: {
42118
+ sessionId: SESSION_ID_SCHEMA,
42119
+ turnId: { type: "string", description: "Turn id from list_parent_session_prompts" }
42120
+ },
42121
+ required: ["sessionId", "turnId"],
42122
+ additionalProperties: false
42123
+ }
42124
+ }
42125
+ ];
42126
+ function textResult(text, isError = false) {
42127
+ return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
42128
+ }
42129
+ function isForkSessionMcpToolName(name) {
42130
+ return name === LIST_PARENT_SESSION_PROMPTS_TOOL || name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL;
42131
+ }
42132
+ async function callForkSessionMcpTool(ctx, cloud, name, args) {
42133
+ const childSessionId = ctx.sessionId.trim();
42134
+ if (!childSessionId) {
42135
+ return textResult("sessionId is required.", true);
42136
+ }
42137
+ const parentResolved = await resolveParentSessionIdForChild({
42138
+ childSessionId,
42139
+ cloudApiBaseUrl: cloud.cloudApiBaseUrl,
42140
+ getCloudAccessToken: cloud.getCloudAccessToken
42141
+ });
42142
+ if (!parentResolved.ok) {
42143
+ return textResult(parentResolved.error, true);
42144
+ }
42145
+ const parentSessionId = parentResolved.parentSessionId;
42146
+ if (name === LIST_PARENT_SESSION_PROMPTS_TOOL) {
42147
+ const detail = await fetchCloudParentSessionPrompts({
42148
+ childSessionId,
42149
+ cloudApiBaseUrl: cloud.cloudApiBaseUrl,
42150
+ getCloudAccessToken: cloud.getCloudAccessToken
42151
+ });
42152
+ if (!detail.ok) return textResult(detail.error, true);
42153
+ const turns = Array.isArray(detail.data.turns) ? detail.data.turns : [];
42154
+ const payload = turns.map((t) => ({
42155
+ turnId: typeof t.turnId === "string" ? t.turnId : "",
42156
+ title: typeof t.title === "string" ? t.title : null,
42157
+ status: typeof t.status === "string" ? t.status : null,
42158
+ promptText: typeof t.promptText === "string" ? t.promptText : null
42159
+ }));
42160
+ return textResult(JSON.stringify({ parentSessionId, turns: payload }, null, 2));
42161
+ }
42162
+ if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL) {
42163
+ const turnId = typeof args.turnId === "string" ? args.turnId.trim() : "";
42164
+ if (!turnId) return textResult("turnId is required.", true);
42165
+ const transcript = await fetchCloudParentTurnTranscript({
42166
+ childSessionId,
42167
+ turnId,
42168
+ cloudApiBaseUrl: cloud.cloudApiBaseUrl,
42169
+ getCloudAccessToken: cloud.getCloudAccessToken,
42170
+ e2ee: ctx.e2ee
42171
+ });
42172
+ if (!transcript.ok) return textResult(transcript.error, true);
42173
+ return textResult(transcript.text);
42174
+ }
42175
+ return textResult(`Unknown fork session tool: ${name}`, true);
42176
+ }
42177
+
42178
+ // src/mcp/bridge-mcp-tools.ts
42179
+ function requireCloud(shared) {
42180
+ const cloudApiBaseUrl = shared.cloudApiBaseUrl?.trim() ?? "";
42181
+ const getCloudAccessToken = shared.getCloudAccessToken;
42182
+ if (!cloudApiBaseUrl || !getCloudAccessToken) return null;
42183
+ return { cloudApiBaseUrl, getCloudAccessToken };
42184
+ }
42185
+ function createBridgeMcpToolRegistry(shared) {
42186
+ const cloud = requireCloud(shared);
42187
+ return {
42188
+ listTools: async () => [...FORK_SESSION_MCP_TOOL_DEFINITIONS],
42189
+ callTool: async (name, args) => {
42190
+ if (isForkSessionMcpToolName(name)) {
42191
+ if (!cloud) {
42192
+ return {
42193
+ content: [{ type: "text", text: "Bridge MCP tools require cloud API credentials." }],
42194
+ isError: true
42195
+ };
42196
+ }
42197
+ const sessionId = typeof args.sessionId === "string" ? args.sessionId.trim() : "";
42198
+ if (!sessionId) {
42199
+ return {
42200
+ content: [{ type: "text", text: "sessionId is required." }],
42201
+ isError: true
42202
+ };
42203
+ }
42204
+ return callForkSessionMcpTool({ ...shared, sessionId }, cloud, name, args);
42205
+ }
42206
+ throw new Error(`Unknown bridge MCP tool: ${name}`);
42207
+ }
42208
+ };
42209
+ }
42210
+
42211
+ // src/mcp/bridge-access/start-server.ts
42212
+ import * as http from "node:http";
42213
+
42214
+ // src/mcp/bridge-access/read-json-body.ts
42215
+ function readJsonBody(req) {
42216
+ return new Promise((resolve22, reject) => {
42217
+ const chunks = [];
42218
+ req.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
42219
+ req.on("end", () => {
42220
+ try {
42221
+ const raw = Buffer.concat(chunks).toString("utf8").trim();
42222
+ if (!raw) {
42223
+ resolve22({});
42224
+ return;
42225
+ }
42226
+ const parsed = JSON.parse(raw);
42227
+ resolve22(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
42228
+ } catch (e) {
42229
+ reject(e);
42230
+ }
42231
+ });
42232
+ req.on("error", reject);
42233
+ });
42234
+ }
42235
+
42236
+ // src/mcp/bridge-access/send-json-response.ts
42237
+ function sendJsonResponse(res, status, body) {
42238
+ res.writeHead(status, { "Content-Type": "application/json" });
42239
+ res.end(JSON.stringify(body));
42240
+ }
42241
+
42242
+ // src/mcp/bridge-access/handle-request.ts
42243
+ function createBridgeAccessRequestHandler(registry2) {
42244
+ return (req, res) => {
42245
+ void (async () => {
42246
+ if (req.method !== "POST") {
42247
+ sendJsonResponse(res, 405, { ok: false, error: "Method not allowed" });
42248
+ return;
42249
+ }
42250
+ try {
42251
+ const body = await readJsonBody(req);
42252
+ if (req.url === "/tools/list") {
42253
+ const tools = await Promise.resolve(registry2.listTools());
42254
+ sendJsonResponse(res, 200, { ok: true, data: tools });
42255
+ return;
42256
+ }
42257
+ if (req.url === "/tools/call") {
42258
+ const sessionId = typeof body.sessionId === "string" ? body.sessionId.trim() : "";
42259
+ if (!sessionId) {
42260
+ sendJsonResponse(res, 400, { ok: false, error: "sessionId is required" });
42261
+ return;
42262
+ }
42263
+ const name = typeof body.name === "string" ? body.name.trim() : "";
42264
+ const args = body.args && typeof body.args === "object" && !Array.isArray(body.args) ? body.args : {};
42265
+ if (!name) {
42266
+ sendJsonResponse(res, 400, { ok: false, error: "name is required" });
42267
+ return;
42268
+ }
42269
+ const data = await registry2.callTool(name, { ...args, sessionId });
42270
+ sendJsonResponse(res, 200, { ok: true, data });
42271
+ return;
42272
+ }
42273
+ sendJsonResponse(res, 404, { ok: false, error: "Not found" });
42274
+ } catch (err) {
42275
+ const message = err instanceof Error ? err.message : String(err);
42276
+ sendJsonResponse(res, 500, { ok: false, error: message });
42277
+ }
42278
+ })();
42279
+ };
42280
+ }
42281
+
42282
+ // src/mcp/bridge-access/start-server.ts
42283
+ function startBridgeAccessServer(registry2) {
42284
+ const server = http.createServer(createBridgeAccessRequestHandler(registry2));
42285
+ return new Promise((resolve22, reject) => {
42286
+ server.once("error", reject);
42287
+ server.listen(0, "127.0.0.1", () => {
42288
+ const addr = server.address();
42289
+ if (!addr || typeof addr === "string") {
42290
+ reject(new Error("Bridge access server did not bind"));
42291
+ return;
42292
+ }
42293
+ resolve22({
42294
+ port: addr.port,
42295
+ close: () => new Promise((closeResolve, closeReject) => {
42296
+ server.close((err) => err ? closeReject(err) : closeResolve());
42297
+ })
42298
+ });
42299
+ });
42300
+ });
42301
+ }
42302
+
42303
+ // src/mcp/bridge-access/create-state.ts
42304
+ async function createBridgeAccessState(options = {}) {
42305
+ const registry2 = createBridgeMcpToolRegistry({
42306
+ cloudApiBaseUrl: options.cloudApiBaseUrl,
42307
+ getCloudAccessToken: options.getCloudAccessToken,
42308
+ e2ee: options.e2ee
42309
+ });
42310
+ const server = await startBridgeAccessServer(registry2);
42311
+ return {
42312
+ getPort: () => server.port,
42313
+ getRegistry: () => registry2,
42314
+ close: async () => {
42315
+ await server.close();
42316
+ }
42317
+ };
42318
+ }
42319
+
41953
42320
  // src/connection/create-bridge-connection.ts
41954
42321
  async function createBridgeConnection(options) {
41955
42322
  const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
@@ -42012,12 +42379,18 @@ async function createBridgeConnection(options) {
42012
42379
  worktreesRootPath,
42013
42380
  log: logFn
42014
42381
  });
42382
+ const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
42383
+ const bridgeAccess = await createBridgeAccessState({
42384
+ cloudApiBaseUrl: apiUrl,
42385
+ getCloudAccessToken: () => tokens.accessToken,
42386
+ e2ee
42387
+ });
42015
42388
  const acpManager = await createAcpManager({
42016
42389
  log: logFn,
42390
+ getBridgeAccessPort: () => bridgeAccess.getPort(),
42017
42391
  reportAgentCapabilities: sendAgentCapabilitiesToBridge
42018
42392
  });
42019
42393
  logFn("CLI running. Press Ctrl+C to exit.");
42020
- const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
42021
42394
  const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
42022
42395
  const bridgeHeartbeat = createBridgeHeartbeatController({ getWs, log: logFn });
42023
42396
  const baseOnBridgeIdentified = createOnBridgeIdentified({
@@ -42083,6 +42456,7 @@ async function createBridgeConnection(options) {
42083
42456
  stopFileIndexWatcher();
42084
42457
  bridgeHeartbeat.stop();
42085
42458
  await closeBridgeConnection(state, acpManager, devServerManager, logFn);
42459
+ await bridgeAccess.close();
42086
42460
  }
42087
42461
  };
42088
42462
  }