@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/cli.js
CHANGED
|
@@ -25064,7 +25064,7 @@ var {
|
|
|
25064
25064
|
} = import_index.default;
|
|
25065
25065
|
|
|
25066
25066
|
// src/cli-version.ts
|
|
25067
|
-
var CLI_VERSION = "0.1.
|
|
25067
|
+
var CLI_VERSION = "0.1.27".length > 0 ? "0.1.27" : "0.0.0-dev";
|
|
25068
25068
|
|
|
25069
25069
|
// src/cli/defaults.ts
|
|
25070
25070
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
@@ -25352,6 +25352,17 @@ function createCliE2eeRuntime(key) {
|
|
|
25352
25352
|
const merged = { ...message, ...parsed };
|
|
25353
25353
|
delete merged.ee;
|
|
25354
25354
|
return merged;
|
|
25355
|
+
},
|
|
25356
|
+
decryptEnvelopeToBuffer(envelope) {
|
|
25357
|
+
if (envelope.k !== key.id) throw new Error(`E2EE key mismatch: ${envelope.k}`);
|
|
25358
|
+
const sealed = Buffer.from(base64UrlDecode(envelope.c));
|
|
25359
|
+
if (sealed.length < 16) throw new Error("Invalid E2EE payload.");
|
|
25360
|
+
const ciphertext = sealed.subarray(0, sealed.length - 16);
|
|
25361
|
+
const tag = sealed.subarray(sealed.length - 16);
|
|
25362
|
+
const nonce = Buffer.from(base64UrlDecode(envelope.n));
|
|
25363
|
+
const decipher = createDecipheriv("aes-256-gcm", rawKey, nonce);
|
|
25364
|
+
decipher.setAuthTag(tag);
|
|
25365
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
25355
25366
|
}
|
|
25356
25367
|
};
|
|
25357
25368
|
}
|
|
@@ -27204,8 +27215,77 @@ function isClaudeCodePermissionMode(value) {
|
|
|
27204
27215
|
return MODE_SET.has(value);
|
|
27205
27216
|
}
|
|
27206
27217
|
|
|
27218
|
+
// ../types/src/cli-permission-mode.ts
|
|
27219
|
+
var CLI_PERMISSION_MODE_DEFAULT = "default";
|
|
27220
|
+
var CLI_PERMISSION_MODE_DANGEROUS = "dangerous";
|
|
27221
|
+
function normalizeCliPermissionModeInput(raw) {
|
|
27222
|
+
if (typeof raw !== "string") return CLI_PERMISSION_MODE_DEFAULT;
|
|
27223
|
+
const t = raw.trim();
|
|
27224
|
+
if (t === CLI_PERMISSION_MODE_DANGEROUS) return CLI_PERMISSION_MODE_DANGEROUS;
|
|
27225
|
+
if (t === "standard") return CLI_PERMISSION_MODE_DEFAULT;
|
|
27226
|
+
return CLI_PERMISSION_MODE_DEFAULT;
|
|
27227
|
+
}
|
|
27228
|
+
|
|
27229
|
+
// ../types/src/acp-permission-auto-approve.ts
|
|
27230
|
+
function isRejectKind(kind) {
|
|
27231
|
+
return kind === "reject_once" || kind === "reject_always";
|
|
27232
|
+
}
|
|
27233
|
+
function normalizeOptions(raw) {
|
|
27234
|
+
if (!Array.isArray(raw)) return [];
|
|
27235
|
+
const out = [];
|
|
27236
|
+
for (const item of raw) {
|
|
27237
|
+
if (item == null || typeof item !== "object" || Array.isArray(item)) continue;
|
|
27238
|
+
const o = item;
|
|
27239
|
+
const rawId = o.optionId ?? o.id;
|
|
27240
|
+
const optionId = typeof rawId === "string" && rawId.trim() !== "" ? rawId.trim() : typeof rawId === "number" && Number.isFinite(rawId) ? String(rawId) : "";
|
|
27241
|
+
if (!optionId) continue;
|
|
27242
|
+
const kind = typeof o.kind === "string" ? o.kind : void 0;
|
|
27243
|
+
out.push({ optionId, ...kind ? { kind } : {} });
|
|
27244
|
+
}
|
|
27245
|
+
return out;
|
|
27246
|
+
}
|
|
27247
|
+
function pickAllowOption(options) {
|
|
27248
|
+
const nonReject = options.filter((o) => !isRejectKind(o.kind));
|
|
27249
|
+
if (nonReject.length === 0) return null;
|
|
27250
|
+
const allowOnce = nonReject.find((o) => o.kind === "allow_once");
|
|
27251
|
+
if (allowOnce) return allowOnce;
|
|
27252
|
+
const notAlways = nonReject.filter((o) => o.kind !== "allow_always");
|
|
27253
|
+
if (notAlways.length > 0) return notAlways[0] ?? null;
|
|
27254
|
+
return nonReject.find((o) => o.kind === "allow_always") ?? nonReject[0] ?? null;
|
|
27255
|
+
}
|
|
27256
|
+
function firstNonEmptyOptionsArray(...candidates) {
|
|
27257
|
+
for (const c of candidates) {
|
|
27258
|
+
if (Array.isArray(c) && c.length > 0) return c;
|
|
27259
|
+
}
|
|
27260
|
+
const fallback = candidates[0];
|
|
27261
|
+
return Array.isArray(fallback) ? fallback : [];
|
|
27262
|
+
}
|
|
27263
|
+
function extractAcpPermissionRequestOptionArray(params) {
|
|
27264
|
+
const toolCall = params.toolCall;
|
|
27265
|
+
const fromToolCall = toolCall != null && typeof toolCall === "object" && !Array.isArray(toolCall) ? toolCall : null;
|
|
27266
|
+
return firstNonEmptyOptionsArray(
|
|
27267
|
+
params.options,
|
|
27268
|
+
params.permissionOptions,
|
|
27269
|
+
fromToolCall?.options,
|
|
27270
|
+
fromToolCall?.permissionOptions
|
|
27271
|
+
);
|
|
27272
|
+
}
|
|
27273
|
+
function buildCliAutoApprovedPermissionRpcResult(requestParams) {
|
|
27274
|
+
const opt = pickAllowOption(normalizeOptions(extractAcpPermissionRequestOptionArray(requestParams)));
|
|
27275
|
+
if (!opt) return null;
|
|
27276
|
+
const kind = opt.kind?.trim();
|
|
27277
|
+
return {
|
|
27278
|
+
outcome: {
|
|
27279
|
+
outcome: "selected",
|
|
27280
|
+
optionId: opt.optionId,
|
|
27281
|
+
...kind ? { _meta: { permissionOptionKind: kind } } : {}
|
|
27282
|
+
}
|
|
27283
|
+
};
|
|
27284
|
+
}
|
|
27285
|
+
|
|
27207
27286
|
// ../types/src/agent-config.ts
|
|
27208
27287
|
var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
|
|
27288
|
+
var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
|
|
27209
27289
|
function getClaudePermissionModeFromAgentConfig(config2) {
|
|
27210
27290
|
if (!config2) return null;
|
|
27211
27291
|
const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
|
|
@@ -27213,6 +27293,10 @@ function getClaudePermissionModeFromAgentConfig(config2) {
|
|
|
27213
27293
|
const t = raw.trim();
|
|
27214
27294
|
return isClaudeCodePermissionMode(t) ? t : null;
|
|
27215
27295
|
}
|
|
27296
|
+
function getCliPermissionModeFromAgentConfig(config2) {
|
|
27297
|
+
if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
|
|
27298
|
+
return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
|
|
27299
|
+
}
|
|
27216
27300
|
|
|
27217
27301
|
// src/git/session-git-queue.ts
|
|
27218
27302
|
import { execFile as execFile7 } from "node:child_process";
|
|
@@ -32179,6 +32263,96 @@ function augmentPromptResultAuthFields(agentType, errorText) {
|
|
|
32179
32263
|
return { agentAuthRequired: true, agentType };
|
|
32180
32264
|
}
|
|
32181
32265
|
|
|
32266
|
+
// src/agents/acp/fetch-session-attachments.ts
|
|
32267
|
+
function metaSaysEncrypted(meta) {
|
|
32268
|
+
if (!meta) return false;
|
|
32269
|
+
const e = meta.encrypted;
|
|
32270
|
+
return e === true || e === "true" || e === 1;
|
|
32271
|
+
}
|
|
32272
|
+
function warnIfDecodedImageMagicUnexpected(buf, mimeType, idShort) {
|
|
32273
|
+
const m = mimeType.toLowerCase();
|
|
32274
|
+
if (!m.startsWith("image/") || buf.length < 4) return;
|
|
32275
|
+
const b0 = buf[0];
|
|
32276
|
+
const b1 = buf[1];
|
|
32277
|
+
const b2 = buf[2];
|
|
32278
|
+
const b3 = buf[3];
|
|
32279
|
+
let looksOk = false;
|
|
32280
|
+
if (m.includes("png") && b0 === 137 && b1 === 80 && b2 === 78 && b3 === 71) looksOk = true;
|
|
32281
|
+
else if ((m.includes("jpeg") || m.includes("jpg")) && b0 === 255 && b1 === 216 && b2 === 255) looksOk = true;
|
|
32282
|
+
else if (m.includes("gif") && b0 === 71 && b1 === 73 && b2 === 70) looksOk = true;
|
|
32283
|
+
else if (m.includes("webp") && buf.length >= 12 && buf.subarray(0, 4).toString("ascii") === "RIFF" && buf.subarray(8, 12).toString("ascii") === "WEBP")
|
|
32284
|
+
looksOk = true;
|
|
32285
|
+
else if (!/(png|jpe?g|gif|webp)/i.test(m)) looksOk = true;
|
|
32286
|
+
if (!looksOk) {
|
|
32287
|
+
logDebug(
|
|
32288
|
+
`[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")}`
|
|
32289
|
+
);
|
|
32290
|
+
}
|
|
32291
|
+
}
|
|
32292
|
+
async function fetchSessionAttachmentPayloadsForAgent(params) {
|
|
32293
|
+
const { attachments, sessionId, cloudApiBaseUrl, getCloudAccessToken, e2ee, log: log2 } = params;
|
|
32294
|
+
const token = getCloudAccessToken();
|
|
32295
|
+
if (!token) {
|
|
32296
|
+
return { ok: false, error: "Missing cloud access token; cannot download attachments." };
|
|
32297
|
+
}
|
|
32298
|
+
const wantedCount = attachments.filter((a) => typeof a.attachmentId === "string" && a.attachmentId.trim() !== "").length;
|
|
32299
|
+
if (wantedCount === 0) {
|
|
32300
|
+
return { ok: false, error: "No valid attachment ids in prompt." };
|
|
32301
|
+
}
|
|
32302
|
+
const base = cloudApiBaseUrl.replace(/\/+$/, "");
|
|
32303
|
+
const out = [];
|
|
32304
|
+
for (const a of attachments) {
|
|
32305
|
+
const id = typeof a.attachmentId === "string" ? a.attachmentId.trim() : "";
|
|
32306
|
+
if (!id) continue;
|
|
32307
|
+
const metaUrl = `${base}/api/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/meta`;
|
|
32308
|
+
const blobUrl = `${base}/api/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/blob`;
|
|
32309
|
+
const metaRes = await fetch(metaUrl, { headers: { Authorization: `Bearer ${token}` } });
|
|
32310
|
+
if (!metaRes.ok) {
|
|
32311
|
+
const t = await metaRes.text().catch(() => "");
|
|
32312
|
+
log2(`[Agent] Attachment meta fetch failed ${metaRes.status}: ${t.slice(0, 200)}`);
|
|
32313
|
+
return { ok: false, error: `Could not load attachment (${id.slice(0, 8)}\u2026): ${metaRes.status}` };
|
|
32314
|
+
}
|
|
32315
|
+
const meta = await metaRes.json().catch(() => null);
|
|
32316
|
+
const mimeType = typeof meta?.mimeType === "string" && meta.mimeType.trim() ? meta.mimeType.trim() : a.mimeType;
|
|
32317
|
+
const blobRes = await fetch(blobUrl, { headers: { Authorization: `Bearer ${token}` } });
|
|
32318
|
+
if (!blobRes.ok) {
|
|
32319
|
+
const t = await blobRes.text().catch(() => "");
|
|
32320
|
+
log2(`[Agent] Attachment blob fetch failed ${blobRes.status}: ${t.slice(0, 200)}`);
|
|
32321
|
+
return { ok: false, error: `Could not load attachment data (${id.slice(0, 8)}\u2026): ${blobRes.status}` };
|
|
32322
|
+
}
|
|
32323
|
+
const buf = Buffer.from(await blobRes.arrayBuffer());
|
|
32324
|
+
let imageBytes;
|
|
32325
|
+
const encrypted = metaSaysEncrypted(meta);
|
|
32326
|
+
if (encrypted) {
|
|
32327
|
+
if (!e2ee) {
|
|
32328
|
+
return { ok: false, error: "Encrypted attachments require E2EE keys on this bridge." };
|
|
32329
|
+
}
|
|
32330
|
+
const k = typeof meta?.k === "string" ? meta.k : "";
|
|
32331
|
+
const n = typeof meta?.n === "string" ? meta.n : "";
|
|
32332
|
+
if (!k || !n) {
|
|
32333
|
+
return { ok: false, error: "Invalid encrypted attachment metadata (missing key id or nonce)." };
|
|
32334
|
+
}
|
|
32335
|
+
const c = base64UrlEncode(buf);
|
|
32336
|
+
imageBytes = e2ee.decryptEnvelopeToBuffer({ k, n, c });
|
|
32337
|
+
} else {
|
|
32338
|
+
imageBytes = buf;
|
|
32339
|
+
}
|
|
32340
|
+
warnIfDecodedImageMagicUnexpected(imageBytes, mimeType, id.slice(0, 8));
|
|
32341
|
+
logDebug(
|
|
32342
|
+
`[Agent] Loaded prompt image ${id.slice(0, 8)}\u2026: ${imageBytes.length} bytes, mime=${mimeType}, ${encrypted ? "E2EE decrypted" : "plaintext from storage"}`
|
|
32343
|
+
);
|
|
32344
|
+
const dataBase64 = imageBytes.toString("base64");
|
|
32345
|
+
out.push({ mimeType, dataBase64 });
|
|
32346
|
+
}
|
|
32347
|
+
if (out.length !== wantedCount) {
|
|
32348
|
+
return {
|
|
32349
|
+
ok: false,
|
|
32350
|
+
error: `Expected ${wantedCount} image attachment(s) but only loaded ${out.length} (check attachment ids and empty rows).`
|
|
32351
|
+
};
|
|
32352
|
+
}
|
|
32353
|
+
return { ok: true, images: out };
|
|
32354
|
+
}
|
|
32355
|
+
|
|
32182
32356
|
// src/agents/acp/send-prompt-to-agent.ts
|
|
32183
32357
|
async function sendPromptToAgent(options) {
|
|
32184
32358
|
const {
|
|
@@ -32196,10 +32370,49 @@ async function sendPromptToAgent(options) {
|
|
|
32196
32370
|
sessionChangeSummaryFilePaths,
|
|
32197
32371
|
cloudApiBaseUrl,
|
|
32198
32372
|
getCloudAccessToken,
|
|
32199
|
-
e2ee
|
|
32373
|
+
e2ee,
|
|
32374
|
+
attachments
|
|
32200
32375
|
} = options;
|
|
32201
32376
|
try {
|
|
32202
|
-
|
|
32377
|
+
let sendOpts = {};
|
|
32378
|
+
if (attachments && attachments.length > 0) {
|
|
32379
|
+
if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
|
|
32380
|
+
sendResult2({
|
|
32381
|
+
type: "prompt_result",
|
|
32382
|
+
id: promptId,
|
|
32383
|
+
...sessionId ? { sessionId } : {},
|
|
32384
|
+
...runId ? { runId } : {},
|
|
32385
|
+
success: false,
|
|
32386
|
+
error: "Prompt includes images but the bridge is not configured with a cloud API URL and token to fetch them.",
|
|
32387
|
+
...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
|
|
32388
|
+
...augmentPromptResultAuthFields(agentType, "missing cloud for images download")
|
|
32389
|
+
});
|
|
32390
|
+
return;
|
|
32391
|
+
}
|
|
32392
|
+
const resolved = await fetchSessionAttachmentPayloadsForAgent({
|
|
32393
|
+
attachments,
|
|
32394
|
+
sessionId,
|
|
32395
|
+
cloudApiBaseUrl,
|
|
32396
|
+
getCloudAccessToken,
|
|
32397
|
+
e2ee,
|
|
32398
|
+
log: log2
|
|
32399
|
+
});
|
|
32400
|
+
if (!resolved.ok) {
|
|
32401
|
+
sendResult2({
|
|
32402
|
+
type: "prompt_result",
|
|
32403
|
+
id: promptId,
|
|
32404
|
+
...sessionId ? { sessionId } : {},
|
|
32405
|
+
...runId ? { runId } : {},
|
|
32406
|
+
success: false,
|
|
32407
|
+
error: resolved.error,
|
|
32408
|
+
...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
|
|
32409
|
+
...augmentPromptResultAuthFields(agentType, resolved.error)
|
|
32410
|
+
});
|
|
32411
|
+
return;
|
|
32412
|
+
}
|
|
32413
|
+
sendOpts = { images: resolved.images };
|
|
32414
|
+
}
|
|
32415
|
+
const result = await handle.sendPrompt(promptText, sendOpts);
|
|
32203
32416
|
if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
|
|
32204
32417
|
await collectTurnGitDiffFromPreTurnSnapshot({
|
|
32205
32418
|
sessionId,
|
|
@@ -32641,13 +32854,16 @@ function parseAcpInitAgentCapabilities(initResult) {
|
|
|
32641
32854
|
const canLoad = agentCapabilities?.loadSession === true;
|
|
32642
32855
|
const sessionCaps = agentCapabilities?.sessionCapabilities;
|
|
32643
32856
|
const canResume = Boolean(sessionCaps?.resume);
|
|
32644
|
-
|
|
32857
|
+
const promptCaps = agentCapabilities?.promptCapabilities;
|
|
32858
|
+
const promptSupportsImage = promptCaps?.image === true;
|
|
32859
|
+
return { canResume, canLoad, promptSupportsImage };
|
|
32645
32860
|
}
|
|
32646
32861
|
|
|
32647
32862
|
// src/agents/acp/clients/shared/bootstrap-acp-wire-session.ts
|
|
32648
32863
|
async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
|
|
32649
32864
|
const initResult = await transport.initialize(initializeRequest);
|
|
32650
|
-
const { canResume, canLoad } = parseAcpInitAgentCapabilities(initResult);
|
|
32865
|
+
const { canResume, canLoad, promptSupportsImage } = parseAcpInitAgentCapabilities(initResult);
|
|
32866
|
+
ctx.agentPromptImageSupported = promptSupportsImage;
|
|
32651
32867
|
await transport.afterInitialize?.();
|
|
32652
32868
|
const established = await establishAcpSessionWithTransport(transport, ctx, canResume, canLoad);
|
|
32653
32869
|
const sessionId = established.sessionId;
|
|
@@ -32738,11 +32954,27 @@ function normalizeAcpPromptTurnFailure(err, stderrCaptureText) {
|
|
|
32738
32954
|
}
|
|
32739
32955
|
|
|
32740
32956
|
// src/agents/acp/clients/shared/send-acp-prompt-via-transport.ts
|
|
32741
|
-
async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText) {
|
|
32957
|
+
async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText, images) {
|
|
32958
|
+
if (images && images.length > 0 && !ctx.agentPromptImageSupported) {
|
|
32959
|
+
await new Promise((r) => setImmediate(r));
|
|
32960
|
+
return normalizeAcpPromptTurnFailure(
|
|
32961
|
+
new Error(
|
|
32962
|
+
"This agent does not advertise image support in ACP (missing agentCapabilities.promptCapabilities.image). Remove images or use an agent that supports prompt images."
|
|
32963
|
+
),
|
|
32964
|
+
ctx.getStderrText()
|
|
32965
|
+
);
|
|
32966
|
+
}
|
|
32967
|
+
const textBlock = promptText.trim() !== "" ? promptText : images?.length ? " " : "";
|
|
32968
|
+
const prompt = [{ type: "text", text: textBlock }];
|
|
32969
|
+
if (images && images.length > 0) {
|
|
32970
|
+
for (const im of images) {
|
|
32971
|
+
prompt.push({ type: "image", mimeType: im.mimeType, data: im.data });
|
|
32972
|
+
}
|
|
32973
|
+
}
|
|
32742
32974
|
try {
|
|
32743
32975
|
const response = await transport.prompt({
|
|
32744
32976
|
sessionId,
|
|
32745
|
-
prompt
|
|
32977
|
+
prompt
|
|
32746
32978
|
});
|
|
32747
32979
|
await new Promise((r2) => setImmediate(r2));
|
|
32748
32980
|
const r = response;
|
|
@@ -32758,6 +32990,22 @@ async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText)
|
|
|
32758
32990
|
}
|
|
32759
32991
|
}
|
|
32760
32992
|
|
|
32993
|
+
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
32994
|
+
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
32995
|
+
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
32996
|
+
return new Promise((resolve18) => {
|
|
32997
|
+
pending.set(requestId, { resolve: resolve18, params: paramsRecord });
|
|
32998
|
+
try {
|
|
32999
|
+
onRequest?.({
|
|
33000
|
+
requestId,
|
|
33001
|
+
method: "session/request_permission",
|
|
33002
|
+
params: paramsRecord
|
|
33003
|
+
});
|
|
33004
|
+
} catch {
|
|
33005
|
+
}
|
|
33006
|
+
});
|
|
33007
|
+
}
|
|
33008
|
+
|
|
32761
33009
|
// src/agents/acp/clients/sdk/sdk-acp-session-transport.ts
|
|
32762
33010
|
function createSdkAcpSessionTransport(connection) {
|
|
32763
33011
|
const c = connection;
|
|
@@ -32868,16 +33116,11 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32868
33116
|
async requestPermission(params) {
|
|
32869
33117
|
const requestId = `perm-${++permissionSeq}`;
|
|
32870
33118
|
const paramsRecord = params != null && typeof params === "object" ? params : {};
|
|
32871
|
-
|
|
32872
|
-
|
|
32873
|
-
|
|
32874
|
-
|
|
32875
|
-
|
|
32876
|
-
});
|
|
32877
|
-
} catch {
|
|
32878
|
-
}
|
|
32879
|
-
return await new Promise((resolve19) => {
|
|
32880
|
-
pendingPermissionReplies.set(requestId, { resolve: resolve19, params: paramsRecord });
|
|
33119
|
+
return await awaitSdkStdioPermissionRequestHandshake({
|
|
33120
|
+
requestId,
|
|
33121
|
+
paramsRecord,
|
|
33122
|
+
pending: pendingPermissionReplies,
|
|
33123
|
+
onRequest
|
|
32881
33124
|
});
|
|
32882
33125
|
},
|
|
32883
33126
|
async readTextFile(params) {
|
|
@@ -32907,15 +33150,17 @@ async function createSdkStdioAcpClient(options) {
|
|
|
32907
33150
|
const established = await bootstrapAcpWireSession(transport, sessionCtx, {
|
|
32908
33151
|
protocolVersion: PROTOCOL_VERSION2,
|
|
32909
33152
|
clientCapabilities: {
|
|
32910
|
-
fs: { readTextFile: true, writeTextFile: true }
|
|
33153
|
+
fs: { readTextFile: true, writeTextFile: true },
|
|
33154
|
+
prompt: { image: true }
|
|
32911
33155
|
},
|
|
32912
33156
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
32913
33157
|
});
|
|
32914
33158
|
const sessionId = established.sessionId;
|
|
32915
33159
|
settleResolve({
|
|
32916
33160
|
sessionId,
|
|
32917
|
-
async sendPrompt(prompt,
|
|
32918
|
-
|
|
33161
|
+
async sendPrompt(prompt, options2) {
|
|
33162
|
+
const imgs = options2?.images?.map((im) => ({ type: "image", mimeType: im.mimeType, data: im.dataBase64 }));
|
|
33163
|
+
return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt, imgs);
|
|
32919
33164
|
},
|
|
32920
33165
|
async cancel() {
|
|
32921
33166
|
for (const [id, entry] of [...pendingPermissionReplies.entries()]) {
|
|
@@ -33283,14 +33528,19 @@ async function createCursorAcpClient(options) {
|
|
|
33283
33528
|
});
|
|
33284
33529
|
const established = await bootstrapAcpWireSession(transport, sessionCtx, {
|
|
33285
33530
|
protocolVersion: 1,
|
|
33286
|
-
clientCapabilities: {
|
|
33531
|
+
clientCapabilities: {
|
|
33532
|
+
fs: { readTextFile: true, writeTextFile: true },
|
|
33533
|
+
terminal: false,
|
|
33534
|
+
prompt: { image: true }
|
|
33535
|
+
},
|
|
33287
33536
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
33288
33537
|
});
|
|
33289
33538
|
const sessionId = established.sessionId;
|
|
33290
33539
|
resolve18({
|
|
33291
33540
|
sessionId,
|
|
33292
|
-
async sendPrompt(prompt,
|
|
33293
|
-
|
|
33541
|
+
async sendPrompt(prompt, options2) {
|
|
33542
|
+
const imgs = options2?.images?.map((im) => ({ type: "image", mimeType: im.mimeType, data: im.dataBase64 }));
|
|
33543
|
+
return sendAcpPromptViaTransport(transport, sessionCtx, sessionId, prompt, imgs);
|
|
33294
33544
|
},
|
|
33295
33545
|
async cancel() {
|
|
33296
33546
|
cancelPendingPermissionRequests2();
|
|
@@ -33578,7 +33828,7 @@ function createBridgeOnFileChange(opts) {
|
|
|
33578
33828
|
|
|
33579
33829
|
// src/agents/acp/hooks/bridge-on-request.ts
|
|
33580
33830
|
function createBridgeOnRequest(opts) {
|
|
33581
|
-
const { routing, getSendRequest, log: log2 } = opts;
|
|
33831
|
+
const { routing, getSendRequest, log: log2, getAutoApproveAcpPermissions, resolveAcpPermissionRequest } = opts;
|
|
33582
33832
|
return (request) => {
|
|
33583
33833
|
const runId = routing.runId;
|
|
33584
33834
|
const sessionId = routing.sessionId;
|
|
@@ -33586,6 +33836,26 @@ function createBridgeOnRequest(opts) {
|
|
|
33586
33836
|
if (!runId || !sendReq) return;
|
|
33587
33837
|
const kind = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
|
|
33588
33838
|
const sessionUpdate = request.method === "cursor/create_plan" ? "plan" : request.method === "session/request_permission" ? "permission" : "question";
|
|
33839
|
+
if (request.method === "session/request_permission" && getAutoApproveAcpPermissions() && resolveAcpPermissionRequest) {
|
|
33840
|
+
const params = request.params != null && typeof request.params === "object" && !Array.isArray(request.params) ? request.params : {};
|
|
33841
|
+
const auto = buildCliAutoApprovedPermissionRpcResult(params);
|
|
33842
|
+
if (auto != null) {
|
|
33843
|
+
try {
|
|
33844
|
+
resolveAcpPermissionRequest(request.requestId, auto);
|
|
33845
|
+
log2(
|
|
33846
|
+
`[Bridge service] CLI dangerous mode: auto-approved permission requestId=${request.requestId} runId=${runId}`
|
|
33847
|
+
);
|
|
33848
|
+
return;
|
|
33849
|
+
} catch (err) {
|
|
33850
|
+
log2(
|
|
33851
|
+
`[Bridge service] CLI dangerous mode: auto-approve failed (${errorMessage(err)}); forwarding permission`
|
|
33852
|
+
);
|
|
33853
|
+
}
|
|
33854
|
+
}
|
|
33855
|
+
log2(
|
|
33856
|
+
`[Bridge service] CLI dangerous mode: no allow option to auto-select; forwarding permission requestId=${request.requestId}`
|
|
33857
|
+
);
|
|
33858
|
+
}
|
|
33589
33859
|
try {
|
|
33590
33860
|
sendReq({
|
|
33591
33861
|
type: "session_update",
|
|
@@ -34136,6 +34406,7 @@ async function ensureAcpClient(options) {
|
|
|
34136
34406
|
sendRequest,
|
|
34137
34407
|
log: log2
|
|
34138
34408
|
} = options;
|
|
34409
|
+
state.latestAgentConfigForBridgeHooks = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
|
|
34139
34410
|
const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
|
|
34140
34411
|
if (state.acpStartPromise && !state.acpHandle) {
|
|
34141
34412
|
await state.acpStartPromise;
|
|
@@ -34193,7 +34464,11 @@ async function ensureAcpClient(options) {
|
|
|
34193
34464
|
sessionParentPath: targetSessionParentPath,
|
|
34194
34465
|
getSendSessionUpdate: () => sendSessionUpdate,
|
|
34195
34466
|
getSendRequest: () => sendRequest,
|
|
34196
|
-
log: log2
|
|
34467
|
+
log: log2,
|
|
34468
|
+
getAutoApproveAcpPermissions: () => getCliPermissionModeFromAgentConfig(state.latestAgentConfigForBridgeHooks) === CLI_PERMISSION_MODE_DANGEROUS,
|
|
34469
|
+
resolveAcpPermissionRequest: (requestId, result) => {
|
|
34470
|
+
state.acpHandle?.resolveRequest?.(requestId, result);
|
|
34471
|
+
}
|
|
34197
34472
|
});
|
|
34198
34473
|
const persisted = cloudSessionId != null && cloudSessionId !== "" && preferredAgentType != null && preferredAgentType !== "" ? readLocalAgentSessionFile(cloudSessionId) : null;
|
|
34199
34474
|
const persistedAcpSessionId = persisted && persisted.backendAgentType === preferredAgentType && typeof persisted.acpSessionId === "string" && persisted.acpSessionId.trim() !== "" ? persisted.acpSessionId.trim() : null;
|
|
@@ -34229,6 +34504,7 @@ async function ensureAcpClient(options) {
|
|
|
34229
34504
|
state.acpStartPromise = null;
|
|
34230
34505
|
state.acpAgentKey = null;
|
|
34231
34506
|
state.activeSessionConfigOptions = null;
|
|
34507
|
+
state.latestAgentConfigForBridgeHooks = null;
|
|
34232
34508
|
state.lastAcpStartError = "Agent subprocess exited";
|
|
34233
34509
|
},
|
|
34234
34510
|
...hooks,
|
|
@@ -34259,7 +34535,8 @@ async function createAcpManager(options) {
|
|
|
34259
34535
|
lastAcpStartError: null,
|
|
34260
34536
|
lastAcpCwd: null,
|
|
34261
34537
|
acpAgentKey: null,
|
|
34262
|
-
activeSessionConfigOptions: null
|
|
34538
|
+
activeSessionConfigOptions: null,
|
|
34539
|
+
latestAgentConfigForBridgeHooks: null
|
|
34263
34540
|
};
|
|
34264
34541
|
let backendFallbackAgentType = null;
|
|
34265
34542
|
const promptRouting = {};
|
|
@@ -34294,7 +34571,8 @@ async function createAcpManager(options) {
|
|
|
34294
34571
|
sessionChangeSummaryFilePaths,
|
|
34295
34572
|
cloudApiBaseUrl,
|
|
34296
34573
|
getCloudAccessToken,
|
|
34297
|
-
e2ee
|
|
34574
|
+
e2ee,
|
|
34575
|
+
attachments
|
|
34298
34576
|
} = opts;
|
|
34299
34577
|
const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
|
|
34300
34578
|
pendingCancelRunId = void 0;
|
|
@@ -34365,7 +34643,8 @@ async function createAcpManager(options) {
|
|
|
34365
34643
|
sessionChangeSummaryFilePaths,
|
|
34366
34644
|
cloudApiBaseUrl,
|
|
34367
34645
|
getCloudAccessToken,
|
|
34368
|
-
e2ee
|
|
34646
|
+
e2ee,
|
|
34647
|
+
attachments
|
|
34369
34648
|
});
|
|
34370
34649
|
}
|
|
34371
34650
|
void run().finally(() => {
|
|
@@ -34401,6 +34680,7 @@ async function createAcpManager(options) {
|
|
|
34401
34680
|
state.acpStartPromise = null;
|
|
34402
34681
|
state.acpAgentKey = null;
|
|
34403
34682
|
state.activeSessionConfigOptions = null;
|
|
34683
|
+
state.latestAgentConfigForBridgeHooks = null;
|
|
34404
34684
|
}
|
|
34405
34685
|
return {
|
|
34406
34686
|
setPreferredAgentType,
|
|
@@ -37736,7 +38016,8 @@ function dispatchLocalPrompt(next, deps) {
|
|
|
37736
38016
|
...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
|
|
37737
38017
|
...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
|
|
37738
38018
|
...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {},
|
|
37739
|
-
...pl.agentConfig != null && typeof pl.agentConfig === "object" && !Array.isArray(pl.agentConfig) && Object.keys(pl.agentConfig).length > 0 ? { agentConfig: pl.agentConfig } : {}
|
|
38019
|
+
...pl.agentConfig != null && typeof pl.agentConfig === "object" && !Array.isArray(pl.agentConfig) && Object.keys(pl.agentConfig).length > 0 ? { agentConfig: pl.agentConfig } : {},
|
|
38020
|
+
...Array.isArray(pl.attachments) && pl.attachments.length > 0 ? { attachments: pl.attachments } : {}
|
|
37740
38021
|
};
|
|
37741
38022
|
handleBridgePrompt(msg, deps);
|
|
37742
38023
|
}
|
|
@@ -38003,15 +38284,30 @@ function resolveChangeSummaryPromptForAgent(params) {
|
|
|
38003
38284
|
}
|
|
38004
38285
|
|
|
38005
38286
|
// src/agents/acp/from-bridge/handle-bridge-prompt.ts
|
|
38287
|
+
function parseBridgeAttachments(msg) {
|
|
38288
|
+
const raw = msg.attachments;
|
|
38289
|
+
if (!Array.isArray(raw)) return [];
|
|
38290
|
+
const out = [];
|
|
38291
|
+
for (const x of raw) {
|
|
38292
|
+
if (x === null || typeof x !== "object" || Array.isArray(x)) continue;
|
|
38293
|
+
const o = x;
|
|
38294
|
+
const id = typeof o.attachmentId === "string" ? o.attachmentId.trim() : "";
|
|
38295
|
+
if (!id) continue;
|
|
38296
|
+
const mt = typeof o.mimeType === "string" && o.mimeType.trim() ? o.mimeType.trim() : "application/octet-stream";
|
|
38297
|
+
out.push({ attachmentId: id, mimeType: mt });
|
|
38298
|
+
}
|
|
38299
|
+
return out;
|
|
38300
|
+
}
|
|
38006
38301
|
function handleBridgePrompt(msg, deps) {
|
|
38007
38302
|
const { getWs, log: log2, acpManager, sessionWorktreeManager } = deps;
|
|
38008
38303
|
const rawPrompt = msg.prompt;
|
|
38009
38304
|
const promptText = typeof rawPrompt === "string" ? rawPrompt : rawPrompt != null ? String(rawPrompt) : "";
|
|
38305
|
+
const attachments = parseBridgeAttachments(msg);
|
|
38010
38306
|
const sessionId = msg.sessionId;
|
|
38011
38307
|
const runId = typeof msg.runId === "string" ? msg.runId : void 0;
|
|
38012
38308
|
const promptId = typeof msg.id === "string" ? msg.id : void 0;
|
|
38013
38309
|
const { sendBridgeMessage, sendResult: sendResult2, sendSessionUpdate } = createBridgePromptSenders(deps, getWs);
|
|
38014
|
-
if (!promptText.trim()) {
|
|
38310
|
+
if (!promptText.trim() && attachments.length === 0) {
|
|
38015
38311
|
log2(
|
|
38016
38312
|
`[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).`
|
|
38017
38313
|
);
|
|
@@ -38078,7 +38374,8 @@ function handleBridgePrompt(msg, deps) {
|
|
|
38078
38374
|
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
38079
38375
|
cloudApiBaseUrl: deps.cloudApiBaseUrl,
|
|
38080
38376
|
getCloudAccessToken: deps.getCloudAccessToken,
|
|
38081
|
-
e2ee: deps.e2ee
|
|
38377
|
+
e2ee: deps.e2ee,
|
|
38378
|
+
...attachments.length > 0 ? { attachments } : {}
|
|
38082
38379
|
});
|
|
38083
38380
|
}
|
|
38084
38381
|
void sessionWorktreeManager.resolveSessionParentPathForPrompt(sessionId, { isNewSession, sessionParent, sessionParentPath }).then((cwd) => preambleAndPrompt(cwd)).catch((err) => {
|