@buildautomaton/cli 0.1.27 → 0.1.29
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 +946 -616
- package/dist/cli.js.map +4 -4
- package/dist/index.js +911 -581
- 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/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 path41 = __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 = path41.resolve(baseDir, baseName);
|
|
1910
|
+
if (fs38.existsSync(localBin)) return localBin;
|
|
1911
|
+
if (sourceExt.includes(path41.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 = path41.resolve(
|
|
1930
|
+
path41.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 = path41.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path41.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(path41.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 = path41.basename(filename, path41.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(path42) {
|
|
2805
|
+
if (path42 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path42;
|
|
2807
2807
|
return this;
|
|
2808
2808
|
}
|
|
2809
2809
|
/**
|
|
@@ -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: path41, errorMaps, issueData } = params;
|
|
7065
|
+
const fullPath = [...path41, ...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, path41, key) {
|
|
7374
7374
|
this._cachedPath = [];
|
|
7375
7375
|
this.parent = parent;
|
|
7376
7376
|
this.data = value;
|
|
7377
|
-
this._path =
|
|
7377
|
+
this._path = path41;
|
|
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(path41, isFile, isDirectory) {
|
|
11533
|
+
log2(`checking %s`, path41);
|
|
11534
11534
|
try {
|
|
11535
|
-
const stat3 = fs_1.statSync(
|
|
11535
|
+
const stat3 = fs_1.statSync(path41);
|
|
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(path41, type = exports.READABLE) {
|
|
11556
|
+
return check2(path41, (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, path41) {
|
|
11854
|
+
if (!path41)
|
|
11855
11855
|
return obj;
|
|
11856
|
-
return
|
|
11856
|
+
return path41.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(path41, 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(path41);
|
|
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, path41 = []) => {
|
|
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 = [...path41, ...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(path41) {
|
|
12339
12339
|
const segs = [];
|
|
12340
|
-
for (const seg of
|
|
12340
|
+
for (const seg of path41) {
|
|
12341
12341
|
if (typeof seg === "number")
|
|
12342
12342
|
segs.push(`[${seg}]`);
|
|
12343
12343
|
else if (typeof seg === "symbol")
|
|
@@ -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.29".length > 0 ? "0.1.29" : "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 path40 from "node:path";
|
|
25076
25076
|
|
|
25077
25077
|
// src/cli-log-level.ts
|
|
25078
25078
|
var verbosity = "info";
|
|
@@ -25638,6 +25638,12 @@ function sendWsMessage(ws, payload) {
|
|
|
25638
25638
|
}
|
|
25639
25639
|
}
|
|
25640
25640
|
|
|
25641
|
+
// src/connection/heartbeat/constants.ts
|
|
25642
|
+
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
25643
|
+
var BRIDGE_HEARTBEAT_SEQ_MAX = 2147483646;
|
|
25644
|
+
var BRIDGE_HEARTBEAT_MISSED_ACKS_BEFORE_RECONNECT = 4;
|
|
25645
|
+
var BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX = 5;
|
|
25646
|
+
|
|
25641
25647
|
// ../../node_modules/.pnpm/open@10.2.0/node_modules/open/index.js
|
|
25642
25648
|
import process7 from "node:process";
|
|
25643
25649
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
@@ -26616,14 +26622,18 @@ function runPendingAuth(options) {
|
|
|
26616
26622
|
}
|
|
26617
26623
|
function connect() {
|
|
26618
26624
|
const url2 = buildPendingBridgeUrl(apiUrl, connectionId);
|
|
26625
|
+
let pendingHbSeq = -1;
|
|
26619
26626
|
ws = createWsBridge({
|
|
26620
26627
|
url: url2,
|
|
26621
26628
|
onOpen: () => {
|
|
26622
26629
|
clearQuietOnOpen();
|
|
26630
|
+
pendingHbSeq = -1;
|
|
26623
26631
|
sendWsMessage(ws, { type: "identify", role: "cli", cliVersion: CLI_VERSION });
|
|
26624
26632
|
keepaliveInterval = setInterval(() => {
|
|
26625
26633
|
if (resolved || !ws || ws.readyState !== 1) return;
|
|
26626
|
-
|
|
26634
|
+
pendingHbSeq = pendingHbSeq >= BRIDGE_HEARTBEAT_SEQ_MAX ? 0 : pendingHbSeq + 1;
|
|
26635
|
+
const hb = { t: "h", s: pendingHbSeq };
|
|
26636
|
+
sendWsMessage(ws, hb);
|
|
26627
26637
|
}, PENDING_KEEPALIVE_MS);
|
|
26628
26638
|
if (browserFallback) {
|
|
26629
26639
|
clearTimeout(browserFallback);
|
|
@@ -26686,6 +26696,321 @@ function runPendingAuth(options) {
|
|
|
26686
26696
|
};
|
|
26687
26697
|
}
|
|
26688
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 CLI_SQLITE_MIGRATIONS = [
|
|
26933
|
+
{
|
|
26934
|
+
name: CHECKPOINT_V1,
|
|
26935
|
+
checkpoint: true,
|
|
26936
|
+
migrate: (db) => {
|
|
26937
|
+
db.exec(CHECKPOINT_V1_SQL);
|
|
26938
|
+
}
|
|
26939
|
+
}
|
|
26940
|
+
];
|
|
26941
|
+
function migrateCliSqlite(db) {
|
|
26942
|
+
db.exec(readCliSqliteMigrationSql("000_bootstrap_migrations_table.sql"));
|
|
26943
|
+
const appliedRows = db.all("SELECT name FROM __migrations");
|
|
26944
|
+
const applied2 = new Set(appliedRows.map((r) => r.name));
|
|
26945
|
+
for (const migration of CLI_SQLITE_MIGRATIONS) {
|
|
26946
|
+
if (applied2.has(migration.name)) continue;
|
|
26947
|
+
if (migration.checkpoint === true && checkpointSatisfiedByLegacyChain(applied2, migration.replacesLegacyMigrations)) {
|
|
26948
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
26949
|
+
continue;
|
|
26950
|
+
}
|
|
26951
|
+
if (migration.alreadyApplied?.(db)) {
|
|
26952
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
26953
|
+
continue;
|
|
26954
|
+
}
|
|
26955
|
+
try {
|
|
26956
|
+
migration.migrate(db);
|
|
26957
|
+
recordMigrationAndPruneCheckpointLegacy(db, migration, applied2);
|
|
26958
|
+
} catch (e) {
|
|
26959
|
+
console.error(`[cli-sqlite] Migration failed: ${migration.name}`, e);
|
|
26960
|
+
throw e;
|
|
26961
|
+
}
|
|
26962
|
+
}
|
|
26963
|
+
}
|
|
26964
|
+
|
|
26965
|
+
// src/sqlite/cli-database.ts
|
|
26966
|
+
var { Database: SqliteDatabase } = sqliteWasm;
|
|
26967
|
+
var openDatabases = /* @__PURE__ */ new Map();
|
|
26968
|
+
var processExitCloseRegistered = false;
|
|
26969
|
+
function registerProcessExitSqliteClose() {
|
|
26970
|
+
if (processExitCloseRegistered) return;
|
|
26971
|
+
processExitCloseRegistered = true;
|
|
26972
|
+
process.once("exit", () => {
|
|
26973
|
+
for (const db of openDatabases.values()) {
|
|
26974
|
+
safeCloseCliSqliteDatabase(db);
|
|
26975
|
+
}
|
|
26976
|
+
openDatabases.clear();
|
|
26977
|
+
});
|
|
26978
|
+
}
|
|
26979
|
+
function safeCloseCliSqliteDatabase(db) {
|
|
26980
|
+
if (db == null) return;
|
|
26981
|
+
try {
|
|
26982
|
+
if (db.isOpen) db.close();
|
|
26983
|
+
} catch {
|
|
26984
|
+
}
|
|
26985
|
+
}
|
|
26986
|
+
function closeAllCliSqliteConnections() {
|
|
26987
|
+
for (const db of openDatabases.values()) {
|
|
26988
|
+
safeCloseCliSqliteDatabase(db);
|
|
26989
|
+
}
|
|
26990
|
+
openDatabases.clear();
|
|
26991
|
+
}
|
|
26992
|
+
function getCliDatabase(options) {
|
|
26993
|
+
const sqlitePath = getCliSqlitePath();
|
|
26994
|
+
const existing = openDatabases.get(sqlitePath);
|
|
26995
|
+
if (existing?.isOpen) return existing;
|
|
26996
|
+
if (existing && !existing.isOpen) {
|
|
26997
|
+
safeCloseCliSqliteDatabase(existing);
|
|
26998
|
+
openDatabases.delete(sqlitePath);
|
|
26999
|
+
}
|
|
27000
|
+
ensureCliSqliteParentDir(sqlitePath);
|
|
27001
|
+
const db = new SqliteDatabase(sqlitePath);
|
|
27002
|
+
try {
|
|
27003
|
+
migrateCliSqlite(db);
|
|
27004
|
+
importCliSqliteLegacyDiskData(db, options?.logLegacyMigration);
|
|
27005
|
+
} catch (e) {
|
|
27006
|
+
safeCloseCliSqliteDatabase(db);
|
|
27007
|
+
throw e;
|
|
27008
|
+
}
|
|
27009
|
+
openDatabases.set(sqlitePath, db);
|
|
27010
|
+
registerProcessExitSqliteClose();
|
|
27011
|
+
return db;
|
|
27012
|
+
}
|
|
27013
|
+
|
|
26689
27014
|
// src/connection/close-bridge-connection.ts
|
|
26690
27015
|
async function closeBridgeConnection(state, acpManager, devServerManager, log2) {
|
|
26691
27016
|
const say = log2 ?? logImmediate;
|
|
@@ -26729,20 +27054,24 @@ async function closeBridgeConnection(state, acpManager, devServerManager, log2)
|
|
|
26729
27054
|
say("Stopping local dev server processes\u2026");
|
|
26730
27055
|
await devServerManager.shutdownAllGraceful();
|
|
26731
27056
|
}
|
|
27057
|
+
try {
|
|
27058
|
+
closeAllCliSqliteConnections();
|
|
27059
|
+
} catch {
|
|
27060
|
+
}
|
|
26732
27061
|
say("Shutdown complete.");
|
|
26733
27062
|
}
|
|
26734
27063
|
|
|
26735
27064
|
// src/paths/session-layout-paths.ts
|
|
26736
|
-
import * as
|
|
27065
|
+
import * as path12 from "node:path";
|
|
26737
27066
|
function resolveIsolatedSessionParentPathFromCheckouts(worktreePaths) {
|
|
26738
|
-
const resolved = worktreePaths.map((p) =>
|
|
27067
|
+
const resolved = worktreePaths.map((p) => path12.resolve(p)).filter(Boolean);
|
|
26739
27068
|
if (resolved.length === 0) return null;
|
|
26740
27069
|
resolved.sort();
|
|
26741
27070
|
return resolved[0];
|
|
26742
27071
|
}
|
|
26743
27072
|
function resolveSessionParentPathForAgentProcess(resolvedSessionParentPath) {
|
|
26744
27073
|
if (resolvedSessionParentPath != null && String(resolvedSessionParentPath).trim() !== "") {
|
|
26745
|
-
return
|
|
27074
|
+
return path12.resolve(String(resolvedSessionParentPath).trim());
|
|
26746
27075
|
}
|
|
26747
27076
|
return getBridgeRoot();
|
|
26748
27077
|
}
|
|
@@ -27074,9 +27403,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
27074
27403
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
27075
27404
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
27076
27405
|
if (!rawPath || !summary) continue;
|
|
27077
|
-
const
|
|
27078
|
-
if (!
|
|
27079
|
-
rows.push({ path:
|
|
27406
|
+
const path41 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
27407
|
+
if (!path41) continue;
|
|
27408
|
+
rows.push({ path: path41, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
27080
27409
|
}
|
|
27081
27410
|
return rows;
|
|
27082
27411
|
}
|
|
@@ -27302,17 +27631,17 @@ function getCliPermissionModeFromAgentConfig(config2) {
|
|
|
27302
27631
|
import { execFile as execFile7 } from "node:child_process";
|
|
27303
27632
|
import { readFile as readFile2, stat as stat2 } from "node:fs/promises";
|
|
27304
27633
|
import { promisify as promisify7 } from "node:util";
|
|
27305
|
-
import * as
|
|
27634
|
+
import * as path15 from "node:path";
|
|
27306
27635
|
|
|
27307
27636
|
// src/git/pre-turn-snapshot.ts
|
|
27308
|
-
import * as
|
|
27309
|
-
import * as
|
|
27637
|
+
import * as fs15 from "node:fs";
|
|
27638
|
+
import * as path14 from "node:path";
|
|
27310
27639
|
import { execFile as execFile6 } from "node:child_process";
|
|
27311
27640
|
import { promisify as promisify6 } from "node:util";
|
|
27312
27641
|
|
|
27313
27642
|
// src/git/discover-repos.ts
|
|
27314
|
-
import * as
|
|
27315
|
-
import * as
|
|
27643
|
+
import * as fs14 from "node:fs";
|
|
27644
|
+
import * as path13 from "node:path";
|
|
27316
27645
|
|
|
27317
27646
|
// ../../node_modules/.pnpm/simple-git@3.32.3/node_modules/simple-git/dist/esm/index.js
|
|
27318
27647
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -27351,8 +27680,8 @@ function pathspec(...paths) {
|
|
|
27351
27680
|
cache.set(key, paths);
|
|
27352
27681
|
return key;
|
|
27353
27682
|
}
|
|
27354
|
-
function isPathSpec(
|
|
27355
|
-
return
|
|
27683
|
+
function isPathSpec(path41) {
|
|
27684
|
+
return path41 instanceof String && cache.has(path41);
|
|
27356
27685
|
}
|
|
27357
27686
|
function toPaths(pathSpec) {
|
|
27358
27687
|
return cache.get(pathSpec) || [];
|
|
@@ -27441,8 +27770,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
27441
27770
|
function forEachLineWithContent(input, callback) {
|
|
27442
27771
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
27443
27772
|
}
|
|
27444
|
-
function folderExists(
|
|
27445
|
-
return (0, import_file_exists.exists)(
|
|
27773
|
+
function folderExists(path41) {
|
|
27774
|
+
return (0, import_file_exists.exists)(path41, import_file_exists.FOLDER);
|
|
27446
27775
|
}
|
|
27447
27776
|
function append(target, item) {
|
|
27448
27777
|
if (Array.isArray(target)) {
|
|
@@ -27846,8 +28175,8 @@ function checkIsRepoRootTask() {
|
|
|
27846
28175
|
commands,
|
|
27847
28176
|
format: "utf-8",
|
|
27848
28177
|
onError,
|
|
27849
|
-
parser(
|
|
27850
|
-
return /^\.(git)?$/.test(
|
|
28178
|
+
parser(path41) {
|
|
28179
|
+
return /^\.(git)?$/.test(path41.trim());
|
|
27851
28180
|
}
|
|
27852
28181
|
};
|
|
27853
28182
|
}
|
|
@@ -28281,11 +28610,11 @@ function parseGrep(grep) {
|
|
|
28281
28610
|
const paths = /* @__PURE__ */ new Set();
|
|
28282
28611
|
const results = {};
|
|
28283
28612
|
forEachLineWithContent(grep, (input) => {
|
|
28284
|
-
const [
|
|
28285
|
-
paths.add(
|
|
28286
|
-
(results[
|
|
28613
|
+
const [path41, line, preview] = input.split(NULL);
|
|
28614
|
+
paths.add(path41);
|
|
28615
|
+
(results[path41] = results[path41] || []).push({
|
|
28287
28616
|
line: asNumber(line),
|
|
28288
|
-
path:
|
|
28617
|
+
path: path41,
|
|
28289
28618
|
preview
|
|
28290
28619
|
});
|
|
28291
28620
|
});
|
|
@@ -29050,14 +29379,14 @@ var init_hash_object = __esm2({
|
|
|
29050
29379
|
init_task();
|
|
29051
29380
|
}
|
|
29052
29381
|
});
|
|
29053
|
-
function parseInit(bare,
|
|
29382
|
+
function parseInit(bare, path41, text) {
|
|
29054
29383
|
const response = String(text).trim();
|
|
29055
29384
|
let result;
|
|
29056
29385
|
if (result = initResponseRegex.exec(response)) {
|
|
29057
|
-
return new InitSummary(bare,
|
|
29386
|
+
return new InitSummary(bare, path41, false, result[1]);
|
|
29058
29387
|
}
|
|
29059
29388
|
if (result = reInitResponseRegex.exec(response)) {
|
|
29060
|
-
return new InitSummary(bare,
|
|
29389
|
+
return new InitSummary(bare, path41, true, result[1]);
|
|
29061
29390
|
}
|
|
29062
29391
|
let gitDir = "";
|
|
29063
29392
|
const tokens = response.split(" ");
|
|
@@ -29068,7 +29397,7 @@ function parseInit(bare, path37, text) {
|
|
|
29068
29397
|
break;
|
|
29069
29398
|
}
|
|
29070
29399
|
}
|
|
29071
|
-
return new InitSummary(bare,
|
|
29400
|
+
return new InitSummary(bare, path41, /^re/i.test(response), gitDir);
|
|
29072
29401
|
}
|
|
29073
29402
|
var InitSummary;
|
|
29074
29403
|
var initResponseRegex;
|
|
@@ -29077,9 +29406,9 @@ var init_InitSummary = __esm2({
|
|
|
29077
29406
|
"src/lib/responses/InitSummary.ts"() {
|
|
29078
29407
|
"use strict";
|
|
29079
29408
|
InitSummary = class {
|
|
29080
|
-
constructor(bare,
|
|
29409
|
+
constructor(bare, path41, existing, gitDir) {
|
|
29081
29410
|
this.bare = bare;
|
|
29082
|
-
this.path =
|
|
29411
|
+
this.path = path41;
|
|
29083
29412
|
this.existing = existing;
|
|
29084
29413
|
this.gitDir = gitDir;
|
|
29085
29414
|
}
|
|
@@ -29091,7 +29420,7 @@ var init_InitSummary = __esm2({
|
|
|
29091
29420
|
function hasBareCommand(command) {
|
|
29092
29421
|
return command.includes(bareCommand);
|
|
29093
29422
|
}
|
|
29094
|
-
function initTask(bare = false,
|
|
29423
|
+
function initTask(bare = false, path41, customArgs) {
|
|
29095
29424
|
const commands = ["init", ...customArgs];
|
|
29096
29425
|
if (bare && !hasBareCommand(commands)) {
|
|
29097
29426
|
commands.splice(1, 0, bareCommand);
|
|
@@ -29100,7 +29429,7 @@ function initTask(bare = false, path37, customArgs) {
|
|
|
29100
29429
|
commands,
|
|
29101
29430
|
format: "utf-8",
|
|
29102
29431
|
parser(text) {
|
|
29103
|
-
return parseInit(commands.includes("--bare"),
|
|
29432
|
+
return parseInit(commands.includes("--bare"), path41, text);
|
|
29104
29433
|
}
|
|
29105
29434
|
};
|
|
29106
29435
|
}
|
|
@@ -29916,12 +30245,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
29916
30245
|
"use strict";
|
|
29917
30246
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
29918
30247
|
FileStatusSummary = class {
|
|
29919
|
-
constructor(
|
|
29920
|
-
this.path =
|
|
30248
|
+
constructor(path41, index, working_dir) {
|
|
30249
|
+
this.path = path41;
|
|
29921
30250
|
this.index = index;
|
|
29922
30251
|
this.working_dir = working_dir;
|
|
29923
30252
|
if (index === "R" || working_dir === "R") {
|
|
29924
|
-
const detail = fromPathRegex.exec(
|
|
30253
|
+
const detail = fromPathRegex.exec(path41) || [null, path41, path41];
|
|
29925
30254
|
this.from = detail[2] || "";
|
|
29926
30255
|
this.path = detail[1] || "";
|
|
29927
30256
|
}
|
|
@@ -29952,14 +30281,14 @@ function splitLine(result, lineStr) {
|
|
|
29952
30281
|
default:
|
|
29953
30282
|
return;
|
|
29954
30283
|
}
|
|
29955
|
-
function data(index, workingDir,
|
|
30284
|
+
function data(index, workingDir, path41) {
|
|
29956
30285
|
const raw = `${index}${workingDir}`;
|
|
29957
30286
|
const handler = parsers6.get(raw);
|
|
29958
30287
|
if (handler) {
|
|
29959
|
-
handler(result,
|
|
30288
|
+
handler(result, path41);
|
|
29960
30289
|
}
|
|
29961
30290
|
if (raw !== "##" && raw !== "!!") {
|
|
29962
|
-
result.files.push(new FileStatusSummary(
|
|
30291
|
+
result.files.push(new FileStatusSummary(path41, index, workingDir));
|
|
29963
30292
|
}
|
|
29964
30293
|
}
|
|
29965
30294
|
}
|
|
@@ -30232,15 +30561,15 @@ var init_simple_git_api = __esm2({
|
|
|
30232
30561
|
this._executor = _executor;
|
|
30233
30562
|
}
|
|
30234
30563
|
_runTask(task, then) {
|
|
30235
|
-
const
|
|
30236
|
-
const promise2 =
|
|
30564
|
+
const chain2 = this._executor.chain();
|
|
30565
|
+
const promise2 = chain2.push(task);
|
|
30237
30566
|
if (then) {
|
|
30238
30567
|
taskCallback(task, promise2, then);
|
|
30239
30568
|
}
|
|
30240
30569
|
return Object.create(this, {
|
|
30241
30570
|
then: { value: promise2.then.bind(promise2) },
|
|
30242
30571
|
catch: { value: promise2.catch.bind(promise2) },
|
|
30243
|
-
_executor: { value:
|
|
30572
|
+
_executor: { value: chain2 }
|
|
30244
30573
|
});
|
|
30245
30574
|
}
|
|
30246
30575
|
add(files) {
|
|
@@ -30268,9 +30597,9 @@ var init_simple_git_api = __esm2({
|
|
|
30268
30597
|
next
|
|
30269
30598
|
);
|
|
30270
30599
|
}
|
|
30271
|
-
hashObject(
|
|
30600
|
+
hashObject(path41, write) {
|
|
30272
30601
|
return this._runTask(
|
|
30273
|
-
hashObjectTask(
|
|
30602
|
+
hashObjectTask(path41, write === true),
|
|
30274
30603
|
trailingFunctionArgument(arguments)
|
|
30275
30604
|
);
|
|
30276
30605
|
}
|
|
@@ -30623,8 +30952,8 @@ var init_branch = __esm2({
|
|
|
30623
30952
|
}
|
|
30624
30953
|
});
|
|
30625
30954
|
function toPath(input) {
|
|
30626
|
-
const
|
|
30627
|
-
return
|
|
30955
|
+
const path41 = input.trim().replace(/^["']|["']$/g, "");
|
|
30956
|
+
return path41 && normalize(path41);
|
|
30628
30957
|
}
|
|
30629
30958
|
var parseCheckIgnore;
|
|
30630
30959
|
var init_CheckIgnore = __esm2({
|
|
@@ -30938,8 +31267,8 @@ __export2(sub_module_exports, {
|
|
|
30938
31267
|
subModuleTask: () => subModuleTask,
|
|
30939
31268
|
updateSubModuleTask: () => updateSubModuleTask
|
|
30940
31269
|
});
|
|
30941
|
-
function addSubModuleTask(repo,
|
|
30942
|
-
return subModuleTask(["add", repo,
|
|
31270
|
+
function addSubModuleTask(repo, path41) {
|
|
31271
|
+
return subModuleTask(["add", repo, path41]);
|
|
30943
31272
|
}
|
|
30944
31273
|
function initSubModuleTask(customArgs) {
|
|
30945
31274
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -31272,8 +31601,8 @@ var require_git = __commonJS2({
|
|
|
31272
31601
|
}
|
|
31273
31602
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
31274
31603
|
};
|
|
31275
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
31276
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
31604
|
+
Git2.prototype.submoduleAdd = function(repo, path41, then) {
|
|
31605
|
+
return this._runTask(addSubModuleTask2(repo, path41), trailingFunctionArgument2(arguments));
|
|
31277
31606
|
};
|
|
31278
31607
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
31279
31608
|
return this._runTask(
|
|
@@ -31917,20 +32246,20 @@ async function isGitRepoDirectory(dirPath) {
|
|
|
31917
32246
|
// src/git/discover-repos.ts
|
|
31918
32247
|
async function discoverGitRepos(cwd = getBridgeRoot()) {
|
|
31919
32248
|
const result = [];
|
|
31920
|
-
const cwdResolved =
|
|
32249
|
+
const cwdResolved = path13.resolve(cwd);
|
|
31921
32250
|
if (await isGitRepoDirectory(cwdResolved)) {
|
|
31922
32251
|
const remoteUrl = await getRemoteOriginUrl(cwdResolved);
|
|
31923
32252
|
result.push({ absolutePath: cwdResolved, remoteUrl });
|
|
31924
32253
|
}
|
|
31925
32254
|
let entries;
|
|
31926
32255
|
try {
|
|
31927
|
-
entries =
|
|
32256
|
+
entries = fs14.readdirSync(cwdResolved, { withFileTypes: true });
|
|
31928
32257
|
} catch {
|
|
31929
32258
|
return result;
|
|
31930
32259
|
}
|
|
31931
32260
|
for (const ent of entries) {
|
|
31932
32261
|
if (!ent.isDirectory()) continue;
|
|
31933
|
-
const childPath =
|
|
32262
|
+
const childPath = path13.join(cwdResolved, ent.name);
|
|
31934
32263
|
if (await isGitRepoDirectory(childPath)) {
|
|
31935
32264
|
const remoteUrl = await getRemoteOriginUrl(childPath);
|
|
31936
32265
|
result.push({ absolutePath: childPath, remoteUrl });
|
|
@@ -31939,22 +32268,22 @@ async function discoverGitRepos(cwd = getBridgeRoot()) {
|
|
|
31939
32268
|
return result;
|
|
31940
32269
|
}
|
|
31941
32270
|
async function discoverGitReposUnderRoot(rootPath) {
|
|
31942
|
-
const root =
|
|
32271
|
+
const root = path13.resolve(rootPath);
|
|
31943
32272
|
const roots = [];
|
|
31944
32273
|
async function walk(dir) {
|
|
31945
32274
|
if (await isGitRepoDirectory(dir)) {
|
|
31946
|
-
roots.push(
|
|
32275
|
+
roots.push(path13.resolve(dir));
|
|
31947
32276
|
return;
|
|
31948
32277
|
}
|
|
31949
32278
|
let entries;
|
|
31950
32279
|
try {
|
|
31951
|
-
entries =
|
|
32280
|
+
entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
31952
32281
|
} catch {
|
|
31953
32282
|
return;
|
|
31954
32283
|
}
|
|
31955
32284
|
for (const ent of entries) {
|
|
31956
32285
|
if (!ent.isDirectory() || ent.name === ".git") continue;
|
|
31957
|
-
await walk(
|
|
32286
|
+
await walk(path13.join(dir, ent.name));
|
|
31958
32287
|
}
|
|
31959
32288
|
}
|
|
31960
32289
|
await walk(root);
|
|
@@ -31970,7 +32299,7 @@ async function discoverGitReposUnderRoot(rootPath) {
|
|
|
31970
32299
|
// src/git/pre-turn-snapshot.ts
|
|
31971
32300
|
var execFileAsync5 = promisify6(execFile6);
|
|
31972
32301
|
function snapshotsDirForCwd(agentCwd) {
|
|
31973
|
-
return
|
|
32302
|
+
return path14.join(agentCwd, ".buildautomaton", "snapshots");
|
|
31974
32303
|
}
|
|
31975
32304
|
async function gitStashCreate(repoRoot, log2) {
|
|
31976
32305
|
try {
|
|
@@ -31999,7 +32328,7 @@ async function gitRun(repoRoot, args, log2, label) {
|
|
|
31999
32328
|
async function resolveSnapshotRepoRoots(options) {
|
|
32000
32329
|
const { worktreePaths, fallbackCwd, sessionId, log: log2 } = options;
|
|
32001
32330
|
if (worktreePaths?.length) {
|
|
32002
|
-
const uniq = [...new Set(worktreePaths.map((p) =>
|
|
32331
|
+
const uniq = [...new Set(worktreePaths.map((p) => path14.resolve(p)))];
|
|
32003
32332
|
return uniq;
|
|
32004
32333
|
}
|
|
32005
32334
|
try {
|
|
@@ -32007,7 +32336,7 @@ async function resolveSnapshotRepoRoots(options) {
|
|
|
32007
32336
|
const mapped = repos.map((r) => r.absolutePath);
|
|
32008
32337
|
const sid = sessionId?.trim();
|
|
32009
32338
|
if (sid) {
|
|
32010
|
-
const filtered = mapped.filter((root) =>
|
|
32339
|
+
const filtered = mapped.filter((root) => path14.basename(root) === sid);
|
|
32011
32340
|
if (filtered.length > 0) return filtered;
|
|
32012
32341
|
}
|
|
32013
32342
|
return mapped;
|
|
@@ -32028,7 +32357,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
32028
32357
|
}
|
|
32029
32358
|
const dir = snapshotsDirForCwd(agentCwd);
|
|
32030
32359
|
try {
|
|
32031
|
-
|
|
32360
|
+
fs15.mkdirSync(dir, { recursive: true });
|
|
32032
32361
|
} catch (e) {
|
|
32033
32362
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
32034
32363
|
}
|
|
@@ -32037,9 +32366,9 @@ async function capturePreTurnSnapshot(options) {
|
|
|
32037
32366
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
32038
32367
|
repos
|
|
32039
32368
|
};
|
|
32040
|
-
const filePath =
|
|
32369
|
+
const filePath = path14.join(dir, `${runId}.json`);
|
|
32041
32370
|
try {
|
|
32042
|
-
|
|
32371
|
+
fs15.writeFileSync(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
32043
32372
|
} catch (e) {
|
|
32044
32373
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
32045
32374
|
}
|
|
@@ -32052,7 +32381,7 @@ async function capturePreTurnSnapshot(options) {
|
|
|
32052
32381
|
async function applyPreTurnSnapshot(filePath, log2) {
|
|
32053
32382
|
let data;
|
|
32054
32383
|
try {
|
|
32055
|
-
const raw =
|
|
32384
|
+
const raw = fs15.readFileSync(filePath, "utf8");
|
|
32056
32385
|
data = JSON.parse(raw);
|
|
32057
32386
|
} catch (e) {
|
|
32058
32387
|
return { ok: false, error: e instanceof Error ? e.message : String(e) };
|
|
@@ -32075,7 +32404,7 @@ async function applyPreTurnSnapshot(filePath, log2) {
|
|
|
32075
32404
|
return { ok: true };
|
|
32076
32405
|
}
|
|
32077
32406
|
function snapshotFilePath(agentCwd, runId) {
|
|
32078
|
-
return
|
|
32407
|
+
return path14.join(snapshotsDirForCwd(agentCwd), `${runId}.json`);
|
|
32079
32408
|
}
|
|
32080
32409
|
|
|
32081
32410
|
// src/git/session-git-queue.ts
|
|
@@ -32124,7 +32453,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32124
32453
|
continue;
|
|
32125
32454
|
}
|
|
32126
32455
|
const lines = namesRaw.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
32127
|
-
const slug =
|
|
32456
|
+
const slug = path15.basename(repo.path).replace(/[^\w.-]+/g, "_") || "repo";
|
|
32128
32457
|
for (const rel of lines) {
|
|
32129
32458
|
if (rel.includes("..")) continue;
|
|
32130
32459
|
try {
|
|
@@ -32138,7 +32467,7 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32138
32467
|
);
|
|
32139
32468
|
if (!patchContent.trim()) continue;
|
|
32140
32469
|
const displayPath = multiRepo ? `${slug}/${rel}` : rel;
|
|
32141
|
-
const workspaceFilePath =
|
|
32470
|
+
const workspaceFilePath = path15.join(repo.path, rel);
|
|
32142
32471
|
const newText = await readWorkspaceFileAsUtf8(workspaceFilePath);
|
|
32143
32472
|
sendSessionUpdate({
|
|
32144
32473
|
type: "session_file_change",
|
|
@@ -32160,9 +32489,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32160
32489
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
32161
32490
|
async function putEncryptedChangeSummaryRows(params) {
|
|
32162
32491
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
32163
|
-
const entries = params.rows.map(({ path:
|
|
32492
|
+
const entries = params.rows.map(({ path: path41, summary }) => {
|
|
32164
32493
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
32165
|
-
return { path:
|
|
32494
|
+
return { path: path41, summary: JSON.stringify(enc) };
|
|
32166
32495
|
});
|
|
32167
32496
|
const res = await fetch(
|
|
32168
32497
|
`${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -32473,8 +32802,8 @@ async function sendPromptToAgent(options) {
|
|
|
32473
32802
|
}
|
|
32474
32803
|
|
|
32475
32804
|
// src/agents/acp/ensure-acp-client.ts
|
|
32476
|
-
import * as
|
|
32477
|
-
import * as
|
|
32805
|
+
import * as fs16 from "node:fs";
|
|
32806
|
+
import * as path19 from "node:path";
|
|
32478
32807
|
|
|
32479
32808
|
// src/error-message.ts
|
|
32480
32809
|
function errorMessage(err) {
|
|
@@ -32638,8 +32967,8 @@ function enrichAcpPermissionRpcResultFromRequestParams(result, params) {
|
|
|
32638
32967
|
}
|
|
32639
32968
|
|
|
32640
32969
|
// src/agents/acp/clients/shared/acp-fs-read-write.ts
|
|
32641
|
-
import { mkdirSync as mkdirSync2, readFileSync as
|
|
32642
|
-
import { dirname as
|
|
32970
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
32971
|
+
import { dirname as dirname3 } from "node:path";
|
|
32643
32972
|
|
|
32644
32973
|
// src/files/diff/unified-diff.ts
|
|
32645
32974
|
function computeLineDiff(oldText, newText) {
|
|
@@ -32688,21 +33017,21 @@ function editSnippetToUnifiedDiff(filePath, oldText, newText) {
|
|
|
32688
33017
|
}
|
|
32689
33018
|
|
|
32690
33019
|
// src/agents/acp/safe-fs-path.ts
|
|
32691
|
-
import * as
|
|
33020
|
+
import * as path16 from "node:path";
|
|
32692
33021
|
function resolveSafePathUnderCwd(cwd, filePath) {
|
|
32693
33022
|
const trimmed2 = filePath.trim();
|
|
32694
33023
|
if (!trimmed2) return null;
|
|
32695
|
-
const normalizedCwd =
|
|
32696
|
-
const resolved =
|
|
32697
|
-
const rel =
|
|
32698
|
-
if (rel.startsWith("..") ||
|
|
33024
|
+
const normalizedCwd = path16.resolve(cwd);
|
|
33025
|
+
const resolved = path16.isAbsolute(trimmed2) ? path16.normalize(trimmed2) : path16.resolve(normalizedCwd, trimmed2);
|
|
33026
|
+
const rel = path16.relative(normalizedCwd, resolved);
|
|
33027
|
+
if (rel.startsWith("..") || path16.isAbsolute(rel)) return null;
|
|
32699
33028
|
return resolved;
|
|
32700
33029
|
}
|
|
32701
33030
|
function toDisplayPathRelativeToCwd(cwd, absolutePath) {
|
|
32702
|
-
const normalizedCwd =
|
|
32703
|
-
const rel =
|
|
32704
|
-
if (!rel || rel === "") return
|
|
32705
|
-
return rel.split(
|
|
33031
|
+
const normalizedCwd = path16.resolve(cwd);
|
|
33032
|
+
const rel = path16.relative(normalizedCwd, path16.resolve(absolutePath));
|
|
33033
|
+
if (!rel || rel === "") return path16.basename(absolutePath);
|
|
33034
|
+
return rel.split(path16.sep).join("/");
|
|
32706
33035
|
}
|
|
32707
33036
|
|
|
32708
33037
|
// src/agents/acp/clients/shared/acp-fs-read-write.ts
|
|
@@ -32717,7 +33046,7 @@ function acpReadTextFileInProcess(ctx, filePath, line, limit) {
|
|
|
32717
33046
|
const resolvedPath = resolveSafePathUnderCwd(ctx.cwd, filePath);
|
|
32718
33047
|
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32719
33048
|
try {
|
|
32720
|
-
let content =
|
|
33049
|
+
let content = readFileSync3(resolvedPath, "utf8");
|
|
32721
33050
|
content = sliceFileContentForAcp(content, line, limit);
|
|
32722
33051
|
return { content };
|
|
32723
33052
|
} catch (e) {
|
|
@@ -32730,11 +33059,11 @@ function acpWriteTextFileInProcess(ctx, filePath, newText) {
|
|
|
32730
33059
|
if (!resolvedPath) throw new Error("Invalid or disallowed path");
|
|
32731
33060
|
let oldText = "";
|
|
32732
33061
|
try {
|
|
32733
|
-
oldText =
|
|
33062
|
+
oldText = readFileSync3(resolvedPath, "utf8");
|
|
32734
33063
|
} catch (e) {
|
|
32735
33064
|
if (e.code !== "ENOENT") throw e;
|
|
32736
33065
|
}
|
|
32737
|
-
mkdirSync2(
|
|
33066
|
+
mkdirSync2(dirname3(resolvedPath), { recursive: true });
|
|
32738
33067
|
writeFileSync2(resolvedPath, newText, "utf8");
|
|
32739
33068
|
const displayPath = toDisplayPathRelativeToCwd(ctx.cwd, resolvedPath);
|
|
32740
33069
|
const patchContent = editSnippetToUnifiedDiff(displayPath, oldText, newText);
|
|
@@ -33671,20 +34000,20 @@ function resolveAgentCommand(preferredAgentType) {
|
|
|
33671
34000
|
|
|
33672
34001
|
// src/agents/acp/session-file-change-path-kind.ts
|
|
33673
34002
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
33674
|
-
import { existsSync, statSync } from "node:fs";
|
|
34003
|
+
import { existsSync as existsSync2, statSync } from "node:fs";
|
|
33675
34004
|
|
|
33676
34005
|
// src/git/get-git-repo-root-sync.ts
|
|
33677
34006
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
33678
|
-
import * as
|
|
34007
|
+
import * as path17 from "node:path";
|
|
33679
34008
|
function getGitRepoRootSync(startDir) {
|
|
33680
34009
|
try {
|
|
33681
34010
|
const out = execFileSync2("git", ["rev-parse", "--show-toplevel"], {
|
|
33682
|
-
cwd:
|
|
34011
|
+
cwd: path17.resolve(startDir),
|
|
33683
34012
|
encoding: "utf8",
|
|
33684
34013
|
stdio: ["ignore", "pipe", "ignore"],
|
|
33685
34014
|
maxBuffer: 1024 * 1024
|
|
33686
34015
|
}).trim();
|
|
33687
|
-
return out ?
|
|
34016
|
+
return out ? path17.resolve(out) : null;
|
|
33688
34017
|
} catch {
|
|
33689
34018
|
return null;
|
|
33690
34019
|
}
|
|
@@ -33692,26 +34021,26 @@ function getGitRepoRootSync(startDir) {
|
|
|
33692
34021
|
|
|
33693
34022
|
// src/agents/acp/workspace-files.ts
|
|
33694
34023
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
33695
|
-
import { readFileSync as
|
|
33696
|
-
import * as
|
|
34024
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
34025
|
+
import * as path18 from "node:path";
|
|
33697
34026
|
function resolveWorkspaceFilePath(sessionParentPath, rawPath) {
|
|
33698
34027
|
const trimmed2 = rawPath.trim();
|
|
33699
34028
|
if (!trimmed2) return null;
|
|
33700
|
-
const normalizedSessionParent =
|
|
34029
|
+
const normalizedSessionParent = path18.resolve(sessionParentPath);
|
|
33701
34030
|
let resolvedPath = resolveSafePathUnderCwd(sessionParentPath, trimmed2);
|
|
33702
34031
|
if (!resolvedPath) {
|
|
33703
|
-
const candidate =
|
|
34032
|
+
const candidate = path18.isAbsolute(trimmed2) ? path18.normalize(trimmed2) : path18.normalize(path18.resolve(normalizedSessionParent, trimmed2));
|
|
33704
34033
|
const gitRoot2 = getGitRepoRootSync(sessionParentPath);
|
|
33705
34034
|
if (!gitRoot2) return null;
|
|
33706
|
-
const rel =
|
|
33707
|
-
if (rel.startsWith("..") ||
|
|
34035
|
+
const rel = path18.relative(gitRoot2, candidate);
|
|
34036
|
+
if (rel.startsWith("..") || path18.isAbsolute(rel)) return null;
|
|
33708
34037
|
resolvedPath = candidate;
|
|
33709
34038
|
}
|
|
33710
34039
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
33711
34040
|
if (gitRoot) {
|
|
33712
|
-
const relFromRoot =
|
|
33713
|
-
if (!relFromRoot.startsWith("..") && !
|
|
33714
|
-
return { resolvedPath, display: relFromRoot.split(
|
|
34041
|
+
const relFromRoot = path18.relative(gitRoot, resolvedPath);
|
|
34042
|
+
if (!relFromRoot.startsWith("..") && !path18.isAbsolute(relFromRoot)) {
|
|
34043
|
+
return { resolvedPath, display: relFromRoot.split(path18.sep).join("/") };
|
|
33715
34044
|
}
|
|
33716
34045
|
}
|
|
33717
34046
|
return { resolvedPath, display: toDisplayPathRelativeToCwd(sessionParentPath, resolvedPath) };
|
|
@@ -33720,11 +34049,11 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
33720
34049
|
if (!displayPath || displayPath.includes("..")) return "";
|
|
33721
34050
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
33722
34051
|
if (gitRoot) {
|
|
33723
|
-
const resolvedPath2 =
|
|
33724
|
-
const rel =
|
|
33725
|
-
if (!rel.startsWith("..") && !
|
|
34052
|
+
const resolvedPath2 = path18.resolve(gitRoot, displayPath);
|
|
34053
|
+
const rel = path18.relative(gitRoot, resolvedPath2);
|
|
34054
|
+
if (!rel.startsWith("..") && !path18.isAbsolute(rel)) {
|
|
33726
34055
|
try {
|
|
33727
|
-
return
|
|
34056
|
+
return readFileSync4(resolvedPath2, "utf8");
|
|
33728
34057
|
} catch {
|
|
33729
34058
|
}
|
|
33730
34059
|
}
|
|
@@ -33732,7 +34061,7 @@ function readUtf8WorkspaceFile(sessionParentPath, displayPath) {
|
|
|
33732
34061
|
const resolvedPath = resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
33733
34062
|
if (!resolvedPath) return "";
|
|
33734
34063
|
try {
|
|
33735
|
-
return
|
|
34064
|
+
return readFileSync4(resolvedPath, "utf8");
|
|
33736
34065
|
} catch {
|
|
33737
34066
|
return "";
|
|
33738
34067
|
}
|
|
@@ -33741,9 +34070,9 @@ function tryWorkspaceDisplayToPath(sessionParentPath, displayPath) {
|
|
|
33741
34070
|
if (!displayPath || displayPath.includes("..")) return null;
|
|
33742
34071
|
const gitRoot = getGitRepoRootSync(sessionParentPath);
|
|
33743
34072
|
if (gitRoot) {
|
|
33744
|
-
const resolvedPath =
|
|
33745
|
-
const rel =
|
|
33746
|
-
if (!rel.startsWith("..") && !
|
|
34073
|
+
const resolvedPath = path18.resolve(gitRoot, displayPath);
|
|
34074
|
+
const rel = path18.relative(gitRoot, resolvedPath);
|
|
34075
|
+
if (!rel.startsWith("..") && !path18.isAbsolute(rel)) return resolvedPath;
|
|
33747
34076
|
}
|
|
33748
34077
|
return resolveSafePathUnderCwd(sessionParentPath, displayPath);
|
|
33749
34078
|
}
|
|
@@ -33778,7 +34107,7 @@ function gitHeadPathObjectType(sessionParentPath, displayPath) {
|
|
|
33778
34107
|
}
|
|
33779
34108
|
function getSessionFileChangeDirectoryFlags(sessionParentPath, displayPath) {
|
|
33780
34109
|
const resolvedPath = tryWorkspaceDisplayToPath(sessionParentPath, displayPath);
|
|
33781
|
-
if (resolvedPath &&
|
|
34110
|
+
if (resolvedPath && existsSync2(resolvedPath)) {
|
|
33782
34111
|
try {
|
|
33783
34112
|
if (statSync(resolvedPath).isDirectory()) {
|
|
33784
34113
|
return { isDirectory: true, directoryRemoved: false };
|
|
@@ -33878,7 +34207,7 @@ function createBridgeOnRequest(opts) {
|
|
|
33878
34207
|
}
|
|
33879
34208
|
|
|
33880
34209
|
// src/agents/acp/hooks/extract-acp-file-diffs-from-update/paths-and-text.ts
|
|
33881
|
-
import { fileURLToPath as
|
|
34210
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
33882
34211
|
function readOptionalTextField(v) {
|
|
33883
34212
|
if (v === null || v === void 0) return "";
|
|
33884
34213
|
if (typeof v === "string") return v;
|
|
@@ -33888,7 +34217,7 @@ function normalizePathField(raw) {
|
|
|
33888
34217
|
const t = raw.trim();
|
|
33889
34218
|
if (t.startsWith("file://")) {
|
|
33890
34219
|
try {
|
|
33891
|
-
return
|
|
34220
|
+
return fileURLToPath3(t);
|
|
33892
34221
|
} catch {
|
|
33893
34222
|
return t;
|
|
33894
34223
|
}
|
|
@@ -34346,29 +34675,34 @@ function buildAcpSessionBridgeHooks(opts) {
|
|
|
34346
34675
|
}
|
|
34347
34676
|
|
|
34348
34677
|
// src/agents/acp/local-agent-session-file.ts
|
|
34349
|
-
|
|
34350
|
-
import os3 from "node:os";
|
|
34351
|
-
import path12 from "node:path";
|
|
34352
|
-
var LOCAL_AGENT_SESSION_DIR = path12.join(os3.homedir(), ".buildautomaton", "agent-sessions");
|
|
34353
|
-
function safeFileSlug(cloudSessionId) {
|
|
34678
|
+
function sessionKeyForCloudSessionId(cloudSessionId) {
|
|
34354
34679
|
const t = cloudSessionId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 220);
|
|
34355
34680
|
return t.length > 0 ? t : "session";
|
|
34356
34681
|
}
|
|
34357
|
-
function localAgentSessionFilePath(cloudSessionId) {
|
|
34358
|
-
return path12.join(LOCAL_AGENT_SESSION_DIR, `${safeFileSlug(cloudSessionId)}.json`);
|
|
34359
|
-
}
|
|
34360
34682
|
function readLocalAgentSessionFile(cloudSessionId) {
|
|
34361
34683
|
try {
|
|
34362
|
-
const
|
|
34363
|
-
const
|
|
34364
|
-
const
|
|
34365
|
-
|
|
34684
|
+
const db = getCliDatabase();
|
|
34685
|
+
const key = sessionKeyForCloudSessionId(cloudSessionId);
|
|
34686
|
+
const row = db.get(
|
|
34687
|
+
"SELECT acp_session_id, backend_agent_type, config_options_json, updated_at FROM agent_session WHERE session_key = ?",
|
|
34688
|
+
[key]
|
|
34689
|
+
);
|
|
34690
|
+
if (!row) return null;
|
|
34691
|
+
let configOptions = null;
|
|
34692
|
+
if (row.config_options_json != null && row.config_options_json !== "") {
|
|
34693
|
+
try {
|
|
34694
|
+
const parsed = JSON.parse(row.config_options_json);
|
|
34695
|
+
configOptions = Array.isArray(parsed) ? parsed : null;
|
|
34696
|
+
} catch {
|
|
34697
|
+
configOptions = null;
|
|
34698
|
+
}
|
|
34699
|
+
}
|
|
34366
34700
|
return {
|
|
34367
34701
|
v: 1,
|
|
34368
|
-
acpSessionId:
|
|
34369
|
-
backendAgentType:
|
|
34370
|
-
configOptions
|
|
34371
|
-
updatedAt:
|
|
34702
|
+
acpSessionId: row.acp_session_id,
|
|
34703
|
+
backendAgentType: row.backend_agent_type,
|
|
34704
|
+
configOptions,
|
|
34705
|
+
updatedAt: row.updated_at
|
|
34372
34706
|
};
|
|
34373
34707
|
} catch {
|
|
34374
34708
|
return null;
|
|
@@ -34376,9 +34710,8 @@ function readLocalAgentSessionFile(cloudSessionId) {
|
|
|
34376
34710
|
}
|
|
34377
34711
|
function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
34378
34712
|
try {
|
|
34379
|
-
const
|
|
34380
|
-
|
|
34381
|
-
const p = localAgentSessionFilePath(cloudSessionId);
|
|
34713
|
+
const db = getCliDatabase();
|
|
34714
|
+
const key = sessionKeyForCloudSessionId(cloudSessionId);
|
|
34382
34715
|
const prev = readLocalAgentSessionFile(cloudSessionId);
|
|
34383
34716
|
const next = {
|
|
34384
34717
|
v: 1,
|
|
@@ -34387,7 +34720,17 @@ function writeLocalAgentSessionFile(cloudSessionId, patch) {
|
|
|
34387
34720
|
configOptions: patch.configOptions !== void 0 ? patch.configOptions : prev?.configOptions ?? null,
|
|
34388
34721
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
34389
34722
|
};
|
|
34390
|
-
|
|
34723
|
+
const configJson = next.configOptions != null ? JSON.stringify(next.configOptions) : null;
|
|
34724
|
+
db.run(
|
|
34725
|
+
`INSERT INTO agent_session (session_key, acp_session_id, backend_agent_type, config_options_json, updated_at)
|
|
34726
|
+
VALUES (?, ?, ?, ?, ?)
|
|
34727
|
+
ON CONFLICT(session_key) DO UPDATE SET
|
|
34728
|
+
acp_session_id = excluded.acp_session_id,
|
|
34729
|
+
backend_agent_type = excluded.backend_agent_type,
|
|
34730
|
+
config_options_json = excluded.config_options_json,
|
|
34731
|
+
updated_at = excluded.updated_at`,
|
|
34732
|
+
[key, next.acpSessionId, next.backendAgentType, configJson, next.updatedAt]
|
|
34733
|
+
);
|
|
34391
34734
|
} catch {
|
|
34392
34735
|
}
|
|
34393
34736
|
}
|
|
@@ -34411,7 +34754,7 @@ async function ensureAcpClient(options) {
|
|
|
34411
34754
|
if (state.acpStartPromise && !state.acpHandle) {
|
|
34412
34755
|
await state.acpStartPromise;
|
|
34413
34756
|
}
|
|
34414
|
-
if (state.acpHandle && state.lastAcpCwd != null &&
|
|
34757
|
+
if (state.acpHandle && state.lastAcpCwd != null && path19.resolve(state.lastAcpCwd) !== path19.resolve(targetSessionParentPath)) {
|
|
34415
34758
|
try {
|
|
34416
34759
|
state.acpHandle.disconnect();
|
|
34417
34760
|
} catch {
|
|
@@ -34446,7 +34789,7 @@ async function ensureAcpClient(options) {
|
|
|
34446
34789
|
if (!state.acpStartPromise) {
|
|
34447
34790
|
let statOk = false;
|
|
34448
34791
|
try {
|
|
34449
|
-
const st =
|
|
34792
|
+
const st = fs16.statSync(targetSessionParentPath);
|
|
34450
34793
|
statOk = st.isDirectory();
|
|
34451
34794
|
if (!statOk) {
|
|
34452
34795
|
state.lastAcpStartError = `Agent cwd is not a directory: ${targetSessionParentPath}`;
|
|
@@ -34693,12 +35036,12 @@ async function createAcpManager(options) {
|
|
|
34693
35036
|
}
|
|
34694
35037
|
|
|
34695
35038
|
// src/worktrees/session-worktree-manager.ts
|
|
34696
|
-
import * as
|
|
34697
|
-
import
|
|
35039
|
+
import * as path26 from "node:path";
|
|
35040
|
+
import os8 from "node:os";
|
|
34698
35041
|
|
|
34699
35042
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34700
|
-
import * as
|
|
34701
|
-
import * as
|
|
35043
|
+
import * as fs18 from "node:fs";
|
|
35044
|
+
import * as path21 from "node:path";
|
|
34702
35045
|
|
|
34703
35046
|
// src/git/worktree-add.ts
|
|
34704
35047
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
@@ -34707,12 +35050,12 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
|
34707
35050
|
}
|
|
34708
35051
|
|
|
34709
35052
|
// src/worktrees/worktree-layout-file.ts
|
|
34710
|
-
import * as
|
|
34711
|
-
import * as
|
|
34712
|
-
import
|
|
35053
|
+
import * as fs17 from "node:fs";
|
|
35054
|
+
import * as path20 from "node:path";
|
|
35055
|
+
import os7 from "node:os";
|
|
34713
35056
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
34714
35057
|
function defaultWorktreeLayoutPath() {
|
|
34715
|
-
return
|
|
35058
|
+
return path20.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
34716
35059
|
}
|
|
34717
35060
|
function normalizeLoadedLayout(raw) {
|
|
34718
35061
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -34724,8 +35067,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
34724
35067
|
function loadWorktreeLayout() {
|
|
34725
35068
|
try {
|
|
34726
35069
|
const p = defaultWorktreeLayoutPath();
|
|
34727
|
-
if (!
|
|
34728
|
-
const raw = JSON.parse(
|
|
35070
|
+
if (!fs17.existsSync(p)) return { launcherCwds: [] };
|
|
35071
|
+
const raw = JSON.parse(fs17.readFileSync(p, "utf8"));
|
|
34729
35072
|
return normalizeLoadedLayout(raw);
|
|
34730
35073
|
} catch {
|
|
34731
35074
|
return { launcherCwds: [] };
|
|
@@ -34733,24 +35076,24 @@ function loadWorktreeLayout() {
|
|
|
34733
35076
|
}
|
|
34734
35077
|
function saveWorktreeLayout(layout) {
|
|
34735
35078
|
try {
|
|
34736
|
-
const dir =
|
|
34737
|
-
|
|
34738
|
-
|
|
35079
|
+
const dir = path20.dirname(defaultWorktreeLayoutPath());
|
|
35080
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
35081
|
+
fs17.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
34739
35082
|
} catch {
|
|
34740
35083
|
}
|
|
34741
35084
|
}
|
|
34742
35085
|
function baseNameSafe(pathString) {
|
|
34743
|
-
return
|
|
35086
|
+
return path20.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
34744
35087
|
}
|
|
34745
35088
|
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
34746
|
-
const norm =
|
|
34747
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
35089
|
+
const norm = path20.resolve(bridgeRootPath2);
|
|
35090
|
+
const existing = layout.launcherCwds.find((e) => path20.resolve(e.absolutePath) === norm);
|
|
34748
35091
|
return existing?.dirName;
|
|
34749
35092
|
}
|
|
34750
35093
|
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
34751
35094
|
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
34752
35095
|
if (existing) return existing;
|
|
34753
|
-
const norm =
|
|
35096
|
+
const norm = path20.resolve(bridgeRootPath2);
|
|
34754
35097
|
const base = baseNameSafe(norm);
|
|
34755
35098
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
34756
35099
|
let name = base;
|
|
@@ -34767,10 +35110,10 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
|
34767
35110
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34768
35111
|
async function prepareNewSessionWorktrees(options) {
|
|
34769
35112
|
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
|
|
34770
|
-
const bridgeResolved =
|
|
35113
|
+
const bridgeResolved = path21.resolve(bridgeRoot);
|
|
34771
35114
|
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
34772
|
-
const bridgeKeyDir =
|
|
34773
|
-
const sessionDir =
|
|
35115
|
+
const bridgeKeyDir = path21.join(worktreesRootPath, cwdKey);
|
|
35116
|
+
const sessionDir = path21.join(bridgeKeyDir, sessionId);
|
|
34774
35117
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
34775
35118
|
if (repos.length === 0) {
|
|
34776
35119
|
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
@@ -34778,14 +35121,14 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
34778
35121
|
}
|
|
34779
35122
|
const branch = `session-${sessionId}`;
|
|
34780
35123
|
const worktreePaths = [];
|
|
34781
|
-
|
|
35124
|
+
fs18.mkdirSync(sessionDir, { recursive: true });
|
|
34782
35125
|
for (const repo of repos) {
|
|
34783
|
-
let rel =
|
|
34784
|
-
if (rel.startsWith("..") ||
|
|
35126
|
+
let rel = path21.relative(bridgeResolved, repo.absolutePath);
|
|
35127
|
+
if (rel.startsWith("..") || path21.isAbsolute(rel)) continue;
|
|
34785
35128
|
const relNorm = rel === "" ? "." : rel;
|
|
34786
|
-
const wtPath = relNorm === "." ? sessionDir :
|
|
35129
|
+
const wtPath = relNorm === "." ? sessionDir : path21.join(sessionDir, relNorm);
|
|
34787
35130
|
if (relNorm !== ".") {
|
|
34788
|
-
|
|
35131
|
+
fs18.mkdirSync(path21.dirname(wtPath), { recursive: true });
|
|
34789
35132
|
}
|
|
34790
35133
|
try {
|
|
34791
35134
|
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
@@ -34827,23 +35170,23 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
34827
35170
|
}
|
|
34828
35171
|
|
|
34829
35172
|
// src/worktrees/remove-session-worktrees.ts
|
|
34830
|
-
import * as
|
|
35173
|
+
import * as fs21 from "node:fs";
|
|
34831
35174
|
|
|
34832
35175
|
// src/git/worktree-remove.ts
|
|
34833
|
-
import * as
|
|
35176
|
+
import * as fs20 from "node:fs";
|
|
34834
35177
|
|
|
34835
35178
|
// src/git/resolve-main-repo-from-git-file.ts
|
|
34836
|
-
import * as
|
|
34837
|
-
import * as
|
|
35179
|
+
import * as fs19 from "node:fs";
|
|
35180
|
+
import * as path22 from "node:path";
|
|
34838
35181
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
34839
|
-
const gitDirFile =
|
|
34840
|
-
if (!
|
|
34841
|
-
const first2 =
|
|
35182
|
+
const gitDirFile = path22.join(wt, ".git");
|
|
35183
|
+
if (!fs19.existsSync(gitDirFile) || !fs19.statSync(gitDirFile).isFile()) return "";
|
|
35184
|
+
const first2 = fs19.readFileSync(gitDirFile, "utf8").trim();
|
|
34842
35185
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
34843
35186
|
if (!m) return "";
|
|
34844
|
-
const gitWorktreePath =
|
|
34845
|
-
const gitDir =
|
|
34846
|
-
return
|
|
35187
|
+
const gitWorktreePath = path22.resolve(wt, m[1].trim());
|
|
35188
|
+
const gitDir = path22.dirname(path22.dirname(gitWorktreePath));
|
|
35189
|
+
return path22.dirname(gitDir);
|
|
34847
35190
|
}
|
|
34848
35191
|
|
|
34849
35192
|
// src/git/worktree-remove.ts
|
|
@@ -34852,7 +35195,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
34852
35195
|
if (mainRepo) {
|
|
34853
35196
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
34854
35197
|
} else {
|
|
34855
|
-
|
|
35198
|
+
fs20.rmSync(worktreePath, { recursive: true, force: true });
|
|
34856
35199
|
}
|
|
34857
35200
|
}
|
|
34858
35201
|
|
|
@@ -34865,7 +35208,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
34865
35208
|
} catch (e) {
|
|
34866
35209
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
34867
35210
|
try {
|
|
34868
|
-
|
|
35211
|
+
fs21.rmSync(wt, { recursive: true, force: true });
|
|
34869
35212
|
} catch {
|
|
34870
35213
|
}
|
|
34871
35214
|
}
|
|
@@ -35085,7 +35428,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
35085
35428
|
}
|
|
35086
35429
|
|
|
35087
35430
|
// src/git/working-directory/changes/get-working-tree-change-repo-details.ts
|
|
35088
|
-
import * as
|
|
35431
|
+
import * as path24 from "node:path";
|
|
35089
35432
|
|
|
35090
35433
|
// src/git/working-directory/changes/parse-git-status.ts
|
|
35091
35434
|
function parseNameStatusLines(lines) {
|
|
@@ -35205,8 +35548,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
35205
35548
|
}
|
|
35206
35549
|
|
|
35207
35550
|
// src/git/working-directory/changes/list-changed-files-for-repo.ts
|
|
35208
|
-
import * as
|
|
35209
|
-
import * as
|
|
35551
|
+
import * as fs23 from "node:fs";
|
|
35552
|
+
import * as path23 from "node:path";
|
|
35210
35553
|
|
|
35211
35554
|
// src/git/working-directory/changes/count-lines.ts
|
|
35212
35555
|
import { createReadStream } from "node:fs";
|
|
@@ -35230,7 +35573,7 @@ async function countTextFileLines(filePath) {
|
|
|
35230
35573
|
}
|
|
35231
35574
|
|
|
35232
35575
|
// src/git/working-directory/changes/hydrate-patch.ts
|
|
35233
|
-
import * as
|
|
35576
|
+
import * as fs22 from "node:fs";
|
|
35234
35577
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
35235
35578
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
35236
35579
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -35245,7 +35588,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
35245
35588
|
}
|
|
35246
35589
|
async function readWorktreeFileLines(filePath) {
|
|
35247
35590
|
try {
|
|
35248
|
-
const raw = await
|
|
35591
|
+
const raw = await fs22.promises.readFile(filePath, "utf8");
|
|
35249
35592
|
return raw.split(/\r?\n/);
|
|
35250
35593
|
} catch {
|
|
35251
35594
|
return null;
|
|
@@ -35380,7 +35723,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
35380
35723
|
const rows = [];
|
|
35381
35724
|
for (const pathInRepo of paths) {
|
|
35382
35725
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
35383
|
-
const repoFilePath =
|
|
35726
|
+
const repoFilePath = path23.join(repoGitCwd, pathInRepo);
|
|
35384
35727
|
const nums = numByPath.get(pathInRepo);
|
|
35385
35728
|
let additions = nums?.additions ?? 0;
|
|
35386
35729
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -35393,7 +35736,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
35393
35736
|
deletions = fromGit.deletions;
|
|
35394
35737
|
} else {
|
|
35395
35738
|
try {
|
|
35396
|
-
const st = await
|
|
35739
|
+
const st = await fs23.promises.stat(repoFilePath);
|
|
35397
35740
|
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
35398
35741
|
else additions = 0;
|
|
35399
35742
|
} catch {
|
|
@@ -35419,7 +35762,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
35419
35762
|
} else {
|
|
35420
35763
|
pathInRepo = row.pathRelLauncher;
|
|
35421
35764
|
}
|
|
35422
|
-
const filePath =
|
|
35765
|
+
const filePath = path23.join(repoGitCwd, pathInRepo);
|
|
35423
35766
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
35424
35767
|
if (patch) {
|
|
35425
35768
|
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
@@ -35435,8 +35778,8 @@ function normRepoRel(p) {
|
|
|
35435
35778
|
return x === "" ? "." : x;
|
|
35436
35779
|
}
|
|
35437
35780
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
35438
|
-
const bridgeRoot =
|
|
35439
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
35781
|
+
const bridgeRoot = path24.resolve(getBridgeRoot());
|
|
35782
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path24.resolve(options.sessionWorktreeRootPath) : null;
|
|
35440
35783
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
35441
35784
|
const out = [];
|
|
35442
35785
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -35449,7 +35792,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
35449
35792
|
}
|
|
35450
35793
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
35451
35794
|
for (const target of options.commitTargetPaths) {
|
|
35452
|
-
const t =
|
|
35795
|
+
const t = path24.resolve(target);
|
|
35453
35796
|
if (!await isGitRepoDirectory(t)) continue;
|
|
35454
35797
|
const g = cliSimpleGit(t);
|
|
35455
35798
|
let branch = "HEAD";
|
|
@@ -35462,8 +35805,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
35462
35805
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
35463
35806
|
let repoRelPath;
|
|
35464
35807
|
if (sessionWtRoot) {
|
|
35465
|
-
const anchor = legacyNested ?
|
|
35466
|
-
const relNorm =
|
|
35808
|
+
const anchor = legacyNested ? path24.dirname(t) : t;
|
|
35809
|
+
const relNorm = path24.relative(sessionWtRoot, anchor);
|
|
35467
35810
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
35468
35811
|
} else {
|
|
35469
35812
|
let top = t;
|
|
@@ -35472,8 +35815,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
35472
35815
|
} catch {
|
|
35473
35816
|
top = t;
|
|
35474
35817
|
}
|
|
35475
|
-
const rel =
|
|
35476
|
-
repoRelPath = rel.startsWith("..") ?
|
|
35818
|
+
const rel = path24.relative(bridgeRoot, path24.resolve(top)).replace(/\\/g, "/") || ".";
|
|
35819
|
+
repoRelPath = rel.startsWith("..") ? path24.basename(path24.resolve(top)) : rel;
|
|
35477
35820
|
}
|
|
35478
35821
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
35479
35822
|
if (filter && norm !== filter) continue;
|
|
@@ -35538,11 +35881,11 @@ async function commitSessionWorktrees(options) {
|
|
|
35538
35881
|
}
|
|
35539
35882
|
|
|
35540
35883
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
35541
|
-
import * as
|
|
35542
|
-
import * as
|
|
35884
|
+
import * as fs24 from "node:fs";
|
|
35885
|
+
import * as path25 from "node:path";
|
|
35543
35886
|
function isGitDir(dirPath) {
|
|
35544
35887
|
try {
|
|
35545
|
-
return
|
|
35888
|
+
return fs24.existsSync(path25.join(dirPath, ".git"));
|
|
35546
35889
|
} catch {
|
|
35547
35890
|
return false;
|
|
35548
35891
|
}
|
|
@@ -35551,23 +35894,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
35551
35894
|
const out = [];
|
|
35552
35895
|
const walk = (dir) => {
|
|
35553
35896
|
if (isGitDir(dir)) {
|
|
35554
|
-
out.push(
|
|
35897
|
+
out.push(path25.resolve(dir));
|
|
35555
35898
|
return;
|
|
35556
35899
|
}
|
|
35557
35900
|
let entries;
|
|
35558
35901
|
try {
|
|
35559
|
-
entries =
|
|
35902
|
+
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
35560
35903
|
} catch {
|
|
35561
35904
|
return;
|
|
35562
35905
|
}
|
|
35563
35906
|
for (const e of entries) {
|
|
35564
35907
|
if (e.name.startsWith(".")) continue;
|
|
35565
|
-
const full =
|
|
35908
|
+
const full = path25.join(dir, e.name);
|
|
35566
35909
|
if (!e.isDirectory()) continue;
|
|
35567
35910
|
walk(full);
|
|
35568
35911
|
}
|
|
35569
35912
|
};
|
|
35570
|
-
walk(
|
|
35913
|
+
walk(path25.resolve(rootPath));
|
|
35571
35914
|
return [...new Set(out)];
|
|
35572
35915
|
}
|
|
35573
35916
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -35576,16 +35919,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
35576
35919
|
if (depth > maxDepth) return;
|
|
35577
35920
|
let entries;
|
|
35578
35921
|
try {
|
|
35579
|
-
entries =
|
|
35922
|
+
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
35580
35923
|
} catch {
|
|
35581
35924
|
return;
|
|
35582
35925
|
}
|
|
35583
35926
|
for (const e of entries) {
|
|
35584
35927
|
if (e.name.startsWith(".")) continue;
|
|
35585
|
-
const full =
|
|
35928
|
+
const full = path25.join(dir, e.name);
|
|
35586
35929
|
if (!e.isDirectory()) continue;
|
|
35587
35930
|
if (e.name === sessionId) {
|
|
35588
|
-
if (isGitDir(full)) out.push(
|
|
35931
|
+
if (isGitDir(full)) out.push(path25.resolve(full));
|
|
35589
35932
|
} else {
|
|
35590
35933
|
walk(full, depth + 1);
|
|
35591
35934
|
}
|
|
@@ -35597,14 +35940,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
35597
35940
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
35598
35941
|
let st;
|
|
35599
35942
|
try {
|
|
35600
|
-
st =
|
|
35943
|
+
st = fs24.statSync(sessionDir);
|
|
35601
35944
|
} catch {
|
|
35602
35945
|
return null;
|
|
35603
35946
|
}
|
|
35604
35947
|
if (!st.isDirectory()) return null;
|
|
35605
35948
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
35606
35949
|
if (worktreePaths.length === 0) return null;
|
|
35607
|
-
const abs =
|
|
35950
|
+
const abs = path25.resolve(sessionDir);
|
|
35608
35951
|
return {
|
|
35609
35952
|
sessionParentPath: abs,
|
|
35610
35953
|
workingTreeRelRoot: abs,
|
|
@@ -35614,20 +35957,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
35614
35957
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
35615
35958
|
const sid = sessionId.trim();
|
|
35616
35959
|
if (!sid) return null;
|
|
35617
|
-
const hintR =
|
|
35960
|
+
const hintR = path25.resolve(checkoutPath);
|
|
35618
35961
|
let best = null;
|
|
35619
|
-
let cur =
|
|
35962
|
+
let cur = path25.dirname(hintR);
|
|
35620
35963
|
for (let i = 0; i < 40; i++) {
|
|
35621
35964
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
35622
|
-
if (paths.some((p) =>
|
|
35623
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
35965
|
+
if (paths.some((p) => path25.resolve(p) === hintR)) {
|
|
35966
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path25.resolve(paths[0]);
|
|
35624
35967
|
best = {
|
|
35625
|
-
sessionParentPath:
|
|
35626
|
-
workingTreeRelRoot:
|
|
35627
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
35968
|
+
sessionParentPath: path25.resolve(isolated),
|
|
35969
|
+
workingTreeRelRoot: path25.resolve(cur),
|
|
35970
|
+
repoCheckoutPaths: paths.map((p) => path25.resolve(p))
|
|
35628
35971
|
};
|
|
35629
35972
|
}
|
|
35630
|
-
const next =
|
|
35973
|
+
const next = path25.dirname(cur);
|
|
35631
35974
|
if (next === cur) break;
|
|
35632
35975
|
cur = next;
|
|
35633
35976
|
}
|
|
@@ -35635,33 +35978,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
35635
35978
|
}
|
|
35636
35979
|
function discoverSessionWorktreeOnDisk(options) {
|
|
35637
35980
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
35638
|
-
if (!sessionId.trim() || !
|
|
35981
|
+
if (!sessionId.trim() || !fs24.existsSync(worktreesRootPath)) return null;
|
|
35639
35982
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
35640
35983
|
const keys = [];
|
|
35641
35984
|
if (preferredKey) keys.push(preferredKey);
|
|
35642
35985
|
try {
|
|
35643
|
-
for (const name of
|
|
35986
|
+
for (const name of fs24.readdirSync(worktreesRootPath)) {
|
|
35644
35987
|
if (name.startsWith(".")) continue;
|
|
35645
|
-
const p =
|
|
35646
|
-
if (!
|
|
35988
|
+
const p = path25.join(worktreesRootPath, name);
|
|
35989
|
+
if (!fs24.statSync(p).isDirectory()) continue;
|
|
35647
35990
|
if (name !== preferredKey) keys.push(name);
|
|
35648
35991
|
}
|
|
35649
35992
|
} catch {
|
|
35650
35993
|
return null;
|
|
35651
35994
|
}
|
|
35652
35995
|
for (const key of keys) {
|
|
35653
|
-
const layoutRoot =
|
|
35654
|
-
if (!
|
|
35655
|
-
const sessionDir =
|
|
35996
|
+
const layoutRoot = path25.join(worktreesRootPath, key);
|
|
35997
|
+
if (!fs24.existsSync(layoutRoot) || !fs24.statSync(layoutRoot).isDirectory()) continue;
|
|
35998
|
+
const sessionDir = path25.join(layoutRoot, sessionId);
|
|
35656
35999
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
35657
36000
|
if (nested) return nested;
|
|
35658
36001
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
35659
36002
|
if (legacyPaths.length > 0) {
|
|
35660
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
36003
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
35661
36004
|
return {
|
|
35662
|
-
sessionParentPath:
|
|
35663
|
-
workingTreeRelRoot:
|
|
35664
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
36005
|
+
sessionParentPath: path25.resolve(isolated),
|
|
36006
|
+
workingTreeRelRoot: path25.resolve(layoutRoot),
|
|
36007
|
+
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
35665
36008
|
};
|
|
35666
36009
|
}
|
|
35667
36010
|
}
|
|
@@ -35670,12 +36013,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
35670
36013
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
35671
36014
|
const sid = sessionId.trim();
|
|
35672
36015
|
if (!sid) return null;
|
|
35673
|
-
const hint =
|
|
35674
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
36016
|
+
const hint = path25.resolve(sessionWorktreeRootPathOrHint);
|
|
36017
|
+
const underHint = tryBindingFromSessionDirectory(path25.join(hint, sid));
|
|
35675
36018
|
if (underHint) return underHint;
|
|
35676
36019
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
35677
36020
|
if (direct) {
|
|
35678
|
-
if (
|
|
36021
|
+
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
35679
36022
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
35680
36023
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
35681
36024
|
return legacyFromCheckout;
|
|
@@ -35683,24 +36026,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
35683
36026
|
}
|
|
35684
36027
|
return direct;
|
|
35685
36028
|
}
|
|
35686
|
-
if (
|
|
36029
|
+
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
35687
36030
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
35688
36031
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
35689
36032
|
}
|
|
35690
36033
|
let st;
|
|
35691
36034
|
try {
|
|
35692
|
-
st =
|
|
36035
|
+
st = fs24.statSync(hint);
|
|
35693
36036
|
} catch {
|
|
35694
36037
|
return null;
|
|
35695
36038
|
}
|
|
35696
36039
|
if (!st.isDirectory()) return null;
|
|
35697
36040
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
35698
36041
|
if (legacyPaths.length === 0) return null;
|
|
35699
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
36042
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
35700
36043
|
return {
|
|
35701
|
-
sessionParentPath:
|
|
36044
|
+
sessionParentPath: path25.resolve(isolated),
|
|
35702
36045
|
workingTreeRelRoot: hint,
|
|
35703
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
36046
|
+
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
35704
36047
|
};
|
|
35705
36048
|
}
|
|
35706
36049
|
|
|
@@ -35723,10 +36066,10 @@ var SessionWorktreeManager = class {
|
|
|
35723
36066
|
this.layout = loadWorktreeLayout();
|
|
35724
36067
|
}
|
|
35725
36068
|
rememberSessionWorktrees(sessionId, binding) {
|
|
35726
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
36069
|
+
const paths = binding.repoCheckoutPaths.map((p) => path26.resolve(p));
|
|
35727
36070
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
35728
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
35729
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
36071
|
+
this.sessionParentPathBySession.set(sessionId, path26.resolve(binding.sessionParentPath));
|
|
36072
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path26.resolve(binding.workingTreeRelRoot));
|
|
35730
36073
|
}
|
|
35731
36074
|
sessionParentPathAfterRemember(sessionId) {
|
|
35732
36075
|
return this.sessionParentPathBySession.get(sessionId);
|
|
@@ -35743,7 +36086,7 @@ var SessionWorktreeManager = class {
|
|
|
35743
36086
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
35744
36087
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
35745
36088
|
if (!parent || !relRoot) return false;
|
|
35746
|
-
return
|
|
36089
|
+
return path26.resolve(parent) !== path26.resolve(relRoot);
|
|
35747
36090
|
}
|
|
35748
36091
|
/**
|
|
35749
36092
|
* Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
|
|
@@ -35752,7 +36095,7 @@ var SessionWorktreeManager = class {
|
|
|
35752
36095
|
if (!sessionId) return null;
|
|
35753
36096
|
const sid = sessionId.trim();
|
|
35754
36097
|
const cached2 = this.sessionParentPathBySession.get(sid);
|
|
35755
|
-
if (cached2) return
|
|
36098
|
+
if (cached2) return path26.resolve(cached2);
|
|
35756
36099
|
const paths = this.ensureRepoCheckoutPathsForSession(sid) ?? this.getRepoCheckoutPathsForSession(sid);
|
|
35757
36100
|
if (!paths?.length) return null;
|
|
35758
36101
|
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
@@ -35766,7 +36109,7 @@ var SessionWorktreeManager = class {
|
|
|
35766
36109
|
const sid = sessionId.trim();
|
|
35767
36110
|
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
35768
36111
|
if (parentPathRaw) {
|
|
35769
|
-
const resolved =
|
|
36112
|
+
const resolved = path26.resolve(parentPathRaw);
|
|
35770
36113
|
if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
|
|
35771
36114
|
const diskFirst = this.tryDiscoverFromDisk(sid);
|
|
35772
36115
|
if (diskFirst) {
|
|
@@ -35785,7 +36128,7 @@ var SessionWorktreeManager = class {
|
|
|
35785
36128
|
this.rememberSessionWorktrees(sid, tryRoot);
|
|
35786
36129
|
return this.sessionParentPathAfterRemember(sid);
|
|
35787
36130
|
}
|
|
35788
|
-
const next =
|
|
36131
|
+
const next = path26.dirname(cur);
|
|
35789
36132
|
if (next === cur) break;
|
|
35790
36133
|
cur = next;
|
|
35791
36134
|
}
|
|
@@ -35938,15 +36281,22 @@ var SessionWorktreeManager = class {
|
|
|
35938
36281
|
}
|
|
35939
36282
|
};
|
|
35940
36283
|
function defaultWorktreesRootPath() {
|
|
35941
|
-
return
|
|
36284
|
+
return path26.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
35942
36285
|
}
|
|
35943
36286
|
|
|
35944
36287
|
// src/files/watch-file-index.ts
|
|
35945
36288
|
import { watch } from "node:fs";
|
|
36289
|
+
import path31 from "node:path";
|
|
36290
|
+
|
|
36291
|
+
// src/files/index/paths.ts
|
|
35946
36292
|
import path27 from "node:path";
|
|
36293
|
+
import crypto2 from "node:crypto";
|
|
36294
|
+
function getCwdHashForFileIndex(resolvedCwd) {
|
|
36295
|
+
return crypto2.createHash("sha256").update(path27.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
36296
|
+
}
|
|
35947
36297
|
|
|
35948
36298
|
// src/files/index/build-file-index.ts
|
|
35949
|
-
import
|
|
36299
|
+
import path29 from "node:path";
|
|
35950
36300
|
|
|
35951
36301
|
// src/runtime/yield-to-event-loop.ts
|
|
35952
36302
|
function yieldToEventLoop() {
|
|
@@ -35954,47 +36304,12 @@ function yieldToEventLoop() {
|
|
|
35954
36304
|
}
|
|
35955
36305
|
|
|
35956
36306
|
// src/files/index/walk-workspace-tree.ts
|
|
35957
|
-
import
|
|
35958
|
-
import
|
|
35959
|
-
|
|
35960
|
-
// src/files/index/constants.ts
|
|
35961
|
-
import path21 from "node:path";
|
|
35962
|
-
import os6 from "node:os";
|
|
35963
|
-
var INDEX_WORK_YIELD_EVERY = 256;
|
|
35964
|
-
var INDEX_DIR = path21.join(os6.homedir(), ".buildautomaton");
|
|
35965
|
-
var INDEX_HASH_LEN = 16;
|
|
35966
|
-
var INDEX_VERSION = 2;
|
|
35967
|
-
var INDEX_LOG_PREFIX = "[file-index]";
|
|
35968
|
-
|
|
35969
|
-
// src/files/index/walk-workspace-tree.ts
|
|
35970
|
-
function walkWorkspaceTreeSync(dir, baseDir, out) {
|
|
35971
|
-
let names;
|
|
35972
|
-
try {
|
|
35973
|
-
names = fs20.readdirSync(dir);
|
|
35974
|
-
} catch {
|
|
35975
|
-
return;
|
|
35976
|
-
}
|
|
35977
|
-
for (const name of names) {
|
|
35978
|
-
if (name.startsWith(".")) continue;
|
|
35979
|
-
const full = path22.join(dir, name);
|
|
35980
|
-
let stat3;
|
|
35981
|
-
try {
|
|
35982
|
-
stat3 = fs20.statSync(full);
|
|
35983
|
-
} catch {
|
|
35984
|
-
continue;
|
|
35985
|
-
}
|
|
35986
|
-
const relative5 = path22.relative(baseDir, full).replace(/\\/g, "/");
|
|
35987
|
-
if (stat3.isDirectory()) {
|
|
35988
|
-
walkWorkspaceTreeSync(full, baseDir, out);
|
|
35989
|
-
} else if (stat3.isFile()) {
|
|
35990
|
-
out.push(relative5);
|
|
35991
|
-
}
|
|
35992
|
-
}
|
|
35993
|
-
}
|
|
36307
|
+
import fs25 from "node:fs";
|
|
36308
|
+
import path28 from "node:path";
|
|
35994
36309
|
async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
35995
36310
|
let names;
|
|
35996
36311
|
try {
|
|
35997
|
-
names = await
|
|
36312
|
+
names = await fs25.promises.readdir(dir);
|
|
35998
36313
|
} catch {
|
|
35999
36314
|
return;
|
|
36000
36315
|
}
|
|
@@ -36004,14 +36319,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, out, state) {
|
|
|
36004
36319
|
await yieldToEventLoop();
|
|
36005
36320
|
}
|
|
36006
36321
|
state.n++;
|
|
36007
|
-
const full =
|
|
36322
|
+
const full = path28.join(dir, name);
|
|
36008
36323
|
let stat3;
|
|
36009
36324
|
try {
|
|
36010
|
-
stat3 = await
|
|
36325
|
+
stat3 = await fs25.promises.stat(full);
|
|
36011
36326
|
} catch {
|
|
36012
36327
|
continue;
|
|
36013
36328
|
}
|
|
36014
|
-
const relative5 =
|
|
36329
|
+
const relative5 = path28.relative(baseDir, full).replace(/\\/g, "/");
|
|
36015
36330
|
if (stat3.isDirectory()) {
|
|
36016
36331
|
await walkWorkspaceTreeAsync(full, baseDir, out, state);
|
|
36017
36332
|
} else if (stat3.isFile()) {
|
|
@@ -36023,205 +36338,124 @@ function createWalkYieldState() {
|
|
|
36023
36338
|
return { n: 0 };
|
|
36024
36339
|
}
|
|
36025
36340
|
|
|
36026
|
-
// src/files/index/
|
|
36027
|
-
|
|
36028
|
-
|
|
36029
|
-
const
|
|
36030
|
-
|
|
36031
|
-
out.push(lower.slice(i, i + 3));
|
|
36032
|
-
}
|
|
36033
|
-
return out;
|
|
36034
|
-
}
|
|
36035
|
-
function binarySearch(arr, x) {
|
|
36036
|
-
let lo = 0;
|
|
36037
|
-
let hi = arr.length - 1;
|
|
36038
|
-
while (lo <= hi) {
|
|
36039
|
-
const mid = lo + hi >>> 1;
|
|
36040
|
-
if (arr[mid] < x) lo = mid + 1;
|
|
36041
|
-
else if (arr[mid] > x) hi = mid - 1;
|
|
36042
|
-
else return mid;
|
|
36043
|
-
}
|
|
36044
|
-
return -1;
|
|
36045
|
-
}
|
|
36046
|
-
function intersectSortedTrigramSets(arrays) {
|
|
36047
|
-
if (arrays.length === 0) return [];
|
|
36048
|
-
if (arrays.length === 1) return arrays[0];
|
|
36049
|
-
const byLength = arrays.slice().sort((a, b) => a.length - b.length);
|
|
36050
|
-
const smallest = byLength[0];
|
|
36051
|
-
const rest = byLength.slice(1);
|
|
36052
|
-
const result = [];
|
|
36053
|
-
for (const idx of smallest) {
|
|
36054
|
-
if (rest.every((arr) => binarySearch(arr, idx) >= 0)) {
|
|
36055
|
-
result.push(idx);
|
|
36056
|
-
}
|
|
36057
|
-
}
|
|
36058
|
-
return result;
|
|
36059
|
-
}
|
|
36060
|
-
|
|
36061
|
-
// src/files/index/build-trigram-map.ts
|
|
36062
|
-
function buildTrigramMapForPaths(paths) {
|
|
36063
|
-
const trigramIndex = {};
|
|
36064
|
-
for (let i = 0; i < paths.length; i++) {
|
|
36065
|
-
const trigrams = getTrigrams(paths[i]);
|
|
36066
|
-
const seen = /* @__PURE__ */ new Set();
|
|
36067
|
-
for (const tri of trigrams) {
|
|
36068
|
-
if (seen.has(tri)) continue;
|
|
36069
|
-
seen.add(tri);
|
|
36070
|
-
if (!trigramIndex[tri]) trigramIndex[tri] = [];
|
|
36071
|
-
trigramIndex[tri].push(i);
|
|
36072
|
-
}
|
|
36073
|
-
}
|
|
36074
|
-
return trigramIndex;
|
|
36341
|
+
// src/files/index/file-index-sqlite-lock.ts
|
|
36342
|
+
import fs26 from "node:fs";
|
|
36343
|
+
function isSqliteCorruptError(e) {
|
|
36344
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
36345
|
+
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
36075
36346
|
}
|
|
36076
|
-
|
|
36077
|
-
|
|
36078
|
-
|
|
36079
|
-
|
|
36080
|
-
await
|
|
36081
|
-
}
|
|
36082
|
-
|
|
36083
|
-
|
|
36084
|
-
|
|
36085
|
-
|
|
36086
|
-
|
|
36087
|
-
|
|
36088
|
-
|
|
36347
|
+
var chain = Promise.resolve();
|
|
36348
|
+
function withFileIndexSqliteLock(fn) {
|
|
36349
|
+
const run = async () => {
|
|
36350
|
+
try {
|
|
36351
|
+
return await Promise.resolve(fn());
|
|
36352
|
+
} catch (e) {
|
|
36353
|
+
if (!isSqliteCorruptError(e)) throw e;
|
|
36354
|
+
closeAllCliSqliteConnections();
|
|
36355
|
+
try {
|
|
36356
|
+
fs26.unlinkSync(getCliSqlitePath());
|
|
36357
|
+
} catch {
|
|
36358
|
+
}
|
|
36359
|
+
chain = Promise.resolve();
|
|
36360
|
+
return await Promise.resolve(fn());
|
|
36089
36361
|
}
|
|
36090
|
-
}
|
|
36091
|
-
|
|
36092
|
-
|
|
36093
|
-
|
|
36094
|
-
|
|
36095
|
-
|
|
36096
|
-
|
|
36097
|
-
// src/files/index/paths.ts
|
|
36098
|
-
import path23 from "node:path";
|
|
36099
|
-
import crypto2 from "node:crypto";
|
|
36100
|
-
function getIndexPathForCwd(resolvedCwd) {
|
|
36101
|
-
const hash = crypto2.createHash("sha256").update(resolvedCwd).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
36102
|
-
return path23.join(INDEX_DIR, `.file-index-${hash}.json`);
|
|
36103
|
-
}
|
|
36104
|
-
|
|
36105
|
-
// src/files/index/write-index-file.ts
|
|
36106
|
-
function writeIndexFileSync(resolvedCwd, data) {
|
|
36107
|
-
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
36108
|
-
try {
|
|
36109
|
-
if (!fs21.existsSync(INDEX_DIR)) fs21.mkdirSync(INDEX_DIR, { recursive: true });
|
|
36110
|
-
fs21.writeFileSync(indexPath, JSON.stringify(data), "utf8");
|
|
36111
|
-
} catch (e) {
|
|
36112
|
-
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
36113
|
-
}
|
|
36114
|
-
}
|
|
36115
|
-
async function writeIndexFileAsync(resolvedCwd, data) {
|
|
36116
|
-
const indexPath = getIndexPathForCwd(resolvedCwd);
|
|
36117
|
-
try {
|
|
36118
|
-
await fs21.promises.mkdir(INDEX_DIR, { recursive: true });
|
|
36119
|
-
await fs21.promises.writeFile(indexPath, JSON.stringify(data), "utf8");
|
|
36120
|
-
} catch (e) {
|
|
36121
|
-
console.error(`${INDEX_LOG_PREFIX} Failed to write index:`, e);
|
|
36122
|
-
}
|
|
36123
|
-
}
|
|
36124
|
-
function makeTrigramIndexData(paths, trigramIndex) {
|
|
36125
|
-
return { version: INDEX_VERSION, paths, trigramIndex };
|
|
36362
|
+
};
|
|
36363
|
+
const next = chain.then(run);
|
|
36364
|
+
chain = next.then(
|
|
36365
|
+
() => void 0,
|
|
36366
|
+
() => void 0
|
|
36367
|
+
);
|
|
36368
|
+
return next;
|
|
36126
36369
|
}
|
|
36127
36370
|
|
|
36128
36371
|
// src/files/index/build-file-index.ts
|
|
36129
36372
|
function sortPaths(paths) {
|
|
36130
36373
|
paths.sort((a, b) => a.localeCompare(b, void 0, { sensitivity: "base" }));
|
|
36131
36374
|
}
|
|
36132
|
-
function
|
|
36133
|
-
const
|
|
36134
|
-
const
|
|
36135
|
-
|
|
36136
|
-
sortPaths(paths);
|
|
36137
|
-
const trigramIndex = buildTrigramMapForPaths(paths);
|
|
36138
|
-
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
36139
|
-
writeIndexFileSync(resolved, data);
|
|
36140
|
-
return data;
|
|
36141
|
-
}
|
|
36142
|
-
async function buildFileIndexAsync(cwd) {
|
|
36143
|
-
const resolved = path24.resolve(cwd);
|
|
36144
|
-
const paths = [];
|
|
36145
|
-
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
36146
|
-
await yieldToEventLoop();
|
|
36147
|
-
sortPaths(paths);
|
|
36148
|
-
const trigramIndex = await buildTrigramMapForPathsAsync(paths);
|
|
36149
|
-
const data = makeTrigramIndexData(paths, trigramIndex);
|
|
36150
|
-
await writeIndexFileAsync(resolved, data);
|
|
36151
|
-
return data;
|
|
36152
|
-
}
|
|
36153
|
-
|
|
36154
|
-
// src/files/index/load-file-index.ts
|
|
36155
|
-
import fs22 from "node:fs";
|
|
36156
|
-
import path25 from "node:path";
|
|
36157
|
-
function loadFileIndex(cwd) {
|
|
36158
|
-
const resolved = path25.resolve(cwd);
|
|
36159
|
-
const indexPath = getIndexPathForCwd(resolved);
|
|
36375
|
+
function persistPathsToSqlite(resolved, paths) {
|
|
36376
|
+
const db = getCliDatabase();
|
|
36377
|
+
const h = getCwdHashForFileIndex(resolved);
|
|
36378
|
+
db.run("BEGIN IMMEDIATE");
|
|
36160
36379
|
try {
|
|
36161
|
-
|
|
36162
|
-
const
|
|
36163
|
-
|
|
36164
|
-
const
|
|
36165
|
-
|
|
36166
|
-
return obj;
|
|
36380
|
+
db.run("DELETE FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
36381
|
+
const ins = db.prepare("INSERT INTO file_index_path (cwd_hash, path) VALUES (?, ?)");
|
|
36382
|
+
try {
|
|
36383
|
+
for (const rel of paths) {
|
|
36384
|
+
ins.run([h, rel]);
|
|
36167
36385
|
}
|
|
36168
|
-
|
|
36386
|
+
} finally {
|
|
36387
|
+
ins.finalize();
|
|
36169
36388
|
}
|
|
36170
|
-
|
|
36171
|
-
|
|
36389
|
+
db.run("COMMIT");
|
|
36390
|
+
} catch (e) {
|
|
36391
|
+
try {
|
|
36392
|
+
db.run("ROLLBACK");
|
|
36393
|
+
} catch {
|
|
36172
36394
|
}
|
|
36173
|
-
|
|
36174
|
-
} catch {
|
|
36175
|
-
return null;
|
|
36395
|
+
throw e;
|
|
36176
36396
|
}
|
|
36177
36397
|
}
|
|
36398
|
+
async function buildFileIndexAsync(cwd) {
|
|
36399
|
+
return withFileIndexSqliteLock(async () => {
|
|
36400
|
+
const resolved = path29.resolve(cwd);
|
|
36401
|
+
const paths = [];
|
|
36402
|
+
await walkWorkspaceTreeAsync(resolved, resolved, paths, createWalkYieldState());
|
|
36403
|
+
await yieldToEventLoop();
|
|
36404
|
+
sortPaths(paths);
|
|
36405
|
+
persistPathsToSqlite(resolved, paths);
|
|
36406
|
+
return { pathCount: paths.length };
|
|
36407
|
+
});
|
|
36408
|
+
}
|
|
36178
36409
|
|
|
36179
36410
|
// src/files/index/ensure-file-index.ts
|
|
36180
|
-
import
|
|
36181
|
-
async function ensureFileIndexAsync(cwd) {
|
|
36182
|
-
const resolved = path26.resolve(cwd);
|
|
36183
|
-
const cached2 = loadFileIndex(resolved);
|
|
36184
|
-
if (cached2 !== null) return { data: cached2, fromCache: true };
|
|
36185
|
-
const data = await buildFileIndexAsync(resolved);
|
|
36186
|
-
return { data, fromCache: false };
|
|
36187
|
-
}
|
|
36411
|
+
import path30 from "node:path";
|
|
36188
36412
|
|
|
36189
36413
|
// src/files/index/search-file-index.ts
|
|
36190
|
-
function
|
|
36191
|
-
|
|
36192
|
-
|
|
36193
|
-
|
|
36194
|
-
|
|
36195
|
-
const
|
|
36196
|
-
|
|
36197
|
-
|
|
36198
|
-
|
|
36199
|
-
|
|
36200
|
-
|
|
36201
|
-
|
|
36202
|
-
|
|
36203
|
-
|
|
36204
|
-
|
|
36414
|
+
function escapeLikePattern(fragment) {
|
|
36415
|
+
return fragment.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
36416
|
+
}
|
|
36417
|
+
function bridgeFileIndexIsPopulated(resolvedCwd) {
|
|
36418
|
+
const db = getCliDatabase();
|
|
36419
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
36420
|
+
const row = db.get("SELECT 1 as ok FROM file_index_path WHERE cwd_hash = ? LIMIT 1", [h]);
|
|
36421
|
+
return row != null;
|
|
36422
|
+
}
|
|
36423
|
+
function bridgeFileIndexPathCount(resolvedCwd) {
|
|
36424
|
+
const db = getCliDatabase();
|
|
36425
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
36426
|
+
const row = db.get("SELECT COUNT(*) as c FROM file_index_path WHERE cwd_hash = ?", [h]);
|
|
36427
|
+
const c = row?.c ?? 0;
|
|
36428
|
+
return Number(c);
|
|
36429
|
+
}
|
|
36430
|
+
function searchBridgeFilePaths(resolvedCwd, query, limit = 100) {
|
|
36205
36431
|
const q = query.trim().toLowerCase();
|
|
36206
36432
|
if (!q) return [];
|
|
36207
|
-
const
|
|
36208
|
-
const
|
|
36209
|
-
const
|
|
36210
|
-
|
|
36211
|
-
|
|
36212
|
-
|
|
36213
|
-
|
|
36214
|
-
|
|
36215
|
-
|
|
36216
|
-
|
|
36217
|
-
|
|
36218
|
-
|
|
36219
|
-
|
|
36220
|
-
|
|
36221
|
-
}
|
|
36433
|
+
const db = getCliDatabase();
|
|
36434
|
+
const h = getCwdHashForFileIndex(resolvedCwd);
|
|
36435
|
+
const pattern = `%${escapeLikePattern(q)}%`;
|
|
36436
|
+
const lim = Math.max(0, Math.min(1e4, Math.floor(limit)));
|
|
36437
|
+
const rows = db.all(
|
|
36438
|
+
`SELECT path FROM file_index_path WHERE cwd_hash = ? AND lower(path) LIKE ? ESCAPE '\\' LIMIT ?`,
|
|
36439
|
+
[h, pattern, lim]
|
|
36440
|
+
);
|
|
36441
|
+
return rows.map((r) => String(r.path));
|
|
36442
|
+
}
|
|
36443
|
+
async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
36444
|
+
await yieldToEventLoop();
|
|
36445
|
+
const out = searchBridgeFilePaths(resolvedCwd, query, limit);
|
|
36446
|
+
if (out.length >= INDEX_WORK_YIELD_EVERY) await yieldToEventLoop();
|
|
36222
36447
|
return out;
|
|
36223
36448
|
}
|
|
36224
36449
|
|
|
36450
|
+
// src/files/index/ensure-file-index.ts
|
|
36451
|
+
async function ensureFileIndexAsync(cwd) {
|
|
36452
|
+
const resolved = path30.resolve(cwd);
|
|
36453
|
+
if (bridgeFileIndexIsPopulated(resolved)) {
|
|
36454
|
+
return { fromCache: true, pathCount: bridgeFileIndexPathCount(resolved) };
|
|
36455
|
+
}
|
|
36456
|
+
return { ...await buildFileIndexAsync(resolved), fromCache: false };
|
|
36457
|
+
}
|
|
36458
|
+
|
|
36225
36459
|
// src/files/watch-file-index.ts
|
|
36226
36460
|
var DEBOUNCE_MS = 900;
|
|
36227
36461
|
function shouldIgnoreRelative(rel) {
|
|
@@ -36262,7 +36496,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
36262
36496
|
}
|
|
36263
36497
|
}
|
|
36264
36498
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
36265
|
-
const resolved =
|
|
36499
|
+
const resolved = path31.resolve(cwd);
|
|
36266
36500
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
36267
36501
|
console.error("[file-index] Initial index build failed:", e);
|
|
36268
36502
|
});
|
|
@@ -36290,7 +36524,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
36290
36524
|
}
|
|
36291
36525
|
|
|
36292
36526
|
// src/connection/create-bridge-connection.ts
|
|
36293
|
-
import * as
|
|
36527
|
+
import * as path39 from "node:path";
|
|
36294
36528
|
|
|
36295
36529
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
36296
36530
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -36334,7 +36568,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
36334
36568
|
}
|
|
36335
36569
|
|
|
36336
36570
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
36337
|
-
import
|
|
36571
|
+
import fs27 from "node:fs";
|
|
36338
36572
|
|
|
36339
36573
|
// src/dev-servers/manager/forward-pipe.ts
|
|
36340
36574
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -36370,7 +36604,7 @@ function wireDevServerChildProcess(d) {
|
|
|
36370
36604
|
d.setPollInterval(void 0);
|
|
36371
36605
|
return;
|
|
36372
36606
|
}
|
|
36373
|
-
|
|
36607
|
+
fs27.readFile(d.mergedLogPath, (err, buf) => {
|
|
36374
36608
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
36375
36609
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
36376
36610
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -36408,7 +36642,7 @@ ${errTail}` : ""}`);
|
|
|
36408
36642
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
36409
36643
|
};
|
|
36410
36644
|
if (mergedPath) {
|
|
36411
|
-
|
|
36645
|
+
fs27.readFile(mergedPath, (err, buf) => {
|
|
36412
36646
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
36413
36647
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
36414
36648
|
if (chunk.length > 0) {
|
|
@@ -36510,13 +36744,13 @@ function parseDevServerDefs(servers) {
|
|
|
36510
36744
|
}
|
|
36511
36745
|
|
|
36512
36746
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
36513
|
-
import
|
|
36747
|
+
import fs28 from "node:fs";
|
|
36514
36748
|
function isSpawnEbadf(e) {
|
|
36515
36749
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
36516
36750
|
}
|
|
36517
36751
|
function rmDirQuiet(dir) {
|
|
36518
36752
|
try {
|
|
36519
|
-
|
|
36753
|
+
fs28.rmSync(dir, { recursive: true, force: true });
|
|
36520
36754
|
} catch {
|
|
36521
36755
|
}
|
|
36522
36756
|
}
|
|
@@ -36524,7 +36758,7 @@ var cachedDevNullReadFd;
|
|
|
36524
36758
|
function devNullReadFd() {
|
|
36525
36759
|
if (cachedDevNullReadFd === void 0) {
|
|
36526
36760
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
36527
|
-
cachedDevNullReadFd =
|
|
36761
|
+
cachedDevNullReadFd = fs28.openSync(devPath, "r");
|
|
36528
36762
|
}
|
|
36529
36763
|
return cachedDevNullReadFd;
|
|
36530
36764
|
}
|
|
@@ -36598,15 +36832,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
36598
36832
|
|
|
36599
36833
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
36600
36834
|
import { spawn as spawn6 } from "node:child_process";
|
|
36601
|
-
import
|
|
36835
|
+
import fs29 from "node:fs";
|
|
36602
36836
|
import { tmpdir } from "node:os";
|
|
36603
|
-
import
|
|
36837
|
+
import path32 from "node:path";
|
|
36604
36838
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
36605
|
-
const tmpRoot =
|
|
36606
|
-
const logPath =
|
|
36839
|
+
const tmpRoot = fs29.mkdtempSync(path32.join(tmpdir(), "ba-devsrv-log-"));
|
|
36840
|
+
const logPath = path32.join(tmpRoot, "combined.log");
|
|
36607
36841
|
let logFd;
|
|
36608
36842
|
try {
|
|
36609
|
-
logFd =
|
|
36843
|
+
logFd = fs29.openSync(logPath, "a");
|
|
36610
36844
|
} catch {
|
|
36611
36845
|
rmDirQuiet(tmpRoot);
|
|
36612
36846
|
return null;
|
|
@@ -36625,7 +36859,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36625
36859
|
} else {
|
|
36626
36860
|
proc = spawn6("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
36627
36861
|
}
|
|
36628
|
-
|
|
36862
|
+
fs29.closeSync(logFd);
|
|
36629
36863
|
return {
|
|
36630
36864
|
proc,
|
|
36631
36865
|
pipedStdoutStderr: true,
|
|
@@ -36634,7 +36868,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36634
36868
|
};
|
|
36635
36869
|
} catch (e) {
|
|
36636
36870
|
try {
|
|
36637
|
-
|
|
36871
|
+
fs29.closeSync(logFd);
|
|
36638
36872
|
} catch {
|
|
36639
36873
|
}
|
|
36640
36874
|
rmDirQuiet(tmpRoot);
|
|
@@ -36645,22 +36879,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
36645
36879
|
|
|
36646
36880
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
36647
36881
|
import { spawn as spawn7 } from "node:child_process";
|
|
36648
|
-
import
|
|
36882
|
+
import fs30 from "node:fs";
|
|
36649
36883
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
36650
|
-
import
|
|
36884
|
+
import path33 from "node:path";
|
|
36651
36885
|
function shSingleQuote(s) {
|
|
36652
36886
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
36653
36887
|
}
|
|
36654
36888
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
36655
|
-
const tmpRoot =
|
|
36656
|
-
const logPath =
|
|
36657
|
-
const innerPath =
|
|
36658
|
-
const runnerPath =
|
|
36889
|
+
const tmpRoot = fs30.mkdtempSync(path33.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36890
|
+
const logPath = path33.join(tmpRoot, "combined.log");
|
|
36891
|
+
const innerPath = path33.join(tmpRoot, "_cmd.sh");
|
|
36892
|
+
const runnerPath = path33.join(tmpRoot, "_run.sh");
|
|
36659
36893
|
try {
|
|
36660
|
-
|
|
36894
|
+
fs30.writeFileSync(innerPath, `#!/bin/sh
|
|
36661
36895
|
${command}
|
|
36662
36896
|
`);
|
|
36663
|
-
|
|
36897
|
+
fs30.writeFileSync(
|
|
36664
36898
|
runnerPath,
|
|
36665
36899
|
`#!/bin/sh
|
|
36666
36900
|
cd ${shSingleQuote(cwd)}
|
|
@@ -36686,13 +36920,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
36686
36920
|
}
|
|
36687
36921
|
}
|
|
36688
36922
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
36689
|
-
const tmpRoot =
|
|
36690
|
-
const logPath =
|
|
36691
|
-
const runnerPath =
|
|
36923
|
+
const tmpRoot = fs30.mkdtempSync(path33.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
36924
|
+
const logPath = path33.join(tmpRoot, "combined.log");
|
|
36925
|
+
const runnerPath = path33.join(tmpRoot, "_run.bat");
|
|
36692
36926
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
36693
36927
|
const com = process.env.ComSpec || "cmd.exe";
|
|
36694
36928
|
try {
|
|
36695
|
-
|
|
36929
|
+
fs30.writeFileSync(
|
|
36696
36930
|
runnerPath,
|
|
36697
36931
|
`@ECHO OFF\r
|
|
36698
36932
|
CD /D ${q(cwd)}\r
|
|
@@ -37629,30 +37863,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
37629
37863
|
}
|
|
37630
37864
|
|
|
37631
37865
|
// src/skills/discover-local-agent-skills.ts
|
|
37632
|
-
import
|
|
37633
|
-
import
|
|
37866
|
+
import fs31 from "node:fs";
|
|
37867
|
+
import path34 from "node:path";
|
|
37634
37868
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
37635
37869
|
function discoverLocalSkills(cwd) {
|
|
37636
37870
|
const out = [];
|
|
37637
37871
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
37638
37872
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
37639
|
-
const base =
|
|
37640
|
-
if (!
|
|
37873
|
+
const base = path34.join(cwd, rel);
|
|
37874
|
+
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
37641
37875
|
let entries = [];
|
|
37642
37876
|
try {
|
|
37643
|
-
entries =
|
|
37877
|
+
entries = fs31.readdirSync(base);
|
|
37644
37878
|
} catch {
|
|
37645
37879
|
continue;
|
|
37646
37880
|
}
|
|
37647
37881
|
for (const name of entries) {
|
|
37648
|
-
const dir =
|
|
37882
|
+
const dir = path34.join(base, name);
|
|
37649
37883
|
try {
|
|
37650
|
-
if (!
|
|
37884
|
+
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
37651
37885
|
} catch {
|
|
37652
37886
|
continue;
|
|
37653
37887
|
}
|
|
37654
|
-
const skillMd =
|
|
37655
|
-
if (!
|
|
37888
|
+
const skillMd = path34.join(dir, "SKILL.md");
|
|
37889
|
+
if (!fs31.existsSync(skillMd)) continue;
|
|
37656
37890
|
const key = `${rel}/${name}`;
|
|
37657
37891
|
if (seenKeys.has(key)) continue;
|
|
37658
37892
|
seenKeys.add(key);
|
|
@@ -37664,23 +37898,23 @@ function discoverLocalSkills(cwd) {
|
|
|
37664
37898
|
function discoverSkillLayoutRoots(cwd) {
|
|
37665
37899
|
const roots = [];
|
|
37666
37900
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
37667
|
-
const base =
|
|
37668
|
-
if (!
|
|
37901
|
+
const base = path34.join(cwd, rel);
|
|
37902
|
+
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
37669
37903
|
let entries = [];
|
|
37670
37904
|
try {
|
|
37671
|
-
entries =
|
|
37905
|
+
entries = fs31.readdirSync(base);
|
|
37672
37906
|
} catch {
|
|
37673
37907
|
continue;
|
|
37674
37908
|
}
|
|
37675
37909
|
const skills2 = [];
|
|
37676
37910
|
for (const name of entries) {
|
|
37677
|
-
const dir =
|
|
37911
|
+
const dir = path34.join(base, name);
|
|
37678
37912
|
try {
|
|
37679
|
-
if (!
|
|
37913
|
+
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
37680
37914
|
} catch {
|
|
37681
37915
|
continue;
|
|
37682
37916
|
}
|
|
37683
|
-
if (!
|
|
37917
|
+
if (!fs31.existsSync(path34.join(dir, "SKILL.md"))) continue;
|
|
37684
37918
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
37685
37919
|
skills2.push({ name, relPath });
|
|
37686
37920
|
}
|
|
@@ -37782,6 +38016,7 @@ function reportGitRepos(getWs, log2) {
|
|
|
37782
38016
|
var API_TO_BRIDGE_MESSAGE_TYPES = [
|
|
37783
38017
|
"auth_token",
|
|
37784
38018
|
"bridge_identified",
|
|
38019
|
+
"ha",
|
|
37785
38020
|
"dev_servers_config",
|
|
37786
38021
|
"server_control",
|
|
37787
38022
|
"agent_config",
|
|
@@ -37810,6 +38045,10 @@ function parseApiToBridgeMessage(data, log2) {
|
|
|
37810
38045
|
}
|
|
37811
38046
|
return null;
|
|
37812
38047
|
}
|
|
38048
|
+
if (t === "ha") {
|
|
38049
|
+
const s = data.s;
|
|
38050
|
+
if (typeof s !== "number" || !Number.isFinite(s)) return null;
|
|
38051
|
+
}
|
|
37813
38052
|
return data;
|
|
37814
38053
|
}
|
|
37815
38054
|
|
|
@@ -37850,6 +38089,13 @@ var handleBridgeIdentified = (msg, deps) => {
|
|
|
37850
38089
|
});
|
|
37851
38090
|
};
|
|
37852
38091
|
|
|
38092
|
+
// src/connection/heartbeat/ack.ts
|
|
38093
|
+
var handleBridgeHeartbeatAck = (msg, deps) => {
|
|
38094
|
+
const raw = msg.s;
|
|
38095
|
+
if (typeof raw !== "number" || !Number.isFinite(raw)) return;
|
|
38096
|
+
deps.onBridgeHeartbeatAck?.(Math.trunc(raw));
|
|
38097
|
+
};
|
|
38098
|
+
|
|
37853
38099
|
// src/agents/acp/from-bridge/handle-bridge-agent-config.ts
|
|
37854
38100
|
function handleBridgeAgentConfig(msg, { acpManager }) {
|
|
37855
38101
|
if (!Array.isArray(msg.agents) || msg.agents.length === 0) return;
|
|
@@ -37862,7 +38108,7 @@ var handleAgentConfigMessage = (msg, deps) => {
|
|
|
37862
38108
|
};
|
|
37863
38109
|
|
|
37864
38110
|
// src/prompt-turn-queue/runner.ts
|
|
37865
|
-
import
|
|
38111
|
+
import fs32 from "node:fs";
|
|
37866
38112
|
|
|
37867
38113
|
// src/prompt-turn-queue/client-report.ts
|
|
37868
38114
|
function sendPromptQueueClientReport(ws, queues) {
|
|
@@ -37871,32 +38117,6 @@ function sendPromptQueueClientReport(ws, queues) {
|
|
|
37871
38117
|
return true;
|
|
37872
38118
|
}
|
|
37873
38119
|
|
|
37874
|
-
// src/prompt-turn-queue/disk-store.ts
|
|
37875
|
-
import fs29 from "node:fs";
|
|
37876
|
-
|
|
37877
|
-
// src/prompt-turn-queue/paths.ts
|
|
37878
|
-
import crypto3 from "node:crypto";
|
|
37879
|
-
import fs28 from "node:fs";
|
|
37880
|
-
import path31 from "node:path";
|
|
37881
|
-
import os7 from "node:os";
|
|
37882
|
-
var QUEUE_KEY_HEX_64 = /^[a-f0-9]{64}$/i;
|
|
37883
|
-
function queueStateFileSlug(queueKey) {
|
|
37884
|
-
if (QUEUE_KEY_HEX_64.test(queueKey)) return queueKey.toLowerCase();
|
|
37885
|
-
return crypto3.createHash("sha256").update(queueKey, "utf8").digest("hex");
|
|
37886
|
-
}
|
|
37887
|
-
function getPromptQueuesDirectory() {
|
|
37888
|
-
const override = process.env.BUILDAMATON_PROMPT_QUEUES_DIR?.trim();
|
|
37889
|
-
if (override) return path31.resolve(override);
|
|
37890
|
-
return path31.join(os7.homedir(), ".buildautomaton", "queues");
|
|
37891
|
-
}
|
|
37892
|
-
function ensurePromptQueuesDirectory() {
|
|
37893
|
-
const dir = getPromptQueuesDirectory();
|
|
37894
|
-
if (!fs28.existsSync(dir)) fs28.mkdirSync(dir, { recursive: true });
|
|
37895
|
-
}
|
|
37896
|
-
function queueStateFilePath(queueKey) {
|
|
37897
|
-
return path31.join(getPromptQueuesDirectory(), `${queueStateFileSlug(queueKey)}.json`);
|
|
37898
|
-
}
|
|
37899
|
-
|
|
37900
38120
|
// src/prompt-turn-queue/disk-store.ts
|
|
37901
38121
|
var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
|
|
37902
38122
|
"queued",
|
|
@@ -37906,28 +38126,27 @@ var MERGEABLE_SERVER_STATES = /* @__PURE__ */ new Set([
|
|
|
37906
38126
|
"stopping",
|
|
37907
38127
|
"discarded"
|
|
37908
38128
|
]);
|
|
37909
|
-
function parsePersistedQueueFile(raw) {
|
|
37910
|
-
try {
|
|
37911
|
-
const o = JSON.parse(raw);
|
|
37912
|
-
const queueKey = typeof o.queueKey === "string" ? o.queueKey : typeof o.queueKeyHash === "string" ? o.queueKeyHash : null;
|
|
37913
|
-
if (!queueKey || typeof o.updatedAt !== "string" || !Array.isArray(o.turns)) return null;
|
|
37914
|
-
return { queueKey, updatedAt: o.updatedAt, turns: o.turns };
|
|
37915
|
-
} catch {
|
|
37916
|
-
return null;
|
|
37917
|
-
}
|
|
37918
|
-
}
|
|
37919
38129
|
function readPersistedQueue(queueKey) {
|
|
37920
|
-
const
|
|
38130
|
+
const db = getCliDatabase();
|
|
38131
|
+
const row = db.get("SELECT queue_key, updated_at, turns_json FROM prompt_queue WHERE queue_key = ?", [
|
|
38132
|
+
queueKey
|
|
38133
|
+
]);
|
|
38134
|
+
if (!row) return null;
|
|
37921
38135
|
try {
|
|
37922
|
-
|
|
38136
|
+
const turns = JSON.parse(row.turns_json);
|
|
38137
|
+
if (!Array.isArray(turns)) return null;
|
|
38138
|
+
return { queueKey: row.queue_key, updatedAt: row.updated_at, turns };
|
|
37923
38139
|
} catch {
|
|
37924
38140
|
return null;
|
|
37925
38141
|
}
|
|
37926
38142
|
}
|
|
37927
38143
|
function writePersistedQueue(file2) {
|
|
37928
|
-
|
|
37929
|
-
|
|
37930
|
-
|
|
38144
|
+
const db = getCliDatabase();
|
|
38145
|
+
db.run(
|
|
38146
|
+
`INSERT INTO prompt_queue (queue_key, updated_at, turns_json) VALUES (?, ?, ?)
|
|
38147
|
+
ON CONFLICT(queue_key) DO UPDATE SET updated_at = excluded.updated_at, turns_json = excluded.turns_json`,
|
|
38148
|
+
[file2.queueKey, file2.updatedAt, JSON.stringify(file2.turns)]
|
|
38149
|
+
);
|
|
37931
38150
|
}
|
|
37932
38151
|
function mergeServerQueueSnapshot(queueKey, serverTurns) {
|
|
37933
38152
|
const prev = readPersistedQueue(queueKey);
|
|
@@ -37985,7 +38204,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
37985
38204
|
const tid = typeof pl.snapshotRevertTurnId === "string" && pl.snapshotRevertTurnId.trim() !== "" ? pl.snapshotRevertTurnId.trim() : next.turnId;
|
|
37986
38205
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
37987
38206
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
37988
|
-
if (!
|
|
38207
|
+
if (!fs32.existsSync(file2)) {
|
|
37989
38208
|
deps.log(
|
|
37990
38209
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
37991
38210
|
);
|
|
@@ -38209,9 +38428,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
38209
38428
|
for (const item of raw) {
|
|
38210
38429
|
if (!item || typeof item !== "object") continue;
|
|
38211
38430
|
const o = item;
|
|
38212
|
-
const
|
|
38213
|
-
if (!
|
|
38214
|
-
const row = { path:
|
|
38431
|
+
const path41 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
38432
|
+
if (!path41) continue;
|
|
38433
|
+
const row = { path: path41 };
|
|
38215
38434
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
38216
38435
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
38217
38436
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -38428,8 +38647,8 @@ function randomSecret() {
|
|
|
38428
38647
|
}
|
|
38429
38648
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
38430
38649
|
}
|
|
38431
|
-
async function requestPreviewApi(port, secret, method,
|
|
38432
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
38650
|
+
async function requestPreviewApi(port, secret, method, path41, body) {
|
|
38651
|
+
const url2 = `http://127.0.0.1:${port}${path41}`;
|
|
38433
38652
|
const headers = {
|
|
38434
38653
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
38435
38654
|
"Content-Type": "application/json"
|
|
@@ -38441,7 +38660,7 @@ async function requestPreviewApi(port, secret, method, path37, body) {
|
|
|
38441
38660
|
});
|
|
38442
38661
|
const data = await res.json().catch(() => ({}));
|
|
38443
38662
|
if (!res.ok) {
|
|
38444
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
38663
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path41}: ${res.status}`);
|
|
38445
38664
|
}
|
|
38446
38665
|
return data;
|
|
38447
38666
|
}
|
|
@@ -38606,15 +38825,15 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
38606
38825
|
};
|
|
38607
38826
|
|
|
38608
38827
|
// src/files/list-dir.ts
|
|
38609
|
-
import
|
|
38610
|
-
import
|
|
38828
|
+
import fs33 from "node:fs";
|
|
38829
|
+
import path36 from "node:path";
|
|
38611
38830
|
|
|
38612
38831
|
// src/files/ensure-under-cwd.ts
|
|
38613
|
-
import
|
|
38832
|
+
import path35 from "node:path";
|
|
38614
38833
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
38615
|
-
const normalized =
|
|
38616
|
-
const resolved =
|
|
38617
|
-
if (!resolved.startsWith(cwd +
|
|
38834
|
+
const normalized = path35.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
38835
|
+
const resolved = path35.resolve(cwd, normalized);
|
|
38836
|
+
if (!resolved.startsWith(cwd + path35.sep) && resolved !== cwd) {
|
|
38618
38837
|
return null;
|
|
38619
38838
|
}
|
|
38620
38839
|
return resolved;
|
|
@@ -38628,7 +38847,7 @@ async function listDirAsync(relativePath) {
|
|
|
38628
38847
|
return { error: "Path is outside working directory" };
|
|
38629
38848
|
}
|
|
38630
38849
|
try {
|
|
38631
|
-
const names = await
|
|
38850
|
+
const names = await fs33.promises.readdir(resolved, { withFileTypes: true });
|
|
38632
38851
|
const visible = names.filter((d) => !d.name.startsWith("."));
|
|
38633
38852
|
const entries = [];
|
|
38634
38853
|
for (let i = 0; i < visible.length; i++) {
|
|
@@ -38636,12 +38855,12 @@ async function listDirAsync(relativePath) {
|
|
|
38636
38855
|
await yieldToEventLoop();
|
|
38637
38856
|
}
|
|
38638
38857
|
const d = visible[i];
|
|
38639
|
-
const entryPath =
|
|
38640
|
-
const fullPath =
|
|
38858
|
+
const entryPath = path36.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
38859
|
+
const fullPath = path36.join(resolved, d.name);
|
|
38641
38860
|
let isDir = d.isDirectory();
|
|
38642
38861
|
if (d.isSymbolicLink()) {
|
|
38643
38862
|
try {
|
|
38644
|
-
const targetStat = await
|
|
38863
|
+
const targetStat = await fs33.promises.stat(fullPath);
|
|
38645
38864
|
isDir = targetStat.isDirectory();
|
|
38646
38865
|
} catch {
|
|
38647
38866
|
isDir = false;
|
|
@@ -38666,25 +38885,25 @@ async function listDirAsync(relativePath) {
|
|
|
38666
38885
|
}
|
|
38667
38886
|
|
|
38668
38887
|
// src/files/read-file.ts
|
|
38669
|
-
import
|
|
38888
|
+
import fs34 from "node:fs";
|
|
38670
38889
|
import { StringDecoder } from "node:string_decoder";
|
|
38671
38890
|
function resolveFilePath(relativePath) {
|
|
38672
38891
|
const resolved = ensureUnderCwd(relativePath, getBridgeRoot());
|
|
38673
38892
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
38674
38893
|
let real;
|
|
38675
38894
|
try {
|
|
38676
|
-
real =
|
|
38895
|
+
real = fs34.realpathSync(resolved);
|
|
38677
38896
|
} catch {
|
|
38678
38897
|
real = resolved;
|
|
38679
38898
|
}
|
|
38680
|
-
const stat3 =
|
|
38899
|
+
const stat3 = fs34.statSync(real);
|
|
38681
38900
|
if (!stat3.isFile()) return { error: "Not a file" };
|
|
38682
38901
|
return real;
|
|
38683
38902
|
}
|
|
38684
38903
|
var LINE_CHUNK_SIZE = 64 * 1024;
|
|
38685
38904
|
function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
38686
|
-
const fileSize =
|
|
38687
|
-
const fd =
|
|
38905
|
+
const fileSize = fs34.statSync(filePath).size;
|
|
38906
|
+
const fd = fs34.openSync(filePath, "r");
|
|
38688
38907
|
const bufSize = 64 * 1024;
|
|
38689
38908
|
const buf = Buffer.alloc(bufSize);
|
|
38690
38909
|
const decoder = new StringDecoder("utf8");
|
|
@@ -38697,7 +38916,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
38697
38916
|
let line0Accum = "";
|
|
38698
38917
|
try {
|
|
38699
38918
|
let bytesRead;
|
|
38700
|
-
while (!done && (bytesRead =
|
|
38919
|
+
while (!done && (bytesRead = fs34.readSync(fd, buf, 0, bufSize, null)) > 0) {
|
|
38701
38920
|
const text = partial2 + decoder.write(buf.subarray(0, bytesRead));
|
|
38702
38921
|
partial2 = "";
|
|
38703
38922
|
let lineStart = 0;
|
|
@@ -38832,7 +39051,7 @@ function readFileRange(filePath, startLine, endLine, lineOffsetIn, lineChunkSize
|
|
|
38832
39051
|
}
|
|
38833
39052
|
return { content: resultLines.join("\n"), size: fileSize };
|
|
38834
39053
|
} finally {
|
|
38835
|
-
|
|
39054
|
+
fs34.closeSync(fd);
|
|
38836
39055
|
}
|
|
38837
39056
|
}
|
|
38838
39057
|
function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
@@ -38843,8 +39062,8 @@ function readFile3(relativePath, startLine, endLine, lineOffset, lineChunkSize =
|
|
|
38843
39062
|
if (hasRange) {
|
|
38844
39063
|
return readFileRange(result, startLine, endLine, lineOffset, lineChunkSize);
|
|
38845
39064
|
}
|
|
38846
|
-
const stat3 =
|
|
38847
|
-
const raw =
|
|
39065
|
+
const stat3 = fs34.statSync(result);
|
|
39066
|
+
const raw = fs34.readFileSync(result, "utf8");
|
|
38848
39067
|
const lines = raw.split(/\r?\n/);
|
|
38849
39068
|
return { content: raw, totalLines: lines.length, size: stat3.size };
|
|
38850
39069
|
} catch (err) {
|
|
@@ -38857,14 +39076,14 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
|
|
|
38857
39076
|
}
|
|
38858
39077
|
|
|
38859
39078
|
// src/files/handle-file-browser-search.ts
|
|
39079
|
+
import path37 from "node:path";
|
|
38860
39080
|
var SEARCH_LIMIT = 100;
|
|
38861
39081
|
function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
38862
39082
|
void (async () => {
|
|
38863
39083
|
await yieldToEventLoop();
|
|
38864
39084
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
38865
|
-
const cwd = getBridgeRoot();
|
|
38866
|
-
|
|
38867
|
-
if (index === null) {
|
|
39085
|
+
const cwd = path37.resolve(getBridgeRoot());
|
|
39086
|
+
if (!bridgeFileIndexIsPopulated(cwd)) {
|
|
38868
39087
|
const payload2 = {
|
|
38869
39088
|
type: "file_browser_search_response",
|
|
38870
39089
|
id: msg.id,
|
|
@@ -38874,7 +39093,7 @@ function handleFileBrowserSearch(msg, socket, e2ee) {
|
|
|
38874
39093
|
sendWsMessage(socket, e2ee ? e2ee.encryptFields(payload2, ["paths"]) : payload2);
|
|
38875
39094
|
return;
|
|
38876
39095
|
}
|
|
38877
|
-
const results = await
|
|
39096
|
+
const results = await searchBridgeFilePathsAsync(cwd, q, SEARCH_LIMIT);
|
|
38878
39097
|
const payload = {
|
|
38879
39098
|
type: "file_browser_search_response",
|
|
38880
39099
|
id: msg.id,
|
|
@@ -38962,8 +39181,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
38962
39181
|
}
|
|
38963
39182
|
|
|
38964
39183
|
// src/skills/install-remote-skills.ts
|
|
38965
|
-
import
|
|
38966
|
-
import
|
|
39184
|
+
import fs35 from "node:fs";
|
|
39185
|
+
import path38 from "node:path";
|
|
38967
39186
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
38968
39187
|
const installed2 = [];
|
|
38969
39188
|
if (!Array.isArray(items)) {
|
|
@@ -38974,15 +39193,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
38974
39193
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
38975
39194
|
continue;
|
|
38976
39195
|
}
|
|
38977
|
-
const skillDir =
|
|
39196
|
+
const skillDir = path38.join(cwd, targetDir, item.skillName);
|
|
38978
39197
|
for (const f of item.files) {
|
|
38979
39198
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
38980
|
-
const dest =
|
|
38981
|
-
|
|
39199
|
+
const dest = path38.join(skillDir, f.path);
|
|
39200
|
+
fs35.mkdirSync(path38.dirname(dest), { recursive: true });
|
|
38982
39201
|
if (f.text !== void 0) {
|
|
38983
|
-
|
|
39202
|
+
fs35.writeFileSync(dest, f.text, "utf8");
|
|
38984
39203
|
} else if (f.base64) {
|
|
38985
|
-
|
|
39204
|
+
fs35.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
38986
39205
|
}
|
|
38987
39206
|
}
|
|
38988
39207
|
installed2.push({
|
|
@@ -39132,7 +39351,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
39132
39351
|
};
|
|
39133
39352
|
|
|
39134
39353
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
39135
|
-
import * as
|
|
39354
|
+
import * as fs36 from "node:fs";
|
|
39136
39355
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
39137
39356
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
39138
39357
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -39144,7 +39363,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
39144
39363
|
if (!s) return;
|
|
39145
39364
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
39146
39365
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
39147
|
-
if (!
|
|
39366
|
+
if (!fs36.existsSync(file2)) {
|
|
39148
39367
|
sendWsMessage(s, {
|
|
39149
39368
|
type: "revert_turn_snapshot_result",
|
|
39150
39369
|
id,
|
|
@@ -39193,6 +39412,9 @@ function dispatchBridgeMessage(msg, deps) {
|
|
|
39193
39412
|
case "bridge_identified":
|
|
39194
39413
|
handleBridgeIdentified(msg, deps);
|
|
39195
39414
|
break;
|
|
39415
|
+
case "ha":
|
|
39416
|
+
handleBridgeHeartbeatAck(msg, deps);
|
|
39417
|
+
break;
|
|
39196
39418
|
case "dev_servers_config":
|
|
39197
39419
|
handleDevServersConfig(msg, deps);
|
|
39198
39420
|
break;
|
|
@@ -39248,9 +39470,17 @@ function dispatchBridgeMessage(msg, deps) {
|
|
|
39248
39470
|
}
|
|
39249
39471
|
|
|
39250
39472
|
// src/routing/handle-bridge-message.ts
|
|
39473
|
+
function normalizeInboundBridgeWebSocketJson(data) {
|
|
39474
|
+
if (data === null || typeof data !== "object" || Array.isArray(data)) return data;
|
|
39475
|
+
const o = data;
|
|
39476
|
+
if (o.t === "ha" && typeof o.s === "number" && Number.isFinite(o.s)) {
|
|
39477
|
+
return { type: "ha", s: Math.trunc(o.s) };
|
|
39478
|
+
}
|
|
39479
|
+
return data;
|
|
39480
|
+
}
|
|
39251
39481
|
function handleBridgeMessage(data, deps) {
|
|
39252
39482
|
if (!deps.getWs()) return;
|
|
39253
|
-
const msg = parseApiToBridgeMessage(data, deps.log);
|
|
39483
|
+
const msg = parseApiToBridgeMessage(normalizeInboundBridgeWebSocketJson(data), deps.log);
|
|
39254
39484
|
if (!msg) return;
|
|
39255
39485
|
setImmediate(() => {
|
|
39256
39486
|
dispatchBridgeMessage(msg, deps);
|
|
@@ -39298,7 +39528,8 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
39298
39528
|
persistTokens,
|
|
39299
39529
|
onAuthInvalid,
|
|
39300
39530
|
e2ee,
|
|
39301
|
-
identifyReportedPaths
|
|
39531
|
+
identifyReportedPaths,
|
|
39532
|
+
bridgeHeartbeat
|
|
39302
39533
|
} = params;
|
|
39303
39534
|
let authRefreshInFlight = false;
|
|
39304
39535
|
function handleOpen() {
|
|
@@ -39330,6 +39561,7 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
39330
39561
|
}
|
|
39331
39562
|
}
|
|
39332
39563
|
function handleClose(code, reason) {
|
|
39564
|
+
bridgeHeartbeat?.stop();
|
|
39333
39565
|
try {
|
|
39334
39566
|
const was = state.currentWs;
|
|
39335
39567
|
state.currentWs = null;
|
|
@@ -39364,6 +39596,7 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
39364
39596
|
} catch {
|
|
39365
39597
|
}
|
|
39366
39598
|
}
|
|
39599
|
+
bridgeHeartbeat?.stop();
|
|
39367
39600
|
const prev = state.currentWs;
|
|
39368
39601
|
if (prev) {
|
|
39369
39602
|
prev.removeAllListeners();
|
|
@@ -39455,11 +39688,98 @@ function createMainBridgeWebSocketLifecycle(params) {
|
|
|
39455
39688
|
return { connect };
|
|
39456
39689
|
}
|
|
39457
39690
|
|
|
39691
|
+
// src/connection/heartbeat/controller.ts
|
|
39692
|
+
function meanRttMs(samples) {
|
|
39693
|
+
if (samples.length === 0) return void 0;
|
|
39694
|
+
let sum = 0;
|
|
39695
|
+
for (const x of samples) sum += x;
|
|
39696
|
+
return sum / samples.length;
|
|
39697
|
+
}
|
|
39698
|
+
function createBridgeHeartbeatController(params) {
|
|
39699
|
+
const { getWs, log: log2 } = params;
|
|
39700
|
+
let interval = null;
|
|
39701
|
+
let seqCursor = -1;
|
|
39702
|
+
let awaitingSeq = null;
|
|
39703
|
+
let sentAtMs = 0;
|
|
39704
|
+
let missed = 0;
|
|
39705
|
+
const rttSamples = [];
|
|
39706
|
+
function clearTimer() {
|
|
39707
|
+
if (interval != null) {
|
|
39708
|
+
clearInterval(interval);
|
|
39709
|
+
interval = null;
|
|
39710
|
+
}
|
|
39711
|
+
}
|
|
39712
|
+
function nextSeq() {
|
|
39713
|
+
seqCursor = seqCursor >= BRIDGE_HEARTBEAT_SEQ_MAX ? 0 : seqCursor + 1;
|
|
39714
|
+
return seqCursor;
|
|
39715
|
+
}
|
|
39716
|
+
function tick() {
|
|
39717
|
+
const ws = getWs();
|
|
39718
|
+
if (!ws || ws.readyState !== wrapper_default.OPEN) return;
|
|
39719
|
+
if (awaitingSeq !== null) {
|
|
39720
|
+
missed++;
|
|
39721
|
+
if (missed >= BRIDGE_HEARTBEAT_MISSED_ACKS_BEFORE_RECONNECT) {
|
|
39722
|
+
try {
|
|
39723
|
+
log2("[Bridge service] Heartbeat missed repeatedly; reconnecting\u2026");
|
|
39724
|
+
} catch {
|
|
39725
|
+
}
|
|
39726
|
+
clearTimer();
|
|
39727
|
+
awaitingSeq = null;
|
|
39728
|
+
missed = 0;
|
|
39729
|
+
rttSamples.length = 0;
|
|
39730
|
+
safeCloseWebSocket(ws);
|
|
39731
|
+
return;
|
|
39732
|
+
}
|
|
39733
|
+
}
|
|
39734
|
+
const seq = nextSeq();
|
|
39735
|
+
const mean = meanRttMs(rttSamples);
|
|
39736
|
+
const payload = mean !== void 0 && Number.isFinite(mean) ? { t: "h", s: seq, m: Math.round(mean) } : { t: "h", s: seq };
|
|
39737
|
+
sendWsMessage(ws, payload);
|
|
39738
|
+
awaitingSeq = seq;
|
|
39739
|
+
sentAtMs = Date.now();
|
|
39740
|
+
}
|
|
39741
|
+
return {
|
|
39742
|
+
start() {
|
|
39743
|
+
clearTimer();
|
|
39744
|
+
awaitingSeq = null;
|
|
39745
|
+
missed = 0;
|
|
39746
|
+
seqCursor = -1;
|
|
39747
|
+
rttSamples.length = 0;
|
|
39748
|
+
interval = setInterval(tick, BRIDGE_APP_HEARTBEAT_INTERVAL_MS);
|
|
39749
|
+
},
|
|
39750
|
+
stop() {
|
|
39751
|
+
clearTimer();
|
|
39752
|
+
awaitingSeq = null;
|
|
39753
|
+
missed = 0;
|
|
39754
|
+
rttSamples.length = 0;
|
|
39755
|
+
},
|
|
39756
|
+
onAck(seq) {
|
|
39757
|
+
if (awaitingSeq === null) return;
|
|
39758
|
+
if (!Number.isFinite(seq)) return;
|
|
39759
|
+
const ack = Math.trunc(seq);
|
|
39760
|
+
const pending = awaitingSeq;
|
|
39761
|
+
if (ack < pending) return;
|
|
39762
|
+
if (ack === pending) {
|
|
39763
|
+
const rtt = Date.now() - sentAtMs;
|
|
39764
|
+
if (Number.isFinite(rtt) && rtt >= 0 && rtt < 6e5) {
|
|
39765
|
+
rttSamples.push(rtt);
|
|
39766
|
+
if (rttSamples.length > BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX) {
|
|
39767
|
+
rttSamples.splice(0, rttSamples.length - BRIDGE_HEARTBEAT_RTT_SAMPLE_MAX);
|
|
39768
|
+
}
|
|
39769
|
+
}
|
|
39770
|
+
}
|
|
39771
|
+
awaitingSeq = null;
|
|
39772
|
+
missed = 0;
|
|
39773
|
+
}
|
|
39774
|
+
};
|
|
39775
|
+
}
|
|
39776
|
+
|
|
39458
39777
|
// src/connection/create-bridge-connection.ts
|
|
39459
39778
|
async function createBridgeConnection(options) {
|
|
39460
39779
|
const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
|
|
39461
39780
|
const firehoseServerUrl = options.firehoseServerUrl ?? options.proxyServerUrl;
|
|
39462
39781
|
const logFn = options.log ?? log;
|
|
39782
|
+
getCliDatabase({ logLegacyMigration: logFn });
|
|
39463
39783
|
const tokens = {
|
|
39464
39784
|
accessToken: options.authToken,
|
|
39465
39785
|
refreshToken: options.refreshToken
|
|
@@ -39494,13 +39814,18 @@ async function createBridgeConnection(options) {
|
|
|
39494
39814
|
}
|
|
39495
39815
|
const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
|
|
39496
39816
|
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
|
|
39497
|
-
const
|
|
39817
|
+
const bridgeHeartbeat = createBridgeHeartbeatController({ getWs, log: logFn });
|
|
39818
|
+
const baseOnBridgeIdentified = createOnBridgeIdentified({
|
|
39498
39819
|
devServerManager,
|
|
39499
39820
|
firehoseServerUrl,
|
|
39500
39821
|
workspaceId,
|
|
39501
39822
|
state,
|
|
39502
39823
|
logFn
|
|
39503
39824
|
});
|
|
39825
|
+
const onBridgeIdentified = (msg) => {
|
|
39826
|
+
baseOnBridgeIdentified(msg);
|
|
39827
|
+
bridgeHeartbeat.start();
|
|
39828
|
+
};
|
|
39504
39829
|
const sendLocalSkillsReport = createSendLocalSkillsReport(getWs, logFn);
|
|
39505
39830
|
const reportAutoDetectedAgents = createReportAutoDetectedAgents(getWs, logFn);
|
|
39506
39831
|
const messageDeps = {
|
|
@@ -39509,6 +39834,9 @@ async function createBridgeConnection(options) {
|
|
|
39509
39834
|
acpManager,
|
|
39510
39835
|
sessionWorktreeManager,
|
|
39511
39836
|
onBridgeIdentified,
|
|
39837
|
+
onBridgeHeartbeatAck: (seq) => {
|
|
39838
|
+
bridgeHeartbeat.onAck(seq);
|
|
39839
|
+
},
|
|
39512
39840
|
sendLocalSkillsReport,
|
|
39513
39841
|
reportAutoDetectedAgents,
|
|
39514
39842
|
devServerManager,
|
|
@@ -39517,8 +39845,8 @@ async function createBridgeConnection(options) {
|
|
|
39517
39845
|
getCloudAccessToken: () => tokens.accessToken
|
|
39518
39846
|
};
|
|
39519
39847
|
const identifyReportedPaths = {
|
|
39520
|
-
bridgeRootPath:
|
|
39521
|
-
worktreesRootPath:
|
|
39848
|
+
bridgeRootPath: path39.resolve(getBridgeRoot()),
|
|
39849
|
+
worktreesRootPath: path39.resolve(worktreesRootPath)
|
|
39522
39850
|
};
|
|
39523
39851
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
39524
39852
|
state,
|
|
@@ -39532,13 +39860,15 @@ async function createBridgeConnection(options) {
|
|
|
39532
39860
|
persistTokens,
|
|
39533
39861
|
onAuthInvalid,
|
|
39534
39862
|
e2ee,
|
|
39535
|
-
identifyReportedPaths
|
|
39863
|
+
identifyReportedPaths,
|
|
39864
|
+
bridgeHeartbeat
|
|
39536
39865
|
});
|
|
39537
39866
|
connect();
|
|
39538
39867
|
const stopFileIndexWatcher = startFileIndexWatcher(getBridgeRoot());
|
|
39539
39868
|
return {
|
|
39540
39869
|
close: async () => {
|
|
39541
39870
|
stopFileIndexWatcher();
|
|
39871
|
+
bridgeHeartbeat.stop();
|
|
39542
39872
|
await closeBridgeConnection(state, acpManager, devServerManager, logFn);
|
|
39543
39873
|
}
|
|
39544
39874
|
};
|
|
@@ -39754,9 +40084,9 @@ async function runCliAction(program2, opts) {
|
|
|
39754
40084
|
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
39755
40085
|
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);
|
|
39756
40086
|
if (bridgeRootOpt) {
|
|
39757
|
-
const resolvedBridgeRoot =
|
|
40087
|
+
const resolvedBridgeRoot = path40.resolve(process.cwd(), bridgeRootOpt);
|
|
39758
40088
|
try {
|
|
39759
|
-
const st =
|
|
40089
|
+
const st = fs37.statSync(resolvedBridgeRoot);
|
|
39760
40090
|
if (!st.isDirectory()) {
|
|
39761
40091
|
console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
|
|
39762
40092
|
process.exit(1);
|
|
@@ -39776,7 +40106,7 @@ async function runCliAction(program2, opts) {
|
|
|
39776
40106
|
);
|
|
39777
40107
|
let worktreesRootPath;
|
|
39778
40108
|
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
39779
|
-
worktreesRootPath =
|
|
40109
|
+
worktreesRootPath = path40.resolve(opts.worktreesRoot.trim());
|
|
39780
40110
|
}
|
|
39781
40111
|
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
39782
40112
|
if (e2eCertificates) {
|