@buildautomaton/cli 0.1.15 → 0.1.17
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/README.md +4 -4
- package/dist/cli.js +1718 -607
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1123 -214
- package/dist/index.js.map +4 -4
- package/package.json +4 -2
package/dist/cli.js
CHANGED
|
@@ -973,8 +973,8 @@ var require_command = __commonJS({
|
|
|
973
973
|
"../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
|
|
974
974
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
975
975
|
var childProcess2 = __require("node:child_process");
|
|
976
|
-
var
|
|
977
|
-
var
|
|
976
|
+
var path34 = __require("node:path");
|
|
977
|
+
var fs31 = __require("node:fs");
|
|
978
978
|
var process8 = __require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
980
980
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1906,11 +1906,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1906
1906
|
let launchWithNode = false;
|
|
1907
1907
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1908
1908
|
function findFile(baseDir, baseName) {
|
|
1909
|
-
const localBin =
|
|
1910
|
-
if (
|
|
1911
|
-
if (sourceExt.includes(
|
|
1909
|
+
const localBin = path34.resolve(baseDir, baseName);
|
|
1910
|
+
if (fs31.existsSync(localBin)) return localBin;
|
|
1911
|
+
if (sourceExt.includes(path34.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
|
-
(ext) =>
|
|
1913
|
+
(ext) => fs31.existsSync(`${localBin}${ext}`)
|
|
1914
1914
|
);
|
|
1915
1915
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1916
1916
|
return void 0;
|
|
@@ -1922,21 +1922,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1922
1922
|
if (this._scriptPath) {
|
|
1923
1923
|
let resolvedScriptPath;
|
|
1924
1924
|
try {
|
|
1925
|
-
resolvedScriptPath =
|
|
1925
|
+
resolvedScriptPath = fs31.realpathSync(this._scriptPath);
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
1929
|
-
executableDir =
|
|
1930
|
-
|
|
1929
|
+
executableDir = path34.resolve(
|
|
1930
|
+
path34.dirname(resolvedScriptPath),
|
|
1931
1931
|
executableDir
|
|
1932
1932
|
);
|
|
1933
1933
|
}
|
|
1934
1934
|
if (executableDir) {
|
|
1935
1935
|
let localFile = findFile(executableDir, executableFile);
|
|
1936
1936
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1937
|
-
const legacyName =
|
|
1937
|
+
const legacyName = path34.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path34.extname(this._scriptPath)
|
|
1940
1940
|
);
|
|
1941
1941
|
if (legacyName !== this._name) {
|
|
1942
1942
|
localFile = findFile(
|
|
@@ -1947,7 +1947,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1947
1947
|
}
|
|
1948
1948
|
executableFile = localFile || executableFile;
|
|
1949
1949
|
}
|
|
1950
|
-
launchWithNode = sourceExt.includes(
|
|
1950
|
+
launchWithNode = sourceExt.includes(path34.extname(executableFile));
|
|
1951
1951
|
let proc;
|
|
1952
1952
|
if (process8.platform !== "win32") {
|
|
1953
1953
|
if (launchWithNode) {
|
|
@@ -2787,7 +2787,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2787
2787
|
* @return {Command}
|
|
2788
2788
|
*/
|
|
2789
2789
|
nameFromFilename(filename) {
|
|
2790
|
-
this._name =
|
|
2790
|
+
this._name = path34.basename(filename, path34.extname(filename));
|
|
2791
2791
|
return this;
|
|
2792
2792
|
}
|
|
2793
2793
|
/**
|
|
@@ -2801,9 +2801,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2801
2801
|
* @param {string} [path]
|
|
2802
2802
|
* @return {(string|null|Command)}
|
|
2803
2803
|
*/
|
|
2804
|
-
executableDir(
|
|
2805
|
-
if (
|
|
2806
|
-
this._executableDir =
|
|
2804
|
+
executableDir(path35) {
|
|
2805
|
+
if (path35 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path35;
|
|
2807
2807
|
return this;
|
|
2808
2808
|
}
|
|
2809
2809
|
/**
|
|
@@ -5236,7 +5236,7 @@ var require_websocket = __commonJS({
|
|
|
5236
5236
|
var http = __require("http");
|
|
5237
5237
|
var net = __require("net");
|
|
5238
5238
|
var tls = __require("tls");
|
|
5239
|
-
var { randomBytes, createHash:
|
|
5239
|
+
var { randomBytes: randomBytes3, createHash: createHash3 } = __require("crypto");
|
|
5240
5240
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
5241
5241
|
var { URL: URL2 } = __require("url");
|
|
5242
5242
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -5766,7 +5766,7 @@ var require_websocket = __commonJS({
|
|
|
5766
5766
|
}
|
|
5767
5767
|
}
|
|
5768
5768
|
const defaultPort = isSecure ? 443 : 80;
|
|
5769
|
-
const key =
|
|
5769
|
+
const key = randomBytes3(16).toString("base64");
|
|
5770
5770
|
const request = isSecure ? https2.request : http.request;
|
|
5771
5771
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
5772
5772
|
let perMessageDeflate;
|
|
@@ -5896,7 +5896,7 @@ var require_websocket = __commonJS({
|
|
|
5896
5896
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
5897
5897
|
return;
|
|
5898
5898
|
}
|
|
5899
|
-
const digest =
|
|
5899
|
+
const digest = createHash3("sha1").update(key + GUID).digest("base64");
|
|
5900
5900
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
5901
5901
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
5902
5902
|
return;
|
|
@@ -6263,7 +6263,7 @@ var require_websocket_server = __commonJS({
|
|
|
6263
6263
|
var EventEmitter2 = __require("events");
|
|
6264
6264
|
var http = __require("http");
|
|
6265
6265
|
var { Duplex } = __require("stream");
|
|
6266
|
-
var { createHash:
|
|
6266
|
+
var { createHash: createHash3 } = __require("crypto");
|
|
6267
6267
|
var extension = require_extension();
|
|
6268
6268
|
var PerMessageDeflate = require_permessage_deflate();
|
|
6269
6269
|
var subprotocol = require_subprotocol();
|
|
@@ -6564,7 +6564,7 @@ var require_websocket_server = __commonJS({
|
|
|
6564
6564
|
);
|
|
6565
6565
|
}
|
|
6566
6566
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
6567
|
-
const digest =
|
|
6567
|
+
const digest = createHash3("sha1").update(key + GUID).digest("base64");
|
|
6568
6568
|
const headers = [
|
|
6569
6569
|
"HTTP/1.1 101 Switching Protocols",
|
|
6570
6570
|
"Upgrade: websocket",
|
|
@@ -7423,15 +7423,15 @@ var require_src2 = __commonJS({
|
|
|
7423
7423
|
var fs_1 = __require("fs");
|
|
7424
7424
|
var debug_1 = __importDefault(require_src());
|
|
7425
7425
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
7426
|
-
function check2(
|
|
7427
|
-
log2(`checking %s`,
|
|
7426
|
+
function check2(path34, isFile, isDirectory) {
|
|
7427
|
+
log2(`checking %s`, path34);
|
|
7428
7428
|
try {
|
|
7429
|
-
const
|
|
7430
|
-
if (
|
|
7429
|
+
const stat3 = fs_1.statSync(path34);
|
|
7430
|
+
if (stat3.isFile() && isFile) {
|
|
7431
7431
|
log2(`[OK] path represents a file`);
|
|
7432
7432
|
return true;
|
|
7433
7433
|
}
|
|
7434
|
-
if (
|
|
7434
|
+
if (stat3.isDirectory() && isDirectory) {
|
|
7435
7435
|
log2(`[OK] path represents a directory`);
|
|
7436
7436
|
return true;
|
|
7437
7437
|
}
|
|
@@ -7446,8 +7446,8 @@ var require_src2 = __commonJS({
|
|
|
7446
7446
|
throw e;
|
|
7447
7447
|
}
|
|
7448
7448
|
}
|
|
7449
|
-
function exists2(
|
|
7450
|
-
return check2(
|
|
7449
|
+
function exists2(path34, type = exports.READABLE) {
|
|
7450
|
+
return check2(path34, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
7451
7451
|
}
|
|
7452
7452
|
exports.exists = exists2;
|
|
7453
7453
|
exports.FILE = 1;
|
|
@@ -7922,8 +7922,8 @@ var init_parseUtil = __esm({
|
|
|
7922
7922
|
init_errors();
|
|
7923
7923
|
init_en();
|
|
7924
7924
|
makeIssue = (params) => {
|
|
7925
|
-
const { data, path:
|
|
7926
|
-
const fullPath = [...
|
|
7925
|
+
const { data, path: path34, errorMaps, issueData } = params;
|
|
7926
|
+
const fullPath = [...path34, ...issueData.path || []];
|
|
7927
7927
|
const fullIssue = {
|
|
7928
7928
|
...issueData,
|
|
7929
7929
|
path: fullPath
|
|
@@ -8231,11 +8231,11 @@ var init_types = __esm({
|
|
|
8231
8231
|
init_parseUtil();
|
|
8232
8232
|
init_util2();
|
|
8233
8233
|
ParseInputLazyPath = class {
|
|
8234
|
-
constructor(parent, value,
|
|
8234
|
+
constructor(parent, value, path34, key) {
|
|
8235
8235
|
this._cachedPath = [];
|
|
8236
8236
|
this.parent = parent;
|
|
8237
8237
|
this.data = value;
|
|
8238
|
-
this._path =
|
|
8238
|
+
this._path = path34;
|
|
8239
8239
|
this._key = key;
|
|
8240
8240
|
}
|
|
8241
8241
|
get path() {
|
|
@@ -11850,10 +11850,10 @@ function assignProp(target, prop, value) {
|
|
|
11850
11850
|
configurable: true
|
|
11851
11851
|
});
|
|
11852
11852
|
}
|
|
11853
|
-
function getElementAtPath(obj,
|
|
11854
|
-
if (!
|
|
11853
|
+
function getElementAtPath(obj, path34) {
|
|
11854
|
+
if (!path34)
|
|
11855
11855
|
return obj;
|
|
11856
|
-
return
|
|
11856
|
+
return path34.reduce((acc, key) => acc?.[key], obj);
|
|
11857
11857
|
}
|
|
11858
11858
|
function promiseAllObject(promisesObj) {
|
|
11859
11859
|
const keys = Object.keys(promisesObj);
|
|
@@ -12102,11 +12102,11 @@ function aborted(x, startIndex = 0) {
|
|
|
12102
12102
|
}
|
|
12103
12103
|
return false;
|
|
12104
12104
|
}
|
|
12105
|
-
function prefixIssues(
|
|
12105
|
+
function prefixIssues(path34, issues) {
|
|
12106
12106
|
return issues.map((iss) => {
|
|
12107
12107
|
var _a2;
|
|
12108
12108
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
12109
|
-
iss.path.unshift(
|
|
12109
|
+
iss.path.unshift(path34);
|
|
12110
12110
|
return iss;
|
|
12111
12111
|
});
|
|
12112
12112
|
}
|
|
@@ -12295,7 +12295,7 @@ function treeifyError(error40, _mapper) {
|
|
|
12295
12295
|
return issue2.message;
|
|
12296
12296
|
};
|
|
12297
12297
|
const result = { errors: [] };
|
|
12298
|
-
const processError = (error41,
|
|
12298
|
+
const processError = (error41, path34 = []) => {
|
|
12299
12299
|
var _a2, _b;
|
|
12300
12300
|
for (const issue2 of error41.issues) {
|
|
12301
12301
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -12305,7 +12305,7 @@ function treeifyError(error40, _mapper) {
|
|
|
12305
12305
|
} else if (issue2.code === "invalid_element") {
|
|
12306
12306
|
processError({ issues: issue2.issues }, issue2.path);
|
|
12307
12307
|
} else {
|
|
12308
|
-
const fullpath = [...
|
|
12308
|
+
const fullpath = [...path34, ...issue2.path];
|
|
12309
12309
|
if (fullpath.length === 0) {
|
|
12310
12310
|
result.errors.push(mapper(issue2));
|
|
12311
12311
|
continue;
|
|
@@ -12335,9 +12335,9 @@ function treeifyError(error40, _mapper) {
|
|
|
12335
12335
|
processError(error40);
|
|
12336
12336
|
return result;
|
|
12337
12337
|
}
|
|
12338
|
-
function toDotPath(
|
|
12338
|
+
function toDotPath(path34) {
|
|
12339
12339
|
const segs = [];
|
|
12340
|
-
for (const seg of
|
|
12340
|
+
for (const seg of path34) {
|
|
12341
12341
|
if (typeof seg === "number")
|
|
12342
12342
|
segs.push(`[${seg}]`);
|
|
12343
12343
|
else if (typeof seg === "symbol")
|
|
@@ -24800,8 +24800,8 @@ var init_acp = __esm({
|
|
|
24800
24800
|
this.#requestHandler = requestHandler;
|
|
24801
24801
|
this.#notificationHandler = notificationHandler;
|
|
24802
24802
|
this.#stream = stream;
|
|
24803
|
-
this.#closedPromise = new Promise((
|
|
24804
|
-
this.#abortController.signal.addEventListener("abort", () =>
|
|
24803
|
+
this.#closedPromise = new Promise((resolve17) => {
|
|
24804
|
+
this.#abortController.signal.addEventListener("abort", () => resolve17());
|
|
24805
24805
|
});
|
|
24806
24806
|
this.#receive();
|
|
24807
24807
|
}
|
|
@@ -24950,8 +24950,8 @@ var init_acp = __esm({
|
|
|
24950
24950
|
}
|
|
24951
24951
|
async sendRequest(method, params) {
|
|
24952
24952
|
const id = this.#nextRequestId++;
|
|
24953
|
-
const responsePromise = new Promise((
|
|
24954
|
-
this.#pendingResponses.set(id, { resolve:
|
|
24953
|
+
const responsePromise = new Promise((resolve17, reject) => {
|
|
24954
|
+
this.#pendingResponses.set(id, { resolve: resolve17, reject });
|
|
24955
24955
|
});
|
|
24956
24956
|
await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
|
|
24957
24957
|
return responsePromise;
|
|
@@ -25046,10 +25046,6 @@ var init_acp = __esm({
|
|
|
25046
25046
|
}
|
|
25047
25047
|
});
|
|
25048
25048
|
|
|
25049
|
-
// src/cli.ts
|
|
25050
|
-
import * as fs29 from "node:fs";
|
|
25051
|
-
import * as path32 from "node:path";
|
|
25052
|
-
|
|
25053
25049
|
// ../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/esm.mjs
|
|
25054
25050
|
var import_index = __toESM(require_commander(), 1);
|
|
25055
25051
|
var {
|
|
@@ -25067,6 +25063,14 @@ var {
|
|
|
25067
25063
|
Help
|
|
25068
25064
|
} = import_index.default;
|
|
25069
25065
|
|
|
25066
|
+
// src/cli/defaults.ts
|
|
25067
|
+
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
25068
|
+
var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
25069
|
+
|
|
25070
|
+
// src/cli/run-cli-action.ts
|
|
25071
|
+
import * as fs30 from "node:fs";
|
|
25072
|
+
import * as path33 from "node:path";
|
|
25073
|
+
|
|
25070
25074
|
// src/config.ts
|
|
25071
25075
|
import fs from "node:fs";
|
|
25072
25076
|
import path from "node:path";
|
|
@@ -25145,15 +25149,291 @@ function clearConfigForApi(apiUrl) {
|
|
|
25145
25149
|
}
|
|
25146
25150
|
}
|
|
25147
25151
|
|
|
25148
|
-
// src/
|
|
25152
|
+
// src/e2e-certificates/certificates.ts
|
|
25153
|
+
import * as fs2 from "node:fs/promises";
|
|
25149
25154
|
import * as path2 from "node:path";
|
|
25155
|
+
|
|
25156
|
+
// ../e2ee/src/constants.ts
|
|
25157
|
+
var E2EE_ALG = "A1";
|
|
25158
|
+
var E2EE_KEY_BYTES = 32;
|
|
25159
|
+
var E2EE_NONCE_BYTES = 12;
|
|
25160
|
+
|
|
25161
|
+
// ../e2ee/src/types.ts
|
|
25162
|
+
function isE2eeEnvelope(value) {
|
|
25163
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
25164
|
+
const o = value;
|
|
25165
|
+
return typeof o.k === "string" && typeof o.n === "string" && typeof o.c === "string";
|
|
25166
|
+
}
|
|
25167
|
+
function isE2eeKeyRecord(value) {
|
|
25168
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
25169
|
+
const o = value;
|
|
25170
|
+
return typeof o.id === "string" && o.id.length > 0 && typeof o.name === "string" && o.name.length > 0 && o.a === E2EE_ALG && typeof o.k === "string" && o.k.length > 0 && typeof o.createdAt === "string" && o.createdAt.length > 0;
|
|
25171
|
+
}
|
|
25172
|
+
|
|
25173
|
+
// ../e2ee/src/encoding.ts
|
|
25174
|
+
function base64UrlEncode(bytes) {
|
|
25175
|
+
let binary = "";
|
|
25176
|
+
for (let i = 0; i < bytes.length; i += 1) binary += String.fromCharCode(bytes[i]);
|
|
25177
|
+
const b64 = btoa(binary);
|
|
25178
|
+
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
25179
|
+
}
|
|
25180
|
+
function base64UrlDecode(value) {
|
|
25181
|
+
const b64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
25182
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
25183
|
+
const binary = atob(padded);
|
|
25184
|
+
const out = new Uint8Array(binary.length);
|
|
25185
|
+
for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);
|
|
25186
|
+
return out;
|
|
25187
|
+
}
|
|
25188
|
+
|
|
25189
|
+
// ../e2ee/src/pem.ts
|
|
25190
|
+
var E2EE_PEM_LABEL = "BUILD AUTOMATON E2EE KEY";
|
|
25191
|
+
function pemHeaderValue(headers, name) {
|
|
25192
|
+
return headers[name.toLowerCase()];
|
|
25193
|
+
}
|
|
25194
|
+
function encodePemBase64(bytes) {
|
|
25195
|
+
const raw = base64UrlEncode(bytes).replace(/-/g, "+").replace(/_/g, "/");
|
|
25196
|
+
const padded = raw + "=".repeat((4 - raw.length % 4) % 4);
|
|
25197
|
+
return padded.replace(/.{1,64}/g, "$&\n").trimEnd();
|
|
25198
|
+
}
|
|
25199
|
+
function decodePemBase64(value) {
|
|
25200
|
+
const compact = value.replace(/\s+/g, "");
|
|
25201
|
+
const binary = atob(compact);
|
|
25202
|
+
const out = new Uint8Array(binary.length);
|
|
25203
|
+
for (let i = 0; i < binary.length; i += 1) out[i] = binary.charCodeAt(i);
|
|
25204
|
+
return out;
|
|
25205
|
+
}
|
|
25206
|
+
function parseE2eeKeyRecordPem(raw, fallbackName) {
|
|
25207
|
+
const lines = raw.trim().split(/\r?\n/);
|
|
25208
|
+
if (lines[0]?.trim() !== `-----BEGIN ${E2EE_PEM_LABEL}-----`) {
|
|
25209
|
+
throw new Error("The E2EE key file is not a BuildAutomaton PEM key.");
|
|
25210
|
+
}
|
|
25211
|
+
const endIndex = lines.findIndex((line) => line.trim() === `-----END ${E2EE_PEM_LABEL}-----`);
|
|
25212
|
+
if (endIndex < 0) throw new Error("The E2EE key PEM is missing its end marker.");
|
|
25213
|
+
const headers = {};
|
|
25214
|
+
const bodyLines = [];
|
|
25215
|
+
let readingBody = false;
|
|
25216
|
+
for (const line of lines.slice(1, endIndex)) {
|
|
25217
|
+
const trimmed2 = line.trim();
|
|
25218
|
+
if (!trimmed2) {
|
|
25219
|
+
readingBody = true;
|
|
25220
|
+
continue;
|
|
25221
|
+
}
|
|
25222
|
+
const headerMatch = /^([A-Za-z0-9-]+):\s*(.*)$/.exec(trimmed2);
|
|
25223
|
+
if (!readingBody && headerMatch) {
|
|
25224
|
+
headers[headerMatch[1].toLowerCase()] = headerMatch[2].trim();
|
|
25225
|
+
continue;
|
|
25226
|
+
}
|
|
25227
|
+
readingBody = true;
|
|
25228
|
+
bodyLines.push(trimmed2);
|
|
25229
|
+
}
|
|
25230
|
+
const keyBytes = decodePemBase64(bodyLines.join(""));
|
|
25231
|
+
if (keyBytes.byteLength !== E2EE_KEY_BYTES) throw new Error("The E2EE key PEM does not contain a 256-bit key.");
|
|
25232
|
+
const key = {
|
|
25233
|
+
id: pemHeaderValue(headers, "Key-Id") ?? "",
|
|
25234
|
+
name: pemHeaderValue(headers, "Name") ?? fallbackName,
|
|
25235
|
+
a: pemHeaderValue(headers, "Algorithm") ?? E2EE_ALG,
|
|
25236
|
+
k: base64UrlEncode(keyBytes),
|
|
25237
|
+
createdAt: pemHeaderValue(headers, "Created-At") ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
25238
|
+
};
|
|
25239
|
+
if (!isE2eeKeyRecord(key)) throw new Error("The E2EE key PEM has invalid metadata.");
|
|
25240
|
+
return {
|
|
25241
|
+
...key,
|
|
25242
|
+
name: key.name.trim() || fallbackName
|
|
25243
|
+
};
|
|
25244
|
+
}
|
|
25245
|
+
function parseE2eeKeyRecord(raw, fallbackName) {
|
|
25246
|
+
return parseE2eeKeyRecordPem(raw.trim(), fallbackName);
|
|
25247
|
+
}
|
|
25248
|
+
function serializeE2eeKeyRecord(key) {
|
|
25249
|
+
return [
|
|
25250
|
+
`-----BEGIN ${E2EE_PEM_LABEL}-----`,
|
|
25251
|
+
`Key-Id: ${key.id}`,
|
|
25252
|
+
`Name: ${key.name}`,
|
|
25253
|
+
`Algorithm: ${key.a}`,
|
|
25254
|
+
`Created-At: ${key.createdAt}`,
|
|
25255
|
+
"",
|
|
25256
|
+
encodePemBase64(base64UrlDecode(key.k)),
|
|
25257
|
+
`-----END ${E2EE_PEM_LABEL}-----`,
|
|
25258
|
+
""
|
|
25259
|
+
].join("\n");
|
|
25260
|
+
}
|
|
25261
|
+
|
|
25262
|
+
// src/lib/e2ee/cli-e2ee-key.ts
|
|
25263
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
25264
|
+
function createE2eeKeyRecord(name) {
|
|
25265
|
+
const raw = randomBytes(E2EE_KEY_BYTES);
|
|
25266
|
+
const digest = createHash("sha256").update(raw).digest();
|
|
25267
|
+
return {
|
|
25268
|
+
id: base64UrlEncode(digest.subarray(0, 16)),
|
|
25269
|
+
name: name.trim() || "BuildAutomaton E2EE key",
|
|
25270
|
+
a: E2EE_ALG,
|
|
25271
|
+
k: base64UrlEncode(raw),
|
|
25272
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25273
|
+
};
|
|
25274
|
+
}
|
|
25275
|
+
|
|
25276
|
+
// src/lib/e2ee/cli-e2ee-runtime.ts
|
|
25277
|
+
import { createCipheriv, createDecipheriv, randomBytes as randomBytes2 } from "node:crypto";
|
|
25278
|
+
function nonceFromCounter(prefix, counter) {
|
|
25279
|
+
const nonce = Buffer.alloc(E2EE_NONCE_BYTES);
|
|
25280
|
+
prefix.copy(nonce, 0);
|
|
25281
|
+
nonce.writeBigUInt64BE(counter, 4);
|
|
25282
|
+
return nonce;
|
|
25283
|
+
}
|
|
25284
|
+
function createCliE2eeRuntime(key) {
|
|
25285
|
+
const rawKey = Buffer.from(base64UrlDecode(key.k));
|
|
25286
|
+
const prefix = randomBytes2(4);
|
|
25287
|
+
let counter = 0n;
|
|
25288
|
+
function nextNonce() {
|
|
25289
|
+
counter += 1n;
|
|
25290
|
+
return nonceFromCounter(prefix, counter);
|
|
25291
|
+
}
|
|
25292
|
+
function encryptObject(messageWithoutSensitiveFields, plaintext) {
|
|
25293
|
+
const nonce = nextNonce();
|
|
25294
|
+
const cipher = createCipheriv("aes-256-gcm", rawKey, nonce);
|
|
25295
|
+
const ciphertext = Buffer.concat([cipher.update(JSON.stringify(plaintext), "utf8"), cipher.final()]);
|
|
25296
|
+
const tag = cipher.getAuthTag();
|
|
25297
|
+
return {
|
|
25298
|
+
k: key.id,
|
|
25299
|
+
n: base64UrlEncode(nonce),
|
|
25300
|
+
c: base64UrlEncode(Buffer.concat([ciphertext, tag]))
|
|
25301
|
+
};
|
|
25302
|
+
}
|
|
25303
|
+
return {
|
|
25304
|
+
keyId: key.id,
|
|
25305
|
+
handshake: { k: key.id, a: key.a },
|
|
25306
|
+
encryptFields(message, fields) {
|
|
25307
|
+
const plaintext = {};
|
|
25308
|
+
const stripped = { ...message };
|
|
25309
|
+
let hasPlaintext = false;
|
|
25310
|
+
for (const field of fields) {
|
|
25311
|
+
if (Object.prototype.hasOwnProperty.call(stripped, field) && stripped[field] !== void 0) {
|
|
25312
|
+
plaintext[field] = stripped[field];
|
|
25313
|
+
delete stripped[field];
|
|
25314
|
+
hasPlaintext = true;
|
|
25315
|
+
}
|
|
25316
|
+
}
|
|
25317
|
+
if (!hasPlaintext) return message;
|
|
25318
|
+
stripped.ee = encryptObject(stripped, plaintext);
|
|
25319
|
+
return stripped;
|
|
25320
|
+
},
|
|
25321
|
+
decryptMessage(message) {
|
|
25322
|
+
const envelope = message.ee;
|
|
25323
|
+
if (!isE2eeEnvelope(envelope)) return message;
|
|
25324
|
+
if (envelope.k !== key.id) throw new Error(`E2EE key mismatch: ${envelope.k}`);
|
|
25325
|
+
const sealed = Buffer.from(base64UrlDecode(envelope.c));
|
|
25326
|
+
if (sealed.length < 16) throw new Error("Invalid E2EE payload.");
|
|
25327
|
+
const ciphertext = sealed.subarray(0, sealed.length - 16);
|
|
25328
|
+
const tag = sealed.subarray(sealed.length - 16);
|
|
25329
|
+
const nonce = Buffer.from(base64UrlDecode(envelope.n));
|
|
25330
|
+
const decipher = createDecipheriv("aes-256-gcm", rawKey, nonce);
|
|
25331
|
+
decipher.setAuthTag(tag);
|
|
25332
|
+
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
25333
|
+
const parsed = JSON.parse(decrypted);
|
|
25334
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
25335
|
+
throw new Error("E2EE payload did not decode to an object.");
|
|
25336
|
+
}
|
|
25337
|
+
const merged = { ...message, ...parsed };
|
|
25338
|
+
delete merged.ee;
|
|
25339
|
+
return merged;
|
|
25340
|
+
}
|
|
25341
|
+
};
|
|
25342
|
+
}
|
|
25343
|
+
|
|
25344
|
+
// src/e2e-certificates/certificates.ts
|
|
25345
|
+
var E2E_CERTIFICATE_ALGORITHM = "A1";
|
|
25346
|
+
var CERTIFICATE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".pem", ".key", ".crt"]);
|
|
25347
|
+
function certificateFromKey({
|
|
25348
|
+
raw,
|
|
25349
|
+
name,
|
|
25350
|
+
createdAt
|
|
25351
|
+
}) {
|
|
25352
|
+
try {
|
|
25353
|
+
const key = parseE2eeKeyRecord(raw, name);
|
|
25354
|
+
return {
|
|
25355
|
+
...key,
|
|
25356
|
+
name: key.name || name,
|
|
25357
|
+
algorithm: E2E_CERTIFICATE_ALGORITHM,
|
|
25358
|
+
pemBundle: serializeE2eeKeyRecord({ ...key, createdAt: key.createdAt || createdAt })
|
|
25359
|
+
};
|
|
25360
|
+
} catch {
|
|
25361
|
+
return void 0;
|
|
25362
|
+
}
|
|
25363
|
+
}
|
|
25364
|
+
function baseNameForCertificate(fileName) {
|
|
25365
|
+
return path2.basename(fileName, path2.extname(fileName)) || "BuildAutomaton E2EE certificate";
|
|
25366
|
+
}
|
|
25367
|
+
async function readCertificateFiles(directory) {
|
|
25368
|
+
let entries;
|
|
25369
|
+
try {
|
|
25370
|
+
entries = await fs2.readdir(directory, { withFileTypes: true });
|
|
25371
|
+
} catch (err) {
|
|
25372
|
+
const nodeErr = err;
|
|
25373
|
+
if (nodeErr.code === "ENOENT") return [];
|
|
25374
|
+
throw err;
|
|
25375
|
+
}
|
|
25376
|
+
const certificates = [];
|
|
25377
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
25378
|
+
if (!entry.isFile() || !CERTIFICATE_FILE_EXTENSIONS.has(path2.extname(entry.name).toLowerCase())) continue;
|
|
25379
|
+
const filePath = path2.join(directory, entry.name);
|
|
25380
|
+
const raw = await fs2.readFile(filePath, "utf8").catch(() => void 0);
|
|
25381
|
+
if (!raw) continue;
|
|
25382
|
+
const stat3 = await fs2.stat(filePath).catch(() => void 0);
|
|
25383
|
+
const certificate = certificateFromKey({
|
|
25384
|
+
raw,
|
|
25385
|
+
name: baseNameForCertificate(entry.name),
|
|
25386
|
+
createdAt: stat3?.mtime?.toISOString() ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
25387
|
+
});
|
|
25388
|
+
if (certificate) {
|
|
25389
|
+
certificates.push(certificate);
|
|
25390
|
+
}
|
|
25391
|
+
}
|
|
25392
|
+
return certificates;
|
|
25393
|
+
}
|
|
25394
|
+
function createCertificate(directory) {
|
|
25395
|
+
const baseName = path2.basename(directory) || "BuildAutomaton E2EE certificate";
|
|
25396
|
+
const key = createE2eeKeyRecord(baseName);
|
|
25397
|
+
return {
|
|
25398
|
+
...key,
|
|
25399
|
+
algorithm: E2E_CERTIFICATE_ALGORITHM,
|
|
25400
|
+
pemBundle: serializeE2eeKeyRecord(key)
|
|
25401
|
+
};
|
|
25402
|
+
}
|
|
25403
|
+
async function loadOrCreateE2eCertificates(directory) {
|
|
25404
|
+
const resolved = path2.resolve(directory);
|
|
25405
|
+
await fs2.mkdir(resolved, { recursive: true, mode: 448 });
|
|
25406
|
+
const existing = await readCertificateFiles(resolved);
|
|
25407
|
+
if (existing.length > 0) {
|
|
25408
|
+
return {
|
|
25409
|
+
directory: resolved,
|
|
25410
|
+
certificates: existing,
|
|
25411
|
+
activeCertificate: existing[0],
|
|
25412
|
+
generated: false
|
|
25413
|
+
};
|
|
25414
|
+
}
|
|
25415
|
+
const certificate = createCertificate(resolved);
|
|
25416
|
+
const fileName = `buildautomaton-e2ee-key-${certificate.id.slice(0, 12)}.pem`;
|
|
25417
|
+
await fs2.writeFile(path2.join(resolved, fileName), certificate.pemBundle, {
|
|
25418
|
+
mode: 384
|
|
25419
|
+
});
|
|
25420
|
+
return {
|
|
25421
|
+
directory: resolved,
|
|
25422
|
+
certificates: [certificate],
|
|
25423
|
+
activeCertificate: certificate,
|
|
25424
|
+
generated: true
|
|
25425
|
+
};
|
|
25426
|
+
}
|
|
25427
|
+
|
|
25428
|
+
// src/files/cwd/bridge-workspace-directory.ts
|
|
25429
|
+
import * as path3 from "node:path";
|
|
25150
25430
|
var bridgeWorkspaceDirectory = null;
|
|
25151
25431
|
function initBridgeWorkspaceDirectory() {
|
|
25152
|
-
bridgeWorkspaceDirectory =
|
|
25432
|
+
bridgeWorkspaceDirectory = path3.resolve(process.cwd());
|
|
25153
25433
|
}
|
|
25154
25434
|
function getBridgeWorkspaceDirectory() {
|
|
25155
25435
|
if (bridgeWorkspaceDirectory == null) {
|
|
25156
|
-
bridgeWorkspaceDirectory =
|
|
25436
|
+
bridgeWorkspaceDirectory = path3.resolve(process.cwd());
|
|
25157
25437
|
}
|
|
25158
25438
|
return bridgeWorkspaceDirectory;
|
|
25159
25439
|
}
|
|
@@ -25324,30 +25604,30 @@ function sendWsMessage(ws, payload) {
|
|
|
25324
25604
|
// ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
|
|
25325
25605
|
import process7 from "node:process";
|
|
25326
25606
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
25327
|
-
import
|
|
25607
|
+
import path4 from "node:path";
|
|
25328
25608
|
import { fileURLToPath } from "node:url";
|
|
25329
25609
|
import { promisify as promisify5 } from "node:util";
|
|
25330
25610
|
import childProcess from "node:child_process";
|
|
25331
|
-
import
|
|
25611
|
+
import fs7, { constants as fsConstants2 } from "node:fs/promises";
|
|
25332
25612
|
|
|
25333
25613
|
// ../../node_modules/.pnpm/wsl-utils@0.1.0/node_modules/wsl-utils/index.js
|
|
25334
25614
|
import process3 from "node:process";
|
|
25335
|
-
import
|
|
25615
|
+
import fs6, { constants as fsConstants } from "node:fs/promises";
|
|
25336
25616
|
|
|
25337
25617
|
// ../../node_modules/.pnpm/is-wsl@3.1.1/node_modules/is-wsl/index.js
|
|
25338
25618
|
import process2 from "node:process";
|
|
25339
25619
|
import os2 from "node:os";
|
|
25340
|
-
import
|
|
25620
|
+
import fs5 from "node:fs";
|
|
25341
25621
|
|
|
25342
25622
|
// ../../node_modules/.pnpm/is-inside-container@1.0.0/node_modules/is-inside-container/index.js
|
|
25343
|
-
import
|
|
25623
|
+
import fs4 from "node:fs";
|
|
25344
25624
|
|
|
25345
25625
|
// ../../node_modules/.pnpm/is-docker@3.0.0/node_modules/is-docker/index.js
|
|
25346
|
-
import
|
|
25626
|
+
import fs3 from "node:fs";
|
|
25347
25627
|
var isDockerCached;
|
|
25348
25628
|
function hasDockerEnv() {
|
|
25349
25629
|
try {
|
|
25350
|
-
|
|
25630
|
+
fs3.statSync("/.dockerenv");
|
|
25351
25631
|
return true;
|
|
25352
25632
|
} catch {
|
|
25353
25633
|
return false;
|
|
@@ -25355,7 +25635,7 @@ function hasDockerEnv() {
|
|
|
25355
25635
|
}
|
|
25356
25636
|
function hasDockerCGroup() {
|
|
25357
25637
|
try {
|
|
25358
|
-
return
|
|
25638
|
+
return fs3.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
25359
25639
|
} catch {
|
|
25360
25640
|
return false;
|
|
25361
25641
|
}
|
|
@@ -25371,7 +25651,7 @@ function isDocker() {
|
|
|
25371
25651
|
var cachedResult;
|
|
25372
25652
|
var hasContainerEnv = () => {
|
|
25373
25653
|
try {
|
|
25374
|
-
|
|
25654
|
+
fs4.statSync("/run/.containerenv");
|
|
25375
25655
|
return true;
|
|
25376
25656
|
} catch {
|
|
25377
25657
|
return false;
|
|
@@ -25396,12 +25676,12 @@ var isWsl = () => {
|
|
|
25396
25676
|
return true;
|
|
25397
25677
|
}
|
|
25398
25678
|
try {
|
|
25399
|
-
if (
|
|
25679
|
+
if (fs5.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
|
|
25400
25680
|
return !isInsideContainer();
|
|
25401
25681
|
}
|
|
25402
25682
|
} catch {
|
|
25403
25683
|
}
|
|
25404
|
-
if (
|
|
25684
|
+
if (fs5.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs5.existsSync("/run/WSL")) {
|
|
25405
25685
|
return !isInsideContainer();
|
|
25406
25686
|
}
|
|
25407
25687
|
return false;
|
|
@@ -25419,14 +25699,14 @@ var wslDrivesMountPoint = /* @__PURE__ */ (() => {
|
|
|
25419
25699
|
const configFilePath2 = "/etc/wsl.conf";
|
|
25420
25700
|
let isConfigFileExists = false;
|
|
25421
25701
|
try {
|
|
25422
|
-
await
|
|
25702
|
+
await fs6.access(configFilePath2, fsConstants.F_OK);
|
|
25423
25703
|
isConfigFileExists = true;
|
|
25424
25704
|
} catch {
|
|
25425
25705
|
}
|
|
25426
25706
|
if (!isConfigFileExists) {
|
|
25427
25707
|
return defaultMountPoint;
|
|
25428
25708
|
}
|
|
25429
|
-
const configContent = await
|
|
25709
|
+
const configContent = await fs6.readFile(configFilePath2, { encoding: "utf8" });
|
|
25430
25710
|
const configMountPoint = /(?<!#.*)root\s*=\s*(?<mountPoint>.*)/g.exec(configContent);
|
|
25431
25711
|
if (!configMountPoint) {
|
|
25432
25712
|
return defaultMountPoint;
|
|
@@ -25580,8 +25860,8 @@ async function defaultBrowser2() {
|
|
|
25580
25860
|
|
|
25581
25861
|
// ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
|
|
25582
25862
|
var execFile5 = promisify5(childProcess.execFile);
|
|
25583
|
-
var __dirname =
|
|
25584
|
-
var localXdgOpenPath =
|
|
25863
|
+
var __dirname = path4.dirname(fileURLToPath(import.meta.url));
|
|
25864
|
+
var localXdgOpenPath = path4.join(__dirname, "xdg-open");
|
|
25585
25865
|
var { platform, arch } = process7;
|
|
25586
25866
|
async function getWindowsDefaultBrowserFromWsl() {
|
|
25587
25867
|
const powershellPath = await powerShellPath();
|
|
@@ -25731,7 +26011,7 @@ var baseOpen = async (options) => {
|
|
|
25731
26011
|
const isBundled = !__dirname || __dirname === "/";
|
|
25732
26012
|
let exeLocalXdgOpen = false;
|
|
25733
26013
|
try {
|
|
25734
|
-
await
|
|
26014
|
+
await fs7.access(localXdgOpenPath, fsConstants2.X_OK);
|
|
25735
26015
|
exeLocalXdgOpen = true;
|
|
25736
26016
|
} catch {
|
|
25737
26017
|
}
|
|
@@ -25754,14 +26034,14 @@ var baseOpen = async (options) => {
|
|
|
25754
26034
|
}
|
|
25755
26035
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
25756
26036
|
if (options.wait) {
|
|
25757
|
-
return new Promise((
|
|
26037
|
+
return new Promise((resolve17, reject) => {
|
|
25758
26038
|
subprocess.once("error", reject);
|
|
25759
26039
|
subprocess.once("close", (exitCode) => {
|
|
25760
26040
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
25761
26041
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
25762
26042
|
return;
|
|
25763
26043
|
}
|
|
25764
|
-
|
|
26044
|
+
resolve17(subprocess);
|
|
25765
26045
|
});
|
|
25766
26046
|
});
|
|
25767
26047
|
}
|
|
@@ -25845,8 +26125,11 @@ function isLocalApiUrl(apiUrl) {
|
|
|
25845
26125
|
return false;
|
|
25846
26126
|
}
|
|
25847
26127
|
}
|
|
26128
|
+
function appUrlForApiUrl(apiUrl) {
|
|
26129
|
+
return apiUrl && isLocalApiUrl(apiUrl) ? process.env.BUILDAUTOMATON_APP_URL ?? "http://localhost:3000" : process.env.BUILDAUTOMATON_APP_URL ?? "https://app.buildautomaton.com";
|
|
26130
|
+
}
|
|
25848
26131
|
async function openBrowser(connectionId, initialWorkspaceId, preferredBridgeName, apiUrl, logFn = log) {
|
|
25849
|
-
const appUrl =
|
|
26132
|
+
const appUrl = appUrlForApiUrl(apiUrl);
|
|
25850
26133
|
let connectCliUrl = `${appUrl.replace(/\/$/, "")}/bridges/connect?connectionId=${connectionId}`;
|
|
25851
26134
|
if (initialWorkspaceId) {
|
|
25852
26135
|
try {
|
|
@@ -26054,8 +26337,8 @@ function runPendingAuth(options) {
|
|
|
26054
26337
|
let hasOpenedBrowser = false;
|
|
26055
26338
|
let resolved = false;
|
|
26056
26339
|
let resolveAuth;
|
|
26057
|
-
const authPromise = new Promise((
|
|
26058
|
-
resolveAuth =
|
|
26340
|
+
const authPromise = new Promise((resolve17) => {
|
|
26341
|
+
resolveAuth = resolve17;
|
|
26059
26342
|
});
|
|
26060
26343
|
let reconnectAttempt = 0;
|
|
26061
26344
|
const signInQuiet = createEmptyReconnectQuietSlot();
|
|
@@ -26177,7 +26460,7 @@ function runPendingAuth(options) {
|
|
|
26177
26460
|
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
26178
26461
|
const say = log2 ?? logImmediate;
|
|
26179
26462
|
say("Cleaning up connections\u2026");
|
|
26180
|
-
await new Promise((
|
|
26463
|
+
await new Promise((resolve17) => setImmediate(resolve17));
|
|
26181
26464
|
state.closedByUser = true;
|
|
26182
26465
|
clearReconnectQuietTimer(state.mainQuiet);
|
|
26183
26466
|
clearReconnectQuietTimer(state.firehoseQuiet);
|
|
@@ -26248,19 +26531,19 @@ function localAgentErrorSuggestsAuth(agentType, errorText) {
|
|
|
26248
26531
|
|
|
26249
26532
|
// src/git/session-git-queue.ts
|
|
26250
26533
|
import { execFile as execFile7 } from "node:child_process";
|
|
26251
|
-
import { readFile, stat } from "node:fs/promises";
|
|
26534
|
+
import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
26252
26535
|
import { promisify as promisify7 } from "node:util";
|
|
26253
|
-
import * as
|
|
26536
|
+
import * as path7 from "node:path";
|
|
26254
26537
|
|
|
26255
26538
|
// src/git/pre-turn-snapshot.ts
|
|
26256
|
-
import * as
|
|
26257
|
-
import * as
|
|
26539
|
+
import * as fs9 from "node:fs";
|
|
26540
|
+
import * as path6 from "node:path";
|
|
26258
26541
|
import { execFile as execFile6 } from "node:child_process";
|
|
26259
26542
|
import { promisify as promisify6 } from "node:util";
|
|
26260
26543
|
|
|
26261
26544
|
// src/git/discover-repos.ts
|
|
26262
|
-
import * as
|
|
26263
|
-
import * as
|
|
26545
|
+
import * as fs8 from "node:fs";
|
|
26546
|
+
import * as path5 from "node:path";
|
|
26264
26547
|
|
|
26265
26548
|
// ../../node_modules/.pnpm/simple-git@3.32.3/node_modules/simple-git/dist/esm/index.js
|
|
26266
26549
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -26299,8 +26582,8 @@ function pathspec(...paths) {
|
|
|
26299
26582
|
cache.set(key, paths);
|
|
26300
26583
|
return key;
|
|
26301
26584
|
}
|
|
26302
|
-
function isPathSpec(
|
|
26303
|
-
return
|
|
26585
|
+
function isPathSpec(path34) {
|
|
26586
|
+
return path34 instanceof String && cache.has(path34);
|
|
26304
26587
|
}
|
|
26305
26588
|
function toPaths(pathSpec) {
|
|
26306
26589
|
return cache.get(pathSpec) || [];
|
|
@@ -26389,8 +26672,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
26389
26672
|
function forEachLineWithContent(input, callback) {
|
|
26390
26673
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
26391
26674
|
}
|
|
26392
|
-
function folderExists(
|
|
26393
|
-
return (0, import_file_exists.exists)(
|
|
26675
|
+
function folderExists(path34) {
|
|
26676
|
+
return (0, import_file_exists.exists)(path34, import_file_exists.FOLDER);
|
|
26394
26677
|
}
|
|
26395
26678
|
function append(target, item) {
|
|
26396
26679
|
if (Array.isArray(target)) {
|
|
@@ -26794,8 +27077,8 @@ function checkIsRepoRootTask() {
|
|
|
26794
27077
|
commands,
|
|
26795
27078
|
format: "utf-8",
|
|
26796
27079
|
onError,
|
|
26797
|
-
parser(
|
|
26798
|
-
return /^\.(git)?$/.test(
|
|
27080
|
+
parser(path34) {
|
|
27081
|
+
return /^\.(git)?$/.test(path34.trim());
|
|
26799
27082
|
}
|
|
26800
27083
|
};
|
|
26801
27084
|
}
|
|
@@ -27229,11 +27512,11 @@ function parseGrep(grep) {
|
|
|
27229
27512
|
const paths = /* @__PURE__ */ new Set();
|
|
27230
27513
|
const results = {};
|
|
27231
27514
|
forEachLineWithContent(grep, (input) => {
|
|
27232
|
-
const [
|
|
27233
|
-
paths.add(
|
|
27234
|
-
(results[
|
|
27515
|
+
const [path34, line, preview] = input.split(NULL);
|
|
27516
|
+
paths.add(path34);
|
|
27517
|
+
(results[path34] = results[path34] || []).push({
|
|
27235
27518
|
line: asNumber(line),
|
|
27236
|
-
path:
|
|
27519
|
+
path: path34,
|
|
27237
27520
|
preview
|
|
27238
27521
|
});
|
|
27239
27522
|
});
|
|
@@ -27998,14 +28281,14 @@ var init_hash_object = __esm2({
|
|
|
27998
28281
|
init_task();
|
|
27999
28282
|
}
|
|
28000
28283
|
});
|
|
28001
|
-
function parseInit(bare,
|
|
28284
|
+
function parseInit(bare, path34, text) {
|
|
28002
28285
|
const response = String(text).trim();
|
|
28003
28286
|
let result;
|
|
28004
28287
|
if (result = initResponseRegex.exec(response)) {
|
|
28005
|
-
return new InitSummary(bare,
|
|
28288
|
+
return new InitSummary(bare, path34, false, result[1]);
|
|
28006
28289
|
}
|
|
28007
28290
|
if (result = reInitResponseRegex.exec(response)) {
|
|
28008
|
-
return new InitSummary(bare,
|
|
28291
|
+
return new InitSummary(bare, path34, true, result[1]);
|
|
28009
28292
|
}
|
|
28010
28293
|
let gitDir = "";
|
|
28011
28294
|
const tokens = response.split(" ");
|
|
@@ -28016,7 +28299,7 @@ function parseInit(bare, path33, text) {
|
|
|
28016
28299
|
break;
|
|
28017
28300
|
}
|
|
28018
28301
|
}
|
|
28019
|
-
return new InitSummary(bare,
|
|
28302
|
+
return new InitSummary(bare, path34, /^re/i.test(response), gitDir);
|
|
28020
28303
|
}
|
|
28021
28304
|
var InitSummary;
|
|
28022
28305
|
var initResponseRegex;
|
|
@@ -28025,9 +28308,9 @@ var init_InitSummary = __esm2({
|
|
|
28025
28308
|
"src/lib/responses/InitSummary.ts"() {
|
|
28026
28309
|
"use strict";
|
|
28027
28310
|
InitSummary = class {
|
|
28028
|
-
constructor(bare,
|
|
28311
|
+
constructor(bare, path34, existing, gitDir) {
|
|
28029
28312
|
this.bare = bare;
|
|
28030
|
-
this.path =
|
|
28313
|
+
this.path = path34;
|
|
28031
28314
|
this.existing = existing;
|
|
28032
28315
|
this.gitDir = gitDir;
|
|
28033
28316
|
}
|
|
@@ -28039,7 +28322,7 @@ var init_InitSummary = __esm2({
|
|
|
28039
28322
|
function hasBareCommand(command) {
|
|
28040
28323
|
return command.includes(bareCommand);
|
|
28041
28324
|
}
|
|
28042
|
-
function initTask(bare = false,
|
|
28325
|
+
function initTask(bare = false, path34, customArgs) {
|
|
28043
28326
|
const commands = ["init", ...customArgs];
|
|
28044
28327
|
if (bare && !hasBareCommand(commands)) {
|
|
28045
28328
|
commands.splice(1, 0, bareCommand);
|
|
@@ -28048,7 +28331,7 @@ function initTask(bare = false, path33, customArgs) {
|
|
|
28048
28331
|
commands,
|
|
28049
28332
|
format: "utf-8",
|
|
28050
28333
|
parser(text) {
|
|
28051
|
-
return parseInit(commands.includes("--bare"),
|
|
28334
|
+
return parseInit(commands.includes("--bare"), path34, text);
|
|
28052
28335
|
}
|
|
28053
28336
|
};
|
|
28054
28337
|
}
|
|
@@ -28864,12 +29147,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
28864
29147
|
"use strict";
|
|
28865
29148
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
28866
29149
|
FileStatusSummary = class {
|
|
28867
|
-
constructor(
|
|
28868
|
-
this.path =
|
|
29150
|
+
constructor(path34, index, working_dir) {
|
|
29151
|
+
this.path = path34;
|
|
28869
29152
|
this.index = index;
|
|
28870
29153
|
this.working_dir = working_dir;
|
|
28871
29154
|
if (index === "R" || working_dir === "R") {
|
|
28872
|
-
const detail = fromPathRegex.exec(
|
|
29155
|
+
const detail = fromPathRegex.exec(path34) || [null, path34, path34];
|
|
28873
29156
|
this.from = detail[2] || "";
|
|
28874
29157
|
this.path = detail[1] || "";
|
|
28875
29158
|
}
|
|
@@ -28900,14 +29183,14 @@ function splitLine(result, lineStr) {
|
|
|
28900
29183
|
default:
|
|
28901
29184
|
return;
|
|
28902
29185
|
}
|
|
28903
|
-
function data(index, workingDir,
|
|
29186
|
+
function data(index, workingDir, path34) {
|
|
28904
29187
|
const raw = `${index}${workingDir}`;
|
|
28905
29188
|
const handler = parsers6.get(raw);
|
|
28906
29189
|
if (handler) {
|
|
28907
|
-
handler(result,
|
|
29190
|
+
handler(result, path34);
|
|
28908
29191
|
}
|
|
28909
29192
|
if (raw !== "##" && raw !== "!!") {
|
|
28910
|
-
result.files.push(new FileStatusSummary(
|
|
29193
|
+
result.files.push(new FileStatusSummary(path34, index, workingDir));
|
|
28911
29194
|
}
|
|
28912
29195
|
}
|
|
28913
29196
|
}
|
|
@@ -29216,9 +29499,9 @@ var init_simple_git_api = __esm2({
|
|
|
29216
29499
|
next
|
|
29217
29500
|
);
|
|
29218
29501
|
}
|
|
29219
|
-
hashObject(
|
|
29502
|
+
hashObject(path34, write) {
|
|
29220
29503
|
return this._runTask(
|
|
29221
|
-
hashObjectTask(
|
|
29504
|
+
hashObjectTask(path34, write === true),
|
|
29222
29505
|
trailingFunctionArgument(arguments)
|
|
29223
29506
|
);
|
|
29224
29507
|
}
|
|
@@ -29571,8 +29854,8 @@ var init_branch = __esm2({
|
|
|
29571
29854
|
}
|
|
29572
29855
|
});
|
|
29573
29856
|
function toPath(input) {
|
|
29574
|
-
const
|
|
29575
|
-
return
|
|
29857
|
+
const path34 = input.trim().replace(/^["']|["']$/g, "");
|
|
29858
|
+
return path34 && normalize(path34);
|
|
29576
29859
|
}
|
|
29577
29860
|
var parseCheckIgnore;
|
|
29578
29861
|
var init_CheckIgnore = __esm2({
|
|
@@ -29886,8 +30169,8 @@ __export2(sub_module_exports, {
|
|
|
29886
30169
|
subModuleTask: () => subModuleTask,
|
|
29887
30170
|
updateSubModuleTask: () => updateSubModuleTask
|
|
29888
30171
|
});
|
|
29889
|
-
function addSubModuleTask(repo,
|
|
29890
|
-
return subModuleTask(["add", repo,
|
|
30172
|
+
function addSubModuleTask(repo, path34) {
|
|
30173
|
+
return subModuleTask(["add", repo, path34]);
|
|
29891
30174
|
}
|
|
29892
30175
|
function initSubModuleTask(customArgs) {
|
|
29893
30176
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -30220,8 +30503,8 @@ var require_git = __commonJS2({
|
|
|
30220
30503
|
}
|
|
30221
30504
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
30222
30505
|
};
|
|
30223
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
30224
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
30506
|
+
Git2.prototype.submoduleAdd = function(repo, path34, then) {
|
|
30507
|
+
return this._runTask(addSubModuleTask2(repo, path34), trailingFunctionArgument2(arguments));
|
|
30225
30508
|
};
|
|
30226
30509
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
30227
30510
|
return this._runTask(
|
|
@@ -30847,20 +31130,20 @@ async function isGitRepoDirectory(dirPath) {
|
|
|
30847
31130
|
// src/git/discover-repos.ts
|
|
30848
31131
|
async function discoverGitRepos(cwd = getBridgeWorkspaceDirectory()) {
|
|
30849
31132
|
const result = [];
|
|
30850
|
-
const cwdResolved =
|
|
31133
|
+
const cwdResolved = path5.resolve(cwd);
|
|
30851
31134
|
if (await isGitRepoDirectory(cwdResolved)) {
|
|
30852
31135
|
const remoteUrl = await getRemoteOriginUrl(cwdResolved);
|
|
30853
31136
|
result.push({ absolutePath: cwdResolved, remoteUrl });
|
|
30854
31137
|
}
|
|
30855
31138
|
let entries;
|
|
30856
31139
|
try {
|
|
30857
|
-
entries =
|
|
31140
|
+
entries = fs8.readdirSync(cwdResolved, { withFileTypes: true });
|
|
30858
31141
|
} catch {
|
|
30859
31142
|
return result;
|
|
30860
31143
|
}
|
|
30861
31144
|
for (const ent of entries) {
|
|
30862
31145
|
if (!ent.isDirectory()) continue;
|
|
30863
|
-
const childPath =
|
|
31146
|
+
const childPath = path5.join(cwdResolved, ent.name);
|
|
30864
31147
|
if (await isGitRepoDirectory(childPath)) {
|
|
30865
31148
|
const remoteUrl = await getRemoteOriginUrl(childPath);
|
|
30866
31149
|
result.push({ absolutePath: childPath, remoteUrl });
|
|
@@ -30869,22 +31152,22 @@ async function discoverGitRepos(cwd = getBridgeWorkspaceDirectory()) {
|
|
|
30869
31152
|
return result;
|
|
30870
31153
|
}
|
|
30871
31154
|
async function discoverGitReposUnderRoot(rootAbs) {
|
|
30872
|
-
const root =
|
|
31155
|
+
const root = path5.resolve(rootAbs);
|
|
30873
31156
|
const roots = [];
|
|
30874
31157
|
async function walk(dir) {
|
|
30875
31158
|
if (await isGitRepoDirectory(dir)) {
|
|
30876
|
-
roots.push(
|
|
31159
|
+
roots.push(path5.resolve(dir));
|
|
30877
31160
|
return;
|
|
30878
31161
|
}
|
|
30879
31162
|
let entries;
|
|
30880
31163
|
try {
|
|
30881
|
-
entries =
|
|
31164
|
+
entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
30882
31165
|
} catch {
|
|
30883
31166
|
return;
|
|
30884
31167
|
}
|
|
30885
31168
|
for (const ent of entries) {
|
|
30886
31169
|
if (!ent.isDirectory() || ent.name === ".git") continue;
|
|
30887
|
-
await walk(
|
|
31170
|
+
await walk(path5.join(dir, ent.name));
|
|
30888
31171
|
}
|
|
30889
31172
|
}
|
|
30890
31173
|
await walk(root);
|
|
@@ -30900,7 +31183,7 @@ async function discoverGitReposUnderRoot(rootAbs) {
|
|
|
30900
31183
|
// src/git/pre-turn-snapshot.ts
|
|
30901
31184
|
var execFileAsync5 = promisify6(execFile6);
|
|
30902
31185
|
function snapshotsDirForCwd(agentCwd) {
|
|
30903
|
-
return
|
|
31186
|
+
return path6.join(agentCwd, ".buildautomaton", "snapshots");
|
|
30904
31187
|
}
|
|
30905
31188
|
async function gitStashCreate(repoRoot, log2) {
|
|
30906
31189
|
try {
|
|
@@ -30929,7 +31212,7 @@ async function gitRun(repoRoot, args, log2, label) {
|
|
|
30929
31212
|
async function resolveSnapshotRepoRoots(options) {
|
|
30930
31213
|
const { worktreePaths, fallbackCwd, log: log2 } = options;
|
|
30931
31214
|
if (worktreePaths?.length) {
|
|
30932
|
-
const uniq = [...new Set(worktreePaths.map((p) =>
|
|
31215
|
+
const uniq = [...new Set(worktreePaths.map((p) => path6.resolve(p)))];
|
|
30933
31216
|
return uniq;
|
|
30934
31217
|
}
|
|
30935
31218
|
try {
|
|
@@ -30952,7 +31235,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
30952
31235
|
}
|
|
30953
31236
|
const dir = snapshotsDirForCwd(agentCwd);
|
|
30954
31237
|
try {
|
|
30955
|
-
|
|
31238
|
+
fs9.mkdirSync(dir, { recursive: true });
|
|
30956
31239
|
} catch (e) {
|
|
30957
31240
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
30958
31241
|
}
|
|
@@ -30961,9 +31244,9 @@ async function capturePreTurnSnapshot(options) {
|
|
|
30961
31244
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30962
31245
|
repos
|
|
30963
31246
|
};
|
|
30964
|
-
const filePath =
|
|
31247
|
+
const filePath = path6.join(dir, `${runId}.json`);
|
|
30965
31248
|
try {
|
|
30966
|
-
|
|
31249
|
+
fs9.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
30967
31250
|
} catch (e) {
|
|
30968
31251
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
30969
31252
|
}
|
|
@@ -30976,7 +31259,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
30976
31259
|
async function applyPreTurnSnapshot(filePath, log2) {
|
|
30977
31260
|
let data;
|
|
30978
31261
|
try {
|
|
30979
|
-
const raw =
|
|
31262
|
+
const raw = fs9.readFileSync(filePath, "utf8");
|
|
30980
31263
|
data = JSON.parse(raw);
|
|
30981
31264
|
} catch (e) {
|
|
30982
31265
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
@@ -30999,7 +31282,7 @@ async function applyPreTurnSnapshot(filePath, log2) {
|
|
|
30999
31282
|
return { ok: true };
|
|
31000
31283
|
}
|
|
31001
31284
|
function snapshotFilePath(agentCwd, runId) {
|
|
31002
|
-
return
|
|
31285
|
+
return path6.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
|
|
31003
31286
|
}
|
|
31004
31287
|
|
|
31005
31288
|
// src/git/session-git-queue.ts
|
|
@@ -31007,9 +31290,9 @@ var execFileAsync6 = promisify7(execFile7);
|
|
|
31007
31290
|
var MAX_FULL_FILE_TEXT_BYTES = 512 * 1024;
|
|
31008
31291
|
async function readWorkspaceFileAsUtf8(absPath) {
|
|
31009
31292
|
try {
|
|
31010
|
-
const st = await
|
|
31293
|
+
const st = await stat2(absPath);
|
|
31011
31294
|
if (!st.isFile() || st.size > MAX_FULL_FILE_TEXT_BYTES) return void 0;
|
|
31012
|
-
return await
|
|
31295
|
+
return await readFile2(absPath, "utf8");
|
|
31013
31296
|
} catch {
|
|
31014
31297
|
return void 0;
|
|
31015
31298
|
}
|
|
@@ -31019,7 +31302,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
31019
31302
|
const filePath = snapshotFilePath(agentCwd, runId);
|
|
31020
31303
|
let data;
|
|
31021
31304
|
try {
|
|
31022
|
-
const raw = await
|
|
31305
|
+
const raw = await readFile2(filePath, "utf8");
|
|
31023
31306
|
data = JSON.parse(raw);
|
|
31024
31307
|
} catch (e) {
|
|
31025
31308
|
log2(
|
|
@@ -31048,7 +31331,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
31048
31331
|
continue;
|
|
31049
31332
|
}
|
|
31050
31333
|
const lines = namesRaw.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
31051
|
-
const slug =
|
|
31334
|
+
const slug = path7.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
|
|
31052
31335
|
for (const rel of lines) {
|
|
31053
31336
|
if (rel.includes("..")) continue;
|
|
31054
31337
|
try {
|
|
@@ -31062,7 +31345,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
31062
31345
|
);
|
|
31063
31346
|
if (!patchContent.trim()) continue;
|
|
31064
31347
|
const displayPath = multiRepo ? `${slug}/${rel}` : rel;
|
|
31065
|
-
const absFile =
|
|
31348
|
+
const absFile = path7.join(repo.path, rel);
|
|
31066
31349
|
const newText = await readWorkspaceFileAsUtf8(absFile);
|
|
31067
31350
|
sendSessionUpdate({
|
|
31068
31351
|
type: "session_file_change",
|
|
@@ -31081,6 +31364,498 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
31081
31364
|
}
|
|
31082
31365
|
}
|
|
31083
31366
|
|
|
31367
|
+
// ../types/dist/index.js
|
|
31368
|
+
init_zod();
|
|
31369
|
+
init_zod();
|
|
31370
|
+
init_zod();
|
|
31371
|
+
init_zod();
|
|
31372
|
+
init_zod();
|
|
31373
|
+
init_zod();
|
|
31374
|
+
init_zod();
|
|
31375
|
+
init_zod();
|
|
31376
|
+
init_zod();
|
|
31377
|
+
init_zod();
|
|
31378
|
+
init_zod();
|
|
31379
|
+
init_zod();
|
|
31380
|
+
var WorkItemStatusSchema = external_exports.enum(["backlog", "in-progress", "completed"]);
|
|
31381
|
+
var WorkItemProgressSchema = external_exports.object({
|
|
31382
|
+
remainingCriteria: external_exports.array(external_exports.string()).default([]),
|
|
31383
|
+
openQuestions: external_exports.array(external_exports.string()).default([]),
|
|
31384
|
+
assignedTo: external_exports.enum(["agent", "human-product", "human-expert"]).optional()
|
|
31385
|
+
});
|
|
31386
|
+
var ChangeSchema = external_exports.object({
|
|
31387
|
+
id: external_exports.string(),
|
|
31388
|
+
description: external_exports.string(),
|
|
31389
|
+
buildingBlockId: external_exports.string(),
|
|
31390
|
+
buildingBlockType: external_exports.enum(["function", "workflow", "connector", "ui-component", "app-fragment", "application", "project"]),
|
|
31391
|
+
action: external_exports.enum(["create", "update", "split", "combine"])
|
|
31392
|
+
});
|
|
31393
|
+
var CompletionCriterionSchema = external_exports.object({
|
|
31394
|
+
id: external_exports.string(),
|
|
31395
|
+
description: external_exports.string(),
|
|
31396
|
+
type: external_exports.enum(["write-code", "write-tests", "verify-tests", "other"]),
|
|
31397
|
+
verified: external_exports.boolean().default(false)
|
|
31398
|
+
});
|
|
31399
|
+
var WorkItemPrioritySchema = external_exports.enum(["low", "medium", "high", "critical"]);
|
|
31400
|
+
var IterationPhaseSchema = external_exports.enum(["analysis", "implementation", "verify", "reprioritize", "completed"]);
|
|
31401
|
+
var WorkItemDependencySchema = external_exports.object({
|
|
31402
|
+
type: external_exports.enum(["work-item"]),
|
|
31403
|
+
id: external_exports.string()
|
|
31404
|
+
});
|
|
31405
|
+
var WorkItemSchema = external_exports.object({
|
|
31406
|
+
id: external_exports.string(),
|
|
31407
|
+
sessionId: external_exports.string().optional(),
|
|
31408
|
+
summary: external_exports.string().optional(),
|
|
31409
|
+
description: external_exports.string(),
|
|
31410
|
+
status: WorkItemStatusSchema,
|
|
31411
|
+
buildingBlockId: external_exports.string().optional(),
|
|
31412
|
+
buildingBlockType: external_exports.enum(["function", "workflow", "connector", "ui-component", "app-fragment", "application", "project"]),
|
|
31413
|
+
changes: external_exports.array(ChangeSchema).default([]),
|
|
31414
|
+
completionCriteria: external_exports.array(CompletionCriterionSchema).default([]),
|
|
31415
|
+
priority: WorkItemPrioritySchema.default("medium"),
|
|
31416
|
+
dependencies: external_exports.array(WorkItemDependencySchema).default([]),
|
|
31417
|
+
assignedToUserId: external_exports.string().optional()
|
|
31418
|
+
});
|
|
31419
|
+
var UserWorkspaceProfileSchema = external_exports.object({
|
|
31420
|
+
id: external_exports.string(),
|
|
31421
|
+
workspaceId: external_exports.string(),
|
|
31422
|
+
userId: external_exports.string(),
|
|
31423
|
+
roleDescription: external_exports.string().optional(),
|
|
31424
|
+
expertiseAreas: external_exports.array(external_exports.string()),
|
|
31425
|
+
preferences: external_exports.record(external_exports.unknown()).optional(),
|
|
31426
|
+
learnings: external_exports.array(external_exports.string())
|
|
31427
|
+
});
|
|
31428
|
+
var WorkspaceOwnerInfoSchema = external_exports.object({
|
|
31429
|
+
ownerId: external_exports.string(),
|
|
31430
|
+
ownerName: external_exports.string().optional(),
|
|
31431
|
+
ownerEmail: external_exports.string().optional(),
|
|
31432
|
+
ownerProfilePictureUrl: external_exports.string().optional()
|
|
31433
|
+
});
|
|
31434
|
+
var WorkspaceRuntimeEntrySchema = external_exports.object({
|
|
31435
|
+
workspaceId: external_exports.string(),
|
|
31436
|
+
path: external_exports.string(),
|
|
31437
|
+
name: external_exports.string().optional(),
|
|
31438
|
+
owner: WorkspaceOwnerInfoSchema.optional(),
|
|
31439
|
+
isOwner: external_exports.boolean().optional()
|
|
31440
|
+
});
|
|
31441
|
+
var ProjectContextSchema = external_exports.object({
|
|
31442
|
+
projectId: external_exports.string(),
|
|
31443
|
+
context: external_exports.record(external_exports.unknown()).default({}),
|
|
31444
|
+
updatedAt: external_exports.string()
|
|
31445
|
+
});
|
|
31446
|
+
var WebSocketMessageTypeSchema = external_exports.enum([
|
|
31447
|
+
"plan-update",
|
|
31448
|
+
"work-item-update",
|
|
31449
|
+
"work-item-added",
|
|
31450
|
+
"work-item-removed",
|
|
31451
|
+
"project-processing-start",
|
|
31452
|
+
"project-processing-update",
|
|
31453
|
+
"project-processing-complete",
|
|
31454
|
+
"project-processing-error",
|
|
31455
|
+
"file-tool-request",
|
|
31456
|
+
"file-tool-response",
|
|
31457
|
+
"file-generated"
|
|
31458
|
+
]);
|
|
31459
|
+
var WebSocketMessageSchema = external_exports.object({
|
|
31460
|
+
type: WebSocketMessageTypeSchema,
|
|
31461
|
+
contextId: external_exports.string().optional(),
|
|
31462
|
+
data: external_exports.any().optional(),
|
|
31463
|
+
error: external_exports.string().optional()
|
|
31464
|
+
});
|
|
31465
|
+
var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
|
|
31466
|
+
var CheckpointSummarySchema = external_exports.object({
|
|
31467
|
+
id: external_exports.string(),
|
|
31468
|
+
kind: CheckpointKindSchema,
|
|
31469
|
+
/** ISO date for daily (YYYY-MM-DD), ISO week for weekly, null for overall */
|
|
31470
|
+
periodKey: external_exports.string().nullable(),
|
|
31471
|
+
summary: external_exports.string(),
|
|
31472
|
+
createdAt: external_exports.string(),
|
|
31473
|
+
updatedAt: external_exports.string()
|
|
31474
|
+
});
|
|
31475
|
+
var ThreadMetaSchema = external_exports.object({
|
|
31476
|
+
threadId: external_exports.string(),
|
|
31477
|
+
workspaceId: external_exports.string(),
|
|
31478
|
+
/** External source (e.g. slack, discord); null if internal-only */
|
|
31479
|
+
externalSource: external_exports.string().nullable(),
|
|
31480
|
+
/** Id in the external system (e.g. channel_id + thread_ts) */
|
|
31481
|
+
externalId: external_exports.string().nullable(),
|
|
31482
|
+
title: external_exports.string().optional(),
|
|
31483
|
+
createdAt: external_exports.string(),
|
|
31484
|
+
updatedAt: external_exports.string()
|
|
31485
|
+
});
|
|
31486
|
+
var ThreadMessageSchema = external_exports.object({
|
|
31487
|
+
messageId: external_exports.string(),
|
|
31488
|
+
threadId: external_exports.string(),
|
|
31489
|
+
/** Role: user, assistant, system */
|
|
31490
|
+
role: external_exports.enum(["user", "assistant", "system"]),
|
|
31491
|
+
content: external_exports.string(),
|
|
31492
|
+
/** Optional reference to a ContentItem (e.g. doc, Notion page) */
|
|
31493
|
+
contentItemId: external_exports.string().nullable(),
|
|
31494
|
+
/** External message id if synced from external chat */
|
|
31495
|
+
externalId: external_exports.string().nullable(),
|
|
31496
|
+
createdAt: external_exports.string(),
|
|
31497
|
+
updatedAt: external_exports.string()
|
|
31498
|
+
});
|
|
31499
|
+
var ThreadCheckpointSummarySchema = CheckpointSummarySchema.extend({
|
|
31500
|
+
threadId: external_exports.string()
|
|
31501
|
+
});
|
|
31502
|
+
var ContentSourceSchema = external_exports.enum(["notion", "doc", "slack_thread", "other"]);
|
|
31503
|
+
var ContentItemMetaSchema = external_exports.object({
|
|
31504
|
+
contentId: external_exports.string(),
|
|
31505
|
+
workspaceId: external_exports.string(),
|
|
31506
|
+
source: ContentSourceSchema,
|
|
31507
|
+
/** Id in the external system (e.g. Notion page id, doc url) */
|
|
31508
|
+
externalId: external_exports.string(),
|
|
31509
|
+
/** If source is slack_thread, points to Thread DO id */
|
|
31510
|
+
threadId: external_exports.string().nullable(),
|
|
31511
|
+
title: external_exports.string().optional(),
|
|
31512
|
+
createdAt: external_exports.string(),
|
|
31513
|
+
updatedAt: external_exports.string()
|
|
31514
|
+
});
|
|
31515
|
+
var ContentStorageRefSchema = external_exports.object({
|
|
31516
|
+
storageKey: external_exports.string(),
|
|
31517
|
+
/** Optional: mime type or format hint */
|
|
31518
|
+
contentType: external_exports.string().optional()
|
|
31519
|
+
});
|
|
31520
|
+
var ContentCheckpointSummarySchema = CheckpointSummarySchema.extend({
|
|
31521
|
+
contentId: external_exports.string()
|
|
31522
|
+
});
|
|
31523
|
+
var StoryMetaSchema = external_exports.object({
|
|
31524
|
+
storyId: external_exports.string(),
|
|
31525
|
+
workspaceId: external_exports.string(),
|
|
31526
|
+
title: external_exports.string(),
|
|
31527
|
+
/** feature | bug | epic */
|
|
31528
|
+
kind: external_exports.enum(["feature", "bug", "epic"]).default("feature"),
|
|
31529
|
+
createdAt: external_exports.string(),
|
|
31530
|
+
updatedAt: external_exports.string()
|
|
31531
|
+
});
|
|
31532
|
+
var StoryContentItemRefSchema = external_exports.object({
|
|
31533
|
+
id: external_exports.string(),
|
|
31534
|
+
storyId: external_exports.string(),
|
|
31535
|
+
contentItemId: external_exports.string(),
|
|
31536
|
+
/** Snapshot summary when added to story (or updated) */
|
|
31537
|
+
summary: external_exports.string(),
|
|
31538
|
+
orderIndex: external_exports.number().default(0),
|
|
31539
|
+
createdAt: external_exports.string(),
|
|
31540
|
+
updatedAt: external_exports.string()
|
|
31541
|
+
});
|
|
31542
|
+
var StoryCheckpointSummarySchema = CheckpointSummarySchema.extend({
|
|
31543
|
+
storyId: external_exports.string()
|
|
31544
|
+
});
|
|
31545
|
+
var BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID = "__builtin_change_summary__";
|
|
31546
|
+
var SessionMetaSchema = external_exports.object({
|
|
31547
|
+
sessionId: external_exports.string(),
|
|
31548
|
+
workspaceId: external_exports.string(),
|
|
31549
|
+
title: external_exports.string().optional(),
|
|
31550
|
+
createdAt: external_exports.string(),
|
|
31551
|
+
updatedAt: external_exports.string()
|
|
31552
|
+
});
|
|
31553
|
+
var SessionPromptSchema = external_exports.object({
|
|
31554
|
+
id: external_exports.string(),
|
|
31555
|
+
sessionId: external_exports.string(),
|
|
31556
|
+
/** text | resource */
|
|
31557
|
+
type: external_exports.enum(["text", "resource"]).default("text"),
|
|
31558
|
+
text: external_exports.string().optional(),
|
|
31559
|
+
resourceUri: external_exports.string().optional(),
|
|
31560
|
+
createdAt: external_exports.string()
|
|
31561
|
+
});
|
|
31562
|
+
var SessionResponseSchema = external_exports.object({
|
|
31563
|
+
id: external_exports.string(),
|
|
31564
|
+
sessionId: external_exports.string(),
|
|
31565
|
+
promptId: external_exports.string(),
|
|
31566
|
+
/** message | completion */
|
|
31567
|
+
kind: external_exports.enum(["message", "completion"]),
|
|
31568
|
+
content: external_exports.string().optional(),
|
|
31569
|
+
/** For completion: stopReason etc. */
|
|
31570
|
+
stopReason: external_exports.string().optional(),
|
|
31571
|
+
createdAt: external_exports.string()
|
|
31572
|
+
});
|
|
31573
|
+
var SessionToolCallSchema = external_exports.object({
|
|
31574
|
+
id: external_exports.string(),
|
|
31575
|
+
sessionId: external_exports.string(),
|
|
31576
|
+
promptId: external_exports.string(),
|
|
31577
|
+
name: external_exports.string(),
|
|
31578
|
+
params: external_exports.record(external_exports.unknown()).optional(),
|
|
31579
|
+
result: external_exports.record(external_exports.unknown()).optional(),
|
|
31580
|
+
createdAt: external_exports.string()
|
|
31581
|
+
});
|
|
31582
|
+
var SessionThreadRefSchema = external_exports.object({
|
|
31583
|
+
sessionId: external_exports.string(),
|
|
31584
|
+
threadId: external_exports.string(),
|
|
31585
|
+
addedAt: external_exports.string()
|
|
31586
|
+
});
|
|
31587
|
+
function normalizeRepoRelativePath(p) {
|
|
31588
|
+
let t = p.trim().replace(/\\/g, "/");
|
|
31589
|
+
while (t.startsWith("./")) t = t.slice(2);
|
|
31590
|
+
return t.replace(/\/+/g, "/");
|
|
31591
|
+
}
|
|
31592
|
+
function resolveChangeSummaryPathAgainstAllowed(rawPath, allowed) {
|
|
31593
|
+
const trimmed2 = rawPath.trim();
|
|
31594
|
+
if (!trimmed2) return null;
|
|
31595
|
+
if (allowed.has(trimmed2)) return trimmed2;
|
|
31596
|
+
const n = normalizeRepoRelativePath(trimmed2);
|
|
31597
|
+
if (allowed.has(n)) return n;
|
|
31598
|
+
for (const a of allowed) {
|
|
31599
|
+
if (normalizeRepoRelativePath(a) === n) return a;
|
|
31600
|
+
}
|
|
31601
|
+
return null;
|
|
31602
|
+
}
|
|
31603
|
+
function clampSummaryToAtMostTwoLines(summary) {
|
|
31604
|
+
const lines = summary.split(/\r?\n/).map((l) => l.trim()).filter((l) => l.length > 0);
|
|
31605
|
+
return lines.slice(0, 2).join("\n");
|
|
31606
|
+
}
|
|
31607
|
+
function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
31608
|
+
if (raw == null || raw.trim() === "") return [];
|
|
31609
|
+
let text = raw.trim();
|
|
31610
|
+
const fence = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
31611
|
+
if (fence?.[1]) text = fence[1].trim();
|
|
31612
|
+
let parsed;
|
|
31613
|
+
try {
|
|
31614
|
+
parsed = JSON.parse(text);
|
|
31615
|
+
} catch {
|
|
31616
|
+
const start = text.indexOf("[");
|
|
31617
|
+
const end = text.lastIndexOf("]");
|
|
31618
|
+
if (start < 0 || end <= start) return [];
|
|
31619
|
+
try {
|
|
31620
|
+
parsed = JSON.parse(text.slice(start, end + 1));
|
|
31621
|
+
} catch {
|
|
31622
|
+
return [];
|
|
31623
|
+
}
|
|
31624
|
+
}
|
|
31625
|
+
const rows = [];
|
|
31626
|
+
let arr = [];
|
|
31627
|
+
if (Array.isArray(parsed)) {
|
|
31628
|
+
arr = parsed;
|
|
31629
|
+
} else if (parsed && typeof parsed === "object" && Array.isArray(parsed.files)) {
|
|
31630
|
+
arr = parsed.files;
|
|
31631
|
+
}
|
|
31632
|
+
const skip = options?.skipPathAllowlist === true;
|
|
31633
|
+
for (const item of arr) {
|
|
31634
|
+
if (!item || typeof item !== "object") continue;
|
|
31635
|
+
const o = item;
|
|
31636
|
+
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
31637
|
+
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
31638
|
+
if (!rawPath || !summary) continue;
|
|
31639
|
+
const path34 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
31640
|
+
if (!path34) continue;
|
|
31641
|
+
rows.push({ path: path34, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
31642
|
+
}
|
|
31643
|
+
return rows;
|
|
31644
|
+
}
|
|
31645
|
+
var PATCH_PREVIEW_MAX = 12e3;
|
|
31646
|
+
function clip(s, max) {
|
|
31647
|
+
if (s.length <= max) return s;
|
|
31648
|
+
return `${s.slice(0, max)}
|
|
31649
|
+
|
|
31650
|
+
\u2026(truncated, ${s.length - max} more characters)`;
|
|
31651
|
+
}
|
|
31652
|
+
function buildSessionChangeSummaryPrompt(files) {
|
|
31653
|
+
const lines = [
|
|
31654
|
+
"You are the same agent that produced the changes below. Summarize **your own** edits so a reader can scan them quickly.",
|
|
31655
|
+
"",
|
|
31656
|
+
"Write in second person (you / your): what you changed in each path and why it matters.",
|
|
31657
|
+
"",
|
|
31658
|
+
"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.",
|
|
31659
|
+
"",
|
|
31660
|
+
"## How to format your reply (machine parsing)",
|
|
31661
|
+
"",
|
|
31662
|
+
"- 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.",
|
|
31663
|
+
"- Inside that fence: **nothing except** one valid JSON value \u2014 the array described below. No trailing commentary inside the fence.",
|
|
31664
|
+
"- **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.",
|
|
31665
|
+
"- If you add optional plain English before the fence (e.g. one short sentence), keep it **separate**: end that sentence, blank line, then ```json.",
|
|
31666
|
+
'- In each `"summary"` string, avoid raw double-quote characters, or escape them as `\\"` so the JSON parses.',
|
|
31667
|
+
"",
|
|
31668
|
+
"JSON shape **inside the fence** (array only):",
|
|
31669
|
+
'[{"path":"<file path exactly as given>","summary":"<one line, or two short lines separated by \\n>"}]',
|
|
31670
|
+
"",
|
|
31671
|
+
"Rules:",
|
|
31672
|
+
"- Include **exactly one** object per file path listed below (same path strings).",
|
|
31673
|
+
"- If a path is a removed directory, state briefly what you removed.",
|
|
31674
|
+
"- Do not invent paths; use only the paths provided.",
|
|
31675
|
+
"",
|
|
31676
|
+
"## Files you changed",
|
|
31677
|
+
""
|
|
31678
|
+
];
|
|
31679
|
+
for (const f of files) {
|
|
31680
|
+
lines.push(`### ${f.path}`);
|
|
31681
|
+
if (f.directoryRemoved) {
|
|
31682
|
+
lines.push("(directory removed)");
|
|
31683
|
+
lines.push("");
|
|
31684
|
+
continue;
|
|
31685
|
+
}
|
|
31686
|
+
if (f.patchContent && f.patchContent.trim() !== "") {
|
|
31687
|
+
lines.push("```diff");
|
|
31688
|
+
lines.push(clip(f.patchContent.trim(), PATCH_PREVIEW_MAX));
|
|
31689
|
+
lines.push("```");
|
|
31690
|
+
} else if (f.oldText != null || f.newText != null) {
|
|
31691
|
+
const oldT = (f.oldText ?? "").trim();
|
|
31692
|
+
const newT = (f.newText ?? "").trim();
|
|
31693
|
+
lines.push("Previous snippet:", clip(oldT, 6e3));
|
|
31694
|
+
lines.push("New snippet:", clip(newT, 6e3));
|
|
31695
|
+
} else {
|
|
31696
|
+
lines.push("(no diff body stored for this path)");
|
|
31697
|
+
}
|
|
31698
|
+
lines.push("");
|
|
31699
|
+
}
|
|
31700
|
+
return lines.join("\n");
|
|
31701
|
+
}
|
|
31702
|
+
function defaultRichness(c) {
|
|
31703
|
+
const patch = typeof c.patchContent === "string" ? c.patchContent.length : 0;
|
|
31704
|
+
const nt = typeof c.newText === "string" ? c.newText.length : 0;
|
|
31705
|
+
const ot = typeof c.oldText === "string" ? c.oldText.length : 0;
|
|
31706
|
+
const dir = c.directoryRemoved === true ? 8 : 0;
|
|
31707
|
+
return (patch > 0 ? 4 : 0) + (nt > 0 ? 2 : 0) + (ot > 0 ? 1 : 0) + dir;
|
|
31708
|
+
}
|
|
31709
|
+
function dedupeSessionFileChangesByPath(items, richness = (item) => defaultRichness(item)) {
|
|
31710
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
31711
|
+
for (const item of items) {
|
|
31712
|
+
const p = typeof item.path === "string" ? item.path.trim() : "";
|
|
31713
|
+
if (!p) continue;
|
|
31714
|
+
const prev = byPath.get(p);
|
|
31715
|
+
if (!prev || richness(item) >= richness(prev)) byPath.set(p, item);
|
|
31716
|
+
}
|
|
31717
|
+
return Array.from(byPath.entries()).sort(([a], [b]) => a.localeCompare(b)).map(([, v]) => v);
|
|
31718
|
+
}
|
|
31719
|
+
var ArtifactMetaSchema = external_exports.object({
|
|
31720
|
+
artifactId: external_exports.string(),
|
|
31721
|
+
workspaceId: external_exports.string(),
|
|
31722
|
+
/** Slug for permalink: /workspaces/:wid/artifacts/:slug */
|
|
31723
|
+
permalinkSlug: external_exports.string(),
|
|
31724
|
+
title: external_exports.string(),
|
|
31725
|
+
/** e.g. summary_report, build_log */
|
|
31726
|
+
type: external_exports.string().default("report"),
|
|
31727
|
+
/** Optional session that produced this artifact */
|
|
31728
|
+
sessionId: external_exports.string().nullable(),
|
|
31729
|
+
createdAt: external_exports.string(),
|
|
31730
|
+
updatedAt: external_exports.string()
|
|
31731
|
+
});
|
|
31732
|
+
var TemplateMetaSchema = external_exports.object({
|
|
31733
|
+
templateId: external_exports.string(),
|
|
31734
|
+
workspaceId: external_exports.string(),
|
|
31735
|
+
name: external_exports.string(),
|
|
31736
|
+
/** e.g. summary_report, build_log */
|
|
31737
|
+
artifactType: external_exports.string().optional(),
|
|
31738
|
+
createdAt: external_exports.string(),
|
|
31739
|
+
updatedAt: external_exports.string()
|
|
31740
|
+
});
|
|
31741
|
+
var GitRepoMetaSchema = external_exports.object({
|
|
31742
|
+
/** Stable id for the repo (e.g. hash of normalized canonical URL). Used for DO idFromName. */
|
|
31743
|
+
repoId: external_exports.string(),
|
|
31744
|
+
/** Canonical external URL (e.g. https://github.com/org/repo). Normalize before storing. */
|
|
31745
|
+
canonicalUrl: external_exports.string().url(),
|
|
31746
|
+
/** Optional workspace this repo was first linked in. */
|
|
31747
|
+
workspaceId: external_exports.string().nullable(),
|
|
31748
|
+
displayName: external_exports.string().optional(),
|
|
31749
|
+
createdAt: external_exports.string(),
|
|
31750
|
+
updatedAt: external_exports.string()
|
|
31751
|
+
});
|
|
31752
|
+
|
|
31753
|
+
// src/agents/acp/put-summarize-change-summaries.ts
|
|
31754
|
+
async function putEncryptedChangeSummaryRows(params) {
|
|
31755
|
+
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
31756
|
+
const entries = params.rows.map(({ path: path34, summary }) => {
|
|
31757
|
+
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
31758
|
+
return { path: path34, summary: JSON.stringify(enc) };
|
|
31759
|
+
});
|
|
31760
|
+
const res = await fetch(
|
|
31761
|
+
`${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
31762
|
+
{
|
|
31763
|
+
method: "PUT",
|
|
31764
|
+
headers: {
|
|
31765
|
+
Authorization: `Bearer ${params.authToken}`,
|
|
31766
|
+
"Content-Type": "application/json"
|
|
31767
|
+
},
|
|
31768
|
+
body: JSON.stringify({ entries })
|
|
31769
|
+
}
|
|
31770
|
+
);
|
|
31771
|
+
if (!res.ok) {
|
|
31772
|
+
const t = await res.text();
|
|
31773
|
+
throw new Error(`PUT summarize-changes summaries failed ${res.status}: ${t.slice(0, 500)}`);
|
|
31774
|
+
}
|
|
31775
|
+
}
|
|
31776
|
+
|
|
31777
|
+
// src/agents/acp/maybe-upload-e2ee-session-change-summaries.ts
|
|
31778
|
+
async function maybeUploadE2eeSessionChangeSummariesAfterAgentSuccess(params) {
|
|
31779
|
+
const {
|
|
31780
|
+
sessionId,
|
|
31781
|
+
runId,
|
|
31782
|
+
resultSuccess,
|
|
31783
|
+
output,
|
|
31784
|
+
e2ee,
|
|
31785
|
+
cloudApiBaseUrl,
|
|
31786
|
+
getCloudAccessToken,
|
|
31787
|
+
followUpCatalogPromptId,
|
|
31788
|
+
sessionChangeSummaryFilePaths,
|
|
31789
|
+
log: log2
|
|
31790
|
+
} = params;
|
|
31791
|
+
const outputStr = typeof output === "string" ? output : "";
|
|
31792
|
+
if (!sessionId) {
|
|
31793
|
+
return;
|
|
31794
|
+
}
|
|
31795
|
+
if (!runId) {
|
|
31796
|
+
return;
|
|
31797
|
+
}
|
|
31798
|
+
if (!resultSuccess) {
|
|
31799
|
+
return;
|
|
31800
|
+
}
|
|
31801
|
+
if (!e2ee) {
|
|
31802
|
+
return;
|
|
31803
|
+
}
|
|
31804
|
+
if (!cloudApiBaseUrl) {
|
|
31805
|
+
return;
|
|
31806
|
+
}
|
|
31807
|
+
if (!getCloudAccessToken) {
|
|
31808
|
+
return;
|
|
31809
|
+
}
|
|
31810
|
+
if (followUpCatalogPromptId !== BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID) {
|
|
31811
|
+
return;
|
|
31812
|
+
}
|
|
31813
|
+
if (!sessionChangeSummaryFilePaths || sessionChangeSummaryFilePaths.length === 0) {
|
|
31814
|
+
return;
|
|
31815
|
+
}
|
|
31816
|
+
if (outputStr.trim() === "") {
|
|
31817
|
+
return;
|
|
31818
|
+
}
|
|
31819
|
+
const allowed = /* @__PURE__ */ new Set();
|
|
31820
|
+
for (const p of sessionChangeSummaryFilePaths) {
|
|
31821
|
+
const t = p.trim();
|
|
31822
|
+
if (!t) continue;
|
|
31823
|
+
allowed.add(t);
|
|
31824
|
+
allowed.add(normalizeRepoRelativePath(t));
|
|
31825
|
+
}
|
|
31826
|
+
const rows = parseChangeSummaryJson(outputStr, allowed);
|
|
31827
|
+
if (rows.length === 0) {
|
|
31828
|
+
return;
|
|
31829
|
+
}
|
|
31830
|
+
const token = getCloudAccessToken();
|
|
31831
|
+
if (!token) {
|
|
31832
|
+
return;
|
|
31833
|
+
}
|
|
31834
|
+
try {
|
|
31835
|
+
await putEncryptedChangeSummaryRows({
|
|
31836
|
+
apiBaseUrl: cloudApiBaseUrl,
|
|
31837
|
+
authToken: token,
|
|
31838
|
+
sessionId,
|
|
31839
|
+
e2ee,
|
|
31840
|
+
rows
|
|
31841
|
+
});
|
|
31842
|
+
} catch (uploadErr) {
|
|
31843
|
+
log2(
|
|
31844
|
+
`[Agent] Encrypted change summary upload failed: ${uploadErr instanceof Error ? uploadErr.message : String(uploadErr)}`
|
|
31845
|
+
);
|
|
31846
|
+
}
|
|
31847
|
+
}
|
|
31848
|
+
|
|
31849
|
+
// src/agents/acp/send-prompt-result-augment.ts
|
|
31850
|
+
function augmentPromptResultAuthFields(agentType, errorText) {
|
|
31851
|
+
const err = errorText ?? "";
|
|
31852
|
+
const at = agentType ?? null;
|
|
31853
|
+
const evaluated = Boolean(at && err.trim());
|
|
31854
|
+
const suggestsAuth = evaluated && at ? localAgentErrorSuggestsAuth(at, err) : false;
|
|
31855
|
+
if (!suggestsAuth || !agentType) return {};
|
|
31856
|
+
return { agentAuthRequired: true, agentType };
|
|
31857
|
+
}
|
|
31858
|
+
|
|
31084
31859
|
// src/agents/acp/send-prompt-to-agent.ts
|
|
31085
31860
|
async function sendPromptToAgent(options) {
|
|
31086
31861
|
const {
|
|
@@ -31093,16 +31868,13 @@ async function sendPromptToAgent(options) {
|
|
|
31093
31868
|
agentCwd,
|
|
31094
31869
|
sendResult: sendResult2,
|
|
31095
31870
|
sendSessionUpdate,
|
|
31096
|
-
log: log2
|
|
31871
|
+
log: log2,
|
|
31872
|
+
followUpCatalogPromptId,
|
|
31873
|
+
sessionChangeSummaryFilePaths,
|
|
31874
|
+
cloudApiBaseUrl,
|
|
31875
|
+
getCloudAccessToken,
|
|
31876
|
+
e2ee
|
|
31097
31877
|
} = options;
|
|
31098
|
-
function augmentAuthFields(errorText) {
|
|
31099
|
-
const err = errorText ?? "";
|
|
31100
|
-
const at = agentType ?? null;
|
|
31101
|
-
const evaluated = Boolean(at && err.trim());
|
|
31102
|
-
const suggestsAuth = evaluated && at ? localAgentErrorSuggestsAuth(at, err) : false;
|
|
31103
|
-
if (!suggestsAuth || !agentType) return {};
|
|
31104
|
-
return { agentAuthRequired: true, agentType };
|
|
31105
|
-
}
|
|
31106
31878
|
try {
|
|
31107
31879
|
const result = await handle.sendPrompt(promptText, {});
|
|
31108
31880
|
if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
|
|
@@ -31114,6 +31886,18 @@ async function sendPromptToAgent(options) {
|
|
|
31114
31886
|
log: log2
|
|
31115
31887
|
});
|
|
31116
31888
|
}
|
|
31889
|
+
await maybeUploadE2eeSessionChangeSummariesAfterAgentSuccess({
|
|
31890
|
+
sessionId,
|
|
31891
|
+
runId,
|
|
31892
|
+
resultSuccess: result.success === true,
|
|
31893
|
+
output: result.output,
|
|
31894
|
+
e2ee,
|
|
31895
|
+
cloudApiBaseUrl,
|
|
31896
|
+
getCloudAccessToken,
|
|
31897
|
+
followUpCatalogPromptId,
|
|
31898
|
+
sessionChangeSummaryFilePaths,
|
|
31899
|
+
log: log2
|
|
31900
|
+
});
|
|
31117
31901
|
const errStr = typeof result.error === "string" ? result.error : void 0;
|
|
31118
31902
|
sendResult2({
|
|
31119
31903
|
type: "prompt_result",
|
|
@@ -31121,7 +31905,8 @@ async function sendPromptToAgent(options) {
|
|
|
31121
31905
|
...sessionId ? { sessionId } : {},
|
|
31122
31906
|
...runId ? { runId } : {},
|
|
31123
31907
|
...result,
|
|
31124
|
-
...
|
|
31908
|
+
...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
|
|
31909
|
+
...augmentPromptResultAuthFields(agentType, errStr)
|
|
31125
31910
|
});
|
|
31126
31911
|
if (!result.success) {
|
|
31127
31912
|
log2(
|
|
@@ -31138,14 +31923,15 @@ async function sendPromptToAgent(options) {
|
|
|
31138
31923
|
...runId ? { runId } : {},
|
|
31139
31924
|
success: false,
|
|
31140
31925
|
error: errMsg,
|
|
31141
|
-
...
|
|
31926
|
+
...followUpCatalogPromptId != null && followUpCatalogPromptId !== "" ? { followUpCatalogPromptId } : {},
|
|
31927
|
+
...augmentPromptResultAuthFields(agentType, errMsg)
|
|
31142
31928
|
});
|
|
31143
31929
|
}
|
|
31144
31930
|
}
|
|
31145
31931
|
|
|
31146
31932
|
// src/agents/acp/ensure-acp-client.ts
|
|
31147
|
-
import * as
|
|
31148
|
-
import * as
|
|
31933
|
+
import * as fs10 from "node:fs";
|
|
31934
|
+
import * as path11 from "node:path";
|
|
31149
31935
|
|
|
31150
31936
|
// src/error-message.ts
|
|
31151
31937
|
function errorMessage(err) {
|
|
@@ -31234,21 +32020,21 @@ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
|
|
|
31234
32020
|
}
|
|
31235
32021
|
|
|
31236
32022
|
// src/agents/acp/safe-fs-path.ts
|
|
31237
|
-
import * as
|
|
32023
|
+
import * as path8 from "node:path";
|
|
31238
32024
|
function resolveSafePathUnderCwd(cwd, filePath) {
|
|
31239
32025
|
const trimmed2 = filePath.trim();
|
|
31240
32026
|
if (!trimmed2) return null;
|
|
31241
|
-
const normalizedCwd =
|
|
31242
|
-
const resolved =
|
|
31243
|
-
const rel =
|
|
31244
|
-
if (rel.startsWith("..") ||
|
|
32027
|
+
const normalizedCwd = path8.resolve(cwd);
|
|
32028
|
+
const resolved = path8.isAbsolute(trimmed2) ? path8.normalize(trimmed2) : path8.resolve(normalizedCwd, trimmed2);
|
|
32029
|
+
const rel = path8.relative(normalizedCwd, resolved);
|
|
32030
|
+
if (rel.startsWith("..") || path8.isAbsolute(rel)) return null;
|
|
31245
32031
|
return resolved;
|
|
31246
32032
|
}
|
|
31247
32033
|
function toDisplayPathRelativeToCwd(cwd, absolutePath) {
|
|
31248
|
-
const normalizedCwd =
|
|
31249
|
-
const rel =
|
|
31250
|
-
if (!rel || rel === "") return
|
|
31251
|
-
return rel.split(
|
|
32034
|
+
const normalizedCwd = path8.resolve(cwd);
|
|
32035
|
+
const rel = path8.relative(normalizedCwd, path8.resolve(absolutePath));
|
|
32036
|
+
if (!rel || rel === "") return path8.basename(absolutePath);
|
|
32037
|
+
return rel.split(path8.sep).join("/");
|
|
31252
32038
|
}
|
|
31253
32039
|
|
|
31254
32040
|
// src/agents/acp/clients/agent-stderr-capture.ts
|
|
@@ -31368,7 +32154,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
31368
32154
|
child.once("close", (code, signal) => {
|
|
31369
32155
|
onAgentSubprocessExit?.({ code, signal });
|
|
31370
32156
|
});
|
|
31371
|
-
return new Promise((
|
|
32157
|
+
return new Promise((resolve17, reject) => {
|
|
31372
32158
|
let initSettled = false;
|
|
31373
32159
|
const settleReject = (err) => {
|
|
31374
32160
|
if (initSettled) return;
|
|
@@ -31382,7 +32168,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
31382
32168
|
const settleResolve = (handle) => {
|
|
31383
32169
|
if (initSettled) return;
|
|
31384
32170
|
initSettled = true;
|
|
31385
|
-
|
|
32171
|
+
resolve17(handle);
|
|
31386
32172
|
};
|
|
31387
32173
|
child.on("error", (err) => {
|
|
31388
32174
|
settleReject(new Error(formatSpawnError(err, command[0])));
|
|
@@ -31418,8 +32204,8 @@ async function createSdkStdioAcpClient(options) {
|
|
|
31418
32204
|
});
|
|
31419
32205
|
} catch {
|
|
31420
32206
|
}
|
|
31421
|
-
return await new Promise((
|
|
31422
|
-
pendingPermissionResolvers.set(requestId,
|
|
32207
|
+
return await new Promise((resolve18) => {
|
|
32208
|
+
pendingPermissionResolvers.set(requestId, resolve18);
|
|
31423
32209
|
});
|
|
31424
32210
|
},
|
|
31425
32211
|
async readTextFile(params) {
|
|
@@ -31527,9 +32313,9 @@ async function createSdkStdioAcpClient(options) {
|
|
|
31527
32313
|
}
|
|
31528
32314
|
},
|
|
31529
32315
|
async cancel() {
|
|
31530
|
-
for (const [id,
|
|
32316
|
+
for (const [id, resolve18] of [...pendingPermissionResolvers.entries()]) {
|
|
31531
32317
|
pendingPermissionResolvers.delete(id);
|
|
31532
|
-
|
|
32318
|
+
resolve18({ outcome: { outcome: "cancelled" } });
|
|
31533
32319
|
}
|
|
31534
32320
|
try {
|
|
31535
32321
|
await connection.cancel({ sessionId });
|
|
@@ -31545,10 +32331,10 @@ async function createSdkStdioAcpClient(options) {
|
|
|
31545
32331
|
}
|
|
31546
32332
|
},
|
|
31547
32333
|
resolveRequest(requestId, result) {
|
|
31548
|
-
const
|
|
31549
|
-
if (!
|
|
32334
|
+
const resolve18 = pendingPermissionResolvers.get(requestId);
|
|
32335
|
+
if (!resolve18) return;
|
|
31550
32336
|
pendingPermissionResolvers.delete(requestId);
|
|
31551
|
-
|
|
32337
|
+
resolve18(result);
|
|
31552
32338
|
},
|
|
31553
32339
|
disconnect() {
|
|
31554
32340
|
child.kill();
|
|
@@ -31689,7 +32475,7 @@ async function createCursorAcpClient(options) {
|
|
|
31689
32475
|
onRequest,
|
|
31690
32476
|
onFileChange
|
|
31691
32477
|
} = options;
|
|
31692
|
-
const dbgFs = process.env.
|
|
32478
|
+
const dbgFs = process.env.BUILDAUTOMATON_DEBUG_ACP_FS === "1";
|
|
31693
32479
|
const isWindows = process.platform === "win32";
|
|
31694
32480
|
const child = spawn3(command[0], command.slice(1), {
|
|
31695
32481
|
cwd,
|
|
@@ -31699,7 +32485,7 @@ async function createCursorAcpClient(options) {
|
|
|
31699
32485
|
});
|
|
31700
32486
|
const stderrCapture = createStderrCapture(child);
|
|
31701
32487
|
child.stderr?.on("data", (chunk) => stderrCapture.append(chunk));
|
|
31702
|
-
return new Promise((
|
|
32488
|
+
return new Promise((resolve17, reject) => {
|
|
31703
32489
|
child.on("error", (err) => {
|
|
31704
32490
|
child.kill();
|
|
31705
32491
|
reject(new Error(formatSpawnError2(err, command[0])));
|
|
@@ -31886,7 +32672,7 @@ async function createCursorAcpClient(options) {
|
|
|
31886
32672
|
const newResult = await send("session/new", { cwd, mcpServers: [] });
|
|
31887
32673
|
const sessionId = newResult?.sessionId ?? "";
|
|
31888
32674
|
if (!sessionId) throw new Error("Cursor ACP session/new did not return sessionId");
|
|
31889
|
-
|
|
32675
|
+
resolve17({
|
|
31890
32676
|
sessionId,
|
|
31891
32677
|
async sendPrompt(prompt, _options) {
|
|
31892
32678
|
promptOutputBuffer = "";
|
|
@@ -32077,16 +32863,16 @@ import { existsSync, statSync } from "node:fs";
|
|
|
32077
32863
|
|
|
32078
32864
|
// src/git/get-git-repo-root-sync.ts
|
|
32079
32865
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
32080
|
-
import * as
|
|
32866
|
+
import * as path9 from "node:path";
|
|
32081
32867
|
function getGitRepoRootSync(startDir) {
|
|
32082
32868
|
try {
|
|
32083
32869
|
const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
|
|
32084
|
-
cwd:
|
|
32870
|
+
cwd: path9.resolve(startDir),
|
|
32085
32871
|
encoding: "utf8",
|
|
32086
32872
|
stdio: ["ignore", "pipe", "ignore"],
|
|
32087
32873
|
maxBuffer: 1024 * 1024
|
|
32088
32874
|
}).trim();
|
|
32089
|
-
return out ?
|
|
32875
|
+
return out ? path9.resolve(out) : null;
|
|
32090
32876
|
} catch {
|
|
32091
32877
|
return null;
|
|
32092
32878
|
}
|
|
@@ -32095,25 +32881,25 @@ function getGitRepoRootSync(startDir) {
|
|
|
32095
32881
|
// src/agents/acp/workspace-files.ts
|
|
32096
32882
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
32097
32883
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
32098
|
-
import * as
|
|
32884
|
+
import * as path10 from "node:path";
|
|
32099
32885
|
function resolveWorkspaceFilePath(cwd, rawPath) {
|
|
32100
32886
|
const trimmed2 = rawPath.trim();
|
|
32101
32887
|
if (!trimmed2) return null;
|
|
32102
|
-
const normalizedCwd =
|
|
32888
|
+
const normalizedCwd = path10.resolve(cwd);
|
|
32103
32889
|
let abs = resolveSafePathUnderCwd(cwd, trimmed2);
|
|
32104
32890
|
if (!abs) {
|
|
32105
|
-
const candidate =
|
|
32891
|
+
const candidate = path10.isAbsolute(trimmed2) ? path10.normalize(trimmed2) : path10.normalize(path10.resolve(normalizedCwd, trimmed2));
|
|
32106
32892
|
const gitRoot2 = getGitRepoRootSync(cwd);
|
|
32107
32893
|
if (!gitRoot2) return null;
|
|
32108
|
-
const rel =
|
|
32109
|
-
if (rel.startsWith("..") ||
|
|
32894
|
+
const rel = path10.relative(gitRoot2, candidate);
|
|
32895
|
+
if (rel.startsWith("..") || path10.isAbsolute(rel)) return null;
|
|
32110
32896
|
abs = candidate;
|
|
32111
32897
|
}
|
|
32112
32898
|
const gitRoot = getGitRepoRootSync(cwd);
|
|
32113
32899
|
if (gitRoot) {
|
|
32114
|
-
const relFromRoot =
|
|
32115
|
-
if (!relFromRoot.startsWith("..") && !
|
|
32116
|
-
return { abs, display: relFromRoot.split(
|
|
32900
|
+
const relFromRoot = path10.relative(gitRoot, abs);
|
|
32901
|
+
if (!relFromRoot.startsWith("..") && !path10.isAbsolute(relFromRoot)) {
|
|
32902
|
+
return { abs, display: relFromRoot.split(path10.sep).join("/") };
|
|
32117
32903
|
}
|
|
32118
32904
|
}
|
|
32119
32905
|
return { abs, display: toDisplayPathRelativeToCwd(cwd, abs) };
|
|
@@ -32122,9 +32908,9 @@ function readUtf8WorkspaceFile(cwd, displayPath) {
|
|
|
32122
32908
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
32123
32909
|
const gitRoot = getGitRepoRootSync(cwd);
|
|
32124
32910
|
if (gitRoot) {
|
|
32125
|
-
const abs2 =
|
|
32126
|
-
const rel =
|
|
32127
|
-
if (!rel.startsWith("..") && !
|
|
32911
|
+
const abs2 = path10.resolve(gitRoot, displayPath);
|
|
32912
|
+
const rel = path10.relative(gitRoot, abs2);
|
|
32913
|
+
if (!rel.startsWith("..") && !path10.isAbsolute(rel)) {
|
|
32128
32914
|
try {
|
|
32129
32915
|
return readFileSync4(abs2, "utf8");
|
|
32130
32916
|
} catch {
|
|
@@ -32143,9 +32929,9 @@ function tryWorkspaceDisplayToAbs(cwd, displayPath) {
|
|
|
32143
32929
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
32144
32930
|
const gitRoot = getGitRepoRootSync(cwd);
|
|
32145
32931
|
if (gitRoot) {
|
|
32146
|
-
const abs =
|
|
32147
|
-
const rel =
|
|
32148
|
-
if (!rel.startsWith("..") && !
|
|
32932
|
+
const abs = path10.resolve(gitRoot, displayPath);
|
|
32933
|
+
const rel = path10.relative(gitRoot, abs);
|
|
32934
|
+
if (!rel.startsWith("..") && !path10.isAbsolute(rel)) return abs;
|
|
32149
32935
|
}
|
|
32150
32936
|
return resolveSafePathUnderCwd(cwd, displayPath);
|
|
32151
32937
|
}
|
|
@@ -32713,10 +33499,10 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
32713
33499
|
// src/agents/acp/ensure-acp-client.ts
|
|
32714
33500
|
async function ensureAcpClient(options) {
|
|
32715
33501
|
const { state, preferredAgentType, mode, cwd, routing, sendSessionUpdate, sendRequest, log: log2 } = options;
|
|
32716
|
-
const targetCwd =
|
|
33502
|
+
const targetCwd = path11.resolve(
|
|
32717
33503
|
cwd != null && String(cwd).trim() !== "" ? String(cwd).trim() : getBridgeWorkspaceDirectory()
|
|
32718
33504
|
);
|
|
32719
|
-
if (state.acpHandle && state.lastAcpCwd != null &&
|
|
33505
|
+
if (state.acpHandle && state.lastAcpCwd != null && path11.resolve(state.lastAcpCwd) !== path11.resolve(targetCwd)) {
|
|
32720
33506
|
try {
|
|
32721
33507
|
state.acpHandle.disconnect();
|
|
32722
33508
|
} catch {
|
|
@@ -32748,7 +33534,7 @@ async function ensureAcpClient(options) {
|
|
|
32748
33534
|
if (!state.acpStartPromise) {
|
|
32749
33535
|
let statOk = false;
|
|
32750
33536
|
try {
|
|
32751
|
-
const st =
|
|
33537
|
+
const st = fs10.statSync(targetCwd);
|
|
32752
33538
|
statOk = st.isDirectory();
|
|
32753
33539
|
if (!statOk) {
|
|
32754
33540
|
state.lastAcpStartError = `Agent cwd is not a directory: ${targetCwd}`;
|
|
@@ -32833,7 +33619,12 @@ async function createAcpManager(options) {
|
|
|
32833
33619
|
agentType,
|
|
32834
33620
|
cwd,
|
|
32835
33621
|
sendResult: sendResult2,
|
|
32836
|
-
sendSessionUpdate
|
|
33622
|
+
sendSessionUpdate,
|
|
33623
|
+
followUpCatalogPromptId,
|
|
33624
|
+
sessionChangeSummaryFilePaths,
|
|
33625
|
+
cloudApiBaseUrl,
|
|
33626
|
+
getCloudAccessToken,
|
|
33627
|
+
e2ee
|
|
32837
33628
|
} = opts;
|
|
32838
33629
|
const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
|
|
32839
33630
|
pendingCancelRunId = void 0;
|
|
@@ -32897,7 +33688,12 @@ async function createAcpManager(options) {
|
|
|
32897
33688
|
agentCwd: cwd,
|
|
32898
33689
|
sendResult: sendResult2,
|
|
32899
33690
|
sendSessionUpdate,
|
|
32900
|
-
log: log2
|
|
33691
|
+
log: log2,
|
|
33692
|
+
followUpCatalogPromptId,
|
|
33693
|
+
sessionChangeSummaryFilePaths,
|
|
33694
|
+
cloudApiBaseUrl,
|
|
33695
|
+
getCloudAccessToken,
|
|
33696
|
+
e2ee
|
|
32901
33697
|
});
|
|
32902
33698
|
}
|
|
32903
33699
|
void run().finally(() => {
|
|
@@ -32944,12 +33740,12 @@ async function createAcpManager(options) {
|
|
|
32944
33740
|
}
|
|
32945
33741
|
|
|
32946
33742
|
// src/worktrees/session-worktree-manager.ts
|
|
32947
|
-
import * as
|
|
33743
|
+
import * as path17 from "node:path";
|
|
32948
33744
|
import os4 from "node:os";
|
|
32949
33745
|
|
|
32950
33746
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
32951
|
-
import * as
|
|
32952
|
-
import * as
|
|
33747
|
+
import * as fs12 from "node:fs";
|
|
33748
|
+
import * as path13 from "node:path";
|
|
32953
33749
|
|
|
32954
33750
|
// src/git/worktree-add.ts
|
|
32955
33751
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
@@ -32958,12 +33754,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
|
32958
33754
|
}
|
|
32959
33755
|
|
|
32960
33756
|
// src/worktrees/worktree-layout-file.ts
|
|
32961
|
-
import * as
|
|
32962
|
-
import * as
|
|
33757
|
+
import * as fs11 from "node:fs";
|
|
33758
|
+
import * as path12 from "node:path";
|
|
32963
33759
|
import os3 from "node:os";
|
|
32964
33760
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
32965
33761
|
function defaultWorktreeLayoutPath() {
|
|
32966
|
-
return
|
|
33762
|
+
return path12.join(os3.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
32967
33763
|
}
|
|
32968
33764
|
function normalizeLoadedLayout(raw) {
|
|
32969
33765
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -32975,8 +33771,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
32975
33771
|
function loadWorktreeLayout() {
|
|
32976
33772
|
try {
|
|
32977
33773
|
const p = defaultWorktreeLayoutPath();
|
|
32978
|
-
if (!
|
|
32979
|
-
const raw = JSON.parse(
|
|
33774
|
+
if (!fs11.existsSync(p)) return { launcherCwds: [] };
|
|
33775
|
+
const raw = JSON.parse(fs11.readFileSync(p, "utf8"));
|
|
32980
33776
|
return normalizeLoadedLayout(raw);
|
|
32981
33777
|
} catch {
|
|
32982
33778
|
return { launcherCwds: [] };
|
|
@@ -32984,18 +33780,18 @@ function loadWorktreeLayout() {
|
|
|
32984
33780
|
}
|
|
32985
33781
|
function saveWorktreeLayout(layout) {
|
|
32986
33782
|
try {
|
|
32987
|
-
const dir =
|
|
32988
|
-
|
|
32989
|
-
|
|
33783
|
+
const dir = path12.dirname(defaultWorktreeLayoutPath());
|
|
33784
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
33785
|
+
fs11.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
32990
33786
|
} catch {
|
|
32991
33787
|
}
|
|
32992
33788
|
}
|
|
32993
33789
|
function baseNameSafe(abs) {
|
|
32994
|
-
return
|
|
33790
|
+
return path12.basename(abs).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
32995
33791
|
}
|
|
32996
33792
|
function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
|
|
32997
|
-
const norm =
|
|
32998
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
33793
|
+
const norm = path12.resolve(launcherCwdAbs);
|
|
33794
|
+
const existing = layout.launcherCwds.find((e) => path12.resolve(e.absolutePath) === norm);
|
|
32999
33795
|
if (existing) return existing.dirName;
|
|
33000
33796
|
const base = baseNameSafe(norm);
|
|
33001
33797
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
@@ -33013,9 +33809,9 @@ function allocateDirNameForLauncherCwd(layout, launcherCwdAbs) {
|
|
|
33013
33809
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
33014
33810
|
async function prepareNewSessionWorktrees(options) {
|
|
33015
33811
|
const { rootAbs, launcherCwd, sessionId, layout, log: log2 } = options;
|
|
33016
|
-
const launcherResolved =
|
|
33812
|
+
const launcherResolved = path13.resolve(launcherCwd);
|
|
33017
33813
|
const cwdKey = allocateDirNameForLauncherCwd(layout, launcherResolved);
|
|
33018
|
-
const agentMirrorRoot =
|
|
33814
|
+
const agentMirrorRoot = path13.join(rootAbs, cwdKey);
|
|
33019
33815
|
const repos = await discoverGitReposUnderRoot(launcherResolved);
|
|
33020
33816
|
if (repos.length === 0) {
|
|
33021
33817
|
log2("[worktrees] No Git repositories under launcher working directory; skipping worktree creation.");
|
|
@@ -33023,13 +33819,13 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
33023
33819
|
}
|
|
33024
33820
|
const branch = `session-${sessionId}`;
|
|
33025
33821
|
const worktreePaths = [];
|
|
33026
|
-
|
|
33822
|
+
fs12.mkdirSync(agentMirrorRoot, { recursive: true });
|
|
33027
33823
|
for (const repo of repos) {
|
|
33028
|
-
let rel =
|
|
33029
|
-
if (rel.startsWith("..") ||
|
|
33824
|
+
let rel = path13.relative(launcherResolved, repo.absolutePath);
|
|
33825
|
+
if (rel.startsWith("..") || path13.isAbsolute(rel)) continue;
|
|
33030
33826
|
const relNorm = rel === "" ? "." : rel;
|
|
33031
|
-
const wtPath =
|
|
33032
|
-
|
|
33827
|
+
const wtPath = path13.join(agentMirrorRoot, relNorm, sessionId);
|
|
33828
|
+
fs12.mkdirSync(path13.dirname(wtPath), { recursive: true });
|
|
33033
33829
|
try {
|
|
33034
33830
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
33035
33831
|
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}).`);
|
|
@@ -33066,23 +33862,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
33066
33862
|
}
|
|
33067
33863
|
|
|
33068
33864
|
// src/worktrees/remove-session-worktrees.ts
|
|
33069
|
-
import * as
|
|
33865
|
+
import * as fs15 from "node:fs";
|
|
33070
33866
|
|
|
33071
33867
|
// src/git/worktree-remove.ts
|
|
33072
|
-
import * as
|
|
33868
|
+
import * as fs14 from "node:fs";
|
|
33073
33869
|
|
|
33074
33870
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
33075
|
-
import * as
|
|
33076
|
-
import * as
|
|
33871
|
+
import * as fs13 from "node:fs";
|
|
33872
|
+
import * as path14 from "node:path";
|
|
33077
33873
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
33078
|
-
const gitDirFile =
|
|
33079
|
-
if (!
|
|
33080
|
-
const first2 =
|
|
33874
|
+
const gitDirFile = path14.join(wt, ".git");
|
|
33875
|
+
if (!fs13.existsSync(gitDirFile) || !fs13.statSync(gitDirFile).isFile()) return "";
|
|
33876
|
+
const first2 = fs13.readFileSync(gitDirFile, "utf8").trim();
|
|
33081
33877
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
33082
33878
|
if (!m) return "";
|
|
33083
|
-
const gitWorktreePath =
|
|
33084
|
-
const gitDir =
|
|
33085
|
-
return
|
|
33879
|
+
const gitWorktreePath = path14.resolve(wt, m[1].trim());
|
|
33880
|
+
const gitDir = path14.dirname(path14.dirname(gitWorktreePath));
|
|
33881
|
+
return path14.dirname(gitDir);
|
|
33086
33882
|
}
|
|
33087
33883
|
|
|
33088
33884
|
// src/git/worktree-remove.ts
|
|
@@ -33091,7 +33887,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
33091
33887
|
if (mainRepo) {
|
|
33092
33888
|
await simpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
33093
33889
|
} else {
|
|
33094
|
-
|
|
33890
|
+
fs14.rmSync(worktreePath, { recursive: true, force: true });
|
|
33095
33891
|
}
|
|
33096
33892
|
}
|
|
33097
33893
|
|
|
@@ -33104,7 +33900,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
33104
33900
|
} catch (e) {
|
|
33105
33901
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
33106
33902
|
try {
|
|
33107
|
-
|
|
33903
|
+
fs15.rmSync(wt, { recursive: true, force: true });
|
|
33108
33904
|
} catch {
|
|
33109
33905
|
}
|
|
33110
33906
|
}
|
|
@@ -33324,7 +34120,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
33324
34120
|
}
|
|
33325
34121
|
|
|
33326
34122
|
// src/git/working-directory/changes/get-working-tree-change-repo-details.ts
|
|
33327
|
-
import * as
|
|
34123
|
+
import * as path16 from "node:path";
|
|
33328
34124
|
|
|
33329
34125
|
// src/git/working-directory/changes/parse-git-status.ts
|
|
33330
34126
|
function parseNameStatusLines(lines) {
|
|
@@ -33444,8 +34240,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
33444
34240
|
}
|
|
33445
34241
|
|
|
33446
34242
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
33447
|
-
import * as
|
|
33448
|
-
import * as
|
|
34243
|
+
import * as fs17 from "node:fs";
|
|
34244
|
+
import * as path15 from "node:path";
|
|
33449
34245
|
|
|
33450
34246
|
// src/git/working-directory/changes/count-lines.ts
|
|
33451
34247
|
import { createReadStream } from "node:fs";
|
|
@@ -33469,7 +34265,7 @@ async function countTextFileLines(absFile) {
|
|
|
33469
34265
|
}
|
|
33470
34266
|
|
|
33471
34267
|
// src/git/working-directory/changes/hydrate-patch.ts
|
|
33472
|
-
import * as
|
|
34268
|
+
import * as fs16 from "node:fs";
|
|
33473
34269
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
33474
34270
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
33475
34271
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -33484,7 +34280,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
33484
34280
|
}
|
|
33485
34281
|
async function readWorktreeFileLines(abs) {
|
|
33486
34282
|
try {
|
|
33487
|
-
const raw = await
|
|
34283
|
+
const raw = await fs16.promises.readFile(abs, "utf8");
|
|
33488
34284
|
return raw.split(/\r?\n/);
|
|
33489
34285
|
} catch {
|
|
33490
34286
|
return null;
|
|
@@ -33619,7 +34415,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
33619
34415
|
const rows = [];
|
|
33620
34416
|
for (const pathInRepo of paths) {
|
|
33621
34417
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
33622
|
-
const abs =
|
|
34418
|
+
const abs = path15.join(repoGitCwd, pathInRepo);
|
|
33623
34419
|
const nums = numByPath.get(pathInRepo);
|
|
33624
34420
|
let additions = nums?.additions ?? 0;
|
|
33625
34421
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -33632,7 +34428,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
33632
34428
|
deletions = fromGit.deletions;
|
|
33633
34429
|
} else {
|
|
33634
34430
|
try {
|
|
33635
|
-
const st = await
|
|
34431
|
+
const st = await fs17.promises.stat(abs);
|
|
33636
34432
|
if (st.isFile()) additions = await countTextFileLines(abs);
|
|
33637
34433
|
else additions = 0;
|
|
33638
34434
|
} catch {
|
|
@@ -33658,7 +34454,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
33658
34454
|
} else {
|
|
33659
34455
|
pathInRepo = row.pathRelLauncher;
|
|
33660
34456
|
}
|
|
33661
|
-
const absFile =
|
|
34457
|
+
const absFile = path15.join(repoGitCwd, pathInRepo);
|
|
33662
34458
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
33663
34459
|
if (patch) {
|
|
33664
34460
|
patch = await hydrateUnifiedPatchWithFileContext(patch, absFile, repoGitCwd, pathInRepo, row.change);
|
|
@@ -33674,8 +34470,8 @@ function normRepoRel(p) {
|
|
|
33674
34470
|
return x === "" ? "." : x;
|
|
33675
34471
|
}
|
|
33676
34472
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
33677
|
-
const launcher =
|
|
33678
|
-
const mirror = options.agentMirrorRootAbs ?
|
|
34473
|
+
const launcher = path16.resolve(getBridgeWorkspaceDirectory());
|
|
34474
|
+
const mirror = options.agentMirrorRootAbs ? path16.resolve(options.agentMirrorRootAbs) : null;
|
|
33679
34475
|
const out = [];
|
|
33680
34476
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
33681
34477
|
const basisInput = options.basis ?? { kind: "working" };
|
|
@@ -33687,7 +34483,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
33687
34483
|
}
|
|
33688
34484
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
33689
34485
|
for (const target of options.commitTargetAbsDirs) {
|
|
33690
|
-
const t =
|
|
34486
|
+
const t = path16.resolve(target);
|
|
33691
34487
|
if (!await isGitRepoDirectory(t)) continue;
|
|
33692
34488
|
const g = simpleGit(t);
|
|
33693
34489
|
let branch = "HEAD";
|
|
@@ -33700,7 +34496,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
33700
34496
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
33701
34497
|
let repoRelPath;
|
|
33702
34498
|
if (mirror) {
|
|
33703
|
-
const relNorm =
|
|
34499
|
+
const relNorm = path16.relative(mirror, path16.dirname(t));
|
|
33704
34500
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
33705
34501
|
} else {
|
|
33706
34502
|
let top = t;
|
|
@@ -33709,8 +34505,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
33709
34505
|
} catch {
|
|
33710
34506
|
top = t;
|
|
33711
34507
|
}
|
|
33712
|
-
const rel =
|
|
33713
|
-
repoRelPath = rel.startsWith("..") ?
|
|
34508
|
+
const rel = path16.relative(launcher, path16.resolve(top)).replace(/\\/g, "/") || ".";
|
|
34509
|
+
repoRelPath = rel.startsWith("..") ? path16.basename(path16.resolve(top)) : rel;
|
|
33714
34510
|
}
|
|
33715
34511
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
33716
34512
|
if (filter && norm !== filter) continue;
|
|
@@ -33802,7 +34598,7 @@ var SessionWorktreeManager = class {
|
|
|
33802
34598
|
}
|
|
33803
34599
|
if (!opts.isNewSession) {
|
|
33804
34600
|
const agentCwd = this.sessionAgentCwd.get(sessionId);
|
|
33805
|
-
if (agentCwd) return
|
|
34601
|
+
if (agentCwd) return path17.resolve(agentCwd);
|
|
33806
34602
|
return void 0;
|
|
33807
34603
|
}
|
|
33808
34604
|
const prep = await prepareNewSessionWorktrees({
|
|
@@ -33815,7 +34611,7 @@ var SessionWorktreeManager = class {
|
|
|
33815
34611
|
if (!prep) return void 0;
|
|
33816
34612
|
this.sessionPaths.set(sessionId, prep.worktreePaths);
|
|
33817
34613
|
this.sessionAgentCwd.set(sessionId, prep.agentCwd);
|
|
33818
|
-
return
|
|
34614
|
+
return path17.resolve(prep.agentCwd);
|
|
33819
34615
|
}
|
|
33820
34616
|
async renameSessionBranch(sessionId, newBranch) {
|
|
33821
34617
|
const paths = this.sessionPaths.get(sessionId);
|
|
@@ -33836,7 +34632,7 @@ var SessionWorktreeManager = class {
|
|
|
33836
34632
|
getAgentCwdForSession(sessionId) {
|
|
33837
34633
|
if (!sessionId) return null;
|
|
33838
34634
|
const c = this.sessionAgentCwd.get(sessionId);
|
|
33839
|
-
return c ?
|
|
34635
|
+
return c ? path17.resolve(c) : null;
|
|
33840
34636
|
}
|
|
33841
34637
|
async removeSessionWorktrees(sessionId) {
|
|
33842
34638
|
const paths = this.sessionPaths.get(sessionId);
|
|
@@ -33884,30 +34680,30 @@ var SessionWorktreeManager = class {
|
|
|
33884
34680
|
}
|
|
33885
34681
|
};
|
|
33886
34682
|
function defaultWorktreesRootAbs() {
|
|
33887
|
-
return
|
|
34683
|
+
return path17.join(os4.homedir(), ".buildautomaton", "worktrees");
|
|
33888
34684
|
}
|
|
33889
34685
|
|
|
33890
34686
|
// src/files/watch-file-index.ts
|
|
33891
34687
|
import { watch } from "node:fs";
|
|
33892
|
-
import
|
|
34688
|
+
import path24 from "node:path";
|
|
33893
34689
|
|
|
33894
34690
|
// src/files/index/build-file-index.ts
|
|
33895
|
-
import
|
|
34691
|
+
import path21 from "node:path";
|
|
33896
34692
|
|
|
33897
34693
|
// src/runtime/yield-to-event-loop.ts
|
|
33898
34694
|
function yieldToEventLoop() {
|
|
33899
|
-
return new Promise((
|
|
34695
|
+
return new Promise((resolve17) => setImmediate(resolve17));
|
|
33900
34696
|
}
|
|
33901
34697
|
|
|
33902
34698
|
// src/files/index/walk-workspace-tree.ts
|
|
33903
|
-
import
|
|
33904
|
-
import
|
|
34699
|
+
import fs18 from "node:fs";
|
|
34700
|
+
import path19 from "node:path";
|
|
33905
34701
|
|
|
33906
34702
|
// src/files/index/constants.ts
|
|
33907
|
-
import
|
|
34703
|
+
import path18 from "node:path";
|
|
33908
34704
|
import os5 from "node:os";
|
|
33909
34705
|
var INDEX_WORK_YIELD_EVERY = 256;
|
|
33910
|
-
var INDEX_DIR =
|
|
34706
|
+
var INDEX_DIR = path18.join(os5.homedir(), ".buildautomaton");
|
|
33911
34707
|
var INDEX_HASH_LEN = 16;
|
|
33912
34708
|
var INDEX_VERSION = 2;
|
|
33913
34709
|
var INDEX_LOG_PREFIX = "[file-index]";
|
|
@@ -33916,23 +34712,23 @@ var INDEX_LOG_PREFIX = "[file-index]";
|
|
|
33916
34712
|
function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
33917
34713
|
let names;
|
|
33918
34714
|
try {
|
|
33919
|
-
names =
|
|
34715
|
+
names = fs18.readdirSync(dir);
|
|
33920
34716
|
} catch {
|
|
33921
34717
|
return;
|
|
33922
34718
|
}
|
|
33923
34719
|
for (const name of names) {
|
|
33924
34720
|
if (name.startsWith(".")) continue;
|
|
33925
|
-
const full =
|
|
33926
|
-
let
|
|
34721
|
+
const full = path19.join(dir, name);
|
|
34722
|
+
let stat3;
|
|
33927
34723
|
try {
|
|
33928
|
-
|
|
34724
|
+
stat3 = fs18.statSync(full);
|
|
33929
34725
|
} catch {
|
|
33930
34726
|
continue;
|
|
33931
34727
|
}
|
|
33932
|
-
const relative5 =
|
|
33933
|
-
if (
|
|
34728
|
+
const relative5 = path19.relative(baseDir, full).replace(/\\/g, "/");
|
|
34729
|
+
if (stat3.isDirectory()) {
|
|
33934
34730
|
walkWorkspaceTreeSync(full, baseDir, out);
|
|
33935
|
-
} else if (
|
|
34731
|
+
} else if (stat3.isFile()) {
|
|
33936
34732
|
out.push(relative5);
|
|
33937
34733
|
}
|
|
33938
34734
|
}
|
|
@@ -33940,7 +34736,7 @@ function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
|
33940
34736
|
async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
33941
34737
|
let names;
|
|
33942
34738
|
try {
|
|
33943
|
-
names = await
|
|
34739
|
+
names = await fs18.promises.readdir(dir);
|
|
33944
34740
|
} catch {
|
|
33945
34741
|
return;
|
|
33946
34742
|
}
|
|
@@ -33950,17 +34746,17 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
|
33950
34746
|
await yieldToEventLoop();
|
|
33951
34747
|
}
|
|
33952
34748
|
state.n++;
|
|
33953
|
-
const full =
|
|
33954
|
-
let
|
|
34749
|
+
const full = path19.join(dir, name);
|
|
34750
|
+
let stat3;
|
|
33955
34751
|
try {
|
|
33956
|
-
|
|
34752
|
+
stat3 = await fs18.promises.stat(full);
|
|
33957
34753
|
} catch {
|
|
33958
34754
|
continue;
|
|
33959
34755
|
}
|
|
33960
|
-
const relative5 =
|
|
33961
|
-
if (
|
|
34756
|
+
const relative5 = path19.relative(baseDir, full).replace(/\\/g, "/");
|
|
34757
|
+
if (stat3.isDirectory()) {
|
|
33962
34758
|
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
33963
|
-
} else if (
|
|
34759
|
+
} else if (stat3.isFile()) {
|
|
33964
34760
|
out.push(relative5);
|
|
33965
34761
|
}
|
|
33966
34762
|
}
|
|
@@ -34038,22 +34834,22 @@ async function buildTrigramMapForPathsAsync(paths) {
|
|
|
34038
34834
|
}
|
|
34039
34835
|
|
|
34040
34836
|
// src/files/index/write-index-file.ts
|
|
34041
|
-
import
|
|
34837
|
+
import fs19 from "node:fs";
|
|
34042
34838
|
|
|
34043
34839
|
// src/files/index/paths.ts
|
|
34044
|
-
import
|
|
34840
|
+
import path20 from "node:path";
|
|
34045
34841
|
import crypto2 from "node:crypto";
|
|
34046
34842
|
function getIndexPathForCwd(resolvedCwd) {
|
|
34047
34843
|
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
34048
|
-
return
|
|
34844
|
+
return path20.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
34049
34845
|
}
|
|
34050
34846
|
|
|
34051
34847
|
// src/files/index/write-index-file.ts
|
|
34052
34848
|
function writeIndexFileSync(resolvedCwd, data) {
|
|
34053
34849
|
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
34054
34850
|
try {
|
|
34055
|
-
if (!
|
|
34056
|
-
|
|
34851
|
+
if (!fs19.existsSync(INDEX_DIR)) fs19.mkdirSync(INDEX_DIR, { recursive: true });
|
|
34852
|
+
fs19.writeFileSync(indexPath, JSON.stringify(data), "utf8");
|
|
34057
34853
|
} catch (e) {
|
|
34058
34854
|
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
34059
34855
|
}
|
|
@@ -34061,8 +34857,8 @@ function writeIndexFileSync(resolvedCwd, data) {
|
|
|
34061
34857
|
async function writeIndexFileAsync(resolvedCwd, data) {
|
|
34062
34858
|
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
34063
34859
|
try {
|
|
34064
|
-
await
|
|
34065
|
-
await
|
|
34860
|
+
await fs19.promises.mkdir(INDEX_DIR, { recursive: true });
|
|
34861
|
+
await fs19.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
|
|
34066
34862
|
} catch (e) {
|
|
34067
34863
|
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
34068
34864
|
}
|
|
@@ -34076,7 +34872,7 @@ function sortPaths(paths) {
|
|
|
34076
34872
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
34077
34873
|
}
|
|
34078
34874
|
function buildFileIndex(cwd) {
|
|
34079
|
-
const resolved =
|
|
34875
|
+
const resolved = path21.resolve(cwd);
|
|
34080
34876
|
const paths = [];
|
|
34081
34877
|
walkWorkspaceTreeSync(resolved, resolved, paths);
|
|
34082
34878
|
sortPaths(paths);
|
|
@@ -34086,7 +34882,7 @@ function buildFileIndex(cwd) {
|
|
|
34086
34882
|
return data;
|
|
34087
34883
|
}
|
|
34088
34884
|
async function buildFileIndexAsync(cwd) {
|
|
34089
|
-
const resolved =
|
|
34885
|
+
const resolved = path21.resolve(cwd);
|
|
34090
34886
|
const paths = [];
|
|
34091
34887
|
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
34092
34888
|
await yieldToEventLoop();
|
|
@@ -34098,13 +34894,13 @@ async function buildFileIndexAsync(cwd) {
|
|
|
34098
34894
|
}
|
|
34099
34895
|
|
|
34100
34896
|
// src/files/index/load-file-index.ts
|
|
34101
|
-
import
|
|
34102
|
-
import
|
|
34897
|
+
import fs20 from "node:fs";
|
|
34898
|
+
import path22 from "node:path";
|
|
34103
34899
|
function loadFileIndex(cwd) {
|
|
34104
|
-
const resolved =
|
|
34900
|
+
const resolved = path22.resolve(cwd);
|
|
34105
34901
|
const indexPath = getIndexPathForCwd(resolved);
|
|
34106
34902
|
try {
|
|
34107
|
-
const raw =
|
|
34903
|
+
const raw = fs20.readFileSync(indexPath, "utf8");
|
|
34108
34904
|
const parsed = JSON.parse(raw);
|
|
34109
34905
|
if (parsed !== null && typeof parsed === "object" && Array.isArray(parsed.paths)) {
|
|
34110
34906
|
const obj = parsed;
|
|
@@ -34123,9 +34919,9 @@ function loadFileIndex(cwd) {
|
|
|
34123
34919
|
}
|
|
34124
34920
|
|
|
34125
34921
|
// src/files/index/ensure-file-index.ts
|
|
34126
|
-
import
|
|
34922
|
+
import path23 from "node:path";
|
|
34127
34923
|
async function ensureFileIndexAsync(cwd) {
|
|
34128
|
-
const resolved =
|
|
34924
|
+
const resolved = path23.resolve(cwd);
|
|
34129
34925
|
const cached2 = loadFileIndex(resolved);
|
|
34130
34926
|
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
34131
34927
|
const data = await buildFileIndexAsync(resolved);
|
|
@@ -34208,7 +35004,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
34208
35004
|
}
|
|
34209
35005
|
}
|
|
34210
35006
|
function startFileIndexWatcher(cwd = getBridgeWorkspaceDirectory()) {
|
|
34211
|
-
const resolved =
|
|
35007
|
+
const resolved = path24.resolve(cwd);
|
|
34212
35008
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
34213
35009
|
console.error("[file-index] Initial index build failed:", e);
|
|
34214
35010
|
});
|
|
@@ -34236,7 +35032,7 @@ function startFileIndexWatcher(cwd = getBridgeWorkspaceDirectory()) {
|
|
|
34236
35032
|
}
|
|
34237
35033
|
|
|
34238
35034
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
34239
|
-
import { rm } from "node:fs/promises";
|
|
35035
|
+
import { rm as rm2 } from "node:fs/promises";
|
|
34240
35036
|
|
|
34241
35037
|
// src/dev-servers/process/send-server-status.ts
|
|
34242
35038
|
function sendDevServerStatus(getWs, serverId, status, options) {
|
|
@@ -34255,15 +35051,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
|
|
|
34255
35051
|
|
|
34256
35052
|
// src/dev-servers/process/terminate-child-process.ts
|
|
34257
35053
|
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
34258
|
-
const exited = new Promise((
|
|
34259
|
-
proc.once("exit", () =>
|
|
35054
|
+
const exited = new Promise((resolve17) => {
|
|
35055
|
+
proc.once("exit", () => resolve17());
|
|
34260
35056
|
});
|
|
34261
35057
|
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
|
|
34262
35058
|
try {
|
|
34263
35059
|
proc.kill("SIGTERM");
|
|
34264
35060
|
} catch {
|
|
34265
35061
|
}
|
|
34266
|
-
await Promise.race([exited, new Promise((
|
|
35062
|
+
await Promise.race([exited, new Promise((resolve17) => setTimeout(resolve17, graceMs))]);
|
|
34267
35063
|
}
|
|
34268
35064
|
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
34269
35065
|
log2(
|
|
@@ -34277,7 +35073,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
34277
35073
|
}
|
|
34278
35074
|
|
|
34279
35075
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
34280
|
-
import
|
|
35076
|
+
import fs21 from "node:fs";
|
|
34281
35077
|
|
|
34282
35078
|
// src/dev-servers/manager/forward-pipe.ts
|
|
34283
35079
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -34313,7 +35109,7 @@ function wireDevServerChildProcess(d) {
|
|
|
34313
35109
|
d.setPollInterval(void 0);
|
|
34314
35110
|
return;
|
|
34315
35111
|
}
|
|
34316
|
-
|
|
35112
|
+
fs21.readFile(d.mergedLogPath, (err, buf) => {
|
|
34317
35113
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
34318
35114
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
34319
35115
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -34351,7 +35147,7 @@ ${errTail}` : ""}`);
|
|
|
34351
35147
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
34352
35148
|
};
|
|
34353
35149
|
if (mergedPath) {
|
|
34354
|
-
|
|
35150
|
+
fs21.readFile(mergedPath, (err, buf) => {
|
|
34355
35151
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
34356
35152
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
34357
35153
|
if (chunk.length > 0) {
|
|
@@ -34453,13 +35249,13 @@ function parseDevServerDefs(servers) {
|
|
|
34453
35249
|
}
|
|
34454
35250
|
|
|
34455
35251
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
34456
|
-
import
|
|
35252
|
+
import fs22 from "node:fs";
|
|
34457
35253
|
function isSpawnEbadf(e) {
|
|
34458
35254
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
34459
35255
|
}
|
|
34460
35256
|
function rmDirQuiet(dir) {
|
|
34461
35257
|
try {
|
|
34462
|
-
|
|
35258
|
+
fs22.rmSync(dir, { recursive: true, force: true });
|
|
34463
35259
|
} catch {
|
|
34464
35260
|
}
|
|
34465
35261
|
}
|
|
@@ -34467,7 +35263,7 @@ var cachedDevNullReadFd;
|
|
|
34467
35263
|
function devNullReadFd() {
|
|
34468
35264
|
if (cachedDevNullReadFd === void 0) {
|
|
34469
35265
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
34470
|
-
cachedDevNullReadFd =
|
|
35266
|
+
cachedDevNullReadFd = fs22.openSync(devPath, "r");
|
|
34471
35267
|
}
|
|
34472
35268
|
return cachedDevNullReadFd;
|
|
34473
35269
|
}
|
|
@@ -34541,15 +35337,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
34541
35337
|
|
|
34542
35338
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
34543
35339
|
import { spawn as spawn6 } from "node:child_process";
|
|
34544
|
-
import
|
|
35340
|
+
import fs23 from "node:fs";
|
|
34545
35341
|
import { tmpdir } from "node:os";
|
|
34546
|
-
import
|
|
35342
|
+
import path25 from "node:path";
|
|
34547
35343
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
34548
|
-
const tmpRoot =
|
|
34549
|
-
const logPath =
|
|
35344
|
+
const tmpRoot = fs23.mkdtempSync(path25.join(tmpdir(), "ba-devsrv-log-"));
|
|
35345
|
+
const logPath = path25.join(tmpRoot, "combined.log");
|
|
34550
35346
|
let logFd;
|
|
34551
35347
|
try {
|
|
34552
|
-
logFd =
|
|
35348
|
+
logFd = fs23.openSync(logPath, "a");
|
|
34553
35349
|
} catch {
|
|
34554
35350
|
rmDirQuiet(tmpRoot);
|
|
34555
35351
|
return null;
|
|
@@ -34568,7 +35364,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
34568
35364
|
} else {
|
|
34569
35365
|
proc = spawn6("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
34570
35366
|
}
|
|
34571
|
-
|
|
35367
|
+
fs23.closeSync(logFd);
|
|
34572
35368
|
return {
|
|
34573
35369
|
proc,
|
|
34574
35370
|
pipedStdoutStderr: true,
|
|
@@ -34577,7 +35373,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
34577
35373
|
};
|
|
34578
35374
|
} catch (e) {
|
|
34579
35375
|
try {
|
|
34580
|
-
|
|
35376
|
+
fs23.closeSync(logFd);
|
|
34581
35377
|
} catch {
|
|
34582
35378
|
}
|
|
34583
35379
|
rmDirQuiet(tmpRoot);
|
|
@@ -34588,22 +35384,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
34588
35384
|
|
|
34589
35385
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
34590
35386
|
import { spawn as spawn7 } from "node:child_process";
|
|
34591
|
-
import
|
|
35387
|
+
import fs24 from "node:fs";
|
|
34592
35388
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
34593
|
-
import
|
|
35389
|
+
import path26 from "node:path";
|
|
34594
35390
|
function shSingleQuote(s) {
|
|
34595
35391
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
34596
35392
|
}
|
|
34597
35393
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
34598
|
-
const tmpRoot =
|
|
34599
|
-
const logPath =
|
|
34600
|
-
const innerPath =
|
|
34601
|
-
const runnerPath =
|
|
35394
|
+
const tmpRoot = fs24.mkdtempSync(path26.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
35395
|
+
const logPath = path26.join(tmpRoot, "combined.log");
|
|
35396
|
+
const innerPath = path26.join(tmpRoot, "_cmd.sh");
|
|
35397
|
+
const runnerPath = path26.join(tmpRoot, "_run.sh");
|
|
34602
35398
|
try {
|
|
34603
|
-
|
|
35399
|
+
fs24.writeFileSync(innerPath, `#!/bin/sh
|
|
34604
35400
|
${command}
|
|
34605
35401
|
`);
|
|
34606
|
-
|
|
35402
|
+
fs24.writeFileSync(
|
|
34607
35403
|
runnerPath,
|
|
34608
35404
|
`#!/bin/sh
|
|
34609
35405
|
cd ${shSingleQuote(cwd)}
|
|
@@ -34629,13 +35425,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
34629
35425
|
}
|
|
34630
35426
|
}
|
|
34631
35427
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
34632
|
-
const tmpRoot =
|
|
34633
|
-
const logPath =
|
|
34634
|
-
const runnerPath =
|
|
35428
|
+
const tmpRoot = fs24.mkdtempSync(path26.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
35429
|
+
const logPath = path26.join(tmpRoot, "combined.log");
|
|
35430
|
+
const runnerPath = path26.join(tmpRoot, "_run.bat");
|
|
34635
35431
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
34636
35432
|
const com = process.env.ComSpec || "cmd.exe";
|
|
34637
35433
|
try {
|
|
34638
|
-
|
|
35434
|
+
fs24.writeFileSync(
|
|
34639
35435
|
runnerPath,
|
|
34640
35436
|
`@ECHO OFF\r
|
|
34641
35437
|
CD /D ${q(cwd)}\r
|
|
@@ -34745,8 +35541,90 @@ var StreamTail = class {
|
|
|
34745
35541
|
}
|
|
34746
35542
|
};
|
|
34747
35543
|
|
|
34748
|
-
// src/dev-servers/manager/dev-server-
|
|
35544
|
+
// src/dev-servers/manager/dev-server-constants.ts
|
|
34749
35545
|
var BRIDGE_SHUTDOWN_GRACE_MS = 8e3;
|
|
35546
|
+
|
|
35547
|
+
// src/dev-servers/manager/dev-server-firehose-messages.ts
|
|
35548
|
+
function buildFirehoseSnapshotMessage(params) {
|
|
35549
|
+
const payload = {
|
|
35550
|
+
type: "log_snapshot",
|
|
35551
|
+
serverId: params.serverId,
|
|
35552
|
+
viewerId: params.viewerId,
|
|
35553
|
+
stdoutTail: params.tails.stdout,
|
|
35554
|
+
stderrTail: params.tails.stderr
|
|
35555
|
+
};
|
|
35556
|
+
return params.e2ee ? params.e2ee.encryptFields(payload, ["stdoutTail", "stderrTail"]) : payload;
|
|
35557
|
+
}
|
|
35558
|
+
function buildFirehoseLogChunkMessage(params) {
|
|
35559
|
+
const payload = {
|
|
35560
|
+
type: "log_chunk",
|
|
35561
|
+
serverId: params.serverId,
|
|
35562
|
+
stream: params.stream,
|
|
35563
|
+
text: params.text
|
|
35564
|
+
};
|
|
35565
|
+
return params.e2ee ? params.e2ee.encryptFields(payload, ["text"]) : payload;
|
|
35566
|
+
}
|
|
35567
|
+
|
|
35568
|
+
// src/dev-servers/manager/dev-server-firehose-sink.ts
|
|
35569
|
+
var DevServerFirehoseSink = class {
|
|
35570
|
+
constructor(options) {
|
|
35571
|
+
this.options = options;
|
|
35572
|
+
}
|
|
35573
|
+
logViewerRefCountByServerId = /* @__PURE__ */ new Map();
|
|
35574
|
+
firehoseSend = null;
|
|
35575
|
+
attach(send) {
|
|
35576
|
+
this.firehoseSend = send;
|
|
35577
|
+
}
|
|
35578
|
+
detach() {
|
|
35579
|
+
this.firehoseSend = null;
|
|
35580
|
+
this.logViewerRefCountByServerId.clear();
|
|
35581
|
+
}
|
|
35582
|
+
openLogViewer(serverId, viewerId) {
|
|
35583
|
+
const next = (this.logViewerRefCountByServerId.get(serverId) ?? 0) + 1;
|
|
35584
|
+
this.logViewerRefCountByServerId.set(serverId, next);
|
|
35585
|
+
this.sendSnapshot(serverId, viewerId);
|
|
35586
|
+
}
|
|
35587
|
+
closeLogViewer(serverId) {
|
|
35588
|
+
const n = (this.logViewerRefCountByServerId.get(serverId) ?? 0) - 1;
|
|
35589
|
+
if (n <= 0) this.logViewerRefCountByServerId.delete(serverId);
|
|
35590
|
+
else this.logViewerRefCountByServerId.set(serverId, n);
|
|
35591
|
+
}
|
|
35592
|
+
pushLogChunk(serverId, stream, chunk) {
|
|
35593
|
+
if ((this.logViewerRefCountByServerId.get(serverId) ?? 0) <= 0) return;
|
|
35594
|
+
if (!this.options.isPipedCaptureEnabled(serverId)) return;
|
|
35595
|
+
if (!this.firehoseSend) return;
|
|
35596
|
+
const text = chunk.toString("utf8");
|
|
35597
|
+
setImmediate(() => {
|
|
35598
|
+
if (!this.firehoseSend) return;
|
|
35599
|
+
this.firehoseSend(buildFirehoseLogChunkMessage({ serverId, stream, text, e2ee: this.options.e2ee }));
|
|
35600
|
+
});
|
|
35601
|
+
}
|
|
35602
|
+
sendSnapshot(serverId, viewerId) {
|
|
35603
|
+
const payload = buildFirehoseSnapshotMessage({
|
|
35604
|
+
serverId,
|
|
35605
|
+
viewerId,
|
|
35606
|
+
tails: this.options.getTails(serverId),
|
|
35607
|
+
e2ee: this.options.e2ee
|
|
35608
|
+
});
|
|
35609
|
+
setImmediate(() => {
|
|
35610
|
+
const send = this.firehoseSend;
|
|
35611
|
+
if (!send) return;
|
|
35612
|
+
send(payload);
|
|
35613
|
+
});
|
|
35614
|
+
}
|
|
35615
|
+
};
|
|
35616
|
+
|
|
35617
|
+
// src/dev-servers/manager/cleanup-merged-log-dir.ts
|
|
35618
|
+
import { rm } from "node:fs/promises";
|
|
35619
|
+
function cleanupMergedLogDirForServer(map2, serverId) {
|
|
35620
|
+
const mergedDir = map2.get(serverId);
|
|
35621
|
+
if (!mergedDir) return;
|
|
35622
|
+
map2.delete(serverId);
|
|
35623
|
+
void rm(mergedDir, { recursive: true, force: true }).catch(() => {
|
|
35624
|
+
});
|
|
35625
|
+
}
|
|
35626
|
+
|
|
35627
|
+
// src/dev-servers/manager/dev-server-manager.ts
|
|
34750
35628
|
var emptyTails = () => ({ stdout: [], stderr: [] });
|
|
34751
35629
|
var DevServerManager = class {
|
|
34752
35630
|
defsById = /* @__PURE__ */ new Map();
|
|
@@ -34754,66 +35632,36 @@ var DevServerManager = class {
|
|
|
34754
35632
|
streamTailsByServerId = /* @__PURE__ */ new Map();
|
|
34755
35633
|
spawnGenerationByServerId = /* @__PURE__ */ new Map();
|
|
34756
35634
|
pipedCaptureByServerId = /* @__PURE__ */ new Map();
|
|
34757
|
-
logViewerRefCountByServerId = /* @__PURE__ */ new Map();
|
|
34758
|
-
firehoseSend = null;
|
|
34759
35635
|
mergedLogPollByServerId = /* @__PURE__ */ new Map();
|
|
34760
35636
|
mergedLogCleanupDirByServerId = /* @__PURE__ */ new Map();
|
|
34761
35637
|
abortControllersByServerId = /* @__PURE__ */ new Map();
|
|
34762
35638
|
getWs;
|
|
34763
35639
|
log;
|
|
34764
35640
|
getBridgeCwd;
|
|
35641
|
+
e2ee;
|
|
35642
|
+
firehoseSink;
|
|
34765
35643
|
constructor(options) {
|
|
34766
35644
|
this.getWs = options.getWs;
|
|
34767
35645
|
this.log = options.log;
|
|
34768
35646
|
this.getBridgeCwd = options.getBridgeCwd ?? (() => process.cwd());
|
|
35647
|
+
this.e2ee = options.e2ee;
|
|
35648
|
+
this.firehoseSink = new DevServerFirehoseSink({
|
|
35649
|
+
getTails: (serverId) => this.snapshotTails(serverId),
|
|
35650
|
+
isPipedCaptureEnabled: (serverId) => this.pipedCaptureByServerId.get(serverId) === true,
|
|
35651
|
+
e2ee: this.e2ee
|
|
35652
|
+
});
|
|
34769
35653
|
}
|
|
34770
35654
|
attachFirehose(send) {
|
|
34771
|
-
this.
|
|
35655
|
+
this.firehoseSink.attach(send);
|
|
34772
35656
|
}
|
|
34773
35657
|
detachFirehose() {
|
|
34774
|
-
this.
|
|
34775
|
-
this.logViewerRefCountByServerId.clear();
|
|
35658
|
+
this.firehoseSink.detach();
|
|
34776
35659
|
}
|
|
34777
35660
|
handleFirehoseLogViewerOpen(serverId, _viewerId) {
|
|
34778
|
-
|
|
34779
|
-
this.logViewerRefCountByServerId.set(serverId, next);
|
|
34780
|
-
this.sendSnapshotToFirehose(serverId, _viewerId);
|
|
35661
|
+
this.firehoseSink.openLogViewer(serverId, _viewerId);
|
|
34781
35662
|
}
|
|
34782
35663
|
handleFirehoseLogViewerClose(serverId, _viewerId) {
|
|
34783
|
-
|
|
34784
|
-
if (n <= 0) this.logViewerRefCountByServerId.delete(serverId);
|
|
34785
|
-
else this.logViewerRefCountByServerId.set(serverId, n);
|
|
34786
|
-
}
|
|
34787
|
-
sendSnapshotToFirehose(serverId, viewerId) {
|
|
34788
|
-
const tails = this.streamTailsByServerId.get(serverId);
|
|
34789
|
-
const payload = {
|
|
34790
|
-
type: "log_snapshot",
|
|
34791
|
-
serverId,
|
|
34792
|
-
viewerId,
|
|
34793
|
-
stdoutTail: tails?.stdout.getTail() ?? [],
|
|
34794
|
-
stderrTail: tails?.stderr.getTail() ?? []
|
|
34795
|
-
};
|
|
34796
|
-
setImmediate(() => {
|
|
34797
|
-
const send = this.firehoseSend;
|
|
34798
|
-
if (!send) return;
|
|
34799
|
-
send(payload);
|
|
34800
|
-
});
|
|
34801
|
-
}
|
|
34802
|
-
pushRemoteLogChunk(serverId, stream, chunk) {
|
|
34803
|
-
if ((this.logViewerRefCountByServerId.get(serverId) ?? 0) <= 0) return;
|
|
34804
|
-
if (!this.pipedCaptureByServerId.get(serverId)) return;
|
|
34805
|
-
const send = this.firehoseSend;
|
|
34806
|
-
if (!send) return;
|
|
34807
|
-
const text = chunk.toString("utf8");
|
|
34808
|
-
setImmediate(() => {
|
|
34809
|
-
if (!this.firehoseSend) return;
|
|
34810
|
-
this.firehoseSend({
|
|
34811
|
-
type: "log_chunk",
|
|
34812
|
-
serverId,
|
|
34813
|
-
stream,
|
|
34814
|
-
text
|
|
34815
|
-
});
|
|
34816
|
-
});
|
|
35664
|
+
this.firehoseSink.closeLogViewer(serverId);
|
|
34817
35665
|
}
|
|
34818
35666
|
applyConfig(servers) {
|
|
34819
35667
|
this.defsById.clear();
|
|
@@ -34866,12 +35714,7 @@ var DevServerManager = class {
|
|
|
34866
35714
|
}
|
|
34867
35715
|
this.clearTails(serverId);
|
|
34868
35716
|
this.pipedCaptureByServerId.delete(serverId);
|
|
34869
|
-
|
|
34870
|
-
if (mergedDir) {
|
|
34871
|
-
this.mergedLogCleanupDirByServerId.delete(serverId);
|
|
34872
|
-
void rm(mergedDir, { recursive: true, force: true }).catch(() => {
|
|
34873
|
-
});
|
|
34874
|
-
}
|
|
35717
|
+
cleanupMergedLogDirForServer(this.mergedLogCleanupDirByServerId, serverId);
|
|
34875
35718
|
this.sendStatus(serverId, "stopped", void 0, tails);
|
|
34876
35719
|
}
|
|
34877
35720
|
start(serverId) {
|
|
@@ -34954,7 +35797,7 @@ var DevServerManager = class {
|
|
|
34954
35797
|
log: this.log,
|
|
34955
35798
|
stdoutTail,
|
|
34956
35799
|
stderrTail,
|
|
34957
|
-
pushRemoteLogChunk: (sid, stream, chunk) => this.
|
|
35800
|
+
pushRemoteLogChunk: (sid, stream, chunk) => this.firehoseSink.pushLogChunk(sid, stream, chunk),
|
|
34958
35801
|
sendStatus: (status, detail, tails) => this.sendStatus(serverId, status, detail, tails),
|
|
34959
35802
|
setPollInterval: (iv) => {
|
|
34960
35803
|
if (iv) this.mergedLogPollByServerId.set(serverId, iv);
|
|
@@ -34968,7 +35811,7 @@ var DevServerManager = class {
|
|
|
34968
35811
|
this.mergedLogCleanupDirByServerId.delete(serverId);
|
|
34969
35812
|
},
|
|
34970
35813
|
rmMergedCleanupDir: (dir) => {
|
|
34971
|
-
void
|
|
35814
|
+
void rm2(dir, { recursive: true, force: true }).catch(() => {
|
|
34972
35815
|
});
|
|
34973
35816
|
},
|
|
34974
35817
|
clearTailBuffers: () => this.clearTails(serverId)
|
|
@@ -35005,12 +35848,7 @@ var DevServerManager = class {
|
|
|
35005
35848
|
this.processes.delete(serverId);
|
|
35006
35849
|
this.clearPoll(serverId);
|
|
35007
35850
|
this.pipedCaptureByServerId.delete(serverId);
|
|
35008
|
-
|
|
35009
|
-
if (mergedDir) {
|
|
35010
|
-
this.mergedLogCleanupDirByServerId.delete(serverId);
|
|
35011
|
-
void rm(mergedDir, { recursive: true, force: true }).catch(() => {
|
|
35012
|
-
});
|
|
35013
|
-
}
|
|
35851
|
+
cleanupMergedLogDirForServer(this.mergedLogCleanupDirByServerId, serverId);
|
|
35014
35852
|
const tails = this.snapshotTails(serverId);
|
|
35015
35853
|
this.clearTails(serverId);
|
|
35016
35854
|
this.sendStatus(serverId, "unknown", "Bridge closed before process exited", tails);
|
|
@@ -35104,7 +35942,7 @@ async function proxyToLocal(request) {
|
|
|
35104
35942
|
};
|
|
35105
35943
|
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
35106
35944
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
35107
|
-
const once = await new Promise((
|
|
35945
|
+
const once = await new Promise((resolve17) => {
|
|
35108
35946
|
const req = mod.request(opts, (res) => {
|
|
35109
35947
|
const chunks = [];
|
|
35110
35948
|
res.on("data", (c) => chunks.push(c));
|
|
@@ -35115,7 +35953,7 @@ async function proxyToLocal(request) {
|
|
|
35115
35953
|
if (typeof v === "string") headers[k] = v;
|
|
35116
35954
|
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
35117
35955
|
}
|
|
35118
|
-
|
|
35956
|
+
resolve17({
|
|
35119
35957
|
id: request.id,
|
|
35120
35958
|
statusCode: res.statusCode ?? 0,
|
|
35121
35959
|
headers,
|
|
@@ -35124,7 +35962,7 @@ async function proxyToLocal(request) {
|
|
|
35124
35962
|
});
|
|
35125
35963
|
});
|
|
35126
35964
|
req.on("error", (err) => {
|
|
35127
|
-
|
|
35965
|
+
resolve17({
|
|
35128
35966
|
id: request.id,
|
|
35129
35967
|
statusCode: 0,
|
|
35130
35968
|
headers: {},
|
|
@@ -35485,30 +36323,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
35485
36323
|
}
|
|
35486
36324
|
|
|
35487
36325
|
// src/skills/discover-local-agent-skills.ts
|
|
35488
|
-
import
|
|
35489
|
-
import
|
|
36326
|
+
import fs25 from "node:fs";
|
|
36327
|
+
import path27 from "node:path";
|
|
35490
36328
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
35491
36329
|
function discoverLocalSkills(cwd) {
|
|
35492
36330
|
const out = [];
|
|
35493
36331
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
35494
36332
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
35495
|
-
const base =
|
|
35496
|
-
if (!
|
|
36333
|
+
const base = path27.join(cwd, rel);
|
|
36334
|
+
if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
|
|
35497
36335
|
let entries = [];
|
|
35498
36336
|
try {
|
|
35499
|
-
entries =
|
|
36337
|
+
entries = fs25.readdirSync(base);
|
|
35500
36338
|
} catch {
|
|
35501
36339
|
continue;
|
|
35502
36340
|
}
|
|
35503
36341
|
for (const name of entries) {
|
|
35504
|
-
const dir =
|
|
36342
|
+
const dir = path27.join(base, name);
|
|
35505
36343
|
try {
|
|
35506
|
-
if (!
|
|
36344
|
+
if (!fs25.statSync(dir).isDirectory()) continue;
|
|
35507
36345
|
} catch {
|
|
35508
36346
|
continue;
|
|
35509
36347
|
}
|
|
35510
|
-
const skillMd =
|
|
35511
|
-
if (!
|
|
36348
|
+
const skillMd = path27.join(dir, "SKILL.md");
|
|
36349
|
+
if (!fs25.existsSync(skillMd)) continue;
|
|
35512
36350
|
const key = `${rel}/${name}`;
|
|
35513
36351
|
if (seenKeys.has(key)) continue;
|
|
35514
36352
|
seenKeys.add(key);
|
|
@@ -35520,23 +36358,23 @@ function discoverLocalSkills(cwd) {
|
|
|
35520
36358
|
function discoverSkillLayoutRoots(cwd) {
|
|
35521
36359
|
const roots = [];
|
|
35522
36360
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
35523
|
-
const base =
|
|
35524
|
-
if (!
|
|
36361
|
+
const base = path27.join(cwd, rel);
|
|
36362
|
+
if (!fs25.existsSync(base) || !fs25.statSync(base).isDirectory()) continue;
|
|
35525
36363
|
let entries = [];
|
|
35526
36364
|
try {
|
|
35527
|
-
entries =
|
|
36365
|
+
entries = fs25.readdirSync(base);
|
|
35528
36366
|
} catch {
|
|
35529
36367
|
continue;
|
|
35530
36368
|
}
|
|
35531
36369
|
const skills2 = [];
|
|
35532
36370
|
for (const name of entries) {
|
|
35533
|
-
const dir =
|
|
36371
|
+
const dir = path27.join(base, name);
|
|
35534
36372
|
try {
|
|
35535
|
-
if (!
|
|
36373
|
+
if (!fs25.statSync(dir).isDirectory()) continue;
|
|
35536
36374
|
} catch {
|
|
35537
36375
|
continue;
|
|
35538
36376
|
}
|
|
35539
|
-
if (!
|
|
36377
|
+
if (!fs25.existsSync(path27.join(dir, "SKILL.md"))) continue;
|
|
35540
36378
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
35541
36379
|
skills2.push({ name, relPath });
|
|
35542
36380
|
}
|
|
@@ -35638,7 +36476,7 @@ function reportGitRepos(getWs, log2) {
|
|
|
35638
36476
|
var handleAuthToken = (msg, { log: log2 }) => {
|
|
35639
36477
|
if (typeof msg.token !== "string") return;
|
|
35640
36478
|
log2("Received auth token. Save it for future runs:");
|
|
35641
|
-
log2(` export
|
|
36479
|
+
log2(` export BUILDAUTOMATON_AUTH_TOKEN="${msg.token}"`);
|
|
35642
36480
|
};
|
|
35643
36481
|
|
|
35644
36482
|
// src/bridge/routing/handlers/bridge-identified.ts
|
|
@@ -35681,13 +36519,49 @@ var handleAgentConfigMessage = (msg, deps) => {
|
|
|
35681
36519
|
};
|
|
35682
36520
|
|
|
35683
36521
|
// src/agents/acp/from-bridge/handle-bridge-prompt.ts
|
|
35684
|
-
import * as
|
|
36522
|
+
import * as path29 from "node:path";
|
|
36523
|
+
|
|
36524
|
+
// src/agents/acp/from-bridge/bridge-prompt-wiring.ts
|
|
36525
|
+
function createBridgePromptSenders(deps, getWs) {
|
|
36526
|
+
const sendBridgeMessage = (message, encryptedFields = []) => {
|
|
36527
|
+
const s = getWs();
|
|
36528
|
+
if (!s) return false;
|
|
36529
|
+
const wire = deps.e2ee && encryptedFields.length > 0 ? deps.e2ee.encryptFields(message, encryptedFields) : message;
|
|
36530
|
+
sendWsMessage(s, wire);
|
|
36531
|
+
return true;
|
|
36532
|
+
};
|
|
36533
|
+
const sendResult2 = (result) => {
|
|
36534
|
+
const skipEncryptForChangeSummaryFollowUp = result.type === "prompt_result" && result.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
|
|
36535
|
+
const encryptedFields = result.type === "prompt_result" && !skipEncryptForChangeSummaryFollowUp ? ["output", "error"] : [];
|
|
36536
|
+
sendBridgeMessage(result, encryptedFields);
|
|
36537
|
+
};
|
|
36538
|
+
const sendSessionUpdate = (payload) => {
|
|
36539
|
+
const s = getWs();
|
|
36540
|
+
if (!s) {
|
|
36541
|
+
deps.log("[Bridge service] Session update not sent: not connected to the bridge.");
|
|
36542
|
+
return;
|
|
36543
|
+
}
|
|
36544
|
+
const p = payload;
|
|
36545
|
+
const wire = p.type === "session_update" && deps.e2ee ? deps.e2ee.encryptFields(payload, ["payload"]) : p.type === "session_file_change" && deps.e2ee ? deps.e2ee.encryptFields(payload, [
|
|
36546
|
+
"path",
|
|
36547
|
+
"oldText",
|
|
36548
|
+
"newText",
|
|
36549
|
+
"patchContent",
|
|
36550
|
+
"isDirectory",
|
|
36551
|
+
"directoryRemoved"
|
|
36552
|
+
]) : payload;
|
|
36553
|
+
sendWsMessage(s, wire);
|
|
36554
|
+
};
|
|
36555
|
+
return { sendBridgeMessage, sendResult: sendResult2, sendSessionUpdate };
|
|
36556
|
+
}
|
|
36557
|
+
|
|
36558
|
+
// src/agents/acp/from-bridge/bridge-prompt-preamble.ts
|
|
35685
36559
|
import { execFile as execFile10 } from "node:child_process";
|
|
35686
36560
|
import { promisify as promisify10 } from "node:util";
|
|
35687
36561
|
|
|
35688
36562
|
// src/git/bridge-queue-key.ts
|
|
35689
|
-
import * as
|
|
35690
|
-
import { createHash } from "node:crypto";
|
|
36563
|
+
import * as path28 from "node:path";
|
|
36564
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
35691
36565
|
function normalizeCanonicalGitUrl(url2) {
|
|
35692
36566
|
let s = url2.trim();
|
|
35693
36567
|
if (!s) return s;
|
|
@@ -35711,14 +36585,14 @@ function normalizeCanonicalGitUrl(url2) {
|
|
|
35711
36585
|
}
|
|
35712
36586
|
function canonicalUrlToRepoIdSync(url2) {
|
|
35713
36587
|
const normalized = normalizeCanonicalGitUrl(url2);
|
|
35714
|
-
return
|
|
36588
|
+
return createHash2("sha256").update(normalized).digest("hex").slice(0, 32);
|
|
35715
36589
|
}
|
|
35716
36590
|
function fallbackRepoIdFromPath(absPath) {
|
|
35717
|
-
return
|
|
36591
|
+
return createHash2("sha256").update(path28.resolve(absPath)).digest("hex").slice(0, 32);
|
|
35718
36592
|
}
|
|
35719
36593
|
async function resolveBridgeQueueBindFields(options) {
|
|
35720
36594
|
const { effectiveCwd, worktreePaths, primaryRepoRoots, log: log2 } = options;
|
|
35721
|
-
const cwdAbs = worktreePaths.length > 0 ?
|
|
36595
|
+
const cwdAbs = worktreePaths.length > 0 ? path28.resolve(worktreePaths[0]) : path28.resolve(effectiveCwd);
|
|
35722
36596
|
if (!primaryRepoRoots.length) {
|
|
35723
36597
|
log2("[Bridge service] Prompt queue bind skipped: no Git repository roots under the working directory.");
|
|
35724
36598
|
return null;
|
|
@@ -35740,7 +36614,7 @@ async function resolveBridgeQueueBindFields(options) {
|
|
|
35740
36614
|
return { canonicalQueueKey, repoId, cwdAbs };
|
|
35741
36615
|
}
|
|
35742
36616
|
|
|
35743
|
-
// src/agents/acp/from-bridge/
|
|
36617
|
+
// src/agents/acp/from-bridge/bridge-prompt-preamble.ts
|
|
35744
36618
|
var execFileAsync9 = promisify10(execFile10);
|
|
35745
36619
|
async function readGitBranch(cwd) {
|
|
35746
36620
|
try {
|
|
@@ -35751,6 +36625,132 @@ async function readGitBranch(cwd) {
|
|
|
35751
36625
|
return null;
|
|
35752
36626
|
}
|
|
35753
36627
|
}
|
|
36628
|
+
async function runBridgePromptPreamble(params) {
|
|
36629
|
+
const { getWs, log: log2, sessionWorktreeManager, sessionId, runId, effectiveCwd } = params;
|
|
36630
|
+
const s = getWs();
|
|
36631
|
+
const worktreePaths = sessionWorktreeManager.getWorktreePathsForSession(sessionId) ?? [];
|
|
36632
|
+
const repoRoots = await resolveSnapshotRepoRoots({
|
|
36633
|
+
worktreePaths,
|
|
36634
|
+
fallbackCwd: effectiveCwd,
|
|
36635
|
+
log: log2
|
|
36636
|
+
});
|
|
36637
|
+
if (s && sessionId) {
|
|
36638
|
+
const bind = await resolveBridgeQueueBindFields({
|
|
36639
|
+
effectiveCwd,
|
|
36640
|
+
worktreePaths,
|
|
36641
|
+
primaryRepoRoots: repoRoots,
|
|
36642
|
+
log: log2
|
|
36643
|
+
});
|
|
36644
|
+
if (bind) {
|
|
36645
|
+
sendWsMessage(s, {
|
|
36646
|
+
type: "bridge_queue_bind",
|
|
36647
|
+
sessionId,
|
|
36648
|
+
canonicalQueueKey: bind.canonicalQueueKey,
|
|
36649
|
+
repoId: bind.repoId,
|
|
36650
|
+
cwdAbs: bind.cwdAbs
|
|
36651
|
+
});
|
|
36652
|
+
}
|
|
36653
|
+
}
|
|
36654
|
+
if (s && sessionId) {
|
|
36655
|
+
const cliGitBranch = await readGitBranch(effectiveCwd);
|
|
36656
|
+
sendWsMessage(s, {
|
|
36657
|
+
type: "session_git_context_report",
|
|
36658
|
+
sessionId,
|
|
36659
|
+
cliGitBranch,
|
|
36660
|
+
agentUsesWorktree: sessionWorktreeManager.usesWorktreeSession(sessionId)
|
|
36661
|
+
});
|
|
36662
|
+
}
|
|
36663
|
+
if (s && sessionId && runId) {
|
|
36664
|
+
const cap = repoRoots.length > 0 ? await capturePreTurnSnapshot({ runId, repoRoots, agentCwd: effectiveCwd, log: log2 }) : { ok: false, error: "No git repos" };
|
|
36665
|
+
sendWsMessage(s, {
|
|
36666
|
+
type: "pre_turn_snapshot_report",
|
|
36667
|
+
sessionId,
|
|
36668
|
+
turnId: runId,
|
|
36669
|
+
captured: cap.ok
|
|
36670
|
+
});
|
|
36671
|
+
}
|
|
36672
|
+
}
|
|
36673
|
+
function parseChangeSummarySnapshots(raw) {
|
|
36674
|
+
if (!Array.isArray(raw) || raw.length === 0) return void 0;
|
|
36675
|
+
const out = [];
|
|
36676
|
+
for (const item of raw) {
|
|
36677
|
+
if (!item || typeof item !== "object") continue;
|
|
36678
|
+
const o = item;
|
|
36679
|
+
const path34 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
36680
|
+
if (!path34) continue;
|
|
36681
|
+
const row = { path: path34 };
|
|
36682
|
+
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
36683
|
+
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
36684
|
+
if (typeof o.newText === "string") row.newText = o.newText;
|
|
36685
|
+
if (o.directoryRemoved === true) row.directoryRemoved = true;
|
|
36686
|
+
out.push(row);
|
|
36687
|
+
}
|
|
36688
|
+
return out.length > 0 ? out : void 0;
|
|
36689
|
+
}
|
|
36690
|
+
function parseFollowUpFieldsFromPromptMessage(msg) {
|
|
36691
|
+
const followUpCatalogPromptId = typeof msg.followUpCatalogPromptId === "string" && msg.followUpCatalogPromptId.trim() !== "" ? msg.followUpCatalogPromptId.trim() : null;
|
|
36692
|
+
const rawPaths = msg.sessionChangeSummaryFilePaths;
|
|
36693
|
+
const sessionChangeSummaryFilePaths = Array.isArray(rawPaths) ? rawPaths.filter((p) => typeof p === "string" && p.trim() !== "").map((p) => p.trim()) : void 0;
|
|
36694
|
+
const sessionChangeSummaryFileSnapshots = parseChangeSummarySnapshots(msg.sessionChangeSummaryFileSnapshots);
|
|
36695
|
+
return { followUpCatalogPromptId, sessionChangeSummaryFilePaths, sessionChangeSummaryFileSnapshots };
|
|
36696
|
+
}
|
|
36697
|
+
|
|
36698
|
+
// src/agents/acp/change-summary/decrypt-change-summary-file-input.ts
|
|
36699
|
+
function decryptChangeSummaryFileInput(row, e2ee) {
|
|
36700
|
+
if (!e2ee) return row;
|
|
36701
|
+
for (const field of ["path", "patchContent", "oldText", "newText"]) {
|
|
36702
|
+
const raw = row[field];
|
|
36703
|
+
if (typeof raw !== "string" || raw.trim() === "") continue;
|
|
36704
|
+
let o;
|
|
36705
|
+
try {
|
|
36706
|
+
o = JSON.parse(raw);
|
|
36707
|
+
} catch {
|
|
36708
|
+
continue;
|
|
36709
|
+
}
|
|
36710
|
+
if (!isE2eeEnvelope(o.ee)) continue;
|
|
36711
|
+
try {
|
|
36712
|
+
const d = e2ee.decryptMessage(o);
|
|
36713
|
+
const out = {
|
|
36714
|
+
path: typeof d.path === "string" ? d.path : row.path
|
|
36715
|
+
};
|
|
36716
|
+
if (d.directoryRemoved === true) out.directoryRemoved = true;
|
|
36717
|
+
else if (row.directoryRemoved === true) out.directoryRemoved = true;
|
|
36718
|
+
if (typeof d.patchContent === "string") out.patchContent = d.patchContent;
|
|
36719
|
+
else if (typeof row.patchContent === "string" && row.patchContent !== raw) out.patchContent = row.patchContent;
|
|
36720
|
+
if (typeof d.oldText === "string") out.oldText = d.oldText;
|
|
36721
|
+
else if (typeof row.oldText === "string") out.oldText = row.oldText;
|
|
36722
|
+
if (typeof d.newText === "string") out.newText = d.newText;
|
|
36723
|
+
else if (typeof row.newText === "string") out.newText = row.newText;
|
|
36724
|
+
return out;
|
|
36725
|
+
} catch {
|
|
36726
|
+
return row;
|
|
36727
|
+
}
|
|
36728
|
+
}
|
|
36729
|
+
return row;
|
|
36730
|
+
}
|
|
36731
|
+
|
|
36732
|
+
// src/agents/acp/change-summary/resolve-change-summary-prompt-for-agent.ts
|
|
36733
|
+
function hasSummarizePayload(f) {
|
|
36734
|
+
return f.directoryRemoved === true || f.patchContent != null && f.patchContent.trim() !== "" || f.oldText != null && f.oldText.trim() !== "" || f.newText != null && f.newText.trim() !== "";
|
|
36735
|
+
}
|
|
36736
|
+
function resolveChangeSummaryPromptForAgent(params) {
|
|
36737
|
+
const isBuiltin = params.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
|
|
36738
|
+
const snaps = params.sessionChangeSummaryFileSnapshots;
|
|
36739
|
+
if (!isBuiltin || !snaps || snaps.length === 0) {
|
|
36740
|
+
return { promptText: params.bridgePromptText, sessionChangeSummaryFilePaths: void 0 };
|
|
36741
|
+
}
|
|
36742
|
+
const decrypted = dedupeSessionFileChangesByPath(snaps.map((row) => decryptChangeSummaryFileInput(row, params.e2ee)));
|
|
36743
|
+
const withPayload = decrypted.filter(hasSummarizePayload);
|
|
36744
|
+
if (withPayload.length === 0) {
|
|
36745
|
+
return { promptText: params.bridgePromptText, sessionChangeSummaryFilePaths: void 0 };
|
|
36746
|
+
}
|
|
36747
|
+
return {
|
|
36748
|
+
promptText: buildSessionChangeSummaryPrompt(withPayload),
|
|
36749
|
+
sessionChangeSummaryFilePaths: withPayload.map((f) => f.path)
|
|
36750
|
+
};
|
|
36751
|
+
}
|
|
36752
|
+
|
|
36753
|
+
// src/agents/acp/from-bridge/handle-bridge-prompt.ts
|
|
35754
36754
|
function handleBridgePrompt(msg, deps) {
|
|
35755
36755
|
const { getWs, log: log2, acpManager, sessionWorktreeManager } = deps;
|
|
35756
36756
|
const rawPrompt = msg.prompt;
|
|
@@ -35758,21 +36758,22 @@ function handleBridgePrompt(msg, deps) {
|
|
|
35758
36758
|
const sessionId = msg.sessionId;
|
|
35759
36759
|
const runId = typeof msg.runId === "string" ? msg.runId : void 0;
|
|
35760
36760
|
const promptId = typeof msg.id === "string" ? msg.id : void 0;
|
|
36761
|
+
const { sendBridgeMessage, sendResult: sendResult2, sendSessionUpdate } = createBridgePromptSenders(deps, getWs);
|
|
35761
36762
|
if (!promptText.trim()) {
|
|
35762
36763
|
log2(
|
|
35763
36764
|
`[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).`
|
|
35764
36765
|
);
|
|
35765
|
-
|
|
35766
|
-
|
|
35767
|
-
sendWsMessage(s, {
|
|
36766
|
+
sendBridgeMessage(
|
|
36767
|
+
{
|
|
35768
36768
|
type: "prompt_result",
|
|
35769
36769
|
...promptId ? { id: promptId } : {},
|
|
35770
36770
|
...sessionId ? { sessionId } : {},
|
|
35771
36771
|
...runId ? { runId } : {},
|
|
35772
36772
|
success: false,
|
|
35773
36773
|
error: "Empty or missing prompt text from the bridge; this turn was not sent to the agent."
|
|
35774
|
-
}
|
|
35775
|
-
|
|
36774
|
+
},
|
|
36775
|
+
["error"]
|
|
36776
|
+
);
|
|
35776
36777
|
return;
|
|
35777
36778
|
}
|
|
35778
36779
|
const isNewSession = msg.isNewSession === true;
|
|
@@ -35780,65 +36781,35 @@ function handleBridgePrompt(msg, deps) {
|
|
|
35780
36781
|
const agentType = typeof msg.agentType === "string" && msg.agentType.trim() ? msg.agentType.trim() : void 0;
|
|
35781
36782
|
const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
|
|
35782
36783
|
acpManager.logPromptReceivedFromBridge({ agentType, mode });
|
|
35783
|
-
const sendResult2 = (result) => {
|
|
35784
|
-
const s = getWs();
|
|
35785
|
-
if (s) sendWsMessage(s, result);
|
|
35786
|
-
};
|
|
35787
|
-
const sendSessionUpdate = (payload) => {
|
|
35788
|
-
const s = getWs();
|
|
35789
|
-
if (!s) {
|
|
35790
|
-
log2("[Bridge service] Session update not sent: not connected to the bridge.");
|
|
35791
|
-
return;
|
|
35792
|
-
}
|
|
35793
|
-
const p = payload;
|
|
35794
|
-
sendWsMessage(s, payload);
|
|
35795
|
-
};
|
|
35796
36784
|
async function preambleAndPrompt(resolvedCwd) {
|
|
35797
|
-
const
|
|
35798
|
-
|
|
35799
|
-
|
|
35800
|
-
|
|
35801
|
-
|
|
35802
|
-
|
|
35803
|
-
|
|
36785
|
+
const effectiveCwd = path29.resolve(resolvedCwd ?? getBridgeWorkspaceDirectory());
|
|
36786
|
+
await runBridgePromptPreamble({
|
|
36787
|
+
getWs,
|
|
36788
|
+
log: log2,
|
|
36789
|
+
sessionWorktreeManager,
|
|
36790
|
+
sessionId,
|
|
36791
|
+
runId,
|
|
36792
|
+
effectiveCwd
|
|
35804
36793
|
});
|
|
35805
|
-
|
|
35806
|
-
|
|
35807
|
-
|
|
35808
|
-
|
|
35809
|
-
|
|
35810
|
-
|
|
35811
|
-
|
|
35812
|
-
|
|
35813
|
-
|
|
35814
|
-
|
|
35815
|
-
|
|
35816
|
-
|
|
35817
|
-
|
|
35818
|
-
|
|
35819
|
-
|
|
35820
|
-
}
|
|
35821
|
-
}
|
|
35822
|
-
if (s && sessionId) {
|
|
35823
|
-
const cliGitBranch = await readGitBranch(effectiveCwd);
|
|
35824
|
-
sendWsMessage(s, {
|
|
35825
|
-
type: "session_git_context_report",
|
|
35826
|
-
sessionId,
|
|
35827
|
-
cliGitBranch,
|
|
35828
|
-
agentUsesWorktree: sessionWorktreeManager.usesWorktreeSession(sessionId)
|
|
35829
|
-
});
|
|
35830
|
-
}
|
|
35831
|
-
if (s && sessionId && runId) {
|
|
35832
|
-
const cap = repoRoots.length > 0 ? await capturePreTurnSnapshot({ runId, repoRoots, agentCwd: effectiveCwd, log: log2 }) : { ok: false, error: "No git repos" };
|
|
35833
|
-
sendWsMessage(s, {
|
|
35834
|
-
type: "pre_turn_snapshot_report",
|
|
35835
|
-
sessionId,
|
|
35836
|
-
turnId: runId,
|
|
35837
|
-
captured: cap.ok
|
|
35838
|
-
});
|
|
36794
|
+
const {
|
|
36795
|
+
followUpCatalogPromptId,
|
|
36796
|
+
sessionChangeSummaryFilePaths: pathsFromBridge,
|
|
36797
|
+
sessionChangeSummaryFileSnapshots
|
|
36798
|
+
} = parseFollowUpFieldsFromPromptMessage(msg);
|
|
36799
|
+
const { promptText: resolvedPromptText, sessionChangeSummaryFilePaths } = resolveChangeSummaryPromptForAgent({
|
|
36800
|
+
followUpCatalogPromptId,
|
|
36801
|
+
sessionChangeSummaryFileSnapshots,
|
|
36802
|
+
bridgePromptText: promptText,
|
|
36803
|
+
e2ee: deps.e2ee
|
|
36804
|
+
});
|
|
36805
|
+
if (sessionChangeSummaryFileSnapshots && sessionChangeSummaryFileSnapshots.length > 0 && resolvedPromptText === promptText) {
|
|
36806
|
+
deps.log(
|
|
36807
|
+
"[Agent] Change-summary snapshots were present but the prompt was not rebuilt (decrypt failed or empty payloads); sending the bridge prompt as-is."
|
|
36808
|
+
);
|
|
35839
36809
|
}
|
|
36810
|
+
const pathsForUpload = sessionChangeSummaryFilePaths ?? pathsFromBridge;
|
|
35840
36811
|
acpManager.handlePrompt({
|
|
35841
|
-
promptText,
|
|
36812
|
+
promptText: resolvedPromptText,
|
|
35842
36813
|
promptId: msg.id,
|
|
35843
36814
|
sessionId,
|
|
35844
36815
|
runId,
|
|
@@ -35846,7 +36817,12 @@ function handleBridgePrompt(msg, deps) {
|
|
|
35846
36817
|
agentType,
|
|
35847
36818
|
cwd: effectiveCwd,
|
|
35848
36819
|
sendResult: sendResult2,
|
|
35849
|
-
sendSessionUpdate
|
|
36820
|
+
sendSessionUpdate,
|
|
36821
|
+
followUpCatalogPromptId,
|
|
36822
|
+
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
36823
|
+
cloudApiBaseUrl: deps.cloudApiBaseUrl,
|
|
36824
|
+
getCloudAccessToken: deps.getCloudAccessToken,
|
|
36825
|
+
e2ee: deps.e2ee
|
|
35850
36826
|
});
|
|
35851
36827
|
}
|
|
35852
36828
|
void sessionWorktreeManager.resolveCwdForPrompt(sessionId, { isNewSession, sessionWorktreesEnabled }).then((cwd) => preambleAndPrompt(cwd)).catch((err) => {
|
|
@@ -35903,8 +36879,8 @@ var PREVIEW_API_BASE_PATH = "/__preview";
|
|
|
35903
36879
|
var PREVIEW_SECRET_HEADER = "X-Preview-Secret";
|
|
35904
36880
|
var DEFAULT_PORT = 3e3;
|
|
35905
36881
|
var DEFAULT_COMMAND = "npm run preview";
|
|
35906
|
-
var PREVIEW_COMMAND_ENV = "
|
|
35907
|
-
var PREVIEW_PORT_ENV = "
|
|
36882
|
+
var PREVIEW_COMMAND_ENV = "BUILDAUTOMATON_PREVIEW_COMMAND";
|
|
36883
|
+
var PREVIEW_PORT_ENV = "BUILDAUTOMATON_PREVIEW_PORT";
|
|
35908
36884
|
var previewProcess = null;
|
|
35909
36885
|
var previewPort = DEFAULT_PORT;
|
|
35910
36886
|
var previewSecret = "";
|
|
@@ -35918,8 +36894,8 @@ function randomSecret() {
|
|
|
35918
36894
|
}
|
|
35919
36895
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
35920
36896
|
}
|
|
35921
|
-
async function requestPreviewApi(port, secret, method,
|
|
35922
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
36897
|
+
async function requestPreviewApi(port, secret, method, path34, body) {
|
|
36898
|
+
const url2 = `http://127.0.0.1:${port}${path34}`;
|
|
35923
36899
|
const headers = {
|
|
35924
36900
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
35925
36901
|
"Content-Type": "application/json"
|
|
@@ -35931,7 +36907,7 @@ async function requestPreviewApi(port, secret, method, path33, body) {
|
|
|
35931
36907
|
});
|
|
35932
36908
|
const data = await res.json().catch(() => ({}));
|
|
35933
36909
|
if (!res.ok) {
|
|
35934
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
36910
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path34}: ${res.status}`);
|
|
35935
36911
|
}
|
|
35936
36912
|
return data;
|
|
35937
36913
|
}
|
|
@@ -35957,7 +36933,7 @@ var OPERATIONS = [
|
|
|
35957
36933
|
var previewSkill = {
|
|
35958
36934
|
id: "preview",
|
|
35959
36935
|
name: "Preview",
|
|
35960
|
-
description: "Start and manage a local preview server that implements the BuildAutomaton Preview Server API. Configure the command with
|
|
36936
|
+
description: "Start and manage a local preview server that implements the BuildAutomaton Preview Server API. Configure the command with BUILDAUTOMATON_PREVIEW_COMMAND (default: npm run preview). The server receives PORT and PREVIEW_SECRET and must expose /__preview/status and /__preview/stop.",
|
|
35961
36937
|
operations: OPERATIONS,
|
|
35962
36938
|
async execute(operationId, params) {
|
|
35963
36939
|
const command = getPreviewCommand();
|
|
@@ -36094,15 +37070,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
36094
37070
|
};
|
|
36095
37071
|
|
|
36096
37072
|
// src/files/list-dir.ts
|
|
36097
|
-
import
|
|
36098
|
-
import
|
|
37073
|
+
import fs26 from "node:fs";
|
|
37074
|
+
import path31 from "node:path";
|
|
36099
37075
|
|
|
36100
37076
|
// src/files/ensure-under-cwd.ts
|
|
36101
|
-
import
|
|
37077
|
+
import path30 from "node:path";
|
|
36102
37078
|
function ensureUnderCwd(relativePath, cwd = getBridgeWorkspaceDirectory()) {
|
|
36103
|
-
const normalized =
|
|
36104
|
-
const resolved =
|
|
36105
|
-
if (!resolved.startsWith(cwd +
|
|
37079
|
+
const normalized = path30.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
37080
|
+
const resolved = path30.resolve(cwd, normalized);
|
|
37081
|
+
if (!resolved.startsWith(cwd + path30.sep) && resolved !== cwd) {
|
|
36106
37082
|
return null;
|
|
36107
37083
|
}
|
|
36108
37084
|
return resolved;
|
|
@@ -36116,7 +37092,7 @@ async function listDirAsync(relativePath) {
|
|
|
36116
37092
|
return { error: "Path is outside working directory" };
|
|
36117
37093
|
}
|
|
36118
37094
|
try {
|
|
36119
|
-
const names = await
|
|
37095
|
+
const names = await fs26.promises.readdir(resolved, { withFileTypes: true });
|
|
36120
37096
|
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
36121
37097
|
const entries = [];
|
|
36122
37098
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -36124,12 +37100,12 @@ async function listDirAsync(relativePath) {
|
|
|
36124
37100
|
await yieldToEventLoop();
|
|
36125
37101
|
}
|
|
36126
37102
|
const d = visible[i];
|
|
36127
|
-
const entryPath =
|
|
36128
|
-
const fullPath =
|
|
37103
|
+
const entryPath = path31.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
37104
|
+
const fullPath = path31.join(resolved, d.name);
|
|
36129
37105
|
let isDir = d.isDirectory();
|
|
36130
37106
|
if (d.isSymbolicLink()) {
|
|
36131
37107
|
try {
|
|
36132
|
-
const targetStat = await
|
|
37108
|
+
const targetStat = await fs26.promises.stat(fullPath);
|
|
36133
37109
|
isDir = targetStat.isDirectory();
|
|
36134
37110
|
} catch {
|
|
36135
37111
|
isDir = false;
|
|
@@ -36154,25 +37130,25 @@ async function listDirAsync(relativePath) {
|
|
|
36154
37130
|
}
|
|
36155
37131
|
|
|
36156
37132
|
// src/files/read-file.ts
|
|
36157
|
-
import
|
|
37133
|
+
import fs27 from "node:fs";
|
|
36158
37134
|
import { StringDecoder } from "node:string_decoder";
|
|
36159
37135
|
function resolveFilePath(relativePath) {
|
|
36160
37136
|
const resolved = ensureUnderCwd(relativePath, getBridgeWorkspaceDirectory());
|
|
36161
37137
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
36162
37138
|
let real;
|
|
36163
37139
|
try {
|
|
36164
|
-
real =
|
|
37140
|
+
real = fs27.realpathSync(resolved);
|
|
36165
37141
|
} catch {
|
|
36166
37142
|
real = resolved;
|
|
36167
37143
|
}
|
|
36168
|
-
const
|
|
36169
|
-
if (!
|
|
37144
|
+
const stat3 = fs27.statSync(real);
|
|
37145
|
+
if (!stat3.isFile()) return { error: "Not a file" };
|
|
36170
37146
|
return real;
|
|
36171
37147
|
}
|
|
36172
37148
|
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
36173
37149
|
function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
36174
|
-
const fileSize =
|
|
36175
|
-
const fd =
|
|
37150
|
+
const fileSize = fs27.statSync(filePath).size;
|
|
37151
|
+
const fd = fs27.openSync(filePath, "r");
|
|
36176
37152
|
const bufSize = 64 * 1024;
|
|
36177
37153
|
const buf = Buffer.alloc(bufSize);
|
|
36178
37154
|
const decoder = new StringDecoder("utf8");
|
|
@@ -36185,7 +37161,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
36185
37161
|
let line0Accum = "";
|
|
36186
37162
|
try {
|
|
36187
37163
|
let bytesRead;
|
|
36188
|
-
while (!done && (bytesRead =
|
|
37164
|
+
while (!done && (bytesRead = fs27.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
36189
37165
|
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
36190
37166
|
partial2 = "";
|
|
36191
37167
|
let lineStart = 0;
|
|
@@ -36320,10 +37296,10 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
36320
37296
|
}
|
|
36321
37297
|
return { content: resultLines.join("\n"), size: fileSize };
|
|
36322
37298
|
} finally {
|
|
36323
|
-
|
|
37299
|
+
fs27.closeSync(fd);
|
|
36324
37300
|
}
|
|
36325
37301
|
}
|
|
36326
|
-
function
|
|
37302
|
+
function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
36327
37303
|
try {
|
|
36328
37304
|
const result = resolveFilePath(relativePath);
|
|
36329
37305
|
if (typeof result === "object") return result;
|
|
@@ -36331,43 +37307,45 @@ function readFile2(relativePath, startLine, endLine, lineOffset, lineChunkSize =
|
|
|
36331
37307
|
if (hasRange) {
|
|
36332
37308
|
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
36333
37309
|
}
|
|
36334
|
-
const
|
|
36335
|
-
const raw =
|
|
37310
|
+
const stat3 = fs27.statSync(result);
|
|
37311
|
+
const raw = fs27.readFileSync(result, "utf8");
|
|
36336
37312
|
const lines = raw.split(/\r?\n/);
|
|
36337
|
-
return { content: raw, totalLines: lines.length, size:
|
|
37313
|
+
return { content: raw, totalLines: lines.length, size: stat3.size };
|
|
36338
37314
|
} catch (err) {
|
|
36339
37315
|
return { error: err instanceof Error ? err.message : String(err) };
|
|
36340
37316
|
}
|
|
36341
37317
|
}
|
|
36342
37318
|
async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
36343
37319
|
await yieldToEventLoop();
|
|
36344
|
-
return
|
|
37320
|
+
return readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize);
|
|
36345
37321
|
}
|
|
36346
37322
|
|
|
36347
37323
|
// src/files/handle-file-browser-search.ts
|
|
36348
37324
|
var SEARCH_LIMIT = 100;
|
|
36349
|
-
function handleFileBrowserSearch(msg, socket) {
|
|
37325
|
+
function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
36350
37326
|
void (async () => {
|
|
36351
37327
|
await yieldToEventLoop();
|
|
36352
37328
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
36353
37329
|
const cwd = getBridgeWorkspaceDirectory();
|
|
36354
37330
|
const index = loadFileIndex(cwd);
|
|
36355
37331
|
if (index === null) {
|
|
36356
|
-
|
|
37332
|
+
const payload2 = {
|
|
36357
37333
|
type: "file_browser_search_response",
|
|
36358
37334
|
id: msg.id,
|
|
36359
37335
|
paths: [],
|
|
36360
37336
|
indexReady: false
|
|
36361
|
-
}
|
|
37337
|
+
};
|
|
37338
|
+
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
|
|
36362
37339
|
return;
|
|
36363
37340
|
}
|
|
36364
37341
|
const results = await searchFileIndexAsync(index, q, SEARCH_LIMIT);
|
|
36365
|
-
|
|
37342
|
+
const payload = {
|
|
36366
37343
|
type: "file_browser_search_response",
|
|
36367
37344
|
id: msg.id,
|
|
36368
37345
|
paths: results,
|
|
36369
37346
|
indexReady: true
|
|
36370
|
-
}
|
|
37347
|
+
};
|
|
37348
|
+
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["paths"]) : payload);
|
|
36371
37349
|
})();
|
|
36372
37350
|
}
|
|
36373
37351
|
function triggerFileIndexBuild() {
|
|
@@ -36379,7 +37357,10 @@ function triggerFileIndexBuild() {
|
|
|
36379
37357
|
}
|
|
36380
37358
|
|
|
36381
37359
|
// src/files/handle-file-browser-request.ts
|
|
36382
|
-
function
|
|
37360
|
+
function sendFileBrowserMessage(socket, e2ee, payload) {
|
|
37361
|
+
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload, ["entries", "content", "totalLines", "size", "lineOffset"]) : payload);
|
|
37362
|
+
}
|
|
37363
|
+
function handleFileBrowserRequest(msg, socket, e2ee) {
|
|
36383
37364
|
void (async () => {
|
|
36384
37365
|
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
36385
37366
|
const op = msg.op === "read" ? "read" : "list";
|
|
@@ -36388,7 +37369,7 @@ function handleFileBrowserRequest(msg, socket) {
|
|
|
36388
37369
|
if ("error" in result) {
|
|
36389
37370
|
sendWsMessage(socket, { type: "file_browser_response", id: msg.id, error: result.error });
|
|
36390
37371
|
} else {
|
|
36391
|
-
|
|
37372
|
+
sendFileBrowserMessage(socket, e2ee, { type: "file_browser_response", id: msg.id, entries: result.entries });
|
|
36392
37373
|
if (reqPath === "." || reqPath === "") {
|
|
36393
37374
|
triggerFileIndexBuild();
|
|
36394
37375
|
}
|
|
@@ -36410,27 +37391,28 @@ function handleFileBrowserRequest(msg, socket) {
|
|
|
36410
37391
|
size: result.size
|
|
36411
37392
|
};
|
|
36412
37393
|
if (result.lineOffset != null) payload.lineOffset = result.lineOffset;
|
|
36413
|
-
|
|
37394
|
+
sendFileBrowserMessage(socket, e2ee, payload);
|
|
36414
37395
|
}
|
|
36415
37396
|
}
|
|
36416
37397
|
})();
|
|
36417
37398
|
}
|
|
36418
37399
|
|
|
36419
37400
|
// src/bridge/routing/handlers/file-browser-messages.ts
|
|
36420
|
-
function handleFileBrowserRequestMessage(msg, { getWs }) {
|
|
37401
|
+
function handleFileBrowserRequestMessage(msg, { getWs, e2ee }) {
|
|
36421
37402
|
if (typeof msg.id !== "string" || typeof msg.path !== "string") return;
|
|
36422
37403
|
const socket = getWs();
|
|
36423
37404
|
if (!socket) return;
|
|
36424
37405
|
handleFileBrowserRequest(
|
|
36425
37406
|
msg,
|
|
36426
|
-
socket
|
|
37407
|
+
socket,
|
|
37408
|
+
e2ee
|
|
36427
37409
|
);
|
|
36428
37410
|
}
|
|
36429
|
-
function handleFileBrowserSearchMessage(msg, { getWs }) {
|
|
37411
|
+
function handleFileBrowserSearchMessage(msg, { getWs, e2ee }) {
|
|
36430
37412
|
if (typeof msg.id !== "string") return;
|
|
36431
37413
|
const socket = getWs();
|
|
36432
37414
|
if (!socket) return;
|
|
36433
|
-
handleFileBrowserSearch(msg, socket);
|
|
37415
|
+
handleFileBrowserSearch(msg, socket, e2ee);
|
|
36434
37416
|
}
|
|
36435
37417
|
|
|
36436
37418
|
// src/bridge/routing/handlers/skill-layout-request.ts
|
|
@@ -36442,8 +37424,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
36442
37424
|
}
|
|
36443
37425
|
|
|
36444
37426
|
// src/skills/install-remote-skills.ts
|
|
36445
|
-
import
|
|
36446
|
-
import
|
|
37427
|
+
import fs28 from "node:fs";
|
|
37428
|
+
import path32 from "node:path";
|
|
36447
37429
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
36448
37430
|
const installed2 = [];
|
|
36449
37431
|
if (!Array.isArray(items)) {
|
|
@@ -36454,15 +37436,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
36454
37436
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
36455
37437
|
continue;
|
|
36456
37438
|
}
|
|
36457
|
-
const skillDir =
|
|
37439
|
+
const skillDir = path32.join(cwd, targetDir, item.skillName);
|
|
36458
37440
|
for (const f of item.files) {
|
|
36459
37441
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
36460
|
-
const dest =
|
|
36461
|
-
|
|
37442
|
+
const dest = path32.join(skillDir, f.path);
|
|
37443
|
+
fs28.mkdirSync(path32.dirname(dest), { recursive: true });
|
|
36462
37444
|
if (f.text !== void 0) {
|
|
36463
|
-
|
|
37445
|
+
fs28.writeFileSync(dest, f.text, "utf8");
|
|
36464
37446
|
} else if (f.base64) {
|
|
36465
|
-
|
|
37447
|
+
fs28.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
36466
37448
|
}
|
|
36467
37449
|
}
|
|
36468
37450
|
installed2.push({
|
|
@@ -36500,9 +37482,10 @@ var handleRefreshLocalSkills = (_msg, deps) => {
|
|
|
36500
37482
|
};
|
|
36501
37483
|
|
|
36502
37484
|
// src/bridge/routing/handlers/session-git-request.ts
|
|
36503
|
-
function sendResult(ws, id, payload) {
|
|
37485
|
+
function sendResult(ws, id, payload, e2ee, encryptedFields = []) {
|
|
36504
37486
|
if (!ws) return;
|
|
36505
|
-
|
|
37487
|
+
const message = { type: "session_git_result", id, ...payload };
|
|
37488
|
+
sendWsMessage(ws, e2ee && encryptedFields.length > 0 ? e2ee.encryptFields(message, encryptedFields) : message);
|
|
36506
37489
|
}
|
|
36507
37490
|
var handleSessionGitRequestMessage = (msg, deps) => {
|
|
36508
37491
|
if (typeof msg.id !== "string") return;
|
|
@@ -36512,7 +37495,7 @@ var handleSessionGitRequestMessage = (msg, deps) => {
|
|
|
36512
37495
|
return;
|
|
36513
37496
|
void (async () => {
|
|
36514
37497
|
const ws = deps.getWs();
|
|
36515
|
-
const reply = (payload) => sendResult(ws, msg.id, payload);
|
|
37498
|
+
const reply = (payload, encryptedFields = []) => sendResult(ws, msg.id, payload, deps.e2ee, encryptedFields);
|
|
36516
37499
|
try {
|
|
36517
37500
|
if (action === "status") {
|
|
36518
37501
|
const r = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
@@ -36538,7 +37521,7 @@ var handleSessionGitRequestMessage = (msg, deps) => {
|
|
|
36538
37521
|
reply({
|
|
36539
37522
|
ok: true,
|
|
36540
37523
|
repos
|
|
36541
|
-
});
|
|
37524
|
+
}, ["repos"]);
|
|
36542
37525
|
return;
|
|
36543
37526
|
}
|
|
36544
37527
|
if (action === "push") {
|
|
@@ -36607,7 +37590,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
36607
37590
|
};
|
|
36608
37591
|
|
|
36609
37592
|
// src/bridge/routing/handlers/revert-turn-snapshot.ts
|
|
36610
|
-
import * as
|
|
37593
|
+
import * as fs29 from "node:fs";
|
|
36611
37594
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
36612
37595
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
36613
37596
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -36619,7 +37602,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
36619
37602
|
if (!s) return;
|
|
36620
37603
|
const agentBase = sessionWorktreeManager.getAgentCwdForSession(sessionId) ?? getBridgeWorkspaceDirectory();
|
|
36621
37604
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
36622
|
-
if (!
|
|
37605
|
+
if (!fs29.existsSync(file2)) {
|
|
36623
37606
|
sendWsMessage(s, {
|
|
36624
37607
|
type: "revert_turn_snapshot_result",
|
|
36625
37608
|
id,
|
|
@@ -36640,8 +37623,15 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
36640
37623
|
|
|
36641
37624
|
// src/bridge/routing/handlers/dev-server-control.ts
|
|
36642
37625
|
var handleDevServerControl = (msg, deps) => {
|
|
36643
|
-
|
|
36644
|
-
|
|
37626
|
+
let wire = msg;
|
|
37627
|
+
try {
|
|
37628
|
+
wire = deps.e2ee ? deps.e2ee.decryptMessage(msg) : msg;
|
|
37629
|
+
} catch (e) {
|
|
37630
|
+
deps.log(`[E2EE] Could not decrypt dev server command: ${e instanceof Error ? e.message : String(e)}`);
|
|
37631
|
+
return;
|
|
37632
|
+
}
|
|
37633
|
+
const serverId = typeof wire.serverId === "string" ? wire.serverId : "";
|
|
37634
|
+
const action = wire.action === "start" || wire.action === "stop" ? wire.action : null;
|
|
36645
37635
|
if (!serverId || !action) return;
|
|
36646
37636
|
deps.devServerManager?.handleControl(serverId, action);
|
|
36647
37637
|
};
|
|
@@ -36767,7 +37757,8 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
36767
37757
|
messageDeps,
|
|
36768
37758
|
tokens,
|
|
36769
37759
|
persistTokens,
|
|
36770
|
-
onAuthInvalid
|
|
37760
|
+
onAuthInvalid,
|
|
37761
|
+
e2ee
|
|
36771
37762
|
} = params;
|
|
36772
37763
|
let authRefreshInFlight = false;
|
|
36773
37764
|
function handleOpen() {
|
|
@@ -36780,15 +37771,15 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
36780
37771
|
}
|
|
36781
37772
|
const socket = getWs();
|
|
36782
37773
|
if (socket) {
|
|
36783
|
-
sendWsMessage(socket, { type: "identify", role: "cli" });
|
|
37774
|
+
sendWsMessage(socket, { type: "identify", role: "cli", ...e2ee ? { e: e2ee.handshake } : {} });
|
|
36784
37775
|
reportGitRepos(getWs, logFn);
|
|
36785
37776
|
}
|
|
36786
37777
|
if (justAuthenticated && socket) {
|
|
36787
37778
|
logFn(
|
|
36788
37779
|
"Save these for future runs (access token may rotate; refresh token is stored in ~/.buildautomaton/config.json when you use browser auth):"
|
|
36789
37780
|
);
|
|
36790
|
-
logFn(` export
|
|
36791
|
-
logFn(` export
|
|
37781
|
+
logFn(` export BUILDAUTOMATON_AUTH_TOKEN="${tokens.accessToken}"`);
|
|
37782
|
+
logFn(` export BUILDAUTOMATON_WORKSPACE_ID="${workspaceId}"`);
|
|
36792
37783
|
}
|
|
36793
37784
|
}
|
|
36794
37785
|
function handleClose(code, reason) {
|
|
@@ -36903,7 +37894,8 @@ async function createBridgeConnection(options) {
|
|
|
36903
37894
|
function getWs() {
|
|
36904
37895
|
return state.currentWs;
|
|
36905
37896
|
}
|
|
36906
|
-
const
|
|
37897
|
+
const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
|
|
37898
|
+
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeCwd: getBridgeWorkspaceDirectory, e2ee });
|
|
36907
37899
|
const onBridgeIdentified = createOnBridgeIdentified({
|
|
36908
37900
|
sessionWorktreeManager,
|
|
36909
37901
|
devServerManager,
|
|
@@ -36922,7 +37914,10 @@ async function createBridgeConnection(options) {
|
|
|
36922
37914
|
onBridgeIdentified,
|
|
36923
37915
|
sendLocalSkillsReport,
|
|
36924
37916
|
reportAutoDetectedAgents,
|
|
36925
|
-
devServerManager
|
|
37917
|
+
devServerManager,
|
|
37918
|
+
e2ee,
|
|
37919
|
+
cloudApiBaseUrl: apiUrl,
|
|
37920
|
+
getCloudAccessToken: () => tokens.accessToken
|
|
36926
37921
|
};
|
|
36927
37922
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
36928
37923
|
state,
|
|
@@ -36934,7 +37929,8 @@ async function createBridgeConnection(options) {
|
|
|
36934
37929
|
messageDeps,
|
|
36935
37930
|
tokens,
|
|
36936
37931
|
persistTokens,
|
|
36937
|
-
onAuthInvalid
|
|
37932
|
+
onAuthInvalid,
|
|
37933
|
+
e2ee
|
|
36938
37934
|
});
|
|
36939
37935
|
connect();
|
|
36940
37936
|
const stopFileIndexWatcher = startFileIndexWatcher(getBridgeWorkspaceDirectory());
|
|
@@ -36946,14 +37942,149 @@ async function createBridgeConnection(options) {
|
|
|
36946
37942
|
};
|
|
36947
37943
|
}
|
|
36948
37944
|
|
|
37945
|
+
// src/e2e-certificates/key-command.ts
|
|
37946
|
+
import * as readline3 from "node:readline";
|
|
37947
|
+
function installE2eCertificateKeyCommand({
|
|
37948
|
+
log: log2,
|
|
37949
|
+
onOpenCertificate,
|
|
37950
|
+
onInterrupt
|
|
37951
|
+
}) {
|
|
37952
|
+
if (!process.stdin.isTTY || typeof process.stdin.setRawMode !== "function") {
|
|
37953
|
+
log2("[E2EE] Press c to import the E2EE key in a browser when running in an interactive terminal.");
|
|
37954
|
+
return () => {
|
|
37955
|
+
};
|
|
37956
|
+
}
|
|
37957
|
+
readline3.emitKeypressEvents(process.stdin);
|
|
37958
|
+
process.stdin.setRawMode(true);
|
|
37959
|
+
process.stdin.resume();
|
|
37960
|
+
const onKeypress = (str, key) => {
|
|
37961
|
+
if (key?.ctrl && key.name === "c") {
|
|
37962
|
+
onInterrupt();
|
|
37963
|
+
return;
|
|
37964
|
+
}
|
|
37965
|
+
if (!key?.ctrl && !key?.meta && (key?.name === "c" || str === "c")) {
|
|
37966
|
+
onOpenCertificate();
|
|
37967
|
+
}
|
|
37968
|
+
};
|
|
37969
|
+
process.stdin.on("keypress", onKeypress);
|
|
37970
|
+
log2("[E2EE] Press c to import the active E2EE key into the browser.");
|
|
37971
|
+
return () => {
|
|
37972
|
+
process.stdin.off("keypress", onKeypress);
|
|
37973
|
+
if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
|
|
37974
|
+
process.stdin.setRawMode(false);
|
|
37975
|
+
}
|
|
37976
|
+
};
|
|
37977
|
+
}
|
|
37978
|
+
|
|
37979
|
+
// src/e2e-certificates/open-import-url.ts
|
|
37980
|
+
async function openE2eCertificateImportUrl({
|
|
37981
|
+
apiUrl,
|
|
37982
|
+
workspaceId,
|
|
37983
|
+
certificate,
|
|
37984
|
+
log: log2
|
|
37985
|
+
}) {
|
|
37986
|
+
const appUrl = appUrlForApiUrl(apiUrl);
|
|
37987
|
+
const payload = encodeURIComponent(certificate.pemBundle);
|
|
37988
|
+
const url2 = `${appUrl.replace(/\/$/, "")}/w/${encodeURIComponent(workspaceId)}/settings/e2e-encryption?certificate=${payload}`;
|
|
37989
|
+
log2(`[E2EE] Opening browser to import key "${certificate.name}" (${certificate.id})...`);
|
|
37990
|
+
try {
|
|
37991
|
+
await open_default(url2, { wait: false });
|
|
37992
|
+
} catch {
|
|
37993
|
+
log2("[E2EE] Could not open browser. Open this URL manually:");
|
|
37994
|
+
log2(url2);
|
|
37995
|
+
}
|
|
37996
|
+
}
|
|
37997
|
+
|
|
37998
|
+
// src/run-bridge-connected.ts
|
|
37999
|
+
async function runConnectedBridge(options, restartWithoutAuth) {
|
|
38000
|
+
const {
|
|
38001
|
+
apiUrl,
|
|
38002
|
+
workspaceId,
|
|
38003
|
+
authToken,
|
|
38004
|
+
refreshToken,
|
|
38005
|
+
justAuthenticated,
|
|
38006
|
+
worktreesRootAbs,
|
|
38007
|
+
e2eCertificate
|
|
38008
|
+
} = options;
|
|
38009
|
+
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
38010
|
+
let cleanupKeyCommand;
|
|
38011
|
+
const handle = await createBridgeConnection({
|
|
38012
|
+
apiUrl,
|
|
38013
|
+
workspaceId,
|
|
38014
|
+
authToken,
|
|
38015
|
+
refreshToken,
|
|
38016
|
+
firehoseServerUrl,
|
|
38017
|
+
justAuthenticated,
|
|
38018
|
+
worktreesRootAbs,
|
|
38019
|
+
e2eCertificate,
|
|
38020
|
+
log,
|
|
38021
|
+
persistTokens: (t) => {
|
|
38022
|
+
writeConfigForApi(apiUrl, {
|
|
38023
|
+
workspaceId,
|
|
38024
|
+
token: t.token,
|
|
38025
|
+
refreshToken: t.refreshToken
|
|
38026
|
+
});
|
|
38027
|
+
},
|
|
38028
|
+
onAuthInvalid: () => {
|
|
38029
|
+
cleanupKeyCommand?.();
|
|
38030
|
+
log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
|
|
38031
|
+
clearConfigForApi(apiUrl);
|
|
38032
|
+
void handle.close().then(() => {
|
|
38033
|
+
void restartWithoutAuth({ apiUrl, firehoseServerUrl, worktreesRootAbs, e2eCertificate });
|
|
38034
|
+
});
|
|
38035
|
+
}
|
|
38036
|
+
});
|
|
38037
|
+
const onSignal = (kind) => {
|
|
38038
|
+
cleanupKeyCommand?.();
|
|
38039
|
+
logImmediate(
|
|
38040
|
+
kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
|
|
38041
|
+
);
|
|
38042
|
+
setImmediate(() => {
|
|
38043
|
+
void handle.close().then(() => {
|
|
38044
|
+
process.exit(0);
|
|
38045
|
+
});
|
|
38046
|
+
});
|
|
38047
|
+
};
|
|
38048
|
+
const onSigInt = () => onSignal("interrupt");
|
|
38049
|
+
const onSigTerm = () => onSignal("stop");
|
|
38050
|
+
process.on("SIGINT", onSigInt);
|
|
38051
|
+
process.on("SIGTERM", onSigTerm);
|
|
38052
|
+
if (e2eCertificate) {
|
|
38053
|
+
let openingCertificate = false;
|
|
38054
|
+
cleanupKeyCommand = installE2eCertificateKeyCommand({
|
|
38055
|
+
log,
|
|
38056
|
+
onInterrupt: onSigInt,
|
|
38057
|
+
onOpenCertificate: () => {
|
|
38058
|
+
if (openingCertificate) return;
|
|
38059
|
+
openingCertificate = true;
|
|
38060
|
+
void openE2eCertificateImportUrl({
|
|
38061
|
+
apiUrl,
|
|
38062
|
+
workspaceId,
|
|
38063
|
+
certificate: e2eCertificate,
|
|
38064
|
+
log
|
|
38065
|
+
}).finally(() => {
|
|
38066
|
+
openingCertificate = false;
|
|
38067
|
+
});
|
|
38068
|
+
}
|
|
38069
|
+
});
|
|
38070
|
+
}
|
|
38071
|
+
}
|
|
38072
|
+
|
|
36949
38073
|
// src/run-bridge.ts
|
|
36950
38074
|
async function runBridge(options) {
|
|
36951
38075
|
installBridgeProcessResilience();
|
|
36952
|
-
const {
|
|
38076
|
+
const {
|
|
38077
|
+
apiUrl,
|
|
38078
|
+
workspaceId,
|
|
38079
|
+
authToken,
|
|
38080
|
+
bridgeName,
|
|
38081
|
+
worktreesRootAbs,
|
|
38082
|
+
e2eCertificate
|
|
38083
|
+
} = options;
|
|
36953
38084
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
36954
38085
|
const hasAuth = workspaceId && authToken;
|
|
36955
38086
|
if (!hasAuth) {
|
|
36956
|
-
const
|
|
38087
|
+
const handle = runPendingAuth({
|
|
36957
38088
|
apiUrl,
|
|
36958
38089
|
initialWorkspaceId: workspaceId,
|
|
36959
38090
|
preferredBridgeName: bridgeName,
|
|
@@ -36961,23 +38092,23 @@ async function runBridge(options) {
|
|
|
36961
38092
|
onAuth: (_auth) => {
|
|
36962
38093
|
}
|
|
36963
38094
|
});
|
|
36964
|
-
const
|
|
38095
|
+
const onSignal = (kind) => {
|
|
36965
38096
|
logImmediate(
|
|
36966
38097
|
kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
|
|
36967
38098
|
);
|
|
36968
38099
|
setImmediate(() => {
|
|
36969
|
-
|
|
38100
|
+
handle.close();
|
|
36970
38101
|
process.exit(0);
|
|
36971
38102
|
});
|
|
36972
38103
|
};
|
|
36973
|
-
const
|
|
36974
|
-
const
|
|
36975
|
-
process.on("SIGINT",
|
|
36976
|
-
process.on("SIGTERM",
|
|
36977
|
-
const auth = await
|
|
36978
|
-
process.off("SIGINT",
|
|
36979
|
-
process.off("SIGTERM",
|
|
36980
|
-
|
|
38104
|
+
const onSigInt = () => onSignal("interrupt");
|
|
38105
|
+
const onSigTerm = () => onSignal("stop");
|
|
38106
|
+
process.on("SIGINT", onSigInt);
|
|
38107
|
+
process.on("SIGTERM", onSigTerm);
|
|
38108
|
+
const auth = await handle.authPromise;
|
|
38109
|
+
process.off("SIGINT", onSigInt);
|
|
38110
|
+
process.off("SIGTERM", onSigTerm);
|
|
38111
|
+
handle.close();
|
|
36981
38112
|
if (!auth) return;
|
|
36982
38113
|
writeConfigForApi(apiUrl, {
|
|
36983
38114
|
workspaceId: auth.workspaceId,
|
|
@@ -36992,111 +38123,91 @@ async function runBridge(options) {
|
|
|
36992
38123
|
firehoseServerUrl,
|
|
36993
38124
|
bridgeName,
|
|
36994
38125
|
justAuthenticated: true,
|
|
36995
|
-
worktreesRootAbs
|
|
38126
|
+
worktreesRootAbs,
|
|
38127
|
+
e2eCertificate
|
|
36996
38128
|
});
|
|
36997
38129
|
return;
|
|
36998
38130
|
}
|
|
36999
|
-
|
|
38131
|
+
await runConnectedBridge(options, runBridge);
|
|
38132
|
+
}
|
|
38133
|
+
|
|
38134
|
+
// src/cli/run-cli-action.ts
|
|
38135
|
+
async function runCliAction(program2, opts) {
|
|
38136
|
+
const positionalUrl = program2.args?.[0];
|
|
38137
|
+
const urlFromPositional = typeof positionalUrl === "string" && /^https?:\/\//i.test(positionalUrl) ? positionalUrl : void 0;
|
|
38138
|
+
const apiUrlFromCli = opts.apiUrl ?? urlFromPositional;
|
|
38139
|
+
const apiUrl = apiUrlFromCli ?? DEFAULT_API_URL;
|
|
38140
|
+
let workspaceId = opts.workspaceId ?? "";
|
|
38141
|
+
let authToken = opts.token;
|
|
38142
|
+
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
38143
|
+
if (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim()) {
|
|
38144
|
+
const resolvedCwd = path33.resolve(process.cwd(), opts.cwd.trim());
|
|
38145
|
+
try {
|
|
38146
|
+
const st = fs30.statSync(resolvedCwd);
|
|
38147
|
+
if (!st.isDirectory()) {
|
|
38148
|
+
console.error(`--cwd is not a directory: ${resolvedCwd}`);
|
|
38149
|
+
process.exit(1);
|
|
38150
|
+
}
|
|
38151
|
+
} catch {
|
|
38152
|
+
console.error(`--cwd path does not exist or is not accessible: ${resolvedCwd}`);
|
|
38153
|
+
process.exit(1);
|
|
38154
|
+
}
|
|
38155
|
+
process.chdir(resolvedCwd);
|
|
38156
|
+
}
|
|
38157
|
+
initBridgeWorkspaceDirectory();
|
|
38158
|
+
let worktreesRootAbs;
|
|
38159
|
+
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
38160
|
+
worktreesRootAbs = path33.resolve(opts.worktreesRoot.trim());
|
|
38161
|
+
}
|
|
38162
|
+
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
38163
|
+
if (e2eCertificates) {
|
|
38164
|
+
const action = e2eCertificates.generated ? "Generated" : "Loaded";
|
|
38165
|
+
console.log(
|
|
38166
|
+
`[E2EE] ${action} ${e2eCertificates.certificates.length} key${e2eCertificates.certificates.length === 1 ? "" : "s"} from ${e2eCertificates.directory}`
|
|
38167
|
+
);
|
|
38168
|
+
console.log(
|
|
38169
|
+
`[E2EE] Active key: ${e2eCertificates.activeCertificate.name} (${e2eCertificates.activeCertificate.id})`
|
|
38170
|
+
);
|
|
38171
|
+
}
|
|
38172
|
+
let refreshToken;
|
|
38173
|
+
if ((!workspaceId || !authToken) && opts.config !== false) {
|
|
38174
|
+
const saved = readConfigForApi(apiUrl);
|
|
38175
|
+
if (saved?.workspaceId && saved?.token) {
|
|
38176
|
+
if (!workspaceId) workspaceId = saved.workspaceId;
|
|
38177
|
+
if (!authToken) authToken = saved.token;
|
|
38178
|
+
refreshToken = saved.refreshToken;
|
|
38179
|
+
}
|
|
38180
|
+
}
|
|
38181
|
+
await runBridge({
|
|
37000
38182
|
apiUrl,
|
|
37001
|
-
workspaceId,
|
|
38183
|
+
workspaceId: workspaceId || void 0,
|
|
37002
38184
|
authToken,
|
|
37003
38185
|
refreshToken,
|
|
37004
38186
|
firehoseServerUrl,
|
|
37005
|
-
|
|
38187
|
+
bridgeName: opts.name?.trim() || void 0,
|
|
37006
38188
|
worktreesRootAbs,
|
|
37007
|
-
|
|
37008
|
-
persistTokens: (t) => {
|
|
37009
|
-
writeConfigForApi(apiUrl, {
|
|
37010
|
-
workspaceId,
|
|
37011
|
-
token: t.token,
|
|
37012
|
-
refreshToken: t.refreshToken
|
|
37013
|
-
});
|
|
37014
|
-
},
|
|
37015
|
-
onAuthInvalid: () => {
|
|
37016
|
-
log("[Bridge service] Access token invalid or revoked; re-authenticating\u2026");
|
|
37017
|
-
clearConfigForApi(apiUrl);
|
|
37018
|
-
void handle.close().then(() => {
|
|
37019
|
-
void runBridge({ apiUrl, firehoseServerUrl, worktreesRootAbs });
|
|
37020
|
-
});
|
|
37021
|
-
}
|
|
38189
|
+
e2eCertificate: e2eCertificates?.activeCertificate
|
|
37022
38190
|
});
|
|
37023
|
-
const onSignal = (kind) => {
|
|
37024
|
-
logImmediate(
|
|
37025
|
-
kind === "interrupt" ? "Keyboard interrupt (Ctrl+C) \u2014 stopping\u2026" : "Stop requested \u2014 shutting down\u2026"
|
|
37026
|
-
);
|
|
37027
|
-
setImmediate(() => {
|
|
37028
|
-
void handle.close().then(() => {
|
|
37029
|
-
process.exit(0);
|
|
37030
|
-
});
|
|
37031
|
-
});
|
|
37032
|
-
};
|
|
37033
|
-
const onSigInt = () => onSignal("interrupt");
|
|
37034
|
-
const onSigTerm = () => onSignal("stop");
|
|
37035
|
-
process.on("SIGINT", onSigInt);
|
|
37036
|
-
process.on("SIGTERM", onSigTerm);
|
|
37037
38191
|
}
|
|
37038
38192
|
|
|
37039
38193
|
// src/cli.ts
|
|
37040
|
-
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
37041
|
-
var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
37042
38194
|
async function main() {
|
|
37043
38195
|
const program2 = new Command();
|
|
37044
|
-
program2.name("buildautomaton").description("CLI for BuildAutomaton: ACP client, WebSocket bridge to backend, and skills (e.g. preview)").version("0.1.0").option("-u, --api-url <url>", "Backend API URL", process.env.BUILDAUTOMATON_API_URL ?? DEFAULT_API_URL).option("-w, --workspace-id <id>", "Workspace ID (or set
|
|
38196
|
+
program2.name("buildautomaton").description("CLI for BuildAutomaton: ACP client, WebSocket bridge to backend, and skills (e.g. preview)").version("0.1.0").option("-u, --api-url <url>", "Backend API URL", process.env.BUILDAUTOMATON_API_URL ?? DEFAULT_API_URL).option("-w, --workspace-id <id>", "Workspace ID (or set BUILDAUTOMATON_WORKSPACE_ID)", process.env.BUILDAUTOMATON_WORKSPACE_ID).option("-t, --token <token>", "Auth token (or set BUILDAUTOMATON_AUTH_TOKEN)", process.env.BUILDAUTOMATON_AUTH_TOKEN).option(
|
|
37045
38197
|
"--firehose-url <url>",
|
|
37046
|
-
"Firehose server URL (default: Fly app; or
|
|
37047
|
-
process.env.
|
|
38198
|
+
"Firehose server URL (default: Fly app; or BUILDAUTOMATON_FIREHOSE_URL / legacy BUILDAUTOMATON_PROXY_URL)",
|
|
38199
|
+
process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL
|
|
37048
38200
|
).option("--proxy-url <url>", "Deprecated alias for --firehose-url", void 0).option(
|
|
37049
38201
|
"--cwd <path>",
|
|
37050
38202
|
"Working directory for the bridge (absolute or relative to the current directory); affects skills, git, file index, and agent cwd"
|
|
37051
38203
|
).option("-n, --name <name>", "Bridge name when creating via browser (alphanumeric and underscores only)").option(
|
|
37052
38204
|
"--worktrees-root <path>",
|
|
37053
38205
|
"Root directory for per-session git worktrees (default: ~/.buildautomaton/worktrees). Whether worktrees are used is controlled in the cloud for each bridge token."
|
|
37054
|
-
).option(
|
|
37055
|
-
|
|
37056
|
-
|
|
37057
|
-
|
|
37058
|
-
|
|
37059
|
-
let workspaceId = opts.workspaceId ?? "";
|
|
37060
|
-
let authToken = opts.token;
|
|
37061
|
-
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAMATON_FIREHOSE_URL ?? process.env.BUILDAMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
37062
|
-
if (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim()) {
|
|
37063
|
-
const resolvedCwd = path32.resolve(process.cwd(), opts.cwd.trim());
|
|
37064
|
-
try {
|
|
37065
|
-
const st = fs29.statSync(resolvedCwd);
|
|
37066
|
-
if (!st.isDirectory()) {
|
|
37067
|
-
console.error(`--cwd is not a directory: ${resolvedCwd}`);
|
|
37068
|
-
process.exit(1);
|
|
37069
|
-
}
|
|
37070
|
-
} catch {
|
|
37071
|
-
console.error(`--cwd path does not exist or is not accessible: ${resolvedCwd}`);
|
|
37072
|
-
process.exit(1);
|
|
37073
|
-
}
|
|
37074
|
-
process.chdir(resolvedCwd);
|
|
37075
|
-
}
|
|
37076
|
-
initBridgeWorkspaceDirectory();
|
|
37077
|
-
let worktreesRootAbs;
|
|
37078
|
-
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
37079
|
-
worktreesRootAbs = path32.resolve(opts.worktreesRoot.trim());
|
|
37080
|
-
}
|
|
37081
|
-
let refreshToken;
|
|
37082
|
-
if ((!workspaceId || !authToken) && opts.config !== false) {
|
|
37083
|
-
const saved = readConfigForApi(apiUrl);
|
|
37084
|
-
if (saved?.workspaceId && saved?.token) {
|
|
37085
|
-
if (!workspaceId) workspaceId = saved.workspaceId;
|
|
37086
|
-
if (!authToken) authToken = saved.token;
|
|
37087
|
-
refreshToken = saved.refreshToken;
|
|
37088
|
-
}
|
|
37089
|
-
}
|
|
37090
|
-
await runBridge({
|
|
37091
|
-
apiUrl,
|
|
37092
|
-
workspaceId: workspaceId || void 0,
|
|
37093
|
-
authToken,
|
|
37094
|
-
refreshToken,
|
|
37095
|
-
firehoseServerUrl,
|
|
37096
|
-
bridgeName: opts.name?.trim() || void 0,
|
|
37097
|
-
worktreesRootAbs
|
|
37098
|
-
});
|
|
37099
|
-
});
|
|
38206
|
+
).option(
|
|
38207
|
+
"--e2ee-certificates-dir <path>",
|
|
38208
|
+
"Directory to load or generate E2EE keys for sessions, files, and logs",
|
|
38209
|
+
process.env.BUILDAUTOMATON_E2EE_CERTIFICATES_DIR
|
|
38210
|
+
).option("--no-config", "Ignore saved config at ~/.buildautomaton/config.json").action(async (opts) => runCliAction(program2, opts));
|
|
37100
38211
|
await program2.parseAsync(process.argv);
|
|
37101
38212
|
}
|
|
37102
38213
|
main().catch((err) => {
|