@buildautomaton/cli 0.1.44 → 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.44".length > 0 ? "0.1.44" : "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";
@@ -27438,38 +27438,38 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
27438
27438
  // src/agents/acp/acp-prompt-routing-registry.ts
27439
27439
  var AcpPromptRoutingRegistry = class {
27440
27440
  runs = /* @__PURE__ */ new Map();
27441
- streamingRunIdByAcpAgent = /* @__PURE__ */ new Map();
27441
+ streamingRunIdBySessionAgent = /* @__PURE__ */ new Map();
27442
27442
  registerRun(route) {
27443
27443
  this.runs.set(route.runId, route);
27444
27444
  }
27445
27445
  unregisterRun(runId) {
27446
27446
  this.runs.delete(runId);
27447
- for (const [acpAgentKey, streamingRunId] of this.streamingRunIdByAcpAgent.entries()) {
27447
+ for (const [sessionAgentKey, streamingRunId] of this.streamingRunIdBySessionAgent.entries()) {
27448
27448
  if (streamingRunId === runId) {
27449
- this.streamingRunIdByAcpAgent.delete(acpAgentKey);
27449
+ this.streamingRunIdBySessionAgent.delete(sessionAgentKey);
27450
27450
  }
27451
27451
  }
27452
27452
  }
27453
27453
  isRegisteredRun(runId) {
27454
27454
  return this.runs.has(runId);
27455
27455
  }
27456
- setStreamingRunId(acpAgentKey, runId) {
27456
+ setStreamingRunId(sessionAgentKey, runId) {
27457
27457
  if (runId) {
27458
- this.streamingRunIdByAcpAgent.set(acpAgentKey, runId);
27458
+ this.streamingRunIdBySessionAgent.set(sessionAgentKey, runId);
27459
27459
  } else {
27460
- this.streamingRunIdByAcpAgent.delete(acpAgentKey);
27460
+ this.streamingRunIdBySessionAgent.delete(sessionAgentKey);
27461
27461
  }
27462
27462
  }
27463
- clearStreamingRunId(acpAgentKey, runId) {
27464
- if (this.streamingRunIdByAcpAgent.get(acpAgentKey) === runId) {
27465
- this.streamingRunIdByAcpAgent.delete(acpAgentKey);
27463
+ clearStreamingRunId(sessionAgentKey, runId) {
27464
+ if (this.streamingRunIdBySessionAgent.get(sessionAgentKey) === runId) {
27465
+ this.streamingRunIdBySessionAgent.delete(sessionAgentKey);
27466
27466
  }
27467
27467
  }
27468
- getStreamingRunId(acpAgentKey) {
27469
- return this.streamingRunIdByAcpAgent.get(acpAgentKey);
27468
+ getStreamingRunId(sessionAgentKey) {
27469
+ return this.streamingRunIdBySessionAgent.get(sessionAgentKey);
27470
27470
  }
27471
- resolveRouting(acpAgentKey) {
27472
- const runId = this.streamingRunIdByAcpAgent.get(acpAgentKey);
27471
+ resolveRouting(sessionAgentKey) {
27472
+ const runId = this.streamingRunIdBySessionAgent.get(sessionAgentKey);
27473
27473
  if (!runId) return void 0;
27474
27474
  return this.runs.get(runId);
27475
27475
  }
@@ -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(),
@@ -27492,9 +27493,9 @@ function createAcpManagerContext(options) {
27492
27493
  async function cancelRun(ctx, runId) {
27493
27494
  const meta = ctx.runDispatch.get(runId);
27494
27495
  if (!meta) return false;
27495
- const streamingRunId = ctx.promptRouting.getStreamingRunId(meta.acpAgentKey);
27496
+ const streamingRunId = ctx.promptRouting.getStreamingRunId(meta.acpSessionAgentKey);
27496
27497
  if (streamingRunId && streamingRunId !== runId) return false;
27497
- const handle = ctx.acpAgents.get(meta.acpAgentKey)?.acpHandle;
27498
+ const handle = ctx.acpAgents.get(meta.acpSessionAgentKey)?.acpHandle;
27498
27499
  if (handle?.cancel) {
27499
27500
  ctx.log("[Agent] Stop requested");
27500
27501
  try {
@@ -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,
@@ -30696,6 +30699,11 @@ function writeLocalAgentSessionFile(cloudSessionId, patch) {
30696
30699
  }
30697
30700
 
30698
30701
  // src/agents/acp/acp-agent.ts
30702
+ function computeAcpSessionAgentKey(cloudSessionId, acpAgentKey) {
30703
+ const sid = cloudSessionId?.trim();
30704
+ if (!sid) return `::${acpAgentKey}`;
30705
+ return `${sid}::${acpAgentKey}`;
30706
+ }
30699
30707
  function computeAcpAgentKey(preferredAgentType, mode, agentConfig) {
30700
30708
  const resolved = resolveAgentCommand(preferredAgentType);
30701
30709
  if (!resolved) return null;
@@ -30704,6 +30712,30 @@ function computeAcpAgentKey(preferredAgentType, mode, agentConfig) {
30704
30712
  return `${resolved.label}::${fullCmd.join("\0")}${cacheConfig}`;
30705
30713
  }
30706
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
+
30707
30739
  // src/agents/acp/ensure-acp-client.ts
30708
30740
  function invalidateAcpClientState(state) {
30709
30741
  state.clientEpoch += 1;
@@ -30735,11 +30767,13 @@ async function ensureAcpClient(options) {
30735
30767
  sessionParentPath,
30736
30768
  resolveRouting,
30737
30769
  cloudSessionId,
30770
+ bridgeAccessPort,
30738
30771
  reportAgentCapabilities,
30739
30772
  sendSessionUpdate,
30740
30773
  sendRequest,
30741
30774
  log: log2
30742
30775
  } = options;
30776
+ const mcpServers = buildAcpMcpServers(bridgeAccessPort ?? 0);
30743
30777
  state.latestAgentConfigForBridgeHooks = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
30744
30778
  const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
30745
30779
  if (state.acpStartPromise && !state.acpHandle) {
@@ -30855,7 +30889,8 @@ async function ensureAcpClient(options) {
30855
30889
  state.lastAcpStartError = "Agent subprocess exited";
30856
30890
  },
30857
30891
  ...hooks,
30858
- cwd: targetSessionParentPath
30892
+ cwd: targetSessionParentPath,
30893
+ mcpServers
30859
30894
  }).then(async (h) => {
30860
30895
  if (spawnEpoch !== state.clientEpoch || isCliImmediateShutdownRequested()) {
30861
30896
  try {
@@ -35836,7 +35871,7 @@ async function putEncryptedChangeSummaryRows(params) {
35836
35871
  return { path: path46, summary: JSON.stringify(enc) };
35837
35872
  });
35838
35873
  const res = await fetch(
35839
- `${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
35874
+ `${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
35840
35875
  {
35841
35876
  method: "PUT",
35842
35877
  headers: {
@@ -35975,8 +36010,8 @@ async function fetchSessionAttachmentPayloadsForAgent(params) {
35975
36010
  for (const a of attachments) {
35976
36011
  const id = typeof a.attachmentId === "string" ? a.attachmentId.trim() : "";
35977
36012
  if (!id) continue;
35978
- const metaUrl = `${base}/api/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/meta`;
35979
- 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`;
35980
36015
  const metaRes = await fetch(metaUrl, { headers: { Authorization: `Bearer ${token}` } });
35981
36016
  if (!metaRes.ok) {
35982
36017
  const t = await metaRes.text().catch(() => "");
@@ -36024,6 +36059,106 @@ async function fetchSessionAttachmentPayloadsForAgent(params) {
36024
36059
  return { ok: true, images: out };
36025
36060
  }
36026
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
+
36027
36162
  // src/agents/acp/send-prompt-to-agent.ts
36028
36163
  async function sendPromptToAgent(options) {
36029
36164
  const {
@@ -36045,6 +36180,15 @@ async function sendPromptToAgent(options) {
36045
36180
  attachments
36046
36181
  } = options;
36047
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
+ }
36048
36192
  let sendOpts = {};
36049
36193
  if (attachments && attachments.length > 0) {
36050
36194
  if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
@@ -36083,7 +36227,7 @@ async function sendPromptToAgent(options) {
36083
36227
  }
36084
36228
  sendOpts = { images: resolved.images };
36085
36229
  }
36086
- const result = await handle.sendPrompt(promptText, sendOpts);
36230
+ const result = await handle.sendPrompt(agentPromptText, sendOpts);
36087
36231
  if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
36088
36232
  await collectTurnGitDiffFromPreTurnSnapshot({
36089
36233
  sessionId,
@@ -36144,11 +36288,11 @@ async function sendPromptToAgent(options) {
36144
36288
  }
36145
36289
 
36146
36290
  // src/agents/acp/manager/get-acp-agent-state.ts
36147
- function getAcpAgentState(ctx, acpAgentKey) {
36148
- let state = ctx.acpAgents.get(acpAgentKey);
36291
+ function getAcpSessionAgentState(ctx, acpSessionAgentKey) {
36292
+ let state = ctx.acpAgents.get(acpSessionAgentKey);
36149
36293
  if (!state) {
36150
36294
  state = createEmptyAcpClientState();
36151
- ctx.acpAgents.set(acpAgentKey, state);
36295
+ ctx.acpAgents.set(acpSessionAgentKey, state);
36152
36296
  }
36153
36297
  return state;
36154
36298
  }
@@ -36192,11 +36336,12 @@ function handlePrompt(ctx, opts) {
36192
36336
  return;
36193
36337
  }
36194
36338
  const activeAcpAgentKey = acpAgentKey;
36339
+ const activeAcpSessionAgentKey = computeAcpSessionAgentKey(sessionId, activeAcpAgentKey);
36195
36340
  ctx.pendingCancelRunIds.delete(activeRunId);
36196
36341
  ctx.promptRouting.registerRun({ sessionId, runId: activeRunId });
36197
- ctx.runDispatch.set(activeRunId, { acpAgentKey: activeAcpAgentKey });
36342
+ ctx.runDispatch.set(activeRunId, { acpSessionAgentKey: activeAcpSessionAgentKey });
36198
36343
  async function run() {
36199
- const acpAgentState = getAcpAgentState(ctx, activeAcpAgentKey);
36344
+ const acpAgentState = getAcpSessionAgentState(ctx, activeAcpSessionAgentKey);
36200
36345
  const handle = await ensureAcpClient({
36201
36346
  state: acpAgentState,
36202
36347
  acpAgentKey: activeAcpAgentKey,
@@ -36204,8 +36349,9 @@ function handlePrompt(ctx, opts) {
36204
36349
  mode,
36205
36350
  agentConfig: agentConfig ?? null,
36206
36351
  sessionParentPath,
36207
- resolveRouting: () => ctx.promptRouting.resolveRouting(activeAcpAgentKey),
36352
+ resolveRouting: () => ctx.promptRouting.resolveRouting(activeAcpSessionAgentKey),
36208
36353
  cloudSessionId: sessionId,
36354
+ bridgeAccessPort: ctx.getBridgeAccessPort(),
36209
36355
  sendSessionUpdate,
36210
36356
  sendRequest: sendSessionUpdate,
36211
36357
  log: ctx.log,
@@ -36247,7 +36393,7 @@ function handlePrompt(ctx, opts) {
36247
36393
  });
36248
36394
  return;
36249
36395
  }
36250
- ctx.promptRouting.setStreamingRunId(activeAcpAgentKey, activeRunId);
36396
+ ctx.promptRouting.setStreamingRunId(activeAcpSessionAgentKey, activeRunId);
36251
36397
  try {
36252
36398
  await sendPromptToAgent({
36253
36399
  handle,
@@ -36268,7 +36414,7 @@ function handlePrompt(ctx, opts) {
36268
36414
  attachments
36269
36415
  });
36270
36416
  } finally {
36271
- ctx.promptRouting.clearStreamingRunId(activeAcpAgentKey, activeRunId);
36417
+ ctx.promptRouting.clearStreamingRunId(activeAcpSessionAgentKey, activeRunId);
36272
36418
  }
36273
36419
  }
36274
36420
  void run().finally(() => {
@@ -36292,6 +36438,7 @@ function logPromptReceivedFromBridge(ctx, opts) {
36292
36438
  async function createAcpManager(options) {
36293
36439
  const ctx = createAcpManagerContext({
36294
36440
  log: options.log,
36441
+ getBridgeAccessPort: options.getBridgeAccessPort,
36295
36442
  reportAgentCapabilities: options.reportAgentCapabilities
36296
36443
  });
36297
36444
  return {
@@ -41944,6 +42091,232 @@ async function warmupAgentCapabilitiesOnConnect(params) {
41944
42091
  })();
41945
42092
  }
41946
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
+
41947
42320
  // src/connection/create-bridge-connection.ts
41948
42321
  async function createBridgeConnection(options) {
41949
42322
  const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
@@ -42006,12 +42379,18 @@ async function createBridgeConnection(options) {
42006
42379
  worktreesRootPath,
42007
42380
  log: logFn
42008
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
+ });
42009
42388
  const acpManager = await createAcpManager({
42010
42389
  log: logFn,
42390
+ getBridgeAccessPort: () => bridgeAccess.getPort(),
42011
42391
  reportAgentCapabilities: sendAgentCapabilitiesToBridge
42012
42392
  });
42013
42393
  logFn("CLI running. Press Ctrl+C to exit.");
42014
- const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
42015
42394
  const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
42016
42395
  const bridgeHeartbeat = createBridgeHeartbeatController({ getWs, log: logFn });
42017
42396
  const baseOnBridgeIdentified = createOnBridgeIdentified({
@@ -42077,6 +42456,7 @@ async function createBridgeConnection(options) {
42077
42456
  stopFileIndexWatcher();
42078
42457
  bridgeHeartbeat.stop();
42079
42458
  await closeBridgeConnection(state, acpManager, devServerManager, logFn);
42459
+ await bridgeAccess.close();
42080
42460
  }
42081
42461
  };
42082
42462
  }