@buildautomaton/cli 0.1.38 → 0.1.39
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 +1183 -861
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1168 -846
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -973,7 +973,7 @@ 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
|
|
976
|
+
var path46 = __require("node:path");
|
|
977
977
|
var fs41 = __require("node:fs");
|
|
978
978
|
var process8 = __require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
@@ -1906,9 +1906,9 @@ 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 =
|
|
1909
|
+
const localBin = path46.resolve(baseDir, baseName);
|
|
1910
1910
|
if (fs41.existsSync(localBin)) return localBin;
|
|
1911
|
-
if (sourceExt.includes(
|
|
1911
|
+
if (sourceExt.includes(path46.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
1913
|
(ext) => fs41.existsSync(`${localBin}${ext}`)
|
|
1914
1914
|
);
|
|
@@ -1926,17 +1926,17 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
1929
|
-
executableDir =
|
|
1930
|
-
|
|
1929
|
+
executableDir = path46.resolve(
|
|
1930
|
+
path46.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 = path46.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path46.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(path46.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 = path46.basename(filename, path46.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(path47) {
|
|
2805
|
+
if (path47 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path47;
|
|
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: path46, errorMaps, issueData } = params;
|
|
7065
|
+
const fullPath = [...path46, ...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, path46, key) {
|
|
7374
7374
|
this._cachedPath = [];
|
|
7375
7375
|
this.parent = parent;
|
|
7376
7376
|
this.data = value;
|
|
7377
|
-
this._path =
|
|
7377
|
+
this._path = path46;
|
|
7378
7378
|
this._key = key;
|
|
7379
7379
|
}
|
|
7380
7380
|
get path() {
|
|
@@ -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(path46, isFile, isDirectory) {
|
|
11533
|
+
log2(`checking %s`, path46);
|
|
11534
11534
|
try {
|
|
11535
|
-
const stat3 = fs_1.statSync(
|
|
11535
|
+
const stat3 = fs_1.statSync(path46);
|
|
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(path46, type = exports.READABLE) {
|
|
11556
|
+
return check2(path46, (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, path46) {
|
|
11854
|
+
if (!path46)
|
|
11855
11855
|
return obj;
|
|
11856
|
-
return
|
|
11856
|
+
return path46.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(path46, 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(path46);
|
|
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, path46 = []) => {
|
|
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 = [...path46, ...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(path46) {
|
|
12339
12339
|
const segs = [];
|
|
12340
|
-
for (const seg of
|
|
12340
|
+
for (const seg of path46) {
|
|
12341
12341
|
if (typeof seg === "number")
|
|
12342
12342
|
segs.push(`[${seg}]`);
|
|
12343
12343
|
else if (typeof seg === "symbol")
|
|
@@ -24800,8 +24800,8 @@ var init_acp = __esm({
|
|
|
24800
24800
|
this.#requestHandler = requestHandler;
|
|
24801
24801
|
this.#notificationHandler = notificationHandler;
|
|
24802
24802
|
this.#stream = stream;
|
|
24803
|
-
this.#closedPromise = new Promise((
|
|
24804
|
-
this.#abortController.signal.addEventListener("abort", () =>
|
|
24803
|
+
this.#closedPromise = new Promise((resolve22) => {
|
|
24804
|
+
this.#abortController.signal.addEventListener("abort", () => resolve22());
|
|
24805
24805
|
});
|
|
24806
24806
|
this.#receive();
|
|
24807
24807
|
}
|
|
@@ -24950,8 +24950,8 @@ var init_acp = __esm({
|
|
|
24950
24950
|
}
|
|
24951
24951
|
async sendRequest(method, params) {
|
|
24952
24952
|
const id = this.#nextRequestId++;
|
|
24953
|
-
const responsePromise = new Promise((
|
|
24954
|
-
this.#pendingResponses.set(id, { resolve:
|
|
24953
|
+
const responsePromise = new Promise((resolve22, reject) => {
|
|
24954
|
+
this.#pendingResponses.set(id, { resolve: resolve22, reject });
|
|
24955
24955
|
});
|
|
24956
24956
|
await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
|
|
24957
24957
|
return responsePromise;
|
|
@@ -25064,7 +25064,7 @@ var {
|
|
|
25064
25064
|
} = import_index.default;
|
|
25065
25065
|
|
|
25066
25066
|
// src/cli-version.ts
|
|
25067
|
-
var CLI_VERSION = "0.1.
|
|
25067
|
+
var CLI_VERSION = "0.1.39".length > 0 ? "0.1.39" : "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";
|
|
@@ -25072,7 +25072,7 @@ var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
|
25072
25072
|
|
|
25073
25073
|
// src/cli/run-cli-action.ts
|
|
25074
25074
|
import * as fs40 from "node:fs";
|
|
25075
|
-
import * as
|
|
25075
|
+
import * as path45 from "node:path";
|
|
25076
25076
|
|
|
25077
25077
|
// src/cli-log-level.ts
|
|
25078
25078
|
var verbosity = "info";
|
|
@@ -26079,14 +26079,14 @@ var baseOpen = async (options) => {
|
|
|
26079
26079
|
}
|
|
26080
26080
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
26081
26081
|
if (options.wait) {
|
|
26082
|
-
return new Promise((
|
|
26082
|
+
return new Promise((resolve22, reject) => {
|
|
26083
26083
|
subprocess.once("error", reject);
|
|
26084
26084
|
subprocess.once("close", (exitCode) => {
|
|
26085
26085
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
26086
26086
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
26087
26087
|
return;
|
|
26088
26088
|
}
|
|
26089
|
-
|
|
26089
|
+
resolve22(subprocess);
|
|
26090
26090
|
});
|
|
26091
26091
|
});
|
|
26092
26092
|
}
|
|
@@ -26575,8 +26575,8 @@ function runPendingAuth(options) {
|
|
|
26575
26575
|
let hasOpenedBrowser = false;
|
|
26576
26576
|
let resolved = false;
|
|
26577
26577
|
let resolveAuth;
|
|
26578
|
-
const authPromise = new Promise((
|
|
26579
|
-
resolveAuth =
|
|
26578
|
+
const authPromise = new Promise((resolve22) => {
|
|
26579
|
+
resolveAuth = resolve22;
|
|
26580
26580
|
});
|
|
26581
26581
|
let reconnectAttempt = 0;
|
|
26582
26582
|
const signInQuiet = createEmptyReconnectQuietSlot();
|
|
@@ -26727,7 +26727,7 @@ import sqliteWasm from "node-sqlite3-wasm";
|
|
|
26727
26727
|
|
|
26728
26728
|
// src/runtime/yield-to-event-loop.ts
|
|
26729
26729
|
function yieldToEventLoop() {
|
|
26730
|
-
return new Promise((
|
|
26730
|
+
return new Promise((resolve22) => setImmediate(resolve22));
|
|
26731
26731
|
}
|
|
26732
26732
|
|
|
26733
26733
|
// src/sqlite/cli-sqlite-paths.ts
|
|
@@ -27570,9 +27570,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
27570
27570
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
27571
27571
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
27572
27572
|
if (!rawPath || !summary) continue;
|
|
27573
|
-
const
|
|
27574
|
-
if (!
|
|
27575
|
-
rows.push({ path:
|
|
27573
|
+
const path46 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
27574
|
+
if (!path46) continue;
|
|
27575
|
+
rows.push({ path: path46, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
27576
27576
|
}
|
|
27577
27577
|
return rows;
|
|
27578
27578
|
}
|
|
@@ -27866,8 +27866,8 @@ function pathspec(...paths) {
|
|
|
27866
27866
|
cache.set(key, paths);
|
|
27867
27867
|
return key;
|
|
27868
27868
|
}
|
|
27869
|
-
function isPathSpec(
|
|
27870
|
-
return
|
|
27869
|
+
function isPathSpec(path46) {
|
|
27870
|
+
return path46 instanceof String && cache.has(path46);
|
|
27871
27871
|
}
|
|
27872
27872
|
function toPaths(pathSpec) {
|
|
27873
27873
|
return cache.get(pathSpec) || [];
|
|
@@ -27956,8 +27956,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
27956
27956
|
function forEachLineWithContent(input, callback) {
|
|
27957
27957
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
27958
27958
|
}
|
|
27959
|
-
function folderExists(
|
|
27960
|
-
return (0, import_file_exists.exists)(
|
|
27959
|
+
function folderExists(path46) {
|
|
27960
|
+
return (0, import_file_exists.exists)(path46, import_file_exists.FOLDER);
|
|
27961
27961
|
}
|
|
27962
27962
|
function append(target, item) {
|
|
27963
27963
|
if (Array.isArray(target)) {
|
|
@@ -28361,8 +28361,8 @@ function checkIsRepoRootTask() {
|
|
|
28361
28361
|
commands,
|
|
28362
28362
|
format: "utf-8",
|
|
28363
28363
|
onError,
|
|
28364
|
-
parser(
|
|
28365
|
-
return /^\.(git)?$/.test(
|
|
28364
|
+
parser(path46) {
|
|
28365
|
+
return /^\.(git)?$/.test(path46.trim());
|
|
28366
28366
|
}
|
|
28367
28367
|
};
|
|
28368
28368
|
}
|
|
@@ -28796,11 +28796,11 @@ function parseGrep(grep) {
|
|
|
28796
28796
|
const paths = /* @__PURE__ */ new Set();
|
|
28797
28797
|
const results = {};
|
|
28798
28798
|
forEachLineWithContent(grep, (input) => {
|
|
28799
|
-
const [
|
|
28800
|
-
paths.add(
|
|
28801
|
-
(results[
|
|
28799
|
+
const [path46, line, preview] = input.split(NULL);
|
|
28800
|
+
paths.add(path46);
|
|
28801
|
+
(results[path46] = results[path46] || []).push({
|
|
28802
28802
|
line: asNumber(line),
|
|
28803
|
-
path:
|
|
28803
|
+
path: path46,
|
|
28804
28804
|
preview
|
|
28805
28805
|
});
|
|
28806
28806
|
});
|
|
@@ -29565,14 +29565,14 @@ var init_hash_object = __esm2({
|
|
|
29565
29565
|
init_task();
|
|
29566
29566
|
}
|
|
29567
29567
|
});
|
|
29568
|
-
function parseInit(bare,
|
|
29568
|
+
function parseInit(bare, path46, text) {
|
|
29569
29569
|
const response = String(text).trim();
|
|
29570
29570
|
let result;
|
|
29571
29571
|
if (result = initResponseRegex.exec(response)) {
|
|
29572
|
-
return new InitSummary(bare,
|
|
29572
|
+
return new InitSummary(bare, path46, false, result[1]);
|
|
29573
29573
|
}
|
|
29574
29574
|
if (result = reInitResponseRegex.exec(response)) {
|
|
29575
|
-
return new InitSummary(bare,
|
|
29575
|
+
return new InitSummary(bare, path46, true, result[1]);
|
|
29576
29576
|
}
|
|
29577
29577
|
let gitDir = "";
|
|
29578
29578
|
const tokens = response.split(" ");
|
|
@@ -29583,7 +29583,7 @@ function parseInit(bare, path43, text) {
|
|
|
29583
29583
|
break;
|
|
29584
29584
|
}
|
|
29585
29585
|
}
|
|
29586
|
-
return new InitSummary(bare,
|
|
29586
|
+
return new InitSummary(bare, path46, /^re/i.test(response), gitDir);
|
|
29587
29587
|
}
|
|
29588
29588
|
var InitSummary;
|
|
29589
29589
|
var initResponseRegex;
|
|
@@ -29592,9 +29592,9 @@ var init_InitSummary = __esm2({
|
|
|
29592
29592
|
"src/lib/responses/InitSummary.ts"() {
|
|
29593
29593
|
"use strict";
|
|
29594
29594
|
InitSummary = class {
|
|
29595
|
-
constructor(bare,
|
|
29595
|
+
constructor(bare, path46, existing, gitDir) {
|
|
29596
29596
|
this.bare = bare;
|
|
29597
|
-
this.path =
|
|
29597
|
+
this.path = path46;
|
|
29598
29598
|
this.existing = existing;
|
|
29599
29599
|
this.gitDir = gitDir;
|
|
29600
29600
|
}
|
|
@@ -29606,7 +29606,7 @@ var init_InitSummary = __esm2({
|
|
|
29606
29606
|
function hasBareCommand(command) {
|
|
29607
29607
|
return command.includes(bareCommand);
|
|
29608
29608
|
}
|
|
29609
|
-
function initTask(bare = false,
|
|
29609
|
+
function initTask(bare = false, path46, customArgs) {
|
|
29610
29610
|
const commands = ["init", ...customArgs];
|
|
29611
29611
|
if (bare && !hasBareCommand(commands)) {
|
|
29612
29612
|
commands.splice(1, 0, bareCommand);
|
|
@@ -29615,7 +29615,7 @@ function initTask(bare = false, path43, customArgs) {
|
|
|
29615
29615
|
commands,
|
|
29616
29616
|
format: "utf-8",
|
|
29617
29617
|
parser(text) {
|
|
29618
|
-
return parseInit(commands.includes("--bare"),
|
|
29618
|
+
return parseInit(commands.includes("--bare"), path46, text);
|
|
29619
29619
|
}
|
|
29620
29620
|
};
|
|
29621
29621
|
}
|
|
@@ -30431,12 +30431,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
30431
30431
|
"use strict";
|
|
30432
30432
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
30433
30433
|
FileStatusSummary = class {
|
|
30434
|
-
constructor(
|
|
30435
|
-
this.path =
|
|
30434
|
+
constructor(path46, index, working_dir) {
|
|
30435
|
+
this.path = path46;
|
|
30436
30436
|
this.index = index;
|
|
30437
30437
|
this.working_dir = working_dir;
|
|
30438
30438
|
if (index === "R" || working_dir === "R") {
|
|
30439
|
-
const detail = fromPathRegex.exec(
|
|
30439
|
+
const detail = fromPathRegex.exec(path46) || [null, path46, path46];
|
|
30440
30440
|
this.from = detail[2] || "";
|
|
30441
30441
|
this.path = detail[1] || "";
|
|
30442
30442
|
}
|
|
@@ -30467,14 +30467,14 @@ function splitLine(result, lineStr) {
|
|
|
30467
30467
|
default:
|
|
30468
30468
|
return;
|
|
30469
30469
|
}
|
|
30470
|
-
function data(index, workingDir,
|
|
30470
|
+
function data(index, workingDir, path46) {
|
|
30471
30471
|
const raw = `${index}${workingDir}`;
|
|
30472
30472
|
const handler = parsers6.get(raw);
|
|
30473
30473
|
if (handler) {
|
|
30474
|
-
handler(result,
|
|
30474
|
+
handler(result, path46);
|
|
30475
30475
|
}
|
|
30476
30476
|
if (raw !== "##" && raw !== "!!") {
|
|
30477
|
-
result.files.push(new FileStatusSummary(
|
|
30477
|
+
result.files.push(new FileStatusSummary(path46, index, workingDir));
|
|
30478
30478
|
}
|
|
30479
30479
|
}
|
|
30480
30480
|
}
|
|
@@ -30783,9 +30783,9 @@ var init_simple_git_api = __esm2({
|
|
|
30783
30783
|
next
|
|
30784
30784
|
);
|
|
30785
30785
|
}
|
|
30786
|
-
hashObject(
|
|
30786
|
+
hashObject(path46, write) {
|
|
30787
30787
|
return this._runTask(
|
|
30788
|
-
hashObjectTask(
|
|
30788
|
+
hashObjectTask(path46, write === true),
|
|
30789
30789
|
trailingFunctionArgument(arguments)
|
|
30790
30790
|
);
|
|
30791
30791
|
}
|
|
@@ -31138,8 +31138,8 @@ var init_branch = __esm2({
|
|
|
31138
31138
|
}
|
|
31139
31139
|
});
|
|
31140
31140
|
function toPath(input) {
|
|
31141
|
-
const
|
|
31142
|
-
return
|
|
31141
|
+
const path46 = input.trim().replace(/^["']|["']$/g, "");
|
|
31142
|
+
return path46 && normalize(path46);
|
|
31143
31143
|
}
|
|
31144
31144
|
var parseCheckIgnore;
|
|
31145
31145
|
var init_CheckIgnore = __esm2({
|
|
@@ -31453,8 +31453,8 @@ __export2(sub_module_exports, {
|
|
|
31453
31453
|
subModuleTask: () => subModuleTask,
|
|
31454
31454
|
updateSubModuleTask: () => updateSubModuleTask
|
|
31455
31455
|
});
|
|
31456
|
-
function addSubModuleTask(repo,
|
|
31457
|
-
return subModuleTask(["add", repo,
|
|
31456
|
+
function addSubModuleTask(repo, path46) {
|
|
31457
|
+
return subModuleTask(["add", repo, path46]);
|
|
31458
31458
|
}
|
|
31459
31459
|
function initSubModuleTask(customArgs) {
|
|
31460
31460
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -31787,8 +31787,8 @@ var require_git = __commonJS2({
|
|
|
31787
31787
|
}
|
|
31788
31788
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
31789
31789
|
};
|
|
31790
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
31791
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
31790
|
+
Git2.prototype.submoduleAdd = function(repo, path46, then) {
|
|
31791
|
+
return this._runTask(addSubModuleTask2(repo, path46), trailingFunctionArgument2(arguments));
|
|
31792
31792
|
};
|
|
31793
31793
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
31794
31794
|
return this._runTask(
|
|
@@ -32425,8 +32425,8 @@ async function runGitTask(fn) {
|
|
|
32425
32425
|
}
|
|
32426
32426
|
async function yieldToEventLoop2() {
|
|
32427
32427
|
throwIfGitShutdownRequested();
|
|
32428
|
-
await new Promise((
|
|
32429
|
-
setImmediate(
|
|
32428
|
+
await new Promise((resolve22) => {
|
|
32429
|
+
setImmediate(resolve22);
|
|
32430
32430
|
});
|
|
32431
32431
|
throwIfGitShutdownRequested();
|
|
32432
32432
|
}
|
|
@@ -32751,9 +32751,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32751
32751
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
32752
32752
|
async function putEncryptedChangeSummaryRows(params) {
|
|
32753
32753
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
32754
|
-
const entries = params.rows.map(({ path:
|
|
32754
|
+
const entries = params.rows.map(({ path: path46, summary }) => {
|
|
32755
32755
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
32756
|
-
return { path:
|
|
32756
|
+
return { path: path46, summary: JSON.stringify(enc) };
|
|
32757
32757
|
});
|
|
32758
32758
|
const res = await fetch(
|
|
32759
32759
|
`${base}/api/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -33756,11 +33756,11 @@ async function sendAcpPromptViaTransport(transport, ctx, sessionId, promptText,
|
|
|
33756
33756
|
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
33757
33757
|
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
33758
33758
|
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
33759
|
-
return new Promise((
|
|
33760
|
-
pending.set(requestId, { resolve:
|
|
33759
|
+
return new Promise((resolve22) => {
|
|
33760
|
+
pending.set(requestId, { resolve: resolve22, params: paramsRecord });
|
|
33761
33761
|
if (onRequest == null) {
|
|
33762
33762
|
pending.delete(requestId);
|
|
33763
|
-
|
|
33763
|
+
resolve22({ outcome: { outcome: "denied" } });
|
|
33764
33764
|
return;
|
|
33765
33765
|
}
|
|
33766
33766
|
try {
|
|
@@ -33826,7 +33826,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
33826
33826
|
child.once("close", (code, signal) => {
|
|
33827
33827
|
onAgentSubprocessExit?.({ code, signal });
|
|
33828
33828
|
});
|
|
33829
|
-
return new Promise((
|
|
33829
|
+
return new Promise((resolve22, reject) => {
|
|
33830
33830
|
let initSettled = false;
|
|
33831
33831
|
const settleReject = (err) => {
|
|
33832
33832
|
if (initSettled) return;
|
|
@@ -33840,7 +33840,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
33840
33840
|
const settleResolve = (handle) => {
|
|
33841
33841
|
if (initSettled) return;
|
|
33842
33842
|
initSettled = true;
|
|
33843
|
-
|
|
33843
|
+
resolve22(handle);
|
|
33844
33844
|
};
|
|
33845
33845
|
child.on("error", (err) => {
|
|
33846
33846
|
settleReject(new Error(formatSpawnError(err, command[0])));
|
|
@@ -34131,7 +34131,7 @@ async function createCursorAcpClient(options) {
|
|
|
34131
34131
|
logDebug,
|
|
34132
34132
|
getStderrText: () => stderrCapture.getText()
|
|
34133
34133
|
};
|
|
34134
|
-
return new Promise((
|
|
34134
|
+
return new Promise((resolve22, reject) => {
|
|
34135
34135
|
child.on("error", (err) => {
|
|
34136
34136
|
child.kill();
|
|
34137
34137
|
reject(new Error(formatSpawnError2(err, command[0])));
|
|
@@ -34307,7 +34307,7 @@ async function createCursorAcpClient(options) {
|
|
|
34307
34307
|
clientInfo: { name: "buildautomaton-cli", version: "0.1.0" }
|
|
34308
34308
|
});
|
|
34309
34309
|
const sessionId = established.sessionId;
|
|
34310
|
-
|
|
34310
|
+
resolve22({
|
|
34311
34311
|
sessionId,
|
|
34312
34312
|
async sendPrompt(prompt, options2) {
|
|
34313
34313
|
const imgs = options2?.images?.map((im) => ({ type: "image", mimeType: im.mimeType, data: im.dataBase64 }));
|
|
@@ -35553,266 +35553,65 @@ async function createAcpManager(options) {
|
|
|
35553
35553
|
};
|
|
35554
35554
|
}
|
|
35555
35555
|
|
|
35556
|
-
// src/
|
|
35557
|
-
|
|
35558
|
-
import os8 from "node:os";
|
|
35559
|
-
|
|
35560
|
-
// src/worktrees/prepare-new-session-worktrees.ts
|
|
35561
|
-
import * as fs18 from "node:fs";
|
|
35562
|
-
import * as path21 from "node:path";
|
|
35563
|
-
|
|
35564
|
-
// src/git/worktrees/worktree-add.ts
|
|
35565
|
-
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch) {
|
|
35566
|
-
const mainGit = cliSimpleGit(mainRepoPath);
|
|
35567
|
-
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
|
|
35568
|
-
}
|
|
35569
|
-
|
|
35570
|
-
// src/worktrees/worktree-layout-file.ts
|
|
35571
|
-
import * as fs17 from "node:fs";
|
|
35572
|
-
import * as path20 from "node:path";
|
|
35573
|
-
import os7 from "node:os";
|
|
35574
|
-
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
35575
|
-
function defaultWorktreeLayoutPath() {
|
|
35576
|
-
return path20.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
35577
|
-
}
|
|
35578
|
-
function normalizeLoadedLayout(raw) {
|
|
35579
|
-
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
35580
|
-
const j = raw;
|
|
35581
|
-
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
35582
|
-
}
|
|
35583
|
-
return { launcherCwds: [] };
|
|
35584
|
-
}
|
|
35585
|
-
function loadWorktreeLayout() {
|
|
35586
|
-
try {
|
|
35587
|
-
const p = defaultWorktreeLayoutPath();
|
|
35588
|
-
if (!fs17.existsSync(p)) return { launcherCwds: [] };
|
|
35589
|
-
const raw = JSON.parse(fs17.readFileSync(p, "utf8"));
|
|
35590
|
-
return normalizeLoadedLayout(raw);
|
|
35591
|
-
} catch {
|
|
35592
|
-
return { launcherCwds: [] };
|
|
35593
|
-
}
|
|
35594
|
-
}
|
|
35595
|
-
function saveWorktreeLayout(layout) {
|
|
35596
|
-
try {
|
|
35597
|
-
const dir = path20.dirname(defaultWorktreeLayoutPath());
|
|
35598
|
-
fs17.mkdirSync(dir, { recursive: true });
|
|
35599
|
-
fs17.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
35600
|
-
} catch {
|
|
35601
|
-
}
|
|
35602
|
-
}
|
|
35603
|
-
function baseNameSafe(pathString) {
|
|
35604
|
-
return path20.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
35605
|
-
}
|
|
35606
|
-
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
35607
|
-
const norm = path20.resolve(bridgeRootPath2);
|
|
35608
|
-
const existing = layout.launcherCwds.find((e) => path20.resolve(e.absolutePath) === norm);
|
|
35609
|
-
return existing?.dirName;
|
|
35610
|
-
}
|
|
35611
|
-
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
35612
|
-
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
35613
|
-
if (existing) return existing;
|
|
35614
|
-
const norm = path20.resolve(bridgeRootPath2);
|
|
35615
|
-
const base = baseNameSafe(norm);
|
|
35616
|
-
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
35617
|
-
let name = base;
|
|
35618
|
-
let n = 2;
|
|
35619
|
-
while (used.has(name)) {
|
|
35620
|
-
name = `${base}-${n}`;
|
|
35621
|
-
n += 1;
|
|
35622
|
-
}
|
|
35623
|
-
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
35624
|
-
saveWorktreeLayout(layout);
|
|
35625
|
-
return name;
|
|
35626
|
-
}
|
|
35627
|
-
|
|
35628
|
-
// src/worktrees/prepare-new-session-worktrees.ts
|
|
35629
|
-
async function prepareNewSessionWorktrees(options) {
|
|
35630
|
-
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2 } = options;
|
|
35631
|
-
const bridgeResolved = path21.resolve(bridgeRoot);
|
|
35632
|
-
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
35633
|
-
const bridgeKeyDir = path21.join(worktreesRootPath, cwdKey);
|
|
35634
|
-
const sessionDir = path21.join(bridgeKeyDir, sessionId);
|
|
35635
|
-
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
35636
|
-
if (repos.length === 0) {
|
|
35637
|
-
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
35638
|
-
return null;
|
|
35639
|
-
}
|
|
35640
|
-
const branch = `session-${sessionId}`;
|
|
35641
|
-
const worktreePaths = [];
|
|
35642
|
-
fs18.mkdirSync(sessionDir, { recursive: true });
|
|
35643
|
-
for (const repo of repos) {
|
|
35644
|
-
let rel = path21.relative(bridgeResolved, repo.absolutePath);
|
|
35645
|
-
if (rel.startsWith("..") || path21.isAbsolute(rel)) continue;
|
|
35646
|
-
const relNorm = rel === "" ? "." : rel;
|
|
35647
|
-
const wtPath = relNorm === "." ? sessionDir : path21.join(sessionDir, relNorm);
|
|
35648
|
-
if (relNorm !== ".") {
|
|
35649
|
-
fs18.mkdirSync(path21.dirname(wtPath), { recursive: true });
|
|
35650
|
-
}
|
|
35651
|
-
try {
|
|
35652
|
-
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch);
|
|
35653
|
-
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}).`);
|
|
35654
|
-
worktreePaths.push(wtPath);
|
|
35655
|
-
} catch (e) {
|
|
35656
|
-
log2(
|
|
35657
|
-
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
35658
|
-
);
|
|
35659
|
-
}
|
|
35660
|
-
}
|
|
35661
|
-
if (worktreePaths.length === 0) return null;
|
|
35662
|
-
return {
|
|
35663
|
-
worktreePaths,
|
|
35664
|
-
sessionParentPath: sessionDir,
|
|
35665
|
-
workingTreeRelRoot: sessionDir
|
|
35666
|
-
};
|
|
35667
|
-
}
|
|
35668
|
-
|
|
35669
|
-
// src/git/branches/rename-branch.ts
|
|
35670
|
-
async function gitRenameCurrentBranch(repoDir, newName) {
|
|
35671
|
-
const g = cliSimpleGit(repoDir);
|
|
35672
|
-
await g.raw(["branch", "-m", newName]);
|
|
35673
|
-
}
|
|
35674
|
-
|
|
35675
|
-
// src/worktrees/rename-session-worktree-branches.ts
|
|
35676
|
-
async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
35677
|
-
const safe = newBranch.replace(/[^a-zA-Z0-9/_-]+/g, "-").slice(0, 80) || "session-branch";
|
|
35678
|
-
for (const wt of paths) {
|
|
35679
|
-
try {
|
|
35680
|
-
await gitRenameCurrentBranch(wt, safe);
|
|
35681
|
-
log2(`[worktrees] Renamed branch in ${wt} \u2192 ${safe}`);
|
|
35682
|
-
} catch (e) {
|
|
35683
|
-
log2(
|
|
35684
|
-
`[worktrees] Branch rename failed in ${wt}: ${e instanceof Error ? e.message : String(e)}`
|
|
35685
|
-
);
|
|
35686
|
-
}
|
|
35687
|
-
}
|
|
35688
|
-
}
|
|
35689
|
-
|
|
35690
|
-
// src/worktrees/remove-session-worktrees.ts
|
|
35691
|
-
import * as fs21 from "node:fs";
|
|
35692
|
-
|
|
35693
|
-
// src/git/worktrees/worktree-remove.ts
|
|
35694
|
-
import * as fs20 from "node:fs";
|
|
35695
|
-
|
|
35696
|
-
// src/git/worktrees/resolve-main-repo-from-git-file.ts
|
|
35697
|
-
import * as fs19 from "node:fs";
|
|
35698
|
-
import * as path22 from "node:path";
|
|
35699
|
-
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
35700
|
-
const gitDirFile = path22.join(wt, ".git");
|
|
35701
|
-
if (!fs19.existsSync(gitDirFile) || !fs19.statSync(gitDirFile).isFile()) return "";
|
|
35702
|
-
const first2 = fs19.readFileSync(gitDirFile, "utf8").trim();
|
|
35703
|
-
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
35704
|
-
if (!m) return "";
|
|
35705
|
-
const gitWorktreePath = path22.resolve(wt, m[1].trim());
|
|
35706
|
-
const gitDir = path22.dirname(path22.dirname(gitWorktreePath));
|
|
35707
|
-
return path22.dirname(gitDir);
|
|
35708
|
-
}
|
|
35556
|
+
// src/git/changes/types.ts
|
|
35557
|
+
var MAX_PATCH_CHARS = 35e4;
|
|
35709
35558
|
|
|
35710
|
-
// src/git/
|
|
35711
|
-
|
|
35712
|
-
const
|
|
35713
|
-
|
|
35714
|
-
|
|
35715
|
-
} else {
|
|
35716
|
-
fs20.rmSync(worktreePath, { recursive: true, force: true });
|
|
35717
|
-
}
|
|
35559
|
+
// src/git/changes/lib/repo-format.ts
|
|
35560
|
+
function posixJoinDirFile(dir, file2) {
|
|
35561
|
+
const d = dir === "." || dir === "" ? "" : dir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
35562
|
+
const f = file2.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
35563
|
+
return d ? `${d}/${f}` : f;
|
|
35718
35564
|
}
|
|
35719
|
-
|
|
35720
|
-
|
|
35721
|
-
|
|
35722
|
-
for (const wt of paths) {
|
|
35565
|
+
function formatRepoShortTitle(remoteUrl, repoRelPath) {
|
|
35566
|
+
const u = remoteUrl.trim();
|
|
35567
|
+
if (u) {
|
|
35723
35568
|
try {
|
|
35724
|
-
|
|
35725
|
-
|
|
35726
|
-
|
|
35727
|
-
|
|
35728
|
-
|
|
35729
|
-
|
|
35730
|
-
}
|
|
35569
|
+
if (u.startsWith("git@")) {
|
|
35570
|
+
const colon = u.indexOf(":");
|
|
35571
|
+
if (colon > 0) {
|
|
35572
|
+
const pathPart = u.slice(colon + 1).replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
35573
|
+
if (pathPart.includes("/")) return pathPart;
|
|
35574
|
+
}
|
|
35575
|
+
} else {
|
|
35576
|
+
const parsed = new URL(u);
|
|
35577
|
+
const p = parsed.pathname.replace(/^\//, "").replace(/\.git$/i, "");
|
|
35578
|
+
const parts = p.split("/").filter(Boolean);
|
|
35579
|
+
if (parts.length >= 2) {
|
|
35580
|
+
return `${parts[parts.length - 2]}/${parts[parts.length - 1]}`;
|
|
35581
|
+
}
|
|
35582
|
+
if (parts.length === 1) return parts[0];
|
|
35731
35583
|
}
|
|
35584
|
+
} catch {
|
|
35732
35585
|
}
|
|
35733
35586
|
}
|
|
35734
|
-
|
|
35735
|
-
|
|
35736
|
-
|
|
35737
|
-
|
|
35738
|
-
const m = /* @__PURE__ */ new Map();
|
|
35739
|
-
for (const line of lines) {
|
|
35740
|
-
if (!line.trim()) continue;
|
|
35741
|
-
const tabParts = line.split(" ");
|
|
35742
|
-
if (tabParts.length < 2) continue;
|
|
35743
|
-
const status = tabParts[0].trim();
|
|
35744
|
-
const code = status[0];
|
|
35745
|
-
if (code === "A") {
|
|
35746
|
-
m.set(tabParts[tabParts.length - 1], "added");
|
|
35747
|
-
} else if (code === "D") {
|
|
35748
|
-
m.set(tabParts[tabParts.length - 1], "removed");
|
|
35749
|
-
} else if (code === "R" || code === "C") {
|
|
35750
|
-
if (tabParts.length >= 3) m.set(tabParts[tabParts.length - 1], "modified");
|
|
35751
|
-
} else if (code === "M" || code === "U" || code === "T") {
|
|
35752
|
-
m.set(tabParts[tabParts.length - 1], "modified");
|
|
35753
|
-
}
|
|
35754
|
-
}
|
|
35755
|
-
return m;
|
|
35756
|
-
}
|
|
35757
|
-
function parseNumstatFirstLine(line) {
|
|
35758
|
-
const parts = line.split(" ");
|
|
35759
|
-
if (parts.length < 3) return null;
|
|
35760
|
-
const [a, d] = parts;
|
|
35761
|
-
const additions = a === "-" ? 0 : parseInt(String(a), 10) || 0;
|
|
35762
|
-
const deletions = d === "-" ? 0 : parseInt(String(d), 10) || 0;
|
|
35763
|
-
return { additions, deletions };
|
|
35764
|
-
}
|
|
35765
|
-
function parseNumstat(lines) {
|
|
35766
|
-
const m = /* @__PURE__ */ new Map();
|
|
35767
|
-
for (const line of lines) {
|
|
35768
|
-
if (!line.trim()) continue;
|
|
35769
|
-
const parts = line.split(" ");
|
|
35770
|
-
if (parts.length < 3) continue;
|
|
35771
|
-
const [a, d, p] = parts;
|
|
35772
|
-
const additions = a === "-" ? 0 : parseInt(String(a), 10) || 0;
|
|
35773
|
-
const deletions = d === "-" ? 0 : parseInt(String(d), 10) || 0;
|
|
35774
|
-
m.set(p, { additions, deletions });
|
|
35587
|
+
if (repoRelPath && repoRelPath !== ".") {
|
|
35588
|
+
const segments = repoRelPath.split("/").filter(Boolean);
|
|
35589
|
+
const last2 = segments[segments.length - 1];
|
|
35590
|
+
if (last2) return last2;
|
|
35775
35591
|
}
|
|
35776
|
-
return
|
|
35592
|
+
return "Repository";
|
|
35777
35593
|
}
|
|
35778
|
-
|
|
35779
|
-
const
|
|
35594
|
+
function formatRemoteDisplayLabel(remoteUrl) {
|
|
35595
|
+
const u = remoteUrl.trim();
|
|
35596
|
+
if (!u) return "";
|
|
35597
|
+
let hostPath = u;
|
|
35780
35598
|
try {
|
|
35781
|
-
|
|
35782
|
-
|
|
35783
|
-
|
|
35599
|
+
if (u.startsWith("git@")) {
|
|
35600
|
+
const rest = u.slice("git@".length);
|
|
35601
|
+
const slash = rest.indexOf(":");
|
|
35602
|
+
if (slash > 0) hostPath = `${rest.slice(0, slash)}/${rest.slice(slash + 1)}`;
|
|
35603
|
+
} else {
|
|
35604
|
+
const parsed = new URL(u);
|
|
35605
|
+
hostPath = `${parsed.hostname}${parsed.pathname}`.replace(/\/\.git$/i, "").replace(/\.git$/i, "");
|
|
35606
|
+
}
|
|
35784
35607
|
} catch {
|
|
35785
|
-
|
|
35786
|
-
}
|
|
35787
|
-
}
|
|
35788
|
-
|
|
35789
|
-
// src/git/changes/lib/working-tree-changed-path-count.ts
|
|
35790
|
-
function workingTreeChangedPathCount(nameStatusLines, numstatLines, untrackedLines) {
|
|
35791
|
-
const kindByPath = parseNameStatusLines(nameStatusLines);
|
|
35792
|
-
const numByPath = parseNumstat(numstatLines);
|
|
35793
|
-
const paths = /* @__PURE__ */ new Set([...kindByPath.keys(), ...numByPath.keys()]);
|
|
35794
|
-
for (const p of untrackedLines.map((s) => s.trim()).filter(Boolean)) {
|
|
35795
|
-
paths.add(p);
|
|
35608
|
+
hostPath = u.replace(/^https?:\/\//i, "").replace(/\.git$/i, "");
|
|
35796
35609
|
}
|
|
35797
|
-
return
|
|
35610
|
+
return `origin \xB7 ${hostPath}`;
|
|
35798
35611
|
}
|
|
35799
35612
|
|
|
35800
|
-
// src/git/changes/
|
|
35801
|
-
|
|
35802
|
-
return runGitTask(async () => {
|
|
35803
|
-
const g = cliSimpleGit(repoGitCwd);
|
|
35804
|
-
const [nameStatusRaw, numstatRaw, untrackedRaw] = await Promise.all([
|
|
35805
|
-
g.raw(["diff", "--name-status", "HEAD"]).catch(() => ""),
|
|
35806
|
-
g.raw(["diff", "HEAD", "--numstat"]).catch(() => ""),
|
|
35807
|
-
g.raw(["ls-files", "--others", "--exclude-standard"]).catch(() => "")
|
|
35808
|
-
]);
|
|
35809
|
-
return workingTreeChangedPathCount(
|
|
35810
|
-
String(nameStatusRaw).split("\n"),
|
|
35811
|
-
String(numstatRaw).split("\n"),
|
|
35812
|
-
String(untrackedRaw).split("\n")
|
|
35813
|
-
);
|
|
35814
|
-
});
|
|
35815
|
-
}
|
|
35613
|
+
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
35614
|
+
import * as path21 from "node:path";
|
|
35816
35615
|
|
|
35817
35616
|
// src/git/commits/resolve-remote-tracking.ts
|
|
35818
35617
|
async function tryConfigGet(g, key) {
|
|
@@ -35912,96 +35711,6 @@ async function commitsAheadOfRemoteTracking(repoDir) {
|
|
|
35912
35711
|
}
|
|
35913
35712
|
}
|
|
35914
35713
|
|
|
35915
|
-
// src/git/status/working-tree-status.ts
|
|
35916
|
-
async function getRepoWorkingTreeStatus(repoDir) {
|
|
35917
|
-
return runGitTask(async () => {
|
|
35918
|
-
const uncommittedFileCount = await countWorkingTreeChangedFilesForRepo(repoDir);
|
|
35919
|
-
const hasUncommittedChanges = uncommittedFileCount > 0;
|
|
35920
|
-
const ahead = await commitsAheadOfRemoteTracking(repoDir);
|
|
35921
|
-
return { hasUncommittedChanges, hasUnpushedCommits: ahead > 0, uncommittedFileCount };
|
|
35922
|
-
});
|
|
35923
|
-
}
|
|
35924
|
-
async function aggregateSessionPathsWorkingTreeStatus(paths) {
|
|
35925
|
-
let hasUncommittedChanges = false;
|
|
35926
|
-
let hasUnpushedCommits = false;
|
|
35927
|
-
let uncommittedFileCount = 0;
|
|
35928
|
-
await forEachWithGitYield(paths, async (p) => {
|
|
35929
|
-
const s = await getRepoWorkingTreeStatus(p);
|
|
35930
|
-
uncommittedFileCount += s.uncommittedFileCount;
|
|
35931
|
-
if (s.hasUncommittedChanges) hasUncommittedChanges = true;
|
|
35932
|
-
if (s.hasUnpushedCommits) hasUnpushedCommits = true;
|
|
35933
|
-
});
|
|
35934
|
-
return { hasUncommittedChanges, hasUnpushedCommits, uncommittedFileCount };
|
|
35935
|
-
}
|
|
35936
|
-
async function pushAheadOfUpstreamForPaths(paths) {
|
|
35937
|
-
await forEachWithGitYield(paths, async (p) => {
|
|
35938
|
-
const g = cliSimpleGit(p);
|
|
35939
|
-
const ahead = await commitsAheadOfRemoteTracking(p);
|
|
35940
|
-
if (ahead <= 0) return;
|
|
35941
|
-
await g.push();
|
|
35942
|
-
});
|
|
35943
|
-
}
|
|
35944
|
-
|
|
35945
|
-
// src/git/changes/types.ts
|
|
35946
|
-
var MAX_PATCH_CHARS = 35e4;
|
|
35947
|
-
|
|
35948
|
-
// src/git/changes/lib/repo-format.ts
|
|
35949
|
-
function posixJoinDirFile(dir, file2) {
|
|
35950
|
-
const d = dir === "." || dir === "" ? "" : dir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
35951
|
-
const f = file2.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
35952
|
-
return d ? `${d}/${f}` : f;
|
|
35953
|
-
}
|
|
35954
|
-
function formatRepoShortTitle(remoteUrl, repoRelPath) {
|
|
35955
|
-
const u = remoteUrl.trim();
|
|
35956
|
-
if (u) {
|
|
35957
|
-
try {
|
|
35958
|
-
if (u.startsWith("git@")) {
|
|
35959
|
-
const colon = u.indexOf(":");
|
|
35960
|
-
if (colon > 0) {
|
|
35961
|
-
const pathPart = u.slice(colon + 1).replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
35962
|
-
if (pathPart.includes("/")) return pathPart;
|
|
35963
|
-
}
|
|
35964
|
-
} else {
|
|
35965
|
-
const parsed = new URL(u);
|
|
35966
|
-
const p = parsed.pathname.replace(/^\//, "").replace(/\.git$/i, "");
|
|
35967
|
-
const parts = p.split("/").filter(Boolean);
|
|
35968
|
-
if (parts.length >= 2) {
|
|
35969
|
-
return `${parts[parts.length - 2]}/${parts[parts.length - 1]}`;
|
|
35970
|
-
}
|
|
35971
|
-
if (parts.length === 1) return parts[0];
|
|
35972
|
-
}
|
|
35973
|
-
} catch {
|
|
35974
|
-
}
|
|
35975
|
-
}
|
|
35976
|
-
if (repoRelPath && repoRelPath !== ".") {
|
|
35977
|
-
const segments = repoRelPath.split("/").filter(Boolean);
|
|
35978
|
-
const last2 = segments[segments.length - 1];
|
|
35979
|
-
if (last2) return last2;
|
|
35980
|
-
}
|
|
35981
|
-
return "Repository";
|
|
35982
|
-
}
|
|
35983
|
-
function formatRemoteDisplayLabel(remoteUrl) {
|
|
35984
|
-
const u = remoteUrl.trim();
|
|
35985
|
-
if (!u) return "";
|
|
35986
|
-
let hostPath = u;
|
|
35987
|
-
try {
|
|
35988
|
-
if (u.startsWith("git@")) {
|
|
35989
|
-
const rest = u.slice("git@".length);
|
|
35990
|
-
const slash = rest.indexOf(":");
|
|
35991
|
-
if (slash > 0) hostPath = `${rest.slice(0, slash)}/${rest.slice(slash + 1)}`;
|
|
35992
|
-
} else {
|
|
35993
|
-
const parsed = new URL(u);
|
|
35994
|
-
hostPath = `${parsed.hostname}${parsed.pathname}`.replace(/\/\.git$/i, "").replace(/\.git$/i, "");
|
|
35995
|
-
}
|
|
35996
|
-
} catch {
|
|
35997
|
-
hostPath = u.replace(/^https?:\/\//i, "").replace(/\.git$/i, "");
|
|
35998
|
-
}
|
|
35999
|
-
return `origin \xB7 ${hostPath}`;
|
|
36000
|
-
}
|
|
36001
|
-
|
|
36002
|
-
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
36003
|
-
import * as path24 from "node:path";
|
|
36004
|
-
|
|
36005
35714
|
// src/git/commits/lib/parse-log-lines.ts
|
|
36006
35715
|
function parseLogShaDateSubjectLines(raw) {
|
|
36007
35716
|
const out = [];
|
|
@@ -36072,6 +35781,59 @@ async function listRecentCommits(repoDir, limitInput) {
|
|
|
36072
35781
|
}
|
|
36073
35782
|
}
|
|
36074
35783
|
|
|
35784
|
+
// src/git/changes/lib/parse-git-status.ts
|
|
35785
|
+
function parseNameStatusLines(lines) {
|
|
35786
|
+
const m = /* @__PURE__ */ new Map();
|
|
35787
|
+
for (const line of lines) {
|
|
35788
|
+
if (!line.trim()) continue;
|
|
35789
|
+
const tabParts = line.split(" ");
|
|
35790
|
+
if (tabParts.length < 2) continue;
|
|
35791
|
+
const status = tabParts[0].trim();
|
|
35792
|
+
const code = status[0];
|
|
35793
|
+
if (code === "A") {
|
|
35794
|
+
m.set(tabParts[tabParts.length - 1], "added");
|
|
35795
|
+
} else if (code === "D") {
|
|
35796
|
+
m.set(tabParts[tabParts.length - 1], "removed");
|
|
35797
|
+
} else if (code === "R" || code === "C") {
|
|
35798
|
+
if (tabParts.length >= 3) m.set(tabParts[tabParts.length - 1], "modified");
|
|
35799
|
+
} else if (code === "M" || code === "U" || code === "T") {
|
|
35800
|
+
m.set(tabParts[tabParts.length - 1], "modified");
|
|
35801
|
+
}
|
|
35802
|
+
}
|
|
35803
|
+
return m;
|
|
35804
|
+
}
|
|
35805
|
+
function parseNumstatFirstLine(line) {
|
|
35806
|
+
const parts = line.split(" ");
|
|
35807
|
+
if (parts.length < 3) return null;
|
|
35808
|
+
const [a, d] = parts;
|
|
35809
|
+
const additions = a === "-" ? 0 : parseInt(String(a), 10) || 0;
|
|
35810
|
+
const deletions = d === "-" ? 0 : parseInt(String(d), 10) || 0;
|
|
35811
|
+
return { additions, deletions };
|
|
35812
|
+
}
|
|
35813
|
+
function parseNumstat(lines) {
|
|
35814
|
+
const m = /* @__PURE__ */ new Map();
|
|
35815
|
+
for (const line of lines) {
|
|
35816
|
+
if (!line.trim()) continue;
|
|
35817
|
+
const parts = line.split(" ");
|
|
35818
|
+
if (parts.length < 3) continue;
|
|
35819
|
+
const [a, d, p] = parts;
|
|
35820
|
+
const additions = a === "-" ? 0 : parseInt(String(a), 10) || 0;
|
|
35821
|
+
const deletions = d === "-" ? 0 : parseInt(String(d), 10) || 0;
|
|
35822
|
+
m.set(p, { additions, deletions });
|
|
35823
|
+
}
|
|
35824
|
+
return m;
|
|
35825
|
+
}
|
|
35826
|
+
async function numstatFromGitNoIndex(g, pathInRepo) {
|
|
35827
|
+
const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
35828
|
+
try {
|
|
35829
|
+
const out = await g.raw(["diff", "--numstat", "--no-index", "--", devNull, pathInRepo]);
|
|
35830
|
+
const first2 = String(out).split("\n").find((l) => l.trim()) ?? "";
|
|
35831
|
+
return parseNumstatFirstLine(first2);
|
|
35832
|
+
} catch {
|
|
35833
|
+
return null;
|
|
35834
|
+
}
|
|
35835
|
+
}
|
|
35836
|
+
|
|
36075
35837
|
// src/git/changes/lib/patch-truncate.ts
|
|
36076
35838
|
function truncatePatch(s) {
|
|
36077
35839
|
if (s.length <= MAX_PATCH_CHARS) return s;
|
|
@@ -36137,8 +35899,8 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
36137
35899
|
}
|
|
36138
35900
|
|
|
36139
35901
|
// src/git/changes/list-changed-files-for-repo.ts
|
|
36140
|
-
import * as
|
|
36141
|
-
import * as
|
|
35902
|
+
import * as fs18 from "node:fs";
|
|
35903
|
+
import * as path20 from "node:path";
|
|
36142
35904
|
|
|
36143
35905
|
// src/git/changes/lib/count-lines.ts
|
|
36144
35906
|
import { createReadStream } from "node:fs";
|
|
@@ -36162,7 +35924,7 @@ async function countTextFileLines(filePath) {
|
|
|
36162
35924
|
}
|
|
36163
35925
|
|
|
36164
35926
|
// src/git/changes/hydrate-patch.ts
|
|
36165
|
-
import * as
|
|
35927
|
+
import * as fs17 from "node:fs";
|
|
36166
35928
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
36167
35929
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
36168
35930
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -36177,7 +35939,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
36177
35939
|
}
|
|
36178
35940
|
async function readWorktreeFileLines(filePath) {
|
|
36179
35941
|
try {
|
|
36180
|
-
const raw = await
|
|
35942
|
+
const raw = await fs17.promises.readFile(filePath, "utf8");
|
|
36181
35943
|
return raw.split(/\r?\n/);
|
|
36182
35944
|
} catch {
|
|
36183
35945
|
return null;
|
|
@@ -36302,7 +36064,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
36302
36064
|
const rows = [];
|
|
36303
36065
|
await forEachWithGitYield([...paths], async (pathInRepo) => {
|
|
36304
36066
|
const relLauncher = posixJoinDirFile(repoRelPath, pathInRepo.replace(/\\/g, "/"));
|
|
36305
|
-
const repoFilePath =
|
|
36067
|
+
const repoFilePath = path20.join(repoGitCwd, pathInRepo);
|
|
36306
36068
|
const nums = numByPath.get(pathInRepo);
|
|
36307
36069
|
let additions = nums?.additions ?? 0;
|
|
36308
36070
|
let deletions = nums?.deletions ?? 0;
|
|
@@ -36315,7 +36077,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
36315
36077
|
deletions = fromGit.deletions;
|
|
36316
36078
|
} else {
|
|
36317
36079
|
try {
|
|
36318
|
-
const st = await
|
|
36080
|
+
const st = await fs18.promises.stat(repoFilePath);
|
|
36319
36081
|
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
36320
36082
|
else additions = 0;
|
|
36321
36083
|
} catch {
|
|
@@ -36341,7 +36103,7 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
36341
36103
|
} else {
|
|
36342
36104
|
pathInRepo = row.pathRelLauncher;
|
|
36343
36105
|
}
|
|
36344
|
-
const filePath =
|
|
36106
|
+
const filePath = path20.join(repoGitCwd, pathInRepo);
|
|
36345
36107
|
let patch = await unifiedDiffForFile(repoGitCwd, pathInRepo, row.change);
|
|
36346
36108
|
if (patch) {
|
|
36347
36109
|
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
@@ -36357,8 +36119,8 @@ function normRepoRel(p) {
|
|
|
36357
36119
|
return x === "" ? "." : x;
|
|
36358
36120
|
}
|
|
36359
36121
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
36360
|
-
const bridgeRoot =
|
|
36361
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
36122
|
+
const bridgeRoot = path21.resolve(getBridgeRoot());
|
|
36123
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path21.resolve(options.sessionWorktreeRootPath) : null;
|
|
36362
36124
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
36363
36125
|
const out = [];
|
|
36364
36126
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -36373,7 +36135,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
36373
36135
|
for (let i = 0; i < options.commitTargetPaths.length; i++) {
|
|
36374
36136
|
if (i > 0) await yieldToEventLoop2();
|
|
36375
36137
|
const target = options.commitTargetPaths[i];
|
|
36376
|
-
const t =
|
|
36138
|
+
const t = path21.resolve(target);
|
|
36377
36139
|
if (!await isGitRepoDirectory(t)) continue;
|
|
36378
36140
|
const g = cliSimpleGit(t);
|
|
36379
36141
|
let branch = "HEAD";
|
|
@@ -36386,8 +36148,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
36386
36148
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
36387
36149
|
let repoRelPath;
|
|
36388
36150
|
if (sessionWtRoot) {
|
|
36389
|
-
const anchor = legacyNested ?
|
|
36390
|
-
const relNorm =
|
|
36151
|
+
const anchor = legacyNested ? path21.dirname(t) : t;
|
|
36152
|
+
const relNorm = path21.relative(sessionWtRoot, anchor);
|
|
36391
36153
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
36392
36154
|
} else {
|
|
36393
36155
|
let top = t;
|
|
@@ -36396,8 +36158,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
36396
36158
|
} catch {
|
|
36397
36159
|
top = t;
|
|
36398
36160
|
}
|
|
36399
|
-
const rel =
|
|
36400
|
-
repoRelPath = rel.startsWith("..") ?
|
|
36161
|
+
const rel = path21.relative(bridgeRoot, path21.resolve(top)).replace(/\\/g, "/") || ".";
|
|
36162
|
+
repoRelPath = rel.startsWith("..") ? path21.basename(path21.resolve(top)) : rel;
|
|
36401
36163
|
}
|
|
36402
36164
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
36403
36165
|
if (filter && norm !== filter) continue;
|
|
@@ -36429,6 +36191,64 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
36429
36191
|
return out;
|
|
36430
36192
|
}
|
|
36431
36193
|
|
|
36194
|
+
// src/git/changes/lib/working-tree-changed-path-count.ts
|
|
36195
|
+
function workingTreeChangedPathCount(nameStatusLines, numstatLines, untrackedLines) {
|
|
36196
|
+
const kindByPath = parseNameStatusLines(nameStatusLines);
|
|
36197
|
+
const numByPath = parseNumstat(numstatLines);
|
|
36198
|
+
const paths = /* @__PURE__ */ new Set([...kindByPath.keys(), ...numByPath.keys()]);
|
|
36199
|
+
for (const p of untrackedLines.map((s) => s.trim()).filter(Boolean)) {
|
|
36200
|
+
paths.add(p);
|
|
36201
|
+
}
|
|
36202
|
+
return paths.size;
|
|
36203
|
+
}
|
|
36204
|
+
|
|
36205
|
+
// src/git/changes/count-working-tree-changed-files.ts
|
|
36206
|
+
async function countWorkingTreeChangedFilesForRepo(repoGitCwd) {
|
|
36207
|
+
return runGitTask(async () => {
|
|
36208
|
+
const g = cliSimpleGit(repoGitCwd);
|
|
36209
|
+
const [nameStatusRaw, numstatRaw, untrackedRaw] = await Promise.all([
|
|
36210
|
+
g.raw(["diff", "--name-status", "HEAD"]).catch(() => ""),
|
|
36211
|
+
g.raw(["diff", "HEAD", "--numstat"]).catch(() => ""),
|
|
36212
|
+
g.raw(["ls-files", "--others", "--exclude-standard"]).catch(() => "")
|
|
36213
|
+
]);
|
|
36214
|
+
return workingTreeChangedPathCount(
|
|
36215
|
+
String(nameStatusRaw).split("\n"),
|
|
36216
|
+
String(numstatRaw).split("\n"),
|
|
36217
|
+
String(untrackedRaw).split("\n")
|
|
36218
|
+
);
|
|
36219
|
+
});
|
|
36220
|
+
}
|
|
36221
|
+
|
|
36222
|
+
// src/git/status/working-tree-status.ts
|
|
36223
|
+
async function getRepoWorkingTreeStatus(repoDir) {
|
|
36224
|
+
return runGitTask(async () => {
|
|
36225
|
+
const uncommittedFileCount = await countWorkingTreeChangedFilesForRepo(repoDir);
|
|
36226
|
+
const hasUncommittedChanges = uncommittedFileCount > 0;
|
|
36227
|
+
const ahead = await commitsAheadOfRemoteTracking(repoDir);
|
|
36228
|
+
return { hasUncommittedChanges, hasUnpushedCommits: ahead > 0, uncommittedFileCount };
|
|
36229
|
+
});
|
|
36230
|
+
}
|
|
36231
|
+
async function aggregateSessionPathsWorkingTreeStatus(paths) {
|
|
36232
|
+
let hasUncommittedChanges = false;
|
|
36233
|
+
let hasUnpushedCommits = false;
|
|
36234
|
+
let uncommittedFileCount = 0;
|
|
36235
|
+
await forEachWithGitYield(paths, async (p) => {
|
|
36236
|
+
const s = await getRepoWorkingTreeStatus(p);
|
|
36237
|
+
uncommittedFileCount += s.uncommittedFileCount;
|
|
36238
|
+
if (s.hasUncommittedChanges) hasUncommittedChanges = true;
|
|
36239
|
+
if (s.hasUnpushedCommits) hasUnpushedCommits = true;
|
|
36240
|
+
});
|
|
36241
|
+
return { hasUncommittedChanges, hasUnpushedCommits, uncommittedFileCount };
|
|
36242
|
+
}
|
|
36243
|
+
async function pushAheadOfUpstreamForPaths(paths) {
|
|
36244
|
+
await forEachWithGitYield(paths, async (p) => {
|
|
36245
|
+
const g = cliSimpleGit(p);
|
|
36246
|
+
const ahead = await commitsAheadOfRemoteTracking(p);
|
|
36247
|
+
if (ahead <= 0) return;
|
|
36248
|
+
await g.push();
|
|
36249
|
+
});
|
|
36250
|
+
}
|
|
36251
|
+
|
|
36432
36252
|
// src/git/branches/commit-and-push.ts
|
|
36433
36253
|
async function gitCommitAllIfDirty(repoDir, message, options) {
|
|
36434
36254
|
const g = cliSimpleGit(repoDir);
|
|
@@ -36466,12 +36286,137 @@ async function commitSessionWorktrees(options) {
|
|
|
36466
36286
|
}
|
|
36467
36287
|
}
|
|
36468
36288
|
|
|
36289
|
+
// src/worktrees/remove-session-worktrees.ts
|
|
36290
|
+
import * as fs21 from "node:fs";
|
|
36291
|
+
|
|
36292
|
+
// src/git/worktrees/worktree-remove.ts
|
|
36293
|
+
import * as fs20 from "node:fs";
|
|
36294
|
+
|
|
36295
|
+
// src/git/worktrees/resolve-main-repo-from-git-file.ts
|
|
36296
|
+
import * as fs19 from "node:fs";
|
|
36297
|
+
import * as path22 from "node:path";
|
|
36298
|
+
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
36299
|
+
const gitDirFile = path22.join(wt, ".git");
|
|
36300
|
+
if (!fs19.existsSync(gitDirFile) || !fs19.statSync(gitDirFile).isFile()) return "";
|
|
36301
|
+
const first2 = fs19.readFileSync(gitDirFile, "utf8").trim();
|
|
36302
|
+
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
36303
|
+
if (!m) return "";
|
|
36304
|
+
const gitWorktreePath = path22.resolve(wt, m[1].trim());
|
|
36305
|
+
const gitDir = path22.dirname(path22.dirname(gitWorktreePath));
|
|
36306
|
+
return path22.dirname(gitDir);
|
|
36307
|
+
}
|
|
36308
|
+
|
|
36309
|
+
// src/git/worktrees/worktree-remove.ts
|
|
36310
|
+
async function gitWorktreeRemoveForce(worktreePath) {
|
|
36311
|
+
const mainRepo = resolveMainRepoFromWorktreeGitFile(worktreePath);
|
|
36312
|
+
if (mainRepo) {
|
|
36313
|
+
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
36314
|
+
} else {
|
|
36315
|
+
fs20.rmSync(worktreePath, { recursive: true, force: true });
|
|
36316
|
+
}
|
|
36317
|
+
}
|
|
36318
|
+
|
|
36319
|
+
// src/worktrees/remove-session-worktrees.ts
|
|
36320
|
+
async function removeSessionWorktrees(paths, log2) {
|
|
36321
|
+
for (const wt of paths) {
|
|
36322
|
+
try {
|
|
36323
|
+
await gitWorktreeRemoveForce(wt);
|
|
36324
|
+
log2(`[worktrees] Removed worktree ${wt}`);
|
|
36325
|
+
} catch (e) {
|
|
36326
|
+
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
36327
|
+
try {
|
|
36328
|
+
fs21.rmSync(wt, { recursive: true, force: true });
|
|
36329
|
+
} catch {
|
|
36330
|
+
}
|
|
36331
|
+
}
|
|
36332
|
+
}
|
|
36333
|
+
}
|
|
36334
|
+
|
|
36335
|
+
// src/git/branches/rename-branch.ts
|
|
36336
|
+
async function gitRenameCurrentBranch(repoDir, newName) {
|
|
36337
|
+
const g = cliSimpleGit(repoDir);
|
|
36338
|
+
await g.raw(["branch", "-m", newName]);
|
|
36339
|
+
}
|
|
36340
|
+
|
|
36341
|
+
// src/worktrees/rename-session-worktree-branches.ts
|
|
36342
|
+
async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
36343
|
+
const safe = newBranch.replace(/[^a-zA-Z0-9/_-]+/g, "-").slice(0, 80) || "session-branch";
|
|
36344
|
+
for (const wt of paths) {
|
|
36345
|
+
try {
|
|
36346
|
+
await gitRenameCurrentBranch(wt, safe);
|
|
36347
|
+
log2(`[worktrees] Renamed branch in ${wt} \u2192 ${safe}`);
|
|
36348
|
+
} catch (e) {
|
|
36349
|
+
log2(
|
|
36350
|
+
`[worktrees] Branch rename failed in ${wt}: ${e instanceof Error ? e.message : String(e)}`
|
|
36351
|
+
);
|
|
36352
|
+
}
|
|
36353
|
+
}
|
|
36354
|
+
}
|
|
36355
|
+
|
|
36356
|
+
// src/worktrees/worktree-layout-file.ts
|
|
36357
|
+
import * as fs22 from "node:fs";
|
|
36358
|
+
import * as path23 from "node:path";
|
|
36359
|
+
import os7 from "node:os";
|
|
36360
|
+
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
36361
|
+
function defaultWorktreeLayoutPath() {
|
|
36362
|
+
return path23.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
36363
|
+
}
|
|
36364
|
+
function normalizeLoadedLayout(raw) {
|
|
36365
|
+
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
36366
|
+
const j = raw;
|
|
36367
|
+
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
36368
|
+
}
|
|
36369
|
+
return { launcherCwds: [] };
|
|
36370
|
+
}
|
|
36371
|
+
function loadWorktreeLayout() {
|
|
36372
|
+
try {
|
|
36373
|
+
const p = defaultWorktreeLayoutPath();
|
|
36374
|
+
if (!fs22.existsSync(p)) return { launcherCwds: [] };
|
|
36375
|
+
const raw = JSON.parse(fs22.readFileSync(p, "utf8"));
|
|
36376
|
+
return normalizeLoadedLayout(raw);
|
|
36377
|
+
} catch {
|
|
36378
|
+
return { launcherCwds: [] };
|
|
36379
|
+
}
|
|
36380
|
+
}
|
|
36381
|
+
function saveWorktreeLayout(layout) {
|
|
36382
|
+
try {
|
|
36383
|
+
const dir = path23.dirname(defaultWorktreeLayoutPath());
|
|
36384
|
+
fs22.mkdirSync(dir, { recursive: true });
|
|
36385
|
+
fs22.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
36386
|
+
} catch {
|
|
36387
|
+
}
|
|
36388
|
+
}
|
|
36389
|
+
function baseNameSafe(pathString) {
|
|
36390
|
+
return path23.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
36391
|
+
}
|
|
36392
|
+
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
36393
|
+
const norm = path23.resolve(bridgeRootPath2);
|
|
36394
|
+
const existing = layout.launcherCwds.find((e) => path23.resolve(e.absolutePath) === norm);
|
|
36395
|
+
return existing?.dirName;
|
|
36396
|
+
}
|
|
36397
|
+
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
36398
|
+
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
36399
|
+
if (existing) return existing;
|
|
36400
|
+
const norm = path23.resolve(bridgeRootPath2);
|
|
36401
|
+
const base = baseNameSafe(norm);
|
|
36402
|
+
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
36403
|
+
let name = base;
|
|
36404
|
+
let n = 2;
|
|
36405
|
+
while (used.has(name)) {
|
|
36406
|
+
name = `${base}-${n}`;
|
|
36407
|
+
n += 1;
|
|
36408
|
+
}
|
|
36409
|
+
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
36410
|
+
saveWorktreeLayout(layout);
|
|
36411
|
+
return name;
|
|
36412
|
+
}
|
|
36413
|
+
|
|
36469
36414
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
36470
|
-
import * as
|
|
36471
|
-
import * as
|
|
36415
|
+
import * as fs23 from "node:fs";
|
|
36416
|
+
import * as path24 from "node:path";
|
|
36472
36417
|
function isGitDir(dirPath) {
|
|
36473
36418
|
try {
|
|
36474
|
-
return
|
|
36419
|
+
return fs23.existsSync(path24.join(dirPath, ".git"));
|
|
36475
36420
|
} catch {
|
|
36476
36421
|
return false;
|
|
36477
36422
|
}
|
|
@@ -36480,23 +36425,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
36480
36425
|
const out = [];
|
|
36481
36426
|
const walk = (dir) => {
|
|
36482
36427
|
if (isGitDir(dir)) {
|
|
36483
|
-
out.push(
|
|
36428
|
+
out.push(path24.resolve(dir));
|
|
36484
36429
|
return;
|
|
36485
36430
|
}
|
|
36486
36431
|
let entries;
|
|
36487
36432
|
try {
|
|
36488
|
-
entries =
|
|
36433
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
36489
36434
|
} catch {
|
|
36490
36435
|
return;
|
|
36491
36436
|
}
|
|
36492
36437
|
for (const e of entries) {
|
|
36493
36438
|
if (e.name.startsWith(".")) continue;
|
|
36494
|
-
const full =
|
|
36439
|
+
const full = path24.join(dir, e.name);
|
|
36495
36440
|
if (!e.isDirectory()) continue;
|
|
36496
36441
|
walk(full);
|
|
36497
36442
|
}
|
|
36498
36443
|
};
|
|
36499
|
-
walk(
|
|
36444
|
+
walk(path24.resolve(rootPath));
|
|
36500
36445
|
return [...new Set(out)];
|
|
36501
36446
|
}
|
|
36502
36447
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -36505,16 +36450,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
36505
36450
|
if (depth > maxDepth) return;
|
|
36506
36451
|
let entries;
|
|
36507
36452
|
try {
|
|
36508
|
-
entries =
|
|
36453
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
36509
36454
|
} catch {
|
|
36510
36455
|
return;
|
|
36511
36456
|
}
|
|
36512
36457
|
for (const e of entries) {
|
|
36513
36458
|
if (e.name.startsWith(".")) continue;
|
|
36514
|
-
const full =
|
|
36459
|
+
const full = path24.join(dir, e.name);
|
|
36515
36460
|
if (!e.isDirectory()) continue;
|
|
36516
36461
|
if (e.name === sessionId) {
|
|
36517
|
-
if (isGitDir(full)) out.push(
|
|
36462
|
+
if (isGitDir(full)) out.push(path24.resolve(full));
|
|
36518
36463
|
} else {
|
|
36519
36464
|
walk(full, depth + 1);
|
|
36520
36465
|
}
|
|
@@ -36526,14 +36471,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
36526
36471
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
36527
36472
|
let st;
|
|
36528
36473
|
try {
|
|
36529
|
-
st =
|
|
36474
|
+
st = fs23.statSync(sessionDir);
|
|
36530
36475
|
} catch {
|
|
36531
36476
|
return null;
|
|
36532
36477
|
}
|
|
36533
36478
|
if (!st.isDirectory()) return null;
|
|
36534
36479
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
36535
36480
|
if (worktreePaths.length === 0) return null;
|
|
36536
|
-
const abs =
|
|
36481
|
+
const abs = path24.resolve(sessionDir);
|
|
36537
36482
|
return {
|
|
36538
36483
|
sessionParentPath: abs,
|
|
36539
36484
|
workingTreeRelRoot: abs,
|
|
@@ -36543,20 +36488,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
36543
36488
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
36544
36489
|
const sid = sessionId.trim();
|
|
36545
36490
|
if (!sid) return null;
|
|
36546
|
-
const hintR =
|
|
36491
|
+
const hintR = path24.resolve(checkoutPath);
|
|
36547
36492
|
let best = null;
|
|
36548
|
-
let cur =
|
|
36493
|
+
let cur = path24.dirname(hintR);
|
|
36549
36494
|
for (let i = 0; i < 40; i++) {
|
|
36550
36495
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
36551
|
-
if (paths.some((p) =>
|
|
36552
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
36496
|
+
if (paths.some((p) => path24.resolve(p) === hintR)) {
|
|
36497
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path24.resolve(paths[0]);
|
|
36553
36498
|
best = {
|
|
36554
|
-
sessionParentPath:
|
|
36555
|
-
workingTreeRelRoot:
|
|
36556
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
36499
|
+
sessionParentPath: path24.resolve(isolated),
|
|
36500
|
+
workingTreeRelRoot: path24.resolve(cur),
|
|
36501
|
+
repoCheckoutPaths: paths.map((p) => path24.resolve(p))
|
|
36557
36502
|
};
|
|
36558
36503
|
}
|
|
36559
|
-
const next =
|
|
36504
|
+
const next = path24.dirname(cur);
|
|
36560
36505
|
if (next === cur) break;
|
|
36561
36506
|
cur = next;
|
|
36562
36507
|
}
|
|
@@ -36564,33 +36509,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
36564
36509
|
}
|
|
36565
36510
|
function discoverSessionWorktreeOnDisk(options) {
|
|
36566
36511
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
36567
|
-
if (!sessionId.trim() || !
|
|
36512
|
+
if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
|
|
36568
36513
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
36569
36514
|
const keys = [];
|
|
36570
36515
|
if (preferredKey) keys.push(preferredKey);
|
|
36571
36516
|
try {
|
|
36572
|
-
for (const name of
|
|
36517
|
+
for (const name of fs23.readdirSync(worktreesRootPath)) {
|
|
36573
36518
|
if (name.startsWith(".")) continue;
|
|
36574
|
-
const p =
|
|
36575
|
-
if (!
|
|
36519
|
+
const p = path24.join(worktreesRootPath, name);
|
|
36520
|
+
if (!fs23.statSync(p).isDirectory()) continue;
|
|
36576
36521
|
if (name !== preferredKey) keys.push(name);
|
|
36577
36522
|
}
|
|
36578
36523
|
} catch {
|
|
36579
36524
|
return null;
|
|
36580
36525
|
}
|
|
36581
36526
|
for (const key of keys) {
|
|
36582
|
-
const layoutRoot =
|
|
36583
|
-
if (!
|
|
36584
|
-
const sessionDir =
|
|
36527
|
+
const layoutRoot = path24.join(worktreesRootPath, key);
|
|
36528
|
+
if (!fs23.existsSync(layoutRoot) || !fs23.statSync(layoutRoot).isDirectory()) continue;
|
|
36529
|
+
const sessionDir = path24.join(layoutRoot, sessionId);
|
|
36585
36530
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
36586
36531
|
if (nested) return nested;
|
|
36587
36532
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
36588
36533
|
if (legacyPaths.length > 0) {
|
|
36589
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
36534
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
|
|
36590
36535
|
return {
|
|
36591
|
-
sessionParentPath:
|
|
36592
|
-
workingTreeRelRoot:
|
|
36593
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
36536
|
+
sessionParentPath: path24.resolve(isolated),
|
|
36537
|
+
workingTreeRelRoot: path24.resolve(layoutRoot),
|
|
36538
|
+
repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
|
|
36594
36539
|
};
|
|
36595
36540
|
}
|
|
36596
36541
|
}
|
|
@@ -36599,12 +36544,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
36599
36544
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
36600
36545
|
const sid = sessionId.trim();
|
|
36601
36546
|
if (!sid) return null;
|
|
36602
|
-
const hint =
|
|
36603
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
36547
|
+
const hint = path24.resolve(sessionWorktreeRootPathOrHint);
|
|
36548
|
+
const underHint = tryBindingFromSessionDirectory(path24.join(hint, sid));
|
|
36604
36549
|
if (underHint) return underHint;
|
|
36605
36550
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
36606
36551
|
if (direct) {
|
|
36607
|
-
if (
|
|
36552
|
+
if (path24.basename(hint) === sid && isGitDir(hint)) {
|
|
36608
36553
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
36609
36554
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
36610
36555
|
return legacyFromCheckout;
|
|
@@ -36612,216 +36557,349 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
36612
36557
|
}
|
|
36613
36558
|
return direct;
|
|
36614
36559
|
}
|
|
36615
|
-
if (
|
|
36560
|
+
if (path24.basename(hint) === sid && isGitDir(hint)) {
|
|
36616
36561
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
36617
36562
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
36618
36563
|
}
|
|
36619
36564
|
let st;
|
|
36620
36565
|
try {
|
|
36621
|
-
st =
|
|
36566
|
+
st = fs23.statSync(hint);
|
|
36622
36567
|
} catch {
|
|
36623
36568
|
return null;
|
|
36624
36569
|
}
|
|
36625
36570
|
if (!st.isDirectory()) return null;
|
|
36626
36571
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
36627
36572
|
if (legacyPaths.length === 0) return null;
|
|
36628
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
36573
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path24.resolve(legacyPaths[0]);
|
|
36629
36574
|
return {
|
|
36630
|
-
sessionParentPath:
|
|
36575
|
+
sessionParentPath: path24.resolve(isolated),
|
|
36631
36576
|
workingTreeRelRoot: hint,
|
|
36632
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
36577
|
+
repoCheckoutPaths: legacyPaths.map((p) => path24.resolve(p))
|
|
36633
36578
|
};
|
|
36634
36579
|
}
|
|
36635
36580
|
|
|
36636
|
-
// src/worktrees/session-
|
|
36581
|
+
// src/worktrees/manager/discover-session-binding.ts
|
|
36582
|
+
function discoverSessionBinding(params) {
|
|
36583
|
+
return discoverSessionWorktreeOnDisk({
|
|
36584
|
+
sessionId: params.sessionId,
|
|
36585
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
36586
|
+
layout: params.layout,
|
|
36587
|
+
bridgeRoot: getBridgeRoot()
|
|
36588
|
+
});
|
|
36589
|
+
}
|
|
36590
|
+
|
|
36591
|
+
// src/worktrees/manager/resolve-isolated-session-parent-path.ts
|
|
36592
|
+
function resolveIsolatedSessionParentPath(sessionId, cache2, ensureRepoCheckoutPaths) {
|
|
36593
|
+
if (!sessionId) return null;
|
|
36594
|
+
const sid = sessionId.trim();
|
|
36595
|
+
const cached2 = cache2.getSessionParentPath(sid);
|
|
36596
|
+
if (cached2) return cached2;
|
|
36597
|
+
const paths = ensureRepoCheckoutPaths(sid);
|
|
36598
|
+
if (!paths?.length) return null;
|
|
36599
|
+
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
36600
|
+
}
|
|
36601
|
+
function ensureRepoCheckoutPathsForSession(sessionId, cache2, discover) {
|
|
36602
|
+
if (!sessionId?.trim()) return void 0;
|
|
36603
|
+
const sid = sessionId.trim();
|
|
36604
|
+
const cached2 = cache2.getRepoCheckoutPaths(sid);
|
|
36605
|
+
if (cached2?.length) return cached2;
|
|
36606
|
+
const disc = discover(sid);
|
|
36607
|
+
if (disc?.repoCheckoutPaths.length) {
|
|
36608
|
+
cache2.remember(sid, disc);
|
|
36609
|
+
return [...disc.repoCheckoutPaths];
|
|
36610
|
+
}
|
|
36611
|
+
return void 0;
|
|
36612
|
+
}
|
|
36613
|
+
|
|
36614
|
+
// src/worktrees/manager/resolve-commit-targets.ts
|
|
36615
|
+
function resolveCommitTargets(sessionId, cache2, discover) {
|
|
36616
|
+
const paths = cache2.getRepoCheckoutPathsRef(sessionId);
|
|
36617
|
+
if (paths?.length) return paths;
|
|
36618
|
+
const disc = discover(sessionId);
|
|
36619
|
+
if (disc?.repoCheckoutPaths.length) {
|
|
36620
|
+
cache2.remember(sessionId, disc);
|
|
36621
|
+
return disc.repoCheckoutPaths;
|
|
36622
|
+
}
|
|
36623
|
+
return [getBridgeRoot()];
|
|
36624
|
+
}
|
|
36625
|
+
|
|
36626
|
+
// src/worktrees/manager/parse-session-parent.ts
|
|
36637
36627
|
function parseSessionParent(v) {
|
|
36638
36628
|
if (v === "bridge_root" || v === "worktrees_root") return v;
|
|
36639
36629
|
if (v === "session_worktrees_root") return "worktrees_root";
|
|
36640
36630
|
return null;
|
|
36641
36631
|
}
|
|
36642
|
-
|
|
36643
|
-
|
|
36644
|
-
|
|
36632
|
+
|
|
36633
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
36634
|
+
import * as fs24 from "node:fs";
|
|
36635
|
+
import * as path25 from "node:path";
|
|
36636
|
+
|
|
36637
|
+
// src/git/worktrees/worktree-add.ts
|
|
36638
|
+
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
36639
|
+
const mainGit = cliSimpleGit(mainRepoPath);
|
|
36640
|
+
const base = baseRef.trim() || "HEAD";
|
|
36641
|
+
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, base]);
|
|
36642
|
+
}
|
|
36643
|
+
|
|
36644
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
36645
|
+
function normalizeRepoRelPath(rel) {
|
|
36646
|
+
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
36647
|
+
}
|
|
36648
|
+
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
36649
|
+
if (!baseBranches) return "HEAD";
|
|
36650
|
+
const direct = baseBranches[relNorm]?.trim();
|
|
36651
|
+
if (direct) return direct;
|
|
36652
|
+
if (relNorm !== "." && baseBranches["."]?.trim()) return baseBranches["."].trim();
|
|
36653
|
+
return "HEAD";
|
|
36654
|
+
}
|
|
36655
|
+
async function prepareNewSessionWorktrees(options) {
|
|
36656
|
+
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
|
|
36657
|
+
const bridgeResolved = path25.resolve(bridgeRoot);
|
|
36658
|
+
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
36659
|
+
const bridgeKeyDir = path25.join(worktreesRootPath, cwdKey);
|
|
36660
|
+
const sessionDir = path25.join(bridgeKeyDir, sessionId);
|
|
36661
|
+
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
36662
|
+
if (repos.length === 0) {
|
|
36663
|
+
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
36664
|
+
return null;
|
|
36665
|
+
}
|
|
36666
|
+
const branch = `session-${sessionId}`;
|
|
36667
|
+
const worktreePaths = [];
|
|
36668
|
+
fs24.mkdirSync(sessionDir, { recursive: true });
|
|
36669
|
+
for (const repo of repos) {
|
|
36670
|
+
let rel = path25.relative(bridgeResolved, repo.absolutePath);
|
|
36671
|
+
if (rel.startsWith("..") || path25.isAbsolute(rel)) continue;
|
|
36672
|
+
const relNorm = normalizeRepoRelPath(rel === "" ? "." : rel);
|
|
36673
|
+
const wtPath = relNorm === "." ? sessionDir : path25.join(sessionDir, relNorm);
|
|
36674
|
+
if (relNorm !== ".") {
|
|
36675
|
+
fs24.mkdirSync(path25.dirname(wtPath), { recursive: true });
|
|
36676
|
+
}
|
|
36677
|
+
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
36678
|
+
try {
|
|
36679
|
+
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch, baseRef);
|
|
36680
|
+
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}, base ${baseRef}).`);
|
|
36681
|
+
worktreePaths.push(wtPath);
|
|
36682
|
+
} catch (e) {
|
|
36683
|
+
log2(
|
|
36684
|
+
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
36685
|
+
);
|
|
36686
|
+
}
|
|
36687
|
+
}
|
|
36688
|
+
if (worktreePaths.length === 0) return null;
|
|
36689
|
+
return {
|
|
36690
|
+
worktreePaths,
|
|
36691
|
+
sessionParentPath: sessionDir,
|
|
36692
|
+
workingTreeRelRoot: sessionDir
|
|
36693
|
+
};
|
|
36694
|
+
}
|
|
36695
|
+
|
|
36696
|
+
// src/worktrees/manager/prepare-and-remember-session-worktrees.ts
|
|
36697
|
+
async function prepareAndRememberSessionWorktrees(params) {
|
|
36698
|
+
const prep = await prepareNewSessionWorktrees({
|
|
36699
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
36700
|
+
bridgeRoot: getBridgeRoot(),
|
|
36701
|
+
sessionId: params.sessionId,
|
|
36702
|
+
layout: params.layout,
|
|
36703
|
+
log: params.log,
|
|
36704
|
+
...params.worktreeBaseBranches && Object.keys(params.worktreeBaseBranches).length > 0 ? { worktreeBaseBranches: params.worktreeBaseBranches } : {}
|
|
36705
|
+
});
|
|
36706
|
+
if (!prep) return void 0;
|
|
36707
|
+
params.cache.remember(params.sessionId, {
|
|
36708
|
+
sessionParentPath: prep.sessionParentPath,
|
|
36709
|
+
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
36710
|
+
repoCheckoutPaths: prep.worktreePaths
|
|
36711
|
+
});
|
|
36712
|
+
return params.cache.getSessionParentPath(params.sessionId);
|
|
36713
|
+
}
|
|
36714
|
+
|
|
36715
|
+
// src/worktrees/manager/resolve-existing-session-parent-path.ts
|
|
36716
|
+
function resolveExistingSessionParentPath(sessionId, cache2, discover) {
|
|
36717
|
+
const cached2 = cache2.getSessionParentPath(sessionId);
|
|
36718
|
+
if (cached2) return cached2;
|
|
36719
|
+
const disc = discover();
|
|
36720
|
+
if (disc) {
|
|
36721
|
+
cache2.remember(sessionId, disc);
|
|
36722
|
+
return cache2.getSessionParentPath(sessionId);
|
|
36723
|
+
}
|
|
36724
|
+
return void 0;
|
|
36725
|
+
}
|
|
36726
|
+
|
|
36727
|
+
// src/worktrees/manager/resolve-explicit-session-parent-path.ts
|
|
36728
|
+
import * as path26 from "node:path";
|
|
36729
|
+
function resolveExplicitSessionParentPath(params) {
|
|
36730
|
+
const resolved = path26.resolve(params.parentPathRaw);
|
|
36731
|
+
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
36732
|
+
return resolved;
|
|
36733
|
+
}
|
|
36734
|
+
const rememberAndReturn = (binding) => {
|
|
36735
|
+
params.cache.remember(params.sessionId, binding);
|
|
36736
|
+
return params.cache.getSessionParentPath(params.sessionId) ?? resolved;
|
|
36737
|
+
};
|
|
36738
|
+
const diskFirst = params.discover();
|
|
36739
|
+
if (diskFirst) return rememberAndReturn(diskFirst);
|
|
36740
|
+
const fromRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, params.sessionId);
|
|
36741
|
+
if (fromRoot) return rememberAndReturn(fromRoot);
|
|
36742
|
+
let cur = resolved;
|
|
36743
|
+
for (let i = 0; i < 16; i++) {
|
|
36744
|
+
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
36745
|
+
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
36746
|
+
const next = path26.dirname(cur);
|
|
36747
|
+
if (next === cur) break;
|
|
36748
|
+
cur = next;
|
|
36749
|
+
}
|
|
36750
|
+
return resolved;
|
|
36751
|
+
}
|
|
36752
|
+
|
|
36753
|
+
// src/worktrees/manager/resolve-session-parent-path-for-prompt.ts
|
|
36754
|
+
async function resolveSessionParentPathForPrompt(params) {
|
|
36755
|
+
const { sessionId, cache: cache2, worktreesRootPath, layout, log: log2, discover, opts } = params;
|
|
36756
|
+
if (!sessionId) return void 0;
|
|
36757
|
+
const sid = sessionId.trim();
|
|
36758
|
+
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
36759
|
+
if (parentPathRaw) {
|
|
36760
|
+
return resolveExplicitSessionParentPath({
|
|
36761
|
+
sessionId: sid,
|
|
36762
|
+
sessionParent: opts.sessionParent,
|
|
36763
|
+
parentPathRaw,
|
|
36764
|
+
cache: cache2,
|
|
36765
|
+
discover: () => discover(sid)
|
|
36766
|
+
});
|
|
36767
|
+
}
|
|
36768
|
+
const parentKind = parseSessionParent(opts.sessionParent);
|
|
36769
|
+
if (parentKind === "bridge_root") {
|
|
36770
|
+
return void 0;
|
|
36771
|
+
}
|
|
36772
|
+
if (parentKind === "worktrees_root") {
|
|
36773
|
+
if (!opts.isNewSession) {
|
|
36774
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
36775
|
+
}
|
|
36776
|
+
return prepareAndRememberSessionWorktrees({
|
|
36777
|
+
cache: cache2,
|
|
36778
|
+
sessionId: sid,
|
|
36779
|
+
worktreesRootPath,
|
|
36780
|
+
layout,
|
|
36781
|
+
log: log2,
|
|
36782
|
+
...opts.worktreeBaseBranches ? { worktreeBaseBranches: opts.worktreeBaseBranches } : {}
|
|
36783
|
+
});
|
|
36784
|
+
}
|
|
36785
|
+
if (!opts.isNewSession) {
|
|
36786
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
36787
|
+
}
|
|
36788
|
+
return prepareAndRememberSessionWorktrees({
|
|
36789
|
+
cache: cache2,
|
|
36790
|
+
sessionId: sid,
|
|
36791
|
+
worktreesRootPath,
|
|
36792
|
+
layout,
|
|
36793
|
+
log: log2
|
|
36794
|
+
});
|
|
36795
|
+
}
|
|
36796
|
+
|
|
36797
|
+
// src/worktrees/manager/session-worktree-cache.ts
|
|
36798
|
+
import * as path27 from "node:path";
|
|
36799
|
+
var SessionWorktreeCache = class {
|
|
36645
36800
|
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
36646
36801
|
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
36647
36802
|
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
36648
|
-
|
|
36649
|
-
|
|
36650
|
-
this.worktreesRootPath = options.worktreesRootPath;
|
|
36651
|
-
this.log = options.log;
|
|
36652
|
-
this.layout = loadWorktreeLayout();
|
|
36653
|
-
}
|
|
36654
|
-
rememberSessionWorktrees(sessionId, binding) {
|
|
36655
|
-
const paths = binding.repoCheckoutPaths.map((p) => path26.resolve(p));
|
|
36803
|
+
remember(sessionId, binding) {
|
|
36804
|
+
const paths = binding.repoCheckoutPaths.map((p) => path27.resolve(p));
|
|
36656
36805
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
36657
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
36658
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
36806
|
+
this.sessionParentPathBySession.set(sessionId, path27.resolve(binding.sessionParentPath));
|
|
36807
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path27.resolve(binding.workingTreeRelRoot));
|
|
36808
|
+
}
|
|
36809
|
+
clearSession(sessionId) {
|
|
36810
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
36811
|
+
this.sessionRepoCheckoutPaths.delete(sessionId);
|
|
36812
|
+
this.sessionParentPathBySession.delete(sessionId);
|
|
36813
|
+
this.sessionWorkingTreeRelRootBySession.delete(sessionId);
|
|
36814
|
+
return paths;
|
|
36659
36815
|
}
|
|
36660
|
-
|
|
36816
|
+
getSessionParentPath(sessionId) {
|
|
36661
36817
|
return this.sessionParentPathBySession.get(sessionId);
|
|
36662
36818
|
}
|
|
36663
|
-
|
|
36664
|
-
return
|
|
36665
|
-
|
|
36666
|
-
|
|
36667
|
-
|
|
36668
|
-
|
|
36669
|
-
|
|
36819
|
+
getWorkingTreeRelRoot(sessionId) {
|
|
36820
|
+
return this.sessionWorkingTreeRelRootBySession.get(sessionId) ?? null;
|
|
36821
|
+
}
|
|
36822
|
+
hasSession(sessionId) {
|
|
36823
|
+
return this.sessionParentPathBySession.has(sessionId);
|
|
36824
|
+
}
|
|
36825
|
+
getRepoCheckoutPaths(sessionId) {
|
|
36826
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
36827
|
+
return paths?.length ? [...paths] : void 0;
|
|
36828
|
+
}
|
|
36829
|
+
getRepoCheckoutPathsRef(sessionId) {
|
|
36830
|
+
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
36831
|
+
return paths?.length ? paths : void 0;
|
|
36670
36832
|
}
|
|
36671
36833
|
isLegacyNestedLayout(sessionId) {
|
|
36672
36834
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
36673
36835
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
36674
36836
|
if (!parent || !relRoot) return false;
|
|
36675
|
-
return
|
|
36837
|
+
return path27.resolve(parent) !== path27.resolve(relRoot);
|
|
36838
|
+
}
|
|
36839
|
+
};
|
|
36840
|
+
|
|
36841
|
+
// src/worktrees/manager/manager.ts
|
|
36842
|
+
var SessionWorktreeManager = class {
|
|
36843
|
+
worktreesRootPath;
|
|
36844
|
+
log;
|
|
36845
|
+
cache = new SessionWorktreeCache();
|
|
36846
|
+
layout;
|
|
36847
|
+
constructor(options) {
|
|
36848
|
+
this.worktreesRootPath = options.worktreesRootPath;
|
|
36849
|
+
this.log = options.log;
|
|
36850
|
+
this.layout = loadWorktreeLayout();
|
|
36851
|
+
}
|
|
36852
|
+
discover(sessionId) {
|
|
36853
|
+
return discoverSessionBinding({
|
|
36854
|
+
sessionId,
|
|
36855
|
+
worktreesRootPath: this.worktreesRootPath,
|
|
36856
|
+
layout: this.layout
|
|
36857
|
+
});
|
|
36676
36858
|
}
|
|
36677
|
-
/**
|
|
36678
|
-
* Session parent path for `worktrees_root`: the per-session directory (new layout) or primary checkout (legacy).
|
|
36679
|
-
*/
|
|
36680
36859
|
getIsolatedSessionParentPathForSession(sessionId) {
|
|
36681
|
-
|
|
36682
|
-
|
|
36683
|
-
|
|
36684
|
-
|
|
36685
|
-
|
|
36686
|
-
|
|
36687
|
-
|
|
36688
|
-
|
|
36689
|
-
|
|
36690
|
-
|
|
36691
|
-
* or `undefined` meaning use {@link getBridgeRoot}.
|
|
36692
|
-
*/
|
|
36693
|
-
async resolveSessionParentPathForPrompt(sessionId, opts) {
|
|
36694
|
-
if (!sessionId) return void 0;
|
|
36695
|
-
const sid = sessionId.trim();
|
|
36696
|
-
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
36697
|
-
if (parentPathRaw) {
|
|
36698
|
-
const resolved = path26.resolve(parentPathRaw);
|
|
36699
|
-
if (sid && parseSessionParent(opts.sessionParent) === "worktrees_root") {
|
|
36700
|
-
const diskFirst = this.tryDiscoverFromDisk(sid);
|
|
36701
|
-
if (diskFirst) {
|
|
36702
|
-
this.rememberSessionWorktrees(sid, diskFirst);
|
|
36703
|
-
return this.sessionParentPathAfterRemember(sid);
|
|
36704
|
-
}
|
|
36705
|
-
const fromRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, sid);
|
|
36706
|
-
if (fromRoot) {
|
|
36707
|
-
this.rememberSessionWorktrees(sid, fromRoot);
|
|
36708
|
-
return this.sessionParentPathAfterRemember(sid);
|
|
36709
|
-
}
|
|
36710
|
-
let cur = resolved;
|
|
36711
|
-
for (let i = 0; i < 16; i++) {
|
|
36712
|
-
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, sid);
|
|
36713
|
-
if (tryRoot) {
|
|
36714
|
-
this.rememberSessionWorktrees(sid, tryRoot);
|
|
36715
|
-
return this.sessionParentPathAfterRemember(sid);
|
|
36716
|
-
}
|
|
36717
|
-
const next = path26.dirname(cur);
|
|
36718
|
-
if (next === cur) break;
|
|
36719
|
-
cur = next;
|
|
36720
|
-
}
|
|
36721
|
-
}
|
|
36722
|
-
return resolved;
|
|
36723
|
-
}
|
|
36724
|
-
const parentKind = parseSessionParent(opts.sessionParent);
|
|
36725
|
-
if (parentKind === "bridge_root") {
|
|
36726
|
-
return void 0;
|
|
36727
|
-
}
|
|
36728
|
-
if (parentKind === "worktrees_root") {
|
|
36729
|
-
if (!opts.isNewSession) {
|
|
36730
|
-
const cached2 = this.sessionParentPathAfterRemember(sid);
|
|
36731
|
-
if (cached2) return cached2;
|
|
36732
|
-
const disc = this.tryDiscoverFromDisk(sid);
|
|
36733
|
-
if (disc) {
|
|
36734
|
-
this.rememberSessionWorktrees(sid, disc);
|
|
36735
|
-
return this.sessionParentPathAfterRemember(sid);
|
|
36736
|
-
}
|
|
36737
|
-
return void 0;
|
|
36738
|
-
}
|
|
36739
|
-
const prep2 = await prepareNewSessionWorktrees({
|
|
36740
|
-
worktreesRootPath: this.worktreesRootPath,
|
|
36741
|
-
bridgeRoot: getBridgeRoot(),
|
|
36742
|
-
sessionId: sid,
|
|
36743
|
-
layout: this.layout,
|
|
36744
|
-
log: this.log
|
|
36745
|
-
});
|
|
36746
|
-
if (!prep2) return void 0;
|
|
36747
|
-
this.rememberSessionWorktrees(sid, {
|
|
36748
|
-
sessionParentPath: prep2.sessionParentPath,
|
|
36749
|
-
workingTreeRelRoot: prep2.workingTreeRelRoot,
|
|
36750
|
-
repoCheckoutPaths: prep2.worktreePaths
|
|
36751
|
-
});
|
|
36752
|
-
return this.sessionParentPathAfterRemember(sid);
|
|
36753
|
-
}
|
|
36754
|
-
if (!opts.isNewSession) {
|
|
36755
|
-
const cached2 = this.sessionParentPathAfterRemember(sid);
|
|
36756
|
-
if (cached2) return cached2;
|
|
36757
|
-
const disc = this.tryDiscoverFromDisk(sid);
|
|
36758
|
-
if (disc) {
|
|
36759
|
-
this.rememberSessionWorktrees(sid, disc);
|
|
36760
|
-
return this.sessionParentPathAfterRemember(sid);
|
|
36761
|
-
}
|
|
36762
|
-
return void 0;
|
|
36763
|
-
}
|
|
36764
|
-
const prep = await prepareNewSessionWorktrees({
|
|
36860
|
+
return resolveIsolatedSessionParentPath(
|
|
36861
|
+
sessionId,
|
|
36862
|
+
this.cache,
|
|
36863
|
+
(sid) => this.ensureRepoCheckoutPathsForSession(sid)
|
|
36864
|
+
);
|
|
36865
|
+
}
|
|
36866
|
+
resolveSessionParentPathForPrompt(sessionId, opts) {
|
|
36867
|
+
return resolveSessionParentPathForPrompt({
|
|
36868
|
+
sessionId,
|
|
36869
|
+
cache: this.cache,
|
|
36765
36870
|
worktreesRootPath: this.worktreesRootPath,
|
|
36766
|
-
bridgeRoot: getBridgeRoot(),
|
|
36767
|
-
sessionId: sid,
|
|
36768
36871
|
layout: this.layout,
|
|
36769
|
-
log: this.log
|
|
36770
|
-
|
|
36771
|
-
|
|
36772
|
-
this.rememberSessionWorktrees(sid, {
|
|
36773
|
-
sessionParentPath: prep.sessionParentPath,
|
|
36774
|
-
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
36775
|
-
repoCheckoutPaths: prep.worktreePaths
|
|
36872
|
+
log: this.log,
|
|
36873
|
+
discover: (sid) => this.discover(sid),
|
|
36874
|
+
opts
|
|
36776
36875
|
});
|
|
36777
|
-
return this.sessionParentPathAfterRemember(sid);
|
|
36778
36876
|
}
|
|
36779
36877
|
async renameSessionBranch(sessionId, newBranch) {
|
|
36780
|
-
const paths = this.
|
|
36878
|
+
const paths = this.cache.getRepoCheckoutPathsRef(sessionId);
|
|
36781
36879
|
if (!paths?.length) return;
|
|
36782
36880
|
await renameSessionWorktreeBranches(paths, newBranch, this.log);
|
|
36783
36881
|
}
|
|
36784
|
-
/** True when this session uses an isolated worktree layout (not the bridge root). */
|
|
36785
36882
|
usesWorktreeSession(sessionId) {
|
|
36786
36883
|
if (!sessionId) return false;
|
|
36787
|
-
return this.
|
|
36884
|
+
return this.cache.hasSession(sessionId);
|
|
36788
36885
|
}
|
|
36789
|
-
/** Per-repo git checkout directories for this session (for snapshots, commits, change lists). */
|
|
36790
36886
|
getRepoCheckoutPathsForSession(sessionId) {
|
|
36791
36887
|
if (!sessionId) return void 0;
|
|
36792
|
-
|
|
36793
|
-
return paths?.length ? [...paths] : void 0;
|
|
36888
|
+
return this.cache.getRepoCheckoutPaths(sessionId);
|
|
36794
36889
|
}
|
|
36795
|
-
/**
|
|
36796
|
-
* Same paths as {@link getRepoCheckoutPathsForSession}, but loads from disk into memory when the CLI
|
|
36797
|
-
* restarted or maps were not yet populated (avoids discovering every repo under the worktrees root).
|
|
36798
|
-
*/
|
|
36799
36890
|
ensureRepoCheckoutPathsForSession(sessionId) {
|
|
36800
|
-
|
|
36801
|
-
const sid = sessionId.trim();
|
|
36802
|
-
const cached2 = this.sessionRepoCheckoutPaths.get(sid);
|
|
36803
|
-
if (cached2?.length) return [...cached2];
|
|
36804
|
-
const disc = this.tryDiscoverFromDisk(sid);
|
|
36805
|
-
if (disc?.repoCheckoutPaths.length) {
|
|
36806
|
-
this.rememberSessionWorktrees(sid, disc);
|
|
36807
|
-
return [...disc.repoCheckoutPaths];
|
|
36808
|
-
}
|
|
36809
|
-
return void 0;
|
|
36891
|
+
return ensureRepoCheckoutPathsForSession(sessionId, this.cache, (sid) => this.discover(sid));
|
|
36810
36892
|
}
|
|
36811
|
-
/** Session parent directory when in worktrees mode; null otherwise (same as {@link getIsolatedSessionParentPathForSession} path). */
|
|
36812
36893
|
getSessionWorktreeRootForSession(sessionId) {
|
|
36813
36894
|
return this.getIsolatedSessionParentPathForSession(sessionId);
|
|
36814
36895
|
}
|
|
36815
36896
|
async removeSessionWorktrees(sessionId) {
|
|
36816
|
-
const paths = this.
|
|
36817
|
-
this.sessionRepoCheckoutPaths.delete(sessionId);
|
|
36818
|
-
this.sessionParentPathBySession.delete(sessionId);
|
|
36819
|
-
this.sessionWorkingTreeRelRootBySession.delete(sessionId);
|
|
36897
|
+
const paths = this.cache.clearSession(sessionId);
|
|
36820
36898
|
if (!paths?.length) return;
|
|
36821
36899
|
await removeSessionWorktrees(paths, this.log);
|
|
36822
36900
|
}
|
|
36823
36901
|
async commitSession(params) {
|
|
36824
|
-
const paths = this.
|
|
36902
|
+
const paths = this.cache.getRepoCheckoutPathsRef(params.sessionId);
|
|
36825
36903
|
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
36826
36904
|
return commitSessionWorktrees({
|
|
36827
36905
|
paths: targets,
|
|
@@ -36830,28 +36908,17 @@ var SessionWorktreeManager = class {
|
|
|
36830
36908
|
push: params.push
|
|
36831
36909
|
});
|
|
36832
36910
|
}
|
|
36833
|
-
resolveCommitTargets(sessionId) {
|
|
36834
|
-
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
36835
|
-
if (paths?.length) return paths;
|
|
36836
|
-
const disc = this.tryDiscoverFromDisk(sessionId);
|
|
36837
|
-
if (disc?.repoCheckoutPaths.length) {
|
|
36838
|
-
this.rememberSessionWorktrees(sessionId, disc);
|
|
36839
|
-
return disc.repoCheckoutPaths;
|
|
36840
|
-
}
|
|
36841
|
-
return [getBridgeRoot()];
|
|
36842
|
-
}
|
|
36843
36911
|
async getSessionWorkingTreeStatus(sessionId) {
|
|
36844
|
-
return aggregateSessionPathsWorkingTreeStatus(
|
|
36912
|
+
return aggregateSessionPathsWorkingTreeStatus(
|
|
36913
|
+
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
36914
|
+
);
|
|
36845
36915
|
}
|
|
36846
|
-
/** Per-repo changed files vs HEAD (or a single commit vs parent) for the same git roots used for commit/push. */
|
|
36847
36916
|
async getSessionWorkingTreeChangeDetails(sessionId, opts) {
|
|
36848
|
-
const targets = this.
|
|
36849
|
-
const sessionWorkingTreeRelRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId) ?? null;
|
|
36850
|
-
const legacyNested = this.isLegacyNestedLayout(sessionId);
|
|
36917
|
+
const targets = resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid));
|
|
36851
36918
|
return getWorkingTreeChangeRepoDetails({
|
|
36852
36919
|
commitTargetPaths: targets,
|
|
36853
|
-
sessionWorktreeRootPath:
|
|
36854
|
-
legacyRepoNestedSessionLayout:
|
|
36920
|
+
sessionWorktreeRootPath: this.cache.getWorkingTreeRelRoot(sessionId),
|
|
36921
|
+
legacyRepoNestedSessionLayout: this.cache.isLegacyNestedLayout(sessionId),
|
|
36855
36922
|
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
36856
36923
|
basis: opts?.basis,
|
|
36857
36924
|
recentCommitsLimit: opts?.recentCommitsLimit
|
|
@@ -36859,7 +36926,9 @@ var SessionWorktreeManager = class {
|
|
|
36859
36926
|
}
|
|
36860
36927
|
async pushSessionUpstream(sessionId) {
|
|
36861
36928
|
try {
|
|
36862
|
-
await pushAheadOfUpstreamForPaths(
|
|
36929
|
+
await pushAheadOfUpstreamForPaths(
|
|
36930
|
+
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
36931
|
+
);
|
|
36863
36932
|
return { ok: true };
|
|
36864
36933
|
} catch (e) {
|
|
36865
36934
|
const err = e instanceof Error ? e.message : String(e);
|
|
@@ -36867,27 +36936,31 @@ var SessionWorktreeManager = class {
|
|
|
36867
36936
|
}
|
|
36868
36937
|
}
|
|
36869
36938
|
};
|
|
36939
|
+
|
|
36940
|
+
// src/worktrees/manager/default-worktrees-root-path.ts
|
|
36941
|
+
import * as path28 from "node:path";
|
|
36942
|
+
import os8 from "node:os";
|
|
36870
36943
|
function defaultWorktreesRootPath() {
|
|
36871
|
-
return
|
|
36944
|
+
return path28.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
36872
36945
|
}
|
|
36873
36946
|
|
|
36874
36947
|
// src/files/watch-file-index.ts
|
|
36875
36948
|
import { watch } from "node:fs";
|
|
36876
|
-
import
|
|
36949
|
+
import path33 from "node:path";
|
|
36877
36950
|
|
|
36878
36951
|
// src/files/index/paths.ts
|
|
36879
|
-
import
|
|
36952
|
+
import path29 from "node:path";
|
|
36880
36953
|
import crypto2 from "node:crypto";
|
|
36881
36954
|
function getCwdHashForFileIndex(resolvedCwd) {
|
|
36882
|
-
return crypto2.createHash("sha256").update(
|
|
36955
|
+
return crypto2.createHash("sha256").update(path29.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
36883
36956
|
}
|
|
36884
36957
|
|
|
36885
36958
|
// src/files/index/build-file-index.ts
|
|
36886
|
-
import
|
|
36959
|
+
import path31 from "node:path";
|
|
36887
36960
|
|
|
36888
36961
|
// src/files/index/walk-workspace-tree.ts
|
|
36889
36962
|
import fs25 from "node:fs";
|
|
36890
|
-
import
|
|
36963
|
+
import path30 from "node:path";
|
|
36891
36964
|
var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
36892
36965
|
"node_modules",
|
|
36893
36966
|
"bower_components",
|
|
@@ -36916,18 +36989,18 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
|
36916
36989
|
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
36917
36990
|
}
|
|
36918
36991
|
state.n++;
|
|
36919
|
-
const full =
|
|
36992
|
+
const full = path30.join(dir, name);
|
|
36920
36993
|
let stat3;
|
|
36921
36994
|
try {
|
|
36922
36995
|
stat3 = await fs25.promises.stat(full);
|
|
36923
36996
|
} catch {
|
|
36924
36997
|
continue;
|
|
36925
36998
|
}
|
|
36926
|
-
const
|
|
36999
|
+
const relative6 = path30.relative(baseDir, full).replace(/\\/g, "/");
|
|
36927
37000
|
if (stat3.isDirectory()) {
|
|
36928
37001
|
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
36929
37002
|
} else if (stat3.isFile()) {
|
|
36930
|
-
onFile(
|
|
37003
|
+
onFile(relative6);
|
|
36931
37004
|
}
|
|
36932
37005
|
}
|
|
36933
37006
|
}
|
|
@@ -37025,7 +37098,7 @@ async function collectWorkspacePathsAsync(resolved) {
|
|
|
37025
37098
|
}
|
|
37026
37099
|
async function buildFileIndexAsync(cwd) {
|
|
37027
37100
|
return withFileIndexSqliteLock(async () => {
|
|
37028
|
-
const resolved =
|
|
37101
|
+
const resolved = path31.resolve(cwd);
|
|
37029
37102
|
await yieldToEventLoop();
|
|
37030
37103
|
assertNotShutdown();
|
|
37031
37104
|
const paths = await collectWorkspacePathsAsync(resolved);
|
|
@@ -37037,7 +37110,7 @@ async function buildFileIndexAsync(cwd) {
|
|
|
37037
37110
|
}
|
|
37038
37111
|
|
|
37039
37112
|
// src/files/index/ensure-file-index.ts
|
|
37040
|
-
import
|
|
37113
|
+
import path32 from "node:path";
|
|
37041
37114
|
|
|
37042
37115
|
// src/files/index/search-file-index.ts
|
|
37043
37116
|
function escapeLikePattern(fragment) {
|
|
@@ -37089,7 +37162,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
|
37089
37162
|
|
|
37090
37163
|
// src/files/index/ensure-file-index.ts
|
|
37091
37164
|
async function ensureFileIndexAsync(cwd) {
|
|
37092
|
-
const resolved =
|
|
37165
|
+
const resolved = path32.resolve(cwd);
|
|
37093
37166
|
if (await bridgeFileIndexIsPopulated(resolved)) {
|
|
37094
37167
|
return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
|
|
37095
37168
|
}
|
|
@@ -37133,7 +37206,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
37133
37206
|
}
|
|
37134
37207
|
}
|
|
37135
37208
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
37136
|
-
const resolved =
|
|
37209
|
+
const resolved = path33.resolve(cwd);
|
|
37137
37210
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
37138
37211
|
if (e instanceof CliSqliteInterrupted) return;
|
|
37139
37212
|
console.error("[file-index] Initial index build failed:", e);
|
|
@@ -37163,7 +37236,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
37163
37236
|
}
|
|
37164
37237
|
|
|
37165
37238
|
// src/connection/create-bridge-connection.ts
|
|
37166
|
-
import * as
|
|
37239
|
+
import * as path44 from "node:path";
|
|
37167
37240
|
|
|
37168
37241
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
37169
37242
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -37185,15 +37258,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
|
|
|
37185
37258
|
|
|
37186
37259
|
// src/dev-servers/process/terminate-child-process.ts
|
|
37187
37260
|
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
37188
|
-
const exited = new Promise((
|
|
37189
|
-
proc.once("exit", () =>
|
|
37261
|
+
const exited = new Promise((resolve22) => {
|
|
37262
|
+
proc.once("exit", () => resolve22());
|
|
37190
37263
|
});
|
|
37191
37264
|
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
|
|
37192
37265
|
try {
|
|
37193
37266
|
proc.kill("SIGTERM");
|
|
37194
37267
|
} catch {
|
|
37195
37268
|
}
|
|
37196
|
-
await Promise.race([exited, new Promise((
|
|
37269
|
+
await Promise.race([exited, new Promise((resolve22) => setTimeout(resolve22, graceMs))]);
|
|
37197
37270
|
}
|
|
37198
37271
|
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
37199
37272
|
log2(
|
|
@@ -37473,10 +37546,10 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
37473
37546
|
import { spawn as spawn7 } from "node:child_process";
|
|
37474
37547
|
import fs29 from "node:fs";
|
|
37475
37548
|
import { tmpdir } from "node:os";
|
|
37476
|
-
import
|
|
37549
|
+
import path34 from "node:path";
|
|
37477
37550
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
37478
|
-
const tmpRoot = fs29.mkdtempSync(
|
|
37479
|
-
const logPath =
|
|
37551
|
+
const tmpRoot = fs29.mkdtempSync(path34.join(tmpdir(), "ba-devsrv-log-"));
|
|
37552
|
+
const logPath = path34.join(tmpRoot, "combined.log");
|
|
37480
37553
|
let logFd;
|
|
37481
37554
|
try {
|
|
37482
37555
|
logFd = fs29.openSync(logPath, "a");
|
|
@@ -37520,15 +37593,15 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
37520
37593
|
import { spawn as spawn8 } from "node:child_process";
|
|
37521
37594
|
import fs30 from "node:fs";
|
|
37522
37595
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
37523
|
-
import
|
|
37596
|
+
import path35 from "node:path";
|
|
37524
37597
|
function shSingleQuote(s) {
|
|
37525
37598
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
37526
37599
|
}
|
|
37527
37600
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
37528
|
-
const tmpRoot = fs30.mkdtempSync(
|
|
37529
|
-
const logPath =
|
|
37530
|
-
const innerPath =
|
|
37531
|
-
const runnerPath =
|
|
37601
|
+
const tmpRoot = fs30.mkdtempSync(path35.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
37602
|
+
const logPath = path35.join(tmpRoot, "combined.log");
|
|
37603
|
+
const innerPath = path35.join(tmpRoot, "_cmd.sh");
|
|
37604
|
+
const runnerPath = path35.join(tmpRoot, "_run.sh");
|
|
37532
37605
|
try {
|
|
37533
37606
|
fs30.writeFileSync(innerPath, `#!/bin/sh
|
|
37534
37607
|
${command}
|
|
@@ -37559,9 +37632,9 @@ cd ${shSingleQuote(cwd)}
|
|
|
37559
37632
|
}
|
|
37560
37633
|
}
|
|
37561
37634
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
37562
|
-
const tmpRoot = fs30.mkdtempSync(
|
|
37563
|
-
const logPath =
|
|
37564
|
-
const runnerPath =
|
|
37635
|
+
const tmpRoot = fs30.mkdtempSync(path35.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
37636
|
+
const logPath = path35.join(tmpRoot, "combined.log");
|
|
37637
|
+
const runnerPath = path35.join(tmpRoot, "_run.bat");
|
|
37565
37638
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
37566
37639
|
const com = process.env.ComSpec || "cmd.exe";
|
|
37567
37640
|
try {
|
|
@@ -38074,7 +38147,7 @@ async function proxyToLocal(request) {
|
|
|
38074
38147
|
};
|
|
38075
38148
|
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
38076
38149
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
38077
|
-
const once = await new Promise((
|
|
38150
|
+
const once = await new Promise((resolve22) => {
|
|
38078
38151
|
const req = mod.request(opts, (res) => {
|
|
38079
38152
|
const chunks = [];
|
|
38080
38153
|
res.on("data", (c) => chunks.push(c));
|
|
@@ -38085,7 +38158,7 @@ async function proxyToLocal(request) {
|
|
|
38085
38158
|
if (typeof v === "string") headers[k] = v;
|
|
38086
38159
|
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
38087
38160
|
}
|
|
38088
|
-
|
|
38161
|
+
resolve22({
|
|
38089
38162
|
id: request.id,
|
|
38090
38163
|
statusCode: res.statusCode ?? 0,
|
|
38091
38164
|
headers,
|
|
@@ -38094,7 +38167,7 @@ async function proxyToLocal(request) {
|
|
|
38094
38167
|
});
|
|
38095
38168
|
});
|
|
38096
38169
|
req.on("error", (err) => {
|
|
38097
|
-
|
|
38170
|
+
resolve22({
|
|
38098
38171
|
id: request.id,
|
|
38099
38172
|
statusCode: 0,
|
|
38100
38173
|
headers: {},
|
|
@@ -38503,13 +38576,13 @@ function createOnBridgeIdentified(opts) {
|
|
|
38503
38576
|
|
|
38504
38577
|
// src/skills/discover-local-agent-skills.ts
|
|
38505
38578
|
import fs31 from "node:fs";
|
|
38506
|
-
import
|
|
38579
|
+
import path36 from "node:path";
|
|
38507
38580
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
38508
38581
|
function discoverLocalSkills(cwd) {
|
|
38509
38582
|
const out = [];
|
|
38510
38583
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
38511
38584
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
38512
|
-
const base =
|
|
38585
|
+
const base = path36.join(cwd, rel);
|
|
38513
38586
|
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
38514
38587
|
let entries = [];
|
|
38515
38588
|
try {
|
|
@@ -38518,13 +38591,13 @@ function discoverLocalSkills(cwd) {
|
|
|
38518
38591
|
continue;
|
|
38519
38592
|
}
|
|
38520
38593
|
for (const name of entries) {
|
|
38521
|
-
const dir =
|
|
38594
|
+
const dir = path36.join(base, name);
|
|
38522
38595
|
try {
|
|
38523
38596
|
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
38524
38597
|
} catch {
|
|
38525
38598
|
continue;
|
|
38526
38599
|
}
|
|
38527
|
-
const skillMd =
|
|
38600
|
+
const skillMd = path36.join(dir, "SKILL.md");
|
|
38528
38601
|
if (!fs31.existsSync(skillMd)) continue;
|
|
38529
38602
|
const key = `${rel}/${name}`;
|
|
38530
38603
|
if (seenKeys.has(key)) continue;
|
|
@@ -38537,7 +38610,7 @@ function discoverLocalSkills(cwd) {
|
|
|
38537
38610
|
function discoverSkillLayoutRoots(cwd) {
|
|
38538
38611
|
const roots = [];
|
|
38539
38612
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
38540
|
-
const base =
|
|
38613
|
+
const base = path36.join(cwd, rel);
|
|
38541
38614
|
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
38542
38615
|
let entries = [];
|
|
38543
38616
|
try {
|
|
@@ -38547,13 +38620,13 @@ function discoverSkillLayoutRoots(cwd) {
|
|
|
38547
38620
|
}
|
|
38548
38621
|
const skills2 = [];
|
|
38549
38622
|
for (const name of entries) {
|
|
38550
|
-
const dir =
|
|
38623
|
+
const dir = path36.join(base, name);
|
|
38551
38624
|
try {
|
|
38552
38625
|
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
38553
38626
|
} catch {
|
|
38554
38627
|
continue;
|
|
38555
38628
|
}
|
|
38556
|
-
if (!fs31.existsSync(
|
|
38629
|
+
if (!fs31.existsSync(path36.join(dir, "SKILL.md"))) continue;
|
|
38557
38630
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
38558
38631
|
skills2.push({ name, relPath });
|
|
38559
38632
|
}
|
|
@@ -38676,7 +38749,9 @@ var API_TO_BRIDGE_MESSAGE_TYPES = [
|
|
|
38676
38749
|
"file_browser_search",
|
|
38677
38750
|
"skill_layout_request",
|
|
38678
38751
|
"install_skills",
|
|
38679
|
-
"refresh_local_skills"
|
|
38752
|
+
"refresh_local_skills",
|
|
38753
|
+
"bridge_git_context_request",
|
|
38754
|
+
"list_repo_branches_request"
|
|
38680
38755
|
];
|
|
38681
38756
|
var API_TO_BRIDGE_TYPE_SET = new Set(API_TO_BRIDGE_MESSAGE_TYPES);
|
|
38682
38757
|
function parseApiToBridgeMessage(data, log2) {
|
|
@@ -38760,9 +38835,6 @@ var handleAgentConfigMessage = (msg, deps) => {
|
|
|
38760
38835
|
handleBridgeAgentConfig(msg, deps);
|
|
38761
38836
|
};
|
|
38762
38837
|
|
|
38763
|
-
// src/prompt-turn-queue/runner.ts
|
|
38764
|
-
import fs32 from "node:fs";
|
|
38765
|
-
|
|
38766
38838
|
// src/prompt-turn-queue/client-report.ts
|
|
38767
38839
|
function sendPromptQueueClientReport(ws, queues) {
|
|
38768
38840
|
if (!ws) return false;
|
|
@@ -38832,8 +38904,36 @@ async function mergeServerQueueSnapshot(queueKey, serverTurns) {
|
|
|
38832
38904
|
return { queueKey, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), turns };
|
|
38833
38905
|
}
|
|
38834
38906
|
|
|
38835
|
-
// src/prompt-turn-queue/runner.ts
|
|
38836
|
-
|
|
38907
|
+
// src/prompt-turn-queue/runner/dispatch-local-prompt.ts
|
|
38908
|
+
function dispatchLocalPrompt(next, deps) {
|
|
38909
|
+
const pl = next.payload;
|
|
38910
|
+
const rawParent = pl["sessionParent"];
|
|
38911
|
+
const sessionParent = rawParent === "bridge_root" || rawParent === "worktrees_root" ? rawParent : void 0;
|
|
38912
|
+
const rawParentPath = pl["sessionParentPath"];
|
|
38913
|
+
const sessionParentPath = typeof rawParentPath === "string" && rawParentPath.trim() !== "" ? rawParentPath.trim() : void 0;
|
|
38914
|
+
const rawBaseBranches = pl["worktreeBaseBranches"];
|
|
38915
|
+
const worktreeBaseBranches = rawBaseBranches != null && typeof rawBaseBranches === "object" && !Array.isArray(rawBaseBranches) ? rawBaseBranches : void 0;
|
|
38916
|
+
const msg = {
|
|
38917
|
+
type: "prompt",
|
|
38918
|
+
sessionId: next.sessionId,
|
|
38919
|
+
runId: next.turnId,
|
|
38920
|
+
prompt: pl.prompt,
|
|
38921
|
+
mode: typeof pl.mode === "string" ? pl.mode : "agent",
|
|
38922
|
+
isNewSession: pl.isNewSession === true,
|
|
38923
|
+
...sessionParent ? { sessionParent } : {},
|
|
38924
|
+
...sessionParentPath ? { sessionParentPath } : {},
|
|
38925
|
+
...worktreeBaseBranches && Object.keys(worktreeBaseBranches).length > 0 ? { worktreeBaseBranches } : {},
|
|
38926
|
+
...typeof pl.followUpCatalogPromptId === "string" ? { followUpCatalogPromptId: pl.followUpCatalogPromptId } : {},
|
|
38927
|
+
...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
|
|
38928
|
+
...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
|
|
38929
|
+
...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {},
|
|
38930
|
+
...pl.agentConfig != null && typeof pl.agentConfig === "object" && !Array.isArray(pl.agentConfig) && Object.keys(pl.agentConfig).length > 0 ? { agentConfig: pl.agentConfig } : {},
|
|
38931
|
+
...Array.isArray(pl.attachments) && pl.attachments.length > 0 ? { attachments: pl.attachments } : {}
|
|
38932
|
+
};
|
|
38933
|
+
handleBridgePrompt(msg, deps);
|
|
38934
|
+
}
|
|
38935
|
+
|
|
38936
|
+
// src/prompt-turn-queue/runner/queue-selection.ts
|
|
38837
38937
|
function isRunnableServerState(s) {
|
|
38838
38938
|
return s === "queued" || s === "requeued" || s === "requeued_with_revert";
|
|
38839
38939
|
}
|
|
@@ -38852,6 +38952,28 @@ function pickNextRunnableTurn(turns) {
|
|
|
38852
38952
|
function hasRunningTurn(turns) {
|
|
38853
38953
|
return turns.some((t) => t.lastClientState === "running");
|
|
38854
38954
|
}
|
|
38955
|
+
|
|
38956
|
+
// src/prompt-turn-queue/runner/run-id-queue-key-map.ts
|
|
38957
|
+
var runIdToQueueKey = /* @__PURE__ */ new Map();
|
|
38958
|
+
function getRunIdQueueKey(runId) {
|
|
38959
|
+
return runIdToQueueKey.get(runId);
|
|
38960
|
+
}
|
|
38961
|
+
function setRunIdQueueKey(runId, queueKey) {
|
|
38962
|
+
runIdToQueueKey.set(runId, queueKey);
|
|
38963
|
+
}
|
|
38964
|
+
function deleteRunIdQueueKey(runId) {
|
|
38965
|
+
const queueKey = runIdToQueueKey.get(runId);
|
|
38966
|
+
runIdToQueueKey.delete(runId);
|
|
38967
|
+
return queueKey;
|
|
38968
|
+
}
|
|
38969
|
+
function syncRunningTurnQueueKeys(turns, queueKey) {
|
|
38970
|
+
for (const running of turns.filter((t) => t.lastClientState === "running")) {
|
|
38971
|
+
runIdToQueueKey.set(running.turnId, queueKey);
|
|
38972
|
+
}
|
|
38973
|
+
}
|
|
38974
|
+
|
|
38975
|
+
// src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
|
|
38976
|
+
import fs32 from "node:fs";
|
|
38855
38977
|
async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
38856
38978
|
if (next.serverState !== "requeued_with_revert") return true;
|
|
38857
38979
|
const sid = next.sessionId;
|
|
@@ -38873,30 +38995,23 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
38873
38995
|
}
|
|
38874
38996
|
return res.ok;
|
|
38875
38997
|
}
|
|
38876
|
-
|
|
38877
|
-
|
|
38878
|
-
|
|
38879
|
-
|
|
38880
|
-
const
|
|
38881
|
-
|
|
38882
|
-
const
|
|
38883
|
-
|
|
38884
|
-
|
|
38885
|
-
|
|
38886
|
-
|
|
38887
|
-
|
|
38888
|
-
|
|
38889
|
-
|
|
38890
|
-
...sessionParentPath ? { sessionParentPath } : {},
|
|
38891
|
-
...typeof pl.followUpCatalogPromptId === "string" ? { followUpCatalogPromptId: pl.followUpCatalogPromptId } : {},
|
|
38892
|
-
...Array.isArray(pl.sessionChangeSummaryFilePaths) ? { sessionChangeSummaryFilePaths: pl.sessionChangeSummaryFilePaths } : {},
|
|
38893
|
-
...Array.isArray(pl.sessionChangeSummaryFileSnapshots) ? { sessionChangeSummaryFileSnapshots: pl.sessionChangeSummaryFileSnapshots } : {},
|
|
38894
|
-
...typeof pl.agentType === "string" && pl.agentType.trim() ? { agentType: pl.agentType.trim() } : {},
|
|
38895
|
-
...pl.agentConfig != null && typeof pl.agentConfig === "object" && !Array.isArray(pl.agentConfig) && Object.keys(pl.agentConfig).length > 0 ? { agentConfig: pl.agentConfig } : {},
|
|
38896
|
-
...Array.isArray(pl.attachments) && pl.attachments.length > 0 ? { attachments: pl.attachments } : {}
|
|
38897
|
-
};
|
|
38898
|
-
handleBridgePrompt(msg, deps);
|
|
38998
|
+
|
|
38999
|
+
// src/prompt-turn-queue/runner/finalize-prompt-turn-on-bridge.ts
|
|
39000
|
+
async function finalizePromptTurnOnBridge(getWs, runId, success2, opts) {
|
|
39001
|
+
if (!runId) return false;
|
|
39002
|
+
const queueKey = deleteRunIdQueueKey(runId);
|
|
39003
|
+
if (!queueKey) return false;
|
|
39004
|
+
const f = await readPersistedQueue(queueKey);
|
|
39005
|
+
if (!f) return false;
|
|
39006
|
+
const t = f.turns.find((x) => x.turnId === runId);
|
|
39007
|
+
if (!t) return false;
|
|
39008
|
+
t.lastClientState = opts?.terminalClientState ?? (success2 ? "stopped" : "failed");
|
|
39009
|
+
await writePersistedQueue(f);
|
|
39010
|
+
sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: runId, clientState: t.lastClientState }] });
|
|
39011
|
+
return true;
|
|
38899
39012
|
}
|
|
39013
|
+
|
|
39014
|
+
// src/prompt-turn-queue/runner/apply-prompt-queue-state-from-server.ts
|
|
38900
39015
|
async function applyPromptQueueStateFromServer(msg, deps) {
|
|
38901
39016
|
const raw = msg.queues;
|
|
38902
39017
|
if (!raw || typeof raw !== "object") return;
|
|
@@ -38910,9 +39025,7 @@ async function applyPromptQueueStateFromServer(msg, deps) {
|
|
|
38910
39025
|
if (!Array.isArray(serverTurns)) continue;
|
|
38911
39026
|
const file2 = await readPersistedQueue(queueKey);
|
|
38912
39027
|
if (!file2) continue;
|
|
38913
|
-
|
|
38914
|
-
runIdToQueueKey.set(running.turnId, queueKey);
|
|
38915
|
-
}
|
|
39028
|
+
syncRunningTurnQueueKeys(file2.turns, queueKey);
|
|
38916
39029
|
}
|
|
38917
39030
|
for (const [queueKey, serverTurns] of Object.entries(raw)) {
|
|
38918
39031
|
if (!Array.isArray(serverTurns)) continue;
|
|
@@ -38957,7 +39070,7 @@ async function applyPromptQueueStateFromServer(msg, deps) {
|
|
|
38957
39070
|
}
|
|
38958
39071
|
next.lastClientState = "running";
|
|
38959
39072
|
await writePersistedQueue(file2);
|
|
38960
|
-
|
|
39073
|
+
setRunIdQueueKey(next.turnId, queueKey);
|
|
38961
39074
|
startedThisTick.add(next.turnId);
|
|
38962
39075
|
report[queueKey] = [{ turnId: next.turnId, clientState: "running" }];
|
|
38963
39076
|
}
|
|
@@ -38970,24 +39083,10 @@ async function applyPromptQueueStateFromServer(msg, deps) {
|
|
|
38970
39083
|
if (!file2) continue;
|
|
38971
39084
|
const running = file2.turns.find((t) => t.lastClientState === "running");
|
|
38972
39085
|
if (!running || !startedThisTick.has(running.turnId)) continue;
|
|
38973
|
-
if (
|
|
39086
|
+
if (getRunIdQueueKey(running.turnId) !== queueKey) continue;
|
|
38974
39087
|
dispatchLocalPrompt(running, deps);
|
|
38975
39088
|
}
|
|
38976
39089
|
}
|
|
38977
|
-
async function finalizePromptTurnOnBridge(getWs, runId, success2, opts) {
|
|
38978
|
-
if (!runId) return false;
|
|
38979
|
-
const queueKey = runIdToQueueKey.get(runId);
|
|
38980
|
-
runIdToQueueKey.delete(runId);
|
|
38981
|
-
if (!queueKey) return false;
|
|
38982
|
-
const f = await readPersistedQueue(queueKey);
|
|
38983
|
-
if (!f) return false;
|
|
38984
|
-
const t = f.turns.find((x) => x.turnId === runId);
|
|
38985
|
-
if (!t) return false;
|
|
38986
|
-
t.lastClientState = opts?.terminalClientState ?? (success2 ? "stopped" : "failed");
|
|
38987
|
-
await writePersistedQueue(f);
|
|
38988
|
-
sendPromptQueueClientReport(getWs(), { [queueKey]: [{ turnId: runId, clientState: t.lastClientState }] });
|
|
38989
|
-
return true;
|
|
38990
|
-
}
|
|
38991
39090
|
|
|
38992
39091
|
// src/agents/acp/from-bridge/bridge-prompt-wiring.ts
|
|
38993
39092
|
function createBridgePromptSenders(deps, getWs) {
|
|
@@ -39034,6 +39133,91 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
39034
39133
|
return { sendBridgeMessage, sendResult: sendResult2, sendSessionUpdate };
|
|
39035
39134
|
}
|
|
39036
39135
|
|
|
39136
|
+
// src/agents/acp/from-bridge/handle-bridge-prompt/parse-bridge-attachments.ts
|
|
39137
|
+
function parseBridgeAttachments(msg) {
|
|
39138
|
+
const raw = msg.attachments;
|
|
39139
|
+
if (!Array.isArray(raw)) return [];
|
|
39140
|
+
const out = [];
|
|
39141
|
+
for (const x of raw) {
|
|
39142
|
+
if (x === null || typeof x !== "object" || Array.isArray(x)) continue;
|
|
39143
|
+
const o = x;
|
|
39144
|
+
const id = typeof o.attachmentId === "string" ? o.attachmentId.trim() : "";
|
|
39145
|
+
if (!id) continue;
|
|
39146
|
+
const mt = typeof o.mimeType === "string" && o.mimeType.trim() ? o.mimeType.trim() : "application/octet-stream";
|
|
39147
|
+
out.push({ attachmentId: id, mimeType: mt });
|
|
39148
|
+
}
|
|
39149
|
+
return out;
|
|
39150
|
+
}
|
|
39151
|
+
|
|
39152
|
+
// src/agents/acp/from-bridge/handle-bridge-prompt/parse-worktree-base-branches.ts
|
|
39153
|
+
function parseWorktreeBaseBranches(msg) {
|
|
39154
|
+
const raw = msg.worktreeBaseBranches;
|
|
39155
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
39156
|
+
const out = {};
|
|
39157
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
39158
|
+
if (typeof k !== "string" || typeof v !== "string") continue;
|
|
39159
|
+
const rel = k.trim();
|
|
39160
|
+
const branch = v.trim();
|
|
39161
|
+
if (rel && branch) out[rel] = branch;
|
|
39162
|
+
}
|
|
39163
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
39164
|
+
}
|
|
39165
|
+
|
|
39166
|
+
// src/agents/acp/change-summary/decrypt-change-summary-file-input.ts
|
|
39167
|
+
function decryptChangeSummaryFileInput(row, e2ee) {
|
|
39168
|
+
if (!e2ee) return row;
|
|
39169
|
+
for (const field of ["path", "patchContent", "oldText", "newText"]) {
|
|
39170
|
+
const raw = row[field];
|
|
39171
|
+
if (typeof raw !== "string" || raw.trim() === "") continue;
|
|
39172
|
+
let o;
|
|
39173
|
+
try {
|
|
39174
|
+
o = JSON.parse(raw);
|
|
39175
|
+
} catch {
|
|
39176
|
+
continue;
|
|
39177
|
+
}
|
|
39178
|
+
if (!isE2eeEnvelope(o.ee)) continue;
|
|
39179
|
+
try {
|
|
39180
|
+
const d = e2ee.decryptMessage(o);
|
|
39181
|
+
const out = {
|
|
39182
|
+
path: typeof d.path === "string" ? d.path : row.path
|
|
39183
|
+
};
|
|
39184
|
+
if (d.directoryRemoved === true) out.directoryRemoved = true;
|
|
39185
|
+
else if (row.directoryRemoved === true) out.directoryRemoved = true;
|
|
39186
|
+
if (typeof d.patchContent === "string") out.patchContent = d.patchContent;
|
|
39187
|
+
else if (typeof row.patchContent === "string" && row.patchContent !== raw) out.patchContent = row.patchContent;
|
|
39188
|
+
if (typeof d.oldText === "string") out.oldText = d.oldText;
|
|
39189
|
+
else if (typeof row.oldText === "string") out.oldText = row.oldText;
|
|
39190
|
+
if (typeof d.newText === "string") out.newText = d.newText;
|
|
39191
|
+
else if (typeof row.newText === "string") out.newText = row.newText;
|
|
39192
|
+
return out;
|
|
39193
|
+
} catch {
|
|
39194
|
+
return row;
|
|
39195
|
+
}
|
|
39196
|
+
}
|
|
39197
|
+
return row;
|
|
39198
|
+
}
|
|
39199
|
+
|
|
39200
|
+
// src/agents/acp/change-summary/resolve-change-summary-prompt-for-agent.ts
|
|
39201
|
+
function hasSummarizePayload(f) {
|
|
39202
|
+
return f.directoryRemoved === true || f.patchContent != null && f.patchContent.trim() !== "" || f.oldText != null && f.oldText.trim() !== "" || f.newText != null && f.newText.trim() !== "";
|
|
39203
|
+
}
|
|
39204
|
+
function resolveChangeSummaryPromptForAgent(params) {
|
|
39205
|
+
const isBuiltin = params.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
|
|
39206
|
+
const snaps = params.sessionChangeSummaryFileSnapshots;
|
|
39207
|
+
if (!isBuiltin || !snaps || snaps.length === 0) {
|
|
39208
|
+
return { promptText: params.bridgePromptText, sessionChangeSummaryFilePaths: void 0 };
|
|
39209
|
+
}
|
|
39210
|
+
const decrypted = dedupeSessionFileChangesByPath(snaps.map((row) => decryptChangeSummaryFileInput(row, params.e2ee)));
|
|
39211
|
+
const withPayload = decrypted.filter(hasSummarizePayload);
|
|
39212
|
+
if (withPayload.length === 0) {
|
|
39213
|
+
return { promptText: params.bridgePromptText, sessionChangeSummaryFilePaths: void 0 };
|
|
39214
|
+
}
|
|
39215
|
+
return {
|
|
39216
|
+
promptText: buildSessionChangeSummaryPrompt(withPayload),
|
|
39217
|
+
sessionChangeSummaryFilePaths: withPayload.map((f) => f.path)
|
|
39218
|
+
};
|
|
39219
|
+
}
|
|
39220
|
+
|
|
39037
39221
|
// src/agents/acp/from-bridge/bridge-prompt-preamble.ts
|
|
39038
39222
|
import { execFile as execFile8 } from "node:child_process";
|
|
39039
39223
|
import { promisify as promisify8 } from "node:util";
|
|
@@ -39086,9 +39270,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
39086
39270
|
for (const item of raw) {
|
|
39087
39271
|
if (!item || typeof item !== "object") continue;
|
|
39088
39272
|
const o = item;
|
|
39089
|
-
const
|
|
39090
|
-
if (!
|
|
39091
|
-
const row = { path:
|
|
39273
|
+
const path46 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
39274
|
+
if (!path46) continue;
|
|
39275
|
+
const row = { path: path46 };
|
|
39092
39276
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
39093
39277
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
39094
39278
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -39105,76 +39289,73 @@ function parseFollowUpFieldsFromPromptMessage(msg) {
|
|
|
39105
39289
|
return { followUpCatalogPromptId, sessionChangeSummaryFilePaths, sessionChangeSummaryFileSnapshots };
|
|
39106
39290
|
}
|
|
39107
39291
|
|
|
39108
|
-
// src/agents/acp/
|
|
39109
|
-
function
|
|
39110
|
-
|
|
39111
|
-
|
|
39112
|
-
|
|
39113
|
-
|
|
39114
|
-
|
|
39115
|
-
|
|
39116
|
-
|
|
39117
|
-
|
|
39118
|
-
|
|
39119
|
-
|
|
39120
|
-
|
|
39121
|
-
|
|
39122
|
-
|
|
39123
|
-
|
|
39124
|
-
|
|
39125
|
-
|
|
39126
|
-
|
|
39127
|
-
|
|
39128
|
-
|
|
39129
|
-
|
|
39130
|
-
|
|
39131
|
-
|
|
39132
|
-
|
|
39133
|
-
|
|
39134
|
-
|
|
39135
|
-
|
|
39136
|
-
|
|
39137
|
-
|
|
39138
|
-
|
|
39139
|
-
|
|
39140
|
-
}
|
|
39141
|
-
|
|
39142
|
-
|
|
39143
|
-
|
|
39144
|
-
|
|
39145
|
-
|
|
39146
|
-
|
|
39147
|
-
|
|
39148
|
-
|
|
39149
|
-
|
|
39150
|
-
|
|
39151
|
-
}
|
|
39152
|
-
const decrypted = dedupeSessionFileChangesByPath(snaps.map((row) => decryptChangeSummaryFileInput(row, params.e2ee)));
|
|
39153
|
-
const withPayload = decrypted.filter(hasSummarizePayload);
|
|
39154
|
-
if (withPayload.length === 0) {
|
|
39155
|
-
return { promptText: params.bridgePromptText, sessionChangeSummaryFilePaths: void 0 };
|
|
39292
|
+
// src/agents/acp/from-bridge/handle-bridge-prompt/run-preamble-and-prompt.ts
|
|
39293
|
+
async function runPreambleAndPrompt(params) {
|
|
39294
|
+
const {
|
|
39295
|
+
deps,
|
|
39296
|
+
msg,
|
|
39297
|
+
getWs,
|
|
39298
|
+
log: log2,
|
|
39299
|
+
sessionWorktreeManager,
|
|
39300
|
+
sessionId,
|
|
39301
|
+
runId,
|
|
39302
|
+
promptText,
|
|
39303
|
+
attachments,
|
|
39304
|
+
mode,
|
|
39305
|
+
agentType,
|
|
39306
|
+
agentId,
|
|
39307
|
+
agentConfig,
|
|
39308
|
+
resolvedCwd,
|
|
39309
|
+
senders: { sendResult: sendResult2, sendSessionUpdate }
|
|
39310
|
+
} = params;
|
|
39311
|
+
const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
|
|
39312
|
+
await runBridgePromptPreamble({
|
|
39313
|
+
getWs,
|
|
39314
|
+
log: log2,
|
|
39315
|
+
sessionWorktreeManager,
|
|
39316
|
+
sessionId,
|
|
39317
|
+
runId,
|
|
39318
|
+
effectiveCwd
|
|
39319
|
+
});
|
|
39320
|
+
const {
|
|
39321
|
+
followUpCatalogPromptId,
|
|
39322
|
+
sessionChangeSummaryFilePaths: pathsFromBridge,
|
|
39323
|
+
sessionChangeSummaryFileSnapshots
|
|
39324
|
+
} = parseFollowUpFieldsFromPromptMessage(msg);
|
|
39325
|
+
const { promptText: resolvedPromptText, sessionChangeSummaryFilePaths } = resolveChangeSummaryPromptForAgent({
|
|
39326
|
+
followUpCatalogPromptId,
|
|
39327
|
+
sessionChangeSummaryFileSnapshots,
|
|
39328
|
+
bridgePromptText: promptText,
|
|
39329
|
+
e2ee: deps.e2ee
|
|
39330
|
+
});
|
|
39331
|
+
if (sessionChangeSummaryFileSnapshots && sessionChangeSummaryFileSnapshots.length > 0 && resolvedPromptText === promptText) {
|
|
39332
|
+
deps.log(
|
|
39333
|
+
"[Agent] Change-summary snapshots were present but the prompt was not rebuilt (decrypt failed or empty payloads); sending the bridge prompt as-is."
|
|
39334
|
+
);
|
|
39156
39335
|
}
|
|
39157
|
-
|
|
39158
|
-
|
|
39159
|
-
|
|
39160
|
-
|
|
39336
|
+
const pathsForUpload = sessionChangeSummaryFilePaths ?? pathsFromBridge;
|
|
39337
|
+
deps.acpManager.handlePrompt({
|
|
39338
|
+
promptText: resolvedPromptText,
|
|
39339
|
+
promptId: msg.id,
|
|
39340
|
+
sessionId,
|
|
39341
|
+
runId,
|
|
39342
|
+
mode,
|
|
39343
|
+
agentType,
|
|
39344
|
+
agentId,
|
|
39345
|
+
agentConfig,
|
|
39346
|
+
sessionParentPath: effectiveCwd,
|
|
39347
|
+
sendResult: sendResult2,
|
|
39348
|
+
sendSessionUpdate,
|
|
39349
|
+
followUpCatalogPromptId,
|
|
39350
|
+
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
39351
|
+
cloudApiBaseUrl: deps.cloudApiBaseUrl,
|
|
39352
|
+
getCloudAccessToken: deps.getCloudAccessToken,
|
|
39353
|
+
e2ee: deps.e2ee,
|
|
39354
|
+
...attachments.length > 0 ? { attachments } : {}
|
|
39355
|
+
});
|
|
39161
39356
|
}
|
|
39162
39357
|
|
|
39163
|
-
// src/agents/acp/from-bridge/handle-bridge-prompt.ts
|
|
39164
|
-
function parseBridgeAttachments(msg) {
|
|
39165
|
-
const raw = msg.attachments;
|
|
39166
|
-
if (!Array.isArray(raw)) return [];
|
|
39167
|
-
const out = [];
|
|
39168
|
-
for (const x of raw) {
|
|
39169
|
-
if (x === null || typeof x !== "object" || Array.isArray(x)) continue;
|
|
39170
|
-
const o = x;
|
|
39171
|
-
const id = typeof o.attachmentId === "string" ? o.attachmentId.trim() : "";
|
|
39172
|
-
if (!id) continue;
|
|
39173
|
-
const mt = typeof o.mimeType === "string" && o.mimeType.trim() ? o.mimeType.trim() : "application/octet-stream";
|
|
39174
|
-
out.push({ attachmentId: id, mimeType: mt });
|
|
39175
|
-
}
|
|
39176
|
-
return out;
|
|
39177
|
-
}
|
|
39358
|
+
// src/agents/acp/from-bridge/handle-bridge-prompt/handle-bridge-prompt.ts
|
|
39178
39359
|
function handleBridgePrompt(msg, deps) {
|
|
39179
39360
|
const { getWs, log: log2, acpManager, sessionWorktreeManager } = deps;
|
|
39180
39361
|
const rawPrompt = msg.prompt;
|
|
@@ -39183,12 +39364,12 @@ function handleBridgePrompt(msg, deps) {
|
|
|
39183
39364
|
const sessionId = msg.sessionId;
|
|
39184
39365
|
const runId = typeof msg.runId === "string" ? msg.runId : void 0;
|
|
39185
39366
|
const promptId = typeof msg.id === "string" ? msg.id : void 0;
|
|
39186
|
-
const
|
|
39367
|
+
const senders = createBridgePromptSenders(deps, getWs);
|
|
39187
39368
|
if (!promptText.trim() && attachments.length === 0) {
|
|
39188
39369
|
log2(
|
|
39189
39370
|
`[Bridge service] Prompt ignored: empty or missing prompt text (session ${typeof msg.sessionId === "string" ? msg.sessionId.slice(0, 8) : "\u2014"}\u2026, run ${typeof msg.runId === "string" ? msg.runId.slice(0, 8) : "\u2014"}\u2026).`
|
|
39190
39371
|
);
|
|
39191
|
-
sendBridgeMessage(
|
|
39372
|
+
senders.sendBridgeMessage(
|
|
39192
39373
|
{
|
|
39193
39374
|
type: "prompt_result",
|
|
39194
39375
|
...promptId ? { id: promptId } : {},
|
|
@@ -39210,57 +39391,50 @@ function handleBridgePrompt(msg, deps) {
|
|
|
39210
39391
|
const agentId = typeof rawAgentId === "string" && rawAgentId.trim() !== "" ? rawAgentId.trim() : null;
|
|
39211
39392
|
const mode = typeof msg.mode === "string" && msg.mode.trim() ? msg.mode.trim() : void 0;
|
|
39212
39393
|
const agentConfig = msg.agentConfig != null && typeof msg.agentConfig === "object" && !Array.isArray(msg.agentConfig) ? msg.agentConfig : void 0;
|
|
39394
|
+
const worktreeBaseBranches = parseWorktreeBaseBranches(msg);
|
|
39213
39395
|
acpManager.logPromptReceivedFromBridge({ agentType, mode });
|
|
39214
|
-
|
|
39215
|
-
|
|
39216
|
-
|
|
39396
|
+
void sessionWorktreeManager.resolveSessionParentPathForPrompt(sessionId, {
|
|
39397
|
+
isNewSession,
|
|
39398
|
+
sessionParent,
|
|
39399
|
+
sessionParentPath,
|
|
39400
|
+
...worktreeBaseBranches ? { worktreeBaseBranches } : {}
|
|
39401
|
+
}).then(
|
|
39402
|
+
(cwd) => runPreambleAndPrompt({
|
|
39403
|
+
deps,
|
|
39404
|
+
msg,
|
|
39217
39405
|
getWs,
|
|
39218
39406
|
log: log2,
|
|
39219
39407
|
sessionWorktreeManager,
|
|
39220
39408
|
sessionId,
|
|
39221
39409
|
runId,
|
|
39222
|
-
|
|
39223
|
-
|
|
39224
|
-
|
|
39225
|
-
|
|
39226
|
-
|
|
39227
|
-
|
|
39228
|
-
|
|
39229
|
-
|
|
39230
|
-
|
|
39231
|
-
|
|
39232
|
-
|
|
39233
|
-
|
|
39234
|
-
|
|
39235
|
-
|
|
39236
|
-
|
|
39237
|
-
|
|
39238
|
-
|
|
39239
|
-
}
|
|
39240
|
-
const pathsForUpload = sessionChangeSummaryFilePaths ?? pathsFromBridge;
|
|
39241
|
-
acpManager.handlePrompt({
|
|
39242
|
-
promptText: resolvedPromptText,
|
|
39243
|
-
promptId: msg.id,
|
|
39410
|
+
promptText,
|
|
39411
|
+
attachments,
|
|
39412
|
+
mode,
|
|
39413
|
+
agentType,
|
|
39414
|
+
agentId,
|
|
39415
|
+
agentConfig,
|
|
39416
|
+
resolvedCwd: cwd,
|
|
39417
|
+
senders
|
|
39418
|
+
})
|
|
39419
|
+
).catch((err) => {
|
|
39420
|
+
log2(`[Agent] Session parent path resolve failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
39421
|
+
void runPreambleAndPrompt({
|
|
39422
|
+
deps,
|
|
39423
|
+
msg,
|
|
39424
|
+
getWs,
|
|
39425
|
+
log: log2,
|
|
39426
|
+
sessionWorktreeManager,
|
|
39244
39427
|
sessionId,
|
|
39245
39428
|
runId,
|
|
39429
|
+
promptText,
|
|
39430
|
+
attachments,
|
|
39246
39431
|
mode,
|
|
39247
39432
|
agentType,
|
|
39248
39433
|
agentId,
|
|
39249
39434
|
agentConfig,
|
|
39250
|
-
|
|
39251
|
-
|
|
39252
|
-
sendSessionUpdate,
|
|
39253
|
-
followUpCatalogPromptId,
|
|
39254
|
-
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
39255
|
-
cloudApiBaseUrl: deps.cloudApiBaseUrl,
|
|
39256
|
-
getCloudAccessToken: deps.getCloudAccessToken,
|
|
39257
|
-
e2ee: deps.e2ee,
|
|
39258
|
-
...attachments.length > 0 ? { attachments } : {}
|
|
39435
|
+
resolvedCwd: void 0,
|
|
39436
|
+
senders
|
|
39259
39437
|
});
|
|
39260
|
-
}
|
|
39261
|
-
void sessionWorktreeManager.resolveSessionParentPathForPrompt(sessionId, { isNewSession, sessionParent, sessionParentPath }).then((cwd) => preambleAndPrompt(cwd)).catch((err) => {
|
|
39262
|
-
log2(`[Agent] Session parent path resolve failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
39263
|
-
void preambleAndPrompt(void 0);
|
|
39264
39438
|
});
|
|
39265
39439
|
}
|
|
39266
39440
|
|
|
@@ -39308,8 +39482,8 @@ function randomSecret() {
|
|
|
39308
39482
|
}
|
|
39309
39483
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
39310
39484
|
}
|
|
39311
|
-
async function requestPreviewApi(port, secret, method,
|
|
39312
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
39485
|
+
async function requestPreviewApi(port, secret, method, path46, body) {
|
|
39486
|
+
const url2 = `http://127.0.0.1:${port}${path46}`;
|
|
39313
39487
|
const headers = {
|
|
39314
39488
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
39315
39489
|
"Content-Type": "application/json"
|
|
@@ -39321,7 +39495,7 @@ async function requestPreviewApi(port, secret, method, path43, body) {
|
|
|
39321
39495
|
});
|
|
39322
39496
|
const data = await res.json().catch(() => ({}));
|
|
39323
39497
|
if (!res.ok) {
|
|
39324
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
39498
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path46}: ${res.status}`);
|
|
39325
39499
|
}
|
|
39326
39500
|
return data;
|
|
39327
39501
|
}
|
|
@@ -39489,11 +39663,11 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
39489
39663
|
import fs34 from "node:fs";
|
|
39490
39664
|
|
|
39491
39665
|
// src/files/ensure-under-cwd.ts
|
|
39492
|
-
import
|
|
39666
|
+
import path37 from "node:path";
|
|
39493
39667
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
39494
|
-
const normalized =
|
|
39495
|
-
const resolved =
|
|
39496
|
-
if (!resolved.startsWith(cwd +
|
|
39668
|
+
const normalized = path37.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
39669
|
+
const resolved = path37.resolve(cwd, normalized);
|
|
39670
|
+
if (!resolved.startsWith(cwd + path37.sep) && resolved !== cwd) {
|
|
39497
39671
|
return null;
|
|
39498
39672
|
}
|
|
39499
39673
|
return resolved;
|
|
@@ -39503,11 +39677,11 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
|
39503
39677
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
39504
39678
|
|
|
39505
39679
|
// src/files/list-dir/map-dir-entry.ts
|
|
39506
|
-
import
|
|
39680
|
+
import path38 from "node:path";
|
|
39507
39681
|
import fs33 from "node:fs";
|
|
39508
39682
|
async function mapDirEntry(d, relativePath, resolved) {
|
|
39509
|
-
const entryPath =
|
|
39510
|
-
const fullPath =
|
|
39683
|
+
const entryPath = path38.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
39684
|
+
const fullPath = path38.join(resolved, d.name);
|
|
39511
39685
|
let isDir = d.isDirectory();
|
|
39512
39686
|
if (d.isSymbolicLink()) {
|
|
39513
39687
|
try {
|
|
@@ -39858,13 +40032,13 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
|
39858
40032
|
}
|
|
39859
40033
|
|
|
39860
40034
|
// src/files/handle-file-browser-search.ts
|
|
39861
|
-
import
|
|
40035
|
+
import path39 from "node:path";
|
|
39862
40036
|
var SEARCH_LIMIT = 100;
|
|
39863
40037
|
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
39864
40038
|
void (async () => {
|
|
39865
40039
|
await yieldToEventLoop();
|
|
39866
40040
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
39867
|
-
const sessionParentPath =
|
|
40041
|
+
const sessionParentPath = path39.resolve(
|
|
39868
40042
|
sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
39869
40043
|
);
|
|
39870
40044
|
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
@@ -39984,7 +40158,7 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
39984
40158
|
|
|
39985
40159
|
// src/skills/install-remote-skills.ts
|
|
39986
40160
|
import fs38 from "node:fs";
|
|
39987
|
-
import
|
|
40161
|
+
import path40 from "node:path";
|
|
39988
40162
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
39989
40163
|
const installed2 = [];
|
|
39990
40164
|
if (!Array.isArray(items)) {
|
|
@@ -39995,11 +40169,11 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
39995
40169
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
39996
40170
|
continue;
|
|
39997
40171
|
}
|
|
39998
|
-
const skillDir =
|
|
40172
|
+
const skillDir = path40.join(cwd, targetDir, item.skillName);
|
|
39999
40173
|
for (const f of item.files) {
|
|
40000
40174
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
40001
|
-
const dest =
|
|
40002
|
-
fs38.mkdirSync(
|
|
40175
|
+
const dest = path40.join(skillDir, f.path);
|
|
40176
|
+
fs38.mkdirSync(path40.dirname(dest), { recursive: true });
|
|
40003
40177
|
if (f.text !== void 0) {
|
|
40004
40178
|
fs38.writeFileSync(dest, f.text, "utf8");
|
|
40005
40179
|
} else if (f.base64) {
|
|
@@ -40215,6 +40389,148 @@ var handleDevServersConfig = (msg, deps) => {
|
|
|
40215
40389
|
deps.devServerManager?.applyConfig(devServers ?? []);
|
|
40216
40390
|
};
|
|
40217
40391
|
|
|
40392
|
+
// src/git/bridge-git-context.ts
|
|
40393
|
+
import * as path41 from "node:path";
|
|
40394
|
+
|
|
40395
|
+
// src/git/branches/get-current-branch.ts
|
|
40396
|
+
async function getCurrentBranch(repoPath) {
|
|
40397
|
+
try {
|
|
40398
|
+
const git = cliSimpleGit(repoPath);
|
|
40399
|
+
const branch = await git.revparse(["--abbrev-ref", "HEAD"]);
|
|
40400
|
+
const trimmed2 = typeof branch === "string" ? branch.trim() : "";
|
|
40401
|
+
if (!trimmed2 || trimmed2 === "HEAD") return null;
|
|
40402
|
+
return trimmed2;
|
|
40403
|
+
} catch {
|
|
40404
|
+
return null;
|
|
40405
|
+
}
|
|
40406
|
+
}
|
|
40407
|
+
|
|
40408
|
+
// src/git/branches/list-repo-branch-refs.ts
|
|
40409
|
+
function normalizeBranchRef(raw) {
|
|
40410
|
+
const trimmed2 = raw.trim();
|
|
40411
|
+
if (!trimmed2 || trimmed2 === "HEAD") return null;
|
|
40412
|
+
if (trimmed2.startsWith("refs/heads/")) return trimmed2.slice("refs/heads/".length);
|
|
40413
|
+
if (trimmed2.startsWith("refs/remotes/")) return trimmed2.slice("refs/remotes/".length);
|
|
40414
|
+
return trimmed2;
|
|
40415
|
+
}
|
|
40416
|
+
async function listRepoBranchRefs(repoPath) {
|
|
40417
|
+
try {
|
|
40418
|
+
const git = cliSimpleGit(repoPath);
|
|
40419
|
+
const out = await git.raw([
|
|
40420
|
+
"for-each-ref",
|
|
40421
|
+
"--sort=-committerdate",
|
|
40422
|
+
"--format=%(refname:short)",
|
|
40423
|
+
"refs/heads",
|
|
40424
|
+
"refs/remotes"
|
|
40425
|
+
]);
|
|
40426
|
+
const lines = out.split("\n").map((line) => normalizeBranchRef(line)).filter((line) => Boolean(line));
|
|
40427
|
+
const seen = /* @__PURE__ */ new Set();
|
|
40428
|
+
const ordered = [];
|
|
40429
|
+
for (const name of lines) {
|
|
40430
|
+
if (seen.has(name)) continue;
|
|
40431
|
+
seen.add(name);
|
|
40432
|
+
ordered.push(name);
|
|
40433
|
+
}
|
|
40434
|
+
return ordered;
|
|
40435
|
+
} catch {
|
|
40436
|
+
return [];
|
|
40437
|
+
}
|
|
40438
|
+
}
|
|
40439
|
+
|
|
40440
|
+
// src/git/bridge-git-context.ts
|
|
40441
|
+
function folderNameForRelPath(relPath, bridgeRoot) {
|
|
40442
|
+
if (relPath === "." || relPath === "") {
|
|
40443
|
+
return path41.basename(path41.resolve(bridgeRoot)) || "repo";
|
|
40444
|
+
}
|
|
40445
|
+
return path41.basename(relPath) || relPath;
|
|
40446
|
+
}
|
|
40447
|
+
async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
40448
|
+
const root = path41.resolve(bridgeRoot);
|
|
40449
|
+
if (await isGitRepoDirectory(root)) {
|
|
40450
|
+
const remoteUrl = await getRemoteOriginUrl(root);
|
|
40451
|
+
return [{ absolutePath: root, remoteUrl }];
|
|
40452
|
+
}
|
|
40453
|
+
const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
|
|
40454
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
40455
|
+
for (const repo of [...deep, ...shallow]) {
|
|
40456
|
+
byPath.set(path41.resolve(repo.absolutePath), repo);
|
|
40457
|
+
}
|
|
40458
|
+
return [...byPath.values()];
|
|
40459
|
+
}
|
|
40460
|
+
async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
40461
|
+
const bridgeResolved = path41.resolve(bridgeRoot);
|
|
40462
|
+
const repos = await discoverGitReposForBridgeContext(bridgeResolved);
|
|
40463
|
+
const rows = [];
|
|
40464
|
+
for (const repo of repos) {
|
|
40465
|
+
let rel = path41.relative(bridgeResolved, repo.absolutePath);
|
|
40466
|
+
if (rel.startsWith("..") || path41.isAbsolute(rel)) continue;
|
|
40467
|
+
const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
40468
|
+
const currentBranch = await getCurrentBranch(repo.absolutePath);
|
|
40469
|
+
const remoteUrl = repo.remoteUrl.trim() || null;
|
|
40470
|
+
rows.push({
|
|
40471
|
+
relPath,
|
|
40472
|
+
folderName: folderNameForRelPath(relPath, bridgeResolved),
|
|
40473
|
+
currentBranch,
|
|
40474
|
+
remoteUrl
|
|
40475
|
+
});
|
|
40476
|
+
}
|
|
40477
|
+
rows.sort((a, b) => a.relPath.localeCompare(b.relPath));
|
|
40478
|
+
return rows;
|
|
40479
|
+
}
|
|
40480
|
+
async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
40481
|
+
const bridgeResolved = path41.resolve(bridgeRoot);
|
|
40482
|
+
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
40483
|
+
const repoPath = rel === "" ? bridgeResolved : path41.join(bridgeResolved, rel);
|
|
40484
|
+
const resolved = path41.resolve(repoPath);
|
|
40485
|
+
if (!resolved.startsWith(bridgeResolved + path41.sep) && resolved !== bridgeResolved) {
|
|
40486
|
+
return [];
|
|
40487
|
+
}
|
|
40488
|
+
return listRepoBranchRefs(resolved);
|
|
40489
|
+
}
|
|
40490
|
+
|
|
40491
|
+
// src/routing/handlers/bridge-git-context-messages.ts
|
|
40492
|
+
function handleBridgeGitContextRequestMessage(msg, getWs) {
|
|
40493
|
+
void (async () => {
|
|
40494
|
+
const socket = getWs();
|
|
40495
|
+
if (!socket) return;
|
|
40496
|
+
try {
|
|
40497
|
+
const repos = await getBridgeGitContext();
|
|
40498
|
+
sendWsMessage(socket, { type: "bridge_git_context_response", id: msg.id, repos });
|
|
40499
|
+
} catch (e) {
|
|
40500
|
+
sendWsMessage(socket, {
|
|
40501
|
+
type: "bridge_git_context_response",
|
|
40502
|
+
id: msg.id,
|
|
40503
|
+
error: e instanceof Error ? e.message : String(e)
|
|
40504
|
+
});
|
|
40505
|
+
}
|
|
40506
|
+
})();
|
|
40507
|
+
}
|
|
40508
|
+
function handleListRepoBranchesRequestMessage(msg, getWs) {
|
|
40509
|
+
void (async () => {
|
|
40510
|
+
const socket = getWs();
|
|
40511
|
+
if (!socket) return;
|
|
40512
|
+
const repoRelPath = typeof msg.repoRelPath === "string" ? msg.repoRelPath.trim() : "";
|
|
40513
|
+
if (!repoRelPath) {
|
|
40514
|
+
sendWsMessage(socket, {
|
|
40515
|
+
type: "list_repo_branches_response",
|
|
40516
|
+
id: msg.id,
|
|
40517
|
+
error: "repoRelPath required"
|
|
40518
|
+
});
|
|
40519
|
+
return;
|
|
40520
|
+
}
|
|
40521
|
+
try {
|
|
40522
|
+
const branches = await listRepoBranchesForBridge(repoRelPath);
|
|
40523
|
+
sendWsMessage(socket, { type: "list_repo_branches_response", id: msg.id, branches });
|
|
40524
|
+
} catch (e) {
|
|
40525
|
+
sendWsMessage(socket, {
|
|
40526
|
+
type: "list_repo_branches_response",
|
|
40527
|
+
id: msg.id,
|
|
40528
|
+
error: e instanceof Error ? e.message : String(e)
|
|
40529
|
+
});
|
|
40530
|
+
}
|
|
40531
|
+
})();
|
|
40532
|
+
}
|
|
40533
|
+
|
|
40218
40534
|
// src/routing/dispatch-bridge-message.ts
|
|
40219
40535
|
function dispatchBridgeMessage(msg, deps) {
|
|
40220
40536
|
switch (msg.type) {
|
|
@@ -40278,6 +40594,12 @@ function dispatchBridgeMessage(msg, deps) {
|
|
|
40278
40594
|
case "refresh_local_skills":
|
|
40279
40595
|
handleRefreshLocalSkills(msg, deps);
|
|
40280
40596
|
break;
|
|
40597
|
+
case "bridge_git_context_request":
|
|
40598
|
+
handleBridgeGitContextRequestMessage(msg, deps.getWs);
|
|
40599
|
+
break;
|
|
40600
|
+
case "list_repo_branches_request":
|
|
40601
|
+
handleListRepoBranchesRequestMessage(msg, deps.getWs);
|
|
40602
|
+
break;
|
|
40281
40603
|
}
|
|
40282
40604
|
}
|
|
40283
40605
|
|
|
@@ -40649,10 +40971,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
|
40649
40971
|
}
|
|
40650
40972
|
|
|
40651
40973
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
40652
|
-
import * as
|
|
40974
|
+
import * as path43 from "node:path";
|
|
40653
40975
|
|
|
40654
40976
|
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
40655
|
-
import * as
|
|
40977
|
+
import * as path42 from "node:path";
|
|
40656
40978
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
40657
40979
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true } = params;
|
|
40658
40980
|
if (isCliImmediateShutdownRequested()) return false;
|
|
@@ -40692,7 +41014,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
40692
41014
|
if (isCliImmediateShutdownRequested()) return false;
|
|
40693
41015
|
handle = await resolved.createClient({
|
|
40694
41016
|
command: resolved.command,
|
|
40695
|
-
cwd:
|
|
41017
|
+
cwd: path42.resolve(cwd),
|
|
40696
41018
|
backendAgentType: agentType,
|
|
40697
41019
|
sessionMode: "agent",
|
|
40698
41020
|
persistedAcpSessionId: null,
|
|
@@ -40766,7 +41088,7 @@ async function probeAgentCapabilitiesForDetectedTypes(params) {
|
|
|
40766
41088
|
async function warmupAgentCapabilitiesOnConnect(params) {
|
|
40767
41089
|
const { workspaceId, log: log2, getWs } = params;
|
|
40768
41090
|
if (isCliImmediateShutdownRequested()) return;
|
|
40769
|
-
const cwd =
|
|
41091
|
+
const cwd = path43.resolve(getBridgeRoot());
|
|
40770
41092
|
async function sendBatchFromCache() {
|
|
40771
41093
|
const socket = getWs();
|
|
40772
41094
|
if (!socket || socket.readyState !== wrapper_default.OPEN) return;
|
|
@@ -40933,8 +41255,8 @@ async function createBridgeConnection(options) {
|
|
|
40933
41255
|
getCloudAccessToken: () => tokens.accessToken
|
|
40934
41256
|
};
|
|
40935
41257
|
const identifyReportedPaths = {
|
|
40936
|
-
bridgeRootPath:
|
|
40937
|
-
worktreesRootPath:
|
|
41258
|
+
bridgeRootPath: path44.resolve(getBridgeRoot()),
|
|
41259
|
+
worktreesRootPath: path44.resolve(worktreesRootPath)
|
|
40938
41260
|
};
|
|
40939
41261
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
40940
41262
|
state,
|
|
@@ -41188,7 +41510,7 @@ async function runCliAction(program2, opts) {
|
|
|
41188
41510
|
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
41189
41511
|
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);
|
|
41190
41512
|
if (bridgeRootOpt) {
|
|
41191
|
-
const resolvedBridgeRoot =
|
|
41513
|
+
const resolvedBridgeRoot = path45.resolve(process.cwd(), bridgeRootOpt);
|
|
41192
41514
|
try {
|
|
41193
41515
|
const st = fs40.statSync(resolvedBridgeRoot);
|
|
41194
41516
|
if (!st.isDirectory()) {
|
|
@@ -41210,7 +41532,7 @@ async function runCliAction(program2, opts) {
|
|
|
41210
41532
|
);
|
|
41211
41533
|
let worktreesRootPath;
|
|
41212
41534
|
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
41213
|
-
worktreesRootPath =
|
|
41535
|
+
worktreesRootPath = path45.resolve(opts.worktreesRoot.trim());
|
|
41214
41536
|
}
|
|
41215
41537
|
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
41216
41538
|
if (e2eCertificates) {
|