@buildautomaton/cli 0.1.28 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1238 -651
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1203 -616
- package/dist/index.js.map +4 -4
- package/dist/migrations/000_bootstrap_migrations_table.sql +4 -0
- package/dist/migrations/001_cli_sqlite_checkpoint_v1.sql +20 -0
- package/dist/migrations/002_acp_capability_cache.sql +10 -0
- package/dist/migrations/002_agent_capabilities.sql +10 -0
- package/dist/migrations/002_agent_capability_cache.sql +10 -0
- package/package.json +3 -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 path43 = __require("node:path");
|
|
977
|
+
var fs38 = __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 = path43.resolve(baseDir, baseName);
|
|
1910
|
+
if (fs38.existsSync(localBin)) return localBin;
|
|
1911
|
+
if (sourceExt.includes(path43.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
|
-
(ext) =>
|
|
1913
|
+
(ext) => fs38.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 = fs38.realpathSync(this._scriptPath);
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
1929
|
-
executableDir =
|
|
1930
|
-
|
|
1929
|
+
executableDir = path43.resolve(
|
|
1930
|
+
path43.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 = path43.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path43.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(path43.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 = path43.basename(filename, path43.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(path44) {
|
|
2805
|
+
if (path44 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path44;
|
|
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: randomBytes3, 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();
|
|
@@ -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",
|
|
@@ -7061,8 +7061,8 @@ var init_parseUtil = __esm({
|
|
|
7061
7061
|
init_errors();
|
|
7062
7062
|
init_en();
|
|
7063
7063
|
makeIssue = (params) => {
|
|
7064
|
-
const { data, path:
|
|
7065
|
-
const fullPath = [...
|
|
7064
|
+
const { data, path: path43, errorMaps, issueData } = params;
|
|
7065
|
+
const fullPath = [...path43, ...issueData.path || []];
|
|
7066
7066
|
const fullIssue = {
|
|
7067
7067
|
...issueData,
|
|
7068
7068
|
path: fullPath
|
|
@@ -7370,11 +7370,11 @@ var init_types = __esm({
|
|
|
7370
7370
|
init_parseUtil();
|
|
7371
7371
|
init_util();
|
|
7372
7372
|
ParseInputLazyPath = class {
|
|
7373
|
-
constructor(parent, value,
|
|
7373
|
+
constructor(parent, value, path43, key) {
|
|
7374
7374
|
this._cachedPath = [];
|
|
7375
7375
|
this.parent = parent;
|
|
7376
7376
|
this.data = value;
|
|
7377
|
-
this._path =
|
|
7377
|
+
this._path = path43;
|
|
7378
7378
|
this._key = key;
|
|
7379
7379
|
}
|
|
7380
7380
|
get path() {
|
|
@@ -11235,7 +11235,7 @@ var require_has_flag = __commonJS({
|
|
|
11235
11235
|
var require_supports_color = __commonJS({
|
|
11236
11236
|
"../../node_modules/.pnpm/supports-color@7.2.0/node_modules/supports-color/index.js"(exports, module) {
|
|
11237
11237
|
"use strict";
|
|
11238
|
-
var
|
|
11238
|
+
var os9 = __require("os");
|
|
11239
11239
|
var tty = __require("tty");
|
|
11240
11240
|
var hasFlag = require_has_flag();
|
|
11241
11241
|
var { env } = process;
|
|
@@ -11283,7 +11283,7 @@ var require_supports_color = __commonJS({
|
|
|
11283
11283
|
return min;
|
|
11284
11284
|
}
|
|
11285
11285
|
if (process.platform === "win32") {
|
|
11286
|
-
const osRelease =
|
|
11286
|
+
const osRelease = os9.release().split(".");
|
|
11287
11287
|
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
11288
11288
|
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
11289
11289
|
}
|
|
@@ -11529,10 +11529,10 @@ var require_src2 = __commonJS({
|
|
|
11529
11529
|
var fs_1 = __require("fs");
|
|
11530
11530
|
var debug_1 = __importDefault(require_src());
|
|
11531
11531
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
11532
|
-
function check2(
|
|
11533
|
-
log2(`checking %s`,
|
|
11532
|
+
function check2(path43, isFile, isDirectory) {
|
|
11533
|
+
log2(`checking %s`, path43);
|
|
11534
11534
|
try {
|
|
11535
|
-
const stat3 = fs_1.statSync(
|
|
11535
|
+
const stat3 = fs_1.statSync(path43);
|
|
11536
11536
|
if (stat3.isFile() && isFile) {
|
|
11537
11537
|
log2(`[OK] path represents a file`);
|
|
11538
11538
|
return true;
|
|
@@ -11552,8 +11552,8 @@ var require_src2 = __commonJS({
|
|
|
11552
11552
|
throw e;
|
|
11553
11553
|
}
|
|
11554
11554
|
}
|
|
11555
|
-
function exists2(
|
|
11556
|
-
return check2(
|
|
11555
|
+
function exists2(path43, type = exports.READABLE) {
|
|
11556
|
+
return check2(path43, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
11557
11557
|
}
|
|
11558
11558
|
exports.exists = exists2;
|
|
11559
11559
|
exports.FILE = 1;
|
|
@@ -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, path43) {
|
|
11854
|
+
if (!path43)
|
|
11855
11855
|
return obj;
|
|
11856
|
-
return
|
|
11856
|
+
return path43.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(path43, 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(path43);
|
|
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, path43 = []) => {
|
|
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 = [...path43, ...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(path43) {
|
|
12339
12339
|
const segs = [];
|
|
12340
|
-
for (const seg of
|
|
12340
|
+
for (const seg of path43) {
|
|
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((resolve20) => {
|
|
24804
|
+
this.#abortController.signal.addEventListener("abort", () => resolve20());
|
|
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((resolve20, reject) => {
|
|
24954
|
+
this.#pendingResponses.set(id, { resolve: resolve20, reject });
|
|
24955
24955
|
});
|
|
24956
24956
|
await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
|
|
24957
24957
|
return responsePromise;
|
|
@@ -25064,15 +25064,15 @@ var {
|
|
|
25064
25064
|
} = import_index.default;
|
|
25065
25065
|
|
|
25066
25066
|
// src/cli-version.ts
|
|
25067
|
-
var CLI_VERSION = "0.1.
|
|
25067
|
+
var CLI_VERSION = "0.1.30".length > 0 ? "0.1.30" : "0.0.0-dev";
|
|
25068
25068
|
|
|
25069
25069
|
// src/cli/defaults.ts
|
|
25070
25070
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
25071
25071
|
var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
25072
25072
|
|
|
25073
25073
|
// src/cli/run-cli-action.ts
|
|
25074
|
-
import * as
|
|
25075
|
-
import * as
|
|
25074
|
+
import * as fs37 from "node:fs";
|
|
25075
|
+
import * as path42 from "node:path";
|
|
25076
25076
|
|
|
25077
25077
|
// src/cli-log-level.ts
|
|
25078
25078
|
var verbosity = "info";
|
|
@@ -26077,14 +26077,14 @@ var baseOpen = async (options) => {
|
|
|
26077
26077
|
}
|
|
26078
26078
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
26079
26079
|
if (options.wait) {
|
|
26080
|
-
return new Promise((
|
|
26080
|
+
return new Promise((resolve20, reject) => {
|
|
26081
26081
|
subprocess.once("error", reject);
|
|
26082
26082
|
subprocess.once("close", (exitCode) => {
|
|
26083
26083
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
26084
26084
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
26085
26085
|
return;
|
|
26086
26086
|
}
|
|
26087
|
-
|
|
26087
|
+
resolve20(subprocess);
|
|
26088
26088
|
});
|
|
26089
26089
|
});
|
|
26090
26090
|
}
|
|
@@ -26573,8 +26573,8 @@ function runPendingAuth(options) {
|
|
|
26573
26573
|
let hasOpenedBrowser = false;
|
|
26574
26574
|
let resolved = false;
|
|
26575
26575
|
let resolveAuth;
|
|
26576
|
-
const authPromise = new Promise((
|
|
26577
|
-
resolveAuth =
|
|
26576
|
+
const authPromise = new Promise((resolve20) => {
|
|
26577
|
+
resolveAuth = resolve20;
|
|
26578
26578
|
});
|
|
26579
26579
|
let reconnectAttempt = 0;
|
|
26580
26580
|
const signInQuiet = createEmptyReconnectQuietSlot();
|
|
@@ -26696,11 +26696,353 @@ function runPendingAuth(options) {
|
|
|
26696
26696
|
};
|
|
26697
26697
|
}
|
|
26698
26698
|
|
|
26699
|
+
// src/sqlite/cli-database.ts
|
|
26700
|
+
import sqliteWasm from "node-sqlite3-wasm";
|
|
26701
|
+
|
|
26702
|
+
// src/sqlite/cli-sqlite-paths.ts
|
|
26703
|
+
import fs8 from "node:fs";
|
|
26704
|
+
import path5 from "node:path";
|
|
26705
|
+
import os3 from "node:os";
|
|
26706
|
+
function getCliSqlitePath() {
|
|
26707
|
+
const override = process.env.BUILDAMATON_CLI_SQLITE_PATH?.trim();
|
|
26708
|
+
if (override) return path5.resolve(override);
|
|
26709
|
+
return path5.join(os3.homedir(), ".buildautomaton", "cli.sqlite");
|
|
26710
|
+
}
|
|
26711
|
+
function ensureCliSqliteParentDir(sqlitePath) {
|
|
26712
|
+
const dir = path5.dirname(sqlitePath);
|
|
26713
|
+
if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
|
|
26714
|
+
}
|
|
26715
|
+
|
|
26716
|
+
// src/sqlite/legacy_migration/import-cli-legacy-disk-data.ts
|
|
26717
|
+
import fs13 from "node:fs";
|
|
26718
|
+
|
|
26719
|
+
// src/files/index/constants.ts
|
|
26720
|
+
import path6 from "node:path";
|
|
26721
|
+
import os4 from "node:os";
|
|
26722
|
+
var INDEX_WORK_YIELD_EVERY = 256;
|
|
26723
|
+
var INDEX_DIR = path6.join(os4.homedir(), ".buildautomaton");
|
|
26724
|
+
var INDEX_HASH_LEN = 16;
|
|
26725
|
+
|
|
26726
|
+
// src/prompt-turn-queue/paths.ts
|
|
26727
|
+
import path7 from "node:path";
|
|
26728
|
+
import os5 from "node:os";
|
|
26729
|
+
function getPromptQueuesDirectory() {
|
|
26730
|
+
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
26731
|
+
if (override) return path7.resolve(override);
|
|
26732
|
+
return path7.join(os5.homedir(), ".buildautomaton", "queues");
|
|
26733
|
+
}
|
|
26734
|
+
|
|
26735
|
+
// src/sqlite/legacy_migration/archive-file-index-json.ts
|
|
26736
|
+
import fs10 from "node:fs";
|
|
26737
|
+
import path9 from "node:path";
|
|
26738
|
+
|
|
26739
|
+
// src/sqlite/legacy_migration/archive-to-old-version.ts
|
|
26740
|
+
import fs9 from "node:fs";
|
|
26741
|
+
import path8 from "node:path";
|
|
26742
|
+
var OLD_VERSION_DIR = path8.join(INDEX_DIR, "old-version");
|
|
26743
|
+
function moveLegacyFileToOldVersionBackup(category, sourcePath) {
|
|
26744
|
+
const destDir = path8.join(OLD_VERSION_DIR, category);
|
|
26745
|
+
fs9.mkdirSync(destDir, { recursive: true });
|
|
26746
|
+
const base = path8.basename(sourcePath);
|
|
26747
|
+
let dest = path8.join(destDir, base);
|
|
26748
|
+
if (fs9.existsSync(dest)) {
|
|
26749
|
+
const ext = path8.extname(base);
|
|
26750
|
+
const stem = ext ? base.slice(0, -ext.length) : base;
|
|
26751
|
+
dest = path8.join(destDir, `${stem}-${Date.now()}${ext}`);
|
|
26752
|
+
}
|
|
26753
|
+
fs9.renameSync(sourcePath, dest);
|
|
26754
|
+
}
|
|
26755
|
+
|
|
26756
|
+
// src/sqlite/legacy_migration/archive-file-index-json.ts
|
|
26757
|
+
function archiveLegacyFileIndexJsonFiles() {
|
|
26758
|
+
try {
|
|
26759
|
+
if (!fs10.existsSync(INDEX_DIR)) return;
|
|
26760
|
+
for (const name of fs10.readdirSync(INDEX_DIR)) {
|
|
26761
|
+
if (name.startsWith(".file-index-") && name.endsWith(".json")) {
|
|
26762
|
+
const full = path9.join(INDEX_DIR, name);
|
|
26763
|
+
try {
|
|
26764
|
+
moveLegacyFileToOldVersionBackup("file-index", full);
|
|
26765
|
+
} catch (err) {
|
|
26766
|
+
console.error(`[cli-sqlite] legacy import: could not archive ${name}`, err);
|
|
26767
|
+
}
|
|
26768
|
+
}
|
|
26769
|
+
}
|
|
26770
|
+
} catch (e) {
|
|
26771
|
+
console.error("[cli-sqlite] legacy import: archive file-index json failed", e);
|
|
26772
|
+
}
|
|
26773
|
+
}
|
|
26774
|
+
|
|
26775
|
+
// src/sqlite/legacy_migration/import-agent-sessions-from-disk.ts
|
|
26776
|
+
import fs11 from "node:fs";
|
|
26777
|
+
import path10 from "node:path";
|
|
26778
|
+
import os6 from "node:os";
|
|
26779
|
+
var LEGACY_AGENT_SESSION_DIR = path10.join(os6.homedir(), ".buildautomaton", "agent-sessions");
|
|
26780
|
+
function importLegacyAgentSessionsFromDisk(db) {
|
|
26781
|
+
try {
|
|
26782
|
+
if (!fs11.existsSync(LEGACY_AGENT_SESSION_DIR)) return;
|
|
26783
|
+
const names = fs11.readdirSync(LEGACY_AGENT_SESSION_DIR).filter((n) => n.endsWith(".json"));
|
|
26784
|
+
for (const name of names) {
|
|
26785
|
+
const sessionKey = name.slice(0, -".json".length);
|
|
26786
|
+
const full = path10.join(LEGACY_AGENT_SESSION_DIR, name);
|
|
26787
|
+
let raw;
|
|
26788
|
+
try {
|
|
26789
|
+
raw = fs11.readFileSync(full, "utf8");
|
|
26790
|
+
} catch {
|
|
26791
|
+
continue;
|
|
26792
|
+
}
|
|
26793
|
+
let parsed;
|
|
26794
|
+
try {
|
|
26795
|
+
parsed = JSON.parse(raw);
|
|
26796
|
+
} catch {
|
|
26797
|
+
continue;
|
|
26798
|
+
}
|
|
26799
|
+
if (parsed.v !== 1) continue;
|
|
26800
|
+
const acpSessionId = typeof parsed.acpSessionId === "string" ? parsed.acpSessionId : null;
|
|
26801
|
+
const backendAgentType = typeof parsed.backendAgentType === "string" ? parsed.backendAgentType : null;
|
|
26802
|
+
const configOptionsJson = Array.isArray(parsed.configOptions) ? JSON.stringify(parsed.configOptions) : null;
|
|
26803
|
+
const updatedAt = typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
26804
|
+
db.run(
|
|
26805
|
+
`INSERT OR REPLACE INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
|
|
26806
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
26807
|
+
[sessionKey, acpSessionId, backendAgentType, configOptionsJson, updatedAt]
|
|
26808
|
+
);
|
|
26809
|
+
try {
|
|
26810
|
+
moveLegacyFileToOldVersionBackup("agent-sessions", full);
|
|
26811
|
+
} catch {
|
|
26812
|
+
}
|
|
26813
|
+
}
|
|
26814
|
+
} catch (e) {
|
|
26815
|
+
console.error("[cli-sqlite] legacy import: agent_sessions from disk failed", e);
|
|
26816
|
+
}
|
|
26817
|
+
}
|
|
26818
|
+
|
|
26819
|
+
// src/sqlite/legacy_migration/import-prompt-queues-from-disk.ts
|
|
26820
|
+
import fs12 from "node:fs";
|
|
26821
|
+
import path11 from "node:path";
|
|
26822
|
+
|
|
26823
|
+
// src/sqlite/legacy_migration/parse-persisted-queue-json.ts
|
|
26824
|
+
function parsePersistedQueueFromJson(raw) {
|
|
26825
|
+
try {
|
|
26826
|
+
const o = JSON.parse(raw);
|
|
26827
|
+
const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
|
|
26828
|
+
if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
|
|
26829
|
+
return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
|
|
26830
|
+
} catch {
|
|
26831
|
+
return null;
|
|
26832
|
+
}
|
|
26833
|
+
}
|
|
26834
|
+
|
|
26835
|
+
// src/sqlite/legacy_migration/import-prompt-queues-from-disk.ts
|
|
26836
|
+
function importLegacyPromptQueuesFromDisk(db) {
|
|
26837
|
+
try {
|
|
26838
|
+
const dir = getPromptQueuesDirectory();
|
|
26839
|
+
if (!fs12.existsSync(dir)) return;
|
|
26840
|
+
for (const name of fs12.readdirSync(dir)) {
|
|
26841
|
+
if (!name.endsWith(".json")) continue;
|
|
26842
|
+
const full = path11.join(dir, name);
|
|
26843
|
+
let raw;
|
|
26844
|
+
try {
|
|
26845
|
+
raw = fs12.readFileSync(full, "utf8");
|
|
26846
|
+
} catch {
|
|
26847
|
+
continue;
|
|
26848
|
+
}
|
|
26849
|
+
const file2 = parsePersistedQueueFromJson(raw);
|
|
26850
|
+
if (!file2) continue;
|
|
26851
|
+
db.run(
|
|
26852
|
+
`INSERT OR REPLACE INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)`,
|
|
26853
|
+
[file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
|
|
26854
|
+
);
|
|
26855
|
+
try {
|
|
26856
|
+
moveLegacyFileToOldVersionBackup("queues", full);
|
|
26857
|
+
} catch {
|
|
26858
|
+
}
|
|
26859
|
+
}
|
|
26860
|
+
} catch (e) {
|
|
26861
|
+
console.error("[cli-sqlite] legacy import: prompt queues from disk failed", e);
|
|
26862
|
+
}
|
|
26863
|
+
}
|
|
26864
|
+
|
|
26865
|
+
// src/sqlite/legacy_migration/import-cli-legacy-disk-data.ts
|
|
26866
|
+
function legacyCliDiskMigrationIsPending() {
|
|
26867
|
+
try {
|
|
26868
|
+
if (fs13.existsSync(INDEX_DIR)) {
|
|
26869
|
+
for (const name of fs13.readdirSync(INDEX_DIR)) {
|
|
26870
|
+
if (name.startsWith(".file-index-") && name.endsWith(".json")) return true;
|
|
26871
|
+
}
|
|
26872
|
+
}
|
|
26873
|
+
} catch {
|
|
26874
|
+
}
|
|
26875
|
+
try {
|
|
26876
|
+
if (fs13.existsSync(LEGACY_AGENT_SESSION_DIR)) {
|
|
26877
|
+
if (fs13.readdirSync(LEGACY_AGENT_SESSION_DIR).some((n) => n.endsWith(".json"))) return true;
|
|
26878
|
+
}
|
|
26879
|
+
} catch {
|
|
26880
|
+
}
|
|
26881
|
+
try {
|
|
26882
|
+
const dir = getPromptQueuesDirectory();
|
|
26883
|
+
if (fs13.existsSync(dir) && fs13.readdirSync(dir).some((n) => n.endsWith(".json"))) return true;
|
|
26884
|
+
} catch {
|
|
26885
|
+
}
|
|
26886
|
+
return false;
|
|
26887
|
+
}
|
|
26888
|
+
function importCliSqliteLegacyDiskData(db, log2) {
|
|
26889
|
+
const pending = legacyCliDiskMigrationIsPending();
|
|
26890
|
+
if (pending && log2) {
|
|
26891
|
+
log2("Migrating legacy on-disk CLI data to SQLite\u2026");
|
|
26892
|
+
}
|
|
26893
|
+
archiveLegacyFileIndexJsonFiles();
|
|
26894
|
+
importLegacyAgentSessionsFromDisk(db);
|
|
26895
|
+
importLegacyPromptQueuesFromDisk(db);
|
|
26896
|
+
if (pending && log2) {
|
|
26897
|
+
log2("Legacy on-disk CLI data migration finished.");
|
|
26898
|
+
}
|
|
26899
|
+
}
|
|
26900
|
+
|
|
26901
|
+
// src/sqlite/load-cli-migration-sql.ts
|
|
26902
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
26903
|
+
import { dirname, join as join2 } from "node:path";
|
|
26904
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
26905
|
+
function readCliSqliteMigrationSql(filename) {
|
|
26906
|
+
const dir = dirname(fileURLToPath2(import.meta.url));
|
|
26907
|
+
const resolved = join2(dir, "migrations", filename);
|
|
26908
|
+
if (!existsSync(resolved)) {
|
|
26909
|
+
throw new Error(`Missing CLI SQLite migration SQL: ${resolved}`);
|
|
26910
|
+
}
|
|
26911
|
+
return readFileSync(resolved, "utf8");
|
|
26912
|
+
}
|
|
26913
|
+
|
|
26914
|
+
// src/sqlite/migrate-cli-sqlite.ts
|
|
26915
|
+
function checkpointSatisfiedByLegacyChain(applied2, replacesLegacyMigrations) {
|
|
26916
|
+
return Array.isArray(replacesLegacyMigrations) && replacesLegacyMigrations.length > 0 && replacesLegacyMigrations.every((n) => applied2.has(n));
|
|
26917
|
+
}
|
|
26918
|
+
function recordMigrationAndPruneCheckpointLegacy(db, migration, applied2) {
|
|
26919
|
+
db.run("INSERT INTO __migrations (name) VALUES (?)", [migration.name]);
|
|
26920
|
+
applied2.add(migration.name);
|
|
26921
|
+
if (migration.checkpoint !== true) return;
|
|
26922
|
+
const legacy = migration.replacesLegacyMigrations;
|
|
26923
|
+
if (!legacy?.length) return;
|
|
26924
|
+
for (const legacyName of legacy) {
|
|
26925
|
+
if (legacyName === migration.name) continue;
|
|
26926
|
+
db.run("DELETE FROM __migrations WHERE name = ?", [legacyName]);
|
|
26927
|
+
applied2.delete(legacyName);
|
|
26928
|
+
}
|
|
26929
|
+
}
|
|
26930
|
+
var CHECKPOINT_V1 = "001_cli_sqlite_checkpoint_v1";
|
|
26931
|
+
var CHECKPOINT_V1_SQL = readCliSqliteMigrationSql("001_cli_sqlite_checkpoint_v1.sql");
|
|
26932
|
+
var AGENT_CAPABILITIES_SQL = readCliSqliteMigrationSql("002_agent_capabilities.sql");
|
|
26933
|
+
function agentCapabilitiesTableState(db) {
|
|
26934
|
+
const rows = db.all(
|
|
26935
|
+
`SELECT name FROM sqlite_master WHERE type='table' AND name IN ('agent_capabilities', 'agent_capability_cache')`
|
|
26936
|
+
);
|
|
26937
|
+
const names = new Set(rows.map((r) => r.name));
|
|
26938
|
+
if (names.has("agent_capabilities")) return "current";
|
|
26939
|
+
if (names.has("agent_capability_cache")) return "legacy";
|
|
26940
|
+
return "new";
|
|
26941
|
+
}
|
|
26942
|
+
var CLI_SQLITE_MIGRATIONS = [
|
|
26943
|
+
{
|
|
26944
|
+
name: CHECKPOINT_V1,
|
|
26945
|
+
checkpoint: true,
|
|
26946
|
+
migrate: (db) => {
|
|
26947
|
+
db.exec(CHECKPOINT_V1_SQL);
|
|
26948
|
+
}
|
|
26949
|
+
},
|
|
26950
|
+
{
|
|
26951
|
+
name: "002_agent_capabilities",
|
|
26952
|
+
migrate: (db) => {
|
|
26953
|
+
const state = agentCapabilitiesTableState(db);
|
|
26954
|
+
if (state === "current") return;
|
|
26955
|
+
if (state === "legacy") {
|
|
26956
|
+
db.exec(`
|
|
26957
|
+
ALTER TABLE agent_capability_cache RENAME TO agent_capabilities;
|
|
26958
|
+
DROP INDEX IF EXISTS idx_agent_capability_cache_workspace;
|
|
26959
|
+
CREATE INDEX IF NOT EXISTS idx_agent_capabilities_workspace ON agent_capabilities(workspace_id);
|
|
26960
|
+
`);
|
|
26961
|
+
return;
|
|
26962
|
+
}
|
|
26963
|
+
db.exec(AGENT_CAPABILITIES_SQL);
|
|
26964
|
+
},
|
|
26965
|
+
alreadyApplied: (db) => agentCapabilitiesTableState(db) === "current"
|
|
26966
|
+
}
|
|
26967
|
+
];
|
|
26968
|
+
function migrateCliSqlite(db) {
|
|
26969
|
+
db.exec(readCliSqliteMigrationSql("000_bootstrap_migrations_table.sql"));
|
|
26970
|
+
const appliedRows = db.all("SELECT name FROM __migrations");
|
|
26971
|
+
const applied2 = new Set(appliedRows.map((r) => r.name));
|
|
26972
|
+
for (const migration of CLI_SQLITE_MIGRATIONS) {
|
|
26973
|
+
if (applied2.has(migration.name)) continue;
|
|
26974
|
+
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(applied2, migration.replacesLegacyMigrations)) {
|
|
26975
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
26976
|
+
continue;
|
|
26977
|
+
}
|
|
26978
|
+
if (migration.alreadyApplied?.(db)) {
|
|
26979
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
26980
|
+
continue;
|
|
26981
|
+
}
|
|
26982
|
+
try {
|
|
26983
|
+
migration.migrate(db);
|
|
26984
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
26985
|
+
} catch (e) {
|
|
26986
|
+
console.error(`[cli-sqlite] Migration failed: ${migration.name}`, e);
|
|
26987
|
+
throw e;
|
|
26988
|
+
}
|
|
26989
|
+
}
|
|
26990
|
+
}
|
|
26991
|
+
|
|
26992
|
+
// src/sqlite/cli-database.ts
|
|
26993
|
+
var { Database: SqliteDatabase } = sqliteWasm;
|
|
26994
|
+
var openDatabases = /* @__PURE__ */ new Map();
|
|
26995
|
+
var processExitCloseRegistered = false;
|
|
26996
|
+
function registerProcessExitSqliteClose() {
|
|
26997
|
+
if (processExitCloseRegistered) return;
|
|
26998
|
+
processExitCloseRegistered = true;
|
|
26999
|
+
process.once("exit", () => {
|
|
27000
|
+
for (const db of openDatabases.values()) {
|
|
27001
|
+
safeCloseCliSqliteDatabase(db);
|
|
27002
|
+
}
|
|
27003
|
+
openDatabases.clear();
|
|
27004
|
+
});
|
|
27005
|
+
}
|
|
27006
|
+
function safeCloseCliSqliteDatabase(db) {
|
|
27007
|
+
if (db == null) return;
|
|
27008
|
+
try {
|
|
27009
|
+
if (db.isOpen) db.close();
|
|
27010
|
+
} catch {
|
|
27011
|
+
}
|
|
27012
|
+
}
|
|
27013
|
+
function closeAllCliSqliteConnections() {
|
|
27014
|
+
for (const db of openDatabases.values()) {
|
|
27015
|
+
safeCloseCliSqliteDatabase(db);
|
|
27016
|
+
}
|
|
27017
|
+
openDatabases.clear();
|
|
27018
|
+
}
|
|
27019
|
+
function getCliDatabase(options) {
|
|
27020
|
+
const sqlitePath = getCliSqlitePath();
|
|
27021
|
+
const existing = openDatabases.get(sqlitePath);
|
|
27022
|
+
if (existing?.isOpen) return existing;
|
|
27023
|
+
if (existing && !existing.isOpen) {
|
|
27024
|
+
safeCloseCliSqliteDatabase(existing);
|
|
27025
|
+
openDatabases.delete(sqlitePath);
|
|
27026
|
+
}
|
|
27027
|
+
ensureCliSqliteParentDir(sqlitePath);
|
|
27028
|
+
const db = new SqliteDatabase(sqlitePath);
|
|
27029
|
+
try {
|
|
27030
|
+
migrateCliSqlite(db);
|
|
27031
|
+
importCliSqliteLegacyDiskData(db, options?.logLegacyMigration);
|
|
27032
|
+
} catch (e) {
|
|
27033
|
+
safeCloseCliSqliteDatabase(db);
|
|
27034
|
+
throw e;
|
|
27035
|
+
}
|
|
27036
|
+
openDatabases.set(sqlitePath, db);
|
|
27037
|
+
registerProcessExitSqliteClose();
|
|
27038
|
+
return db;
|
|
27039
|
+
}
|
|
27040
|
+
|
|
26699
27041
|
// src/connection/close-bridge-connection.ts
|
|
26700
27042
|
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
26701
27043
|
const say = log2 ?? logImmediate;
|
|
26702
27044
|
say("Cleaning up connections\u2026");
|
|
26703
|
-
await new Promise((
|
|
27045
|
+
await new Promise((resolve20) => setImmediate(resolve20));
|
|
26704
27046
|
state.closedByUser = true;
|
|
26705
27047
|
clearReconnectQuietTimer(state.mainQuiet);
|
|
26706
27048
|
clearReconnectQuietTimer(state.firehoseQuiet);
|
|
@@ -26739,20 +27081,24 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
|
|
|
26739
27081
|
say("Stopping local dev server processes\u2026");
|
|
26740
27082
|
await devServerManager.shutdownAllGraceful();
|
|
26741
27083
|
}
|
|
27084
|
+
try {
|
|
27085
|
+
closeAllCliSqliteConnections();
|
|
27086
|
+
} catch {
|
|
27087
|
+
}
|
|
26742
27088
|
say("Shutdown complete.");
|
|
26743
27089
|
}
|
|
26744
27090
|
|
|
26745
27091
|
// src/paths/session-layout-paths.ts
|
|
26746
|
-
import * as
|
|
27092
|
+
import * as path12 from "node:path";
|
|
26747
27093
|
function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
|
|
26748
|
-
const resolved = worktreePaths.map((p) =>
|
|
27094
|
+
const resolved = worktreePaths.map((p) => path12.resolve(p)).filter(Boolean);
|
|
26749
27095
|
if (resolved.length === 0) return null;
|
|
26750
27096
|
resolved.sort();
|
|
26751
27097
|
return resolved[0];
|
|
26752
27098
|
}
|
|
26753
27099
|
function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
|
|
26754
27100
|
if (resolvedSessionParentPath != null && String(resolvedSessionParentPath).trim() !== "") {
|
|
26755
|
-
return
|
|
27101
|
+
return path12.resolve(String(resolvedSessionParentPath).trim());
|
|
26756
27102
|
}
|
|
26757
27103
|
return getBridgeRoot();
|
|
26758
27104
|
}
|
|
@@ -27084,9 +27430,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
27084
27430
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
27085
27431
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
27086
27432
|
if (!rawPath || !summary) continue;
|
|
27087
|
-
const
|
|
27088
|
-
if (!
|
|
27089
|
-
rows.push({ path:
|
|
27433
|
+
const path43 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
27434
|
+
if (!path43) continue;
|
|
27435
|
+
rows.push({ path: path43, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
27090
27436
|
}
|
|
27091
27437
|
return rows;
|
|
27092
27438
|
}
|
|
@@ -27296,6 +27642,7 @@ function buildCliAutoApprovedPermissionRpcResult(requestParams) {
|
|
|
27296
27642
|
// ../types/src/agent-config.ts
|
|
27297
27643
|
var AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY = "claude_permission_mode";
|
|
27298
27644
|
var AGENT_CONFIG_CLI_PERMISSION_MODE_KEY = "cli_permission_mode";
|
|
27645
|
+
var AGENT_CONFIG_AGENT_MODEL_KEY = "agent_model";
|
|
27299
27646
|
function getClaudePermissionModeFromAgentConfig(config2) {
|
|
27300
27647
|
if (!config2) return null;
|
|
27301
27648
|
const raw = config2[AGENT_CONFIG_CLAUDE_PERMISSION_MODE_KEY];
|
|
@@ -27307,22 +27654,29 @@ function getCliPermissionModeFromAgentConfig(config2) {
|
|
|
27307
27654
|
if (!config2) return CLI_PERMISSION_MODE_DEFAULT;
|
|
27308
27655
|
return normalizeCliPermissionModeInput(config2[AGENT_CONFIG_CLI_PERMISSION_MODE_KEY]);
|
|
27309
27656
|
}
|
|
27657
|
+
function getAgentModelFromAgentConfig(config2) {
|
|
27658
|
+
if (!config2) return null;
|
|
27659
|
+
const cur = config2[AGENT_CONFIG_AGENT_MODEL_KEY];
|
|
27660
|
+
if (typeof cur !== "string") return null;
|
|
27661
|
+
const t = cur.trim();
|
|
27662
|
+
return t !== "" ? t : null;
|
|
27663
|
+
}
|
|
27310
27664
|
|
|
27311
27665
|
// src/git/session-git-queue.ts
|
|
27312
27666
|
import { execFile as execFile7 } from "node:child_process";
|
|
27313
27667
|
import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
27314
27668
|
import { promisify as promisify7 } from "node:util";
|
|
27315
|
-
import * as
|
|
27669
|
+
import * as path15 from "node:path";
|
|
27316
27670
|
|
|
27317
27671
|
// src/git/pre-turn-snapshot.ts
|
|
27318
|
-
import * as
|
|
27319
|
-
import * as
|
|
27672
|
+
import * as fs15 from "node:fs";
|
|
27673
|
+
import * as path14 from "node:path";
|
|
27320
27674
|
import { execFile as execFile6 } from "node:child_process";
|
|
27321
27675
|
import { promisify as promisify6 } from "node:util";
|
|
27322
27676
|
|
|
27323
27677
|
// src/git/discover-repos.ts
|
|
27324
|
-
import * as
|
|
27325
|
-
import * as
|
|
27678
|
+
import * as fs14 from "node:fs";
|
|
27679
|
+
import * as path13 from "node:path";
|
|
27326
27680
|
|
|
27327
27681
|
// ../../node_modules/.pnpm/simple-git@3.32.3/node_modules/simple-git/dist/esm/index.js
|
|
27328
27682
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -27361,8 +27715,8 @@ function pathspec(...paths) {
|
|
|
27361
27715
|
cache.set(key, paths);
|
|
27362
27716
|
return key;
|
|
27363
27717
|
}
|
|
27364
|
-
function isPathSpec(
|
|
27365
|
-
return
|
|
27718
|
+
function isPathSpec(path43) {
|
|
27719
|
+
return path43 instanceof String && cache.has(path43);
|
|
27366
27720
|
}
|
|
27367
27721
|
function toPaths(pathSpec) {
|
|
27368
27722
|
return cache.get(pathSpec) || [];
|
|
@@ -27451,8 +27805,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
27451
27805
|
function forEachLineWithContent(input, callback) {
|
|
27452
27806
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
27453
27807
|
}
|
|
27454
|
-
function folderExists(
|
|
27455
|
-
return (0, import_file_exists.exists)(
|
|
27808
|
+
function folderExists(path43) {
|
|
27809
|
+
return (0, import_file_exists.exists)(path43, import_file_exists.FOLDER);
|
|
27456
27810
|
}
|
|
27457
27811
|
function append(target, item) {
|
|
27458
27812
|
if (Array.isArray(target)) {
|
|
@@ -27856,8 +28210,8 @@ function checkIsRepoRootTask() {
|
|
|
27856
28210
|
commands,
|
|
27857
28211
|
format: "utf-8",
|
|
27858
28212
|
onError,
|
|
27859
|
-
parser(
|
|
27860
|
-
return /^\.(git)?$/.test(
|
|
28213
|
+
parser(path43) {
|
|
28214
|
+
return /^\.(git)?$/.test(path43.trim());
|
|
27861
28215
|
}
|
|
27862
28216
|
};
|
|
27863
28217
|
}
|
|
@@ -28291,11 +28645,11 @@ function parseGrep(grep) {
|
|
|
28291
28645
|
const paths = /* @__PURE__ */ new Set();
|
|
28292
28646
|
const results = {};
|
|
28293
28647
|
forEachLineWithContent(grep, (input) => {
|
|
28294
|
-
const [
|
|
28295
|
-
paths.add(
|
|
28296
|
-
(results[
|
|
28648
|
+
const [path43, line, preview] = input.split(NULL);
|
|
28649
|
+
paths.add(path43);
|
|
28650
|
+
(results[path43] = results[path43] || []).push({
|
|
28297
28651
|
line: asNumber(line),
|
|
28298
|
-
path:
|
|
28652
|
+
path: path43,
|
|
28299
28653
|
preview
|
|
28300
28654
|
});
|
|
28301
28655
|
});
|
|
@@ -29060,14 +29414,14 @@ var init_hash_object = __esm2({
|
|
|
29060
29414
|
init_task();
|
|
29061
29415
|
}
|
|
29062
29416
|
});
|
|
29063
|
-
function parseInit(bare,
|
|
29417
|
+
function parseInit(bare, path43, text) {
|
|
29064
29418
|
const response = String(text).trim();
|
|
29065
29419
|
let result;
|
|
29066
29420
|
if (result = initResponseRegex.exec(response)) {
|
|
29067
|
-
return new InitSummary(bare,
|
|
29421
|
+
return new InitSummary(bare, path43, false, result[1]);
|
|
29068
29422
|
}
|
|
29069
29423
|
if (result = reInitResponseRegex.exec(response)) {
|
|
29070
|
-
return new InitSummary(bare,
|
|
29424
|
+
return new InitSummary(bare, path43, true, result[1]);
|
|
29071
29425
|
}
|
|
29072
29426
|
let gitDir = "";
|
|
29073
29427
|
const tokens = response.split(" ");
|
|
@@ -29078,7 +29432,7 @@ function parseInit(bare, path37, text) {
|
|
|
29078
29432
|
break;
|
|
29079
29433
|
}
|
|
29080
29434
|
}
|
|
29081
|
-
return new InitSummary(bare,
|
|
29435
|
+
return new InitSummary(bare, path43, /^re/i.test(response), gitDir);
|
|
29082
29436
|
}
|
|
29083
29437
|
var InitSummary;
|
|
29084
29438
|
var initResponseRegex;
|
|
@@ -29087,9 +29441,9 @@ var init_InitSummary = __esm2({
|
|
|
29087
29441
|
"src/lib/responses/InitSummary.ts"() {
|
|
29088
29442
|
"use strict";
|
|
29089
29443
|
InitSummary = class {
|
|
29090
|
-
constructor(bare,
|
|
29444
|
+
constructor(bare, path43, existing, gitDir) {
|
|
29091
29445
|
this.bare = bare;
|
|
29092
|
-
this.path =
|
|
29446
|
+
this.path = path43;
|
|
29093
29447
|
this.existing = existing;
|
|
29094
29448
|
this.gitDir = gitDir;
|
|
29095
29449
|
}
|
|
@@ -29101,7 +29455,7 @@ var init_InitSummary = __esm2({
|
|
|
29101
29455
|
function hasBareCommand(command) {
|
|
29102
29456
|
return command.includes(bareCommand);
|
|
29103
29457
|
}
|
|
29104
|
-
function initTask(bare = false,
|
|
29458
|
+
function initTask(bare = false, path43, customArgs) {
|
|
29105
29459
|
const commands = ["init", ...customArgs];
|
|
29106
29460
|
if (bare && !hasBareCommand(commands)) {
|
|
29107
29461
|
commands.splice(1, 0, bareCommand);
|
|
@@ -29110,7 +29464,7 @@ function initTask(bare = false, path37, customArgs) {
|
|
|
29110
29464
|
commands,
|
|
29111
29465
|
format: "utf-8",
|
|
29112
29466
|
parser(text) {
|
|
29113
|
-
return parseInit(commands.includes("--bare"),
|
|
29467
|
+
return parseInit(commands.includes("--bare"), path43, text);
|
|
29114
29468
|
}
|
|
29115
29469
|
};
|
|
29116
29470
|
}
|
|
@@ -29926,12 +30280,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
29926
30280
|
"use strict";
|
|
29927
30281
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
29928
30282
|
FileStatusSummary = class {
|
|
29929
|
-
constructor(
|
|
29930
|
-
this.path =
|
|
30283
|
+
constructor(path43, index, working_dir) {
|
|
30284
|
+
this.path = path43;
|
|
29931
30285
|
this.index = index;
|
|
29932
30286
|
this.working_dir = working_dir;
|
|
29933
30287
|
if (index === "R" || working_dir === "R") {
|
|
29934
|
-
const detail = fromPathRegex.exec(
|
|
30288
|
+
const detail = fromPathRegex.exec(path43) || [null, path43, path43];
|
|
29935
30289
|
this.from = detail[2] || "";
|
|
29936
30290
|
this.path = detail[1] || "";
|
|
29937
30291
|
}
|
|
@@ -29962,14 +30316,14 @@ function splitLine(result, lineStr) {
|
|
|
29962
30316
|
default:
|
|
29963
30317
|
return;
|
|
29964
30318
|
}
|
|
29965
|
-
function data(index, workingDir,
|
|
30319
|
+
function data(index, workingDir, path43) {
|
|
29966
30320
|
const raw = `${index}${workingDir}`;
|
|
29967
30321
|
const handler = parsers6.get(raw);
|
|
29968
30322
|
if (handler) {
|
|
29969
|
-
handler(result,
|
|
30323
|
+
handler(result, path43);
|
|
29970
30324
|
}
|
|
29971
30325
|
if (raw !== "##" && raw !== "!!") {
|
|
29972
|
-
result.files.push(new FileStatusSummary(
|
|
30326
|
+
result.files.push(new FileStatusSummary(path43, index, workingDir));
|
|
29973
30327
|
}
|
|
29974
30328
|
}
|
|
29975
30329
|
}
|
|
@@ -30242,15 +30596,15 @@ var init_simple_git_api = __esm2({
|
|
|
30242
30596
|
this._executor = _executor;
|
|
30243
30597
|
}
|
|
30244
30598
|
_runTask(task, then) {
|
|
30245
|
-
const
|
|
30246
|
-
const promise2 =
|
|
30599
|
+
const chain2 = this._executor.chain();
|
|
30600
|
+
const promise2 = chain2.push(task);
|
|
30247
30601
|
if (then) {
|
|
30248
30602
|
taskCallback(task, promise2, then);
|
|
30249
30603
|
}
|
|
30250
30604
|
return Object.create(this, {
|
|
30251
30605
|
then: { value: promise2.then.bind(promise2) },
|
|
30252
30606
|
catch: { value: promise2.catch.bind(promise2) },
|
|
30253
|
-
_executor: { value:
|
|
30607
|
+
_executor: { value: chain2 }
|
|
30254
30608
|
});
|
|
30255
30609
|
}
|
|
30256
30610
|
add(files) {
|
|
@@ -30278,9 +30632,9 @@ var init_simple_git_api = __esm2({
|
|
|
30278
30632
|
next
|
|
30279
30633
|
);
|
|
30280
30634
|
}
|
|
30281
|
-
hashObject(
|
|
30635
|
+
hashObject(path43, write) {
|
|
30282
30636
|
return this._runTask(
|
|
30283
|
-
hashObjectTask(
|
|
30637
|
+
hashObjectTask(path43, write === true),
|
|
30284
30638
|
trailingFunctionArgument(arguments)
|
|
30285
30639
|
);
|
|
30286
30640
|
}
|
|
@@ -30633,8 +30987,8 @@ var init_branch = __esm2({
|
|
|
30633
30987
|
}
|
|
30634
30988
|
});
|
|
30635
30989
|
function toPath(input) {
|
|
30636
|
-
const
|
|
30637
|
-
return
|
|
30990
|
+
const path43 = input.trim().replace(/^["']|["']$/g, "");
|
|
30991
|
+
return path43 && normalize(path43);
|
|
30638
30992
|
}
|
|
30639
30993
|
var parseCheckIgnore;
|
|
30640
30994
|
var init_CheckIgnore = __esm2({
|
|
@@ -30948,8 +31302,8 @@ __export2(sub_module_exports, {
|
|
|
30948
31302
|
subModuleTask: () => subModuleTask,
|
|
30949
31303
|
updateSubModuleTask: () => updateSubModuleTask
|
|
30950
31304
|
});
|
|
30951
|
-
function addSubModuleTask(repo,
|
|
30952
|
-
return subModuleTask(["add", repo,
|
|
31305
|
+
function addSubModuleTask(repo, path43) {
|
|
31306
|
+
return subModuleTask(["add", repo, path43]);
|
|
30953
31307
|
}
|
|
30954
31308
|
function initSubModuleTask(customArgs) {
|
|
30955
31309
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -31282,8 +31636,8 @@ var require_git = __commonJS2({
|
|
|
31282
31636
|
}
|
|
31283
31637
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
31284
31638
|
};
|
|
31285
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
31286
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
31639
|
+
Git2.prototype.submoduleAdd = function(repo, path43, then) {
|
|
31640
|
+
return this._runTask(addSubModuleTask2(repo, path43), trailingFunctionArgument2(arguments));
|
|
31287
31641
|
};
|
|
31288
31642
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
31289
31643
|
return this._runTask(
|
|
@@ -31927,20 +32281,20 @@ async function isGitRepoDirectory(dirPath) {
|
|
|
31927
32281
|
// src/git/discover-repos.ts
|
|
31928
32282
|
async function discoverGitRepos(cwd = getBridgeRoot()) {
|
|
31929
32283
|
const result = [];
|
|
31930
|
-
const cwdResolved =
|
|
32284
|
+
const cwdResolved = path13.resolve(cwd);
|
|
31931
32285
|
if (await isGitRepoDirectory(cwdResolved)) {
|
|
31932
32286
|
const remoteUrl = await getRemoteOriginUrl(cwdResolved);
|
|
31933
32287
|
result.push({ absolutePath: cwdResolved, remoteUrl });
|
|
31934
32288
|
}
|
|
31935
32289
|
let entries;
|
|
31936
32290
|
try {
|
|
31937
|
-
entries =
|
|
32291
|
+
entries = fs14.readdirSync(cwdResolved, { withFileTypes: true });
|
|
31938
32292
|
} catch {
|
|
31939
32293
|
return result;
|
|
31940
32294
|
}
|
|
31941
32295
|
for (const ent of entries) {
|
|
31942
32296
|
if (!ent.isDirectory()) continue;
|
|
31943
|
-
const childPath =
|
|
32297
|
+
const childPath = path13.join(cwdResolved, ent.name);
|
|
31944
32298
|
if (await isGitRepoDirectory(childPath)) {
|
|
31945
32299
|
const remoteUrl = await getRemoteOriginUrl(childPath);
|
|
31946
32300
|
result.push({ absolutePath: childPath, remoteUrl });
|
|
@@ -31949,22 +32303,22 @@ async function discoverGitRepos(cwd = getBridgeRoot()) {
|
|
|
31949
32303
|
return result;
|
|
31950
32304
|
}
|
|
31951
32305
|
async function discoverGitReposUnderRoot(rootPath) {
|
|
31952
|
-
const root =
|
|
32306
|
+
const root = path13.resolve(rootPath);
|
|
31953
32307
|
const roots = [];
|
|
31954
32308
|
async function walk(dir) {
|
|
31955
32309
|
if (await isGitRepoDirectory(dir)) {
|
|
31956
|
-
roots.push(
|
|
32310
|
+
roots.push(path13.resolve(dir));
|
|
31957
32311
|
return;
|
|
31958
32312
|
}
|
|
31959
32313
|
let entries;
|
|
31960
32314
|
try {
|
|
31961
|
-
entries =
|
|
32315
|
+
entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
31962
32316
|
} catch {
|
|
31963
32317
|
return;
|
|
31964
32318
|
}
|
|
31965
32319
|
for (const ent of entries) {
|
|
31966
32320
|
if (!ent.isDirectory() || ent.name === ".git") continue;
|
|
31967
|
-
await walk(
|
|
32321
|
+
await walk(path13.join(dir, ent.name));
|
|
31968
32322
|
}
|
|
31969
32323
|
}
|
|
31970
32324
|
await walk(root);
|
|
@@ -31980,7 +32334,7 @@ async function discoverGitReposUnderRoot(rootPath) {
|
|
|
31980
32334
|
// src/git/pre-turn-snapshot.ts
|
|
31981
32335
|
var execFileAsync5 = promisify6(execFile6);
|
|
31982
32336
|
function snapshotsDirForCwd(agentCwd) {
|
|
31983
|
-
return
|
|
32337
|
+
return path14.join(agentCwd, ".buildautomaton", "snapshots");
|
|
31984
32338
|
}
|
|
31985
32339
|
async function gitStashCreate(repoRoot, log2) {
|
|
31986
32340
|
try {
|
|
@@ -32009,7 +32363,7 @@ async function gitRun(repoRoot, args, log2, label) {
|
|
|
32009
32363
|
async function resolveSnapshotRepoRoots(options) {
|
|
32010
32364
|
const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
|
|
32011
32365
|
if (worktreePaths?.length) {
|
|
32012
|
-
const uniq = [...new Set(worktreePaths.map((p) =>
|
|
32366
|
+
const uniq = [...new Set(worktreePaths.map((p) => path14.resolve(p)))];
|
|
32013
32367
|
return uniq;
|
|
32014
32368
|
}
|
|
32015
32369
|
try {
|
|
@@ -32017,7 +32371,7 @@ async function resolveSnapshotRepoRoots(options) {
|
|
|
32017
32371
|
const mapped = repos.map((r) => r.absolutePath);
|
|
32018
32372
|
const sid = sessionId?.trim();
|
|
32019
32373
|
if (sid) {
|
|
32020
|
-
const filtered = mapped.filter((root) =>
|
|
32374
|
+
const filtered = mapped.filter((root) => path14.basename(root) === sid);
|
|
32021
32375
|
if (filtered.length > 0) return filtered;
|
|
32022
32376
|
}
|
|
32023
32377
|
return mapped;
|
|
@@ -32038,7 +32392,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
32038
32392
|
}
|
|
32039
32393
|
const dir = snapshotsDirForCwd(agentCwd);
|
|
32040
32394
|
try {
|
|
32041
|
-
|
|
32395
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
32042
32396
|
} catch (e) {
|
|
32043
32397
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
32044
32398
|
}
|
|
@@ -32047,9 +32401,9 @@ async function capturePreTurnSnapshot(options) {
|
|
|
32047
32401
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32048
32402
|
repos
|
|
32049
32403
|
};
|
|
32050
|
-
const filePath =
|
|
32404
|
+
const filePath = path14.join(dir, `${runId}.json`);
|
|
32051
32405
|
try {
|
|
32052
|
-
|
|
32406
|
+
fs15.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
32053
32407
|
} catch (e) {
|
|
32054
32408
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
32055
32409
|
}
|
|
@@ -32062,7 +32416,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
32062
32416
|
async function applyPreTurnSnapshot(filePath, log2) {
|
|
32063
32417
|
let data;
|
|
32064
32418
|
try {
|
|
32065
|
-
const raw =
|
|
32419
|
+
const raw = fs15.readFileSync(filePath, "utf8");
|
|
32066
32420
|
data = JSON.parse(raw);
|
|
32067
32421
|
} catch (e) {
|
|
32068
32422
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
@@ -32085,7 +32439,7 @@ async function applyPreTurnSnapshot(filePath, log2) {
|
|
|
32085
32439
|
return { ok: true };
|
|
32086
32440
|
}
|
|
32087
32441
|
function snapshotFilePath(agentCwd, runId) {
|
|
32088
|
-
return
|
|
32442
|
+
return path14.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
|
|
32089
32443
|
}
|
|
32090
32444
|
|
|
32091
32445
|
// src/git/session-git-queue.ts
|
|
@@ -32134,7 +32488,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32134
32488
|
continue;
|
|
32135
32489
|
}
|
|
32136
32490
|
const lines = namesRaw.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
32137
|
-
const slug =
|
|
32491
|
+
const slug = path15.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
|
|
32138
32492
|
for (const rel of lines) {
|
|
32139
32493
|
if (rel.includes("..")) continue;
|
|
32140
32494
|
try {
|
|
@@ -32148,7 +32502,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32148
32502
|
);
|
|
32149
32503
|
if (!patchContent.trim()) continue;
|
|
32150
32504
|
const displayPath = multiRepo ? `${slug}/${rel}` : rel;
|
|
32151
|
-
const workspaceFilePath =
|
|
32505
|
+
const workspaceFilePath = path15.join(repo.path, rel);
|
|
32152
32506
|
const newText = await readWorkspaceFileAsUtf8(workspaceFilePath);
|
|
32153
32507
|
sendSessionUpdate({
|
|
32154
32508
|
type: "session_file_change",
|
|
@@ -32170,9 +32524,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32170
32524
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
32171
32525
|
async function putEncryptedChangeSummaryRows(params) {
|
|
32172
32526
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
32173
|
-
const entries = params.rows.map(({ path:
|
|
32527
|
+
const entries = params.rows.map(({ path: path43, summary }) => {
|
|
32174
32528
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
32175
|
-
return { path:
|
|
32529
|
+
return { path: path43, summary: JSON.stringify(enc) };
|
|
32176
32530
|
});
|
|
32177
32531
|
const res = await fetch(
|
|
32178
32532
|
`${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -32483,8 +32837,8 @@ async function sendPromptToAgent(options) {
|
|
|
32483
32837
|
}
|
|
32484
32838
|
|
|
32485
32839
|
// src/agents/acp/ensure-acp-client.ts
|
|
32486
|
-
import * as
|
|
32487
|
-
import * as
|
|
32840
|
+
import * as fs16 from "node:fs";
|
|
32841
|
+
import * as path19 from "node:path";
|
|
32488
32842
|
|
|
32489
32843
|
// src/error-message.ts
|
|
32490
32844
|
function errorMessage(err) {
|
|
@@ -32648,8 +33002,8 @@ function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
|
|
|
32648
33002
|
}
|
|
32649
33003
|
|
|
32650
33004
|
// src/agents/acp/clients/shared/acp-fs-read-write.ts
|
|
32651
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
32652
|
-
import { dirname as
|
|
33005
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
33006
|
+
import { dirname as dirname3 } from "node:path";
|
|
32653
33007
|
|
|
32654
33008
|
// src/files/diff/unified-diff.ts
|
|
32655
33009
|
function computeLineDiff(oldText, newText) {
|
|
@@ -32698,21 +33052,21 @@ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
|
|
|
32698
33052
|
}
|
|
32699
33053
|
|
|
32700
33054
|
// src/agents/acp/safe-fs-path.ts
|
|
32701
|
-
import * as
|
|
33055
|
+
import * as path16 from "node:path";
|
|
32702
33056
|
function resolveSafePathUnderCwd(cwd, filePath) {
|
|
32703
33057
|
const trimmed2 = filePath.trim();
|
|
32704
33058
|
if (!trimmed2) return null;
|
|
32705
|
-
const normalizedCwd =
|
|
32706
|
-
const resolved =
|
|
32707
|
-
const rel =
|
|
32708
|
-
if (rel.startsWith("..") ||
|
|
33059
|
+
const normalizedCwd = path16.resolve(cwd);
|
|
33060
|
+
const resolved = path16.isAbsolute(trimmed2) ? path16.normalize(trimmed2) : path16.resolve(normalizedCwd, trimmed2);
|
|
33061
|
+
const rel = path16.relative(normalizedCwd, resolved);
|
|
33062
|
+
if (rel.startsWith("..") || path16.isAbsolute(rel)) return null;
|
|
32709
33063
|
return resolved;
|
|
32710
33064
|
}
|
|
32711
33065
|
function toDisplayPathRelativeToCwd(cwd, absolutePath) {
|
|
32712
|
-
const normalizedCwd =
|
|
32713
|
-
const rel =
|
|
32714
|
-
if (!rel || rel === "") return
|
|
32715
|
-
return rel.split(
|
|
33066
|
+
const normalizedCwd = path16.resolve(cwd);
|
|
33067
|
+
const rel = path16.relative(normalizedCwd, path16.resolve(absolutePath));
|
|
33068
|
+
if (!rel || rel === "") return path16.basename(absolutePath);
|
|
33069
|
+
return rel.split(path16.sep).join("/");
|
|
32716
33070
|
}
|
|
32717
33071
|
|
|
32718
33072
|
// src/agents/acp/clients/shared/acp-fs-read-write.ts
|
|
@@ -32727,7 +33081,7 @@ function acpReadTextFileInProcess(ctx, filePath, line, limit) {
|
|
|
32727
33081
|
const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
|
|
32728
33082
|
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32729
33083
|
try {
|
|
32730
|
-
let content =
|
|
33084
|
+
let content = readFileSync3(resolvedPath, "utf8");
|
|
32731
33085
|
content = sliceFileContentForAcp(content, line, limit);
|
|
32732
33086
|
return { content };
|
|
32733
33087
|
} catch (e) {
|
|
@@ -32740,11 +33094,11 @@ function acpWriteTextFileInProcess(ctx, filePath, newText) {
|
|
|
32740
33094
|
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32741
33095
|
let oldText = "";
|
|
32742
33096
|
try {
|
|
32743
|
-
oldText =
|
|
33097
|
+
oldText = readFileSync3(resolvedPath, "utf8");
|
|
32744
33098
|
} catch (e) {
|
|
32745
33099
|
if (e.code !== "ENOENT") throw e;
|
|
32746
33100
|
}
|
|
32747
|
-
mkdirSync2(
|
|
33101
|
+
mkdirSync2(dirname3(resolvedPath), { recursive: true });
|
|
32748
33102
|
writeFileSync2(resolvedPath, newText, "utf8");
|
|
32749
33103
|
const displayPath = toDisplayPathRelativeToCwd(ctx.cwd, resolvedPath);
|
|
32750
33104
|
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
@@ -32806,6 +33160,48 @@ async function applyClaudePermissionFromAcpSession(params) {
|
|
|
32806
33160
|
}
|
|
32807
33161
|
}
|
|
32808
33162
|
|
|
33163
|
+
// src/agents/acp/apply-acp-model-from-agent-session.ts
|
|
33164
|
+
function flattenSelectOptions2(options) {
|
|
33165
|
+
if (options == null || options.length === 0) return [];
|
|
33166
|
+
const first2 = options[0];
|
|
33167
|
+
if (first2 != null && typeof first2 === "object" && "group" in first2 && first2.group != null) {
|
|
33168
|
+
return options.flatMap((g) => Array.isArray(g.options) ? g.options : []);
|
|
33169
|
+
}
|
|
33170
|
+
return options;
|
|
33171
|
+
}
|
|
33172
|
+
function looksLikeModelOption(o) {
|
|
33173
|
+
if (o.category === "model" || o.category === "models") return true;
|
|
33174
|
+
const id = typeof o.id === "string" ? o.id.toLowerCase() : "";
|
|
33175
|
+
if (id === "model" || id.endsWith("_model") || id.includes("model")) return true;
|
|
33176
|
+
const name = typeof o.name === "string" ? o.name.toLowerCase() : "";
|
|
33177
|
+
return name.includes("model") && !name.includes("mode");
|
|
33178
|
+
}
|
|
33179
|
+
function pickModelConfigOption(configOptions) {
|
|
33180
|
+
if (configOptions == null || configOptions.length === 0) return null;
|
|
33181
|
+
return configOptions.find(looksLikeModelOption) ?? null;
|
|
33182
|
+
}
|
|
33183
|
+
async function applyAcpModelFromAcpSession(params) {
|
|
33184
|
+
const { sessionId, agentConfig, configOptions, setSessionConfigOption, logDebug: logDebug2 } = params;
|
|
33185
|
+
const desired = getAgentModelFromAgentConfig(agentConfig);
|
|
33186
|
+
if (desired == null) return;
|
|
33187
|
+
const modelOpt = pickModelConfigOption(configOptions ?? null);
|
|
33188
|
+
if (modelOpt == null) return;
|
|
33189
|
+
const flat = flattenSelectOptions2(modelOpt.options);
|
|
33190
|
+
const allowed = flat.some((o) => o.value === desired);
|
|
33191
|
+
if (!allowed) return;
|
|
33192
|
+
if (modelOpt.currentValue === desired) return;
|
|
33193
|
+
try {
|
|
33194
|
+
logDebug2(
|
|
33195
|
+
`[Agent] ACP session/set_config_option (model) configId=${JSON.stringify(modelOpt.id)} value=${JSON.stringify(desired)} was=${JSON.stringify(modelOpt.currentValue)} sessionId=${sessionId.slice(0, 8)}\u2026`
|
|
33196
|
+
);
|
|
33197
|
+
await setSessionConfigOption({ sessionId, configId: modelOpt.id, value: desired });
|
|
33198
|
+
} catch (e) {
|
|
33199
|
+
logDebug2(
|
|
33200
|
+
`[Agent] ACP session/set_config_option (model) failed: ${e instanceof Error ? e.message : String(e)}`
|
|
33201
|
+
);
|
|
33202
|
+
}
|
|
33203
|
+
}
|
|
33204
|
+
|
|
32809
33205
|
// src/agents/acp/clients/shared/config-options-for-permission.ts
|
|
32810
33206
|
function configOptionsForPermission(getActive, established) {
|
|
32811
33207
|
const mem = getActive?.();
|
|
@@ -32898,6 +33294,17 @@ async function bootstrapAcpWireSession(transport, ctx, initializeRequest) {
|
|
|
32898
33294
|
logDebug: ctx.logDebug
|
|
32899
33295
|
});
|
|
32900
33296
|
}
|
|
33297
|
+
const cfgAll = ctx.agentConfig != null && typeof ctx.agentConfig === "object" && !Array.isArray(ctx.agentConfig) ? ctx.agentConfig : null;
|
|
33298
|
+
const configOptionsForModel = established.configOptions;
|
|
33299
|
+
if (transport.setSessionConfigOption) {
|
|
33300
|
+
await applyAcpModelFromAcpSession({
|
|
33301
|
+
sessionId,
|
|
33302
|
+
agentConfig: cfgAll,
|
|
33303
|
+
configOptions: configOptionsForPermission(ctx.getActiveConfigOptions, configOptionsForModel),
|
|
33304
|
+
setSessionConfigOption: (p) => transport.setSessionConfigOption(p),
|
|
33305
|
+
logDebug: ctx.logDebug
|
|
33306
|
+
});
|
|
33307
|
+
}
|
|
32901
33308
|
return established;
|
|
32902
33309
|
}
|
|
32903
33310
|
|
|
@@ -33003,10 +33410,15 @@ async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText,
|
|
|
33003
33410
|
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
33004
33411
|
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
33005
33412
|
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
33006
|
-
return new Promise((
|
|
33007
|
-
pending.set(requestId, { resolve:
|
|
33413
|
+
return new Promise((resolve20) => {
|
|
33414
|
+
pending.set(requestId, { resolve: resolve20, params: paramsRecord });
|
|
33415
|
+
if (onRequest == null) {
|
|
33416
|
+
pending.delete(requestId);
|
|
33417
|
+
resolve20({ outcome: { outcome: "denied" } });
|
|
33418
|
+
return;
|
|
33419
|
+
}
|
|
33008
33420
|
try {
|
|
33009
|
-
onRequest
|
|
33421
|
+
onRequest({
|
|
33010
33422
|
requestId,
|
|
33011
33423
|
method: "session/request_permission",
|
|
33012
33424
|
params: paramsRecord
|
|
@@ -33068,7 +33480,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
33068
33480
|
child.once("close", (code, signal) => {
|
|
33069
33481
|
onAgentSubprocessExit?.({ code, signal });
|
|
33070
33482
|
});
|
|
33071
|
-
return new Promise((
|
|
33483
|
+
return new Promise((resolve20, reject) => {
|
|
33072
33484
|
let initSettled = false;
|
|
33073
33485
|
const settleReject = (err) => {
|
|
33074
33486
|
if (initSettled) return;
|
|
@@ -33082,7 +33494,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
33082
33494
|
const settleResolve = (handle) => {
|
|
33083
33495
|
if (initSettled) return;
|
|
33084
33496
|
initSettled = true;
|
|
33085
|
-
|
|
33497
|
+
resolve20(handle);
|
|
33086
33498
|
};
|
|
33087
33499
|
child.on("error", (err) => {
|
|
33088
33500
|
settleReject(new Error(formatSpawnError(err, command[0])));
|
|
@@ -33374,7 +33786,7 @@ async function createCursorAcpClient(options) {
|
|
|
33374
33786
|
logDebug,
|
|
33375
33787
|
getStderrText: () => stderrCapture.getText()
|
|
33376
33788
|
};
|
|
33377
|
-
return new Promise((
|
|
33789
|
+
return new Promise((resolve20, reject) => {
|
|
33378
33790
|
child.on("error", (err) => {
|
|
33379
33791
|
child.kill();
|
|
33380
33792
|
reject(new Error(formatSpawnError2(err, command[0])));
|
|
@@ -33453,12 +33865,16 @@ async function createCursorAcpClient(options) {
|
|
|
33453
33865
|
}
|
|
33454
33866
|
if (method === "session/request_permission" && typeof id === "number") {
|
|
33455
33867
|
const params = msg.params ?? {};
|
|
33456
|
-
|
|
33457
|
-
|
|
33458
|
-
|
|
33459
|
-
|
|
33460
|
-
|
|
33461
|
-
|
|
33868
|
+
if (onRequest) {
|
|
33869
|
+
pendingRequests.set(id, { method, params });
|
|
33870
|
+
onRequest({
|
|
33871
|
+
requestId: String(id),
|
|
33872
|
+
method,
|
|
33873
|
+
params
|
|
33874
|
+
});
|
|
33875
|
+
} else {
|
|
33876
|
+
respond(id, { outcome: { outcome: "denied" } });
|
|
33877
|
+
}
|
|
33462
33878
|
return;
|
|
33463
33879
|
}
|
|
33464
33880
|
if (typeof id === "number" && method) {
|
|
@@ -33546,7 +33962,7 @@ async function createCursorAcpClient(options) {
|
|
|
33546
33962
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
33547
33963
|
});
|
|
33548
33964
|
const sessionId = established.sessionId;
|
|
33549
|
-
|
|
33965
|
+
resolve20({
|
|
33550
33966
|
sessionId,
|
|
33551
33967
|
async sendPrompt(prompt, options2) {
|
|
33552
33968
|
const imgs = options2?.images?.map((im) => ({ type: "image", mimeType: im.mimeType, data: im.dataBase64 }));
|
|
@@ -33681,20 +34097,20 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
33681
34097
|
|
|
33682
34098
|
// src/agents/acp/session-file-change-path-kind.ts
|
|
33683
34099
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
33684
|
-
import { existsSync, statSync } from "node:fs";
|
|
34100
|
+
import { existsSync as existsSync2, statSync } from "node:fs";
|
|
33685
34101
|
|
|
33686
34102
|
// src/git/get-git-repo-root-sync.ts
|
|
33687
34103
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
33688
|
-
import * as
|
|
34104
|
+
import * as path17 from "node:path";
|
|
33689
34105
|
function getGitRepoRootSync(startDir) {
|
|
33690
34106
|
try {
|
|
33691
34107
|
const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
|
|
33692
|
-
cwd:
|
|
34108
|
+
cwd: path17.resolve(startDir),
|
|
33693
34109
|
encoding: "utf8",
|
|
33694
34110
|
stdio: ["ignore", "pipe", "ignore"],
|
|
33695
34111
|
maxBuffer: 1024 * 1024
|
|
33696
34112
|
}).trim();
|
|
33697
|
-
return out ?
|
|
34113
|
+
return out ? path17.resolve(out) : null;
|
|
33698
34114
|
} catch {
|
|
33699
34115
|
return null;
|
|
33700
34116
|
}
|
|
@@ -33702,26 +34118,26 @@ function getGitRepoRootSync(startDir) {
|
|
|
33702
34118
|
|
|
33703
34119
|
// src/agents/acp/workspace-files.ts
|
|
33704
34120
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
33705
|
-
import { readFileSync as
|
|
33706
|
-
import * as
|
|
34121
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
34122
|
+
import * as path18 from "node:path";
|
|
33707
34123
|
function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
|
|
33708
34124
|
const trimmed2 = rawPath.trim();
|
|
33709
34125
|
if (!trimmed2) return null;
|
|
33710
|
-
const normalizedSessionParent =
|
|
34126
|
+
const normalizedSessionParent = path18.resolve(sessionParentPath);
|
|
33711
34127
|
let resolvedPath = resolveSafePathUnderCwd(sessionParentPath, trimmed2);
|
|
33712
34128
|
if (!resolvedPath) {
|
|
33713
|
-
const candidate =
|
|
34129
|
+
const candidate = path18.isAbsolute(trimmed2) ? path18.normalize(trimmed2) : path18.normalize(path18.resolve(normalizedSessionParent, trimmed2));
|
|
33714
34130
|
const gitRoot2 = getGitRepoRootSync(sessionParentPath);
|
|
33715
34131
|
if (!gitRoot2) return null;
|
|
33716
|
-
const rel =
|
|
33717
|
-
if (rel.startsWith("..") ||
|
|
34132
|
+
const rel = path18.relative(gitRoot2, candidate);
|
|
34133
|
+
if (rel.startsWith("..") || path18.isAbsolute(rel)) return null;
|
|
33718
34134
|
resolvedPath = candidate;
|
|
33719
34135
|
}
|
|
33720
34136
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
33721
34137
|
if (gitRoot) {
|
|
33722
|
-
const relFromRoot =
|
|
33723
|
-
if (!relFromRoot.startsWith("..") && !
|
|
33724
|
-
return { resolvedPath, display: relFromRoot.split(
|
|
34138
|
+
const relFromRoot = path18.relative(gitRoot, resolvedPath);
|
|
34139
|
+
if (!relFromRoot.startsWith("..") && !path18.isAbsolute(relFromRoot)) {
|
|
34140
|
+
return { resolvedPath, display: relFromRoot.split(path18.sep).join("/") };
|
|
33725
34141
|
}
|
|
33726
34142
|
}
|
|
33727
34143
|
return { resolvedPath, display: toDisplayPathRelativeToCwd(sessionParentPath, resolvedPath) };
|
|
@@ -33730,11 +34146,11 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
33730
34146
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
33731
34147
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
33732
34148
|
if (gitRoot) {
|
|
33733
|
-
const resolvedPath2 =
|
|
33734
|
-
const rel =
|
|
33735
|
-
if (!rel.startsWith("..") && !
|
|
34149
|
+
const resolvedPath2 = path18.resolve(gitRoot, displayPath);
|
|
34150
|
+
const rel = path18.relative(gitRoot, resolvedPath2);
|
|
34151
|
+
if (!rel.startsWith("..") && !path18.isAbsolute(rel)) {
|
|
33736
34152
|
try {
|
|
33737
|
-
return
|
|
34153
|
+
return readFileSync4(resolvedPath2, "utf8");
|
|
33738
34154
|
} catch {
|
|
33739
34155
|
}
|
|
33740
34156
|
}
|
|
@@ -33742,7 +34158,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
33742
34158
|
const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
33743
34159
|
if (!resolvedPath) return "";
|
|
33744
34160
|
try {
|
|
33745
|
-
return
|
|
34161
|
+
return readFileSync4(resolvedPath, "utf8");
|
|
33746
34162
|
} catch {
|
|
33747
34163
|
return "";
|
|
33748
34164
|
}
|
|
@@ -33751,9 +34167,9 @@ function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
|
|
|
33751
34167
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
33752
34168
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
33753
34169
|
if (gitRoot) {
|
|
33754
|
-
const resolvedPath =
|
|
33755
|
-
const rel =
|
|
33756
|
-
if (!rel.startsWith("..") && !
|
|
34170
|
+
const resolvedPath = path18.resolve(gitRoot, displayPath);
|
|
34171
|
+
const rel = path18.relative(gitRoot, resolvedPath);
|
|
34172
|
+
if (!rel.startsWith("..") && !path18.isAbsolute(rel)) return resolvedPath;
|
|
33757
34173
|
}
|
|
33758
34174
|
return resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
33759
34175
|
}
|
|
@@ -33788,7 +34204,7 @@ function gitHeadPathObjectType(sessionParentPath, displayPath) {
|
|
|
33788
34204
|
}
|
|
33789
34205
|
function getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath) {
|
|
33790
34206
|
const resolvedPath = tryWorkspaceDisplayToPath(sessionParentPath, displayPath);
|
|
33791
|
-
if (resolvedPath &&
|
|
34207
|
+
if (resolvedPath && existsSync2(resolvedPath)) {
|
|
33792
34208
|
try {
|
|
33793
34209
|
if (statSync(resolvedPath).isDirectory()) {
|
|
33794
34210
|
return { isDirectory: true, directoryRemoved: false };
|
|
@@ -33888,7 +34304,7 @@ function createBridgeOnRequest(opts) {
|
|
|
33888
34304
|
}
|
|
33889
34305
|
|
|
33890
34306
|
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/paths-and-text.ts
|
|
33891
|
-
import { fileURLToPath as
|
|
34307
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
33892
34308
|
function readOptionalTextField(v) {
|
|
33893
34309
|
if (v === null || v === void 0) return "";
|
|
33894
34310
|
if (typeof v === "string") return v;
|
|
@@ -33898,7 +34314,7 @@ function normalizePathField(raw) {
|
|
|
33898
34314
|
const t = raw.trim();
|
|
33899
34315
|
if (t.startsWith("file://")) {
|
|
33900
34316
|
try {
|
|
33901
|
-
return
|
|
34317
|
+
return fileURLToPath3(t);
|
|
33902
34318
|
} catch {
|
|
33903
34319
|
return t;
|
|
33904
34320
|
}
|
|
@@ -34356,29 +34772,34 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
34356
34772
|
}
|
|
34357
34773
|
|
|
34358
34774
|
// src/agents/acp/local-agent-session-file.ts
|
|
34359
|
-
|
|
34360
|
-
import os3 from "node:os";
|
|
34361
|
-
import path12 from "node:path";
|
|
34362
|
-
var LOCAL_AGENT_SESSION_DIR = path12.join(os3.homedir(), ".buildautomaton", "agent-sessions");
|
|
34363
|
-
function safeFileSlug(cloudSessionId) {
|
|
34775
|
+
function sessionKeyForCloudSessionId(cloudSessionId) {
|
|
34364
34776
|
const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
|
|
34365
34777
|
return t.length > 0 ? t : "session";
|
|
34366
34778
|
}
|
|
34367
|
-
function localAgentSessionFilePath(cloudSessionId) {
|
|
34368
|
-
return path12.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
|
|
34369
|
-
}
|
|
34370
34779
|
function readLocalAgentSessionFile(cloudSessionId) {
|
|
34371
34780
|
try {
|
|
34372
|
-
const
|
|
34373
|
-
const
|
|
34374
|
-
const
|
|
34375
|
-
|
|
34781
|
+
const db = getCliDatabase();
|
|
34782
|
+
const key = sessionKeyForCloudSessionId(cloudSessionId);
|
|
34783
|
+
const row = db.get(
|
|
34784
|
+
"SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
|
|
34785
|
+
[key]
|
|
34786
|
+
);
|
|
34787
|
+
if (!row) return null;
|
|
34788
|
+
let configOptions = null;
|
|
34789
|
+
if (row.config_options_json != null && row.config_options_json !== "") {
|
|
34790
|
+
try {
|
|
34791
|
+
const parsed = JSON.parse(row.config_options_json);
|
|
34792
|
+
configOptions = Array.isArray(parsed) ? parsed : null;
|
|
34793
|
+
} catch {
|
|
34794
|
+
configOptions = null;
|
|
34795
|
+
}
|
|
34796
|
+
}
|
|
34376
34797
|
return {
|
|
34377
34798
|
v: 1,
|
|
34378
|
-
acpSessionId:
|
|
34379
|
-
backendAgentType:
|
|
34380
|
-
configOptions
|
|
34381
|
-
updatedAt:
|
|
34799
|
+
acpSessionId: row.acp_session_id,
|
|
34800
|
+
backendAgentType: row.backend_agent_type,
|
|
34801
|
+
configOptions,
|
|
34802
|
+
updatedAt: row.updated_at
|
|
34382
34803
|
};
|
|
34383
34804
|
} catch {
|
|
34384
34805
|
return null;
|
|
@@ -34386,9 +34807,8 @@ function readLocalAgentSessionFile(cloudSessionId) {
|
|
|
34386
34807
|
}
|
|
34387
34808
|
function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
34388
34809
|
try {
|
|
34389
|
-
const
|
|
34390
|
-
|
|
34391
|
-
const p = localAgentSessionFilePath(cloudSessionId);
|
|
34810
|
+
const db = getCliDatabase();
|
|
34811
|
+
const key = sessionKeyForCloudSessionId(cloudSessionId);
|
|
34392
34812
|
const prev = readLocalAgentSessionFile(cloudSessionId);
|
|
34393
34813
|
const next = {
|
|
34394
34814
|
v: 1,
|
|
@@ -34397,7 +34817,17 @@ function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
|
34397
34817
|
configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
|
|
34398
34818
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
34399
34819
|
};
|
|
34400
|
-
|
|
34820
|
+
const configJson = next.configOptions != null ? JSON.stringify(next.configOptions) : null;
|
|
34821
|
+
db.run(
|
|
34822
|
+
`INSERT INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
|
|
34823
|
+
VALUES (?, ?, ?, ?, ?)
|
|
34824
|
+
ON CONFLICT(session_key) DO UPDATE SET
|
|
34825
|
+
acp_session_id = excluded.acp_session_id,
|
|
34826
|
+
backend_agent_type = excluded.backend_agent_type,
|
|
34827
|
+
config_options_json = excluded.config_options_json,
|
|
34828
|
+
updated_at = excluded.updated_at`,
|
|
34829
|
+
[key, next.acpSessionId, next.backendAgentType, configJson, next.updatedAt]
|
|
34830
|
+
);
|
|
34401
34831
|
} catch {
|
|
34402
34832
|
}
|
|
34403
34833
|
}
|
|
@@ -34412,6 +34842,7 @@ async function ensureAcpClient(options) {
|
|
|
34412
34842
|
sessionParentPath,
|
|
34413
34843
|
routing,
|
|
34414
34844
|
cloudSessionId,
|
|
34845
|
+
reportAgentCapabilities,
|
|
34415
34846
|
sendSessionUpdate,
|
|
34416
34847
|
sendRequest,
|
|
34417
34848
|
log: log2
|
|
@@ -34421,7 +34852,7 @@ async function ensureAcpClient(options) {
|
|
|
34421
34852
|
if (state.acpStartPromise && !state.acpHandle) {
|
|
34422
34853
|
await state.acpStartPromise;
|
|
34423
34854
|
}
|
|
34424
|
-
if (state.acpHandle && state.lastAcpCwd != null &&
|
|
34855
|
+
if (state.acpHandle && state.lastAcpCwd != null && path19.resolve(state.lastAcpCwd) !== path19.resolve(targetSessionParentPath)) {
|
|
34425
34856
|
try {
|
|
34426
34857
|
state.acpHandle.disconnect();
|
|
34427
34858
|
} catch {
|
|
@@ -34456,7 +34887,7 @@ async function ensureAcpClient(options) {
|
|
|
34456
34887
|
if (!state.acpStartPromise) {
|
|
34457
34888
|
let statOk = false;
|
|
34458
34889
|
try {
|
|
34459
|
-
const st =
|
|
34890
|
+
const st = fs16.statSync(targetSessionParentPath);
|
|
34460
34891
|
statOk = st.isDirectory();
|
|
34461
34892
|
if (!statOk) {
|
|
34462
34893
|
state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
|
|
@@ -34499,6 +34930,12 @@ async function ensureAcpClient(options) {
|
|
|
34499
34930
|
backendAgentType: preferredAgentType
|
|
34500
34931
|
});
|
|
34501
34932
|
}
|
|
34933
|
+
if (reportAgentCapabilities && preferredAgentType && Array.isArray(info.configOptions) && info.configOptions.length > 0) {
|
|
34934
|
+
reportAgentCapabilities({
|
|
34935
|
+
agentType: preferredAgentType,
|
|
34936
|
+
configOptions: info.configOptions
|
|
34937
|
+
});
|
|
34938
|
+
}
|
|
34502
34939
|
},
|
|
34503
34940
|
onAcpConfigOptionsUpdated: (configOptions) => {
|
|
34504
34941
|
state.activeSessionConfigOptions = configOptions;
|
|
@@ -34508,6 +34945,12 @@ async function ensureAcpClient(options) {
|
|
|
34508
34945
|
backendAgentType: preferredAgentType
|
|
34509
34946
|
});
|
|
34510
34947
|
}
|
|
34948
|
+
if (reportAgentCapabilities && preferredAgentType && Array.isArray(configOptions) && configOptions.length > 0) {
|
|
34949
|
+
reportAgentCapabilities({
|
|
34950
|
+
agentType: preferredAgentType,
|
|
34951
|
+
configOptions
|
|
34952
|
+
});
|
|
34953
|
+
}
|
|
34511
34954
|
},
|
|
34512
34955
|
onAgentSubprocessExit: () => {
|
|
34513
34956
|
state.acpHandle = null;
|
|
@@ -34538,7 +34981,7 @@ async function ensureAcpClient(options) {
|
|
|
34538
34981
|
|
|
34539
34982
|
// src/agents/acp/create-acp-manager.ts
|
|
34540
34983
|
async function createAcpManager(options) {
|
|
34541
|
-
const { log: log2 } = options;
|
|
34984
|
+
const { log: log2, reportAgentCapabilities } = options;
|
|
34542
34985
|
const state = {
|
|
34543
34986
|
acpHandle: null,
|
|
34544
34987
|
acpStartPromise: null,
|
|
@@ -34582,7 +35025,8 @@ async function createAcpManager(options) {
|
|
|
34582
35025
|
cloudApiBaseUrl,
|
|
34583
35026
|
getCloudAccessToken,
|
|
34584
35027
|
e2ee,
|
|
34585
|
-
attachments
|
|
35028
|
+
attachments,
|
|
35029
|
+
agentId
|
|
34586
35030
|
} = opts;
|
|
34587
35031
|
const preferredForPrompt = agentType ?? backendFallbackAgentType ?? null;
|
|
34588
35032
|
pendingCancelRunId = void 0;
|
|
@@ -34600,7 +35044,8 @@ async function createAcpManager(options) {
|
|
|
34600
35044
|
cloudSessionId: sessionId,
|
|
34601
35045
|
sendSessionUpdate,
|
|
34602
35046
|
sendRequest: sendSessionUpdate,
|
|
34603
|
-
log: log2
|
|
35047
|
+
log: log2,
|
|
35048
|
+
reportAgentCapabilities
|
|
34604
35049
|
});
|
|
34605
35050
|
if (!handle) {
|
|
34606
35051
|
const errMsg = state.lastAcpStartError || "No agent configured. Register local agents on this bridge in the app.";
|
|
@@ -34703,12 +35148,12 @@ async function createAcpManager(options) {
|
|
|
34703
35148
|
}
|
|
34704
35149
|
|
|
34705
35150
|
// src/worktrees/session-worktree-manager.ts
|
|
34706
|
-
import * as
|
|
34707
|
-
import
|
|
35151
|
+
import * as path26 from "node:path";
|
|
35152
|
+
import os8 from "node:os";
|
|
34708
35153
|
|
|
34709
35154
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34710
|
-
import * as
|
|
34711
|
-
import * as
|
|
35155
|
+
import * as fs18 from "node:fs";
|
|
35156
|
+
import * as path21 from "node:path";
|
|
34712
35157
|
|
|
34713
35158
|
// src/git/worktree-add.ts
|
|
34714
35159
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
@@ -34717,12 +35162,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
|
34717
35162
|
}
|
|
34718
35163
|
|
|
34719
35164
|
// src/worktrees/worktree-layout-file.ts
|
|
34720
|
-
import * as
|
|
34721
|
-
import * as
|
|
34722
|
-
import
|
|
35165
|
+
import * as fs17 from "node:fs";
|
|
35166
|
+
import * as path20 from "node:path";
|
|
35167
|
+
import os7 from "node:os";
|
|
34723
35168
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
34724
35169
|
function defaultWorktreeLayoutPath() {
|
|
34725
|
-
return
|
|
35170
|
+
return path20.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
34726
35171
|
}
|
|
34727
35172
|
function normalizeLoadedLayout(raw) {
|
|
34728
35173
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -34734,8 +35179,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
34734
35179
|
function loadWorktreeLayout() {
|
|
34735
35180
|
try {
|
|
34736
35181
|
const p = defaultWorktreeLayoutPath();
|
|
34737
|
-
if (!
|
|
34738
|
-
const raw = JSON.parse(
|
|
35182
|
+
if (!fs17.existsSync(p)) return { launcherCwds: [] };
|
|
35183
|
+
const raw = JSON.parse(fs17.readFileSync(p, "utf8"));
|
|
34739
35184
|
return normalizeLoadedLayout(raw);
|
|
34740
35185
|
} catch {
|
|
34741
35186
|
return { launcherCwds: [] };
|
|
@@ -34743,24 +35188,24 @@ function loadWorktreeLayout() {
|
|
|
34743
35188
|
}
|
|
34744
35189
|
function saveWorktreeLayout(layout) {
|
|
34745
35190
|
try {
|
|
34746
|
-
const dir =
|
|
34747
|
-
|
|
34748
|
-
|
|
35191
|
+
const dir = path20.dirname(defaultWorktreeLayoutPath());
|
|
35192
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
35193
|
+
fs17.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
34749
35194
|
} catch {
|
|
34750
35195
|
}
|
|
34751
35196
|
}
|
|
34752
35197
|
function baseNameSafe(pathString) {
|
|
34753
|
-
return
|
|
35198
|
+
return path20.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
34754
35199
|
}
|
|
34755
35200
|
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
34756
|
-
const norm =
|
|
34757
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
35201
|
+
const norm = path20.resolve(bridgeRootPath2);
|
|
35202
|
+
const existing = layout.launcherCwds.find((e) => path20.resolve(e.absolutePath) === norm);
|
|
34758
35203
|
return existing?.dirName;
|
|
34759
35204
|
}
|
|
34760
35205
|
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
34761
35206
|
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
34762
35207
|
if (existing) return existing;
|
|
34763
|
-
const norm =
|
|
35208
|
+
const norm = path20.resolve(bridgeRootPath2);
|
|
34764
35209
|
const base = baseNameSafe(norm);
|
|
34765
35210
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
34766
35211
|
let name = base;
|
|
@@ -34777,10 +35222,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
|
34777
35222
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34778
35223
|
async function prepareNewSessionWorktrees(options) {
|
|
34779
35224
|
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
|
|
34780
|
-
const bridgeResolved =
|
|
35225
|
+
const bridgeResolved = path21.resolve(bridgeRoot);
|
|
34781
35226
|
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
34782
|
-
const bridgeKeyDir =
|
|
34783
|
-
const sessionDir =
|
|
35227
|
+
const bridgeKeyDir = path21.join(worktreesRootPath, cwdKey);
|
|
35228
|
+
const sessionDir = path21.join(bridgeKeyDir, sessionId);
|
|
34784
35229
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
34785
35230
|
if (repos.length === 0) {
|
|
34786
35231
|
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
@@ -34788,14 +35233,14 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
34788
35233
|
}
|
|
34789
35234
|
const branch = `session-${sessionId}`;
|
|
34790
35235
|
const worktreePaths = [];
|
|
34791
|
-
|
|
35236
|
+
fs18.mkdirSync(sessionDir, { recursive: true });
|
|
34792
35237
|
for (const repo of repos) {
|
|
34793
|
-
let rel =
|
|
34794
|
-
if (rel.startsWith("..") ||
|
|
35238
|
+
let rel = path21.relative(bridgeResolved, repo.absolutePath);
|
|
35239
|
+
if (rel.startsWith("..") || path21.isAbsolute(rel)) continue;
|
|
34795
35240
|
const relNorm = rel === "" ? "." : rel;
|
|
34796
|
-
const wtPath = relNorm === "." ? sessionDir :
|
|
35241
|
+
const wtPath = relNorm === "." ? sessionDir : path21.join(sessionDir, relNorm);
|
|
34797
35242
|
if (relNorm !== ".") {
|
|
34798
|
-
|
|
35243
|
+
fs18.mkdirSync(path21.dirname(wtPath), { recursive: true });
|
|
34799
35244
|
}
|
|
34800
35245
|
try {
|
|
34801
35246
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
@@ -34837,23 +35282,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
34837
35282
|
}
|
|
34838
35283
|
|
|
34839
35284
|
// src/worktrees/remove-session-worktrees.ts
|
|
34840
|
-
import * as
|
|
35285
|
+
import * as fs21 from "node:fs";
|
|
34841
35286
|
|
|
34842
35287
|
// src/git/worktree-remove.ts
|
|
34843
|
-
import * as
|
|
35288
|
+
import * as fs20 from "node:fs";
|
|
34844
35289
|
|
|
34845
35290
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
34846
|
-
import * as
|
|
34847
|
-
import * as
|
|
35291
|
+
import * as fs19 from "node:fs";
|
|
35292
|
+
import * as path22 from "node:path";
|
|
34848
35293
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
34849
|
-
const gitDirFile =
|
|
34850
|
-
if (!
|
|
34851
|
-
const first2 =
|
|
35294
|
+
const gitDirFile = path22.join(wt, ".git");
|
|
35295
|
+
if (!fs19.existsSync(gitDirFile) || !fs19.statSync(gitDirFile).isFile()) return "";
|
|
35296
|
+
const first2 = fs19.readFileSync(gitDirFile, "utf8").trim();
|
|
34852
35297
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
34853
35298
|
if (!m) return "";
|
|
34854
|
-
const gitWorktreePath =
|
|
34855
|
-
const gitDir =
|
|
34856
|
-
return
|
|
35299
|
+
const gitWorktreePath = path22.resolve(wt, m[1].trim());
|
|
35300
|
+
const gitDir = path22.dirname(path22.dirname(gitWorktreePath));
|
|
35301
|
+
return path22.dirname(gitDir);
|
|
34857
35302
|
}
|
|
34858
35303
|
|
|
34859
35304
|
// src/git/worktree-remove.ts
|
|
@@ -34862,7 +35307,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
34862
35307
|
if (mainRepo) {
|
|
34863
35308
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
34864
35309
|
} else {
|
|
34865
|
-
|
|
35310
|
+
fs20.rmSync(worktreePath, { recursive: true, force: true });
|
|
34866
35311
|
}
|
|
34867
35312
|
}
|
|
34868
35313
|
|
|
@@ -34875,7 +35320,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
34875
35320
|
} catch (e) {
|
|
34876
35321
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
34877
35322
|
try {
|
|
34878
|
-
|
|
35323
|
+
fs21.rmSync(wt, { recursive: true, force: true });
|
|
34879
35324
|
} catch {
|
|
34880
35325
|
}
|
|
34881
35326
|
}
|
|
@@ -35095,7 +35540,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
35095
35540
|
}
|
|
35096
35541
|
|
|
35097
35542
|
// src/git/working-directory/changes/get-working-tree-change-repo-details.ts
|
|
35098
|
-
import * as
|
|
35543
|
+
import * as path24 from "node:path";
|
|
35099
35544
|
|
|
35100
35545
|
// src/git/working-directory/changes/parse-git-status.ts
|
|
35101
35546
|
function parseNameStatusLines(lines) {
|
|
@@ -35215,8 +35660,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
35215
35660
|
}
|
|
35216
35661
|
|
|
35217
35662
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
35218
|
-
import * as
|
|
35219
|
-
import * as
|
|
35663
|
+
import * as fs23 from "node:fs";
|
|
35664
|
+
import * as path23 from "node:path";
|
|
35220
35665
|
|
|
35221
35666
|
// src/git/working-directory/changes/count-lines.ts
|
|
35222
35667
|
import { createReadStream } from "node:fs";
|
|
@@ -35240,7 +35685,7 @@ async function countTextFileLines(filePath) {
|
|
|
35240
35685
|
}
|
|
35241
35686
|
|
|
35242
35687
|
// src/git/working-directory/changes/hydrate-patch.ts
|
|
35243
|
-
import * as
|
|
35688
|
+
import * as fs22 from "node:fs";
|
|
35244
35689
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
35245
35690
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
35246
35691
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -35255,7 +35700,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
35255
35700
|
}
|
|
35256
35701
|
async function readWorktreeFileLines(filePath) {
|
|
35257
35702
|
try {
|
|
35258
|
-
const raw = await
|
|
35703
|
+
const raw = await fs22.promises.readFile(filePath, "utf8");
|
|
35259
35704
|
return raw.split(/\r?\n/);
|
|
35260
35705
|
} catch {
|
|
35261
35706
|
return null;
|
|
@@ -35390,7 +35835,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
35390
35835
|
const rows = [];
|
|
35391
35836
|
for (const pathInRepo of paths) {
|
|
35392
35837
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
35393
|
-
const repoFilePath =
|
|
35838
|
+
const repoFilePath = path23.join(repoGitCwd, pathInRepo);
|
|
35394
35839
|
const nums = numByPath.get(pathInRepo);
|
|
35395
35840
|
let additions = nums?.additions ?? 0;
|
|
35396
35841
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -35403,7 +35848,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
35403
35848
|
deletions = fromGit.deletions;
|
|
35404
35849
|
} else {
|
|
35405
35850
|
try {
|
|
35406
|
-
const st = await
|
|
35851
|
+
const st = await fs23.promises.stat(repoFilePath);
|
|
35407
35852
|
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
35408
35853
|
else additions = 0;
|
|
35409
35854
|
} catch {
|
|
@@ -35429,7 +35874,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
35429
35874
|
} else {
|
|
35430
35875
|
pathInRepo = row.pathRelLauncher;
|
|
35431
35876
|
}
|
|
35432
|
-
const filePath =
|
|
35877
|
+
const filePath = path23.join(repoGitCwd, pathInRepo);
|
|
35433
35878
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
35434
35879
|
if (patch) {
|
|
35435
35880
|
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
@@ -35445,8 +35890,8 @@ function normRepoRel(p) {
|
|
|
35445
35890
|
return x === "" ? "." : x;
|
|
35446
35891
|
}
|
|
35447
35892
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
35448
|
-
const bridgeRoot =
|
|
35449
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
35893
|
+
const bridgeRoot = path24.resolve(getBridgeRoot());
|
|
35894
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path24.resolve(options.sessionWorktreeRootPath) : null;
|
|
35450
35895
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
35451
35896
|
const out = [];
|
|
35452
35897
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -35459,7 +35904,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
35459
35904
|
}
|
|
35460
35905
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
35461
35906
|
for (const target of options.commitTargetPaths) {
|
|
35462
|
-
const t =
|
|
35907
|
+
const t = path24.resolve(target);
|
|
35463
35908
|
if (!await isGitRepoDirectory(t)) continue;
|
|
35464
35909
|
const g = cliSimpleGit(t);
|
|
35465
35910
|
let branch = "HEAD";
|
|
@@ -35472,8 +35917,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
35472
35917
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
35473
35918
|
let repoRelPath;
|
|
35474
35919
|
if (sessionWtRoot) {
|
|
35475
|
-
const anchor = legacyNested ?
|
|
35476
|
-
const relNorm =
|
|
35920
|
+
const anchor = legacyNested ? path24.dirname(t) : t;
|
|
35921
|
+
const relNorm = path24.relative(sessionWtRoot, anchor);
|
|
35477
35922
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
35478
35923
|
} else {
|
|
35479
35924
|
let top = t;
|
|
@@ -35482,8 +35927,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
35482
35927
|
} catch {
|
|
35483
35928
|
top = t;
|
|
35484
35929
|
}
|
|
35485
|
-
const rel =
|
|
35486
|
-
repoRelPath = rel.startsWith("..") ?
|
|
35930
|
+
const rel = path24.relative(bridgeRoot, path24.resolve(top)).replace(/\\/g, "/") || ".";
|
|
35931
|
+
repoRelPath = rel.startsWith("..") ? path24.basename(path24.resolve(top)) : rel;
|
|
35487
35932
|
}
|
|
35488
35933
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
35489
35934
|
if (filter && norm !== filter) continue;
|
|
@@ -35548,11 +35993,11 @@ async function commitSessionWorktrees(options) {
|
|
|
35548
35993
|
}
|
|
35549
35994
|
|
|
35550
35995
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
35551
|
-
import * as
|
|
35552
|
-
import * as
|
|
35996
|
+
import * as fs24 from "node:fs";
|
|
35997
|
+
import * as path25 from "node:path";
|
|
35553
35998
|
function isGitDir(dirPath) {
|
|
35554
35999
|
try {
|
|
35555
|
-
return
|
|
36000
|
+
return fs24.existsSync(path25.join(dirPath, ".git"));
|
|
35556
36001
|
} catch {
|
|
35557
36002
|
return false;
|
|
35558
36003
|
}
|
|
@@ -35561,23 +36006,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
35561
36006
|
const out = [];
|
|
35562
36007
|
const walk = (dir) => {
|
|
35563
36008
|
if (isGitDir(dir)) {
|
|
35564
|
-
out.push(
|
|
36009
|
+
out.push(path25.resolve(dir));
|
|
35565
36010
|
return;
|
|
35566
36011
|
}
|
|
35567
36012
|
let entries;
|
|
35568
36013
|
try {
|
|
35569
|
-
entries =
|
|
36014
|
+
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
35570
36015
|
} catch {
|
|
35571
36016
|
return;
|
|
35572
36017
|
}
|
|
35573
36018
|
for (const e of entries) {
|
|
35574
36019
|
if (e.name.startsWith(".")) continue;
|
|
35575
|
-
const full =
|
|
36020
|
+
const full = path25.join(dir, e.name);
|
|
35576
36021
|
if (!e.isDirectory()) continue;
|
|
35577
36022
|
walk(full);
|
|
35578
36023
|
}
|
|
35579
36024
|
};
|
|
35580
|
-
walk(
|
|
36025
|
+
walk(path25.resolve(rootPath));
|
|
35581
36026
|
return [...new Set(out)];
|
|
35582
36027
|
}
|
|
35583
36028
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -35586,16 +36031,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
35586
36031
|
if (depth > maxDepth) return;
|
|
35587
36032
|
let entries;
|
|
35588
36033
|
try {
|
|
35589
|
-
entries =
|
|
36034
|
+
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
35590
36035
|
} catch {
|
|
35591
36036
|
return;
|
|
35592
36037
|
}
|
|
35593
36038
|
for (const e of entries) {
|
|
35594
36039
|
if (e.name.startsWith(".")) continue;
|
|
35595
|
-
const full =
|
|
36040
|
+
const full = path25.join(dir, e.name);
|
|
35596
36041
|
if (!e.isDirectory()) continue;
|
|
35597
36042
|
if (e.name === sessionId) {
|
|
35598
|
-
if (isGitDir(full)) out.push(
|
|
36043
|
+
if (isGitDir(full)) out.push(path25.resolve(full));
|
|
35599
36044
|
} else {
|
|
35600
36045
|
walk(full, depth + 1);
|
|
35601
36046
|
}
|
|
@@ -35607,14 +36052,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
35607
36052
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
35608
36053
|
let st;
|
|
35609
36054
|
try {
|
|
35610
|
-
st =
|
|
36055
|
+
st = fs24.statSync(sessionDir);
|
|
35611
36056
|
} catch {
|
|
35612
36057
|
return null;
|
|
35613
36058
|
}
|
|
35614
36059
|
if (!st.isDirectory()) return null;
|
|
35615
36060
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
35616
36061
|
if (worktreePaths.length === 0) return null;
|
|
35617
|
-
const abs =
|
|
36062
|
+
const abs = path25.resolve(sessionDir);
|
|
35618
36063
|
return {
|
|
35619
36064
|
sessionParentPath: abs,
|
|
35620
36065
|
workingTreeRelRoot: abs,
|
|
@@ -35624,20 +36069,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
35624
36069
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
35625
36070
|
const sid = sessionId.trim();
|
|
35626
36071
|
if (!sid) return null;
|
|
35627
|
-
const hintR =
|
|
36072
|
+
const hintR = path25.resolve(checkoutPath);
|
|
35628
36073
|
let best = null;
|
|
35629
|
-
let cur =
|
|
36074
|
+
let cur = path25.dirname(hintR);
|
|
35630
36075
|
for (let i = 0; i < 40; i++) {
|
|
35631
36076
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
35632
|
-
if (paths.some((p) =>
|
|
35633
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
36077
|
+
if (paths.some((p) => path25.resolve(p) === hintR)) {
|
|
36078
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path25.resolve(paths[0]);
|
|
35634
36079
|
best = {
|
|
35635
|
-
sessionParentPath:
|
|
35636
|
-
workingTreeRelRoot:
|
|
35637
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
36080
|
+
sessionParentPath: path25.resolve(isolated),
|
|
36081
|
+
workingTreeRelRoot: path25.resolve(cur),
|
|
36082
|
+
repoCheckoutPaths: paths.map((p) => path25.resolve(p))
|
|
35638
36083
|
};
|
|
35639
36084
|
}
|
|
35640
|
-
const next =
|
|
36085
|
+
const next = path25.dirname(cur);
|
|
35641
36086
|
if (next === cur) break;
|
|
35642
36087
|
cur = next;
|
|
35643
36088
|
}
|
|
@@ -35645,33 +36090,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
35645
36090
|
}
|
|
35646
36091
|
function discoverSessionWorktreeOnDisk(options) {
|
|
35647
36092
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
35648
|
-
if (!sessionId.trim() || !
|
|
36093
|
+
if (!sessionId.trim() || !fs24.existsSync(worktreesRootPath)) return null;
|
|
35649
36094
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
35650
36095
|
const keys = [];
|
|
35651
36096
|
if (preferredKey) keys.push(preferredKey);
|
|
35652
36097
|
try {
|
|
35653
|
-
for (const name of
|
|
36098
|
+
for (const name of fs24.readdirSync(worktreesRootPath)) {
|
|
35654
36099
|
if (name.startsWith(".")) continue;
|
|
35655
|
-
const p =
|
|
35656
|
-
if (!
|
|
36100
|
+
const p = path25.join(worktreesRootPath, name);
|
|
36101
|
+
if (!fs24.statSync(p).isDirectory()) continue;
|
|
35657
36102
|
if (name !== preferredKey) keys.push(name);
|
|
35658
36103
|
}
|
|
35659
36104
|
} catch {
|
|
35660
36105
|
return null;
|
|
35661
36106
|
}
|
|
35662
36107
|
for (const key of keys) {
|
|
35663
|
-
const layoutRoot =
|
|
35664
|
-
if (!
|
|
35665
|
-
const sessionDir =
|
|
36108
|
+
const layoutRoot = path25.join(worktreesRootPath, key);
|
|
36109
|
+
if (!fs24.existsSync(layoutRoot) || !fs24.statSync(layoutRoot).isDirectory()) continue;
|
|
36110
|
+
const sessionDir = path25.join(layoutRoot, sessionId);
|
|
35666
36111
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
35667
36112
|
if (nested) return nested;
|
|
35668
36113
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
35669
36114
|
if (legacyPaths.length > 0) {
|
|
35670
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
36115
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
35671
36116
|
return {
|
|
35672
|
-
sessionParentPath:
|
|
35673
|
-
workingTreeRelRoot:
|
|
35674
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
36117
|
+
sessionParentPath: path25.resolve(isolated),
|
|
36118
|
+
workingTreeRelRoot: path25.resolve(layoutRoot),
|
|
36119
|
+
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
35675
36120
|
};
|
|
35676
36121
|
}
|
|
35677
36122
|
}
|
|
@@ -35680,12 +36125,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
35680
36125
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
35681
36126
|
const sid = sessionId.trim();
|
|
35682
36127
|
if (!sid) return null;
|
|
35683
|
-
const hint =
|
|
35684
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
36128
|
+
const hint = path25.resolve(sessionWorktreeRootPathOrHint);
|
|
36129
|
+
const underHint = tryBindingFromSessionDirectory(path25.join(hint, sid));
|
|
35685
36130
|
if (underHint) return underHint;
|
|
35686
36131
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
35687
36132
|
if (direct) {
|
|
35688
|
-
if (
|
|
36133
|
+
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
35689
36134
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
35690
36135
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
35691
36136
|
return legacyFromCheckout;
|
|
@@ -35693,24 +36138,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
35693
36138
|
}
|
|
35694
36139
|
return direct;
|
|
35695
36140
|
}
|
|
35696
|
-
if (
|
|
36141
|
+
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
35697
36142
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
35698
36143
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
35699
36144
|
}
|
|
35700
36145
|
let st;
|
|
35701
36146
|
try {
|
|
35702
|
-
st =
|
|
36147
|
+
st = fs24.statSync(hint);
|
|
35703
36148
|
} catch {
|
|
35704
36149
|
return null;
|
|
35705
36150
|
}
|
|
35706
36151
|
if (!st.isDirectory()) return null;
|
|
35707
36152
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
35708
36153
|
if (legacyPaths.length === 0) return null;
|
|
35709
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
36154
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
35710
36155
|
return {
|
|
35711
|
-
sessionParentPath:
|
|
36156
|
+
sessionParentPath: path25.resolve(isolated),
|
|
35712
36157
|
workingTreeRelRoot: hint,
|
|
35713
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
36158
|
+
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
35714
36159
|
};
|
|
35715
36160
|
}
|
|
35716
36161
|
|
|
@@ -35733,10 +36178,10 @@ var SessionWorktreeManager = class {
|
|
|
35733
36178
|
this.layout = loadWorktreeLayout();
|
|
35734
36179
|
}
|
|
35735
36180
|
rememberSessionWorktrees(sessionId, binding) {
|
|
35736
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
36181
|
+
const paths = binding.repoCheckoutPaths.map((p) => path26.resolve(p));
|
|
35737
36182
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
35738
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
35739
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
36183
|
+
this.sessionParentPathBySession.set(sessionId, path26.resolve(binding.sessionParentPath));
|
|
36184
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path26.resolve(binding.workingTreeRelRoot));
|
|
35740
36185
|
}
|
|
35741
36186
|
sessionParentPathAfterRemember(sessionId) {
|
|
35742
36187
|
return this.sessionParentPathBySession.get(sessionId);
|
|
@@ -35753,7 +36198,7 @@ var SessionWorktreeManager = class {
|
|
|
35753
36198
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
35754
36199
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
35755
36200
|
if (!parent || !relRoot) return false;
|
|
35756
|
-
return
|
|
36201
|
+
return path26.resolve(parent) !== path26.resolve(relRoot);
|
|
35757
36202
|
}
|
|
35758
36203
|
/**
|
|
35759
36204
|
* Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
|
|
@@ -35762,7 +36207,7 @@ var SessionWorktreeManager = class {
|
|
|
35762
36207
|
if (!sessionId) return null;
|
|
35763
36208
|
const sid = sessionId.trim();
|
|
35764
36209
|
const cached2 = this.sessionParentPathBySession.get(sid);
|
|
35765
|
-
if (cached2) return
|
|
36210
|
+
if (cached2) return path26.resolve(cached2);
|
|
35766
36211
|
const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
|
|
35767
36212
|
if (!paths?.length) return null;
|
|
35768
36213
|
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
@@ -35776,7 +36221,7 @@ var SessionWorktreeManager = class {
|
|
|
35776
36221
|
const sid = sessionId.trim();
|
|
35777
36222
|
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
35778
36223
|
if (parentPathRaw) {
|
|
35779
|
-
const resolved =
|
|
36224
|
+
const resolved = path26.resolve(parentPathRaw);
|
|
35780
36225
|
if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
|
|
35781
36226
|
const diskFirst = this.tryDiscoverFromDisk(sid);
|
|
35782
36227
|
if (diskFirst) {
|
|
@@ -35795,7 +36240,7 @@ var SessionWorktreeManager = class {
|
|
|
35795
36240
|
this.rememberSessionWorktrees(sid, tryRoot);
|
|
35796
36241
|
return this.sessionParentPathAfterRemember(sid);
|
|
35797
36242
|
}
|
|
35798
|
-
const next =
|
|
36243
|
+
const next = path26.dirname(cur);
|
|
35799
36244
|
if (next === cur) break;
|
|
35800
36245
|
cur = next;
|
|
35801
36246
|
}
|
|
@@ -35948,63 +36393,35 @@ var SessionWorktreeManager = class {
|
|
|
35948
36393
|
}
|
|
35949
36394
|
};
|
|
35950
36395
|
function defaultWorktreesRootPath() {
|
|
35951
|
-
return
|
|
36396
|
+
return path26.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
35952
36397
|
}
|
|
35953
36398
|
|
|
35954
36399
|
// src/files/watch-file-index.ts
|
|
35955
36400
|
import { watch } from "node:fs";
|
|
36401
|
+
import path31 from "node:path";
|
|
36402
|
+
|
|
36403
|
+
// src/files/index/paths.ts
|
|
35956
36404
|
import path27 from "node:path";
|
|
36405
|
+
import crypto2 from "node:crypto";
|
|
36406
|
+
function getCwdHashForFileIndex(resolvedCwd) {
|
|
36407
|
+
return crypto2.createHash("sha256").update(path27.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
36408
|
+
}
|
|
35957
36409
|
|
|
35958
36410
|
// src/files/index/build-file-index.ts
|
|
35959
|
-
import
|
|
36411
|
+
import path29 from "node:path";
|
|
35960
36412
|
|
|
35961
36413
|
// src/runtime/yield-to-event-loop.ts
|
|
35962
36414
|
function yieldToEventLoop() {
|
|
35963
|
-
return new Promise((
|
|
36415
|
+
return new Promise((resolve20) => setImmediate(resolve20));
|
|
35964
36416
|
}
|
|
35965
36417
|
|
|
35966
36418
|
// src/files/index/walk-workspace-tree.ts
|
|
35967
|
-
import
|
|
35968
|
-
import
|
|
35969
|
-
|
|
35970
|
-
// src/files/index/constants.ts
|
|
35971
|
-
import path21 from "node:path";
|
|
35972
|
-
import os6 from "node:os";
|
|
35973
|
-
var INDEX_WORK_YIELD_EVERY = 256;
|
|
35974
|
-
var INDEX_DIR = path21.join(os6.homedir(), ".buildautomaton");
|
|
35975
|
-
var INDEX_HASH_LEN = 16;
|
|
35976
|
-
var INDEX_VERSION = 2;
|
|
35977
|
-
var INDEX_LOG_PREFIX = "[file-index]";
|
|
35978
|
-
|
|
35979
|
-
// src/files/index/walk-workspace-tree.ts
|
|
35980
|
-
function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
35981
|
-
let names;
|
|
35982
|
-
try {
|
|
35983
|
-
names = fs20.readdirSync(dir);
|
|
35984
|
-
} catch {
|
|
35985
|
-
return;
|
|
35986
|
-
}
|
|
35987
|
-
for (const name of names) {
|
|
35988
|
-
if (name.startsWith(".")) continue;
|
|
35989
|
-
const full = path22.join(dir, name);
|
|
35990
|
-
let stat3;
|
|
35991
|
-
try {
|
|
35992
|
-
stat3 = fs20.statSync(full);
|
|
35993
|
-
} catch {
|
|
35994
|
-
continue;
|
|
35995
|
-
}
|
|
35996
|
-
const relative5 = path22.relative(baseDir, full).replace(/\\/g, "/");
|
|
35997
|
-
if (stat3.isDirectory()) {
|
|
35998
|
-
walkWorkspaceTreeSync(full, baseDir, out);
|
|
35999
|
-
} else if (stat3.isFile()) {
|
|
36000
|
-
out.push(relative5);
|
|
36001
|
-
}
|
|
36002
|
-
}
|
|
36003
|
-
}
|
|
36419
|
+
import fs25 from "node:fs";
|
|
36420
|
+
import path28 from "node:path";
|
|
36004
36421
|
async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
36005
36422
|
let names;
|
|
36006
36423
|
try {
|
|
36007
|
-
names = await
|
|
36424
|
+
names = await fs25.promises.readdir(dir);
|
|
36008
36425
|
} catch {
|
|
36009
36426
|
return;
|
|
36010
36427
|
}
|
|
@@ -36014,14 +36431,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
|
36014
36431
|
await yieldToEventLoop();
|
|
36015
36432
|
}
|
|
36016
36433
|
state.n++;
|
|
36017
|
-
const full =
|
|
36434
|
+
const full = path28.join(dir, name);
|
|
36018
36435
|
let stat3;
|
|
36019
36436
|
try {
|
|
36020
|
-
stat3 = await
|
|
36437
|
+
stat3 = await fs25.promises.stat(full);
|
|
36021
36438
|
} catch {
|
|
36022
36439
|
continue;
|
|
36023
36440
|
}
|
|
36024
|
-
const relative5 =
|
|
36441
|
+
const relative5 = path28.relative(baseDir, full).replace(/\\/g, "/");
|
|
36025
36442
|
if (stat3.isDirectory()) {
|
|
36026
36443
|
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
36027
36444
|
} else if (stat3.isFile()) {
|
|
@@ -36033,205 +36450,124 @@ function createWalkYieldState() {
|
|
|
36033
36450
|
return { n: 0 };
|
|
36034
36451
|
}
|
|
36035
36452
|
|
|
36036
|
-
// src/files/index/
|
|
36037
|
-
|
|
36038
|
-
|
|
36039
|
-
const
|
|
36040
|
-
|
|
36041
|
-
out.push(lower.slice(i, i + 3));
|
|
36042
|
-
}
|
|
36043
|
-
return out;
|
|
36044
|
-
}
|
|
36045
|
-
function binarySearch(arr, x) {
|
|
36046
|
-
let lo = 0;
|
|
36047
|
-
let hi = arr.length - 1;
|
|
36048
|
-
while (lo <= hi) {
|
|
36049
|
-
const mid = lo + hi >>> 1;
|
|
36050
|
-
if (arr[mid] < x) lo = mid + 1;
|
|
36051
|
-
else if (arr[mid] > x) hi = mid - 1;
|
|
36052
|
-
else return mid;
|
|
36053
|
-
}
|
|
36054
|
-
return -1;
|
|
36055
|
-
}
|
|
36056
|
-
function intersectSortedTrigramSets(arrays) {
|
|
36057
|
-
if (arrays.length === 0) return [];
|
|
36058
|
-
if (arrays.length === 1) return arrays[0];
|
|
36059
|
-
const byLength = arrays.slice().sort((a, b) => a.length - b.length);
|
|
36060
|
-
const smallest = byLength[0];
|
|
36061
|
-
const rest = byLength.slice(1);
|
|
36062
|
-
const result = [];
|
|
36063
|
-
for (const idx of smallest) {
|
|
36064
|
-
if (rest.every((arr) => binarySearch(arr, idx) >= 0)) {
|
|
36065
|
-
result.push(idx);
|
|
36066
|
-
}
|
|
36067
|
-
}
|
|
36068
|
-
return result;
|
|
36069
|
-
}
|
|
36070
|
-
|
|
36071
|
-
// src/files/index/build-trigram-map.ts
|
|
36072
|
-
function buildTrigramMapForPaths(paths) {
|
|
36073
|
-
const trigramIndex = {};
|
|
36074
|
-
for (let i = 0; i < paths.length; i++) {
|
|
36075
|
-
const trigrams = getTrigrams(paths[i]);
|
|
36076
|
-
const seen = /* @__PURE__ */ new Set();
|
|
36077
|
-
for (const tri of trigrams) {
|
|
36078
|
-
if (seen.has(tri)) continue;
|
|
36079
|
-
seen.add(tri);
|
|
36080
|
-
if (!trigramIndex[tri]) trigramIndex[tri] = [];
|
|
36081
|
-
trigramIndex[tri].push(i);
|
|
36082
|
-
}
|
|
36083
|
-
}
|
|
36084
|
-
return trigramIndex;
|
|
36453
|
+
// src/files/index/file-index-sqlite-lock.ts
|
|
36454
|
+
import fs26 from "node:fs";
|
|
36455
|
+
function isSqliteCorruptError(e) {
|
|
36456
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
36457
|
+
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
36085
36458
|
}
|
|
36086
|
-
|
|
36087
|
-
|
|
36088
|
-
|
|
36089
|
-
|
|
36090
|
-
await
|
|
36091
|
-
}
|
|
36092
|
-
|
|
36093
|
-
|
|
36094
|
-
|
|
36095
|
-
|
|
36096
|
-
|
|
36097
|
-
|
|
36098
|
-
|
|
36459
|
+
var chain = Promise.resolve();
|
|
36460
|
+
function withFileIndexSqliteLock(fn) {
|
|
36461
|
+
const run = async () => {
|
|
36462
|
+
try {
|
|
36463
|
+
return await Promise.resolve(fn());
|
|
36464
|
+
} catch (e) {
|
|
36465
|
+
if (!isSqliteCorruptError(e)) throw e;
|
|
36466
|
+
closeAllCliSqliteConnections();
|
|
36467
|
+
try {
|
|
36468
|
+
fs26.unlinkSync(getCliSqlitePath());
|
|
36469
|
+
} catch {
|
|
36470
|
+
}
|
|
36471
|
+
chain = Promise.resolve();
|
|
36472
|
+
return await Promise.resolve(fn());
|
|
36099
36473
|
}
|
|
36100
|
-
}
|
|
36101
|
-
|
|
36102
|
-
|
|
36103
|
-
|
|
36104
|
-
|
|
36105
|
-
|
|
36106
|
-
|
|
36107
|
-
// src/files/index/paths.ts
|
|
36108
|
-
import path23 from "node:path";
|
|
36109
|
-
import crypto2 from "node:crypto";
|
|
36110
|
-
function getIndexPathForCwd(resolvedCwd) {
|
|
36111
|
-
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
36112
|
-
return path23.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
36113
|
-
}
|
|
36114
|
-
|
|
36115
|
-
// src/files/index/write-index-file.ts
|
|
36116
|
-
function writeIndexFileSync(resolvedCwd, data) {
|
|
36117
|
-
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
36118
|
-
try {
|
|
36119
|
-
if (!fs21.existsSync(INDEX_DIR)) fs21.mkdirSync(INDEX_DIR, { recursive: true });
|
|
36120
|
-
fs21.writeFileSync(indexPath, JSON.stringify(data), "utf8");
|
|
36121
|
-
} catch (e) {
|
|
36122
|
-
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
36123
|
-
}
|
|
36124
|
-
}
|
|
36125
|
-
async function writeIndexFileAsync(resolvedCwd, data) {
|
|
36126
|
-
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
36127
|
-
try {
|
|
36128
|
-
await fs21.promises.mkdir(INDEX_DIR, { recursive: true });
|
|
36129
|
-
await fs21.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
|
|
36130
|
-
} catch (e) {
|
|
36131
|
-
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
36132
|
-
}
|
|
36133
|
-
}
|
|
36134
|
-
function makeTrigramIndexData(paths, trigramIndex) {
|
|
36135
|
-
return { version: INDEX_VERSION, paths, trigramIndex };
|
|
36474
|
+
};
|
|
36475
|
+
const next = chain.then(run);
|
|
36476
|
+
chain = next.then(
|
|
36477
|
+
() => void 0,
|
|
36478
|
+
() => void 0
|
|
36479
|
+
);
|
|
36480
|
+
return next;
|
|
36136
36481
|
}
|
|
36137
36482
|
|
|
36138
36483
|
// src/files/index/build-file-index.ts
|
|
36139
36484
|
function sortPaths(paths) {
|
|
36140
36485
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
36141
36486
|
}
|
|
36142
|
-
function
|
|
36143
|
-
const
|
|
36144
|
-
const
|
|
36145
|
-
|
|
36146
|
-
sortPaths(paths);
|
|
36147
|
-
const trigramIndex = buildTrigramMapForPaths(paths);
|
|
36148
|
-
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
36149
|
-
writeIndexFileSync(resolved, data);
|
|
36150
|
-
return data;
|
|
36151
|
-
}
|
|
36152
|
-
async function buildFileIndexAsync(cwd) {
|
|
36153
|
-
const resolved = path24.resolve(cwd);
|
|
36154
|
-
const paths = [];
|
|
36155
|
-
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
36156
|
-
await yieldToEventLoop();
|
|
36157
|
-
sortPaths(paths);
|
|
36158
|
-
const trigramIndex = await buildTrigramMapForPathsAsync(paths);
|
|
36159
|
-
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
36160
|
-
await writeIndexFileAsync(resolved, data);
|
|
36161
|
-
return data;
|
|
36162
|
-
}
|
|
36163
|
-
|
|
36164
|
-
// src/files/index/load-file-index.ts
|
|
36165
|
-
import fs22 from "node:fs";
|
|
36166
|
-
import path25 from "node:path";
|
|
36167
|
-
function loadFileIndex(cwd) {
|
|
36168
|
-
const resolved = path25.resolve(cwd);
|
|
36169
|
-
const indexPath = getIndexPathForCwd(resolved);
|
|
36487
|
+
function persistPathsToSqlite(resolved, paths) {
|
|
36488
|
+
const db = getCliDatabase();
|
|
36489
|
+
const h = getCwdHashForFileIndex(resolved);
|
|
36490
|
+
db.run("BEGIN IMMEDIATE");
|
|
36170
36491
|
try {
|
|
36171
|
-
|
|
36172
|
-
const
|
|
36173
|
-
|
|
36174
|
-
const
|
|
36175
|
-
|
|
36176
|
-
return obj;
|
|
36492
|
+
db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
36493
|
+
const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
|
|
36494
|
+
try {
|
|
36495
|
+
for (const rel of paths) {
|
|
36496
|
+
ins.run([h, rel]);
|
|
36177
36497
|
}
|
|
36178
|
-
|
|
36498
|
+
} finally {
|
|
36499
|
+
ins.finalize();
|
|
36179
36500
|
}
|
|
36180
|
-
|
|
36181
|
-
|
|
36501
|
+
db.run("COMMIT");
|
|
36502
|
+
} catch (e) {
|
|
36503
|
+
try {
|
|
36504
|
+
db.run("ROLLBACK");
|
|
36505
|
+
} catch {
|
|
36182
36506
|
}
|
|
36183
|
-
|
|
36184
|
-
} catch {
|
|
36185
|
-
return null;
|
|
36507
|
+
throw e;
|
|
36186
36508
|
}
|
|
36187
36509
|
}
|
|
36510
|
+
async function buildFileIndexAsync(cwd) {
|
|
36511
|
+
return withFileIndexSqliteLock(async () => {
|
|
36512
|
+
const resolved = path29.resolve(cwd);
|
|
36513
|
+
const paths = [];
|
|
36514
|
+
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
36515
|
+
await yieldToEventLoop();
|
|
36516
|
+
sortPaths(paths);
|
|
36517
|
+
persistPathsToSqlite(resolved, paths);
|
|
36518
|
+
return { pathCount: paths.length };
|
|
36519
|
+
});
|
|
36520
|
+
}
|
|
36188
36521
|
|
|
36189
36522
|
// src/files/index/ensure-file-index.ts
|
|
36190
|
-
import
|
|
36191
|
-
async function ensureFileIndexAsync(cwd) {
|
|
36192
|
-
const resolved = path26.resolve(cwd);
|
|
36193
|
-
const cached2 = loadFileIndex(resolved);
|
|
36194
|
-
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
36195
|
-
const data = await buildFileIndexAsync(resolved);
|
|
36196
|
-
return { data, fromCache: false };
|
|
36197
|
-
}
|
|
36523
|
+
import path30 from "node:path";
|
|
36198
36524
|
|
|
36199
36525
|
// src/files/index/search-file-index.ts
|
|
36200
|
-
function
|
|
36201
|
-
|
|
36202
|
-
|
|
36203
|
-
|
|
36204
|
-
|
|
36205
|
-
const
|
|
36206
|
-
|
|
36207
|
-
|
|
36208
|
-
|
|
36209
|
-
|
|
36210
|
-
|
|
36211
|
-
|
|
36212
|
-
|
|
36213
|
-
|
|
36214
|
-
|
|
36526
|
+
function escapeLikePattern(fragment) {
|
|
36527
|
+
return fragment.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
36528
|
+
}
|
|
36529
|
+
function bridgeFileIndexIsPopulated(resolvedCwd) {
|
|
36530
|
+
const db = getCliDatabase();
|
|
36531
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
36532
|
+
const row = db.get("SELECT 1 as ok FROM file_index_path WHERE cwd_hash = ? LIMIT 1", [h]);
|
|
36533
|
+
return row != null;
|
|
36534
|
+
}
|
|
36535
|
+
function bridgeFileIndexPathCount(resolvedCwd) {
|
|
36536
|
+
const db = getCliDatabase();
|
|
36537
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
36538
|
+
const row = db.get("SELECT COUNT(*) as c FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
36539
|
+
const c = row?.c ?? 0;
|
|
36540
|
+
return Number(c);
|
|
36541
|
+
}
|
|
36542
|
+
function searchBridgeFilePaths(resolvedCwd, query, limit = 100) {
|
|
36215
36543
|
const q = query.trim().toLowerCase();
|
|
36216
36544
|
if (!q) return [];
|
|
36217
|
-
const
|
|
36218
|
-
const
|
|
36219
|
-
const
|
|
36220
|
-
|
|
36221
|
-
|
|
36222
|
-
|
|
36223
|
-
|
|
36224
|
-
|
|
36225
|
-
|
|
36226
|
-
|
|
36227
|
-
|
|
36228
|
-
|
|
36229
|
-
|
|
36230
|
-
|
|
36231
|
-
}
|
|
36545
|
+
const db = getCliDatabase();
|
|
36546
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
36547
|
+
const pattern = `%${escapeLikePattern(q)}%`;
|
|
36548
|
+
const lim = Math.max(0, Math.min(1e4, Math.floor(limit)));
|
|
36549
|
+
const rows = db.all(
|
|
36550
|
+
`SELECT path FROM file_index_path WHERE cwd_hash = ? AND lower(path) LIKE ? ESCAPE '\\' LIMIT ?`,
|
|
36551
|
+
[h, pattern, lim]
|
|
36552
|
+
);
|
|
36553
|
+
return rows.map((r) => String(r.path));
|
|
36554
|
+
}
|
|
36555
|
+
async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
36556
|
+
await yieldToEventLoop();
|
|
36557
|
+
const out = searchBridgeFilePaths(resolvedCwd, query, limit);
|
|
36558
|
+
if (out.length >= INDEX_WORK_YIELD_EVERY) await yieldToEventLoop();
|
|
36232
36559
|
return out;
|
|
36233
36560
|
}
|
|
36234
36561
|
|
|
36562
|
+
// src/files/index/ensure-file-index.ts
|
|
36563
|
+
async function ensureFileIndexAsync(cwd) {
|
|
36564
|
+
const resolved = path30.resolve(cwd);
|
|
36565
|
+
if (bridgeFileIndexIsPopulated(resolved)) {
|
|
36566
|
+
return { fromCache: true, pathCount: bridgeFileIndexPathCount(resolved) };
|
|
36567
|
+
}
|
|
36568
|
+
return { ...await buildFileIndexAsync(resolved), fromCache: false };
|
|
36569
|
+
}
|
|
36570
|
+
|
|
36235
36571
|
// src/files/watch-file-index.ts
|
|
36236
36572
|
var DEBOUNCE_MS = 900;
|
|
36237
36573
|
function shouldIgnoreRelative(rel) {
|
|
@@ -36272,7 +36608,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
36272
36608
|
}
|
|
36273
36609
|
}
|
|
36274
36610
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
36275
|
-
const resolved =
|
|
36611
|
+
const resolved = path31.resolve(cwd);
|
|
36276
36612
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
36277
36613
|
console.error("[file-index] Initial index build failed:", e);
|
|
36278
36614
|
});
|
|
@@ -36300,7 +36636,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
36300
36636
|
}
|
|
36301
36637
|
|
|
36302
36638
|
// src/connection/create-bridge-connection.ts
|
|
36303
|
-
import * as
|
|
36639
|
+
import * as path41 from "node:path";
|
|
36304
36640
|
|
|
36305
36641
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
36306
36642
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -36322,15 +36658,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
|
|
|
36322
36658
|
|
|
36323
36659
|
// src/dev-servers/process/terminate-child-process.ts
|
|
36324
36660
|
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
36325
|
-
const exited = new Promise((
|
|
36326
|
-
proc.once("exit", () =>
|
|
36661
|
+
const exited = new Promise((resolve20) => {
|
|
36662
|
+
proc.once("exit", () => resolve20());
|
|
36327
36663
|
});
|
|
36328
36664
|
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
|
|
36329
36665
|
try {
|
|
36330
36666
|
proc.kill("SIGTERM");
|
|
36331
36667
|
} catch {
|
|
36332
36668
|
}
|
|
36333
|
-
await Promise.race([exited, new Promise((
|
|
36669
|
+
await Promise.race([exited, new Promise((resolve20) => setTimeout(resolve20, graceMs))]);
|
|
36334
36670
|
}
|
|
36335
36671
|
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
36336
36672
|
log2(
|
|
@@ -36344,7 +36680,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
36344
36680
|
}
|
|
36345
36681
|
|
|
36346
36682
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
36347
|
-
import
|
|
36683
|
+
import fs27 from "node:fs";
|
|
36348
36684
|
|
|
36349
36685
|
// src/dev-servers/manager/forward-pipe.ts
|
|
36350
36686
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -36380,7 +36716,7 @@ function wireDevServerChildProcess(d) {
|
|
|
36380
36716
|
d.setPollInterval(void 0);
|
|
36381
36717
|
return;
|
|
36382
36718
|
}
|
|
36383
|
-
|
|
36719
|
+
fs27.readFile(d.mergedLogPath, (err, buf) => {
|
|
36384
36720
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
36385
36721
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
36386
36722
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -36418,7 +36754,7 @@ ${errTail}` : ""}`);
|
|
|
36418
36754
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
36419
36755
|
};
|
|
36420
36756
|
if (mergedPath) {
|
|
36421
|
-
|
|
36757
|
+
fs27.readFile(mergedPath, (err, buf) => {
|
|
36422
36758
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
36423
36759
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
36424
36760
|
if (chunk.length > 0) {
|
|
@@ -36520,13 +36856,13 @@ function parseDevServerDefs(servers) {
|
|
|
36520
36856
|
}
|
|
36521
36857
|
|
|
36522
36858
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
36523
|
-
import
|
|
36859
|
+
import fs28 from "node:fs";
|
|
36524
36860
|
function isSpawnEbadf(e) {
|
|
36525
36861
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
36526
36862
|
}
|
|
36527
36863
|
function rmDirQuiet(dir) {
|
|
36528
36864
|
try {
|
|
36529
|
-
|
|
36865
|
+
fs28.rmSync(dir, { recursive: true, force: true });
|
|
36530
36866
|
} catch {
|
|
36531
36867
|
}
|
|
36532
36868
|
}
|
|
@@ -36534,7 +36870,7 @@ var cachedDevNullReadFd;
|
|
|
36534
36870
|
function devNullReadFd() {
|
|
36535
36871
|
if (cachedDevNullReadFd === void 0) {
|
|
36536
36872
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
36537
|
-
cachedDevNullReadFd =
|
|
36873
|
+
cachedDevNullReadFd = fs28.openSync(devPath, "r");
|
|
36538
36874
|
}
|
|
36539
36875
|
return cachedDevNullReadFd;
|
|
36540
36876
|
}
|
|
@@ -36608,15 +36944,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
36608
36944
|
|
|
36609
36945
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
36610
36946
|
import { spawn as spawn6 } from "node:child_process";
|
|
36611
|
-
import
|
|
36947
|
+
import fs29 from "node:fs";
|
|
36612
36948
|
import { tmpdir } from "node:os";
|
|
36613
|
-
import
|
|
36949
|
+
import path32 from "node:path";
|
|
36614
36950
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
36615
|
-
const tmpRoot =
|
|
36616
|
-
const logPath =
|
|
36951
|
+
const tmpRoot = fs29.mkdtempSync(path32.join(tmpdir(), "ba-devsrv-log-"));
|
|
36952
|
+
const logPath = path32.join(tmpRoot, "combined.log");
|
|
36617
36953
|
let logFd;
|
|
36618
36954
|
try {
|
|
36619
|
-
logFd =
|
|
36955
|
+
logFd = fs29.openSync(logPath, "a");
|
|
36620
36956
|
} catch {
|
|
36621
36957
|
rmDirQuiet(tmpRoot);
|
|
36622
36958
|
return null;
|
|
@@ -36635,7 +36971,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36635
36971
|
} else {
|
|
36636
36972
|
proc = spawn6("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
36637
36973
|
}
|
|
36638
|
-
|
|
36974
|
+
fs29.closeSync(logFd);
|
|
36639
36975
|
return {
|
|
36640
36976
|
proc,
|
|
36641
36977
|
pipedStdoutStderr: true,
|
|
@@ -36644,7 +36980,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36644
36980
|
};
|
|
36645
36981
|
} catch (e) {
|
|
36646
36982
|
try {
|
|
36647
|
-
|
|
36983
|
+
fs29.closeSync(logFd);
|
|
36648
36984
|
} catch {
|
|
36649
36985
|
}
|
|
36650
36986
|
rmDirQuiet(tmpRoot);
|
|
@@ -36655,22 +36991,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36655
36991
|
|
|
36656
36992
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
36657
36993
|
import { spawn as spawn7 } from "node:child_process";
|
|
36658
|
-
import
|
|
36994
|
+
import fs30 from "node:fs";
|
|
36659
36995
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
36660
|
-
import
|
|
36996
|
+
import path33 from "node:path";
|
|
36661
36997
|
function shSingleQuote(s) {
|
|
36662
36998
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
36663
36999
|
}
|
|
36664
37000
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
36665
|
-
const tmpRoot =
|
|
36666
|
-
const logPath =
|
|
36667
|
-
const innerPath =
|
|
36668
|
-
const runnerPath =
|
|
37001
|
+
const tmpRoot = fs30.mkdtempSync(path33.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
37002
|
+
const logPath = path33.join(tmpRoot, "combined.log");
|
|
37003
|
+
const innerPath = path33.join(tmpRoot, "_cmd.sh");
|
|
37004
|
+
const runnerPath = path33.join(tmpRoot, "_run.sh");
|
|
36669
37005
|
try {
|
|
36670
|
-
|
|
37006
|
+
fs30.writeFileSync(innerPath, `#!/bin/sh
|
|
36671
37007
|
${command}
|
|
36672
37008
|
`);
|
|
36673
|
-
|
|
37009
|
+
fs30.writeFileSync(
|
|
36674
37010
|
runnerPath,
|
|
36675
37011
|
`#!/bin/sh
|
|
36676
37012
|
cd ${shSingleQuote(cwd)}
|
|
@@ -36696,13 +37032,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
36696
37032
|
}
|
|
36697
37033
|
}
|
|
36698
37034
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
36699
|
-
const tmpRoot =
|
|
36700
|
-
const logPath =
|
|
36701
|
-
const runnerPath =
|
|
37035
|
+
const tmpRoot = fs30.mkdtempSync(path33.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
37036
|
+
const logPath = path33.join(tmpRoot, "combined.log");
|
|
37037
|
+
const runnerPath = path33.join(tmpRoot, "_run.bat");
|
|
36702
37038
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
36703
37039
|
const com = process.env.ComSpec || "cmd.exe";
|
|
36704
37040
|
try {
|
|
36705
|
-
|
|
37041
|
+
fs30.writeFileSync(
|
|
36706
37042
|
runnerPath,
|
|
36707
37043
|
`@ECHO OFF\r
|
|
36708
37044
|
CD /D ${q(cwd)}\r
|
|
@@ -37213,7 +37549,7 @@ async function proxyToLocal(request) {
|
|
|
37213
37549
|
};
|
|
37214
37550
|
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
37215
37551
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
37216
|
-
const once = await new Promise((
|
|
37552
|
+
const once = await new Promise((resolve20) => {
|
|
37217
37553
|
const req = mod.request(opts, (res) => {
|
|
37218
37554
|
const chunks = [];
|
|
37219
37555
|
res.on("data", (c) => chunks.push(c));
|
|
@@ -37224,7 +37560,7 @@ async function proxyToLocal(request) {
|
|
|
37224
37560
|
if (typeof v === "string") headers[k] = v;
|
|
37225
37561
|
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
37226
37562
|
}
|
|
37227
|
-
|
|
37563
|
+
resolve20({
|
|
37228
37564
|
id: request.id,
|
|
37229
37565
|
statusCode: res.statusCode ?? 0,
|
|
37230
37566
|
headers,
|
|
@@ -37233,7 +37569,7 @@ async function proxyToLocal(request) {
|
|
|
37233
37569
|
});
|
|
37234
37570
|
});
|
|
37235
37571
|
req.on("error", (err) => {
|
|
37236
|
-
|
|
37572
|
+
resolve20({
|
|
37237
37573
|
id: request.id,
|
|
37238
37574
|
statusCode: 0,
|
|
37239
37575
|
headers: {},
|
|
@@ -37639,30 +37975,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
37639
37975
|
}
|
|
37640
37976
|
|
|
37641
37977
|
// src/skills/discover-local-agent-skills.ts
|
|
37642
|
-
import
|
|
37643
|
-
import
|
|
37978
|
+
import fs31 from "node:fs";
|
|
37979
|
+
import path34 from "node:path";
|
|
37644
37980
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
37645
37981
|
function discoverLocalSkills(cwd) {
|
|
37646
37982
|
const out = [];
|
|
37647
37983
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
37648
37984
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
37649
|
-
const base =
|
|
37650
|
-
if (!
|
|
37985
|
+
const base = path34.join(cwd, rel);
|
|
37986
|
+
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
37651
37987
|
let entries = [];
|
|
37652
37988
|
try {
|
|
37653
|
-
entries =
|
|
37989
|
+
entries = fs31.readdirSync(base);
|
|
37654
37990
|
} catch {
|
|
37655
37991
|
continue;
|
|
37656
37992
|
}
|
|
37657
37993
|
for (const name of entries) {
|
|
37658
|
-
const dir =
|
|
37994
|
+
const dir = path34.join(base, name);
|
|
37659
37995
|
try {
|
|
37660
|
-
if (!
|
|
37996
|
+
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
37661
37997
|
} catch {
|
|
37662
37998
|
continue;
|
|
37663
37999
|
}
|
|
37664
|
-
const skillMd =
|
|
37665
|
-
if (!
|
|
38000
|
+
const skillMd = path34.join(dir, "SKILL.md");
|
|
38001
|
+
if (!fs31.existsSync(skillMd)) continue;
|
|
37666
38002
|
const key = `${rel}/${name}`;
|
|
37667
38003
|
if (seenKeys.has(key)) continue;
|
|
37668
38004
|
seenKeys.add(key);
|
|
@@ -37674,23 +38010,23 @@ function discoverLocalSkills(cwd) {
|
|
|
37674
38010
|
function discoverSkillLayoutRoots(cwd) {
|
|
37675
38011
|
const roots = [];
|
|
37676
38012
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
37677
|
-
const base =
|
|
37678
|
-
if (!
|
|
38013
|
+
const base = path34.join(cwd, rel);
|
|
38014
|
+
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
37679
38015
|
let entries = [];
|
|
37680
38016
|
try {
|
|
37681
|
-
entries =
|
|
38017
|
+
entries = fs31.readdirSync(base);
|
|
37682
38018
|
} catch {
|
|
37683
38019
|
continue;
|
|
37684
38020
|
}
|
|
37685
38021
|
const skills2 = [];
|
|
37686
38022
|
for (const name of entries) {
|
|
37687
|
-
const dir =
|
|
38023
|
+
const dir = path34.join(base, name);
|
|
37688
38024
|
try {
|
|
37689
|
-
if (!
|
|
38025
|
+
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
37690
38026
|
} catch {
|
|
37691
38027
|
continue;
|
|
37692
38028
|
}
|
|
37693
|
-
if (!
|
|
38029
|
+
if (!fs31.existsSync(path34.join(dir, "SKILL.md"))) continue;
|
|
37694
38030
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
37695
38031
|
skills2.push({ name, relPath });
|
|
37696
38032
|
}
|
|
@@ -37852,6 +38188,13 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
37852
38188
|
`[Bridge service] Auto-detect agents failed: ${e instanceof Error ? e.message : String(e)}`
|
|
37853
38189
|
);
|
|
37854
38190
|
}
|
|
38191
|
+
try {
|
|
38192
|
+
await deps.warmupAgentCapabilitiesOnConnect?.();
|
|
38193
|
+
} catch (e) {
|
|
38194
|
+
deps.log(
|
|
38195
|
+
`[Bridge service] Agent capability warmup failed: ${e instanceof Error ? e.message : String(e)}`
|
|
38196
|
+
);
|
|
38197
|
+
}
|
|
37855
38198
|
})();
|
|
37856
38199
|
});
|
|
37857
38200
|
setImmediate(() => {
|
|
@@ -37884,7 +38227,7 @@ var handleAgentConfigMessage = (msg, deps) => {
|
|
|
37884
38227
|
};
|
|
37885
38228
|
|
|
37886
38229
|
// src/prompt-turn-queue/runner.ts
|
|
37887
|
-
import
|
|
38230
|
+
import fs32 from "node:fs";
|
|
37888
38231
|
|
|
37889
38232
|
// src/prompt-turn-queue/client-report.ts
|
|
37890
38233
|
function sendPromptQueueClientReport(ws, queues) {
|
|
@@ -37893,32 +38236,6 @@ function sendPromptQueueClientReport(ws, queues) {
|
|
|
37893
38236
|
return true;
|
|
37894
38237
|
}
|
|
37895
38238
|
|
|
37896
|
-
// src/prompt-turn-queue/disk-store.ts
|
|
37897
|
-
import fs29 from "node:fs";
|
|
37898
|
-
|
|
37899
|
-
// src/prompt-turn-queue/paths.ts
|
|
37900
|
-
import crypto3 from "node:crypto";
|
|
37901
|
-
import fs28 from "node:fs";
|
|
37902
|
-
import path31 from "node:path";
|
|
37903
|
-
import os7 from "node:os";
|
|
37904
|
-
var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
|
|
37905
|
-
function queueStateFileSlug(queueKey) {
|
|
37906
|
-
if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
|
|
37907
|
-
return crypto3.createHash("sha256").update(queueKey, "utf8").digest("hex");
|
|
37908
|
-
}
|
|
37909
|
-
function getPromptQueuesDirectory() {
|
|
37910
|
-
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
37911
|
-
if (override) return path31.resolve(override);
|
|
37912
|
-
return path31.join(os7.homedir(), ".buildautomaton", "queues");
|
|
37913
|
-
}
|
|
37914
|
-
function ensurePromptQueuesDirectory() {
|
|
37915
|
-
const dir = getPromptQueuesDirectory();
|
|
37916
|
-
if (!fs28.existsSync(dir)) fs28.mkdirSync(dir, { recursive: true });
|
|
37917
|
-
}
|
|
37918
|
-
function queueStateFilePath(queueKey) {
|
|
37919
|
-
return path31.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
|
|
37920
|
-
}
|
|
37921
|
-
|
|
37922
38239
|
// src/prompt-turn-queue/disk-store.ts
|
|
37923
38240
|
var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
|
|
37924
38241
|
"queued",
|
|
@@ -37928,28 +38245,27 @@ var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
|
|
|
37928
38245
|
"stopping",
|
|
37929
38246
|
"discarded"
|
|
37930
38247
|
]);
|
|
37931
|
-
function parsePersistedQueueFile(raw) {
|
|
37932
|
-
try {
|
|
37933
|
-
const o = JSON.parse(raw);
|
|
37934
|
-
const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
|
|
37935
|
-
if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
|
|
37936
|
-
return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
|
|
37937
|
-
} catch {
|
|
37938
|
-
return null;
|
|
37939
|
-
}
|
|
37940
|
-
}
|
|
37941
38248
|
function readPersistedQueue(queueKey) {
|
|
37942
|
-
const
|
|
38249
|
+
const db = getCliDatabase();
|
|
38250
|
+
const row = db.get("SELECT queue_key, updated_at, turns_json FROM prompt_queue WHERE queue_key = ?", [
|
|
38251
|
+
queueKey
|
|
38252
|
+
]);
|
|
38253
|
+
if (!row) return null;
|
|
37943
38254
|
try {
|
|
37944
|
-
|
|
38255
|
+
const turns = JSON.parse(row.turns_json);
|
|
38256
|
+
if (!Array.isArray(turns)) return null;
|
|
38257
|
+
return { queueKey: row.queue_key, updatedAt: row.updated_at, turns };
|
|
37945
38258
|
} catch {
|
|
37946
38259
|
return null;
|
|
37947
38260
|
}
|
|
37948
38261
|
}
|
|
37949
38262
|
function writePersistedQueue(file2) {
|
|
37950
|
-
|
|
37951
|
-
|
|
37952
|
-
|
|
38263
|
+
const db = getCliDatabase();
|
|
38264
|
+
db.run(
|
|
38265
|
+
`INSERT INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)
|
|
38266
|
+
ON CONFLICT(queue_key) DO UPDATE SET updated_at = excluded.updated_at, turns_json = excluded.turns_json`,
|
|
38267
|
+
[file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
|
|
38268
|
+
);
|
|
37953
38269
|
}
|
|
37954
38270
|
function mergeServerQueueSnapshot(queueKey, serverTurns) {
|
|
37955
38271
|
const prev = readPersistedQueue(queueKey);
|
|
@@ -38007,7 +38323,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
38007
38323
|
const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
|
|
38008
38324
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
38009
38325
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
38010
|
-
if (!
|
|
38326
|
+
if (!fs32.existsSync(file2)) {
|
|
38011
38327
|
deps.log(
|
|
38012
38328
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
38013
38329
|
);
|
|
@@ -38231,9 +38547,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
38231
38547
|
for (const item of raw) {
|
|
38232
38548
|
if (!item || typeof item !== "object") continue;
|
|
38233
38549
|
const o = item;
|
|
38234
|
-
const
|
|
38235
|
-
if (!
|
|
38236
|
-
const row = { path:
|
|
38550
|
+
const path43 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
38551
|
+
if (!path43) continue;
|
|
38552
|
+
const row = { path: path43 };
|
|
38237
38553
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
38238
38554
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
38239
38555
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -38351,6 +38667,8 @@ function handleBridgePrompt(msg, deps) {
|
|
|
38351
38667
|
const sessionParent = rawParent === "bridge_root" || rawParent === "worktrees_root" ? rawParent : rawParent === "session_worktrees_root" ? "worktrees_root" : null;
|
|
38352
38668
|
const sessionParentPath = typeof msg.sessionParentPath === "string" && msg.sessionParentPath.trim() ? msg.sessionParentPath.trim() : null;
|
|
38353
38669
|
const agentType = typeof msg.agentType === "string" && msg.agentType.trim() ? msg.agentType.trim() : void 0;
|
|
38670
|
+
const rawAgentId = msg.agentId;
|
|
38671
|
+
const agentId = typeof rawAgentId === "string" && rawAgentId.trim() !== "" ? rawAgentId.trim() : null;
|
|
38354
38672
|
const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
|
|
38355
38673
|
const agentConfig = msg.agentConfig != null && typeof msg.agentConfig === "object" && !Array.isArray(msg.agentConfig) ? msg.agentConfig : void 0;
|
|
38356
38674
|
acpManager.logPromptReceivedFromBridge({ agentType, mode });
|
|
@@ -38388,6 +38706,7 @@ function handleBridgePrompt(msg, deps) {
|
|
|
38388
38706
|
runId,
|
|
38389
38707
|
mode,
|
|
38390
38708
|
agentType,
|
|
38709
|
+
agentId,
|
|
38391
38710
|
agentConfig,
|
|
38392
38711
|
sessionParentPath: effectiveCwd,
|
|
38393
38712
|
sendResult: sendResult2,
|
|
@@ -38450,8 +38769,8 @@ function randomSecret() {
|
|
|
38450
38769
|
}
|
|
38451
38770
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
38452
38771
|
}
|
|
38453
|
-
async function requestPreviewApi(port, secret, method,
|
|
38454
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
38772
|
+
async function requestPreviewApi(port, secret, method, path43, body) {
|
|
38773
|
+
const url2 = `http://127.0.0.1:${port}${path43}`;
|
|
38455
38774
|
const headers = {
|
|
38456
38775
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
38457
38776
|
"Content-Type": "application/json"
|
|
@@ -38463,7 +38782,7 @@ async function requestPreviewApi(port, secret, method, path37, body) {
|
|
|
38463
38782
|
});
|
|
38464
38783
|
const data = await res.json().catch(() => ({}));
|
|
38465
38784
|
if (!res.ok) {
|
|
38466
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
38785
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path43}: ${res.status}`);
|
|
38467
38786
|
}
|
|
38468
38787
|
return data;
|
|
38469
38788
|
}
|
|
@@ -38628,15 +38947,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
38628
38947
|
};
|
|
38629
38948
|
|
|
38630
38949
|
// src/files/list-dir.ts
|
|
38631
|
-
import
|
|
38632
|
-
import
|
|
38950
|
+
import fs33 from "node:fs";
|
|
38951
|
+
import path36 from "node:path";
|
|
38633
38952
|
|
|
38634
38953
|
// src/files/ensure-under-cwd.ts
|
|
38635
|
-
import
|
|
38954
|
+
import path35 from "node:path";
|
|
38636
38955
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
38637
|
-
const normalized =
|
|
38638
|
-
const resolved =
|
|
38639
|
-
if (!resolved.startsWith(cwd +
|
|
38956
|
+
const normalized = path35.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
38957
|
+
const resolved = path35.resolve(cwd, normalized);
|
|
38958
|
+
if (!resolved.startsWith(cwd + path35.sep) && resolved !== cwd) {
|
|
38640
38959
|
return null;
|
|
38641
38960
|
}
|
|
38642
38961
|
return resolved;
|
|
@@ -38650,7 +38969,7 @@ async function listDirAsync(relativePath) {
|
|
|
38650
38969
|
return { error: "Path is outside working directory" };
|
|
38651
38970
|
}
|
|
38652
38971
|
try {
|
|
38653
|
-
const names = await
|
|
38972
|
+
const names = await fs33.promises.readdir(resolved, { withFileTypes: true });
|
|
38654
38973
|
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
38655
38974
|
const entries = [];
|
|
38656
38975
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -38658,12 +38977,12 @@ async function listDirAsync(relativePath) {
|
|
|
38658
38977
|
await yieldToEventLoop();
|
|
38659
38978
|
}
|
|
38660
38979
|
const d = visible[i];
|
|
38661
|
-
const entryPath =
|
|
38662
|
-
const fullPath =
|
|
38980
|
+
const entryPath = path36.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
38981
|
+
const fullPath = path36.join(resolved, d.name);
|
|
38663
38982
|
let isDir = d.isDirectory();
|
|
38664
38983
|
if (d.isSymbolicLink()) {
|
|
38665
38984
|
try {
|
|
38666
|
-
const targetStat = await
|
|
38985
|
+
const targetStat = await fs33.promises.stat(fullPath);
|
|
38667
38986
|
isDir = targetStat.isDirectory();
|
|
38668
38987
|
} catch {
|
|
38669
38988
|
isDir = false;
|
|
@@ -38688,25 +39007,25 @@ async function listDirAsync(relativePath) {
|
|
|
38688
39007
|
}
|
|
38689
39008
|
|
|
38690
39009
|
// src/files/read-file.ts
|
|
38691
|
-
import
|
|
39010
|
+
import fs34 from "node:fs";
|
|
38692
39011
|
import { StringDecoder } from "node:string_decoder";
|
|
38693
39012
|
function resolveFilePath(relativePath) {
|
|
38694
39013
|
const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
|
|
38695
39014
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
38696
39015
|
let real;
|
|
38697
39016
|
try {
|
|
38698
|
-
real =
|
|
39017
|
+
real = fs34.realpathSync(resolved);
|
|
38699
39018
|
} catch {
|
|
38700
39019
|
real = resolved;
|
|
38701
39020
|
}
|
|
38702
|
-
const stat3 =
|
|
39021
|
+
const stat3 = fs34.statSync(real);
|
|
38703
39022
|
if (!stat3.isFile()) return { error: "Not a file" };
|
|
38704
39023
|
return real;
|
|
38705
39024
|
}
|
|
38706
39025
|
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
38707
39026
|
function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
38708
|
-
const fileSize =
|
|
38709
|
-
const fd =
|
|
39027
|
+
const fileSize = fs34.statSync(filePath).size;
|
|
39028
|
+
const fd = fs34.openSync(filePath, "r");
|
|
38710
39029
|
const bufSize = 64 * 1024;
|
|
38711
39030
|
const buf = Buffer.alloc(bufSize);
|
|
38712
39031
|
const decoder = new StringDecoder("utf8");
|
|
@@ -38719,7 +39038,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
38719
39038
|
let line0Accum = "";
|
|
38720
39039
|
try {
|
|
38721
39040
|
let bytesRead;
|
|
38722
|
-
while (!done && (bytesRead =
|
|
39041
|
+
while (!done && (bytesRead = fs34.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
38723
39042
|
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
38724
39043
|
partial2 = "";
|
|
38725
39044
|
let lineStart = 0;
|
|
@@ -38854,7 +39173,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
38854
39173
|
}
|
|
38855
39174
|
return { content: resultLines.join("\n"), size: fileSize };
|
|
38856
39175
|
} finally {
|
|
38857
|
-
|
|
39176
|
+
fs34.closeSync(fd);
|
|
38858
39177
|
}
|
|
38859
39178
|
}
|
|
38860
39179
|
function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
@@ -38865,8 +39184,8 @@ function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize =
|
|
|
38865
39184
|
if (hasRange) {
|
|
38866
39185
|
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
38867
39186
|
}
|
|
38868
|
-
const stat3 =
|
|
38869
|
-
const raw =
|
|
39187
|
+
const stat3 = fs34.statSync(result);
|
|
39188
|
+
const raw = fs34.readFileSync(result, "utf8");
|
|
38870
39189
|
const lines = raw.split(/\r?\n/);
|
|
38871
39190
|
return { content: raw, totalLines: lines.length, size: stat3.size };
|
|
38872
39191
|
} catch (err) {
|
|
@@ -38879,14 +39198,14 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
|
|
|
38879
39198
|
}
|
|
38880
39199
|
|
|
38881
39200
|
// src/files/handle-file-browser-search.ts
|
|
39201
|
+
import path37 from "node:path";
|
|
38882
39202
|
var SEARCH_LIMIT = 100;
|
|
38883
39203
|
function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
38884
39204
|
void (async () => {
|
|
38885
39205
|
await yieldToEventLoop();
|
|
38886
39206
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
38887
|
-
const cwd = getBridgeRoot();
|
|
38888
|
-
|
|
38889
|
-
if (index === null) {
|
|
39207
|
+
const cwd = path37.resolve(getBridgeRoot());
|
|
39208
|
+
if (!bridgeFileIndexIsPopulated(cwd)) {
|
|
38890
39209
|
const payload2 = {
|
|
38891
39210
|
type: "file_browser_search_response",
|
|
38892
39211
|
id: msg.id,
|
|
@@ -38896,7 +39215,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
38896
39215
|
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
|
|
38897
39216
|
return;
|
|
38898
39217
|
}
|
|
38899
|
-
const results = await
|
|
39218
|
+
const results = await searchBridgeFilePathsAsync(cwd, q, SEARCH_LIMIT);
|
|
38900
39219
|
const payload = {
|
|
38901
39220
|
type: "file_browser_search_response",
|
|
38902
39221
|
id: msg.id,
|
|
@@ -38984,8 +39303,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
38984
39303
|
}
|
|
38985
39304
|
|
|
38986
39305
|
// src/skills/install-remote-skills.ts
|
|
38987
|
-
import
|
|
38988
|
-
import
|
|
39306
|
+
import fs35 from "node:fs";
|
|
39307
|
+
import path38 from "node:path";
|
|
38989
39308
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
38990
39309
|
const installed2 = [];
|
|
38991
39310
|
if (!Array.isArray(items)) {
|
|
@@ -38996,15 +39315,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
38996
39315
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
38997
39316
|
continue;
|
|
38998
39317
|
}
|
|
38999
|
-
const skillDir =
|
|
39318
|
+
const skillDir = path38.join(cwd, targetDir, item.skillName);
|
|
39000
39319
|
for (const f of item.files) {
|
|
39001
39320
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
39002
|
-
const dest =
|
|
39003
|
-
|
|
39321
|
+
const dest = path38.join(skillDir, f.path);
|
|
39322
|
+
fs35.mkdirSync(path38.dirname(dest), { recursive: true });
|
|
39004
39323
|
if (f.text !== void 0) {
|
|
39005
|
-
|
|
39324
|
+
fs35.writeFileSync(dest, f.text, "utf8");
|
|
39006
39325
|
} else if (f.base64) {
|
|
39007
|
-
|
|
39326
|
+
fs35.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
39008
39327
|
}
|
|
39009
39328
|
}
|
|
39010
39329
|
installed2.push({
|
|
@@ -39154,7 +39473,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
39154
39473
|
};
|
|
39155
39474
|
|
|
39156
39475
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
39157
|
-
import * as
|
|
39476
|
+
import * as fs36 from "node:fs";
|
|
39158
39477
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
39159
39478
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
39160
39479
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -39166,7 +39485,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
39166
39485
|
if (!s) return;
|
|
39167
39486
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
39168
39487
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
39169
|
-
if (!
|
|
39488
|
+
if (!fs36.existsSync(file2)) {
|
|
39170
39489
|
sendWsMessage(s, {
|
|
39171
39490
|
type: "revert_turn_snapshot_result",
|
|
39172
39491
|
id,
|
|
@@ -39577,11 +39896,248 @@ function createBridgeHeartbeatController(params) {
|
|
|
39577
39896
|
};
|
|
39578
39897
|
}
|
|
39579
39898
|
|
|
39899
|
+
// src/sqlite/hash-json-sha256.ts
|
|
39900
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
39901
|
+
function hashJsonUtf8Sha256(value) {
|
|
39902
|
+
return createHash2("sha256").update(JSON.stringify(value), "utf8").digest("hex");
|
|
39903
|
+
}
|
|
39904
|
+
|
|
39905
|
+
// src/sqlite/agent-capability-cache.ts
|
|
39906
|
+
function hasNonEmptyAgentCapabilityCache(db, workspaceId, agentType) {
|
|
39907
|
+
const t = agentType.trim();
|
|
39908
|
+
if (!t) return false;
|
|
39909
|
+
try {
|
|
39910
|
+
const row = db.get(
|
|
39911
|
+
`SELECT config_options_json FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
|
|
39912
|
+
[workspaceId, t]
|
|
39913
|
+
);
|
|
39914
|
+
if (row?.config_options_json == null || row.config_options_json === "") return false;
|
|
39915
|
+
const parsed = JSON.parse(row.config_options_json);
|
|
39916
|
+
return Array.isArray(parsed) && parsed.length > 0;
|
|
39917
|
+
} catch {
|
|
39918
|
+
return false;
|
|
39919
|
+
}
|
|
39920
|
+
}
|
|
39921
|
+
function upsertCliAgentCapabilityCache(db, row) {
|
|
39922
|
+
const t = row.agentType.trim();
|
|
39923
|
+
if (!t) return false;
|
|
39924
|
+
const hash = hashJsonUtf8Sha256(row.configOptions);
|
|
39925
|
+
try {
|
|
39926
|
+
const prev = db.get(
|
|
39927
|
+
`SELECT content_hash FROM agent_capabilities WHERE workspace_id = ? AND agent_type = ?`,
|
|
39928
|
+
[row.workspaceId, t]
|
|
39929
|
+
);
|
|
39930
|
+
if (prev?.content_hash === hash) return false;
|
|
39931
|
+
} catch {
|
|
39932
|
+
}
|
|
39933
|
+
const json2 = JSON.stringify(row.configOptions);
|
|
39934
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
39935
|
+
db.run(
|
|
39936
|
+
`INSERT INTO agent_capabilities (workspace_id, agent_type, config_options_json, content_hash, updated_at)
|
|
39937
|
+
VALUES (?, ?, ?, ?, ?)
|
|
39938
|
+
ON CONFLICT(workspace_id, agent_type) DO UPDATE SET
|
|
39939
|
+
config_options_json = excluded.config_options_json,
|
|
39940
|
+
content_hash = excluded.content_hash,
|
|
39941
|
+
updated_at = excluded.updated_at`,
|
|
39942
|
+
[row.workspaceId, t, json2, hash, now]
|
|
39943
|
+
);
|
|
39944
|
+
return true;
|
|
39945
|
+
}
|
|
39946
|
+
function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
39947
|
+
const rows = db.all(
|
|
39948
|
+
`SELECT agent_type, config_options_json FROM agent_capabilities WHERE workspace_id = ?`,
|
|
39949
|
+
[workspaceId]
|
|
39950
|
+
);
|
|
39951
|
+
const out = [];
|
|
39952
|
+
for (const r of rows) {
|
|
39953
|
+
try {
|
|
39954
|
+
const parsed = JSON.parse(r.config_options_json);
|
|
39955
|
+
if (!Array.isArray(parsed) || parsed.length === 0) continue;
|
|
39956
|
+
out.push({ agentType: r.agent_type, configOptions: parsed });
|
|
39957
|
+
} catch {
|
|
39958
|
+
}
|
|
39959
|
+
}
|
|
39960
|
+
return out;
|
|
39961
|
+
}
|
|
39962
|
+
|
|
39963
|
+
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
39964
|
+
import * as path40 from "node:path";
|
|
39965
|
+
|
|
39966
|
+
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
39967
|
+
import * as path39 from "node:path";
|
|
39968
|
+
async function probeOneAgentTypeForCapabilities(params) {
|
|
39969
|
+
const { agentType, cwd, workspaceId, log: log2, getDb, reportAgentCapabilities, bridgeReport = true } = params;
|
|
39970
|
+
const resolved = resolveAgentCommand(agentType);
|
|
39971
|
+
if (!resolved) return false;
|
|
39972
|
+
let sqliteChanged = false;
|
|
39973
|
+
const reportedRef = { done: false };
|
|
39974
|
+
const tryReport = (co) => {
|
|
39975
|
+
if (reportedRef.done) return;
|
|
39976
|
+
if (!Array.isArray(co) || co.length === 0) return;
|
|
39977
|
+
reportedRef.done = true;
|
|
39978
|
+
let changed = false;
|
|
39979
|
+
try {
|
|
39980
|
+
changed = upsertCliAgentCapabilityCache(getDb(), {
|
|
39981
|
+
workspaceId,
|
|
39982
|
+
agentType,
|
|
39983
|
+
configOptions: co
|
|
39984
|
+
});
|
|
39985
|
+
} catch {
|
|
39986
|
+
}
|
|
39987
|
+
sqliteChanged ||= changed;
|
|
39988
|
+
if (bridgeReport && changed) {
|
|
39989
|
+
reportAgentCapabilities?.({ agentType, configOptions: co });
|
|
39990
|
+
}
|
|
39991
|
+
};
|
|
39992
|
+
let handle = null;
|
|
39993
|
+
const killTimer = setTimeout(() => {
|
|
39994
|
+
try {
|
|
39995
|
+
handle?.disconnect();
|
|
39996
|
+
} catch {
|
|
39997
|
+
}
|
|
39998
|
+
}, 28e3);
|
|
39999
|
+
killTimer.unref?.();
|
|
40000
|
+
try {
|
|
40001
|
+
handle = await resolved.createClient({
|
|
40002
|
+
command: resolved.command,
|
|
40003
|
+
cwd: path39.resolve(cwd),
|
|
40004
|
+
backendAgentType: agentType,
|
|
40005
|
+
sessionMode: "agent",
|
|
40006
|
+
persistedAcpSessionId: null,
|
|
40007
|
+
agentConfig: null,
|
|
40008
|
+
getActiveConfigOptions: () => null,
|
|
40009
|
+
onAcpSessionEstablished: (info) => {
|
|
40010
|
+
tryReport(info.configOptions ?? null);
|
|
40011
|
+
},
|
|
40012
|
+
onAcpConfigOptionsUpdated: (co) => {
|
|
40013
|
+
tryReport(co);
|
|
40014
|
+
},
|
|
40015
|
+
onAgentSubprocessExit: () => {
|
|
40016
|
+
},
|
|
40017
|
+
onSessionUpdate: () => {
|
|
40018
|
+
}
|
|
40019
|
+
});
|
|
40020
|
+
await new Promise((r) => setTimeout(r, 1200));
|
|
40021
|
+
} catch (e) {
|
|
40022
|
+
log2(
|
|
40023
|
+
`[Bridge service] Agent capability probe (${agentType}): ${e instanceof Error ? e.message : String(e)}`
|
|
40024
|
+
);
|
|
40025
|
+
} finally {
|
|
40026
|
+
clearTimeout(killTimer);
|
|
40027
|
+
try {
|
|
40028
|
+
handle?.disconnect();
|
|
40029
|
+
} catch {
|
|
40030
|
+
}
|
|
40031
|
+
}
|
|
40032
|
+
return sqliteChanged;
|
|
40033
|
+
}
|
|
40034
|
+
|
|
40035
|
+
// src/agents/capabilities/probe-agent-capabilities-for-types.ts
|
|
40036
|
+
async function probeAgentCapabilitiesForDetectedTypes(params) {
|
|
40037
|
+
const {
|
|
40038
|
+
agentTypes,
|
|
40039
|
+
cwd,
|
|
40040
|
+
workspaceId,
|
|
40041
|
+
log: log2,
|
|
40042
|
+
getDb,
|
|
40043
|
+
reportAgentCapabilities,
|
|
40044
|
+
bridgeReport = true,
|
|
40045
|
+
forceAllTypes = false
|
|
40046
|
+
} = params;
|
|
40047
|
+
let changedCount = 0;
|
|
40048
|
+
for (let i = 0; i < agentTypes.length; i++) {
|
|
40049
|
+
if (i > 0) await yieldToEventLoop();
|
|
40050
|
+
const agentType = agentTypes[i];
|
|
40051
|
+
if (!agentType.trim()) continue;
|
|
40052
|
+
if (!forceAllTypes) {
|
|
40053
|
+
try {
|
|
40054
|
+
if (process.env.BUILDAUTOMATON_FORCE_PROBE_ACP_CAPABILITIES !== "1" && hasNonEmptyAgentCapabilityCache(getDb(), workspaceId, agentType)) {
|
|
40055
|
+
continue;
|
|
40056
|
+
}
|
|
40057
|
+
} catch {
|
|
40058
|
+
}
|
|
40059
|
+
}
|
|
40060
|
+
const changed = await probeOneAgentTypeForCapabilities({
|
|
40061
|
+
agentType,
|
|
40062
|
+
cwd,
|
|
40063
|
+
workspaceId,
|
|
40064
|
+
log: log2,
|
|
40065
|
+
getDb,
|
|
40066
|
+
reportAgentCapabilities,
|
|
40067
|
+
bridgeReport
|
|
40068
|
+
});
|
|
40069
|
+
if (changed) changedCount += 1;
|
|
40070
|
+
}
|
|
40071
|
+
return changedCount;
|
|
40072
|
+
}
|
|
40073
|
+
|
|
40074
|
+
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
40075
|
+
async function warmupAgentCapabilitiesOnConnect(params) {
|
|
40076
|
+
const { workspaceId, log: log2, getDb, getWs } = params;
|
|
40077
|
+
const cwd = path40.resolve(getBridgeRoot());
|
|
40078
|
+
const db = getDb();
|
|
40079
|
+
function sendBatchFromCache() {
|
|
40080
|
+
const socket = getWs();
|
|
40081
|
+
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
40082
|
+
try {
|
|
40083
|
+
const rows = listCliAgentCapabilityCacheForWorkspace(db, workspaceId);
|
|
40084
|
+
if (rows.length === 0) return;
|
|
40085
|
+
sendWsMessage(socket, {
|
|
40086
|
+
type: "agent_capabilities_batch",
|
|
40087
|
+
items: rows.map((r) => ({ agentType: r.agentType, configOptions: r.configOptions }))
|
|
40088
|
+
});
|
|
40089
|
+
} catch (e) {
|
|
40090
|
+
log2(
|
|
40091
|
+
`[Bridge service] Agent capability batch to bridge failed: ${e instanceof Error ? e.message : String(e)}`
|
|
40092
|
+
);
|
|
40093
|
+
}
|
|
40094
|
+
}
|
|
40095
|
+
sendBatchFromCache();
|
|
40096
|
+
let types = [];
|
|
40097
|
+
try {
|
|
40098
|
+
types = [...await detectLocalAgentTypes()];
|
|
40099
|
+
} catch (e) {
|
|
40100
|
+
log2(`[Bridge service] detectLocalAgentTypes failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
40101
|
+
}
|
|
40102
|
+
try {
|
|
40103
|
+
const n = await probeAgentCapabilitiesForDetectedTypes({
|
|
40104
|
+
agentTypes: types,
|
|
40105
|
+
cwd,
|
|
40106
|
+
workspaceId,
|
|
40107
|
+
log: log2,
|
|
40108
|
+
getDb,
|
|
40109
|
+
bridgeReport: false,
|
|
40110
|
+
forceAllTypes: false
|
|
40111
|
+
});
|
|
40112
|
+
if (n > 0) sendBatchFromCache();
|
|
40113
|
+
} catch (e) {
|
|
40114
|
+
log2(`[Bridge service] Agent capability probe (missing cache) failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
40115
|
+
}
|
|
40116
|
+
void (async () => {
|
|
40117
|
+
try {
|
|
40118
|
+
await yieldToEventLoop();
|
|
40119
|
+
const n = await probeAgentCapabilitiesForDetectedTypes({
|
|
40120
|
+
agentTypes: types,
|
|
40121
|
+
cwd,
|
|
40122
|
+
workspaceId,
|
|
40123
|
+
log: log2,
|
|
40124
|
+
getDb,
|
|
40125
|
+
bridgeReport: false,
|
|
40126
|
+
forceAllTypes: true
|
|
40127
|
+
});
|
|
40128
|
+
if (n > 0) sendBatchFromCache();
|
|
40129
|
+
} catch (e) {
|
|
40130
|
+
log2(`[Bridge service] Agent capability lazy refresh failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
40131
|
+
}
|
|
40132
|
+
})();
|
|
40133
|
+
}
|
|
40134
|
+
|
|
39580
40135
|
// src/connection/create-bridge-connection.ts
|
|
39581
40136
|
async function createBridgeConnection(options) {
|
|
39582
40137
|
const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
|
|
39583
40138
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
39584
40139
|
const logFn = options.log ?? log;
|
|
40140
|
+
getCliDatabase({ logLegacyMigration: logFn });
|
|
39585
40141
|
const tokens = {
|
|
39586
40142
|
accessToken: options.authToken,
|
|
39587
40143
|
refreshToken: options.refreshToken
|
|
@@ -39604,16 +40160,39 @@ async function createBridgeConnection(options) {
|
|
|
39604
40160
|
firehoseOutage: createEmptyReconnectOutageTracker(),
|
|
39605
40161
|
lastFirehoseReconnectCloseMeta: null
|
|
39606
40162
|
};
|
|
40163
|
+
function getWs() {
|
|
40164
|
+
return state.currentWs;
|
|
40165
|
+
}
|
|
40166
|
+
function sendAgentCapabilitiesToBridge(info) {
|
|
40167
|
+
if (!Array.isArray(info.configOptions) || info.configOptions.length === 0) return;
|
|
40168
|
+
let changed = false;
|
|
40169
|
+
try {
|
|
40170
|
+
changed = upsertCliAgentCapabilityCache(getCliDatabase(), {
|
|
40171
|
+
workspaceId,
|
|
40172
|
+
agentType: info.agentType,
|
|
40173
|
+
configOptions: info.configOptions
|
|
40174
|
+
});
|
|
40175
|
+
} catch {
|
|
40176
|
+
}
|
|
40177
|
+
if (!changed) return;
|
|
40178
|
+
const socket = getWs();
|
|
40179
|
+
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
40180
|
+
sendWsMessage(socket, {
|
|
40181
|
+
type: "agent_capabilities",
|
|
40182
|
+
agentType: info.agentType,
|
|
40183
|
+
configOptions: info.configOptions
|
|
40184
|
+
});
|
|
40185
|
+
}
|
|
39607
40186
|
const worktreesRootPath = options.worktreesRootPath ?? defaultWorktreesRootPath();
|
|
39608
40187
|
const sessionWorktreeManager = new SessionWorktreeManager({
|
|
39609
40188
|
worktreesRootPath,
|
|
39610
40189
|
log: logFn
|
|
39611
40190
|
});
|
|
39612
|
-
const acpManager = await createAcpManager({
|
|
40191
|
+
const acpManager = await createAcpManager({
|
|
40192
|
+
log: logFn,
|
|
40193
|
+
reportAgentCapabilities: sendAgentCapabilitiesToBridge
|
|
40194
|
+
});
|
|
39613
40195
|
logFn("CLI running. Press Ctrl+C to exit.");
|
|
39614
|
-
function getWs() {
|
|
39615
|
-
return state.currentWs;
|
|
39616
|
-
}
|
|
39617
40196
|
const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
|
|
39618
40197
|
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
|
|
39619
40198
|
const bridgeHeartbeat = createBridgeHeartbeatController({ getWs, log: logFn });
|
|
@@ -39641,14 +40220,22 @@ async function createBridgeConnection(options) {
|
|
|
39641
40220
|
},
|
|
39642
40221
|
sendLocalSkillsReport,
|
|
39643
40222
|
reportAutoDetectedAgents,
|
|
40223
|
+
warmupAgentCapabilitiesOnConnect: async () => {
|
|
40224
|
+
await warmupAgentCapabilitiesOnConnect({
|
|
40225
|
+
workspaceId,
|
|
40226
|
+
log: logFn,
|
|
40227
|
+
getDb: getCliDatabase,
|
|
40228
|
+
getWs
|
|
40229
|
+
});
|
|
40230
|
+
},
|
|
39644
40231
|
devServerManager,
|
|
39645
40232
|
e2ee,
|
|
39646
40233
|
cloudApiBaseUrl: apiUrl,
|
|
39647
40234
|
getCloudAccessToken: () => tokens.accessToken
|
|
39648
40235
|
};
|
|
39649
40236
|
const identifyReportedPaths = {
|
|
39650
|
-
bridgeRootPath:
|
|
39651
|
-
worktreesRootPath:
|
|
40237
|
+
bridgeRootPath: path41.resolve(getBridgeRoot()),
|
|
40238
|
+
worktreesRootPath: path41.resolve(worktreesRootPath)
|
|
39652
40239
|
};
|
|
39653
40240
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
39654
40241
|
state,
|
|
@@ -39886,9 +40473,9 @@ async function runCliAction(program2, opts) {
|
|
|
39886
40473
|
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
39887
40474
|
const bridgeRootOpt = (opts.bridgeRoot && typeof opts.bridgeRoot === "string" && opts.bridgeRoot.trim() ? opts.bridgeRoot.trim() : null) ?? (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim() ? opts.cwd.trim() : null);
|
|
39888
40475
|
if (bridgeRootOpt) {
|
|
39889
|
-
const resolvedBridgeRoot =
|
|
40476
|
+
const resolvedBridgeRoot = path42.resolve(process.cwd(), bridgeRootOpt);
|
|
39890
40477
|
try {
|
|
39891
|
-
const st =
|
|
40478
|
+
const st = fs37.statSync(resolvedBridgeRoot);
|
|
39892
40479
|
if (!st.isDirectory()) {
|
|
39893
40480
|
console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
|
|
39894
40481
|
process.exit(1);
|
|
@@ -39908,7 +40495,7 @@ async function runCliAction(program2, opts) {
|
|
|
39908
40495
|
);
|
|
39909
40496
|
let worktreesRootPath;
|
|
39910
40497
|
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
39911
|
-
worktreesRootPath =
|
|
40498
|
+
worktreesRootPath = path42.resolve(opts.worktreesRoot.trim());
|
|
39912
40499
|
}
|
|
39913
40500
|
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
39914
40501
|
if (e2eCertificates) {
|