@buildautomaton/cli 0.1.47 → 0.1.48

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
@@ -24469,7 +24469,7 @@ function installBridgeProcessResilience() {
24469
24469
  }
24470
24470
 
24471
24471
  // src/cli-version.ts
24472
- var CLI_VERSION = "0.1.47".length > 0 ? "0.1.47" : "0.0.0-dev";
24472
+ var CLI_VERSION = "0.1.48".length > 0 ? "0.1.48" : "0.0.0-dev";
24473
24473
 
24474
24474
  // src/connection/heartbeat/constants.ts
24475
24475
  var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
@@ -33121,54 +33121,167 @@ function buildForkedSessionAgentPrompt(userPrompt, childSessionId, parentSession
33121
33121
  ].join("\n");
33122
33122
  }
33123
33123
 
33124
- // src/mcp/tools/session-history/fetch-parent-session-cloud.ts
33124
+ // src/mcp/tools/session-history/cloud/internal-api.ts
33125
33125
  function internalApiBase(cloudApiBaseUrl) {
33126
33126
  return cloudApiBaseUrl.replace(/\/+$/, "");
33127
33127
  }
33128
- async function fetchCloudSessionMeta(params) {
33128
+ async function fetchInternalApiJson(params) {
33129
33129
  const token = params.getCloudAccessToken();
33130
33130
  if (!token) return { ok: false, error: "Missing cloud access token." };
33131
- const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.sessionId)}/meta`;
33131
+ const url2 = `${internalApiBase(params.cloudApiBaseUrl)}${params.path}`;
33132
33132
  const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
33133
33133
  if (!res.ok) {
33134
33134
  const t = await res.text().catch(() => "");
33135
- return { ok: false, error: `Session meta fetch failed (${res.status}): ${t.slice(0, 200)}` };
33135
+ return { ok: false, error: `${params.errorLabel} (${res.status}): ${t.slice(0, 200)}` };
33136
33136
  }
33137
33137
  const data = await res.json().catch(() => null);
33138
- if (!data) return { ok: false, error: "Invalid session meta response." };
33138
+ if (!data) return { ok: false, error: `Invalid ${params.errorLabel.toLowerCase()} response.` };
33139
33139
  return { ok: true, data };
33140
33140
  }
33141
- async function fetchCloudParentSessionPrompts(params) {
33142
- const token = params.getCloudAccessToken();
33143
- if (!token) return { ok: false, error: "Missing cloud access token." };
33144
- const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/prompts`;
33145
- const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
33146
- if (!res.ok) {
33147
- const t = await res.text().catch(() => "");
33148
- return { ok: false, error: `Parent prompts fetch failed (${res.status}): ${t.slice(0, 200)}` };
33141
+
33142
+ // src/mcp/tools/session-history/cloud/fetch-session-meta.ts
33143
+ async function fetchCloudSessionMeta(params) {
33144
+ return fetchInternalApiJson({
33145
+ ...params,
33146
+ path: `/internal/sessions/${encodeURIComponent(params.sessionId)}/meta`,
33147
+ errorLabel: "Session meta fetch failed"
33148
+ });
33149
+ }
33150
+
33151
+ // src/lib/e2ee/decrypt-stored-e2ee-content.ts
33152
+ function parseJsonObject(raw) {
33153
+ try {
33154
+ const parsed = JSON.parse(raw);
33155
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
33156
+ return parsed;
33157
+ }
33158
+ } catch {
33159
+ return null;
33149
33160
  }
33150
- const data = await res.json().catch(() => null);
33151
- if (!data) return { ok: false, error: "Invalid parent prompts response." };
33152
- return { ok: true, data };
33161
+ return null;
33153
33162
  }
33154
- async function fetchCloudParentTurnTranscript(params) {
33155
- const token = params.getCloudAccessToken();
33156
- if (!token) return { ok: false, error: "Missing cloud access token." };
33157
- const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/turns/${encodeURIComponent(params.turnId)}/transcript`;
33158
- const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
33159
- if (!res.ok) {
33160
- const t = await res.text().catch(() => "");
33161
- return { ok: false, error: `Transcript fetch failed (${res.status}): ${t.slice(0, 200)}` };
33163
+ function storedStringHasE2eeEnvelope(raw) {
33164
+ const record2 = parseJsonObject(raw);
33165
+ return record2 != null && isE2eeEnvelope(record2.ee);
33166
+ }
33167
+ function e2eeKeyIdFromStoredString(raw) {
33168
+ const record2 = parseJsonObject(raw);
33169
+ if (record2 != null && isE2eeEnvelope(record2.ee)) return record2.ee.k;
33170
+ return null;
33171
+ }
33172
+ function decryptStoredE2eeRecord(record2, e2ee) {
33173
+ if (!isE2eeEnvelope(record2.ee)) return record2;
33174
+ if (!e2ee) {
33175
+ throw new Error(`E2EE_REQUIRED:${record2.ee.k}`);
33176
+ }
33177
+ if (record2.ee.k !== e2ee.keyId) {
33178
+ throw new Error(`E2EE_KEY_MISMATCH:encrypted=${record2.ee.k}:cli=${e2ee.keyId}`);
33179
+ }
33180
+ return e2ee.decryptMessage(record2);
33181
+ }
33182
+ function formatCliE2eeDecryptError(error40, e2ee) {
33183
+ const message = error40 instanceof Error ? error40.message : String(error40);
33184
+ const required2 = /^E2EE_REQUIRED:(.+)$/.exec(message.trim());
33185
+ if (required2) {
33186
+ const keyId = required2[1]?.trim() || "unknown";
33187
+ return `Parent session content is encrypted (key ${keyId}) but this bridge was not started with E2EE certificates. Restart the CLI with your E2EE certificate to read fork parent history.`;
33188
+ }
33189
+ const mismatch = /^E2EE_KEY_MISMATCH:encrypted=(.+):cli=(.*)$/.exec(message.trim());
33190
+ if (mismatch) {
33191
+ const encryptedKeyId = mismatch[1]?.trim() || "unknown";
33192
+ const cliKeyId = mismatch[2]?.trim() || e2ee?.keyId || "none";
33193
+ return `Parent session content is encrypted with key ${encryptedKeyId}, but this bridge certificate key is ${cliKeyId}. Use the same E2EE certificate that was used for the parent session.`;
33194
+ }
33195
+ if (message.includes("E2EE key mismatch")) {
33196
+ return `Parent session content could not be decrypted: ${message}`;
33197
+ }
33198
+ return `Parent session content could not be decrypted: ${message}`;
33199
+ }
33200
+ function decryptCliE2eeTranscriptPayload(payload, e2ee) {
33201
+ const record2 = parseJsonObject(payload);
33202
+ if (!record2 || !isE2eeEnvelope(record2.ee)) return payload;
33203
+ const decrypted = decryptStoredE2eeRecord(record2, e2ee);
33204
+ if (typeof decrypted.payload === "string") return decrypted.payload;
33205
+ return JSON.stringify(decrypted.payload ?? decrypted);
33206
+ }
33207
+ function decryptCliE2eeMessageField(payload, field, e2ee) {
33208
+ if (payload == null) return null;
33209
+ const record2 = parseJsonObject(payload);
33210
+ if (!record2 || !isE2eeEnvelope(record2.ee)) return payload;
33211
+ const decrypted = decryptStoredE2eeRecord(record2, e2ee);
33212
+ const value = decrypted[field];
33213
+ if (value == null) return null;
33214
+ return typeof value === "string" ? value : JSON.stringify(value);
33215
+ }
33216
+
33217
+ // src/mcp/tools/session-history/cloud/decrypt-parent-prompt-turns.ts
33218
+ function assertE2eeRuntimeForEnvelope(raw, e2ee) {
33219
+ if (storedStringHasE2eeEnvelope(raw) && !e2ee) {
33220
+ throw new Error(`E2EE_REQUIRED:${e2eeKeyIdFromStoredString(raw) ?? "unknown"}`);
33221
+ }
33222
+ }
33223
+ function decryptParentPromptTurns(turns, e2ee) {
33224
+ return turns.map((turn) => {
33225
+ const promptRaw = typeof turn.promptText === "string" ? turn.promptText : null;
33226
+ const titleRaw = typeof turn.title === "string" ? turn.title : null;
33227
+ if (promptRaw) assertE2eeRuntimeForEnvelope(promptRaw, e2ee);
33228
+ if (titleRaw) assertE2eeRuntimeForEnvelope(titleRaw, e2ee);
33229
+ return {
33230
+ ...turn,
33231
+ promptText: decryptCliE2eeMessageField(promptRaw, "prompt", e2ee),
33232
+ title: decryptCliE2eeMessageField(titleRaw, "title", e2ee)
33233
+ };
33234
+ });
33235
+ }
33236
+
33237
+ // src/mcp/tools/session-history/cloud/fetch-parent-prompts.ts
33238
+ async function fetchCloudParentSessionPrompts(params) {
33239
+ const fetched = await fetchInternalApiJson({
33240
+ ...params,
33241
+ path: `/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/prompts`,
33242
+ errorLabel: "Parent prompts fetch failed"
33243
+ });
33244
+ if (!fetched.ok) return fetched;
33245
+ const turns = Array.isArray(fetched.data.turns) ? fetched.data.turns : [];
33246
+ try {
33247
+ const decryptedTurns = decryptParentPromptTurns(turns, params.e2ee);
33248
+ return { ok: true, data: { ...fetched.data, turns: decryptedTurns } };
33249
+ } catch (error40) {
33250
+ return { ok: false, error: formatCliE2eeDecryptError(error40, params.e2ee) };
33162
33251
  }
33163
- const data = await res.json().catch(() => null);
33164
- const rows = Array.isArray(data?.transcript) ? data.transcript : [];
33252
+ }
33253
+
33254
+ // src/mcp/tools/session-history/cloud/format-parent-transcript-text.ts
33255
+ function formatParentTranscriptText(rows, e2ee) {
33165
33256
  const lines = rows.map((row) => {
33166
33257
  const kind = typeof row.kind === "string" ? row.kind : "event";
33167
- const payload = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload ?? "");
33258
+ const rawPayload = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload ?? "");
33259
+ if (storedStringHasE2eeEnvelope(rawPayload) && !e2ee) {
33260
+ throw new Error(`E2EE_REQUIRED:${e2eeKeyIdFromStoredString(rawPayload) ?? "unknown"}`);
33261
+ }
33262
+ const payload = decryptCliE2eeTranscriptPayload(rawPayload, e2ee);
33168
33263
  return `[${kind}] ${payload}`;
33169
33264
  });
33170
- return { ok: true, text: lines.join("\n") };
33265
+ return lines.join("\n");
33171
33266
  }
33267
+
33268
+ // src/mcp/tools/session-history/cloud/fetch-parent-transcript.ts
33269
+ async function fetchCloudParentTurnTranscript(params) {
33270
+ const fetched = await fetchInternalApiJson({
33271
+ ...params,
33272
+ path: `/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/turns/${encodeURIComponent(params.turnId)}/transcript`,
33273
+ errorLabel: "Transcript fetch failed"
33274
+ });
33275
+ if (!fetched.ok) return fetched;
33276
+ const rows = Array.isArray(fetched.data.transcript) ? fetched.data.transcript : [];
33277
+ try {
33278
+ return { ok: true, text: formatParentTranscriptText(rows, params.e2ee) };
33279
+ } catch (error40) {
33280
+ return { ok: false, error: formatCliE2eeDecryptError(error40, params.e2ee) };
33281
+ }
33282
+ }
33283
+
33284
+ // src/mcp/tools/session-history/cloud/resolve-parent-session-id.ts
33172
33285
  async function resolveParentSessionIdForChild(params) {
33173
33286
  const meta = await fetchCloudSessionMeta({
33174
33287
  sessionId: params.childSessionId,
@@ -39200,9 +39313,74 @@ async function warmupAgentCapabilitiesOnConnect(params) {
39200
39313
  })();
39201
39314
  }
39202
39315
 
39203
- // src/mcp/tools/session-history/fork-session-mcp-tools.ts
39316
+ // src/mcp/tools/session-history/fork/mcp-text-result.ts
39317
+ function mcpTextResult(text, isError = false) {
39318
+ return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
39319
+ }
39320
+
39321
+ // src/mcp/tools/session-history/fork/call-get-parent-session-turn-transcript.ts
39322
+ async function callGetParentSessionTurnTranscriptTool(ctx, cloud, childSessionId, args) {
39323
+ const turnId = typeof args.turnId === "string" ? args.turnId.trim() : "";
39324
+ if (!turnId) return mcpTextResult("turnId is required.", true);
39325
+ const transcript = await fetchCloudParentTurnTranscript({
39326
+ childSessionId,
39327
+ turnId,
39328
+ cloudApiBaseUrl: cloud.cloudApiBaseUrl,
39329
+ getCloudAccessToken: cloud.getCloudAccessToken,
39330
+ e2ee: ctx.e2ee
39331
+ });
39332
+ if (!transcript.ok) return mcpTextResult(transcript.error, true);
39333
+ return mcpTextResult(transcript.text);
39334
+ }
39335
+
39336
+ // src/mcp/tools/session-history/fork/call-list-parent-session-prompts.ts
39337
+ async function callListParentSessionPromptsTool(ctx, cloud, childSessionId, parentSessionId) {
39338
+ const detail = await fetchCloudParentSessionPrompts({
39339
+ childSessionId,
39340
+ cloudApiBaseUrl: cloud.cloudApiBaseUrl,
39341
+ getCloudAccessToken: cloud.getCloudAccessToken,
39342
+ e2ee: ctx.e2ee
39343
+ });
39344
+ if (!detail.ok) return mcpTextResult(detail.error, true);
39345
+ const turns = Array.isArray(detail.data.turns) ? detail.data.turns : [];
39346
+ const payload = turns.map((t) => ({
39347
+ turnId: typeof t.turnId === "string" ? t.turnId : "",
39348
+ title: typeof t.title === "string" ? t.title : null,
39349
+ status: typeof t.status === "string" ? t.status : null,
39350
+ promptText: typeof t.promptText === "string" ? t.promptText : null
39351
+ }));
39352
+ return mcpTextResult(JSON.stringify({ parentSessionId, turns: payload }, null, 2));
39353
+ }
39354
+
39355
+ // src/mcp/tools/session-history/fork/tool-names.ts
39204
39356
  var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
39205
39357
  var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
39358
+
39359
+ // src/mcp/tools/session-history/fork/call-fork-session-mcp-tool.ts
39360
+ async function callForkSessionMcpTool(ctx, cloud, name, args) {
39361
+ const childSessionId = ctx.sessionId.trim();
39362
+ if (!childSessionId) {
39363
+ return mcpTextResult("sessionId is required.", true);
39364
+ }
39365
+ const parentResolved = await resolveParentSessionIdForChild({
39366
+ childSessionId,
39367
+ cloudApiBaseUrl: cloud.cloudApiBaseUrl,
39368
+ getCloudAccessToken: cloud.getCloudAccessToken
39369
+ });
39370
+ if (!parentResolved.ok) {
39371
+ return mcpTextResult(parentResolved.error, true);
39372
+ }
39373
+ const parentSessionId = parentResolved.parentSessionId;
39374
+ if (name === LIST_PARENT_SESSION_PROMPTS_TOOL) {
39375
+ return callListParentSessionPromptsTool(ctx, cloud, childSessionId, parentSessionId);
39376
+ }
39377
+ if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL) {
39378
+ return callGetParentSessionTurnTranscriptTool(ctx, cloud, childSessionId, args);
39379
+ }
39380
+ return mcpTextResult(`Unknown fork session tool: ${name}`, true);
39381
+ }
39382
+
39383
+ // src/mcp/tools/session-history/fork/tool-definitions.ts
39206
39384
  var SESSION_ID_SCHEMA = {
39207
39385
  type: "string",
39208
39386
  description: "Id of this forked (child) session \u2014 not the parent session id. Required on every tool call."
@@ -39232,57 +39410,11 @@ var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
39232
39410
  }
39233
39411
  }
39234
39412
  ];
39235
- function textResult(text, isError = false) {
39236
- return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
39237
- }
39413
+
39414
+ // src/mcp/tools/session-history/fork/is-fork-session-mcp-tool-name.ts
39238
39415
  function isForkSessionMcpToolName(name) {
39239
39416
  return name === LIST_PARENT_SESSION_PROMPTS_TOOL || name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL;
39240
39417
  }
39241
- async function callForkSessionMcpTool(ctx, cloud, name, args) {
39242
- const childSessionId = ctx.sessionId.trim();
39243
- if (!childSessionId) {
39244
- return textResult("sessionId is required.", true);
39245
- }
39246
- const parentResolved = await resolveParentSessionIdForChild({
39247
- childSessionId,
39248
- cloudApiBaseUrl: cloud.cloudApiBaseUrl,
39249
- getCloudAccessToken: cloud.getCloudAccessToken
39250
- });
39251
- if (!parentResolved.ok) {
39252
- return textResult(parentResolved.error, true);
39253
- }
39254
- const parentSessionId = parentResolved.parentSessionId;
39255
- if (name === LIST_PARENT_SESSION_PROMPTS_TOOL) {
39256
- const detail = await fetchCloudParentSessionPrompts({
39257
- childSessionId,
39258
- cloudApiBaseUrl: cloud.cloudApiBaseUrl,
39259
- getCloudAccessToken: cloud.getCloudAccessToken
39260
- });
39261
- if (!detail.ok) return textResult(detail.error, true);
39262
- const turns = Array.isArray(detail.data.turns) ? detail.data.turns : [];
39263
- const payload = turns.map((t) => ({
39264
- turnId: typeof t.turnId === "string" ? t.turnId : "",
39265
- title: typeof t.title === "string" ? t.title : null,
39266
- status: typeof t.status === "string" ? t.status : null,
39267
- promptText: typeof t.promptText === "string" ? t.promptText : null
39268
- }));
39269
- return textResult(JSON.stringify({ parentSessionId, turns: payload }, null, 2));
39270
- }
39271
- if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL) {
39272
- const turnId = typeof args.turnId === "string" ? args.turnId.trim() : "";
39273
- if (!turnId) return textResult("turnId is required.", true);
39274
- const transcript = await fetchCloudParentTurnTranscript({
39275
- childSessionId,
39276
- turnId,
39277
- cloudApiBaseUrl: cloud.cloudApiBaseUrl,
39278
- getCloudAccessToken: cloud.getCloudAccessToken,
39279
- e2ee: ctx.e2ee
39280
- });
39281
- if (!transcript.ok) return textResult(transcript.error, true);
39282
- return textResult(transcript.text);
39283
- }
39284
- return textResult(`Unknown fork session tool: ${name}`, true);
39285
- }
39286
39418
 
39287
39419
  // src/mcp/bridge-mcp-tools.ts
39288
39420
  function requireCloud(shared) {