@buildautomaton/cli 0.1.61 → 0.1.63
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 +497 -656
- package/dist/cli.js.map +4 -4
- package/dist/index.js +467 -626
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22625,18 +22625,6 @@ var import_websocket = __toESM(require_websocket(), 1);
|
|
|
22625
22625
|
var import_websocket_server = __toESM(require_websocket_server(), 1);
|
|
22626
22626
|
var wrapper_default = import_websocket.default;
|
|
22627
22627
|
|
|
22628
|
-
// src/net/apply-cli-outbound-network-prefs.ts
|
|
22629
|
-
import dns from "node:dns";
|
|
22630
|
-
var applied = false;
|
|
22631
|
-
function applyCliOutboundNetworkPreferences() {
|
|
22632
|
-
if (applied) return;
|
|
22633
|
-
applied = true;
|
|
22634
|
-
try {
|
|
22635
|
-
dns.setDefaultResultOrder("ipv4first");
|
|
22636
|
-
} catch {
|
|
22637
|
-
}
|
|
22638
|
-
}
|
|
22639
|
-
|
|
22640
22628
|
// src/connection/cli-ws-client.ts
|
|
22641
22629
|
import https from "node:https";
|
|
22642
22630
|
var CLI_WEBSOCKET_CLIENT_PING_MS = 25e3;
|
|
@@ -22738,7 +22726,6 @@ function createWsBridge(options) {
|
|
|
22738
22726
|
onCompactHeartbeatAck,
|
|
22739
22727
|
isActiveSocket
|
|
22740
22728
|
} = options;
|
|
22741
|
-
applyCliOutboundNetworkPreferences();
|
|
22742
22729
|
const ws = new wrapper_default(url2, buildCliWebSocketClientOptions(url2));
|
|
22743
22730
|
let clearClientPing = null;
|
|
22744
22731
|
function disposeClientPing() {
|
|
@@ -23527,7 +23514,6 @@ var StoryCheckpointSummarySchema = CheckpointSummarySchema.extend({
|
|
|
23527
23514
|
|
|
23528
23515
|
// ../types/src/sessions.ts
|
|
23529
23516
|
init_zod();
|
|
23530
|
-
var BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID = "__builtin_change_summary__";
|
|
23531
23517
|
var SessionMetaSchema = external_exports.object({
|
|
23532
23518
|
sessionId: external_exports.string(),
|
|
23533
23519
|
workspaceId: external_exports.string(),
|
|
@@ -23660,146 +23646,6 @@ function buildPlanningSessionFollowUpAgentPrompt(userPrompt, existingTodos) {
|
|
|
23660
23646
|
].join("\n");
|
|
23661
23647
|
}
|
|
23662
23648
|
|
|
23663
|
-
// ../types/src/change-summary-path.ts
|
|
23664
|
-
function normalizeRepoRelativePath(p) {
|
|
23665
|
-
let t = p.trim().replace(/\\/g, "/");
|
|
23666
|
-
while (t.startsWith("./")) t = t.slice(2);
|
|
23667
|
-
return t.replace(/\/+/g, "/");
|
|
23668
|
-
}
|
|
23669
|
-
function resolveChangeSummaryPathAgainstAllowed(rawPath, allowed) {
|
|
23670
|
-
const trimmed2 = rawPath.trim();
|
|
23671
|
-
if (!trimmed2) return null;
|
|
23672
|
-
if (allowed.has(trimmed2)) return trimmed2;
|
|
23673
|
-
const n = normalizeRepoRelativePath(trimmed2);
|
|
23674
|
-
if (allowed.has(n)) return n;
|
|
23675
|
-
for (const a of allowed) {
|
|
23676
|
-
if (normalizeRepoRelativePath(a) === n) return a;
|
|
23677
|
-
}
|
|
23678
|
-
return null;
|
|
23679
|
-
}
|
|
23680
|
-
|
|
23681
|
-
// ../types/src/parse-change-summary-json.ts
|
|
23682
|
-
function clampSummaryToAtMostTwoLines(summary) {
|
|
23683
|
-
const lines = summary.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
|
|
23684
|
-
return lines.slice(0, 2).join("\n");
|
|
23685
|
-
}
|
|
23686
|
-
function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
23687
|
-
if (raw == null || raw.trim() === "") return [];
|
|
23688
|
-
let text = raw.trim();
|
|
23689
|
-
const fence = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
23690
|
-
if (fence?.[1]) text = fence[1].trim();
|
|
23691
|
-
let parsed;
|
|
23692
|
-
try {
|
|
23693
|
-
parsed = JSON.parse(text);
|
|
23694
|
-
} catch {
|
|
23695
|
-
const start = text.indexOf("[");
|
|
23696
|
-
const end = text.lastIndexOf("]");
|
|
23697
|
-
if (start < 0 || end <= start) return [];
|
|
23698
|
-
try {
|
|
23699
|
-
parsed = JSON.parse(text.slice(start, end + 1));
|
|
23700
|
-
} catch {
|
|
23701
|
-
return [];
|
|
23702
|
-
}
|
|
23703
|
-
}
|
|
23704
|
-
const rows = [];
|
|
23705
|
-
let arr = [];
|
|
23706
|
-
if (Array.isArray(parsed)) {
|
|
23707
|
-
arr = parsed;
|
|
23708
|
-
} else if (parsed && typeof parsed === "object" && Array.isArray(parsed.files)) {
|
|
23709
|
-
arr = parsed.files;
|
|
23710
|
-
}
|
|
23711
|
-
const skip = options?.skipPathAllowlist === true;
|
|
23712
|
-
for (const item of arr) {
|
|
23713
|
-
if (!item || typeof item !== "object") continue;
|
|
23714
|
-
const o = item;
|
|
23715
|
-
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
23716
|
-
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
23717
|
-
if (!rawPath || !summary) continue;
|
|
23718
|
-
const path79 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
23719
|
-
if (!path79) continue;
|
|
23720
|
-
rows.push({ path: path79, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
23721
|
-
}
|
|
23722
|
-
return rows;
|
|
23723
|
-
}
|
|
23724
|
-
|
|
23725
|
-
// ../types/src/build-change-summary-prompt.ts
|
|
23726
|
-
var PATCH_PREVIEW_MAX = 12e3;
|
|
23727
|
-
function clip(s, max) {
|
|
23728
|
-
if (s.length <= max) return s;
|
|
23729
|
-
return `${s.slice(0, max)}
|
|
23730
|
-
|
|
23731
|
-
\u2026(truncated, ${s.length - max} more characters)`;
|
|
23732
|
-
}
|
|
23733
|
-
function buildSessionChangeSummaryPrompt(files) {
|
|
23734
|
-
const lines = [
|
|
23735
|
-
"You are the same agent that produced the changes below. Summarize **your own** edits so a reader can scan them quickly.",
|
|
23736
|
-
"",
|
|
23737
|
-
"Write in second person (you / your): what you changed in each path and why it matters.",
|
|
23738
|
-
"",
|
|
23739
|
-
"Each summary must be **very concise**: **one line** of plain text, or **at most two short lines** (use a single line break between the two if needed). No bullets, no paragraphs.",
|
|
23740
|
-
"",
|
|
23741
|
-
"## How to format your reply (machine parsing)",
|
|
23742
|
-
"",
|
|
23743
|
-
"- Put the machine-readable part **only** inside a **markdown fenced code block** whose opening fence is exactly ```json on its own line. Close the block with ``` on its own line after the JSON.",
|
|
23744
|
-
"- Inside that fence: **nothing except** one valid JSON value \u2014 the array described below. No trailing commentary inside the fence.",
|
|
23745
|
-
"- **Do not** attach prose to the JSON on the same line (wrong: `Only one file\u2026page.tsx.[{\u2026}]`). Wrong: any sentence that ends with `.` immediately before `[`. Put a blank line before the ```json line.",
|
|
23746
|
-
"- If you add optional plain English before the fence (e.g. one short sentence), keep it **separate**: end that sentence, blank line, then ```json.",
|
|
23747
|
-
'- In each `"summary"` string, avoid raw double-quote characters, or escape them as `\\"` so the JSON parses.',
|
|
23748
|
-
"",
|
|
23749
|
-
"JSON shape **inside the fence** (array only):",
|
|
23750
|
-
'[{"path":"<file path exactly as given>","summary":"<one line, or two short lines separated by \\n>"}]',
|
|
23751
|
-
"",
|
|
23752
|
-
"Rules:",
|
|
23753
|
-
"- Include **exactly one** object per file path listed below (same path strings).",
|
|
23754
|
-
"- If a path is a removed directory, state briefly what you removed.",
|
|
23755
|
-
"- Do not invent paths; use only the paths provided.",
|
|
23756
|
-
"",
|
|
23757
|
-
"## Files you changed",
|
|
23758
|
-
""
|
|
23759
|
-
];
|
|
23760
|
-
for (const f of files) {
|
|
23761
|
-
lines.push(`### ${f.path}`);
|
|
23762
|
-
if (f.directoryRemoved) {
|
|
23763
|
-
lines.push("(directory removed)");
|
|
23764
|
-
lines.push("");
|
|
23765
|
-
continue;
|
|
23766
|
-
}
|
|
23767
|
-
if (f.patchContent && f.patchContent.trim() !== "") {
|
|
23768
|
-
lines.push("```diff");
|
|
23769
|
-
lines.push(clip(f.patchContent.trim(), PATCH_PREVIEW_MAX));
|
|
23770
|
-
lines.push("```");
|
|
23771
|
-
} else if (f.oldText != null || f.newText != null) {
|
|
23772
|
-
const oldT = (f.oldText ?? "").trim();
|
|
23773
|
-
const newT = (f.newText ?? "").trim();
|
|
23774
|
-
lines.push("Previous snippet:", clip(oldT, 6e3));
|
|
23775
|
-
lines.push("New snippet:", clip(newT, 6e3));
|
|
23776
|
-
} else {
|
|
23777
|
-
lines.push("(no diff body stored for this path)");
|
|
23778
|
-
}
|
|
23779
|
-
lines.push("");
|
|
23780
|
-
}
|
|
23781
|
-
return lines.join("\n");
|
|
23782
|
-
}
|
|
23783
|
-
|
|
23784
|
-
// ../types/src/dedupe-session-file-changes-by-path.ts
|
|
23785
|
-
function defaultRichness(c) {
|
|
23786
|
-
const patch = typeof c.patchContent === "string" ? c.patchContent.length : 0;
|
|
23787
|
-
const nt = typeof c.newText === "string" ? c.newText.length : 0;
|
|
23788
|
-
const ot = typeof c.oldText === "string" ? c.oldText.length : 0;
|
|
23789
|
-
const dir = c.directoryRemoved === true ? 8 : 0;
|
|
23790
|
-
return (patch > 0 ? 4 : 0) + (nt > 0 ? 2 : 0) + (ot > 0 ? 1 : 0) + dir;
|
|
23791
|
-
}
|
|
23792
|
-
function dedupeSessionFileChangesByPath(items, richness = (item) => defaultRichness(item)) {
|
|
23793
|
-
const byPath = /* @__PURE__ */ new Map();
|
|
23794
|
-
for (const item of items) {
|
|
23795
|
-
const p = typeof item.path === "string" ? item.path.trim() : "";
|
|
23796
|
-
if (!p) continue;
|
|
23797
|
-
const prev = byPath.get(p);
|
|
23798
|
-
if (!prev || richness(item) >= richness(prev)) byPath.set(p, item);
|
|
23799
|
-
}
|
|
23800
|
-
return Array.from(byPath.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v);
|
|
23801
|
-
}
|
|
23802
|
-
|
|
23803
23649
|
// ../types/src/diff/line-diff.ts
|
|
23804
23650
|
function normalizeDiffLineText(line) {
|
|
23805
23651
|
return line.replace(/\r$/, "").replace(/\s*\\s*$/, "");
|
|
@@ -24855,6 +24701,71 @@ async function createSdkStdioAcpClient(options) {
|
|
|
24855
24701
|
});
|
|
24856
24702
|
}
|
|
24857
24703
|
|
|
24704
|
+
// src/firehose/proxy/constants.ts
|
|
24705
|
+
var LOCAL_PROXY_REQUEST_TIMEOUT_MS = 3e4;
|
|
24706
|
+
|
|
24707
|
+
// src/firehose/proxy/prepare-local-proxy-request-headers.ts
|
|
24708
|
+
var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
|
|
24709
|
+
"connection",
|
|
24710
|
+
"keep-alive",
|
|
24711
|
+
"proxy-authenticate",
|
|
24712
|
+
"proxy-authorization",
|
|
24713
|
+
"te",
|
|
24714
|
+
"trailers",
|
|
24715
|
+
"transfer-encoding",
|
|
24716
|
+
"upgrade"
|
|
24717
|
+
]);
|
|
24718
|
+
var BODY_HEADERS = /* @__PURE__ */ new Set(["content-length", "content-type", "content-encoding"]);
|
|
24719
|
+
function methodAllowsRequestBody(method) {
|
|
24720
|
+
const normalized = method.toUpperCase();
|
|
24721
|
+
return normalized !== "GET" && normalized !== "HEAD";
|
|
24722
|
+
}
|
|
24723
|
+
function prepareLocalProxyRequestHeaders(method, headers, sendingBody) {
|
|
24724
|
+
const out = {};
|
|
24725
|
+
for (const [key, value] of Object.entries(headers ?? {})) {
|
|
24726
|
+
const lower = key.toLowerCase();
|
|
24727
|
+
if (lower === "host") continue;
|
|
24728
|
+
if (HOP_BY_HOP_HEADERS.has(lower)) continue;
|
|
24729
|
+
if (lower === "origin" || lower === "referer") continue;
|
|
24730
|
+
if (!sendingBody && BODY_HEADERS.has(lower)) continue;
|
|
24731
|
+
out[key] = value;
|
|
24732
|
+
}
|
|
24733
|
+
return out;
|
|
24734
|
+
}
|
|
24735
|
+
|
|
24736
|
+
// src/firehose/proxy/build-local-proxy-http-request.ts
|
|
24737
|
+
var ALLOWED_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
|
|
24738
|
+
function willSendLocalProxyBody(request) {
|
|
24739
|
+
if (!methodAllowsRequestBody(request.method)) return false;
|
|
24740
|
+
return request.body !== void 0 && request.body !== null;
|
|
24741
|
+
}
|
|
24742
|
+
function buildLocalProxyHttpRequest(request) {
|
|
24743
|
+
let url2;
|
|
24744
|
+
try {
|
|
24745
|
+
url2 = new URL(request.url);
|
|
24746
|
+
} catch {
|
|
24747
|
+
return { error: `Invalid URL: ${request.url}` };
|
|
24748
|
+
}
|
|
24749
|
+
const hostname2 = url2.hostname.replace(/^\[|\]$/g, "");
|
|
24750
|
+
if (!ALLOWED_HOSTS.has(url2.hostname) && !ALLOWED_HOSTS.has(hostname2)) {
|
|
24751
|
+
return { error: "Only localhost requests are allowed" };
|
|
24752
|
+
}
|
|
24753
|
+
const sendingBody = willSendLocalProxyBody(request);
|
|
24754
|
+
const headers = prepareLocalProxyRequestHeaders(request.method, request.headers, sendingBody);
|
|
24755
|
+
headers.host = url2.host;
|
|
24756
|
+
const isHttps = url2.protocol === "https:";
|
|
24757
|
+
const port = url2.port ? Number(url2.port) : isHttps ? 443 : 80;
|
|
24758
|
+
return {
|
|
24759
|
+
method: request.method,
|
|
24760
|
+
hostname: url2.hostname,
|
|
24761
|
+
port,
|
|
24762
|
+
path: `${url2.pathname}${url2.search}`,
|
|
24763
|
+
headers,
|
|
24764
|
+
sendingBody,
|
|
24765
|
+
body: sendingBody ? request.body : void 0
|
|
24766
|
+
};
|
|
24767
|
+
}
|
|
24768
|
+
|
|
24858
24769
|
// src/net/transient-local-fetch-retry.ts
|
|
24859
24770
|
var LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS = [30, 100, 200, 400];
|
|
24860
24771
|
function sleepMs(ms) {
|
|
@@ -24879,148 +24790,151 @@ function isTransientLocalServiceError(err) {
|
|
|
24879
24790
|
if (!text) return false;
|
|
24880
24791
|
return text.includes("fetch failed") || text.includes("econnrefused") || text.includes("econnreset") || text.includes("epipe") || text.includes("etimedout") || text.includes("socket hang up") || text.includes("network connection lost") || text.includes("ecanceled") || text.includes("aborted") || text.includes("und_err_socket") || text.includes("other side closed") || text.includes("eai_again");
|
|
24881
24792
|
}
|
|
24882
|
-
|
|
24883
|
-
|
|
24884
|
-
|
|
24885
|
-
}
|
|
24886
|
-
|
|
24887
|
-
|
|
24888
|
-
|
|
24889
|
-
const delays = options?.delaysMs ?? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS;
|
|
24890
|
-
const maxAttempts = options?.maxAttempts ?? (allowRetry ? Math.max(1, delays.length + 1) : 1);
|
|
24891
|
-
let lastErr;
|
|
24892
|
-
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
24893
|
-
try {
|
|
24894
|
-
return await fetch(url2, init);
|
|
24895
|
-
} catch (e) {
|
|
24896
|
-
lastErr = e;
|
|
24897
|
-
const canRetry = allowRetry && attempt < maxAttempts - 1 && isTransientLocalServiceError(e);
|
|
24898
|
-
if (!canRetry) throw e;
|
|
24899
|
-
const waitMs = delays[Math.min(attempt, delays.length - 1)] ?? 100;
|
|
24900
|
-
await sleepMs(waitMs);
|
|
24901
|
-
}
|
|
24793
|
+
|
|
24794
|
+
// src/firehose/proxy/incoming-message-headers.ts
|
|
24795
|
+
function incomingMessageHeaders(res) {
|
|
24796
|
+
const headers = {};
|
|
24797
|
+
for (const [k, v] of Object.entries(res.headers)) {
|
|
24798
|
+
if (typeof v === "string") headers[k] = v;
|
|
24799
|
+
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
24902
24800
|
}
|
|
24903
|
-
|
|
24801
|
+
return headers;
|
|
24904
24802
|
}
|
|
24905
24803
|
|
|
24906
|
-
// src/firehose/proxy/local-
|
|
24907
|
-
|
|
24908
|
-
|
|
24909
|
-
const h = host.replace(/^\[|\]$/g, "");
|
|
24910
|
-
return ALLOWED_HOSTS.includes(host) || ALLOWED_HOSTS.includes(h);
|
|
24911
|
-
}
|
|
24912
|
-
function isIdempotentProxyMethod(method) {
|
|
24913
|
-
const m = method.toUpperCase();
|
|
24914
|
-
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
24915
|
-
}
|
|
24916
|
-
function checkUrlAndHost(request) {
|
|
24917
|
-
let url2;
|
|
24918
|
-
try {
|
|
24919
|
-
url2 = new URL(request.url);
|
|
24920
|
-
} catch {
|
|
24921
|
-
return { error: `Invalid URL: ${request.url}` };
|
|
24922
|
-
}
|
|
24923
|
-
if (!isAllowedHost(url2.hostname)) {
|
|
24924
|
-
return { error: "Only localhost requests are allowed" };
|
|
24925
|
-
}
|
|
24926
|
-
return { url: url2 };
|
|
24804
|
+
// src/firehose/proxy/run-local-http-request.ts
|
|
24805
|
+
async function loadHttpModule(isHttps) {
|
|
24806
|
+
return isHttps ? import("https") : import("http");
|
|
24927
24807
|
}
|
|
24928
|
-
|
|
24929
|
-
|
|
24930
|
-
|
|
24931
|
-
|
|
24932
|
-
|
|
24933
|
-
|
|
24934
|
-
|
|
24935
|
-
const mod = isHttps ? await import("https") : await import("http");
|
|
24936
|
-
const opts = {
|
|
24937
|
-
method: request.method,
|
|
24938
|
-
hostname: url2.hostname,
|
|
24939
|
-
port: url2.port || (isHttps ? 443 : 80),
|
|
24940
|
-
path: url2.pathname + url2.search,
|
|
24941
|
-
headers: request.headers
|
|
24808
|
+
function buildLocalHttpRequestOptions(built) {
|
|
24809
|
+
return {
|
|
24810
|
+
method: built.method,
|
|
24811
|
+
hostname: built.hostname,
|
|
24812
|
+
port: built.port,
|
|
24813
|
+
path: built.path,
|
|
24814
|
+
headers: built.headers
|
|
24942
24815
|
};
|
|
24943
|
-
|
|
24944
|
-
|
|
24945
|
-
|
|
24946
|
-
|
|
24947
|
-
|
|
24948
|
-
|
|
24949
|
-
|
|
24950
|
-
|
|
24951
|
-
|
|
24952
|
-
|
|
24953
|
-
|
|
24954
|
-
|
|
24955
|
-
}
|
|
24956
|
-
resolve35({
|
|
24957
|
-
id: request.id,
|
|
24958
|
-
statusCode: res.statusCode ?? 0,
|
|
24959
|
-
headers,
|
|
24960
|
-
body
|
|
24961
|
-
});
|
|
24816
|
+
}
|
|
24817
|
+
function runLocalHttpRequestOnce(mod, built) {
|
|
24818
|
+
const opts = buildLocalHttpRequestOptions(built);
|
|
24819
|
+
return new Promise((resolve35) => {
|
|
24820
|
+
const req = mod.request(opts, (res) => {
|
|
24821
|
+
const chunks = [];
|
|
24822
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
24823
|
+
res.on("end", () => {
|
|
24824
|
+
resolve35({
|
|
24825
|
+
statusCode: res.statusCode ?? 0,
|
|
24826
|
+
headers: incomingMessageHeaders(res),
|
|
24827
|
+
body: Buffer.concat(chunks)
|
|
24962
24828
|
});
|
|
24963
24829
|
});
|
|
24964
|
-
|
|
24830
|
+
res.on("error", (err) => {
|
|
24965
24831
|
resolve35({
|
|
24966
|
-
id: request.id,
|
|
24967
24832
|
statusCode: 0,
|
|
24968
24833
|
headers: {},
|
|
24969
|
-
body:
|
|
24834
|
+
body: Buffer.alloc(0),
|
|
24970
24835
|
error: err.message
|
|
24971
24836
|
});
|
|
24972
24837
|
});
|
|
24973
|
-
const method = request.method.toUpperCase();
|
|
24974
|
-
if (request.body && method !== "GET" && method !== "HEAD") req.write(request.body);
|
|
24975
|
-
req.end();
|
|
24976
24838
|
});
|
|
24839
|
+
req.setTimeout(LOCAL_PROXY_REQUEST_TIMEOUT_MS, () => {
|
|
24840
|
+
req.destroy(new Error(`Local preview request timed out after ${LOCAL_PROXY_REQUEST_TIMEOUT_MS}ms`));
|
|
24841
|
+
});
|
|
24842
|
+
req.on("error", (err) => {
|
|
24843
|
+
resolve35({
|
|
24844
|
+
statusCode: 0,
|
|
24845
|
+
headers: {},
|
|
24846
|
+
body: Buffer.alloc(0),
|
|
24847
|
+
error: err.message
|
|
24848
|
+
});
|
|
24849
|
+
});
|
|
24850
|
+
if (built.sendingBody && built.body != null) {
|
|
24851
|
+
req.write(built.body);
|
|
24852
|
+
}
|
|
24853
|
+
req.end();
|
|
24854
|
+
});
|
|
24855
|
+
}
|
|
24856
|
+
|
|
24857
|
+
// src/firehose/proxy/proxy-to-local.ts
|
|
24858
|
+
function isIdempotentProxyMethod(method) {
|
|
24859
|
+
const m = method.toUpperCase();
|
|
24860
|
+
return m === "GET" || m === "HEAD" || m === "OPTIONS";
|
|
24861
|
+
}
|
|
24862
|
+
async function proxyToLocal(request) {
|
|
24863
|
+
const built = buildLocalProxyHttpRequest(request);
|
|
24864
|
+
if ("error" in built) {
|
|
24865
|
+
return { id: request.id, statusCode: 0, headers: {}, body: "", error: built.error };
|
|
24866
|
+
}
|
|
24867
|
+
const isHttps = request.url.startsWith("https:");
|
|
24868
|
+
const mod = await loadHttpModule(isHttps);
|
|
24869
|
+
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
24870
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
24871
|
+
const once = await runLocalHttpRequestOnce(mod, built);
|
|
24977
24872
|
const errMsg = once.error ?? "";
|
|
24978
24873
|
const canRetry = attempt < maxAttempts - 1 && errMsg !== "" && isTransientLocalServiceError(new Error(errMsg));
|
|
24979
|
-
if (!canRetry)
|
|
24874
|
+
if (!canRetry) {
|
|
24875
|
+
return {
|
|
24876
|
+
id: request.id,
|
|
24877
|
+
statusCode: once.statusCode,
|
|
24878
|
+
headers: once.headers,
|
|
24879
|
+
body: once.body.toString("utf8"),
|
|
24880
|
+
error: once.error
|
|
24881
|
+
};
|
|
24882
|
+
}
|
|
24980
24883
|
const waitMs = LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS[Math.min(attempt, LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length - 1)] ?? 100;
|
|
24981
24884
|
await sleepMs(waitMs);
|
|
24982
24885
|
}
|
|
24983
24886
|
throw new Error("Local proxy retry loop exited unexpectedly");
|
|
24984
24887
|
}
|
|
24888
|
+
|
|
24889
|
+
// src/firehose/proxy/proxy-to-local-streaming.ts
|
|
24985
24890
|
async function proxyToLocalStreaming(request, callbacks) {
|
|
24986
|
-
const
|
|
24987
|
-
if ("error" in
|
|
24988
|
-
callbacks.onError(
|
|
24891
|
+
const built = buildLocalProxyHttpRequest(request);
|
|
24892
|
+
if ("error" in built) {
|
|
24893
|
+
callbacks.onError(built.error);
|
|
24989
24894
|
return;
|
|
24990
24895
|
}
|
|
24991
|
-
|
|
24992
|
-
|
|
24993
|
-
|
|
24994
|
-
|
|
24995
|
-
|
|
24996
|
-
|
|
24997
|
-
|
|
24998
|
-
|
|
24999
|
-
|
|
25000
|
-
|
|
25001
|
-
|
|
25002
|
-
|
|
25003
|
-
headers[key] = value;
|
|
25004
|
-
});
|
|
25005
|
-
callbacks.onStart(res.status, headers);
|
|
25006
|
-
const reader = res.body?.getReader();
|
|
25007
|
-
if (!reader) {
|
|
25008
|
-
callbacks.onEnd();
|
|
25009
|
-
return;
|
|
25010
|
-
}
|
|
25011
|
-
try {
|
|
25012
|
-
for (; ; ) {
|
|
25013
|
-
const { done, value } = await reader.read();
|
|
25014
|
-
if (done) break;
|
|
25015
|
-
callbacks.onChunk(value);
|
|
24896
|
+
const isHttps = request.url.startsWith("https:");
|
|
24897
|
+
const mod = await loadHttpModule(isHttps);
|
|
24898
|
+
const opts = buildLocalHttpRequestOptions(built);
|
|
24899
|
+
await new Promise((resolve35) => {
|
|
24900
|
+
const req = mod.request(opts, (res) => {
|
|
24901
|
+
try {
|
|
24902
|
+
callbacks.onStart(res.statusCode ?? 0, incomingMessageHeaders(res));
|
|
24903
|
+
} catch (err) {
|
|
24904
|
+
req.destroy();
|
|
24905
|
+
callbacks.onError(err instanceof Error ? err.message : String(err));
|
|
24906
|
+
resolve35();
|
|
24907
|
+
return;
|
|
25016
24908
|
}
|
|
25017
|
-
|
|
25018
|
-
|
|
24909
|
+
res.on("data", (chunk) => {
|
|
24910
|
+
try {
|
|
24911
|
+
callbacks.onChunk(new Uint8Array(chunk));
|
|
24912
|
+
} catch (err) {
|
|
24913
|
+
req.destroy();
|
|
24914
|
+
callbacks.onError(err instanceof Error ? err.message : String(err));
|
|
24915
|
+
}
|
|
24916
|
+
});
|
|
24917
|
+
res.on("end", () => {
|
|
24918
|
+
callbacks.onEnd();
|
|
24919
|
+
resolve35();
|
|
24920
|
+
});
|
|
24921
|
+
res.on("error", (err) => {
|
|
24922
|
+
callbacks.onError(err.message);
|
|
24923
|
+
resolve35();
|
|
24924
|
+
});
|
|
24925
|
+
});
|
|
24926
|
+
req.setTimeout(LOCAL_PROXY_REQUEST_TIMEOUT_MS, () => {
|
|
24927
|
+
req.destroy(new Error(`Local preview request timed out after ${LOCAL_PROXY_REQUEST_TIMEOUT_MS}ms`));
|
|
24928
|
+
});
|
|
24929
|
+
req.on("error", (err) => {
|
|
24930
|
+
callbacks.onError(err.message);
|
|
24931
|
+
resolve35();
|
|
24932
|
+
});
|
|
24933
|
+
if (built.sendingBody && built.body != null) {
|
|
24934
|
+
req.write(built.body);
|
|
25019
24935
|
}
|
|
25020
|
-
|
|
25021
|
-
}
|
|
25022
|
-
callbacks.onError(err instanceof Error ? err.message : String(err));
|
|
25023
|
-
}
|
|
24936
|
+
req.end();
|
|
24937
|
+
});
|
|
25024
24938
|
}
|
|
25025
24939
|
|
|
25026
24940
|
// src/skills/preview.ts
|
|
@@ -25272,7 +25186,7 @@ function installBridgeProcessResilience() {
|
|
|
25272
25186
|
}
|
|
25273
25187
|
|
|
25274
25188
|
// src/cli-version.ts
|
|
25275
|
-
var CLI_VERSION = "0.1.
|
|
25189
|
+
var CLI_VERSION = "0.1.63".length > 0 ? "0.1.63" : "0.0.0-dev";
|
|
25276
25190
|
|
|
25277
25191
|
// src/connection/heartbeat/constants.ts
|
|
25278
25192
|
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -26654,38 +26568,38 @@ function readCodeNavCacheMigrationSql(filename) {
|
|
|
26654
26568
|
}
|
|
26655
26569
|
|
|
26656
26570
|
// src/sqlite/run-sqlite-migrations.ts
|
|
26657
|
-
function checkpointSatisfiedByLegacyChain(
|
|
26658
|
-
return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) =>
|
|
26571
|
+
function checkpointSatisfiedByLegacyChain(applied, replacesLegacyMigrations) {
|
|
26572
|
+
return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) => applied.has(n));
|
|
26659
26573
|
}
|
|
26660
|
-
function recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
26574
|
+
function recordMigrationAndPruneCheckpointLegacy(db, migration, applied) {
|
|
26661
26575
|
db.run("INSERT INTO __migrations (name) VALUES (?)", [migration.name]);
|
|
26662
|
-
|
|
26576
|
+
applied.add(migration.name);
|
|
26663
26577
|
if (migration.checkpoint !== true) return;
|
|
26664
26578
|
const legacy = migration.replacesLegacyMigrations;
|
|
26665
26579
|
if (!legacy?.length) return;
|
|
26666
26580
|
for (const legacyName of legacy) {
|
|
26667
26581
|
if (legacyName === migration.name) continue;
|
|
26668
26582
|
db.run("DELETE FROM __migrations WHERE name = ?", [legacyName]);
|
|
26669
|
-
|
|
26583
|
+
applied.delete(legacyName);
|
|
26670
26584
|
}
|
|
26671
26585
|
}
|
|
26672
26586
|
function runSqliteMigrations(db, migrations, bootstrapSql, label) {
|
|
26673
26587
|
db.exec(bootstrapSql);
|
|
26674
26588
|
const appliedRows = db.all("SELECT name FROM __migrations");
|
|
26675
|
-
const
|
|
26589
|
+
const applied = new Set(appliedRows.map((r) => r.name));
|
|
26676
26590
|
for (const migration of migrations) {
|
|
26677
|
-
if (
|
|
26678
|
-
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(
|
|
26679
|
-
recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
26591
|
+
if (applied.has(migration.name)) continue;
|
|
26592
|
+
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(applied, migration.replacesLegacyMigrations)) {
|
|
26593
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied);
|
|
26680
26594
|
continue;
|
|
26681
26595
|
}
|
|
26682
26596
|
if (migration.alreadyApplied?.(db)) {
|
|
26683
|
-
recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
26597
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied);
|
|
26684
26598
|
continue;
|
|
26685
26599
|
}
|
|
26686
26600
|
try {
|
|
26687
26601
|
migration.migrate(db);
|
|
26688
|
-
recordMigrationAndPruneCheckpointLegacy(db, migration,
|
|
26602
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied);
|
|
26689
26603
|
} catch (e) {
|
|
26690
26604
|
console.error(`[${label}] Migration failed: ${migration.name}`, e);
|
|
26691
26605
|
throw e;
|
|
@@ -32797,102 +32711,6 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32797
32711
|
});
|
|
32798
32712
|
}
|
|
32799
32713
|
|
|
32800
|
-
// src/agents/acp/put-summarize-change-summaries.ts
|
|
32801
|
-
async function putEncryptedChangeSummaryRows(params) {
|
|
32802
|
-
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
32803
|
-
const entries = params.rows.map(({ path: path79, summary }) => {
|
|
32804
|
-
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
32805
|
-
return { path: path79, summary: JSON.stringify(enc) };
|
|
32806
|
-
});
|
|
32807
|
-
const res = await fetch(
|
|
32808
|
-
`${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
32809
|
-
{
|
|
32810
|
-
method: "PUT",
|
|
32811
|
-
headers: {
|
|
32812
|
-
Authorization: `Bearer ${params.authToken}`,
|
|
32813
|
-
"Content-Type": "application/json"
|
|
32814
|
-
},
|
|
32815
|
-
body: JSON.stringify({ entries })
|
|
32816
|
-
}
|
|
32817
|
-
);
|
|
32818
|
-
if (!res.ok) {
|
|
32819
|
-
const t = await res.text();
|
|
32820
|
-
throw new Error(`PUT summarize-changes summaries failed ${res.status}: ${t.slice(0, 500)}`);
|
|
32821
|
-
}
|
|
32822
|
-
}
|
|
32823
|
-
|
|
32824
|
-
// src/agents/acp/maybe-upload-e2ee-session-change-summaries.ts
|
|
32825
|
-
async function maybeUploadE2eeSessionChangeSummariesAfterAgentSuccess(params) {
|
|
32826
|
-
const {
|
|
32827
|
-
sessionId,
|
|
32828
|
-
runId,
|
|
32829
|
-
resultSuccess,
|
|
32830
|
-
output,
|
|
32831
|
-
e2ee,
|
|
32832
|
-
cloudApiBaseUrl,
|
|
32833
|
-
getCloudAccessToken,
|
|
32834
|
-
followUpCatalogPromptId,
|
|
32835
|
-
sessionChangeSummaryFilePaths,
|
|
32836
|
-
log: log2
|
|
32837
|
-
} = params;
|
|
32838
|
-
const outputStr = typeof output === "string" ? output : "";
|
|
32839
|
-
if (!sessionId) {
|
|
32840
|
-
return;
|
|
32841
|
-
}
|
|
32842
|
-
if (!runId) {
|
|
32843
|
-
return;
|
|
32844
|
-
}
|
|
32845
|
-
if (!resultSuccess) {
|
|
32846
|
-
return;
|
|
32847
|
-
}
|
|
32848
|
-
if (!e2ee) {
|
|
32849
|
-
return;
|
|
32850
|
-
}
|
|
32851
|
-
if (!cloudApiBaseUrl) {
|
|
32852
|
-
return;
|
|
32853
|
-
}
|
|
32854
|
-
if (!getCloudAccessToken) {
|
|
32855
|
-
return;
|
|
32856
|
-
}
|
|
32857
|
-
if (followUpCatalogPromptId !== BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID) {
|
|
32858
|
-
return;
|
|
32859
|
-
}
|
|
32860
|
-
if (!sessionChangeSummaryFilePaths || sessionChangeSummaryFilePaths.length === 0) {
|
|
32861
|
-
return;
|
|
32862
|
-
}
|
|
32863
|
-
if (outputStr.trim() === "") {
|
|
32864
|
-
return;
|
|
32865
|
-
}
|
|
32866
|
-
const allowed = /* @__PURE__ */ new Set();
|
|
32867
|
-
for (const p of sessionChangeSummaryFilePaths) {
|
|
32868
|
-
const t = p.trim();
|
|
32869
|
-
if (!t) continue;
|
|
32870
|
-
allowed.add(t);
|
|
32871
|
-
allowed.add(normalizeRepoRelativePath(t));
|
|
32872
|
-
}
|
|
32873
|
-
const rows = parseChangeSummaryJson(outputStr, allowed);
|
|
32874
|
-
if (rows.length === 0) {
|
|
32875
|
-
return;
|
|
32876
|
-
}
|
|
32877
|
-
const token = getCloudAccessToken();
|
|
32878
|
-
if (!token) {
|
|
32879
|
-
return;
|
|
32880
|
-
}
|
|
32881
|
-
try {
|
|
32882
|
-
await putEncryptedChangeSummaryRows({
|
|
32883
|
-
apiBaseUrl: cloudApiBaseUrl,
|
|
32884
|
-
authToken: token,
|
|
32885
|
-
sessionId,
|
|
32886
|
-
e2ee,
|
|
32887
|
-
rows
|
|
32888
|
-
});
|
|
32889
|
-
} catch (uploadErr) {
|
|
32890
|
-
log2(
|
|
32891
|
-
`[Agent] Encrypted change summary upload failed: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`
|
|
32892
|
-
);
|
|
32893
|
-
}
|
|
32894
|
-
}
|
|
32895
|
-
|
|
32896
32714
|
// src/agents/planning/submit-planning-todos-for-turn.ts
|
|
32897
32715
|
async function submitPlanningTodosForTurn(params) {
|
|
32898
32716
|
const token = params.getCloudAccessToken();
|
|
@@ -32961,10 +32779,8 @@ async function finalizeAndSendPromptResult(params) {
|
|
|
32961
32779
|
agentCwd,
|
|
32962
32780
|
isPlanningSession,
|
|
32963
32781
|
followUpCatalogPromptId,
|
|
32964
|
-
sessionChangeSummaryFilePaths,
|
|
32965
32782
|
cloudApiBaseUrl,
|
|
32966
32783
|
getCloudAccessToken,
|
|
32967
|
-
e2ee,
|
|
32968
32784
|
sendResult,
|
|
32969
32785
|
sendSessionUpdate,
|
|
32970
32786
|
log: log2
|
|
@@ -32978,18 +32794,6 @@ async function finalizeAndSendPromptResult(params) {
|
|
|
32978
32794
|
log: log2
|
|
32979
32795
|
});
|
|
32980
32796
|
}
|
|
32981
|
-
await maybeUploadE2eeSessionChangeSummariesAfterAgentSuccess({
|
|
32982
|
-
sessionId,
|
|
32983
|
-
runId,
|
|
32984
|
-
resultSuccess: result.success === true,
|
|
32985
|
-
output: result.output,
|
|
32986
|
-
e2ee,
|
|
32987
|
-
cloudApiBaseUrl,
|
|
32988
|
-
getCloudAccessToken,
|
|
32989
|
-
followUpCatalogPromptId,
|
|
32990
|
-
sessionChangeSummaryFilePaths,
|
|
32991
|
-
log: log2
|
|
32992
|
-
});
|
|
32993
32797
|
const planningTodosSubmit = await maybeSubmitPlanningTodosAfterAgentSuccess({
|
|
32994
32798
|
sessionId,
|
|
32995
32799
|
runId,
|
|
@@ -33525,7 +33329,6 @@ async function sendPromptToAgent(options) {
|
|
|
33525
33329
|
sendSessionUpdate,
|
|
33526
33330
|
log: log2,
|
|
33527
33331
|
followUpCatalogPromptId,
|
|
33528
|
-
sessionChangeSummaryFilePaths,
|
|
33529
33332
|
cloudApiBaseUrl,
|
|
33530
33333
|
getCloudAccessToken,
|
|
33531
33334
|
e2ee,
|
|
@@ -33569,7 +33372,6 @@ async function sendPromptToAgent(options) {
|
|
|
33569
33372
|
agentCwd,
|
|
33570
33373
|
isPlanningSession,
|
|
33571
33374
|
followUpCatalogPromptId,
|
|
33572
|
-
sessionChangeSummaryFilePaths,
|
|
33573
33375
|
cloudApiBaseUrl,
|
|
33574
33376
|
getCloudAccessToken,
|
|
33575
33377
|
e2ee,
|
|
@@ -33640,7 +33442,6 @@ async function runAcpPrompt(ctx, runCtx, opts) {
|
|
|
33640
33442
|
sendResult,
|
|
33641
33443
|
sendSessionUpdate,
|
|
33642
33444
|
followUpCatalogPromptId,
|
|
33643
|
-
sessionChangeSummaryFilePaths,
|
|
33644
33445
|
cloudApiBaseUrl,
|
|
33645
33446
|
getCloudAccessToken,
|
|
33646
33447
|
e2ee,
|
|
@@ -33706,7 +33507,6 @@ async function runAcpPrompt(ctx, runCtx, opts) {
|
|
|
33706
33507
|
sendSessionUpdate,
|
|
33707
33508
|
log: ctx.log,
|
|
33708
33509
|
followUpCatalogPromptId,
|
|
33709
|
-
sessionChangeSummaryFilePaths,
|
|
33710
33510
|
cloudApiBaseUrl,
|
|
33711
33511
|
getCloudAccessToken,
|
|
33712
33512
|
e2ee,
|
|
@@ -34832,6 +34632,9 @@ function envForSpawn(base, userEnv, ports) {
|
|
|
34832
34632
|
});
|
|
34833
34633
|
if (ports.length > 0) {
|
|
34834
34634
|
out.PORTS = ports.join(",");
|
|
34635
|
+
if (!userKeys.has("PORT")) {
|
|
34636
|
+
out.PORT = String(ports[0]);
|
|
34637
|
+
}
|
|
34835
34638
|
}
|
|
34836
34639
|
if (!userKeys.has("NO_COLOR")) {
|
|
34837
34640
|
delete out.NO_COLOR;
|
|
@@ -35734,6 +35537,12 @@ function createBridgePreviewStack(options) {
|
|
|
35734
35537
|
return { previewEnvironmentManager, scheduleInitialIndexBuildsOnce, identifyReportedPaths };
|
|
35735
35538
|
}
|
|
35736
35539
|
|
|
35540
|
+
// src/firehose/build-cli-ws-url.ts
|
|
35541
|
+
function buildFirehoseCliWsUrl(baseUrl) {
|
|
35542
|
+
const base = baseUrl.startsWith("https") ? baseUrl.replace(/^https/, "wss") : baseUrl.replace(/^http/, "ws");
|
|
35543
|
+
return `${base.replace(/\/$/, "")}/ws`;
|
|
35544
|
+
}
|
|
35545
|
+
|
|
35737
35546
|
// src/firehose/proxy/start-streaming-proxy.ts
|
|
35738
35547
|
function startStreamingProxy(ws, log2, pr) {
|
|
35739
35548
|
proxyToLocalStreaming(pr, {
|
|
@@ -35741,15 +35550,7 @@ function startStreamingProxy(ws, log2, pr) {
|
|
|
35741
35550
|
if (ws.readyState !== wrapper_default.OPEN) {
|
|
35742
35551
|
throw new Error("Preview stream interrupted (firehose connection closed)");
|
|
35743
35552
|
}
|
|
35744
|
-
|
|
35745
|
-
const ce = "content-encoding";
|
|
35746
|
-
const cl = "content-length";
|
|
35747
|
-
const keys = Object.keys(forwardedHeaders).filter(
|
|
35748
|
-
(k) => k.toLowerCase() !== ce && k.toLowerCase() !== cl
|
|
35749
|
-
);
|
|
35750
|
-
const filtered = {};
|
|
35751
|
-
for (const k of keys) if (forwardedHeaders[k] != null) filtered[k] = forwardedHeaders[k];
|
|
35752
|
-
sendWsMessage(ws, { type: "proxy_result_start", id: pr.id, statusCode, headers: filtered });
|
|
35553
|
+
sendWsMessage(ws, { type: "proxy_result_start", id: pr.id, statusCode, headers });
|
|
35753
35554
|
},
|
|
35754
35555
|
onChunk: (chunk) => {
|
|
35755
35556
|
const idBuf = Buffer.from(pr.id, "utf8");
|
|
@@ -35766,10 +35567,19 @@ function startStreamingProxy(ws, log2, pr) {
|
|
|
35766
35567
|
});
|
|
35767
35568
|
}
|
|
35768
35569
|
|
|
35769
|
-
// src/firehose/
|
|
35770
|
-
function
|
|
35771
|
-
const
|
|
35772
|
-
|
|
35570
|
+
// src/firehose/create-firehose-message-deps.ts
|
|
35571
|
+
function createFirehoseMessageDeps(ws, log2, previewEnvironmentManager) {
|
|
35572
|
+
const pendingProxyBody = /* @__PURE__ */ new Map();
|
|
35573
|
+
const earlyProxyBinaryBody = /* @__PURE__ */ new Map();
|
|
35574
|
+
const deps = {
|
|
35575
|
+
ws,
|
|
35576
|
+
log: log2,
|
|
35577
|
+
previewEnvironmentManager,
|
|
35578
|
+
pendingProxyBody,
|
|
35579
|
+
earlyProxyBinaryBody,
|
|
35580
|
+
startStreamingProxy: (pr) => startStreamingProxy(ws, log2, pr)
|
|
35581
|
+
};
|
|
35582
|
+
return deps;
|
|
35773
35583
|
}
|
|
35774
35584
|
|
|
35775
35585
|
// src/firehose/routing/firehose-message-router.ts
|
|
@@ -35810,25 +35620,27 @@ var handleProxyMessage = (msg, deps) => {
|
|
|
35810
35620
|
if (!proxy || typeof proxy !== "object") return;
|
|
35811
35621
|
const pr = proxy;
|
|
35812
35622
|
if (pr.streamResponse) {
|
|
35813
|
-
const bodyLength = pr.bodyLength ?? 0;
|
|
35623
|
+
const bodyLength = methodAllowsRequestBody(pr.method) ? pr.bodyLength ?? 0 : 0;
|
|
35624
|
+
const streamingRequest = {
|
|
35625
|
+
id: pr.id,
|
|
35626
|
+
method: pr.method,
|
|
35627
|
+
url: pr.url,
|
|
35628
|
+
headers: pr.headers,
|
|
35629
|
+
streamResponse: true
|
|
35630
|
+
};
|
|
35814
35631
|
if (bodyLength > 0) {
|
|
35815
|
-
deps.
|
|
35816
|
-
|
|
35817
|
-
|
|
35818
|
-
|
|
35819
|
-
|
|
35820
|
-
|
|
35821
|
-
|
|
35822
|
-
|
|
35823
|
-
|
|
35632
|
+
const earlyBody = deps.earlyProxyBinaryBody.get(pr.id);
|
|
35633
|
+
if (earlyBody !== void 0) {
|
|
35634
|
+
deps.earlyProxyBinaryBody.delete(pr.id);
|
|
35635
|
+
deps.startStreamingProxy({
|
|
35636
|
+
...streamingRequest,
|
|
35637
|
+
body: earlyBody.length > 0 ? earlyBody : void 0
|
|
35638
|
+
});
|
|
35639
|
+
} else {
|
|
35640
|
+
deps.pendingProxyBody.set(pr.id, { pr: streamingRequest });
|
|
35641
|
+
}
|
|
35824
35642
|
} else {
|
|
35825
|
-
deps.startStreamingProxy(
|
|
35826
|
-
id: pr.id,
|
|
35827
|
-
method: pr.method,
|
|
35828
|
-
url: pr.url,
|
|
35829
|
-
headers: pr.headers,
|
|
35830
|
-
streamResponse: true
|
|
35831
|
-
});
|
|
35643
|
+
deps.startStreamingProxy(streamingRequest);
|
|
35832
35644
|
}
|
|
35833
35645
|
return;
|
|
35834
35646
|
}
|
|
@@ -35859,37 +35671,63 @@ function dispatchFirehoseJsonMessage(msg, deps) {
|
|
|
35859
35671
|
|
|
35860
35672
|
// src/firehose/routing/try-consume-binary-proxy-body.ts
|
|
35861
35673
|
var PROXY_ID_BYTES = 36;
|
|
35674
|
+
var PROXY_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
35862
35675
|
function tryConsumeBinaryProxyBody(raw, deps) {
|
|
35863
35676
|
if (raw.length < PROXY_ID_BYTES) return false;
|
|
35864
35677
|
const id = raw.slice(0, PROXY_ID_BYTES).toString("utf8");
|
|
35865
|
-
|
|
35866
|
-
if (!pending2) return false;
|
|
35867
|
-
deps.pendingProxyBody.delete(id);
|
|
35678
|
+
if (!PROXY_ID_RE.test(id)) return false;
|
|
35868
35679
|
const body = raw.slice(PROXY_ID_BYTES);
|
|
35869
|
-
|
|
35870
|
-
|
|
35871
|
-
|
|
35872
|
-
|
|
35680
|
+
const bodyBytes = body.length > 0 ? new Uint8Array(body) : new Uint8Array(0);
|
|
35681
|
+
const pending2 = deps.pendingProxyBody.get(id);
|
|
35682
|
+
if (pending2) {
|
|
35683
|
+
deps.pendingProxyBody.delete(id);
|
|
35684
|
+
deps.startStreamingProxy({
|
|
35685
|
+
...pending2.pr,
|
|
35686
|
+
body: bodyBytes.length > 0 ? bodyBytes : void 0
|
|
35687
|
+
});
|
|
35688
|
+
return true;
|
|
35689
|
+
}
|
|
35690
|
+
deps.earlyProxyBinaryBody.set(id, bodyBytes);
|
|
35873
35691
|
return true;
|
|
35874
35692
|
}
|
|
35875
35693
|
|
|
35876
|
-
// src/firehose/
|
|
35877
|
-
function
|
|
35694
|
+
// src/firehose/handle-inbound-firehose-frame.ts
|
|
35695
|
+
function handleInboundFirehoseFrame(raw, deps) {
|
|
35696
|
+
if (Buffer.isBuffer(raw) && tryConsumeBinaryProxyBody(raw, deps)) {
|
|
35697
|
+
return;
|
|
35698
|
+
}
|
|
35699
|
+
let msg;
|
|
35700
|
+
try {
|
|
35701
|
+
const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
|
|
35702
|
+
msg = JSON.parse(text);
|
|
35703
|
+
} catch {
|
|
35704
|
+
return;
|
|
35705
|
+
}
|
|
35706
|
+
if (msg.type === "proxy") {
|
|
35707
|
+
dispatchFirehoseJsonMessage(msg, deps);
|
|
35708
|
+
return;
|
|
35709
|
+
}
|
|
35710
|
+
setImmediate(() => {
|
|
35711
|
+
dispatchFirehoseJsonMessage(msg, deps);
|
|
35712
|
+
});
|
|
35713
|
+
}
|
|
35714
|
+
|
|
35715
|
+
// src/firehose/wire-firehose-websocket.ts
|
|
35716
|
+
function wireFirehoseWebSocket(options) {
|
|
35878
35717
|
const {
|
|
35879
|
-
|
|
35718
|
+
ws,
|
|
35719
|
+
deps,
|
|
35720
|
+
log: log2,
|
|
35721
|
+
previewEnvironmentManager,
|
|
35880
35722
|
workspaceId,
|
|
35881
35723
|
bridgeName,
|
|
35882
35724
|
proxyPorts,
|
|
35883
|
-
log: log2,
|
|
35884
|
-
previewEnvironmentManager,
|
|
35885
35725
|
onOpen,
|
|
35886
35726
|
onClose,
|
|
35887
35727
|
suppressWebSocketErrors
|
|
35888
35728
|
} = options;
|
|
35889
|
-
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
35890
|
-
applyCliOutboundNetworkPreferences();
|
|
35891
|
-
const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
|
|
35892
35729
|
let clearClientPing = null;
|
|
35730
|
+
let identifyParams = { workspaceId, bridgeName, proxyPorts };
|
|
35893
35731
|
function disposeClientPing() {
|
|
35894
35732
|
clearClientPing?.();
|
|
35895
35733
|
clearClientPing = null;
|
|
@@ -35897,36 +35735,32 @@ function connectFirehose(options) {
|
|
|
35897
35735
|
const firehoseSend = (payload) => {
|
|
35898
35736
|
sendWsMessage(ws, payload);
|
|
35899
35737
|
};
|
|
35900
|
-
|
|
35901
|
-
|
|
35902
|
-
ws
|
|
35903
|
-
|
|
35904
|
-
|
|
35905
|
-
|
|
35906
|
-
|
|
35907
|
-
|
|
35738
|
+
function sendIdentify(params) {
|
|
35739
|
+
identifyParams = params;
|
|
35740
|
+
if (ws.readyState !== wrapper_default.OPEN) return;
|
|
35741
|
+
sendWsMessage(ws, {
|
|
35742
|
+
type: "identify",
|
|
35743
|
+
workspaceId: params.workspaceId,
|
|
35744
|
+
bridgeName: params.bridgeName,
|
|
35745
|
+
proxyPorts: params.proxyPorts
|
|
35746
|
+
});
|
|
35747
|
+
}
|
|
35748
|
+
function detachPreviewEnvironmentManager() {
|
|
35749
|
+
previewEnvironmentManager.detachFirehose();
|
|
35750
|
+
}
|
|
35908
35751
|
ws.on("open", () => {
|
|
35909
35752
|
disposeClientPing();
|
|
35910
35753
|
clearClientPing = attachWebSocketClientPing(ws, CLI_WEBSOCKET_CLIENT_PING_MS);
|
|
35911
35754
|
onOpen?.();
|
|
35912
35755
|
previewEnvironmentManager.attachFirehose(firehoseSend);
|
|
35913
|
-
|
|
35756
|
+
sendIdentify(identifyParams);
|
|
35914
35757
|
});
|
|
35915
35758
|
ws.on("message", (raw) => {
|
|
35916
|
-
|
|
35917
|
-
return;
|
|
35918
|
-
}
|
|
35919
|
-
setImmediate(() => {
|
|
35920
|
-
try {
|
|
35921
|
-
const text = Buffer.isBuffer(raw) ? raw.toString("utf8") : String(raw);
|
|
35922
|
-
dispatchFirehoseJsonMessage(JSON.parse(text), deps);
|
|
35923
|
-
} catch {
|
|
35924
|
-
}
|
|
35925
|
-
});
|
|
35759
|
+
handleInboundFirehoseFrame(raw, deps);
|
|
35926
35760
|
});
|
|
35927
35761
|
ws.on("close", (code, reason) => {
|
|
35928
35762
|
disposeClientPing();
|
|
35929
|
-
|
|
35763
|
+
detachPreviewEnvironmentManager();
|
|
35930
35764
|
const reasonStr = typeof reason === "string" ? reason : reason.toString();
|
|
35931
35765
|
onClose?.(code, reasonStr);
|
|
35932
35766
|
});
|
|
@@ -35939,25 +35773,64 @@ function connectFirehose(options) {
|
|
|
35939
35773
|
safeCloseWebSocket(ws);
|
|
35940
35774
|
}
|
|
35941
35775
|
});
|
|
35776
|
+
return { disposeClientPing, sendIdentify, detachPreviewEnvironmentManager };
|
|
35777
|
+
}
|
|
35778
|
+
|
|
35779
|
+
// src/firehose/connect-firehose.ts
|
|
35780
|
+
function connectFirehose(options) {
|
|
35781
|
+
const {
|
|
35782
|
+
firehoseServerUrl,
|
|
35783
|
+
workspaceId,
|
|
35784
|
+
bridgeName,
|
|
35785
|
+
proxyPorts,
|
|
35786
|
+
log: log2,
|
|
35787
|
+
previewEnvironmentManager,
|
|
35788
|
+
onOpen,
|
|
35789
|
+
onClose,
|
|
35790
|
+
suppressWebSocketErrors
|
|
35791
|
+
} = options;
|
|
35792
|
+
const wsUrl = buildFirehoseCliWsUrl(firehoseServerUrl);
|
|
35793
|
+
const ws = new wrapper_default(wsUrl, buildCliWebSocketClientOptions(wsUrl));
|
|
35794
|
+
const deps = createFirehoseMessageDeps(ws, log2, previewEnvironmentManager);
|
|
35795
|
+
const wired = wireFirehoseWebSocket({
|
|
35796
|
+
ws,
|
|
35797
|
+
deps,
|
|
35798
|
+
log: log2,
|
|
35799
|
+
previewEnvironmentManager,
|
|
35800
|
+
workspaceId,
|
|
35801
|
+
bridgeName,
|
|
35802
|
+
proxyPorts,
|
|
35803
|
+
onOpen,
|
|
35804
|
+
onClose,
|
|
35805
|
+
suppressWebSocketErrors
|
|
35806
|
+
});
|
|
35942
35807
|
return {
|
|
35943
35808
|
close() {
|
|
35944
|
-
disposeClientPing();
|
|
35945
|
-
|
|
35809
|
+
wired.disposeClientPing();
|
|
35810
|
+
wired.detachPreviewEnvironmentManager();
|
|
35946
35811
|
safeCloseWebSocket(ws);
|
|
35947
35812
|
},
|
|
35948
|
-
isConnected: () => ws.readyState === wrapper_default.OPEN
|
|
35813
|
+
isConnected: () => ws.readyState === wrapper_default.OPEN,
|
|
35814
|
+
updateIdentify: wired.sendIdentify
|
|
35949
35815
|
};
|
|
35950
35816
|
}
|
|
35951
35817
|
|
|
35952
|
-
// src/connection/
|
|
35953
|
-
function
|
|
35954
|
-
|
|
35955
|
-
|
|
35956
|
-
|
|
35957
|
-
|
|
35958
|
-
|
|
35959
|
-
|
|
35960
|
-
|
|
35818
|
+
// src/connection/firehose/compare-firehose-params.ts
|
|
35819
|
+
function proxyPortsEqual(a, b) {
|
|
35820
|
+
if (a.length !== b.length) return false;
|
|
35821
|
+
const sa = [...a].sort((x, y) => x - y);
|
|
35822
|
+
const sb = [...b].sort((x, y) => x - y);
|
|
35823
|
+
return sa.every((v, i) => v === sb[i]);
|
|
35824
|
+
}
|
|
35825
|
+
function sameFirehoseBridge(a, b) {
|
|
35826
|
+
return a.firehoseServerUrl === b.firehoseServerUrl && a.workspaceId === b.workspaceId && a.bridgeName === b.bridgeName;
|
|
35827
|
+
}
|
|
35828
|
+
function shouldReuseOpenFirehoseConnection(prev, next, isConnected) {
|
|
35829
|
+
return Boolean(prev && sameFirehoseBridge(prev, next) && isConnected());
|
|
35830
|
+
}
|
|
35831
|
+
|
|
35832
|
+
// src/connection/firehose/create-firehose-connect-callbacks.ts
|
|
35833
|
+
function createFirehoseConnectCallbacks(state, myGen, logFn, scheduleFirehoseRetryAfterDrop) {
|
|
35961
35834
|
function firehoseCtx() {
|
|
35962
35835
|
return {
|
|
35963
35836
|
closedByUser: state.closedByUser,
|
|
@@ -35966,6 +35839,55 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
35966
35839
|
firehoseQuiet: state.firehoseQuiet
|
|
35967
35840
|
};
|
|
35968
35841
|
}
|
|
35842
|
+
return {
|
|
35843
|
+
onOpen: () => {
|
|
35844
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
35845
|
+
try {
|
|
35846
|
+
clearFirehoseReconnectQuietOnOpen(
|
|
35847
|
+
{
|
|
35848
|
+
firehoseQuiet: state.firehoseQuiet,
|
|
35849
|
+
firehoseOutage: state.firehoseOutage,
|
|
35850
|
+
lastFirehoseReconnectCloseMeta: state.lastFirehoseReconnectCloseMeta
|
|
35851
|
+
},
|
|
35852
|
+
logFn
|
|
35853
|
+
);
|
|
35854
|
+
} catch {
|
|
35855
|
+
}
|
|
35856
|
+
const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
|
|
35857
|
+
state.firehoseReconnectAttempt = 0;
|
|
35858
|
+
if (!logOpenAsFirehoseReconnect) {
|
|
35859
|
+
try {
|
|
35860
|
+
logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
|
|
35861
|
+
} catch {
|
|
35862
|
+
}
|
|
35863
|
+
}
|
|
35864
|
+
},
|
|
35865
|
+
onClose: (code, reason) => {
|
|
35866
|
+
if (myGen !== state.firehoseGeneration) return;
|
|
35867
|
+
state.firehoseHandle = null;
|
|
35868
|
+
if (state.closedByUser) return;
|
|
35869
|
+
state.lastFirehoseReconnectCloseMeta = { code, reason };
|
|
35870
|
+
try {
|
|
35871
|
+
beginFirehoseDeferredDisconnect(firehoseCtx(), code, reason, logFn);
|
|
35872
|
+
} catch {
|
|
35873
|
+
}
|
|
35874
|
+
try {
|
|
35875
|
+
scheduleFirehoseRetryAfterDrop({ code, reason });
|
|
35876
|
+
} catch {
|
|
35877
|
+
}
|
|
35878
|
+
}
|
|
35879
|
+
};
|
|
35880
|
+
}
|
|
35881
|
+
|
|
35882
|
+
// src/connection/firehose/create-firehose-reconnect-scheduler.ts
|
|
35883
|
+
function createFirehoseReconnectScheduler(ctx, reconnect) {
|
|
35884
|
+
const { state, logFn } = ctx;
|
|
35885
|
+
function clearFirehoseReconnectTimer() {
|
|
35886
|
+
if (state.firehoseReconnectTimeout != null) {
|
|
35887
|
+
clearTimeout(state.firehoseReconnectTimeout);
|
|
35888
|
+
state.firehoseReconnectTimeout = null;
|
|
35889
|
+
}
|
|
35890
|
+
}
|
|
35969
35891
|
function scheduleFirehoseRetryAfterDrop(closeMeta) {
|
|
35970
35892
|
if (state.closedByUser) return;
|
|
35971
35893
|
const meta = closeMeta ?? state.lastFirehoseReconnectCloseMeta ?? void 0;
|
|
@@ -35987,30 +35909,60 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
35987
35909
|
state.firehoseReconnectTimeout = id;
|
|
35988
35910
|
},
|
|
35989
35911
|
shouldAbortBeforeRun: () => state.closedByUser,
|
|
35990
|
-
run:
|
|
35991
|
-
const p = state.lastFirehoseParams;
|
|
35992
|
-
if (!p) return;
|
|
35993
|
-
attachFirehoseAfterIdentified(ctx, p);
|
|
35994
|
-
},
|
|
35912
|
+
run: reconnect,
|
|
35995
35913
|
reschedule: () => {
|
|
35996
35914
|
scheduleFirehoseRetryAfterDrop();
|
|
35997
35915
|
}
|
|
35998
35916
|
});
|
|
35999
35917
|
}
|
|
36000
|
-
|
|
36001
|
-
|
|
36002
|
-
|
|
36003
|
-
|
|
36004
|
-
|
|
36005
|
-
|
|
36006
|
-
|
|
35918
|
+
return { clearFirehoseReconnectTimer, scheduleFirehoseRetryAfterDrop };
|
|
35919
|
+
}
|
|
35920
|
+
function logInitialFirehoseConnect(state, logFn) {
|
|
35921
|
+
if (state.firehoseReconnectAttempt !== 0) return;
|
|
35922
|
+
try {
|
|
35923
|
+
logFn("Connecting to preview tunnel (local HTTP proxy and dev logs)\u2026");
|
|
35924
|
+
} catch {
|
|
36007
35925
|
}
|
|
35926
|
+
}
|
|
35927
|
+
function replaceFirehoseHandle(state) {
|
|
36008
35928
|
state.firehoseGeneration += 1;
|
|
36009
35929
|
const myGen = state.firehoseGeneration;
|
|
36010
35930
|
if (state.firehoseHandle) {
|
|
36011
35931
|
state.firehoseHandle.close();
|
|
36012
35932
|
state.firehoseHandle = null;
|
|
36013
35933
|
}
|
|
35934
|
+
return myGen;
|
|
35935
|
+
}
|
|
35936
|
+
|
|
35937
|
+
// src/connection/firehose/attach-firehose-after-identified.ts
|
|
35938
|
+
function attachFirehoseAfterIdentified(ctx, params) {
|
|
35939
|
+
const { state, previewEnvironmentManager, logFn } = ctx;
|
|
35940
|
+
const prev = state.lastFirehoseParams;
|
|
35941
|
+
if (shouldReuseOpenFirehoseConnection(prev, params, () => state.firehoseHandle?.isConnected() ?? false)) {
|
|
35942
|
+
state.lastFirehoseParams = params;
|
|
35943
|
+
if (prev && !proxyPortsEqual(prev.proxyPorts, params.proxyPorts)) {
|
|
35944
|
+
state.firehoseHandle?.updateIdentify(params);
|
|
35945
|
+
}
|
|
35946
|
+
return;
|
|
35947
|
+
}
|
|
35948
|
+
const { clearFirehoseReconnectTimer, scheduleFirehoseRetryAfterDrop } = createFirehoseReconnectScheduler(
|
|
35949
|
+
ctx,
|
|
35950
|
+
() => {
|
|
35951
|
+
const p = state.lastFirehoseParams;
|
|
35952
|
+
if (!p) return;
|
|
35953
|
+
attachFirehoseAfterIdentified(ctx, p);
|
|
35954
|
+
}
|
|
35955
|
+
);
|
|
35956
|
+
state.lastFirehoseParams = params;
|
|
35957
|
+
clearFirehoseReconnectTimer();
|
|
35958
|
+
logInitialFirehoseConnect(state, logFn);
|
|
35959
|
+
const myGen = replaceFirehoseHandle(state);
|
|
35960
|
+
const { onOpen, onClose } = createFirehoseConnectCallbacks(
|
|
35961
|
+
state,
|
|
35962
|
+
myGen,
|
|
35963
|
+
logFn,
|
|
35964
|
+
scheduleFirehoseRetryAfterDrop
|
|
35965
|
+
);
|
|
36014
35966
|
state.firehoseHandle = connectFirehose({
|
|
36015
35967
|
firehoseServerUrl: params.firehoseServerUrl,
|
|
36016
35968
|
workspaceId: params.workspaceId,
|
|
@@ -36019,45 +35971,17 @@ function attachFirehoseAfterIdentified(ctx, params) {
|
|
|
36019
35971
|
log: logFn,
|
|
36020
35972
|
previewEnvironmentManager,
|
|
36021
35973
|
suppressWebSocketErrors: () => !state.closedByUser && state.firehoseOutage.startedAt != null,
|
|
36022
|
-
onOpen
|
|
36023
|
-
|
|
36024
|
-
try {
|
|
36025
|
-
clearFirehoseReconnectQuietOnOpen(
|
|
36026
|
-
{
|
|
36027
|
-
firehoseQuiet: state.firehoseQuiet,
|
|
36028
|
-
firehoseOutage: state.firehoseOutage,
|
|
36029
|
-
lastFirehoseReconnectCloseMeta: state.lastFirehoseReconnectCloseMeta
|
|
36030
|
-
},
|
|
36031
|
-
logFn
|
|
36032
|
-
);
|
|
36033
|
-
} catch {
|
|
36034
|
-
}
|
|
36035
|
-
const logOpenAsFirehoseReconnect = state.firehoseReconnectAttempt > 0;
|
|
36036
|
-
state.firehoseReconnectAttempt = 0;
|
|
36037
|
-
if (!logOpenAsFirehoseReconnect) {
|
|
36038
|
-
try {
|
|
36039
|
-
logFn("Connected to preview tunnel (local HTTP proxy and dev logs).");
|
|
36040
|
-
} catch {
|
|
36041
|
-
}
|
|
36042
|
-
}
|
|
36043
|
-
},
|
|
36044
|
-
onClose: (code, reason) => {
|
|
36045
|
-
if (myGen !== state.firehoseGeneration) return;
|
|
36046
|
-
state.firehoseHandle = null;
|
|
36047
|
-
if (state.closedByUser) return;
|
|
36048
|
-
state.lastFirehoseReconnectCloseMeta = { code, reason };
|
|
36049
|
-
try {
|
|
36050
|
-
beginFirehoseDeferredDisconnect(firehoseCtx(), code, reason, logFn);
|
|
36051
|
-
} catch {
|
|
36052
|
-
}
|
|
36053
|
-
try {
|
|
36054
|
-
scheduleFirehoseRetryAfterDrop({ code, reason });
|
|
36055
|
-
} catch {
|
|
36056
|
-
}
|
|
36057
|
-
}
|
|
35974
|
+
onOpen,
|
|
35975
|
+
onClose
|
|
36058
35976
|
});
|
|
36059
35977
|
}
|
|
36060
35978
|
|
|
35979
|
+
// src/connection/firehose/update-firehose-identify-on-open-connection.ts
|
|
35980
|
+
function updateFirehoseIdentifyOnOpenConnection(state, params) {
|
|
35981
|
+
state.lastFirehoseParams = params;
|
|
35982
|
+
state.firehoseHandle?.updateIdentify(params);
|
|
35983
|
+
}
|
|
35984
|
+
|
|
36061
35985
|
// src/connection/create-bridge-identified-handler.ts
|
|
36062
35986
|
function createOnBridgeIdentified(opts) {
|
|
36063
35987
|
const { previewEnvironmentManager, firehoseServerUrl, workspaceId, state, logFn } = opts;
|
|
@@ -36094,6 +36018,7 @@ function createBridgeMessageDeps(params) {
|
|
|
36094
36018
|
reportAutoDetectedAgents,
|
|
36095
36019
|
warmupAgentCapabilitiesOnConnect: warmupAgentCapabilitiesOnConnect2,
|
|
36096
36020
|
previewEnvironmentManager,
|
|
36021
|
+
updateFirehoseProxyPorts,
|
|
36097
36022
|
e2ee,
|
|
36098
36023
|
cloudApiBaseUrl,
|
|
36099
36024
|
getCloudAccessToken
|
|
@@ -36112,6 +36037,7 @@ function createBridgeMessageDeps(params) {
|
|
|
36112
36037
|
reportAutoDetectedAgents,
|
|
36113
36038
|
warmupAgentCapabilitiesOnConnect: warmupAgentCapabilitiesOnConnect2,
|
|
36114
36039
|
previewEnvironmentManager,
|
|
36040
|
+
updateFirehoseProxyPorts,
|
|
36115
36041
|
e2ee,
|
|
36116
36042
|
cloudApiBaseUrl,
|
|
36117
36043
|
getCloudAccessToken
|
|
@@ -36372,6 +36298,11 @@ function createBridgeRuntimeMessageSetup(options) {
|
|
|
36372
36298
|
getWs
|
|
36373
36299
|
}),
|
|
36374
36300
|
previewEnvironmentManager,
|
|
36301
|
+
updateFirehoseProxyPorts: (proxyPorts) => {
|
|
36302
|
+
const p = state.lastFirehoseParams;
|
|
36303
|
+
if (!p) return;
|
|
36304
|
+
updateFirehoseIdentifyOnOpenConnection(state, { ...p, proxyPorts });
|
|
36305
|
+
},
|
|
36375
36306
|
e2ee,
|
|
36376
36307
|
cloudApiBaseUrl: apiUrl,
|
|
36377
36308
|
getCloudAccessToken: () => tokens.accessToken
|
|
@@ -43641,16 +43572,16 @@ async function applySessionWipToPreviewCheckouts(options) {
|
|
|
43641
43572
|
return;
|
|
43642
43573
|
}
|
|
43643
43574
|
await gitResetWorktreeToBranch(previewCheckout, deployBranch);
|
|
43644
|
-
const
|
|
43575
|
+
const applied = await applyWorkingTreeWip(
|
|
43645
43576
|
previewCheckout,
|
|
43646
43577
|
state.sessionCheckout,
|
|
43647
43578
|
state.wip,
|
|
43648
43579
|
log2
|
|
43649
43580
|
);
|
|
43650
|
-
if (!
|
|
43581
|
+
if (!applied.ok) {
|
|
43651
43582
|
failure = {
|
|
43652
43583
|
ok: false,
|
|
43653
|
-
error:
|
|
43584
|
+
error: applied.error ?? `Failed to apply session WIP to preview (${state.repoPathRelativeToWorkspaceRoot})`
|
|
43654
43585
|
};
|
|
43655
43586
|
}
|
|
43656
43587
|
});
|
|
@@ -43749,7 +43680,7 @@ async function deploySessionToPreviewEnvironment(options) {
|
|
|
43749
43680
|
return { ok: false, error: "Failed to create preview environment worktrees" };
|
|
43750
43681
|
}
|
|
43751
43682
|
await yieldToEventLoop2();
|
|
43752
|
-
const
|
|
43683
|
+
const applied = await applySessionWipToPreviewCheckouts({
|
|
43753
43684
|
previewWorktreeManager,
|
|
43754
43685
|
environmentId: eid,
|
|
43755
43686
|
deployBranch,
|
|
@@ -43757,8 +43688,8 @@ async function deploySessionToPreviewEnvironment(options) {
|
|
|
43757
43688
|
repoStates,
|
|
43758
43689
|
log: log2
|
|
43759
43690
|
});
|
|
43760
|
-
if (!
|
|
43761
|
-
return { ok: false, error:
|
|
43691
|
+
if (!applied.ok) {
|
|
43692
|
+
return { ok: false, error: applied.error };
|
|
43762
43693
|
}
|
|
43763
43694
|
log2(
|
|
43764
43695
|
`[worktrees] Deployed session ${sid.slice(0, 8)}\u2026 to preview ${eid.slice(0, 8)}\u2026 on branch ${deployBranch}.`
|
|
@@ -44080,8 +44011,6 @@ function dispatchLocalPrompt(next, deps) {
|
|
|
44080
44011
|
...sessionParentPath ? { sessionParentPath } : {},
|
|
44081
44012
|
...worktreeBaseBranches && Object.keys(worktreeBaseBranches).length > 0 ? { worktreeBaseBranches } : {},
|
|
44082
44013
|
...typeof pl.followUpCatalogPromptId === "string" ? { followUpCatalogPromptId: pl.followUpCatalogPromptId } : {},
|
|
44083
|
-
...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
|
|
44084
|
-
...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
|
|
44085
44014
|
...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {},
|
|
44086
44015
|
...pl.agentConfig != null && typeof pl.agentConfig === "object" && !Array.isArray(pl.agentConfig) && Object.keys(pl.agentConfig).length > 0 ? { agentConfig: pl.agentConfig } : {},
|
|
44087
44016
|
...Array.isArray(pl.attachments) && pl.attachments.length > 0 ? { attachments: pl.attachments } : {}
|
|
@@ -44344,8 +44273,7 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
44344
44273
|
return true;
|
|
44345
44274
|
};
|
|
44346
44275
|
const sendResult = (result) => {
|
|
44347
|
-
const
|
|
44348
|
-
const encryptedFields = result.type === "prompt_result" && !skipEncryptForChangeSummaryFollowUp ? ["output", "error"] : [];
|
|
44276
|
+
const encryptedFields = result.type === "prompt_result" ? ["output", "error"] : [];
|
|
44349
44277
|
sendBridgeMessage(result, encryptedFields);
|
|
44350
44278
|
if (result.type === "prompt_result") {
|
|
44351
44279
|
const pr = result;
|
|
@@ -44409,61 +44337,6 @@ function parseWorktreeBaseBranches(msg) {
|
|
|
44409
44337
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
44410
44338
|
}
|
|
44411
44339
|
|
|
44412
|
-
// src/agents/acp/change-summary/decrypt-change-summary-file-input.ts
|
|
44413
|
-
function decryptChangeSummaryFileInput(row, e2ee) {
|
|
44414
|
-
if (!e2ee) return row;
|
|
44415
|
-
for (const field of ["path", "patchContent", "oldText", "newText"]) {
|
|
44416
|
-
const raw = row[field];
|
|
44417
|
-
if (typeof raw !== "string" || raw.trim() === "") continue;
|
|
44418
|
-
let o;
|
|
44419
|
-
try {
|
|
44420
|
-
o = JSON.parse(raw);
|
|
44421
|
-
} catch {
|
|
44422
|
-
continue;
|
|
44423
|
-
}
|
|
44424
|
-
if (!isE2eeEnvelope(o.ee)) continue;
|
|
44425
|
-
try {
|
|
44426
|
-
const d = e2ee.decryptMessage(o);
|
|
44427
|
-
const out = {
|
|
44428
|
-
path: typeof d.path === "string" ? d.path : row.path
|
|
44429
|
-
};
|
|
44430
|
-
if (d.directoryRemoved === true) out.directoryRemoved = true;
|
|
44431
|
-
else if (row.directoryRemoved === true) out.directoryRemoved = true;
|
|
44432
|
-
if (typeof d.patchContent === "string") out.patchContent = d.patchContent;
|
|
44433
|
-
else if (typeof row.patchContent === "string" && row.patchContent !== raw) out.patchContent = row.patchContent;
|
|
44434
|
-
if (typeof d.oldText === "string") out.oldText = d.oldText;
|
|
44435
|
-
else if (typeof row.oldText === "string") out.oldText = row.oldText;
|
|
44436
|
-
if (typeof d.newText === "string") out.newText = d.newText;
|
|
44437
|
-
else if (typeof row.newText === "string") out.newText = row.newText;
|
|
44438
|
-
return out;
|
|
44439
|
-
} catch {
|
|
44440
|
-
return row;
|
|
44441
|
-
}
|
|
44442
|
-
}
|
|
44443
|
-
return row;
|
|
44444
|
-
}
|
|
44445
|
-
|
|
44446
|
-
// src/agents/acp/change-summary/resolve-change-summary-prompt-for-agent.ts
|
|
44447
|
-
function hasSummarizePayload(f) {
|
|
44448
|
-
return f.directoryRemoved === true || f.patchContent != null && f.patchContent.trim() !== "" || f.oldText != null && f.oldText.trim() !== "" || f.newText != null && f.newText.trim() !== "";
|
|
44449
|
-
}
|
|
44450
|
-
function resolveChangeSummaryPromptForAgent(params) {
|
|
44451
|
-
const isBuiltin = params.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
|
|
44452
|
-
const snaps = params.sessionChangeSummaryFileSnapshots;
|
|
44453
|
-
if (!isBuiltin || !snaps || snaps.length === 0) {
|
|
44454
|
-
return { promptText: params.bridgePromptText, sessionChangeSummaryFilePaths: void 0 };
|
|
44455
|
-
}
|
|
44456
|
-
const decrypted = dedupeSessionFileChangesByPath(snaps.map((row) => decryptChangeSummaryFileInput(row, params.e2ee)));
|
|
44457
|
-
const withPayload = decrypted.filter(hasSummarizePayload);
|
|
44458
|
-
if (withPayload.length === 0) {
|
|
44459
|
-
return { promptText: params.bridgePromptText, sessionChangeSummaryFilePaths: void 0 };
|
|
44460
|
-
}
|
|
44461
|
-
return {
|
|
44462
|
-
promptText: buildSessionChangeSummaryPrompt(withPayload),
|
|
44463
|
-
sessionChangeSummaryFilePaths: withPayload.map((f) => f.path)
|
|
44464
|
-
};
|
|
44465
|
-
}
|
|
44466
|
-
|
|
44467
44340
|
// src/agents/acp/from-bridge/bridge-prompt-preamble.ts
|
|
44468
44341
|
import { execFile as execFile8 } from "node:child_process";
|
|
44469
44342
|
import { promisify as promisify9 } from "node:util";
|
|
@@ -44510,29 +44383,9 @@ async function runBridgePromptPreamble(params) {
|
|
|
44510
44383
|
});
|
|
44511
44384
|
}
|
|
44512
44385
|
}
|
|
44513
|
-
function parseChangeSummarySnapshots(raw) {
|
|
44514
|
-
if (!Array.isArray(raw) || raw.length === 0) return void 0;
|
|
44515
|
-
const out = [];
|
|
44516
|
-
for (const item of raw) {
|
|
44517
|
-
if (!item || typeof item !== "object") continue;
|
|
44518
|
-
const o = item;
|
|
44519
|
-
const path79 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
44520
|
-
if (!path79) continue;
|
|
44521
|
-
const row = { path: path79 };
|
|
44522
|
-
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
44523
|
-
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
44524
|
-
if (typeof o.newText === "string") row.newText = o.newText;
|
|
44525
|
-
if (o.directoryRemoved === true) row.directoryRemoved = true;
|
|
44526
|
-
out.push(row);
|
|
44527
|
-
}
|
|
44528
|
-
return out.length > 0 ? out : void 0;
|
|
44529
|
-
}
|
|
44530
44386
|
function parseFollowUpFieldsFromPromptMessage(msg) {
|
|
44531
44387
|
const followUpCatalogPromptId = typeof msg.followUpCatalogPromptId === "string" && msg.followUpCatalogPromptId.trim() !== "" ? msg.followUpCatalogPromptId.trim() : null;
|
|
44532
|
-
|
|
44533
|
-
const sessionChangeSummaryFilePaths = Array.isArray(rawPaths) ? rawPaths.filter((p) => typeof p === "string" && p.trim() !== "").map((p) => p.trim()) : void 0;
|
|
44534
|
-
const sessionChangeSummaryFileSnapshots = parseChangeSummarySnapshots(msg.sessionChangeSummaryFileSnapshots);
|
|
44535
|
-
return { followUpCatalogPromptId, sessionChangeSummaryFilePaths, sessionChangeSummaryFileSnapshots };
|
|
44388
|
+
return { followUpCatalogPromptId };
|
|
44536
44389
|
}
|
|
44537
44390
|
|
|
44538
44391
|
// src/agents/acp/from-bridge/handle-bridge-prompt/run-preamble-and-prompt.ts
|
|
@@ -44563,25 +44416,9 @@ async function runPreambleAndPrompt(params) {
|
|
|
44563
44416
|
runId,
|
|
44564
44417
|
effectiveCwd
|
|
44565
44418
|
});
|
|
44566
|
-
const {
|
|
44567
|
-
followUpCatalogPromptId,
|
|
44568
|
-
sessionChangeSummaryFilePaths: pathsFromBridge,
|
|
44569
|
-
sessionChangeSummaryFileSnapshots
|
|
44570
|
-
} = parseFollowUpFieldsFromPromptMessage(msg);
|
|
44571
|
-
const { promptText: resolvedPromptText, sessionChangeSummaryFilePaths } = resolveChangeSummaryPromptForAgent({
|
|
44572
|
-
followUpCatalogPromptId,
|
|
44573
|
-
sessionChangeSummaryFileSnapshots,
|
|
44574
|
-
bridgePromptText: promptText,
|
|
44575
|
-
e2ee: deps.e2ee
|
|
44576
|
-
});
|
|
44577
|
-
if (sessionChangeSummaryFileSnapshots && sessionChangeSummaryFileSnapshots.length > 0 && resolvedPromptText === promptText) {
|
|
44578
|
-
deps.log(
|
|
44579
|
-
"[Agent] Change-summary snapshots were present but the prompt was not rebuilt (decrypt failed or empty payloads); sending the bridge prompt as-is."
|
|
44580
|
-
);
|
|
44581
|
-
}
|
|
44582
|
-
const pathsForUpload = sessionChangeSummaryFilePaths ?? pathsFromBridge;
|
|
44419
|
+
const { followUpCatalogPromptId } = parseFollowUpFieldsFromPromptMessage(msg);
|
|
44583
44420
|
deps.acpManager.handlePrompt({
|
|
44584
|
-
promptText
|
|
44421
|
+
promptText,
|
|
44585
44422
|
promptId: msg.id,
|
|
44586
44423
|
sessionId,
|
|
44587
44424
|
runId,
|
|
@@ -44593,7 +44430,6 @@ async function runPreambleAndPrompt(params) {
|
|
|
44593
44430
|
sendResult,
|
|
44594
44431
|
sendSessionUpdate,
|
|
44595
44432
|
followUpCatalogPromptId,
|
|
44596
|
-
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
44597
44433
|
cloudApiBaseUrl: deps.cloudApiBaseUrl,
|
|
44598
44434
|
getCloudAccessToken: deps.getCloudAccessToken,
|
|
44599
44435
|
e2ee: deps.e2ee,
|
|
@@ -46179,12 +46015,17 @@ var handlePreviewEnvironmentControl = (msg, deps) => {
|
|
|
46179
46015
|
};
|
|
46180
46016
|
|
|
46181
46017
|
// src/routing/handlers/preview-environments-config.ts
|
|
46018
|
+
var VALID_PORT = (p) => typeof p === "number" && Number.isInteger(p) && p > 0 && p < 65536;
|
|
46182
46019
|
var handlePreviewEnvironmentsConfig = (msg, deps) => {
|
|
46183
46020
|
const previewEnvironments = msg.previewEnvironments;
|
|
46021
|
+
const proxyPorts = Array.isArray(msg.proxyPorts) ? msg.proxyPorts.filter(VALID_PORT) : void 0;
|
|
46184
46022
|
setImmediate(() => {
|
|
46185
46023
|
deps.previewEnvironmentManager?.applyConfig(previewEnvironments ?? []);
|
|
46186
46024
|
const environmentIds = parsePreviewEnvironmentDefs(previewEnvironments ?? []).map((d) => d.environmentId);
|
|
46187
46025
|
void deps.previewWorktreeManager?.syncConfiguredEnvironments(environmentIds);
|
|
46026
|
+
if (proxyPorts !== void 0) {
|
|
46027
|
+
deps.updateFirehoseProxyPorts?.(proxyPorts);
|
|
46028
|
+
}
|
|
46188
46029
|
});
|
|
46189
46030
|
};
|
|
46190
46031
|
|