@buildautomaton/cli 0.1.25 → 0.1.27
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 +328 -31
- package/dist/cli.js.map +4 -4
- package/dist/index.js +354 -57
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22933,8 +22933,77 @@ function isClaudeCodePermissionMode(value) {
|
|
|
22933
22933
|
return MODE_SET.has(value);
|
|
22934
22934
|
}
|
|
22935
22935
|
|
|
22936
|
+
// ../types/src/cli-permission-mode.ts
|
|
22937
|
+
var CLI_PERMISSION_MODE_DEFAULT = "default";
|
|
22938
|
+
var CLI_PERMISSION_MODE_DANGEROUS = "dangerous";
|
|
22939
|
+
function normalizeCliPermissionModeInput(raw) {
|
|
22940
|
+
if (typeof raw !== "string") return CLI_PERMISSION_MODE_DEFAULT;
|
|
22941
|
+
const t = raw.trim();
|
|
22942
|
+
if (t === CLI_PERMISSION_MODE_DANGEROUS) return CLI_PERMISSION_MODE_DANGEROUS;
|
|
22943
|
+
if (t === "standard") return CLI_PERMISSION_MODE_DEFAULT;
|
|
22944
|
+
return CLI_PERMISSION_MODE_DEFAULT;
|
|
22945
|
+
}
|
|
22946
|
+
|
|
22947
|
+
// ../types/src/acp-permission-auto-approve.ts
|
|
22948
|
+
function isRejectKind(kind) {
|
|
22949
|
+
return kind === "reject_once" || kind === "reject_always";
|
|
22950
|
+
}
|
|
22951
|
+
function normalizeOptions(raw) {
|
|
22952
|
+
if (!Array.isArray(raw)) return [];
|
|
22953
|
+
const out = [];
|
|
22954
|
+
for (const item of raw) {
|
|
22955
|
+
if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
|
|
22956
|
+
const o = item;
|
|
22957
|
+
const rawId = o.optionId ?? o.id;
|
|
22958
|
+
const optionId = typeof rawId === "string" && rawId.trim() !== "" ? rawId.trim() : typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : "";
|
|
22959
|
+
if (!optionId) continue;
|
|
22960
|
+
const kind = typeof o.kind === "string" ? o.kind : void 0;
|
|
22961
|
+
out.push({ optionId, ...kind ? { kind } : {} });
|
|
22962
|
+
}
|
|
22963
|
+
return out;
|
|
22964
|
+
}
|
|
22965
|
+
function pickAllowOption(options) {
|
|
22966
|
+
const nonReject = options.filter((o) => !isRejectKind(o.kind));
|
|
22967
|
+
if (nonReject.length === 0) return null;
|
|
22968
|
+
const allowOnce = nonReject.find((o) => o.kind === "allow_once");
|
|
22969
|
+
if (allowOnce) return allowOnce;
|
|
22970
|
+
const notAlways = nonReject.filter((o) => o.kind !== "allow_always");
|
|
22971
|
+
if (notAlways.length > 0) return notAlways[0] ?? null;
|
|
22972
|
+
return nonReject.find((o) => o.kind === "allow_always") ?? nonReject[0] ?? null;
|
|
22973
|
+
}
|
|
22974
|
+
function firstNonEmptyOptionsArray(...candidates) {
|
|
22975
|
+
for (const c of candidates) {
|
|
22976
|
+
if (Array.isArray(c) && c.length > 0) return c;
|
|
22977
|
+
}
|
|
22978
|
+
const fallback = candidates[0];
|
|
22979
|
+
return Array.isArray(fallback) ? fallback : [];
|
|
22980
|
+
}
|
|
22981
|
+
function extractAcpPermissionRequestOptionArray(params) {
|
|
22982
|
+
const toolCall = params.toolCall;
|
|
22983
|
+
const fromToolCall = toolCall != null && typeof toolCall === "object" && !Array.isArray(toolCall) ? toolCall : null;
|
|
22984
|
+
return firstNonEmptyOptionsArray(
|
|
22985
|
+
params.options,
|
|
22986
|
+
params.permissionOptions,
|
|
22987
|
+
fromToolCall?.options,
|
|
22988
|
+
fromToolCall?.permissionOptions
|
|
22989
|
+
);
|
|
22990
|
+
}
|
|
22991
|
+
function buildCliAutoApprovedPermissionRpcResult(requestParams) {
|
|
22992
|
+
const opt = pickAllowOption(normalizeOptions(extractAcpPermissionRequestOptionArray(requestParams)));
|
|
22993
|
+
if (!opt) return null;
|
|
22994
|
+
const kind = opt.kind?.trim();
|
|
22995
|
+
return {
|
|
22996
|
+
outcome: {
|
|
22997
|
+
outcome: "selected",
|
|
22998
|
+
optionId: opt.optionId,
|
|
22999
|
+
...kind ? { _meta: { permissionOptionKind: kind } } : {}
|
|
23000
|
+
}
|
|
23001
|
+
};
|
|
23002
|
+
}
|
|
23003
|
+
|
|
22936
23004
|
// ../types/src/agent-config.ts
|
|
22937
23005
|
var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
|
|
23006
|
+
var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
|
|
22938
23007
|
function getClaudePermissionModeFromAgentConfig(config2) {
|
|
22939
23008
|
if (!config2) return null;
|
|
22940
23009
|
const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
|
|
@@ -22942,6 +23011,10 @@ function getClaudePermissionModeFromAgentConfig(config2) {
|
|
|
22942
23011
|
const t = raw.trim();
|
|
22943
23012
|
return isClaudeCodePermissionMode(t) ? t : null;
|
|
22944
23013
|
}
|
|
23014
|
+
function getCliPermissionModeFromAgentConfig(config2) {
|
|
23015
|
+
if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
|
|
23016
|
+
return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
|
|
23017
|
+
}
|
|
22945
23018
|
|
|
22946
23019
|
// src/agents/acp/claude-acp-permission-from-session.ts
|
|
22947
23020
|
function flattenSelectOptions(options) {
|
|
@@ -23055,13 +23128,16 @@ function parseAcpInitAgentCapabilities(initResult) {
|
|
|
23055
23128
|
const canLoad = agentCapabilities?.loadSession === true;
|
|
23056
23129
|
const sessionCaps = agentCapabilities?.sessionCapabilities;
|
|
23057
23130
|
const canResume = Boolean(sessionCaps?.resume);
|
|
23058
|
-
|
|
23131
|
+
const promptCaps = agentCapabilities?.promptCapabilities;
|
|
23132
|
+
const promptSupportsImage = promptCaps?.image === true;
|
|
23133
|
+
return { canResume, canLoad, promptSupportsImage };
|
|
23059
23134
|
}
|
|
23060
23135
|
|
|
23061
23136
|
// src/agents/acp/clients/shared/bootstrap-acp-wire-session.ts
|
|
23062
23137
|
async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
|
|
23063
23138
|
const initResult = await transport.initialize(initializeRequest);
|
|
23064
|
-
const { canResume, canLoad } = parseAcpInitAgentCapabilities(initResult);
|
|
23139
|
+
const { canResume, canLoad, promptSupportsImage } = parseAcpInitAgentCapabilities(initResult);
|
|
23140
|
+
ctx.agentPromptImageSupported = promptSupportsImage;
|
|
23065
23141
|
await transport.afterInitialize?.();
|
|
23066
23142
|
const established = await establishAcpSessionWithTransport(transport, ctx, canResume, canLoad);
|
|
23067
23143
|
const sessionId = established.sessionId;
|
|
@@ -23152,11 +23228,27 @@ function normalizeAcpPromptTurnFailure(err, stderrCaptureText) {
|
|
|
23152
23228
|
}
|
|
23153
23229
|
|
|
23154
23230
|
// src/agents/acp/clients/shared/send-acp-prompt-via-transport.ts
|
|
23155
|
-
async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText) {
|
|
23231
|
+
async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText, images) {
|
|
23232
|
+
if (images && images.length > 0 && !ctx.agentPromptImageSupported) {
|
|
23233
|
+
await new Promise((r) => setImmediate(r));
|
|
23234
|
+
return normalizeAcpPromptTurnFailure(
|
|
23235
|
+
new Error(
|
|
23236
|
+
"This agent does not advertise image support in ACP (missing agentCapabilities.promptCapabilities.image). Remove images or use an agent that supports prompt images."
|
|
23237
|
+
),
|
|
23238
|
+
ctx.getStderrText()
|
|
23239
|
+
);
|
|
23240
|
+
}
|
|
23241
|
+
const textBlock = promptText.trim() !== "" ? promptText : images?.length ? " " : "";
|
|
23242
|
+
const prompt = [{ type: "text", text: textBlock }];
|
|
23243
|
+
if (images && images.length > 0) {
|
|
23244
|
+
for (const im of images) {
|
|
23245
|
+
prompt.push({ type: "image", mimeType: im.mimeType, data: im.data });
|
|
23246
|
+
}
|
|
23247
|
+
}
|
|
23156
23248
|
try {
|
|
23157
23249
|
const response = await transport.prompt({
|
|
23158
23250
|
sessionId,
|
|
23159
|
-
prompt
|
|
23251
|
+
prompt
|
|
23160
23252
|
});
|
|
23161
23253
|
await new Promise((r2) => setImmediate(r2));
|
|
23162
23254
|
const r = response;
|
|
@@ -23172,6 +23264,22 @@ async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText)
|
|
|
23172
23264
|
}
|
|
23173
23265
|
}
|
|
23174
23266
|
|
|
23267
|
+
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
23268
|
+
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
23269
|
+
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
23270
|
+
return new Promise((resolve16) => {
|
|
23271
|
+
pending.set(requestId, { resolve: resolve16, params: paramsRecord });
|
|
23272
|
+
try {
|
|
23273
|
+
onRequest?.({
|
|
23274
|
+
requestId,
|
|
23275
|
+
method: "session/request_permission",
|
|
23276
|
+
params: paramsRecord
|
|
23277
|
+
});
|
|
23278
|
+
} catch {
|
|
23279
|
+
}
|
|
23280
|
+
});
|
|
23281
|
+
}
|
|
23282
|
+
|
|
23175
23283
|
// src/agents/acp/clients/sdk/sdk-acp-session-transport.ts
|
|
23176
23284
|
function createSdkAcpSessionTransport(connection) {
|
|
23177
23285
|
const c = connection;
|
|
@@ -23282,16 +23390,11 @@ async function createSdkStdioAcpClient(options) {
|
|
|
23282
23390
|
async requestPermission(params) {
|
|
23283
23391
|
const requestId = `perm-${++permissionSeq}`;
|
|
23284
23392
|
const paramsRecord = params != null && typeof params === "object" ? params : {};
|
|
23285
|
-
|
|
23286
|
-
|
|
23287
|
-
|
|
23288
|
-
|
|
23289
|
-
|
|
23290
|
-
});
|
|
23291
|
-
} catch {
|
|
23292
|
-
}
|
|
23293
|
-
return await new Promise((resolve17) => {
|
|
23294
|
-
pendingPermissionReplies.set(requestId, { resolve: resolve17, params: paramsRecord });
|
|
23393
|
+
return await awaitSdkStdioPermissionRequestHandshake({
|
|
23394
|
+
requestId,
|
|
23395
|
+
paramsRecord,
|
|
23396
|
+
pending: pendingPermissionReplies,
|
|
23397
|
+
onRequest
|
|
23295
23398
|
});
|
|
23296
23399
|
},
|
|
23297
23400
|
async readTextFile(params) {
|
|
@@ -23321,15 +23424,17 @@ async function createSdkStdioAcpClient(options) {
|
|
|
23321
23424
|
const established = await bootstrapAcpWireSession(transport, sessionCtx, {
|
|
23322
23425
|
protocolVersion: PROTOCOL_VERSION2,
|
|
23323
23426
|
clientCapabilities: {
|
|
23324
|
-
fs: { readTextFile: true, writeTextFile: true }
|
|
23427
|
+
fs: { readTextFile: true, writeTextFile: true },
|
|
23428
|
+
prompt: { image: true }
|
|
23325
23429
|
},
|
|
23326
23430
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
23327
23431
|
});
|
|
23328
23432
|
const sessionId = established.sessionId;
|
|
23329
23433
|
settleResolve({
|
|
23330
23434
|
sessionId,
|
|
23331
|
-
async sendPrompt(prompt,
|
|
23332
|
-
|
|
23435
|
+
async sendPrompt(prompt, options2) {
|
|
23436
|
+
const imgs = options2?.images?.map((im) => ({ type: "image", mimeType: im.mimeType, data: im.dataBase64 }));
|
|
23437
|
+
return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt, imgs);
|
|
23333
23438
|
},
|
|
23334
23439
|
async cancel() {
|
|
23335
23440
|
for (const [id, entry] of [...pendingPermissionReplies.entries()]) {
|
|
@@ -23791,7 +23896,7 @@ function installBridgeProcessResilience() {
|
|
|
23791
23896
|
}
|
|
23792
23897
|
|
|
23793
23898
|
// src/cli-version.ts
|
|
23794
|
-
var CLI_VERSION = "0.1.
|
|
23899
|
+
var CLI_VERSION = "0.1.27".length > 0 ? "0.1.27" : "0.0.0-dev";
|
|
23795
23900
|
|
|
23796
23901
|
// ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
|
|
23797
23902
|
import process7 from "node:process";
|
|
@@ -29867,6 +29972,122 @@ function augmentPromptResultAuthFields(agentType, errorText) {
|
|
|
29867
29972
|
return { agentAuthRequired: true, agentType };
|
|
29868
29973
|
}
|
|
29869
29974
|
|
|
29975
|
+
// ../e2ee/src/constants.ts
|
|
29976
|
+
var E2EE_NONCE_BYTES = 12;
|
|
29977
|
+
|
|
29978
|
+
// ../e2ee/src/types.ts
|
|
29979
|
+
function isE2eeEnvelope(value) {
|
|
29980
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
29981
|
+
const o = value;
|
|
29982
|
+
return typeof o.k === "string" && typeof o.n === "string" && typeof o.c === "string";
|
|
29983
|
+
}
|
|
29984
|
+
|
|
29985
|
+
// ../e2ee/src/encoding.ts
|
|
29986
|
+
function base64UrlEncode(bytes) {
|
|
29987
|
+
let binary = "";
|
|
29988
|
+
for (let i = 0; i < bytes.length; i += 1) binary += String.fromCharCode(bytes[i]);
|
|
29989
|
+
const b64 = btoa(binary);
|
|
29990
|
+
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
29991
|
+
}
|
|
29992
|
+
function base64UrlDecode(value) {
|
|
29993
|
+
const b64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
29994
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
29995
|
+
const binary = atob(padded);
|
|
29996
|
+
const out = new Uint8Array(binary.length);
|
|
29997
|
+
for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);
|
|
29998
|
+
return out;
|
|
29999
|
+
}
|
|
30000
|
+
|
|
30001
|
+
// src/agents/acp/fetch-session-attachments.ts
|
|
30002
|
+
function metaSaysEncrypted(meta) {
|
|
30003
|
+
if (!meta) return false;
|
|
30004
|
+
const e = meta.encrypted;
|
|
30005
|
+
return e === true || e === "true" || e === 1;
|
|
30006
|
+
}
|
|
30007
|
+
function warnIfDecodedImageMagicUnexpected(buf, mimeType, idShort) {
|
|
30008
|
+
const m = mimeType.toLowerCase();
|
|
30009
|
+
if (!m.startsWith("image/") || buf.length < 4) return;
|
|
30010
|
+
const b0 = buf[0];
|
|
30011
|
+
const b1 = buf[1];
|
|
30012
|
+
const b2 = buf[2];
|
|
30013
|
+
const b3 = buf[3];
|
|
30014
|
+
let looksOk = false;
|
|
30015
|
+
if (m.includes("png") && b0 === 137 && b1 === 80 && b2 === 78 && b3 === 71) looksOk = true;
|
|
30016
|
+
else if ((m.includes("jpeg") || m.includes("jpg")) && b0 === 255 && b1 === 216 && b2 === 255) looksOk = true;
|
|
30017
|
+
else if (m.includes("gif") && b0 === 71 && b1 === 73 && b2 === 70) looksOk = true;
|
|
30018
|
+
else if (m.includes("webp") && buf.length >= 12 && buf.subarray(0, 4).toString("ascii") === "RIFF" && buf.subarray(8, 12).toString("ascii") === "WEBP")
|
|
30019
|
+
looksOk = true;
|
|
30020
|
+
else if (!/(png|jpe?g|gif|webp)/i.test(m)) looksOk = true;
|
|
30021
|
+
if (!looksOk) {
|
|
30022
|
+
logDebug(
|
|
30023
|
+
`[Agent] Attachment ${idShort} (${mimeType}): decoded bytes do not match common image signatures \u2014 wrong E2EE key, corrupt blob, or metadata mismatch. First 12 bytes (hex): ${buf.subarray(0, Math.min(12, buf.length)).toString("hex")}`
|
|
30024
|
+
);
|
|
30025
|
+
}
|
|
30026
|
+
}
|
|
30027
|
+
async function fetchSessionAttachmentPayloadsForAgent(params) {
|
|
30028
|
+
const { attachments, sessionId, cloudApiBaseUrl, getCloudAccessToken, e2ee, log: log2 } = params;
|
|
30029
|
+
const token = getCloudAccessToken();
|
|
30030
|
+
if (!token) {
|
|
30031
|
+
return { ok: false, error: "Missing cloud access token; cannot download attachments." };
|
|
30032
|
+
}
|
|
30033
|
+
const wantedCount = attachments.filter((a) => typeof a.attachmentId === "string" && a.attachmentId.trim() !== "").length;
|
|
30034
|
+
if (wantedCount === 0) {
|
|
30035
|
+
return { ok: false, error: "No valid attachment ids in prompt." };
|
|
30036
|
+
}
|
|
30037
|
+
const base = cloudApiBaseUrl.replace(/\/+$/, "");
|
|
30038
|
+
const out = [];
|
|
30039
|
+
for (const a of attachments) {
|
|
30040
|
+
const id = typeof a.attachmentId === "string" ? a.attachmentId.trim() : "";
|
|
30041
|
+
if (!id) continue;
|
|
30042
|
+
const metaUrl = `${base}/api/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/meta`;
|
|
30043
|
+
const blobUrl = `${base}/api/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/blob`;
|
|
30044
|
+
const metaRes = await fetch(metaUrl, { headers: { Authorization: `Bearer ${token}` } });
|
|
30045
|
+
if (!metaRes.ok) {
|
|
30046
|
+
const t = await metaRes.text().catch(() => "");
|
|
30047
|
+
log2(`[Agent] Attachment meta fetch failed ${metaRes.status}: ${t.slice(0, 200)}`);
|
|
30048
|
+
return { ok: false, error: `Could not load attachment (${id.slice(0, 8)}\u2026): ${metaRes.status}` };
|
|
30049
|
+
}
|
|
30050
|
+
const meta = await metaRes.json().catch(() => null);
|
|
30051
|
+
const mimeType = typeof meta?.mimeType === "string" && meta.mimeType.trim() ? meta.mimeType.trim() : a.mimeType;
|
|
30052
|
+
const blobRes = await fetch(blobUrl, { headers: { Authorization: `Bearer ${token}` } });
|
|
30053
|
+
if (!blobRes.ok) {
|
|
30054
|
+
const t = await blobRes.text().catch(() => "");
|
|
30055
|
+
log2(`[Agent] Attachment blob fetch failed ${blobRes.status}: ${t.slice(0, 200)}`);
|
|
30056
|
+
return { ok: false, error: `Could not load attachment data (${id.slice(0, 8)}\u2026): ${blobRes.status}` };
|
|
30057
|
+
}
|
|
30058
|
+
const buf = Buffer.from(await blobRes.arrayBuffer());
|
|
30059
|
+
let imageBytes;
|
|
30060
|
+
const encrypted = metaSaysEncrypted(meta);
|
|
30061
|
+
if (encrypted) {
|
|
30062
|
+
if (!e2ee) {
|
|
30063
|
+
return { ok: false, error: "Encrypted attachments require E2EE keys on this bridge." };
|
|
30064
|
+
}
|
|
30065
|
+
const k = typeof meta?.k === "string" ? meta.k : "";
|
|
30066
|
+
const n = typeof meta?.n === "string" ? meta.n : "";
|
|
30067
|
+
if (!k || !n) {
|
|
30068
|
+
return { ok: false, error: "Invalid encrypted attachment metadata (missing key id or nonce)." };
|
|
30069
|
+
}
|
|
30070
|
+
const c = base64UrlEncode(buf);
|
|
30071
|
+
imageBytes = e2ee.decryptEnvelopeToBuffer({ k, n, c });
|
|
30072
|
+
} else {
|
|
30073
|
+
imageBytes = buf;
|
|
30074
|
+
}
|
|
30075
|
+
warnIfDecodedImageMagicUnexpected(imageBytes, mimeType, id.slice(0, 8));
|
|
30076
|
+
logDebug(
|
|
30077
|
+
`[Agent] Loaded prompt image ${id.slice(0, 8)}\u2026: ${imageBytes.length} bytes, mime=${mimeType}, ${encrypted ? "E2EE decrypted" : "plaintext from storage"}`
|
|
30078
|
+
);
|
|
30079
|
+
const dataBase64 = imageBytes.toString("base64");
|
|
30080
|
+
out.push({ mimeType, dataBase64 });
|
|
30081
|
+
}
|
|
30082
|
+
if (out.length !== wantedCount) {
|
|
30083
|
+
return {
|
|
30084
|
+
ok: false,
|
|
30085
|
+
error: `Expected ${wantedCount} image attachment(s) but only loaded ${out.length} (check attachment ids and empty rows).`
|
|
30086
|
+
};
|
|
30087
|
+
}
|
|
30088
|
+
return { ok: true, images: out };
|
|
30089
|
+
}
|
|
30090
|
+
|
|
29870
30091
|
// src/agents/acp/send-prompt-to-agent.ts
|
|
29871
30092
|
async function sendPromptToAgent(options) {
|
|
29872
30093
|
const {
|
|
@@ -29884,10 +30105,49 @@ async function sendPromptToAgent(options) {
|
|
|
29884
30105
|
sessionChangeSummaryFilePaths,
|
|
29885
30106
|
cloudApiBaseUrl,
|
|
29886
30107
|
getCloudAccessToken,
|
|
29887
|
-
e2ee
|
|
30108
|
+
e2ee,
|
|
30109
|
+
attachments
|
|
29888
30110
|
} = options;
|
|
29889
30111
|
try {
|
|
29890
|
-
|
|
30112
|
+
let sendOpts = {};
|
|
30113
|
+
if (attachments && attachments.length > 0) {
|
|
30114
|
+
if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
|
|
30115
|
+
sendResult2({
|
|
30116
|
+
type: "prompt_result",
|
|
30117
|
+
id: promptId,
|
|
30118
|
+
...sessionId ? { sessionId } : {},
|
|
30119
|
+
...runId ? { runId } : {},
|
|
30120
|
+
success: false,
|
|
30121
|
+
error: "Prompt includes images but the bridge is not configured with a cloud API URL and token to fetch them.",
|
|
30122
|
+
...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
|
|
30123
|
+
...augmentPromptResultAuthFields(agentType, "missing cloud for images download")
|
|
30124
|
+
});
|
|
30125
|
+
return;
|
|
30126
|
+
}
|
|
30127
|
+
const resolved = await fetchSessionAttachmentPayloadsForAgent({
|
|
30128
|
+
attachments,
|
|
30129
|
+
sessionId,
|
|
30130
|
+
cloudApiBaseUrl,
|
|
30131
|
+
getCloudAccessToken,
|
|
30132
|
+
e2ee,
|
|
30133
|
+
log: log2
|
|
30134
|
+
});
|
|
30135
|
+
if (!resolved.ok) {
|
|
30136
|
+
sendResult2({
|
|
30137
|
+
type: "prompt_result",
|
|
30138
|
+
id: promptId,
|
|
30139
|
+
...sessionId ? { sessionId } : {},
|
|
30140
|
+
...runId ? { runId } : {},
|
|
30141
|
+
success: false,
|
|
30142
|
+
error: resolved.error,
|
|
30143
|
+
...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
|
|
30144
|
+
...augmentPromptResultAuthFields(agentType, resolved.error)
|
|
30145
|
+
});
|
|
30146
|
+
return;
|
|
30147
|
+
}
|
|
30148
|
+
sendOpts = { images: resolved.images };
|
|
30149
|
+
}
|
|
30150
|
+
const result = await handle.sendPrompt(promptText, sendOpts);
|
|
29891
30151
|
if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
|
|
29892
30152
|
await collectTurnGitDiffFromPreTurnSnapshot({
|
|
29893
30153
|
sessionId,
|
|
@@ -30308,14 +30568,19 @@ async function createCursorAcpClient(options) {
|
|
|
30308
30568
|
});
|
|
30309
30569
|
const established = await bootstrapAcpWireSession(transport, sessionCtx, {
|
|
30310
30570
|
protocolVersion: 1,
|
|
30311
|
-
clientCapabilities: {
|
|
30571
|
+
clientCapabilities: {
|
|
30572
|
+
fs: { readTextFile: true, writeTextFile: true },
|
|
30573
|
+
terminal: false,
|
|
30574
|
+
prompt: { image: true }
|
|
30575
|
+
},
|
|
30312
30576
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
30313
30577
|
});
|
|
30314
30578
|
const sessionId = established.sessionId;
|
|
30315
30579
|
resolve16({
|
|
30316
30580
|
sessionId,
|
|
30317
|
-
async sendPrompt(prompt,
|
|
30318
|
-
|
|
30581
|
+
async sendPrompt(prompt, options2) {
|
|
30582
|
+
const imgs = options2?.images?.map((im) => ({ type: "image", mimeType: im.mimeType, data: im.dataBase64 }));
|
|
30583
|
+
return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt, imgs);
|
|
30319
30584
|
},
|
|
30320
30585
|
async cancel() {
|
|
30321
30586
|
cancelPendingPermissionRequests2();
|
|
@@ -30603,7 +30868,7 @@ function createBridgeOnFileChange(opts) {
|
|
|
30603
30868
|
|
|
30604
30869
|
// src/agents/acp/hooks/bridge-on-request.ts
|
|
30605
30870
|
function createBridgeOnRequest(opts) {
|
|
30606
|
-
const { routing, getSendRequest, log: log2 } = opts;
|
|
30871
|
+
const { routing, getSendRequest, log: log2, getAutoApproveAcpPermissions, resolveAcpPermissionRequest } = opts;
|
|
30607
30872
|
return (request) => {
|
|
30608
30873
|
const runId = routing.runId;
|
|
30609
30874
|
const sessionId = routing.sessionId;
|
|
@@ -30611,6 +30876,26 @@ function createBridgeOnRequest(opts) {
|
|
|
30611
30876
|
if (!runId || !sendReq) return;
|
|
30612
30877
|
const kind = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
|
|
30613
30878
|
const sessionUpdate = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
|
|
30879
|
+
if (request.method === "session/request_permission" && getAutoApproveAcpPermissions() && resolveAcpPermissionRequest) {
|
|
30880
|
+
const params = request.params != null && typeof request.params === "object" && !Array.isArray(request.params) ? request.params : {};
|
|
30881
|
+
const auto = buildCliAutoApprovedPermissionRpcResult(params);
|
|
30882
|
+
if (auto != null) {
|
|
30883
|
+
try {
|
|
30884
|
+
resolveAcpPermissionRequest(request.requestId, auto);
|
|
30885
|
+
log2(
|
|
30886
|
+
`[Bridge service] CLI dangerous mode: auto-approved permission requestId=${request.requestId} runId=${runId}`
|
|
30887
|
+
);
|
|
30888
|
+
return;
|
|
30889
|
+
} catch (err) {
|
|
30890
|
+
log2(
|
|
30891
|
+
`[Bridge service] CLI dangerous mode: auto-approve failed (${errorMessage(err)}); forwarding permission`
|
|
30892
|
+
);
|
|
30893
|
+
}
|
|
30894
|
+
}
|
|
30895
|
+
log2(
|
|
30896
|
+
`[Bridge service] CLI dangerous mode: no allow option to auto-select; forwarding permission requestId=${request.requestId}`
|
|
30897
|
+
);
|
|
30898
|
+
}
|
|
30614
30899
|
try {
|
|
30615
30900
|
sendReq({
|
|
30616
30901
|
type: "session_update",
|
|
@@ -31161,6 +31446,7 @@ async function ensureAcpClient(options) {
|
|
|
31161
31446
|
sendRequest,
|
|
31162
31447
|
log: log2
|
|
31163
31448
|
} = options;
|
|
31449
|
+
state.latestAgentConfigForBridgeHooks = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
|
|
31164
31450
|
const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
|
|
31165
31451
|
if (state.acpStartPromise && !state.acpHandle) {
|
|
31166
31452
|
await state.acpStartPromise;
|
|
@@ -31218,7 +31504,11 @@ async function ensureAcpClient(options) {
|
|
|
31218
31504
|
sessionParentPath: targetSessionParentPath,
|
|
31219
31505
|
getSendSessionUpdate: () => sendSessionUpdate,
|
|
31220
31506
|
getSendRequest: () => sendRequest,
|
|
31221
|
-
log: log2
|
|
31507
|
+
log: log2,
|
|
31508
|
+
getAutoApproveAcpPermissions: () => getCliPermissionModeFromAgentConfig(state.latestAgentConfigForBridgeHooks) === CLI_PERMISSION_MODE_DANGEROUS,
|
|
31509
|
+
resolveAcpPermissionRequest: (requestId, result) => {
|
|
31510
|
+
state.acpHandle?.resolveRequest?.(requestId, result);
|
|
31511
|
+
}
|
|
31222
31512
|
});
|
|
31223
31513
|
const persisted = cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "" ? readLocalAgentSessionFile(cloudSessionId) : null;
|
|
31224
31514
|
const persistedAcpSessionId = persisted && persisted.backendAgentType === preferredAgentType && typeof persisted.acpSessionId === "string" && persisted.acpSessionId.trim() !== "" ? persisted.acpSessionId.trim() : null;
|
|
@@ -31254,6 +31544,7 @@ async function ensureAcpClient(options) {
|
|
|
31254
31544
|
state.acpStartPromise = null;
|
|
31255
31545
|
state.acpAgentKey = null;
|
|
31256
31546
|
state.activeSessionConfigOptions = null;
|
|
31547
|
+
state.latestAgentConfigForBridgeHooks = null;
|
|
31257
31548
|
state.lastAcpStartError = "Agent subprocess exited";
|
|
31258
31549
|
},
|
|
31259
31550
|
...hooks,
|
|
@@ -31284,7 +31575,8 @@ async function createAcpManager(options) {
|
|
|
31284
31575
|
lastAcpStartError: null,
|
|
31285
31576
|
lastAcpCwd: null,
|
|
31286
31577
|
acpAgentKey: null,
|
|
31287
|
-
activeSessionConfigOptions: null
|
|
31578
|
+
activeSessionConfigOptions: null,
|
|
31579
|
+
latestAgentConfigForBridgeHooks: null
|
|
31288
31580
|
};
|
|
31289
31581
|
let backendFallbackAgentType = null;
|
|
31290
31582
|
const promptRouting = {};
|
|
@@ -31319,7 +31611,8 @@ async function createAcpManager(options) {
|
|
|
31319
31611
|
sessionChangeSummaryFilePaths,
|
|
31320
31612
|
cloudApiBaseUrl,
|
|
31321
31613
|
getCloudAccessToken,
|
|
31322
|
-
e2ee
|
|
31614
|
+
e2ee,
|
|
31615
|
+
attachments
|
|
31323
31616
|
} = opts;
|
|
31324
31617
|
const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
|
|
31325
31618
|
pendingCancelRunId = void 0;
|
|
@@ -31390,7 +31683,8 @@ async function createAcpManager(options) {
|
|
|
31390
31683
|
sessionChangeSummaryFilePaths,
|
|
31391
31684
|
cloudApiBaseUrl,
|
|
31392
31685
|
getCloudAccessToken,
|
|
31393
|
-
e2ee
|
|
31686
|
+
e2ee,
|
|
31687
|
+
attachments
|
|
31394
31688
|
});
|
|
31395
31689
|
}
|
|
31396
31690
|
void run().finally(() => {
|
|
@@ -31426,6 +31720,7 @@ async function createAcpManager(options) {
|
|
|
31426
31720
|
state.acpStartPromise = null;
|
|
31427
31721
|
state.acpAgentKey = null;
|
|
31428
31722
|
state.activeSessionConfigOptions = null;
|
|
31723
|
+
state.latestAgentConfigForBridgeHooks = null;
|
|
31429
31724
|
}
|
|
31430
31725
|
return {
|
|
31431
31726
|
setPreferredAgentType,
|
|
@@ -34593,7 +34888,8 @@ function dispatchLocalPrompt(next, deps) {
|
|
|
34593
34888
|
...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
|
|
34594
34889
|
...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
|
|
34595
34890
|
...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {},
|
|
34596
|
-
...pl.agentConfig != null && typeof pl.agentConfig === "object" && !Array.isArray(pl.agentConfig) && Object.keys(pl.agentConfig).length > 0 ? { agentConfig: pl.agentConfig } : {}
|
|
34891
|
+
...pl.agentConfig != null && typeof pl.agentConfig === "object" && !Array.isArray(pl.agentConfig) && Object.keys(pl.agentConfig).length > 0 ? { agentConfig: pl.agentConfig } : {},
|
|
34892
|
+
...Array.isArray(pl.attachments) && pl.attachments.length > 0 ? { attachments: pl.attachments } : {}
|
|
34597
34893
|
};
|
|
34598
34894
|
handleBridgePrompt(msg, deps);
|
|
34599
34895
|
}
|
|
@@ -34804,32 +35100,6 @@ function parseFollowUpFieldsFromPromptMessage(msg) {
|
|
|
34804
35100
|
return { followUpCatalogPromptId, sessionChangeSummaryFilePaths, sessionChangeSummaryFileSnapshots };
|
|
34805
35101
|
}
|
|
34806
35102
|
|
|
34807
|
-
// ../e2ee/src/constants.ts
|
|
34808
|
-
var E2EE_NONCE_BYTES = 12;
|
|
34809
|
-
|
|
34810
|
-
// ../e2ee/src/types.ts
|
|
34811
|
-
function isE2eeEnvelope(value) {
|
|
34812
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
34813
|
-
const o = value;
|
|
34814
|
-
return typeof o.k === "string" && typeof o.n === "string" && typeof o.c === "string";
|
|
34815
|
-
}
|
|
34816
|
-
|
|
34817
|
-
// ../e2ee/src/encoding.ts
|
|
34818
|
-
function base64UrlEncode(bytes) {
|
|
34819
|
-
let binary = "";
|
|
34820
|
-
for (let i = 0; i < bytes.length; i += 1) binary += String.fromCharCode(bytes[i]);
|
|
34821
|
-
const b64 = btoa(binary);
|
|
34822
|
-
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
34823
|
-
}
|
|
34824
|
-
function base64UrlDecode(value) {
|
|
34825
|
-
const b64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
34826
|
-
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
34827
|
-
const binary = atob(padded);
|
|
34828
|
-
const out = new Uint8Array(binary.length);
|
|
34829
|
-
for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);
|
|
34830
|
-
return out;
|
|
34831
|
-
}
|
|
34832
|
-
|
|
34833
35103
|
// src/agents/acp/change-summary/decrypt-change-summary-file-input.ts
|
|
34834
35104
|
function decryptChangeSummaryFileInput(row, e2ee) {
|
|
34835
35105
|
if (!e2ee) return row;
|
|
@@ -34886,15 +35156,30 @@ function resolveChangeSummaryPromptForAgent(params) {
|
|
|
34886
35156
|
}
|
|
34887
35157
|
|
|
34888
35158
|
// src/agents/acp/from-bridge/handle-bridge-prompt.ts
|
|
35159
|
+
function parseBridgeAttachments(msg) {
|
|
35160
|
+
const raw = msg.attachments;
|
|
35161
|
+
if (!Array.isArray(raw)) return [];
|
|
35162
|
+
const out = [];
|
|
35163
|
+
for (const x of raw) {
|
|
35164
|
+
if (x === null || typeof x !== "object" || Array.isArray(x)) continue;
|
|
35165
|
+
const o = x;
|
|
35166
|
+
const id = typeof o.attachmentId === "string" ? o.attachmentId.trim() : "";
|
|
35167
|
+
if (!id) continue;
|
|
35168
|
+
const mt = typeof o.mimeType === "string" && o.mimeType.trim() ? o.mimeType.trim() : "application/octet-stream";
|
|
35169
|
+
out.push({ attachmentId: id, mimeType: mt });
|
|
35170
|
+
}
|
|
35171
|
+
return out;
|
|
35172
|
+
}
|
|
34889
35173
|
function handleBridgePrompt(msg, deps) {
|
|
34890
35174
|
const { getWs, log: log2, acpManager, sessionWorktreeManager } = deps;
|
|
34891
35175
|
const rawPrompt = msg.prompt;
|
|
34892
35176
|
const promptText = typeof rawPrompt === "string" ? rawPrompt : rawPrompt != null ? String(rawPrompt) : "";
|
|
35177
|
+
const attachments = parseBridgeAttachments(msg);
|
|
34893
35178
|
const sessionId = msg.sessionId;
|
|
34894
35179
|
const runId = typeof msg.runId === "string" ? msg.runId : void 0;
|
|
34895
35180
|
const promptId = typeof msg.id === "string" ? msg.id : void 0;
|
|
34896
35181
|
const { sendBridgeMessage, sendResult: sendResult2, sendSessionUpdate } = createBridgePromptSenders(deps, getWs);
|
|
34897
|
-
if (!promptText.trim()) {
|
|
35182
|
+
if (!promptText.trim() && attachments.length === 0) {
|
|
34898
35183
|
log2(
|
|
34899
35184
|
`[Bridge service] Prompt ignored: empty or missing prompt text (session ${typeof msg.sessionId === "string" ? msg.sessionId.slice(0, 8) : "\u2014"}\u2026, run ${typeof msg.runId === "string" ? msg.runId.slice(0, 8) : "\u2014"}\u2026).`
|
|
34900
35185
|
);
|
|
@@ -34961,7 +35246,8 @@ function handleBridgePrompt(msg, deps) {
|
|
|
34961
35246
|
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
34962
35247
|
cloudApiBaseUrl: deps.cloudApiBaseUrl,
|
|
34963
35248
|
getCloudAccessToken: deps.getCloudAccessToken,
|
|
34964
|
-
e2ee: deps.e2ee
|
|
35249
|
+
e2ee: deps.e2ee,
|
|
35250
|
+
...attachments.length > 0 ? { attachments } : {}
|
|
34965
35251
|
});
|
|
34966
35252
|
}
|
|
34967
35253
|
void sessionWorktreeManager.resolveSessionParentPathForPrompt(sessionId, { isNewSession, sessionParent, sessionParentPath }).then((cwd) => preambleAndPrompt(cwd)).catch((err) => {
|
|
@@ -35931,6 +36217,17 @@ function createCliE2eeRuntime(key) {
|
|
|
35931
36217
|
const merged = { ...message, ...parsed };
|
|
35932
36218
|
delete merged.ee;
|
|
35933
36219
|
return merged;
|
|
36220
|
+
},
|
|
36221
|
+
decryptEnvelopeToBuffer(envelope) {
|
|
36222
|
+
if (envelope.k !== key.id) throw new Error(`E2EE key mismatch: ${envelope.k}`);
|
|
36223
|
+
const sealed = Buffer.from(base64UrlDecode(envelope.c));
|
|
36224
|
+
if (sealed.length < 16) throw new Error("Invalid E2EE payload.");
|
|
36225
|
+
const ciphertext = sealed.subarray(0, sealed.length - 16);
|
|
36226
|
+
const tag = sealed.subarray(sealed.length - 16);
|
|
36227
|
+
const nonce = Buffer.from(base64UrlDecode(envelope.n));
|
|
36228
|
+
const decipher = createDecipheriv("aes-256-gcm", rawKey, nonce);
|
|
36229
|
+
decipher.setAuthTag(tag);
|
|
36230
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
35934
36231
|
}
|
|
35935
36232
|
};
|
|
35936
36233
|
}
|