@buildautomaton/cli 0.1.49 → 0.1.50
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 +1229 -943
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1208 -922
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -973,8 +973,8 @@ var require_command = __commonJS({
|
|
|
973
973
|
"../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
|
|
974
974
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
975
975
|
var childProcess2 = __require("node:child_process");
|
|
976
|
-
var
|
|
977
|
-
var
|
|
976
|
+
var path55 = __require("node:path");
|
|
977
|
+
var fs46 = __require("node:fs");
|
|
978
978
|
var process8 = __require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
980
980
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1906,11 +1906,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1906
1906
|
let launchWithNode = false;
|
|
1907
1907
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1908
1908
|
function findFile(baseDir, baseName) {
|
|
1909
|
-
const localBin =
|
|
1910
|
-
if (
|
|
1911
|
-
if (sourceExt.includes(
|
|
1909
|
+
const localBin = path55.resolve(baseDir, baseName);
|
|
1910
|
+
if (fs46.existsSync(localBin)) return localBin;
|
|
1911
|
+
if (sourceExt.includes(path55.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
|
-
(ext) =>
|
|
1913
|
+
(ext) => fs46.existsSync(`${localBin}${ext}`)
|
|
1914
1914
|
);
|
|
1915
1915
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1916
1916
|
return void 0;
|
|
@@ -1922,21 +1922,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1922
1922
|
if (this._scriptPath) {
|
|
1923
1923
|
let resolvedScriptPath;
|
|
1924
1924
|
try {
|
|
1925
|
-
resolvedScriptPath =
|
|
1925
|
+
resolvedScriptPath = fs46.realpathSync(this._scriptPath);
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
1929
|
-
executableDir =
|
|
1930
|
-
|
|
1929
|
+
executableDir = path55.resolve(
|
|
1930
|
+
path55.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 = path55.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path55.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(path55.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 = path55.basename(filename, path55.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(path56) {
|
|
2805
|
+
if (path56 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path56;
|
|
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: path55, errorMaps, issueData } = params;
|
|
7065
|
+
const fullPath = [...path55, ...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, path55, key) {
|
|
7374
7374
|
this._cachedPath = [];
|
|
7375
7375
|
this.parent = parent;
|
|
7376
7376
|
this.data = value;
|
|
7377
|
-
this._path =
|
|
7377
|
+
this._path = path55;
|
|
7378
7378
|
this._key = key;
|
|
7379
7379
|
}
|
|
7380
7380
|
get path() {
|
|
@@ -11099,15 +11099,15 @@ function assignProp(target, prop, value) {
|
|
|
11099
11099
|
configurable: true
|
|
11100
11100
|
});
|
|
11101
11101
|
}
|
|
11102
|
-
function getElementAtPath(obj,
|
|
11103
|
-
if (!
|
|
11102
|
+
function getElementAtPath(obj, path55) {
|
|
11103
|
+
if (!path55)
|
|
11104
11104
|
return obj;
|
|
11105
|
-
return
|
|
11105
|
+
return path55.reduce((acc, key) => acc?.[key], obj);
|
|
11106
11106
|
}
|
|
11107
11107
|
function promiseAllObject(promisesObj) {
|
|
11108
11108
|
const keys = Object.keys(promisesObj);
|
|
11109
|
-
const
|
|
11110
|
-
return Promise.all(
|
|
11109
|
+
const promises11 = keys.map((key) => promisesObj[key]);
|
|
11110
|
+
return Promise.all(promises11).then((results) => {
|
|
11111
11111
|
const resolvedObj = {};
|
|
11112
11112
|
for (let i = 0; i < keys.length; i++) {
|
|
11113
11113
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -11351,11 +11351,11 @@ function aborted(x, startIndex = 0) {
|
|
|
11351
11351
|
}
|
|
11352
11352
|
return false;
|
|
11353
11353
|
}
|
|
11354
|
-
function prefixIssues(
|
|
11354
|
+
function prefixIssues(path55, issues) {
|
|
11355
11355
|
return issues.map((iss) => {
|
|
11356
11356
|
var _a2;
|
|
11357
11357
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
11358
|
-
iss.path.unshift(
|
|
11358
|
+
iss.path.unshift(path55);
|
|
11359
11359
|
return iss;
|
|
11360
11360
|
});
|
|
11361
11361
|
}
|
|
@@ -11544,7 +11544,7 @@ function treeifyError(error40, _mapper) {
|
|
|
11544
11544
|
return issue2.message;
|
|
11545
11545
|
};
|
|
11546
11546
|
const result = { errors: [] };
|
|
11547
|
-
const processError = (error41,
|
|
11547
|
+
const processError = (error41, path55 = []) => {
|
|
11548
11548
|
var _a2, _b;
|
|
11549
11549
|
for (const issue2 of error41.issues) {
|
|
11550
11550
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -11554,7 +11554,7 @@ function treeifyError(error40, _mapper) {
|
|
|
11554
11554
|
} else if (issue2.code === "invalid_element") {
|
|
11555
11555
|
processError({ issues: issue2.issues }, issue2.path);
|
|
11556
11556
|
} else {
|
|
11557
|
-
const fullpath = [...
|
|
11557
|
+
const fullpath = [...path55, ...issue2.path];
|
|
11558
11558
|
if (fullpath.length === 0) {
|
|
11559
11559
|
result.errors.push(mapper(issue2));
|
|
11560
11560
|
continue;
|
|
@@ -11584,9 +11584,9 @@ function treeifyError(error40, _mapper) {
|
|
|
11584
11584
|
processError(error40);
|
|
11585
11585
|
return result;
|
|
11586
11586
|
}
|
|
11587
|
-
function toDotPath(
|
|
11587
|
+
function toDotPath(path55) {
|
|
11588
11588
|
const segs = [];
|
|
11589
|
-
for (const seg of
|
|
11589
|
+
for (const seg of path55) {
|
|
11590
11590
|
if (typeof seg === "number")
|
|
11591
11591
|
segs.push(`[${seg}]`);
|
|
11592
11592
|
else if (typeof seg === "symbol")
|
|
@@ -24049,8 +24049,8 @@ var init_acp = __esm({
|
|
|
24049
24049
|
this.#requestHandler = requestHandler;
|
|
24050
24050
|
this.#notificationHandler = notificationHandler;
|
|
24051
24051
|
this.#stream = stream;
|
|
24052
|
-
this.#closedPromise = new Promise((
|
|
24053
|
-
this.#abortController.signal.addEventListener("abort", () =>
|
|
24052
|
+
this.#closedPromise = new Promise((resolve28) => {
|
|
24053
|
+
this.#abortController.signal.addEventListener("abort", () => resolve28());
|
|
24054
24054
|
});
|
|
24055
24055
|
this.#receive();
|
|
24056
24056
|
}
|
|
@@ -24199,8 +24199,8 @@ var init_acp = __esm({
|
|
|
24199
24199
|
}
|
|
24200
24200
|
async sendRequest(method, params) {
|
|
24201
24201
|
const id = this.#nextRequestId++;
|
|
24202
|
-
const responsePromise = new Promise((
|
|
24203
|
-
this.#pendingResponses.set(id, { resolve:
|
|
24202
|
+
const responsePromise = new Promise((resolve28, reject) => {
|
|
24203
|
+
this.#pendingResponses.set(id, { resolve: resolve28, reject });
|
|
24204
24204
|
});
|
|
24205
24205
|
await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
|
|
24206
24206
|
return responsePromise;
|
|
@@ -25069,10 +25069,10 @@ var require_src2 = __commonJS({
|
|
|
25069
25069
|
var fs_1 = __require("fs");
|
|
25070
25070
|
var debug_1 = __importDefault(require_src());
|
|
25071
25071
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
25072
|
-
function check2(
|
|
25073
|
-
log2(`checking %s`,
|
|
25072
|
+
function check2(path55, isFile, isDirectory) {
|
|
25073
|
+
log2(`checking %s`, path55);
|
|
25074
25074
|
try {
|
|
25075
|
-
const stat3 = fs_1.statSync(
|
|
25075
|
+
const stat3 = fs_1.statSync(path55);
|
|
25076
25076
|
if (stat3.isFile() && isFile) {
|
|
25077
25077
|
log2(`[OK] path represents a file`);
|
|
25078
25078
|
return true;
|
|
@@ -25092,8 +25092,8 @@ var require_src2 = __commonJS({
|
|
|
25092
25092
|
throw e;
|
|
25093
25093
|
}
|
|
25094
25094
|
}
|
|
25095
|
-
function exists2(
|
|
25096
|
-
return check2(
|
|
25095
|
+
function exists2(path55, type = exports.READABLE) {
|
|
25096
|
+
return check2(path55, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
25097
25097
|
}
|
|
25098
25098
|
exports.exists = exists2;
|
|
25099
25099
|
exports.FILE = 1;
|
|
@@ -25174,15 +25174,15 @@ var {
|
|
|
25174
25174
|
} = import_index.default;
|
|
25175
25175
|
|
|
25176
25176
|
// src/cli-version.ts
|
|
25177
|
-
var CLI_VERSION = "0.1.
|
|
25177
|
+
var CLI_VERSION = "0.1.50".length > 0 ? "0.1.50" : "0.0.0-dev";
|
|
25178
25178
|
|
|
25179
25179
|
// src/cli/defaults.ts
|
|
25180
25180
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
25181
25181
|
var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
25182
25182
|
|
|
25183
25183
|
// src/cli/run-cli-action.ts
|
|
25184
|
-
import * as
|
|
25185
|
-
import * as
|
|
25184
|
+
import * as fs45 from "node:fs";
|
|
25185
|
+
import * as path54 from "node:path";
|
|
25186
25186
|
|
|
25187
25187
|
// src/cli-log-level.ts
|
|
25188
25188
|
var verbosity = "info";
|
|
@@ -26297,14 +26297,14 @@ var baseOpen = async (options) => {
|
|
|
26297
26297
|
}
|
|
26298
26298
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
26299
26299
|
if (options.wait) {
|
|
26300
|
-
return new Promise((
|
|
26300
|
+
return new Promise((resolve28, reject) => {
|
|
26301
26301
|
subprocess.once("error", reject);
|
|
26302
26302
|
subprocess.once("close", (exitCode) => {
|
|
26303
26303
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
26304
26304
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
26305
26305
|
return;
|
|
26306
26306
|
}
|
|
26307
|
-
|
|
26307
|
+
resolve28(subprocess);
|
|
26308
26308
|
});
|
|
26309
26309
|
});
|
|
26310
26310
|
}
|
|
@@ -26848,8 +26848,8 @@ function runPendingAuth(options) {
|
|
|
26848
26848
|
let hasOpenedBrowser = false;
|
|
26849
26849
|
let resolved = false;
|
|
26850
26850
|
let resolveAuth;
|
|
26851
|
-
const authPromise = new Promise((
|
|
26852
|
-
resolveAuth =
|
|
26851
|
+
const authPromise = new Promise((resolve28) => {
|
|
26852
|
+
resolveAuth = resolve28;
|
|
26853
26853
|
});
|
|
26854
26854
|
let reconnectAttempt = 0;
|
|
26855
26855
|
const signInQuiet = createEmptyReconnectQuietSlot();
|
|
@@ -27000,7 +27000,7 @@ import sqliteWasm from "node-sqlite3-wasm";
|
|
|
27000
27000
|
|
|
27001
27001
|
// src/runtime/yield-to-event-loop.ts
|
|
27002
27002
|
function yieldToEventLoop() {
|
|
27003
|
-
return new Promise((
|
|
27003
|
+
return new Promise((resolve28) => setImmediate(resolve28));
|
|
27004
27004
|
}
|
|
27005
27005
|
|
|
27006
27006
|
// src/sqlite/cli-sqlite-paths.ts
|
|
@@ -28117,9 +28117,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
28117
28117
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
28118
28118
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
28119
28119
|
if (!rawPath || !summary) continue;
|
|
28120
|
-
const
|
|
28121
|
-
if (!
|
|
28122
|
-
rows.push({ path:
|
|
28120
|
+
const path55 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
28121
|
+
if (!path55) continue;
|
|
28122
|
+
rows.push({ path: path55, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
28123
28123
|
}
|
|
28124
28124
|
return rows;
|
|
28125
28125
|
}
|
|
@@ -28337,7 +28337,7 @@ var GitRepoMetaSchema = external_exports.object({
|
|
|
28337
28337
|
updatedAt: external_exports.string()
|
|
28338
28338
|
});
|
|
28339
28339
|
|
|
28340
|
-
// ../types/src/bridge-mcp-
|
|
28340
|
+
// ../types/src/mcp/bridge-mcp-constants.ts
|
|
28341
28341
|
var GET_INTEGRATION_CONTENT_TOOL = "get_integration_content";
|
|
28342
28342
|
var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
|
|
28343
28343
|
var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
|
|
@@ -28631,10 +28631,10 @@ async function killChildProcessTreeGracefully(child, graceMs = ACP_PROCESS_TREE_
|
|
|
28631
28631
|
}
|
|
28632
28632
|
await killProcessTree(pid, "SIGTERM");
|
|
28633
28633
|
if (graceMs <= 0) return;
|
|
28634
|
-
const exited = new Promise((
|
|
28635
|
-
child.once("exit", () =>
|
|
28634
|
+
const exited = new Promise((resolve28) => {
|
|
28635
|
+
child.once("exit", () => resolve28());
|
|
28636
28636
|
});
|
|
28637
|
-
await Promise.race([exited, new Promise((
|
|
28637
|
+
await Promise.race([exited, new Promise((resolve28) => setTimeout(resolve28, graceMs))]);
|
|
28638
28638
|
if (child.exitCode == null && child.signalCode == null) {
|
|
28639
28639
|
await killProcessTree(pid, "SIGKILL");
|
|
28640
28640
|
}
|
|
@@ -28651,8 +28651,8 @@ async function gracefulAcpSubprocessDisconnect(params) {
|
|
|
28651
28651
|
await transport.closeSession?.(sessionId);
|
|
28652
28652
|
} catch {
|
|
28653
28653
|
}
|
|
28654
|
-
await new Promise((
|
|
28655
|
-
const timer = setTimeout(
|
|
28654
|
+
await new Promise((resolve28) => {
|
|
28655
|
+
const timer = setTimeout(resolve28, ACP_GRACEFUL_SESSION_CLOSE_WAIT_MS);
|
|
28656
28656
|
timer.unref?.();
|
|
28657
28657
|
});
|
|
28658
28658
|
}
|
|
@@ -28927,11 +28927,11 @@ function createSdkStdioExtNotificationHandler(options) {
|
|
|
28927
28927
|
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
28928
28928
|
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
28929
28929
|
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
28930
|
-
return new Promise((
|
|
28931
|
-
pending.set(requestId, { resolve:
|
|
28930
|
+
return new Promise((resolve28) => {
|
|
28931
|
+
pending.set(requestId, { resolve: resolve28, params: paramsRecord });
|
|
28932
28932
|
if (onRequest == null) {
|
|
28933
28933
|
pending.delete(requestId);
|
|
28934
|
-
|
|
28934
|
+
resolve28({ outcome: { outcome: "denied" } });
|
|
28935
28935
|
return;
|
|
28936
28936
|
}
|
|
28937
28937
|
try {
|
|
@@ -29441,10 +29441,10 @@ function createSdkStdioInitSettle(child) {
|
|
|
29441
29441
|
forceAcpSubprocessDisconnect(child);
|
|
29442
29442
|
reject(err);
|
|
29443
29443
|
},
|
|
29444
|
-
settleResolve(
|
|
29444
|
+
settleResolve(resolve28, handle) {
|
|
29445
29445
|
if (initSettled) return;
|
|
29446
29446
|
initSettled = true;
|
|
29447
|
-
|
|
29447
|
+
resolve28(handle);
|
|
29448
29448
|
}
|
|
29449
29449
|
};
|
|
29450
29450
|
}
|
|
@@ -29513,7 +29513,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
29513
29513
|
onFileChange,
|
|
29514
29514
|
stderrCapture
|
|
29515
29515
|
});
|
|
29516
|
-
return new Promise((
|
|
29516
|
+
return new Promise((resolve28, reject) => {
|
|
29517
29517
|
const init = createSdkStdioInitSettle(child);
|
|
29518
29518
|
child.on("error", (err) => {
|
|
29519
29519
|
init.settleReject(reject, new Error(formatSpawnError(err, command[0])));
|
|
@@ -29538,7 +29538,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
29538
29538
|
protocolVersion: PROTOCOL_VERSION2
|
|
29539
29539
|
});
|
|
29540
29540
|
init.settleResolve(
|
|
29541
|
-
|
|
29541
|
+
resolve28,
|
|
29542
29542
|
createSdkStdioHandle({
|
|
29543
29543
|
child,
|
|
29544
29544
|
sessionId: established.sessionId,
|
|
@@ -30071,7 +30071,7 @@ async function createCursorAcpClient(options) {
|
|
|
30071
30071
|
onFileChange,
|
|
30072
30072
|
stderrCapture
|
|
30073
30073
|
});
|
|
30074
|
-
return new Promise((
|
|
30074
|
+
return new Promise((resolve28, reject) => {
|
|
30075
30075
|
child.on("error", (err) => {
|
|
30076
30076
|
killChildProcessTree(child, "SIGKILL");
|
|
30077
30077
|
reject(new Error(formatSpawnError(err, command[0])));
|
|
@@ -30083,7 +30083,7 @@ async function createCursorAcpClient(options) {
|
|
|
30083
30083
|
sessionCtx,
|
|
30084
30084
|
incomingDeps: { dbgFs, sessionCtx, onSessionUpdate, onRequest }
|
|
30085
30085
|
});
|
|
30086
|
-
|
|
30086
|
+
resolve28(
|
|
30087
30087
|
createCursorAcpHandle({
|
|
30088
30088
|
child,
|
|
30089
30089
|
sessionId: established.sessionId,
|
|
@@ -31021,7 +31021,7 @@ function computeAcpAgentKey(preferredAgentType, mode, agentConfig) {
|
|
|
31021
31021
|
}
|
|
31022
31022
|
|
|
31023
31023
|
// src/mcp/bridge-mcp-constants.ts
|
|
31024
|
-
var
|
|
31024
|
+
var BRIDGE_MCP_SERVER_NAME2 = "buildautomaton-bridge";
|
|
31025
31025
|
|
|
31026
31026
|
// src/mcp/resolve-bridge-mcp-server-path.ts
|
|
31027
31027
|
import { dirname as dirname4, join as join3 } from "node:path";
|
|
@@ -31036,7 +31036,7 @@ function buildAcpMcpServers(bridgeAccessPort) {
|
|
|
31036
31036
|
if (!Number.isFinite(bridgeAccessPort) || bridgeAccessPort <= 0) return [];
|
|
31037
31037
|
return [
|
|
31038
31038
|
{
|
|
31039
|
-
name:
|
|
31039
|
+
name: BRIDGE_MCP_SERVER_NAME2,
|
|
31040
31040
|
command: process.execPath,
|
|
31041
31041
|
args: [resolveBridgeMcpServerScriptPath(), String(bridgeAccessPort)],
|
|
31042
31042
|
env: []
|
|
@@ -31289,8 +31289,8 @@ function pathspec(...paths) {
|
|
|
31289
31289
|
cache.set(key, paths);
|
|
31290
31290
|
return key;
|
|
31291
31291
|
}
|
|
31292
|
-
function isPathSpec(
|
|
31293
|
-
return
|
|
31292
|
+
function isPathSpec(path55) {
|
|
31293
|
+
return path55 instanceof String && cache.has(path55);
|
|
31294
31294
|
}
|
|
31295
31295
|
function toPaths(pathSpec) {
|
|
31296
31296
|
return cache.get(pathSpec) || [];
|
|
@@ -31379,8 +31379,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
31379
31379
|
function forEachLineWithContent(input, callback) {
|
|
31380
31380
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
31381
31381
|
}
|
|
31382
|
-
function folderExists(
|
|
31383
|
-
return (0, import_file_exists.exists)(
|
|
31382
|
+
function folderExists(path55) {
|
|
31383
|
+
return (0, import_file_exists.exists)(path55, import_file_exists.FOLDER);
|
|
31384
31384
|
}
|
|
31385
31385
|
function append(target, item) {
|
|
31386
31386
|
if (Array.isArray(target)) {
|
|
@@ -31784,8 +31784,8 @@ function checkIsRepoRootTask() {
|
|
|
31784
31784
|
commands,
|
|
31785
31785
|
format: "utf-8",
|
|
31786
31786
|
onError,
|
|
31787
|
-
parser(
|
|
31788
|
-
return /^\.(git)?$/.test(
|
|
31787
|
+
parser(path55) {
|
|
31788
|
+
return /^\.(git)?$/.test(path55.trim());
|
|
31789
31789
|
}
|
|
31790
31790
|
};
|
|
31791
31791
|
}
|
|
@@ -32219,11 +32219,11 @@ function parseGrep(grep) {
|
|
|
32219
32219
|
const paths = /* @__PURE__ */ new Set();
|
|
32220
32220
|
const results = {};
|
|
32221
32221
|
forEachLineWithContent(grep, (input) => {
|
|
32222
|
-
const [
|
|
32223
|
-
paths.add(
|
|
32224
|
-
(results[
|
|
32222
|
+
const [path55, line, preview] = input.split(NULL);
|
|
32223
|
+
paths.add(path55);
|
|
32224
|
+
(results[path55] = results[path55] || []).push({
|
|
32225
32225
|
line: asNumber(line),
|
|
32226
|
-
path:
|
|
32226
|
+
path: path55,
|
|
32227
32227
|
preview
|
|
32228
32228
|
});
|
|
32229
32229
|
});
|
|
@@ -32988,14 +32988,14 @@ var init_hash_object = __esm2({
|
|
|
32988
32988
|
init_task();
|
|
32989
32989
|
}
|
|
32990
32990
|
});
|
|
32991
|
-
function parseInit(bare,
|
|
32991
|
+
function parseInit(bare, path55, text) {
|
|
32992
32992
|
const response = String(text).trim();
|
|
32993
32993
|
let result;
|
|
32994
32994
|
if (result = initResponseRegex.exec(response)) {
|
|
32995
|
-
return new InitSummary(bare,
|
|
32995
|
+
return new InitSummary(bare, path55, false, result[1]);
|
|
32996
32996
|
}
|
|
32997
32997
|
if (result = reInitResponseRegex.exec(response)) {
|
|
32998
|
-
return new InitSummary(bare,
|
|
32998
|
+
return new InitSummary(bare, path55, true, result[1]);
|
|
32999
32999
|
}
|
|
33000
33000
|
let gitDir = "";
|
|
33001
33001
|
const tokens = response.split(" ");
|
|
@@ -33006,7 +33006,7 @@ function parseInit(bare, path48, text) {
|
|
|
33006
33006
|
break;
|
|
33007
33007
|
}
|
|
33008
33008
|
}
|
|
33009
|
-
return new InitSummary(bare,
|
|
33009
|
+
return new InitSummary(bare, path55, /^re/i.test(response), gitDir);
|
|
33010
33010
|
}
|
|
33011
33011
|
var InitSummary;
|
|
33012
33012
|
var initResponseRegex;
|
|
@@ -33015,9 +33015,9 @@ var init_InitSummary = __esm2({
|
|
|
33015
33015
|
"src/lib/responses/InitSummary.ts"() {
|
|
33016
33016
|
"use strict";
|
|
33017
33017
|
InitSummary = class {
|
|
33018
|
-
constructor(bare,
|
|
33018
|
+
constructor(bare, path55, existing, gitDir) {
|
|
33019
33019
|
this.bare = bare;
|
|
33020
|
-
this.path =
|
|
33020
|
+
this.path = path55;
|
|
33021
33021
|
this.existing = existing;
|
|
33022
33022
|
this.gitDir = gitDir;
|
|
33023
33023
|
}
|
|
@@ -33029,7 +33029,7 @@ var init_InitSummary = __esm2({
|
|
|
33029
33029
|
function hasBareCommand(command) {
|
|
33030
33030
|
return command.includes(bareCommand);
|
|
33031
33031
|
}
|
|
33032
|
-
function initTask(bare = false,
|
|
33032
|
+
function initTask(bare = false, path55, customArgs) {
|
|
33033
33033
|
const commands = ["init", ...customArgs];
|
|
33034
33034
|
if (bare && !hasBareCommand(commands)) {
|
|
33035
33035
|
commands.splice(1, 0, bareCommand);
|
|
@@ -33038,7 +33038,7 @@ function initTask(bare = false, path48, customArgs) {
|
|
|
33038
33038
|
commands,
|
|
33039
33039
|
format: "utf-8",
|
|
33040
33040
|
parser(text) {
|
|
33041
|
-
return parseInit(commands.includes("--bare"),
|
|
33041
|
+
return parseInit(commands.includes("--bare"), path55, text);
|
|
33042
33042
|
}
|
|
33043
33043
|
};
|
|
33044
33044
|
}
|
|
@@ -33854,12 +33854,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
33854
33854
|
"use strict";
|
|
33855
33855
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
33856
33856
|
FileStatusSummary = class {
|
|
33857
|
-
constructor(
|
|
33858
|
-
this.path =
|
|
33857
|
+
constructor(path55, index, working_dir) {
|
|
33858
|
+
this.path = path55;
|
|
33859
33859
|
this.index = index;
|
|
33860
33860
|
this.working_dir = working_dir;
|
|
33861
33861
|
if (index === "R" || working_dir === "R") {
|
|
33862
|
-
const detail = fromPathRegex.exec(
|
|
33862
|
+
const detail = fromPathRegex.exec(path55) || [null, path55, path55];
|
|
33863
33863
|
this.from = detail[2] || "";
|
|
33864
33864
|
this.path = detail[1] || "";
|
|
33865
33865
|
}
|
|
@@ -33890,14 +33890,14 @@ function splitLine(result, lineStr) {
|
|
|
33890
33890
|
default:
|
|
33891
33891
|
return;
|
|
33892
33892
|
}
|
|
33893
|
-
function data(index, workingDir,
|
|
33893
|
+
function data(index, workingDir, path55) {
|
|
33894
33894
|
const raw = `${index}${workingDir}`;
|
|
33895
33895
|
const handler = parsers6.get(raw);
|
|
33896
33896
|
if (handler) {
|
|
33897
|
-
handler(result,
|
|
33897
|
+
handler(result, path55);
|
|
33898
33898
|
}
|
|
33899
33899
|
if (raw !== "##" && raw !== "!!") {
|
|
33900
|
-
result.files.push(new FileStatusSummary(
|
|
33900
|
+
result.files.push(new FileStatusSummary(path55, index, workingDir));
|
|
33901
33901
|
}
|
|
33902
33902
|
}
|
|
33903
33903
|
}
|
|
@@ -34206,9 +34206,9 @@ var init_simple_git_api = __esm2({
|
|
|
34206
34206
|
next
|
|
34207
34207
|
);
|
|
34208
34208
|
}
|
|
34209
|
-
hashObject(
|
|
34209
|
+
hashObject(path55, write) {
|
|
34210
34210
|
return this._runTask(
|
|
34211
|
-
hashObjectTask(
|
|
34211
|
+
hashObjectTask(path55, write === true),
|
|
34212
34212
|
trailingFunctionArgument(arguments)
|
|
34213
34213
|
);
|
|
34214
34214
|
}
|
|
@@ -34561,8 +34561,8 @@ var init_branch = __esm2({
|
|
|
34561
34561
|
}
|
|
34562
34562
|
});
|
|
34563
34563
|
function toPath(input) {
|
|
34564
|
-
const
|
|
34565
|
-
return
|
|
34564
|
+
const path55 = input.trim().replace(/^["']|["']$/g, "");
|
|
34565
|
+
return path55 && normalize3(path55);
|
|
34566
34566
|
}
|
|
34567
34567
|
var parseCheckIgnore;
|
|
34568
34568
|
var init_CheckIgnore = __esm2({
|
|
@@ -34876,8 +34876,8 @@ __export2(sub_module_exports, {
|
|
|
34876
34876
|
subModuleTask: () => subModuleTask,
|
|
34877
34877
|
updateSubModuleTask: () => updateSubModuleTask
|
|
34878
34878
|
});
|
|
34879
|
-
function addSubModuleTask(repo,
|
|
34880
|
-
return subModuleTask(["add", repo,
|
|
34879
|
+
function addSubModuleTask(repo, path55) {
|
|
34880
|
+
return subModuleTask(["add", repo, path55]);
|
|
34881
34881
|
}
|
|
34882
34882
|
function initSubModuleTask(customArgs) {
|
|
34883
34883
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -35210,8 +35210,8 @@ var require_git = __commonJS2({
|
|
|
35210
35210
|
}
|
|
35211
35211
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
35212
35212
|
};
|
|
35213
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
35214
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
35213
|
+
Git2.prototype.submoduleAdd = function(repo, path55, then) {
|
|
35214
|
+
return this._runTask(addSubModuleTask2(repo, path55), trailingFunctionArgument2(arguments));
|
|
35215
35215
|
};
|
|
35216
35216
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
35217
35217
|
return this._runTask(
|
|
@@ -35848,14 +35848,14 @@ async function runGitTask(fn) {
|
|
|
35848
35848
|
}
|
|
35849
35849
|
async function yieldToEventLoop2() {
|
|
35850
35850
|
throwIfGitShutdownRequested();
|
|
35851
|
-
await new Promise((
|
|
35852
|
-
setImmediate(
|
|
35851
|
+
await new Promise((resolve28) => {
|
|
35852
|
+
setImmediate(resolve28);
|
|
35853
35853
|
});
|
|
35854
35854
|
throwIfGitShutdownRequested();
|
|
35855
35855
|
}
|
|
35856
35856
|
async function forEachWithGitYield(items, fn) {
|
|
35857
35857
|
for (let i = 0; i < items.length; i++) {
|
|
35858
|
-
|
|
35858
|
+
await yieldToEventLoop2();
|
|
35859
35859
|
await fn(items[i], i);
|
|
35860
35860
|
}
|
|
35861
35861
|
}
|
|
@@ -36174,9 +36174,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
36174
36174
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
36175
36175
|
async function putEncryptedChangeSummaryRows(params) {
|
|
36176
36176
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
36177
|
-
const entries = params.rows.map(({ path:
|
|
36177
|
+
const entries = params.rows.map(({ path: path55, summary }) => {
|
|
36178
36178
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
36179
|
-
return { path:
|
|
36179
|
+
return { path: path55, summary: JSON.stringify(enc) };
|
|
36180
36180
|
});
|
|
36181
36181
|
const res = await fetch(
|
|
36182
36182
|
`${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -36530,7 +36530,7 @@ function buildIntegrationContentAgentPromptNote(sessionId) {
|
|
|
36530
36530
|
"Use the get_integration_content MCP tool on the buildautomaton-bridge server to fetch the full content of each link.",
|
|
36531
36531
|
`When calling the tool, pass sessionId "${sessionRef}" and the URL as url.`,
|
|
36532
36532
|
"By default the tool links the fetched URL as this session external ticket when the session has none yet. Pass associateAsSessionTicket: false when fetching additional links for context only (after the primary ticket is linked, or when you do not want association).",
|
|
36533
|
-
"If the tool reports unsupported_url, do not retry with the same URL. If it reports temporarily_unavailable, you may retry later."
|
|
36533
|
+
"If the tool reports unsupported_url, do not retry with the same URL. If it reports integration_reconnect_required, ask the user to reconnect the integration in workspace settings. If it reports temporarily_unavailable, you may retry later."
|
|
36534
36534
|
].join("\n");
|
|
36535
36535
|
}
|
|
36536
36536
|
function injectIntegrationContentAgentPromptNote(agentPrompt, sessionId) {
|
|
@@ -36565,7 +36565,7 @@ async function sendPromptToAgent(options) {
|
|
|
36565
36565
|
runId,
|
|
36566
36566
|
agentType,
|
|
36567
36567
|
agentCwd,
|
|
36568
|
-
sendResult
|
|
36568
|
+
sendResult,
|
|
36569
36569
|
sendSessionUpdate,
|
|
36570
36570
|
log: log2,
|
|
36571
36571
|
followUpCatalogPromptId,
|
|
@@ -36595,7 +36595,7 @@ async function sendPromptToAgent(options) {
|
|
|
36595
36595
|
let sendOpts = {};
|
|
36596
36596
|
if (attachments && attachments.length > 0) {
|
|
36597
36597
|
if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
|
|
36598
|
-
|
|
36598
|
+
sendResult({
|
|
36599
36599
|
type: "prompt_result",
|
|
36600
36600
|
id: promptId,
|
|
36601
36601
|
...sessionId ? { sessionId } : {},
|
|
@@ -36616,7 +36616,7 @@ async function sendPromptToAgent(options) {
|
|
|
36616
36616
|
log: log2
|
|
36617
36617
|
});
|
|
36618
36618
|
if (!resolved.ok) {
|
|
36619
|
-
|
|
36619
|
+
sendResult({
|
|
36620
36620
|
type: "prompt_result",
|
|
36621
36621
|
id: promptId,
|
|
36622
36622
|
...sessionId ? { sessionId } : {},
|
|
@@ -36655,7 +36655,7 @@ async function sendPromptToAgent(options) {
|
|
|
36655
36655
|
const errStr = typeof result.error === "string" ? result.error : void 0;
|
|
36656
36656
|
const resultStop = typeof result.stopReason === "string" ? result.stopReason.trim() : "";
|
|
36657
36657
|
const cancelledByAgent = resultStop.toLowerCase() === "cancelled" || errStr != null && isUserEndedSessionTurnErrorText(errStr);
|
|
36658
|
-
|
|
36658
|
+
sendResult({
|
|
36659
36659
|
type: "prompt_result",
|
|
36660
36660
|
id: promptId,
|
|
36661
36661
|
...sessionId ? { sessionId } : {},
|
|
@@ -36677,7 +36677,7 @@ async function sendPromptToAgent(options) {
|
|
|
36677
36677
|
} catch (err) {
|
|
36678
36678
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
36679
36679
|
log2(`[Agent] Send failed: ${errMsg}`);
|
|
36680
|
-
|
|
36680
|
+
sendResult({
|
|
36681
36681
|
type: "prompt_result",
|
|
36682
36682
|
id: promptId,
|
|
36683
36683
|
...sessionId ? { sessionId } : {},
|
|
@@ -36711,7 +36711,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36711
36711
|
agentType,
|
|
36712
36712
|
agentConfig,
|
|
36713
36713
|
sessionParentPath,
|
|
36714
|
-
sendResult
|
|
36714
|
+
sendResult,
|
|
36715
36715
|
sendSessionUpdate,
|
|
36716
36716
|
followUpCatalogPromptId,
|
|
36717
36717
|
sessionChangeSummaryFilePaths,
|
|
@@ -36728,7 +36728,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36728
36728
|
const activeRunId = runId;
|
|
36729
36729
|
const acpAgentKey = computeAcpAgentKey(preferredForPrompt, mode, agentConfig ?? null);
|
|
36730
36730
|
if (!acpAgentKey) {
|
|
36731
|
-
|
|
36731
|
+
sendResult({
|
|
36732
36732
|
type: "prompt_result",
|
|
36733
36733
|
id: promptId,
|
|
36734
36734
|
...sessionId ? { sessionId } : {},
|
|
@@ -36765,7 +36765,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36765
36765
|
const evaluated = Boolean(preferredForPrompt && errMsg.trim());
|
|
36766
36766
|
const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
|
|
36767
36767
|
const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
|
|
36768
|
-
|
|
36768
|
+
sendResult({
|
|
36769
36769
|
type: "prompt_result",
|
|
36770
36770
|
id: promptId,
|
|
36771
36771
|
...sessionId ? { sessionId } : {},
|
|
@@ -36785,7 +36785,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36785
36785
|
await handle.cancel?.();
|
|
36786
36786
|
} catch {
|
|
36787
36787
|
}
|
|
36788
|
-
|
|
36788
|
+
sendResult({
|
|
36789
36789
|
type: "prompt_result",
|
|
36790
36790
|
id: promptId,
|
|
36791
36791
|
...sessionId ? { sessionId } : {},
|
|
@@ -36806,7 +36806,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36806
36806
|
runId: activeRunId,
|
|
36807
36807
|
agentType: preferredForPrompt,
|
|
36808
36808
|
agentCwd: resolveSessionParentPathForAgentProcess(sessionParentPath),
|
|
36809
|
-
sendResult
|
|
36809
|
+
sendResult,
|
|
36810
36810
|
sendSessionUpdate,
|
|
36811
36811
|
log: ctx.log,
|
|
36812
36812
|
followUpCatalogPromptId,
|
|
@@ -36862,6 +36862,563 @@ async function createAcpManager(options) {
|
|
|
36862
36862
|
};
|
|
36863
36863
|
}
|
|
36864
36864
|
|
|
36865
|
+
// src/worktrees/worktree-layout-file.ts
|
|
36866
|
+
import * as fs17 from "node:fs";
|
|
36867
|
+
import * as path20 from "node:path";
|
|
36868
|
+
import os7 from "node:os";
|
|
36869
|
+
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
36870
|
+
function defaultWorktreeLayoutPath() {
|
|
36871
|
+
return path20.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
36872
|
+
}
|
|
36873
|
+
function normalizeLoadedLayout(raw) {
|
|
36874
|
+
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
36875
|
+
const j = raw;
|
|
36876
|
+
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
36877
|
+
}
|
|
36878
|
+
return { launcherCwds: [] };
|
|
36879
|
+
}
|
|
36880
|
+
function loadWorktreeLayout() {
|
|
36881
|
+
try {
|
|
36882
|
+
const p = defaultWorktreeLayoutPath();
|
|
36883
|
+
if (!fs17.existsSync(p)) return { launcherCwds: [] };
|
|
36884
|
+
const raw = JSON.parse(fs17.readFileSync(p, "utf8"));
|
|
36885
|
+
return normalizeLoadedLayout(raw);
|
|
36886
|
+
} catch {
|
|
36887
|
+
return { launcherCwds: [] };
|
|
36888
|
+
}
|
|
36889
|
+
}
|
|
36890
|
+
function saveWorktreeLayout(layout) {
|
|
36891
|
+
try {
|
|
36892
|
+
const dir = path20.dirname(defaultWorktreeLayoutPath());
|
|
36893
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
36894
|
+
fs17.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
36895
|
+
} catch {
|
|
36896
|
+
}
|
|
36897
|
+
}
|
|
36898
|
+
function baseNameSafe(pathString) {
|
|
36899
|
+
return path20.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
36900
|
+
}
|
|
36901
|
+
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
36902
|
+
const norm = path20.resolve(bridgeRootPath2);
|
|
36903
|
+
const existing = layout.launcherCwds.find((e) => path20.resolve(e.absolutePath) === norm);
|
|
36904
|
+
return existing?.dirName;
|
|
36905
|
+
}
|
|
36906
|
+
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
36907
|
+
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
36908
|
+
if (existing) return existing;
|
|
36909
|
+
const norm = path20.resolve(bridgeRootPath2);
|
|
36910
|
+
const base = baseNameSafe(norm);
|
|
36911
|
+
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
36912
|
+
let name = base;
|
|
36913
|
+
let n = 2;
|
|
36914
|
+
while (used.has(name)) {
|
|
36915
|
+
name = `${base}-${n}`;
|
|
36916
|
+
n += 1;
|
|
36917
|
+
}
|
|
36918
|
+
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
36919
|
+
saveWorktreeLayout(layout);
|
|
36920
|
+
return name;
|
|
36921
|
+
}
|
|
36922
|
+
|
|
36923
|
+
// src/worktrees/discovery/discover-session-worktree-on-disk.ts
|
|
36924
|
+
import * as fs21 from "node:fs";
|
|
36925
|
+
import * as path25 from "node:path";
|
|
36926
|
+
|
|
36927
|
+
// src/worktrees/discovery/collect-worktree-paths.ts
|
|
36928
|
+
import * as fs19 from "node:fs";
|
|
36929
|
+
import * as path22 from "node:path";
|
|
36930
|
+
|
|
36931
|
+
// src/worktrees/discovery/disk-walk-constants.ts
|
|
36932
|
+
var DISK_WALK_YIELD_EVERY = 64;
|
|
36933
|
+
var LEGACY_WALK_MAX_DEPTH = 12;
|
|
36934
|
+
var SKIP_DISK_WALK_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
36935
|
+
"node_modules",
|
|
36936
|
+
"bower_components",
|
|
36937
|
+
"vendor",
|
|
36938
|
+
"Pods",
|
|
36939
|
+
"Carthage",
|
|
36940
|
+
"DerivedData",
|
|
36941
|
+
".yarn",
|
|
36942
|
+
".pnpm-store",
|
|
36943
|
+
"dist",
|
|
36944
|
+
"build",
|
|
36945
|
+
".next",
|
|
36946
|
+
"coverage",
|
|
36947
|
+
".turbo",
|
|
36948
|
+
".cache",
|
|
36949
|
+
"target",
|
|
36950
|
+
"__pycache__"
|
|
36951
|
+
]);
|
|
36952
|
+
function shouldSkipDiskWalkEntry(name) {
|
|
36953
|
+
return name.startsWith(".") || SKIP_DISK_WALK_DIR_NAMES.has(name);
|
|
36954
|
+
}
|
|
36955
|
+
|
|
36956
|
+
// src/worktrees/discovery/disk-walk-utils.ts
|
|
36957
|
+
import * as fs18 from "node:fs";
|
|
36958
|
+
import * as path21 from "node:path";
|
|
36959
|
+
async function yieldDuringDiskWalk(state) {
|
|
36960
|
+
state.entries++;
|
|
36961
|
+
if (state.entries % DISK_WALK_YIELD_EVERY !== 0) return true;
|
|
36962
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
36963
|
+
await yieldToEventLoop();
|
|
36964
|
+
return !isCliImmediateShutdownRequested();
|
|
36965
|
+
}
|
|
36966
|
+
async function isGitDir(dirPath) {
|
|
36967
|
+
try {
|
|
36968
|
+
await fs18.promises.access(path21.join(dirPath, ".git"));
|
|
36969
|
+
return true;
|
|
36970
|
+
} catch {
|
|
36971
|
+
return false;
|
|
36972
|
+
}
|
|
36973
|
+
}
|
|
36974
|
+
|
|
36975
|
+
// src/worktrees/discovery/collect-worktree-paths.ts
|
|
36976
|
+
async function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
36977
|
+
const out = [];
|
|
36978
|
+
const state = { entries: 0 };
|
|
36979
|
+
const walk = async (dir) => {
|
|
36980
|
+
if (!await yieldDuringDiskWalk(state)) return;
|
|
36981
|
+
if (await isGitDir(dir)) {
|
|
36982
|
+
out.push(path22.resolve(dir));
|
|
36983
|
+
return;
|
|
36984
|
+
}
|
|
36985
|
+
let entries;
|
|
36986
|
+
try {
|
|
36987
|
+
entries = await fs19.promises.readdir(dir, { withFileTypes: true });
|
|
36988
|
+
} catch {
|
|
36989
|
+
return;
|
|
36990
|
+
}
|
|
36991
|
+
for (const e of entries) {
|
|
36992
|
+
if (shouldSkipDiskWalkEntry(e.name)) continue;
|
|
36993
|
+
const full = path22.join(dir, e.name);
|
|
36994
|
+
if (!e.isDirectory()) continue;
|
|
36995
|
+
await walk(full);
|
|
36996
|
+
}
|
|
36997
|
+
};
|
|
36998
|
+
await walk(path22.resolve(rootPath));
|
|
36999
|
+
return { paths: [...new Set(out)], entriesVisited: state.entries };
|
|
37000
|
+
}
|
|
37001
|
+
async function collectWorktreeRootsNamed(root, sessionId, maxDepth = LEGACY_WALK_MAX_DEPTH) {
|
|
37002
|
+
const out = [];
|
|
37003
|
+
const state = { entries: 0 };
|
|
37004
|
+
const walk = async (dir, depth) => {
|
|
37005
|
+
if (depth > maxDepth) return;
|
|
37006
|
+
if (!await yieldDuringDiskWalk(state)) return;
|
|
37007
|
+
let entries;
|
|
37008
|
+
try {
|
|
37009
|
+
entries = await fs19.promises.readdir(dir, { withFileTypes: true });
|
|
37010
|
+
} catch {
|
|
37011
|
+
return;
|
|
37012
|
+
}
|
|
37013
|
+
for (const e of entries) {
|
|
37014
|
+
if (shouldSkipDiskWalkEntry(e.name)) continue;
|
|
37015
|
+
const full = path22.join(dir, e.name);
|
|
37016
|
+
if (!e.isDirectory()) continue;
|
|
37017
|
+
if (e.name === sessionId) {
|
|
37018
|
+
if (await isGitDir(full)) out.push(path22.resolve(full));
|
|
37019
|
+
continue;
|
|
37020
|
+
}
|
|
37021
|
+
if (await isGitDir(full)) continue;
|
|
37022
|
+
await walk(full, depth + 1);
|
|
37023
|
+
}
|
|
37024
|
+
};
|
|
37025
|
+
await walk(root, 0);
|
|
37026
|
+
return { paths: out, entriesVisited: state.entries };
|
|
37027
|
+
}
|
|
37028
|
+
|
|
37029
|
+
// src/worktrees/discovery/layout-keys-for-bridge-root.ts
|
|
37030
|
+
import * as path23 from "node:path";
|
|
37031
|
+
function layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk) {
|
|
37032
|
+
const bridge = path23.resolve(bridgeRoot);
|
|
37033
|
+
const preferred = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
37034
|
+
const relevant = layout.launcherCwds.filter((e) => {
|
|
37035
|
+
const entry = path23.resolve(e.absolutePath);
|
|
37036
|
+
return bridge === entry || bridge.startsWith(entry + path23.sep) || entry.startsWith(bridge + path23.sep);
|
|
37037
|
+
}).sort((a, b) => path23.resolve(b.absolutePath).length - path23.resolve(a.absolutePath).length).map((e) => e.dirName).filter((name) => keysOnDisk.includes(name));
|
|
37038
|
+
const ordered = [];
|
|
37039
|
+
const seen = /* @__PURE__ */ new Set();
|
|
37040
|
+
const add = (k) => {
|
|
37041
|
+
if (seen.has(k) || !keysOnDisk.includes(k)) return;
|
|
37042
|
+
seen.add(k);
|
|
37043
|
+
ordered.push(k);
|
|
37044
|
+
};
|
|
37045
|
+
if (preferred) add(preferred);
|
|
37046
|
+
for (const k of relevant) add(k);
|
|
37047
|
+
if (relevant.length > 0) {
|
|
37048
|
+
return ordered;
|
|
37049
|
+
}
|
|
37050
|
+
for (const k of keysOnDisk) add(k);
|
|
37051
|
+
return ordered;
|
|
37052
|
+
}
|
|
37053
|
+
|
|
37054
|
+
// src/worktrees/discovery/try-binding-from-session-directory.ts
|
|
37055
|
+
import * as fs20 from "node:fs";
|
|
37056
|
+
import * as path24 from "node:path";
|
|
37057
|
+
async function tryBindingFromSessionDirectory(sessionDir) {
|
|
37058
|
+
let st;
|
|
37059
|
+
try {
|
|
37060
|
+
st = await fs20.promises.stat(sessionDir);
|
|
37061
|
+
} catch {
|
|
37062
|
+
return null;
|
|
37063
|
+
}
|
|
37064
|
+
if (!st.isDirectory()) return null;
|
|
37065
|
+
const { paths: worktreePaths } = await collectGitRepoRootsUnderDirectory(sessionDir);
|
|
37066
|
+
if (worktreePaths.length === 0) return null;
|
|
37067
|
+
const abs = path24.resolve(sessionDir);
|
|
37068
|
+
return {
|
|
37069
|
+
sessionParentPath: abs,
|
|
37070
|
+
workingTreeRelRoot: abs,
|
|
37071
|
+
repoCheckoutPaths: worktreePaths
|
|
37072
|
+
};
|
|
37073
|
+
}
|
|
37074
|
+
|
|
37075
|
+
// src/worktrees/discovery/discover-session-worktree-on-disk.ts
|
|
37076
|
+
async function discoverSessionWorktreeOnDisk(options) {
|
|
37077
|
+
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
37078
|
+
const sid = sessionId.trim();
|
|
37079
|
+
if (!sid) return null;
|
|
37080
|
+
try {
|
|
37081
|
+
await fs21.promises.access(worktreesRootPath);
|
|
37082
|
+
} catch {
|
|
37083
|
+
return null;
|
|
37084
|
+
}
|
|
37085
|
+
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
37086
|
+
const keysOnDisk = [];
|
|
37087
|
+
if (preferredKey) keysOnDisk.push(preferredKey);
|
|
37088
|
+
try {
|
|
37089
|
+
for (const name of await fs21.promises.readdir(worktreesRootPath)) {
|
|
37090
|
+
if (name.startsWith(".")) continue;
|
|
37091
|
+
const p = path25.join(worktreesRootPath, name);
|
|
37092
|
+
let st;
|
|
37093
|
+
try {
|
|
37094
|
+
st = await fs21.promises.stat(p);
|
|
37095
|
+
} catch {
|
|
37096
|
+
continue;
|
|
37097
|
+
}
|
|
37098
|
+
if (!st.isDirectory()) continue;
|
|
37099
|
+
if (!keysOnDisk.includes(name)) keysOnDisk.push(name);
|
|
37100
|
+
}
|
|
37101
|
+
} catch {
|
|
37102
|
+
return null;
|
|
37103
|
+
}
|
|
37104
|
+
const keys = layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk);
|
|
37105
|
+
for (const key of keys) {
|
|
37106
|
+
if (isCliImmediateShutdownRequested()) return null;
|
|
37107
|
+
await yieldToEventLoop();
|
|
37108
|
+
const layoutRoot = path25.join(worktreesRootPath, key);
|
|
37109
|
+
let layoutSt;
|
|
37110
|
+
try {
|
|
37111
|
+
layoutSt = await fs21.promises.stat(layoutRoot);
|
|
37112
|
+
} catch {
|
|
37113
|
+
continue;
|
|
37114
|
+
}
|
|
37115
|
+
if (!layoutSt.isDirectory()) continue;
|
|
37116
|
+
const sessionDir = path25.join(layoutRoot, sid);
|
|
37117
|
+
const nested = await tryBindingFromSessionDirectory(sessionDir);
|
|
37118
|
+
if (nested) return nested;
|
|
37119
|
+
const legacy = await collectWorktreeRootsNamed(layoutRoot, sid);
|
|
37120
|
+
if (legacy.paths.length > 0) {
|
|
37121
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacy.paths) ?? path25.resolve(legacy.paths[0]);
|
|
37122
|
+
return {
|
|
37123
|
+
sessionParentPath: path25.resolve(isolated),
|
|
37124
|
+
workingTreeRelRoot: path25.resolve(layoutRoot),
|
|
37125
|
+
repoCheckoutPaths: legacy.paths.map((p) => path25.resolve(p))
|
|
37126
|
+
};
|
|
37127
|
+
}
|
|
37128
|
+
}
|
|
37129
|
+
return null;
|
|
37130
|
+
}
|
|
37131
|
+
|
|
37132
|
+
// src/worktrees/discovery/discover-session-worktrees-under-session-worktree-root.ts
|
|
37133
|
+
import * as fs22 from "node:fs";
|
|
37134
|
+
import * as path27 from "node:path";
|
|
37135
|
+
|
|
37136
|
+
// src/worktrees/discovery/discover-legacy-binding-ascending-from-checkout.ts
|
|
37137
|
+
import * as path26 from "node:path";
|
|
37138
|
+
async function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
37139
|
+
const sid = sessionId.trim();
|
|
37140
|
+
if (!sid) return null;
|
|
37141
|
+
const hintR = path26.resolve(checkoutPath);
|
|
37142
|
+
let best = null;
|
|
37143
|
+
let cur = path26.dirname(hintR);
|
|
37144
|
+
for (let i = 0; i < 40; i++) {
|
|
37145
|
+
if (isCliImmediateShutdownRequested()) return best;
|
|
37146
|
+
await yieldToEventLoop();
|
|
37147
|
+
const paths = await collectWorktreeRootsNamed(cur, sid);
|
|
37148
|
+
if (paths.paths.some((p) => path26.resolve(p) === hintR)) {
|
|
37149
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths.paths) ?? path26.resolve(paths.paths[0]);
|
|
37150
|
+
best = {
|
|
37151
|
+
sessionParentPath: path26.resolve(isolated),
|
|
37152
|
+
workingTreeRelRoot: path26.resolve(cur),
|
|
37153
|
+
repoCheckoutPaths: paths.paths.map((p) => path26.resolve(p))
|
|
37154
|
+
};
|
|
37155
|
+
}
|
|
37156
|
+
const next = path26.dirname(cur);
|
|
37157
|
+
if (next === cur) break;
|
|
37158
|
+
cur = next;
|
|
37159
|
+
}
|
|
37160
|
+
return best;
|
|
37161
|
+
}
|
|
37162
|
+
|
|
37163
|
+
// src/worktrees/discovery/discover-session-worktrees-under-session-worktree-root.ts
|
|
37164
|
+
async function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
37165
|
+
const sid = sessionId.trim();
|
|
37166
|
+
if (!sid) return null;
|
|
37167
|
+
const hint = path27.resolve(sessionWorktreeRootPathOrHint);
|
|
37168
|
+
const underHint = await tryBindingFromSessionDirectory(path27.join(hint, sid));
|
|
37169
|
+
if (underHint) return underHint;
|
|
37170
|
+
const direct = await tryBindingFromSessionDirectory(hint);
|
|
37171
|
+
if (direct) {
|
|
37172
|
+
if (path27.basename(hint) === sid && await isGitDir(hint)) {
|
|
37173
|
+
const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
37174
|
+
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
37175
|
+
return legacyFromCheckout;
|
|
37176
|
+
}
|
|
37177
|
+
}
|
|
37178
|
+
return direct;
|
|
37179
|
+
}
|
|
37180
|
+
if (path27.basename(hint) === sid && await isGitDir(hint)) {
|
|
37181
|
+
const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
37182
|
+
if (legacyFromCheckout) return legacyFromCheckout;
|
|
37183
|
+
}
|
|
37184
|
+
let st;
|
|
37185
|
+
try {
|
|
37186
|
+
st = await fs22.promises.stat(hint);
|
|
37187
|
+
} catch {
|
|
37188
|
+
return null;
|
|
37189
|
+
}
|
|
37190
|
+
if (!st.isDirectory()) return null;
|
|
37191
|
+
const legacyPaths = await collectWorktreeRootsNamed(hint, sid);
|
|
37192
|
+
if (legacyPaths.paths.length === 0) return null;
|
|
37193
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths.paths) ?? path27.resolve(legacyPaths.paths[0]);
|
|
37194
|
+
return {
|
|
37195
|
+
sessionParentPath: path27.resolve(isolated),
|
|
37196
|
+
workingTreeRelRoot: hint,
|
|
37197
|
+
repoCheckoutPaths: legacyPaths.paths.map((p) => path27.resolve(p))
|
|
37198
|
+
};
|
|
37199
|
+
}
|
|
37200
|
+
|
|
37201
|
+
// src/worktrees/manager/discover-session-binding.ts
|
|
37202
|
+
var discoverInflightBySessionId = /* @__PURE__ */ new Map();
|
|
37203
|
+
function discoverSessionBindingAsync(params) {
|
|
37204
|
+
const sid = params.sessionId.trim();
|
|
37205
|
+
if (!sid) return Promise.resolve(null);
|
|
37206
|
+
const existing = discoverInflightBySessionId.get(sid);
|
|
37207
|
+
if (existing) return existing;
|
|
37208
|
+
const promise2 = discoverSessionWorktreeOnDisk({
|
|
37209
|
+
sessionId: sid,
|
|
37210
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
37211
|
+
layout: params.layout,
|
|
37212
|
+
bridgeRoot: getBridgeRoot()
|
|
37213
|
+
}).finally(() => {
|
|
37214
|
+
if (discoverInflightBySessionId.get(sid) === promise2) {
|
|
37215
|
+
discoverInflightBySessionId.delete(sid);
|
|
37216
|
+
}
|
|
37217
|
+
});
|
|
37218
|
+
discoverInflightBySessionId.set(sid, promise2);
|
|
37219
|
+
return promise2;
|
|
37220
|
+
}
|
|
37221
|
+
|
|
37222
|
+
// src/worktrees/manager/resolve-isolated-session-parent-path.ts
|
|
37223
|
+
function resolveIsolatedSessionParentPath(sessionId, cache2, ensureRepoCheckoutPaths) {
|
|
37224
|
+
if (!sessionId) return null;
|
|
37225
|
+
const sid = sessionId.trim();
|
|
37226
|
+
const cached2 = cache2.getSessionParentPath(sid);
|
|
37227
|
+
if (cached2) return cached2;
|
|
37228
|
+
const paths = ensureRepoCheckoutPaths(sid);
|
|
37229
|
+
if (!paths?.length) return null;
|
|
37230
|
+
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
37231
|
+
}
|
|
37232
|
+
function ensureRepoCheckoutPathsForSession(sessionId, cache2) {
|
|
37233
|
+
if (!sessionId?.trim()) return void 0;
|
|
37234
|
+
const cached2 = cache2.getRepoCheckoutPaths(sessionId.trim());
|
|
37235
|
+
return cached2?.length ? [...cached2] : void 0;
|
|
37236
|
+
}
|
|
37237
|
+
async function ensureRepoCheckoutPathsForSessionAsync(sessionId, cache2, discover) {
|
|
37238
|
+
if (!sessionId?.trim()) return void 0;
|
|
37239
|
+
const sid = sessionId.trim();
|
|
37240
|
+
const cached2 = cache2.getRepoCheckoutPaths(sid);
|
|
37241
|
+
if (cached2?.length) return cached2;
|
|
37242
|
+
const disc = await discover(sid);
|
|
37243
|
+
if (disc?.repoCheckoutPaths.length) {
|
|
37244
|
+
cache2.remember(sid, disc);
|
|
37245
|
+
return [...disc.repoCheckoutPaths];
|
|
37246
|
+
}
|
|
37247
|
+
return void 0;
|
|
37248
|
+
}
|
|
37249
|
+
|
|
37250
|
+
// src/worktrees/manager/parse-session-parent.ts
|
|
37251
|
+
function parseSessionParent(v) {
|
|
37252
|
+
if (v === "bridge_root" || v === "worktrees_root") return v;
|
|
37253
|
+
if (v === "session_worktrees_root") return "worktrees_root";
|
|
37254
|
+
return null;
|
|
37255
|
+
}
|
|
37256
|
+
|
|
37257
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
37258
|
+
import * as fs23 from "node:fs";
|
|
37259
|
+
import * as path28 from "node:path";
|
|
37260
|
+
|
|
37261
|
+
// src/git/worktrees/worktree-add.ts
|
|
37262
|
+
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
37263
|
+
const mainGit = cliSimpleGit(mainRepoPath);
|
|
37264
|
+
const base = baseRef.trim() || "HEAD";
|
|
37265
|
+
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, base]);
|
|
37266
|
+
}
|
|
37267
|
+
|
|
37268
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
37269
|
+
function normalizeRepoRelPath(rel) {
|
|
37270
|
+
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
37271
|
+
}
|
|
37272
|
+
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
37273
|
+
if (!baseBranches) return "HEAD";
|
|
37274
|
+
const direct = baseBranches[relNorm]?.trim();
|
|
37275
|
+
if (direct) return direct;
|
|
37276
|
+
if (relNorm !== "." && baseBranches["."]?.trim()) return baseBranches["."].trim();
|
|
37277
|
+
return "HEAD";
|
|
37278
|
+
}
|
|
37279
|
+
async function prepareNewSessionWorktrees(options) {
|
|
37280
|
+
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
|
|
37281
|
+
const bridgeResolved = path28.resolve(bridgeRoot);
|
|
37282
|
+
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
37283
|
+
const bridgeKeyDir = path28.join(worktreesRootPath, cwdKey);
|
|
37284
|
+
const sessionDir = path28.join(bridgeKeyDir, sessionId);
|
|
37285
|
+
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
37286
|
+
if (repos.length === 0) {
|
|
37287
|
+
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
37288
|
+
return null;
|
|
37289
|
+
}
|
|
37290
|
+
const branch = `session-${sessionId}`;
|
|
37291
|
+
const worktreePaths = [];
|
|
37292
|
+
fs23.mkdirSync(sessionDir, { recursive: true });
|
|
37293
|
+
for (const repo of repos) {
|
|
37294
|
+
let rel = path28.relative(bridgeResolved, repo.absolutePath);
|
|
37295
|
+
if (rel.startsWith("..") || path28.isAbsolute(rel)) continue;
|
|
37296
|
+
const relNorm = normalizeRepoRelPath(rel === "" ? "." : rel);
|
|
37297
|
+
const wtPath = relNorm === "." ? sessionDir : path28.join(sessionDir, relNorm);
|
|
37298
|
+
if (relNorm !== ".") {
|
|
37299
|
+
fs23.mkdirSync(path28.dirname(wtPath), { recursive: true });
|
|
37300
|
+
}
|
|
37301
|
+
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
37302
|
+
try {
|
|
37303
|
+
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch, baseRef);
|
|
37304
|
+
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}, base ${baseRef}).`);
|
|
37305
|
+
worktreePaths.push(wtPath);
|
|
37306
|
+
} catch (e) {
|
|
37307
|
+
log2(
|
|
37308
|
+
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
37309
|
+
);
|
|
37310
|
+
}
|
|
37311
|
+
}
|
|
37312
|
+
if (worktreePaths.length === 0) return null;
|
|
37313
|
+
return {
|
|
37314
|
+
worktreePaths,
|
|
37315
|
+
sessionParentPath: sessionDir,
|
|
37316
|
+
workingTreeRelRoot: sessionDir
|
|
37317
|
+
};
|
|
37318
|
+
}
|
|
37319
|
+
|
|
37320
|
+
// src/worktrees/manager/prepare-and-remember-session-worktrees.ts
|
|
37321
|
+
async function prepareAndRememberSessionWorktrees(params) {
|
|
37322
|
+
const prep = await prepareNewSessionWorktrees({
|
|
37323
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
37324
|
+
bridgeRoot: getBridgeRoot(),
|
|
37325
|
+
sessionId: params.sessionId,
|
|
37326
|
+
layout: params.layout,
|
|
37327
|
+
log: params.log,
|
|
37328
|
+
...params.worktreeBaseBranches && Object.keys(params.worktreeBaseBranches).length > 0 ? { worktreeBaseBranches: params.worktreeBaseBranches } : {}
|
|
37329
|
+
});
|
|
37330
|
+
if (!prep) return void 0;
|
|
37331
|
+
params.cache.remember(params.sessionId, {
|
|
37332
|
+
sessionParentPath: prep.sessionParentPath,
|
|
37333
|
+
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
37334
|
+
repoCheckoutPaths: prep.worktreePaths
|
|
37335
|
+
});
|
|
37336
|
+
return params.cache.getSessionParentPath(params.sessionId);
|
|
37337
|
+
}
|
|
37338
|
+
|
|
37339
|
+
// src/worktrees/manager/resolve-existing-session-parent-path.ts
|
|
37340
|
+
async function resolveExistingSessionParentPath(sessionId, cache2, discover) {
|
|
37341
|
+
const cached2 = cache2.getSessionParentPath(sessionId);
|
|
37342
|
+
if (cached2) return cached2;
|
|
37343
|
+
const disc = await discover();
|
|
37344
|
+
if (disc) {
|
|
37345
|
+
cache2.remember(sessionId, disc);
|
|
37346
|
+
return cache2.getSessionParentPath(sessionId);
|
|
37347
|
+
}
|
|
37348
|
+
return void 0;
|
|
37349
|
+
}
|
|
37350
|
+
|
|
37351
|
+
// src/worktrees/manager/resolve-explicit-session-parent-path.ts
|
|
37352
|
+
import * as path29 from "node:path";
|
|
37353
|
+
async function resolveExplicitSessionParentPath(params) {
|
|
37354
|
+
const resolved = path29.resolve(params.parentPathRaw);
|
|
37355
|
+
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
37356
|
+
return resolved;
|
|
37357
|
+
}
|
|
37358
|
+
const rememberAndReturn = (binding) => {
|
|
37359
|
+
params.cache.remember(params.sessionId, binding);
|
|
37360
|
+
return params.cache.getSessionParentPath(params.sessionId) ?? resolved;
|
|
37361
|
+
};
|
|
37362
|
+
const diskFirst = await params.discover();
|
|
37363
|
+
if (diskFirst) return rememberAndReturn(diskFirst);
|
|
37364
|
+
const fromRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, params.sessionId);
|
|
37365
|
+
if (fromRoot) return rememberAndReturn(fromRoot);
|
|
37366
|
+
let cur = resolved;
|
|
37367
|
+
for (let i = 0; i < 16; i++) {
|
|
37368
|
+
await yieldToEventLoop();
|
|
37369
|
+
const tryRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
37370
|
+
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
37371
|
+
const next = path29.dirname(cur);
|
|
37372
|
+
if (next === cur) break;
|
|
37373
|
+
cur = next;
|
|
37374
|
+
}
|
|
37375
|
+
return resolved;
|
|
37376
|
+
}
|
|
37377
|
+
|
|
37378
|
+
// src/worktrees/manager/resolve-session-parent-path-for-prompt.ts
|
|
37379
|
+
async function resolveSessionParentPathForPrompt(params) {
|
|
37380
|
+
const { sessionId, cache: cache2, worktreesRootPath, layout, log: log2, discover, opts } = params;
|
|
37381
|
+
if (!sessionId) return void 0;
|
|
37382
|
+
const sid = sessionId.trim();
|
|
37383
|
+
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
37384
|
+
if (parentPathRaw) {
|
|
37385
|
+
return resolveExplicitSessionParentPath({
|
|
37386
|
+
sessionId: sid,
|
|
37387
|
+
sessionParent: opts.sessionParent,
|
|
37388
|
+
parentPathRaw,
|
|
37389
|
+
cache: cache2,
|
|
37390
|
+
discover: () => discover(sid)
|
|
37391
|
+
});
|
|
37392
|
+
}
|
|
37393
|
+
const parentKind = parseSessionParent(opts.sessionParent);
|
|
37394
|
+
if (parentKind === "bridge_root") {
|
|
37395
|
+
return void 0;
|
|
37396
|
+
}
|
|
37397
|
+
if (parentKind === "worktrees_root") {
|
|
37398
|
+
if (!opts.isNewSession) {
|
|
37399
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
37400
|
+
}
|
|
37401
|
+
return prepareAndRememberSessionWorktrees({
|
|
37402
|
+
cache: cache2,
|
|
37403
|
+
sessionId: sid,
|
|
37404
|
+
worktreesRootPath,
|
|
37405
|
+
layout,
|
|
37406
|
+
log: log2,
|
|
37407
|
+
...opts.worktreeBaseBranches ? { worktreeBaseBranches: opts.worktreeBaseBranches } : {}
|
|
37408
|
+
});
|
|
37409
|
+
}
|
|
37410
|
+
if (!opts.isNewSession) {
|
|
37411
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
37412
|
+
}
|
|
37413
|
+
return prepareAndRememberSessionWorktrees({
|
|
37414
|
+
cache: cache2,
|
|
37415
|
+
sessionId: sid,
|
|
37416
|
+
worktreesRootPath,
|
|
37417
|
+
layout,
|
|
37418
|
+
log: log2
|
|
37419
|
+
});
|
|
37420
|
+
}
|
|
37421
|
+
|
|
36865
37422
|
// src/git/changes/types.ts
|
|
36866
37423
|
var MAX_PATCH_CHARS = 35e4;
|
|
36867
37424
|
|
|
@@ -36919,8 +37476,11 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
36919
37476
|
return `origin \xB7 ${hostPath}`;
|
|
36920
37477
|
}
|
|
36921
37478
|
|
|
36922
|
-
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
36923
|
-
import * as
|
|
37479
|
+
// src/git/changes/repo/get-working-tree-change-repo-details.ts
|
|
37480
|
+
import * as path34 from "node:path";
|
|
37481
|
+
|
|
37482
|
+
// src/git/changes/repo/build-working-tree-change-repo-detail.ts
|
|
37483
|
+
import * as path33 from "node:path";
|
|
36924
37484
|
|
|
36925
37485
|
// src/git/commits/resolve-remote-tracking.ts
|
|
36926
37486
|
async function tryConfigGet(g, key) {
|
|
@@ -37091,8 +37651,8 @@ async function listRecentCommits(repoDir, limitInput) {
|
|
|
37091
37651
|
}
|
|
37092
37652
|
|
|
37093
37653
|
// src/git/changes/parse/normalize-git-diff-path.ts
|
|
37094
|
-
function normalizeGitDiffPath(
|
|
37095
|
-
return
|
|
37654
|
+
function normalizeGitDiffPath(path55) {
|
|
37655
|
+
return path55.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
|
|
37096
37656
|
}
|
|
37097
37657
|
|
|
37098
37658
|
// src/git/changes/parse/expand-git-rename-numstat-path.ts
|
|
@@ -37205,8 +37765,8 @@ async function unifiedDiffForFileInRange(repoCwd, range, pathInRepo, change, mov
|
|
|
37205
37765
|
}
|
|
37206
37766
|
|
|
37207
37767
|
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
37208
|
-
import * as
|
|
37209
|
-
import * as
|
|
37768
|
+
import * as fs24 from "node:fs";
|
|
37769
|
+
import * as path30 from "node:path";
|
|
37210
37770
|
|
|
37211
37771
|
// src/git/changes/lines/count-lines.ts
|
|
37212
37772
|
import { createReadStream } from "node:fs";
|
|
@@ -37252,13 +37812,13 @@ async function countLinesInGitRef(repoGitCwd, ref, pathInRepo) {
|
|
|
37252
37812
|
}
|
|
37253
37813
|
async function resolveWorkingTreeFileTotalLines(options) {
|
|
37254
37814
|
if (options.isBinary) return null;
|
|
37255
|
-
const filePath =
|
|
37815
|
+
const filePath = path30.join(options.repoGitCwd, options.pathInRepo);
|
|
37256
37816
|
if (options.change === "removed") {
|
|
37257
37817
|
return countLinesInGitRef(options.repoGitCwd, "HEAD", options.pathInRepo);
|
|
37258
37818
|
}
|
|
37259
37819
|
if (options.change === "moved" || options.change === "modified") {
|
|
37260
37820
|
try {
|
|
37261
|
-
const st = await
|
|
37821
|
+
const st = await fs24.promises.stat(filePath);
|
|
37262
37822
|
if (!st.isFile()) return null;
|
|
37263
37823
|
return await countTextFileLines(filePath);
|
|
37264
37824
|
} catch {
|
|
@@ -37287,7 +37847,7 @@ function pathInRepoFromLauncher(pathRelLauncher, repoRelPath) {
|
|
|
37287
37847
|
}
|
|
37288
37848
|
return pathRelLauncher;
|
|
37289
37849
|
}
|
|
37290
|
-
function
|
|
37850
|
+
function normalizeRepoRelPath2(repoRelPath) {
|
|
37291
37851
|
return repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
37292
37852
|
}
|
|
37293
37853
|
|
|
@@ -37389,8 +37949,8 @@ function parseNumstatEntries(lines) {
|
|
|
37389
37949
|
}
|
|
37390
37950
|
function parseNumstat(lines) {
|
|
37391
37951
|
const m = /* @__PURE__ */ new Map();
|
|
37392
|
-
for (const [
|
|
37393
|
-
m.set(
|
|
37952
|
+
for (const [path55, entry] of parseNumstatEntries(lines)) {
|
|
37953
|
+
m.set(path55, { additions: entry.additions, deletions: entry.deletions });
|
|
37394
37954
|
}
|
|
37395
37955
|
return m;
|
|
37396
37956
|
}
|
|
@@ -37521,7 +38081,7 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
37521
38081
|
g.raw(["diff", ...RENAME_DIFF_ARGS, "--numstat", range]).catch(() => "")
|
|
37522
38082
|
]);
|
|
37523
38083
|
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
37524
|
-
const normRel =
|
|
38084
|
+
const normRel = normalizeRepoRelPath2(repoRelPath);
|
|
37525
38085
|
const paths = collectChangedPaths({
|
|
37526
38086
|
nameEntries: parsed.nameEntries,
|
|
37527
38087
|
numByPath: parsed.numByPath
|
|
@@ -37549,14 +38109,14 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
37549
38109
|
}
|
|
37550
38110
|
|
|
37551
38111
|
// src/git/changes/listing/apply-untracked-file-stats.ts
|
|
37552
|
-
import * as
|
|
37553
|
-
import * as
|
|
38112
|
+
import * as fs25 from "node:fs";
|
|
38113
|
+
import * as path31 from "node:path";
|
|
37554
38114
|
function createUntrackedStatsApplier(options) {
|
|
37555
38115
|
return async (row, pathInRepo) => {
|
|
37556
38116
|
if (!options.untrackedSet.has(pathInRepo)) return;
|
|
37557
38117
|
if (options.nameByPath.has(pathInRepo)) return;
|
|
37558
38118
|
if (row.change === "moved") return;
|
|
37559
|
-
const repoFilePath =
|
|
38119
|
+
const repoFilePath = path31.join(options.repoGitCwd, pathInRepo);
|
|
37560
38120
|
const fromGit = await numstatFromGitNoIndex(options.g, pathInRepo);
|
|
37561
38121
|
if (fromGit) {
|
|
37562
38122
|
row.additions = fromGit.additions;
|
|
@@ -37564,7 +38124,7 @@ function createUntrackedStatsApplier(options) {
|
|
|
37564
38124
|
return;
|
|
37565
38125
|
}
|
|
37566
38126
|
try {
|
|
37567
|
-
const st = await
|
|
38127
|
+
const st = await fs25.promises.stat(repoFilePath);
|
|
37568
38128
|
row.additions = st.isFile() ? await countTextFileLines(repoFilePath) : 0;
|
|
37569
38129
|
} catch {
|
|
37570
38130
|
row.additions = 0;
|
|
@@ -37574,13 +38134,75 @@ function createUntrackedStatsApplier(options) {
|
|
|
37574
38134
|
}
|
|
37575
38135
|
|
|
37576
38136
|
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
37577
|
-
import * as
|
|
38137
|
+
import * as path32 from "node:path";
|
|
37578
38138
|
|
|
37579
|
-
// src/git/changes/patch/hydrate-
|
|
37580
|
-
|
|
38139
|
+
// src/git/changes/patch/hydrate/append-injected-context-lines.ts
|
|
38140
|
+
async function appendInjectedContextLines(out, inject, maybeYield, injectedTotal) {
|
|
38141
|
+
for (const t of inject) {
|
|
38142
|
+
out.push(` ${t}`);
|
|
38143
|
+
injectedTotal.value++;
|
|
38144
|
+
await maybeYield();
|
|
38145
|
+
}
|
|
38146
|
+
}
|
|
38147
|
+
|
|
38148
|
+
// src/git/changes/patch/hydrate/constants.ts
|
|
37581
38149
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
37582
38150
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
37583
38151
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
38152
|
+
var HYDRATE_YIELD_EVERY_LINES = 512;
|
|
38153
|
+
|
|
38154
|
+
// src/git/changes/patch/hydrate/collect-gap-inject-lines.ts
|
|
38155
|
+
async function collectGapInjectLines(options) {
|
|
38156
|
+
if (options.injectedTotal >= MAX_HYDRATE_LINES_PER_FILE) return null;
|
|
38157
|
+
const remaining = MAX_HYDRATE_LINES_PER_FILE - options.injectedTotal;
|
|
38158
|
+
if (options.gapNewEnd >= options.gapNewStart && options.change !== "removed") {
|
|
38159
|
+
const nNew = options.gapNewEnd - options.gapNewStart + 1;
|
|
38160
|
+
if (options.gapOldEnd < options.gapOldStart || options.gapOldEnd - options.gapOldStart + 1 === nNew) {
|
|
38161
|
+
const cap = Math.min(nNew, MAX_HYDRATE_LINES_PER_GAP, remaining);
|
|
38162
|
+
const dl = await options.diskLines();
|
|
38163
|
+
if (dl && cap > 0) {
|
|
38164
|
+
return dl.slice(options.gapNewStart - 1, options.gapNewStart - 1 + cap);
|
|
38165
|
+
}
|
|
38166
|
+
}
|
|
38167
|
+
return null;
|
|
38168
|
+
}
|
|
38169
|
+
if (options.gapOldEnd >= options.gapOldStart && options.change === "removed") {
|
|
38170
|
+
const nOld = options.gapOldEnd - options.gapOldStart + 1;
|
|
38171
|
+
const cap = Math.min(nOld, MAX_HYDRATE_LINES_PER_GAP, remaining);
|
|
38172
|
+
const bl = await options.blobLines();
|
|
38173
|
+
if (bl && cap > 0) {
|
|
38174
|
+
return bl.slice(options.gapOldStart - 1, options.gapOldStart - 1 + cap);
|
|
38175
|
+
}
|
|
38176
|
+
}
|
|
38177
|
+
return null;
|
|
38178
|
+
}
|
|
38179
|
+
|
|
38180
|
+
// src/git/changes/patch/hydrate/consume-unified-hunk-body.ts
|
|
38181
|
+
async function consumeUnifiedHunkBody(options) {
|
|
38182
|
+
let i = options.startIndex;
|
|
38183
|
+
let oldConsumed = 0;
|
|
38184
|
+
let newConsumed = 0;
|
|
38185
|
+
while (i < options.all.length) {
|
|
38186
|
+
await options.maybeYield();
|
|
38187
|
+
const bl = options.all[i];
|
|
38188
|
+
if (UNIFIED_HUNK_HEADER_RE.test(bl)) break;
|
|
38189
|
+
options.out.push(bl);
|
|
38190
|
+
i++;
|
|
38191
|
+
if (bl.startsWith("\\")) continue;
|
|
38192
|
+
const ch = bl[0];
|
|
38193
|
+
if (ch === " ") {
|
|
38194
|
+
oldConsumed++;
|
|
38195
|
+
newConsumed++;
|
|
38196
|
+
} else if (ch === "-") {
|
|
38197
|
+
oldConsumed++;
|
|
38198
|
+
} else if (ch === "+") {
|
|
38199
|
+
newConsumed++;
|
|
38200
|
+
}
|
|
38201
|
+
}
|
|
38202
|
+
return { nextIndex: i, oldConsumed, newConsumed };
|
|
38203
|
+
}
|
|
38204
|
+
|
|
38205
|
+
// src/git/changes/patch/hydrate/read-git-blob-lines.ts
|
|
37584
38206
|
async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
37585
38207
|
try {
|
|
37586
38208
|
const rel = pathInRepo.replace(/\\/g, "/");
|
|
@@ -37590,35 +38212,66 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
37590
38212
|
return null;
|
|
37591
38213
|
}
|
|
37592
38214
|
}
|
|
38215
|
+
|
|
38216
|
+
// src/git/changes/patch/hydrate/read-worktree-file-lines.ts
|
|
38217
|
+
import * as fs26 from "node:fs";
|
|
37593
38218
|
async function readWorktreeFileLines(filePath) {
|
|
37594
38219
|
try {
|
|
37595
|
-
const raw = await
|
|
38220
|
+
const raw = await fs26.promises.readFile(filePath, "utf8");
|
|
37596
38221
|
return raw.split(/\r?\n/);
|
|
37597
38222
|
} catch {
|
|
37598
38223
|
return null;
|
|
37599
38224
|
}
|
|
37600
38225
|
}
|
|
37601
|
-
|
|
37602
|
-
|
|
37603
|
-
|
|
37604
|
-
const out = [];
|
|
37605
|
-
let prevOldEnd = 0;
|
|
37606
|
-
let prevNewEnd = 0;
|
|
37607
|
-
let injectedTotal = 0;
|
|
37608
|
-
let i = 0;
|
|
38226
|
+
|
|
38227
|
+
// src/git/changes/patch/hydrate/create-hydrate-source-lines.ts
|
|
38228
|
+
function createHydrateSourceLines(options) {
|
|
37609
38229
|
let blobCache;
|
|
37610
38230
|
let diskCache;
|
|
37611
38231
|
const blobLines = async () => {
|
|
37612
38232
|
if (blobCache !== void 0) return blobCache;
|
|
37613
|
-
blobCache = await readGitBlobLines(repoGitCwd, pathInRepo);
|
|
38233
|
+
blobCache = await readGitBlobLines(options.repoGitCwd, options.pathInRepo);
|
|
37614
38234
|
return blobCache;
|
|
37615
38235
|
};
|
|
37616
38236
|
const diskLines = async () => {
|
|
37617
38237
|
if (diskCache !== void 0) return diskCache;
|
|
37618
|
-
diskCache = await readWorktreeFileLines(filePath);
|
|
38238
|
+
diskCache = await readWorktreeFileLines(options.filePath);
|
|
37619
38239
|
return diskCache;
|
|
37620
38240
|
};
|
|
38241
|
+
return { blobLines, diskLines };
|
|
38242
|
+
}
|
|
38243
|
+
|
|
38244
|
+
// src/git/changes/patch/hydrate/create-hydrate-yield.ts
|
|
38245
|
+
function createHydrateYield() {
|
|
38246
|
+
let processedLines = 0;
|
|
38247
|
+
return async () => {
|
|
38248
|
+
processedLines++;
|
|
38249
|
+
if (processedLines % HYDRATE_YIELD_EVERY_LINES === 0) {
|
|
38250
|
+
await yieldToEventLoop();
|
|
38251
|
+
}
|
|
38252
|
+
};
|
|
38253
|
+
}
|
|
38254
|
+
|
|
38255
|
+
// src/git/changes/patch/hydrate/update-hunk-line-ends.ts
|
|
38256
|
+
function updateHunkLineEnds(options) {
|
|
38257
|
+
const prevOldEnd = options.oldStart > 0 ? options.oldStart + options.oldConsumed - 1 : 0;
|
|
38258
|
+
const prevNewEnd = options.newStart > 0 ? options.newStart + options.newConsumed - 1 : 0;
|
|
38259
|
+
return { prevOldEnd, prevNewEnd };
|
|
38260
|
+
}
|
|
38261
|
+
|
|
38262
|
+
// src/git/changes/patch/hydrate/hydrate-unified-patch-with-file-context.ts
|
|
38263
|
+
async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, change) {
|
|
38264
|
+
if (!patch.trim() || patch.includes("Binary files")) return patch;
|
|
38265
|
+
const all = patch.split("\n");
|
|
38266
|
+
const out = [];
|
|
38267
|
+
let prevOldEnd = 0;
|
|
38268
|
+
let prevNewEnd = 0;
|
|
38269
|
+
const injectedTotal = { value: 0 };
|
|
38270
|
+
let i = 0;
|
|
38271
|
+
const maybeYield = createHydrateYield();
|
|
38272
|
+
const { blobLines, diskLines } = createHydrateSourceLines({ repoGitCwd, pathInRepo, filePath });
|
|
37621
38273
|
while (i < all.length) {
|
|
38274
|
+
await maybeYield();
|
|
37622
38275
|
const line = all[i];
|
|
37623
38276
|
const hm = line.match(UNIFIED_HUNK_HEADER_RE);
|
|
37624
38277
|
if (!hm) {
|
|
@@ -37628,66 +38281,31 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
37628
38281
|
}
|
|
37629
38282
|
const oldStart = parseInt(hm[1], 10) || 0;
|
|
37630
38283
|
const newStart = parseInt(hm[3], 10) || 0;
|
|
37631
|
-
const
|
|
37632
|
-
|
|
37633
|
-
|
|
37634
|
-
|
|
37635
|
-
|
|
37636
|
-
|
|
37637
|
-
|
|
37638
|
-
|
|
37639
|
-
|
|
37640
|
-
|
|
37641
|
-
|
|
37642
|
-
|
|
37643
|
-
inject = dl.slice(gapNewStart - 1, gapNewStart - 1 + cap);
|
|
37644
|
-
}
|
|
37645
|
-
}
|
|
37646
|
-
} else if (gapOldEnd >= gapOldStart && change === "removed") {
|
|
37647
|
-
const nOld = gapOldEnd - gapOldStart + 1;
|
|
37648
|
-
const cap = Math.min(nOld, MAX_HYDRATE_LINES_PER_GAP, MAX_HYDRATE_LINES_PER_FILE - injectedTotal);
|
|
37649
|
-
const bl = await blobLines();
|
|
37650
|
-
if (bl && cap > 0) {
|
|
37651
|
-
inject = bl.slice(gapOldStart - 1, gapOldStart - 1 + cap);
|
|
37652
|
-
}
|
|
37653
|
-
}
|
|
37654
|
-
if (inject && inject.length > 0) {
|
|
37655
|
-
for (const t of inject) {
|
|
37656
|
-
out.push(` ${t}`);
|
|
37657
|
-
injectedTotal++;
|
|
37658
|
-
}
|
|
37659
|
-
}
|
|
38284
|
+
const inject = await collectGapInjectLines({
|
|
38285
|
+
change,
|
|
38286
|
+
gapOldStart: prevOldEnd + 1,
|
|
38287
|
+
gapOldEnd: oldStart - 1,
|
|
38288
|
+
gapNewStart: prevNewEnd + 1,
|
|
38289
|
+
gapNewEnd: newStart - 1,
|
|
38290
|
+
injectedTotal: injectedTotal.value,
|
|
38291
|
+
blobLines,
|
|
38292
|
+
diskLines
|
|
38293
|
+
});
|
|
38294
|
+
if (inject && inject.length > 0) {
|
|
38295
|
+
await appendInjectedContextLines(out, inject, maybeYield, injectedTotal);
|
|
37660
38296
|
}
|
|
37661
38297
|
out.push(line);
|
|
37662
38298
|
i++;
|
|
37663
|
-
|
|
37664
|
-
|
|
37665
|
-
|
|
37666
|
-
|
|
37667
|
-
|
|
37668
|
-
|
|
37669
|
-
|
|
37670
|
-
|
|
37671
|
-
|
|
37672
|
-
|
|
37673
|
-
oldConsumed++;
|
|
37674
|
-
newConsumed++;
|
|
37675
|
-
} else if (ch === "-") {
|
|
37676
|
-
oldConsumed++;
|
|
37677
|
-
} else if (ch === "+") {
|
|
37678
|
-
newConsumed++;
|
|
37679
|
-
}
|
|
37680
|
-
}
|
|
37681
|
-
if (oldStart > 0) {
|
|
37682
|
-
prevOldEnd = oldStart + oldConsumed - 1;
|
|
37683
|
-
} else {
|
|
37684
|
-
prevOldEnd = 0;
|
|
37685
|
-
}
|
|
37686
|
-
if (newStart > 0) {
|
|
37687
|
-
prevNewEnd = newStart + newConsumed - 1;
|
|
37688
|
-
} else {
|
|
37689
|
-
prevNewEnd = 0;
|
|
37690
|
-
}
|
|
38299
|
+
const body = await consumeUnifiedHunkBody({ all, startIndex: i, out, maybeYield });
|
|
38300
|
+
i = body.nextIndex;
|
|
38301
|
+
const ends = updateHunkLineEnds({
|
|
38302
|
+
oldStart,
|
|
38303
|
+
newStart,
|
|
38304
|
+
oldConsumed: body.oldConsumed,
|
|
38305
|
+
newConsumed: body.newConsumed
|
|
38306
|
+
});
|
|
38307
|
+
prevOldEnd = ends.prevOldEnd;
|
|
38308
|
+
prevNewEnd = ends.prevNewEnd;
|
|
37691
38309
|
}
|
|
37692
38310
|
return truncatePatch(out.join("\n"));
|
|
37693
38311
|
}
|
|
@@ -37696,7 +38314,7 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
37696
38314
|
async function enrichWorkingTreeFileRows(options) {
|
|
37697
38315
|
await forEachWithGitYield(options.rows, async (row) => {
|
|
37698
38316
|
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
37699
|
-
const filePath =
|
|
38317
|
+
const filePath = path32.join(options.repoGitCwd, pathInRepo);
|
|
37700
38318
|
const hydrateKind = row.change === "moved" ? "modified" : row.change;
|
|
37701
38319
|
let patch = await unifiedDiffForFile(options.repoGitCwd, pathInRepo, row.change, row.movedFromPathInRepo);
|
|
37702
38320
|
if (patch) {
|
|
@@ -37758,14 +38376,76 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
37758
38376
|
return dedupeChangedFileRows(rows);
|
|
37759
38377
|
}
|
|
37760
38378
|
|
|
37761
|
-
// src/git/changes/
|
|
38379
|
+
// src/git/changes/repo/norm-repo-rel-path.ts
|
|
37762
38380
|
function normRepoRel(p) {
|
|
37763
38381
|
const x = p.replace(/\\/g, "/").trim();
|
|
37764
38382
|
return x === "" ? "." : x;
|
|
37765
38383
|
}
|
|
38384
|
+
|
|
38385
|
+
// src/git/changes/repo/build-working-tree-change-repo-detail.ts
|
|
38386
|
+
async function buildWorkingTreeChangeRepoDetail(options) {
|
|
38387
|
+
const t = path33.resolve(options.targetPath);
|
|
38388
|
+
if (!await isGitRepoDirectory(t)) return null;
|
|
38389
|
+
const g = cliSimpleGit(t);
|
|
38390
|
+
let branch = "HEAD";
|
|
38391
|
+
try {
|
|
38392
|
+
await yieldToEventLoop2();
|
|
38393
|
+
branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim() || "HEAD";
|
|
38394
|
+
} catch {
|
|
38395
|
+
branch = "HEAD";
|
|
38396
|
+
}
|
|
38397
|
+
await yieldToEventLoop2();
|
|
38398
|
+
const remoteUrl = await getRemoteOriginUrl(t);
|
|
38399
|
+
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
38400
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path33.resolve(options.sessionWorktreeRootPath) : null;
|
|
38401
|
+
const legacyNested = options.legacyRepoNestedSessionLayout;
|
|
38402
|
+
let repoRelPath;
|
|
38403
|
+
if (sessionWtRoot) {
|
|
38404
|
+
const anchor = legacyNested ? path33.dirname(t) : t;
|
|
38405
|
+
const relNorm = path33.relative(sessionWtRoot, anchor);
|
|
38406
|
+
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
38407
|
+
} else {
|
|
38408
|
+
let top = t;
|
|
38409
|
+
try {
|
|
38410
|
+
await yieldToEventLoop2();
|
|
38411
|
+
top = (await g.raw(["rev-parse", "--show-toplevel"])).trim();
|
|
38412
|
+
} catch {
|
|
38413
|
+
top = t;
|
|
38414
|
+
}
|
|
38415
|
+
const rel = path33.relative(options.bridgeRoot, path33.resolve(top)).replace(/\\/g, "/") || ".";
|
|
38416
|
+
repoRelPath = rel.startsWith("..") ? path33.basename(path33.resolve(top)) : rel;
|
|
38417
|
+
}
|
|
38418
|
+
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
38419
|
+
if (options.repoFilterRelPath && norm !== options.repoFilterRelPath) return null;
|
|
38420
|
+
const repoDisplayName = formatRepoShortTitle(remoteUrl, norm === "." ? "." : norm);
|
|
38421
|
+
const relForList = norm === "." ? "." : norm;
|
|
38422
|
+
const files = options.basis.kind === "commit" ? await listChangedFilesForCommit(t, relForList, options.basis.sha.trim()) : await listChangedFilesForRepo(t, relForList);
|
|
38423
|
+
const st = await g.status();
|
|
38424
|
+
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
38425
|
+
const [unpushedCommits, recentCommitList] = await Promise.all([
|
|
38426
|
+
listUnpushedCommits(t),
|
|
38427
|
+
listRecentCommits(t, options.recentCommitsLimit)
|
|
38428
|
+
]);
|
|
38429
|
+
return {
|
|
38430
|
+
repoRelPath: norm,
|
|
38431
|
+
repoDisplayName,
|
|
38432
|
+
branch,
|
|
38433
|
+
remoteUrl,
|
|
38434
|
+
remoteDisplay,
|
|
38435
|
+
files,
|
|
38436
|
+
hasUncommittedChanges,
|
|
38437
|
+
unpushedCommits,
|
|
38438
|
+
recentCommits: recentCommitList.commits,
|
|
38439
|
+
recentCommitsHasMore: recentCommitList.hasMore,
|
|
38440
|
+
changesView: options.basis.kind === "commit" ? "commit" : "working",
|
|
38441
|
+
changesCommitSha: options.basis.kind === "commit" ? options.basis.sha.trim() : null
|
|
38442
|
+
};
|
|
38443
|
+
}
|
|
38444
|
+
|
|
38445
|
+
// src/git/changes/repo/get-working-tree-change-repo-details.ts
|
|
37766
38446
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
37767
|
-
const bridgeRoot =
|
|
37768
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
38447
|
+
const bridgeRoot = path34.resolve(getBridgeRoot());
|
|
38448
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path34.resolve(options.sessionWorktreeRootPath) : null;
|
|
37769
38449
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
37770
38450
|
const out = [];
|
|
37771
38451
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -37778,59 +38458,18 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
37778
38458
|
}
|
|
37779
38459
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
37780
38460
|
for (let i = 0; i < options.commitTargetPaths.length; i++) {
|
|
37781
|
-
|
|
37782
|
-
const
|
|
37783
|
-
|
|
37784
|
-
|
|
37785
|
-
|
|
37786
|
-
|
|
37787
|
-
|
|
37788
|
-
|
|
37789
|
-
|
|
37790
|
-
|
|
37791
|
-
|
|
37792
|
-
|
|
37793
|
-
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
37794
|
-
let repoRelPath;
|
|
37795
|
-
if (sessionWtRoot) {
|
|
37796
|
-
const anchor = legacyNested ? path23.dirname(t) : t;
|
|
37797
|
-
const relNorm = path23.relative(sessionWtRoot, anchor);
|
|
37798
|
-
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
37799
|
-
} else {
|
|
37800
|
-
let top = t;
|
|
37801
|
-
try {
|
|
37802
|
-
top = (await g.raw(["rev-parse", "--show-toplevel"])).trim();
|
|
37803
|
-
} catch {
|
|
37804
|
-
top = t;
|
|
37805
|
-
}
|
|
37806
|
-
const rel = path23.relative(bridgeRoot, path23.resolve(top)).replace(/\\/g, "/") || ".";
|
|
37807
|
-
repoRelPath = rel.startsWith("..") ? path23.basename(path23.resolve(top)) : rel;
|
|
37808
|
-
}
|
|
37809
|
-
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
37810
|
-
if (filter && norm !== filter) continue;
|
|
37811
|
-
const repoDisplayName = formatRepoShortTitle(remoteUrl, norm === "." ? "." : norm);
|
|
37812
|
-
const relForList = norm === "." ? "." : norm;
|
|
37813
|
-
const files = basis.kind === "commit" ? await listChangedFilesForCommit(t, relForList, basis.sha.trim()) : await listChangedFilesForRepo(t, relForList);
|
|
37814
|
-
const st = await g.status();
|
|
37815
|
-
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
37816
|
-
const [unpushedCommits, recentCommitList] = await Promise.all([
|
|
37817
|
-
listUnpushedCommits(t),
|
|
37818
|
-
listRecentCommits(t, options.recentCommitsLimit)
|
|
37819
|
-
]);
|
|
37820
|
-
out.push({
|
|
37821
|
-
repoRelPath: norm,
|
|
37822
|
-
repoDisplayName,
|
|
37823
|
-
branch,
|
|
37824
|
-
remoteUrl,
|
|
37825
|
-
remoteDisplay,
|
|
37826
|
-
files,
|
|
37827
|
-
hasUncommittedChanges,
|
|
37828
|
-
unpushedCommits,
|
|
37829
|
-
recentCommits: recentCommitList.commits,
|
|
37830
|
-
recentCommitsHasMore: recentCommitList.hasMore,
|
|
37831
|
-
changesView: basis.kind === "commit" ? "commit" : "working",
|
|
37832
|
-
changesCommitSha: basis.kind === "commit" ? basis.sha.trim() : null
|
|
37833
|
-
});
|
|
38461
|
+
await yieldToEventLoop2();
|
|
38462
|
+
const detail = await buildWorkingTreeChangeRepoDetail({
|
|
38463
|
+
targetPath: options.commitTargetPaths[i],
|
|
38464
|
+
bridgeRoot,
|
|
38465
|
+
sessionWorktreeRootPath: sessionWtRoot,
|
|
38466
|
+
legacyRepoNestedSessionLayout: legacyNested,
|
|
38467
|
+
repoFilterRelPath: filter,
|
|
38468
|
+
basis,
|
|
38469
|
+
recentCommitsLimit: options.recentCommitsLimit
|
|
38470
|
+
});
|
|
38471
|
+
if (!detail) continue;
|
|
38472
|
+
out.push(detail);
|
|
37834
38473
|
if (filter) return out;
|
|
37835
38474
|
}
|
|
37836
38475
|
return out;
|
|
@@ -37932,23 +38571,23 @@ async function commitSessionWorktrees(options) {
|
|
|
37932
38571
|
}
|
|
37933
38572
|
|
|
37934
38573
|
// src/worktrees/remove-session-worktrees.ts
|
|
37935
|
-
import * as
|
|
38574
|
+
import * as fs29 from "node:fs";
|
|
37936
38575
|
|
|
37937
38576
|
// src/git/worktrees/worktree-remove.ts
|
|
37938
|
-
import * as
|
|
38577
|
+
import * as fs28 from "node:fs";
|
|
37939
38578
|
|
|
37940
38579
|
// src/git/worktrees/resolve-main-repo-from-git-file.ts
|
|
37941
|
-
import * as
|
|
37942
|
-
import * as
|
|
38580
|
+
import * as fs27 from "node:fs";
|
|
38581
|
+
import * as path35 from "node:path";
|
|
37943
38582
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
37944
|
-
const gitDirFile =
|
|
37945
|
-
if (!
|
|
37946
|
-
const first2 =
|
|
38583
|
+
const gitDirFile = path35.join(wt, ".git");
|
|
38584
|
+
if (!fs27.existsSync(gitDirFile) || !fs27.statSync(gitDirFile).isFile()) return "";
|
|
38585
|
+
const first2 = fs27.readFileSync(gitDirFile, "utf8").trim();
|
|
37947
38586
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
37948
38587
|
if (!m) return "";
|
|
37949
|
-
const gitWorktreePath =
|
|
37950
|
-
const gitDir =
|
|
37951
|
-
return
|
|
38588
|
+
const gitWorktreePath = path35.resolve(wt, m[1].trim());
|
|
38589
|
+
const gitDir = path35.dirname(path35.dirname(gitWorktreePath));
|
|
38590
|
+
return path35.dirname(gitDir);
|
|
37952
38591
|
}
|
|
37953
38592
|
|
|
37954
38593
|
// src/git/worktrees/worktree-remove.ts
|
|
@@ -37957,7 +38596,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
37957
38596
|
if (mainRepo) {
|
|
37958
38597
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
37959
38598
|
} else {
|
|
37960
|
-
|
|
38599
|
+
fs28.rmSync(worktreePath, { recursive: true, force: true });
|
|
37961
38600
|
}
|
|
37962
38601
|
}
|
|
37963
38602
|
|
|
@@ -37970,7 +38609,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
37970
38609
|
} catch (e) {
|
|
37971
38610
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
37972
38611
|
try {
|
|
37973
|
-
|
|
38612
|
+
fs29.rmSync(wt, { recursive: true, force: true });
|
|
37974
38613
|
} catch {
|
|
37975
38614
|
}
|
|
37976
38615
|
}
|
|
@@ -37998,458 +38637,86 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
37998
38637
|
}
|
|
37999
38638
|
}
|
|
38000
38639
|
|
|
38001
|
-
// src/worktrees/
|
|
38002
|
-
|
|
38003
|
-
import * as path25 from "node:path";
|
|
38004
|
-
import os7 from "node:os";
|
|
38005
|
-
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
38006
|
-
function defaultWorktreeLayoutPath() {
|
|
38007
|
-
return path25.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
38008
|
-
}
|
|
38009
|
-
function normalizeLoadedLayout(raw) {
|
|
38010
|
-
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
38011
|
-
const j = raw;
|
|
38012
|
-
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
38013
|
-
}
|
|
38014
|
-
return { launcherCwds: [] };
|
|
38015
|
-
}
|
|
38016
|
-
function loadWorktreeLayout() {
|
|
38017
|
-
try {
|
|
38018
|
-
const p = defaultWorktreeLayoutPath();
|
|
38019
|
-
if (!fs23.existsSync(p)) return { launcherCwds: [] };
|
|
38020
|
-
const raw = JSON.parse(fs23.readFileSync(p, "utf8"));
|
|
38021
|
-
return normalizeLoadedLayout(raw);
|
|
38022
|
-
} catch {
|
|
38023
|
-
return { launcherCwds: [] };
|
|
38024
|
-
}
|
|
38025
|
-
}
|
|
38026
|
-
function saveWorktreeLayout(layout) {
|
|
38027
|
-
try {
|
|
38028
|
-
const dir = path25.dirname(defaultWorktreeLayoutPath());
|
|
38029
|
-
fs23.mkdirSync(dir, { recursive: true });
|
|
38030
|
-
fs23.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
38031
|
-
} catch {
|
|
38032
|
-
}
|
|
38033
|
-
}
|
|
38034
|
-
function baseNameSafe(pathString) {
|
|
38035
|
-
return path25.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
38036
|
-
}
|
|
38037
|
-
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
38038
|
-
const norm = path25.resolve(bridgeRootPath2);
|
|
38039
|
-
const existing = layout.launcherCwds.find((e) => path25.resolve(e.absolutePath) === norm);
|
|
38040
|
-
return existing?.dirName;
|
|
38041
|
-
}
|
|
38042
|
-
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
38043
|
-
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
38044
|
-
if (existing) return existing;
|
|
38045
|
-
const norm = path25.resolve(bridgeRootPath2);
|
|
38046
|
-
const base = baseNameSafe(norm);
|
|
38047
|
-
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
38048
|
-
let name = base;
|
|
38049
|
-
let n = 2;
|
|
38050
|
-
while (used.has(name)) {
|
|
38051
|
-
name = `${base}-${n}`;
|
|
38052
|
-
n += 1;
|
|
38053
|
-
}
|
|
38054
|
-
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
38055
|
-
saveWorktreeLayout(layout);
|
|
38056
|
-
return name;
|
|
38057
|
-
}
|
|
38058
|
-
|
|
38059
|
-
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
38060
|
-
import * as fs24 from "node:fs";
|
|
38061
|
-
import * as path26 from "node:path";
|
|
38062
|
-
function isGitDir(dirPath) {
|
|
38063
|
-
try {
|
|
38064
|
-
return fs24.existsSync(path26.join(dirPath, ".git"));
|
|
38065
|
-
} catch {
|
|
38066
|
-
return false;
|
|
38067
|
-
}
|
|
38068
|
-
}
|
|
38069
|
-
function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
38070
|
-
const out = [];
|
|
38071
|
-
const walk = (dir) => {
|
|
38072
|
-
if (isGitDir(dir)) {
|
|
38073
|
-
out.push(path26.resolve(dir));
|
|
38074
|
-
return;
|
|
38075
|
-
}
|
|
38076
|
-
let entries;
|
|
38077
|
-
try {
|
|
38078
|
-
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
38079
|
-
} catch {
|
|
38080
|
-
return;
|
|
38081
|
-
}
|
|
38082
|
-
for (const e of entries) {
|
|
38083
|
-
if (e.name.startsWith(".")) continue;
|
|
38084
|
-
const full = path26.join(dir, e.name);
|
|
38085
|
-
if (!e.isDirectory()) continue;
|
|
38086
|
-
walk(full);
|
|
38087
|
-
}
|
|
38088
|
-
};
|
|
38089
|
-
walk(path26.resolve(rootPath));
|
|
38090
|
-
return [...new Set(out)];
|
|
38091
|
-
}
|
|
38092
|
-
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
38093
|
-
const out = [];
|
|
38094
|
-
const walk = (dir, depth) => {
|
|
38095
|
-
if (depth > maxDepth) return;
|
|
38096
|
-
let entries;
|
|
38097
|
-
try {
|
|
38098
|
-
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
38099
|
-
} catch {
|
|
38100
|
-
return;
|
|
38101
|
-
}
|
|
38102
|
-
for (const e of entries) {
|
|
38103
|
-
if (e.name.startsWith(".")) continue;
|
|
38104
|
-
const full = path26.join(dir, e.name);
|
|
38105
|
-
if (!e.isDirectory()) continue;
|
|
38106
|
-
if (e.name === sessionId) {
|
|
38107
|
-
if (isGitDir(full)) out.push(path26.resolve(full));
|
|
38108
|
-
} else {
|
|
38109
|
-
walk(full, depth + 1);
|
|
38110
|
-
}
|
|
38111
|
-
}
|
|
38112
|
-
};
|
|
38113
|
-
walk(root, 0);
|
|
38114
|
-
return out;
|
|
38115
|
-
}
|
|
38116
|
-
function tryBindingFromSessionDirectory(sessionDir) {
|
|
38117
|
-
let st;
|
|
38118
|
-
try {
|
|
38119
|
-
st = fs24.statSync(sessionDir);
|
|
38120
|
-
} catch {
|
|
38121
|
-
return null;
|
|
38122
|
-
}
|
|
38123
|
-
if (!st.isDirectory()) return null;
|
|
38124
|
-
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
38125
|
-
if (worktreePaths.length === 0) return null;
|
|
38126
|
-
const abs = path26.resolve(sessionDir);
|
|
38127
|
-
return {
|
|
38128
|
-
sessionParentPath: abs,
|
|
38129
|
-
workingTreeRelRoot: abs,
|
|
38130
|
-
repoCheckoutPaths: worktreePaths
|
|
38131
|
-
};
|
|
38132
|
-
}
|
|
38133
|
-
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
38134
|
-
const sid = sessionId.trim();
|
|
38135
|
-
if (!sid) return null;
|
|
38136
|
-
const hintR = path26.resolve(checkoutPath);
|
|
38137
|
-
let best = null;
|
|
38138
|
-
let cur = path26.dirname(hintR);
|
|
38139
|
-
for (let i = 0; i < 40; i++) {
|
|
38140
|
-
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
38141
|
-
if (paths.some((p) => path26.resolve(p) === hintR)) {
|
|
38142
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path26.resolve(paths[0]);
|
|
38143
|
-
best = {
|
|
38144
|
-
sessionParentPath: path26.resolve(isolated),
|
|
38145
|
-
workingTreeRelRoot: path26.resolve(cur),
|
|
38146
|
-
repoCheckoutPaths: paths.map((p) => path26.resolve(p))
|
|
38147
|
-
};
|
|
38148
|
-
}
|
|
38149
|
-
const next = path26.dirname(cur);
|
|
38150
|
-
if (next === cur) break;
|
|
38151
|
-
cur = next;
|
|
38152
|
-
}
|
|
38153
|
-
return best;
|
|
38154
|
-
}
|
|
38155
|
-
function discoverSessionWorktreeOnDisk(options) {
|
|
38156
|
-
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
38157
|
-
if (!sessionId.trim() || !fs24.existsSync(worktreesRootPath)) return null;
|
|
38158
|
-
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
38159
|
-
const keys = [];
|
|
38160
|
-
if (preferredKey) keys.push(preferredKey);
|
|
38161
|
-
try {
|
|
38162
|
-
for (const name of fs24.readdirSync(worktreesRootPath)) {
|
|
38163
|
-
if (name.startsWith(".")) continue;
|
|
38164
|
-
const p = path26.join(worktreesRootPath, name);
|
|
38165
|
-
if (!fs24.statSync(p).isDirectory()) continue;
|
|
38166
|
-
if (name !== preferredKey) keys.push(name);
|
|
38167
|
-
}
|
|
38168
|
-
} catch {
|
|
38169
|
-
return null;
|
|
38170
|
-
}
|
|
38171
|
-
for (const key of keys) {
|
|
38172
|
-
const layoutRoot = path26.join(worktreesRootPath, key);
|
|
38173
|
-
if (!fs24.existsSync(layoutRoot) || !fs24.statSync(layoutRoot).isDirectory()) continue;
|
|
38174
|
-
const sessionDir = path26.join(layoutRoot, sessionId);
|
|
38175
|
-
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
38176
|
-
if (nested) return nested;
|
|
38177
|
-
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
38178
|
-
if (legacyPaths.length > 0) {
|
|
38179
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
|
|
38180
|
-
return {
|
|
38181
|
-
sessionParentPath: path26.resolve(isolated),
|
|
38182
|
-
workingTreeRelRoot: path26.resolve(layoutRoot),
|
|
38183
|
-
repoCheckoutPaths: legacyPaths.map((p) => path26.resolve(p))
|
|
38184
|
-
};
|
|
38185
|
-
}
|
|
38186
|
-
}
|
|
38187
|
-
return null;
|
|
38188
|
-
}
|
|
38189
|
-
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
38190
|
-
const sid = sessionId.trim();
|
|
38191
|
-
if (!sid) return null;
|
|
38192
|
-
const hint = path26.resolve(sessionWorktreeRootPathOrHint);
|
|
38193
|
-
const underHint = tryBindingFromSessionDirectory(path26.join(hint, sid));
|
|
38194
|
-
if (underHint) return underHint;
|
|
38195
|
-
const direct = tryBindingFromSessionDirectory(hint);
|
|
38196
|
-
if (direct) {
|
|
38197
|
-
if (path26.basename(hint) === sid && isGitDir(hint)) {
|
|
38198
|
-
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
38199
|
-
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
38200
|
-
return legacyFromCheckout;
|
|
38201
|
-
}
|
|
38202
|
-
}
|
|
38203
|
-
return direct;
|
|
38204
|
-
}
|
|
38205
|
-
if (path26.basename(hint) === sid && isGitDir(hint)) {
|
|
38206
|
-
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
38207
|
-
if (legacyFromCheckout) return legacyFromCheckout;
|
|
38208
|
-
}
|
|
38209
|
-
let st;
|
|
38210
|
-
try {
|
|
38211
|
-
st = fs24.statSync(hint);
|
|
38212
|
-
} catch {
|
|
38213
|
-
return null;
|
|
38214
|
-
}
|
|
38215
|
-
if (!st.isDirectory()) return null;
|
|
38216
|
-
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
38217
|
-
if (legacyPaths.length === 0) return null;
|
|
38218
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
|
|
38640
|
+
// src/worktrees/manager/resolve-commit-targets.ts
|
|
38641
|
+
function bridgeRootBinding(bridgeRoot) {
|
|
38219
38642
|
return {
|
|
38220
|
-
sessionParentPath:
|
|
38221
|
-
workingTreeRelRoot:
|
|
38222
|
-
repoCheckoutPaths:
|
|
38643
|
+
sessionParentPath: bridgeRoot,
|
|
38644
|
+
workingTreeRelRoot: bridgeRoot,
|
|
38645
|
+
repoCheckoutPaths: [bridgeRoot]
|
|
38223
38646
|
};
|
|
38224
38647
|
}
|
|
38225
|
-
|
|
38226
|
-
// src/worktrees/manager/discover-session-binding.ts
|
|
38227
|
-
function discoverSessionBinding(params) {
|
|
38228
|
-
return discoverSessionWorktreeOnDisk({
|
|
38229
|
-
sessionId: params.sessionId,
|
|
38230
|
-
worktreesRootPath: params.worktreesRootPath,
|
|
38231
|
-
layout: params.layout,
|
|
38232
|
-
bridgeRoot: getBridgeRoot()
|
|
38233
|
-
});
|
|
38234
|
-
}
|
|
38235
|
-
|
|
38236
|
-
// src/worktrees/manager/resolve-isolated-session-parent-path.ts
|
|
38237
|
-
function resolveIsolatedSessionParentPath(sessionId, cache2, ensureRepoCheckoutPaths) {
|
|
38238
|
-
if (!sessionId) return null;
|
|
38239
|
-
const sid = sessionId.trim();
|
|
38240
|
-
const cached2 = cache2.getSessionParentPath(sid);
|
|
38241
|
-
if (cached2) return cached2;
|
|
38242
|
-
const paths = ensureRepoCheckoutPaths(sid);
|
|
38243
|
-
if (!paths?.length) return null;
|
|
38244
|
-
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
38245
|
-
}
|
|
38246
|
-
function ensureRepoCheckoutPathsForSession(sessionId, cache2, discover) {
|
|
38247
|
-
if (!sessionId?.trim()) return void 0;
|
|
38648
|
+
async function resolveCommitTargetsAsync(sessionId, cache2, discover) {
|
|
38248
38649
|
const sid = sessionId.trim();
|
|
38249
|
-
const
|
|
38250
|
-
if (cached2?.length) return cached2;
|
|
38251
|
-
const disc = discover(sid);
|
|
38252
|
-
if (disc?.repoCheckoutPaths.length) {
|
|
38253
|
-
cache2.remember(sid, disc);
|
|
38254
|
-
return [...disc.repoCheckoutPaths];
|
|
38255
|
-
}
|
|
38256
|
-
return void 0;
|
|
38257
|
-
}
|
|
38258
|
-
|
|
38259
|
-
// src/worktrees/manager/resolve-commit-targets.ts
|
|
38260
|
-
function resolveCommitTargets(sessionId, cache2, discover) {
|
|
38261
|
-
const paths = cache2.getRepoCheckoutPathsRef(sessionId);
|
|
38650
|
+
const paths = cache2.getRepoCheckoutPathsRef(sid);
|
|
38262
38651
|
if (paths?.length) return paths;
|
|
38263
|
-
const disc = discover(
|
|
38652
|
+
const disc = await discover(sid);
|
|
38264
38653
|
if (disc?.repoCheckoutPaths.length) {
|
|
38265
|
-
cache2.remember(
|
|
38654
|
+
cache2.remember(sid, disc);
|
|
38266
38655
|
return disc.repoCheckoutPaths;
|
|
38267
38656
|
}
|
|
38268
|
-
|
|
38657
|
+
const bridgeRoot = getBridgeRoot();
|
|
38658
|
+
cache2.remember(sid, bridgeRootBinding(bridgeRoot));
|
|
38659
|
+
return [bridgeRoot];
|
|
38269
38660
|
}
|
|
38270
38661
|
|
|
38271
|
-
// src/worktrees/manager/
|
|
38272
|
-
function
|
|
38273
|
-
|
|
38274
|
-
|
|
38275
|
-
return
|
|
38276
|
-
|
|
38277
|
-
|
|
38278
|
-
|
|
38279
|
-
|
|
38280
|
-
|
|
38281
|
-
|
|
38282
|
-
// src/git/worktrees/worktree-add.ts
|
|
38283
|
-
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
38284
|
-
const mainGit = cliSimpleGit(mainRepoPath);
|
|
38285
|
-
const base = baseRef.trim() || "HEAD";
|
|
38286
|
-
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, base]);
|
|
38287
|
-
}
|
|
38288
|
-
|
|
38289
|
-
// src/worktrees/prepare-new-session-worktrees.ts
|
|
38290
|
-
function normalizeRepoRelPath2(rel) {
|
|
38291
|
-
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
38292
|
-
}
|
|
38293
|
-
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
38294
|
-
if (!baseBranches) return "HEAD";
|
|
38295
|
-
const direct = baseBranches[relNorm]?.trim();
|
|
38296
|
-
if (direct) return direct;
|
|
38297
|
-
if (relNorm !== "." && baseBranches["."]?.trim()) return baseBranches["."].trim();
|
|
38298
|
-
return "HEAD";
|
|
38662
|
+
// src/worktrees/manager/session-git-ops.ts
|
|
38663
|
+
async function commitSessionWorktree(cache2, params) {
|
|
38664
|
+
const paths = cache2.getRepoCheckoutPathsRef(params.sessionId);
|
|
38665
|
+
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
38666
|
+
return commitSessionWorktrees({
|
|
38667
|
+
paths: targets,
|
|
38668
|
+
branch: params.branch,
|
|
38669
|
+
message: params.message,
|
|
38670
|
+
push: params.push
|
|
38671
|
+
});
|
|
38299
38672
|
}
|
|
38300
|
-
async function
|
|
38301
|
-
|
|
38302
|
-
|
|
38303
|
-
|
|
38304
|
-
const bridgeKeyDir = path27.join(worktreesRootPath, cwdKey);
|
|
38305
|
-
const sessionDir = path27.join(bridgeKeyDir, sessionId);
|
|
38306
|
-
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
38307
|
-
if (repos.length === 0) {
|
|
38308
|
-
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
38309
|
-
return null;
|
|
38310
|
-
}
|
|
38311
|
-
const branch = `session-${sessionId}`;
|
|
38312
|
-
const worktreePaths = [];
|
|
38313
|
-
fs25.mkdirSync(sessionDir, { recursive: true });
|
|
38314
|
-
for (const repo of repos) {
|
|
38315
|
-
let rel = path27.relative(bridgeResolved, repo.absolutePath);
|
|
38316
|
-
if (rel.startsWith("..") || path27.isAbsolute(rel)) continue;
|
|
38317
|
-
const relNorm = normalizeRepoRelPath2(rel === "" ? "." : rel);
|
|
38318
|
-
const wtPath = relNorm === "." ? sessionDir : path27.join(sessionDir, relNorm);
|
|
38319
|
-
if (relNorm !== ".") {
|
|
38320
|
-
fs25.mkdirSync(path27.dirname(wtPath), { recursive: true });
|
|
38321
|
-
}
|
|
38322
|
-
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
38323
|
-
try {
|
|
38324
|
-
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch, baseRef);
|
|
38325
|
-
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}, base ${baseRef}).`);
|
|
38326
|
-
worktreePaths.push(wtPath);
|
|
38327
|
-
} catch (e) {
|
|
38328
|
-
log2(
|
|
38329
|
-
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
38330
|
-
);
|
|
38331
|
-
}
|
|
38332
|
-
}
|
|
38333
|
-
if (worktreePaths.length === 0) return null;
|
|
38334
|
-
return {
|
|
38335
|
-
worktreePaths,
|
|
38336
|
-
sessionParentPath: sessionDir,
|
|
38337
|
-
workingTreeRelRoot: sessionDir
|
|
38338
|
-
};
|
|
38673
|
+
async function getSessionWorkingTreeStatus(cache2, sessionId, discover) {
|
|
38674
|
+
return aggregateSessionPathsWorkingTreeStatus(
|
|
38675
|
+
await resolveCommitTargetsAsync(sessionId, cache2, discover)
|
|
38676
|
+
);
|
|
38339
38677
|
}
|
|
38340
|
-
|
|
38341
|
-
|
|
38342
|
-
|
|
38343
|
-
|
|
38344
|
-
|
|
38345
|
-
|
|
38346
|
-
|
|
38347
|
-
|
|
38348
|
-
|
|
38349
|
-
...params.worktreeBaseBranches && Object.keys(params.worktreeBaseBranches).length > 0 ? { worktreeBaseBranches: params.worktreeBaseBranches } : {}
|
|
38350
|
-
});
|
|
38351
|
-
if (!prep) return void 0;
|
|
38352
|
-
params.cache.remember(params.sessionId, {
|
|
38353
|
-
sessionParentPath: prep.sessionParentPath,
|
|
38354
|
-
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
38355
|
-
repoCheckoutPaths: prep.worktreePaths
|
|
38678
|
+
async function getSessionWorkingTreeChangeDetails(cache2, sessionId, discover, opts) {
|
|
38679
|
+
const targets = await resolveCommitTargetsAsync(sessionId, cache2, discover);
|
|
38680
|
+
return getWorkingTreeChangeRepoDetails({
|
|
38681
|
+
commitTargetPaths: targets,
|
|
38682
|
+
sessionWorktreeRootPath: cache2.getWorkingTreeRelRoot(sessionId),
|
|
38683
|
+
legacyRepoNestedSessionLayout: cache2.isLegacyNestedLayout(sessionId),
|
|
38684
|
+
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
38685
|
+
basis: opts?.basis,
|
|
38686
|
+
recentCommitsLimit: opts?.recentCommitsLimit
|
|
38356
38687
|
});
|
|
38357
|
-
return params.cache.getSessionParentPath(params.sessionId);
|
|
38358
38688
|
}
|
|
38359
|
-
|
|
38360
|
-
|
|
38361
|
-
|
|
38362
|
-
|
|
38363
|
-
|
|
38364
|
-
|
|
38365
|
-
|
|
38366
|
-
cache2.remember(sessionId, disc);
|
|
38367
|
-
return cache2.getSessionParentPath(sessionId);
|
|
38689
|
+
async function pushSessionUpstream(cache2, sessionId, discover) {
|
|
38690
|
+
try {
|
|
38691
|
+
await pushAheadOfUpstreamForPaths(await resolveCommitTargetsAsync(sessionId, cache2, discover));
|
|
38692
|
+
return { ok: true };
|
|
38693
|
+
} catch (e) {
|
|
38694
|
+
const err = e instanceof Error ? e.message : String(e);
|
|
38695
|
+
return { ok: false, error: err };
|
|
38368
38696
|
}
|
|
38369
|
-
return void 0;
|
|
38370
38697
|
}
|
|
38371
|
-
|
|
38372
|
-
|
|
38373
|
-
|
|
38374
|
-
|
|
38375
|
-
const resolved = path28.resolve(params.parentPathRaw);
|
|
38376
|
-
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
38377
|
-
return resolved;
|
|
38378
|
-
}
|
|
38379
|
-
const rememberAndReturn = (binding) => {
|
|
38380
|
-
params.cache.remember(params.sessionId, binding);
|
|
38381
|
-
return params.cache.getSessionParentPath(params.sessionId) ?? resolved;
|
|
38382
|
-
};
|
|
38383
|
-
const diskFirst = params.discover();
|
|
38384
|
-
if (diskFirst) return rememberAndReturn(diskFirst);
|
|
38385
|
-
const fromRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, params.sessionId);
|
|
38386
|
-
if (fromRoot) return rememberAndReturn(fromRoot);
|
|
38387
|
-
let cur = resolved;
|
|
38388
|
-
for (let i = 0; i < 16; i++) {
|
|
38389
|
-
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
38390
|
-
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
38391
|
-
const next = path28.dirname(cur);
|
|
38392
|
-
if (next === cur) break;
|
|
38393
|
-
cur = next;
|
|
38394
|
-
}
|
|
38395
|
-
return resolved;
|
|
38698
|
+
async function removeSessionWorktreeCheckouts(cache2, sessionId, log2) {
|
|
38699
|
+
const paths = cache2.clearSession(sessionId);
|
|
38700
|
+
if (!paths?.length) return;
|
|
38701
|
+
await removeSessionWorktrees(paths, log2);
|
|
38396
38702
|
}
|
|
38397
|
-
|
|
38398
|
-
|
|
38399
|
-
|
|
38400
|
-
|
|
38401
|
-
if (!sessionId) return void 0;
|
|
38402
|
-
const sid = sessionId.trim();
|
|
38403
|
-
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
38404
|
-
if (parentPathRaw) {
|
|
38405
|
-
return resolveExplicitSessionParentPath({
|
|
38406
|
-
sessionId: sid,
|
|
38407
|
-
sessionParent: opts.sessionParent,
|
|
38408
|
-
parentPathRaw,
|
|
38409
|
-
cache: cache2,
|
|
38410
|
-
discover: () => discover(sid)
|
|
38411
|
-
});
|
|
38412
|
-
}
|
|
38413
|
-
const parentKind = parseSessionParent(opts.sessionParent);
|
|
38414
|
-
if (parentKind === "bridge_root") {
|
|
38415
|
-
return void 0;
|
|
38416
|
-
}
|
|
38417
|
-
if (parentKind === "worktrees_root") {
|
|
38418
|
-
if (!opts.isNewSession) {
|
|
38419
|
-
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
38420
|
-
}
|
|
38421
|
-
return prepareAndRememberSessionWorktrees({
|
|
38422
|
-
cache: cache2,
|
|
38423
|
-
sessionId: sid,
|
|
38424
|
-
worktreesRootPath,
|
|
38425
|
-
layout,
|
|
38426
|
-
log: log2,
|
|
38427
|
-
...opts.worktreeBaseBranches ? { worktreeBaseBranches: opts.worktreeBaseBranches } : {}
|
|
38428
|
-
});
|
|
38429
|
-
}
|
|
38430
|
-
if (!opts.isNewSession) {
|
|
38431
|
-
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
38432
|
-
}
|
|
38433
|
-
return prepareAndRememberSessionWorktrees({
|
|
38434
|
-
cache: cache2,
|
|
38435
|
-
sessionId: sid,
|
|
38436
|
-
worktreesRootPath,
|
|
38437
|
-
layout,
|
|
38438
|
-
log: log2
|
|
38439
|
-
});
|
|
38703
|
+
async function renameSessionWorktreeBranch(cache2, sessionId, newBranch, log2) {
|
|
38704
|
+
const paths = cache2.getRepoCheckoutPathsRef(sessionId);
|
|
38705
|
+
if (!paths?.length) return;
|
|
38706
|
+
await renameSessionWorktreeBranches(paths, newBranch, log2);
|
|
38440
38707
|
}
|
|
38441
38708
|
|
|
38442
38709
|
// src/worktrees/manager/session-worktree-cache.ts
|
|
38443
|
-
import * as
|
|
38710
|
+
import * as path36 from "node:path";
|
|
38444
38711
|
var SessionWorktreeCache = class {
|
|
38445
38712
|
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
38446
38713
|
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
38447
38714
|
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
38448
38715
|
remember(sessionId, binding) {
|
|
38449
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
38716
|
+
const paths = binding.repoCheckoutPaths.map((p) => path36.resolve(p));
|
|
38450
38717
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
38451
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
38452
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
38718
|
+
this.sessionParentPathBySession.set(sessionId, path36.resolve(binding.sessionParentPath));
|
|
38719
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path36.resolve(binding.workingTreeRelRoot));
|
|
38453
38720
|
}
|
|
38454
38721
|
clearSession(sessionId) {
|
|
38455
38722
|
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
@@ -38479,7 +38746,7 @@ var SessionWorktreeCache = class {
|
|
|
38479
38746
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
38480
38747
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
38481
38748
|
if (!parent || !relRoot) return false;
|
|
38482
|
-
return
|
|
38749
|
+
return path36.resolve(parent) !== path36.resolve(relRoot);
|
|
38483
38750
|
}
|
|
38484
38751
|
};
|
|
38485
38752
|
|
|
@@ -38494,8 +38761,8 @@ var SessionWorktreeManager = class {
|
|
|
38494
38761
|
this.log = options.log;
|
|
38495
38762
|
this.layout = loadWorktreeLayout();
|
|
38496
38763
|
}
|
|
38497
|
-
|
|
38498
|
-
return
|
|
38764
|
+
discoverAsync(sessionId) {
|
|
38765
|
+
return discoverSessionBindingAsync({
|
|
38499
38766
|
sessionId,
|
|
38500
38767
|
worktreesRootPath: this.worktreesRootPath,
|
|
38501
38768
|
layout: this.layout
|
|
@@ -38515,14 +38782,12 @@ var SessionWorktreeManager = class {
|
|
|
38515
38782
|
worktreesRootPath: this.worktreesRootPath,
|
|
38516
38783
|
layout: this.layout,
|
|
38517
38784
|
log: this.log,
|
|
38518
|
-
discover: (sid) => this.
|
|
38785
|
+
discover: (sid) => this.discoverAsync(sid),
|
|
38519
38786
|
opts
|
|
38520
38787
|
});
|
|
38521
38788
|
}
|
|
38522
38789
|
async renameSessionBranch(sessionId, newBranch) {
|
|
38523
|
-
|
|
38524
|
-
if (!paths?.length) return;
|
|
38525
|
-
await renameSessionWorktreeBranches(paths, newBranch, this.log);
|
|
38790
|
+
await renameSessionWorktreeBranch(this.cache, sessionId, newBranch, this.log);
|
|
38526
38791
|
}
|
|
38527
38792
|
usesWorktreeSession(sessionId) {
|
|
38528
38793
|
if (!sessionId) return false;
|
|
@@ -38533,79 +38798,55 @@ var SessionWorktreeManager = class {
|
|
|
38533
38798
|
return this.cache.getRepoCheckoutPaths(sessionId);
|
|
38534
38799
|
}
|
|
38535
38800
|
ensureRepoCheckoutPathsForSession(sessionId) {
|
|
38536
|
-
return ensureRepoCheckoutPathsForSession(sessionId, this.cache
|
|
38801
|
+
return ensureRepoCheckoutPathsForSession(sessionId, this.cache);
|
|
38802
|
+
}
|
|
38803
|
+
async ensureRepoCheckoutPathsForSessionAsync(sessionId) {
|
|
38804
|
+
return ensureRepoCheckoutPathsForSessionAsync(sessionId, this.cache, (sid) => this.discoverAsync(sid));
|
|
38537
38805
|
}
|
|
38538
38806
|
getSessionWorktreeRootForSession(sessionId) {
|
|
38539
38807
|
return this.getIsolatedSessionParentPathForSession(sessionId);
|
|
38540
38808
|
}
|
|
38541
38809
|
async removeSessionWorktrees(sessionId) {
|
|
38542
|
-
|
|
38543
|
-
if (!paths?.length) return;
|
|
38544
|
-
await removeSessionWorktrees(paths, this.log);
|
|
38810
|
+
await removeSessionWorktreeCheckouts(this.cache, sessionId, this.log);
|
|
38545
38811
|
}
|
|
38546
38812
|
async commitSession(params) {
|
|
38547
|
-
|
|
38548
|
-
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
38549
|
-
return commitSessionWorktrees({
|
|
38550
|
-
paths: targets,
|
|
38551
|
-
branch: params.branch,
|
|
38552
|
-
message: params.message,
|
|
38553
|
-
push: params.push
|
|
38554
|
-
});
|
|
38813
|
+
return commitSessionWorktree(this.cache, params);
|
|
38555
38814
|
}
|
|
38556
38815
|
async getSessionWorkingTreeStatus(sessionId) {
|
|
38557
|
-
return
|
|
38558
|
-
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
38559
|
-
);
|
|
38816
|
+
return getSessionWorkingTreeStatus(this.cache, sessionId, (sid) => this.discoverAsync(sid));
|
|
38560
38817
|
}
|
|
38561
38818
|
async getSessionWorkingTreeChangeDetails(sessionId, opts) {
|
|
38562
|
-
|
|
38563
|
-
return getWorkingTreeChangeRepoDetails({
|
|
38564
|
-
commitTargetPaths: targets,
|
|
38565
|
-
sessionWorktreeRootPath: this.cache.getWorkingTreeRelRoot(sessionId),
|
|
38566
|
-
legacyRepoNestedSessionLayout: this.cache.isLegacyNestedLayout(sessionId),
|
|
38567
|
-
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
38568
|
-
basis: opts?.basis,
|
|
38569
|
-
recentCommitsLimit: opts?.recentCommitsLimit
|
|
38570
|
-
});
|
|
38819
|
+
return getSessionWorkingTreeChangeDetails(this.cache, sessionId, (sid) => this.discoverAsync(sid), opts);
|
|
38571
38820
|
}
|
|
38572
38821
|
async pushSessionUpstream(sessionId) {
|
|
38573
|
-
|
|
38574
|
-
await pushAheadOfUpstreamForPaths(
|
|
38575
|
-
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
38576
|
-
);
|
|
38577
|
-
return { ok: true };
|
|
38578
|
-
} catch (e) {
|
|
38579
|
-
const err = e instanceof Error ? e.message : String(e);
|
|
38580
|
-
return { ok: false, error: err };
|
|
38581
|
-
}
|
|
38822
|
+
return pushSessionUpstream(this.cache, sessionId, (sid) => this.discoverAsync(sid));
|
|
38582
38823
|
}
|
|
38583
38824
|
};
|
|
38584
38825
|
|
|
38585
38826
|
// src/worktrees/manager/default-worktrees-root-path.ts
|
|
38586
|
-
import * as
|
|
38827
|
+
import * as path37 from "node:path";
|
|
38587
38828
|
import os8 from "node:os";
|
|
38588
38829
|
function defaultWorktreesRootPath() {
|
|
38589
|
-
return
|
|
38830
|
+
return path37.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
38590
38831
|
}
|
|
38591
38832
|
|
|
38592
38833
|
// src/files/watch-file-index.ts
|
|
38593
38834
|
import { watch } from "node:fs";
|
|
38594
|
-
import
|
|
38835
|
+
import path42 from "node:path";
|
|
38595
38836
|
|
|
38596
38837
|
// src/files/index/paths.ts
|
|
38597
|
-
import
|
|
38838
|
+
import path38 from "node:path";
|
|
38598
38839
|
import crypto2 from "node:crypto";
|
|
38599
38840
|
function getCwdHashForFileIndex(resolvedCwd) {
|
|
38600
|
-
return crypto2.createHash("sha256").update(
|
|
38841
|
+
return crypto2.createHash("sha256").update(path38.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
38601
38842
|
}
|
|
38602
38843
|
|
|
38603
38844
|
// src/files/index/build-file-index.ts
|
|
38604
|
-
import
|
|
38845
|
+
import path40 from "node:path";
|
|
38605
38846
|
|
|
38606
38847
|
// src/files/index/walk-workspace-tree.ts
|
|
38607
|
-
import
|
|
38608
|
-
import
|
|
38848
|
+
import fs30 from "node:fs";
|
|
38849
|
+
import path39 from "node:path";
|
|
38609
38850
|
var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
38610
38851
|
"node_modules",
|
|
38611
38852
|
"bower_components",
|
|
@@ -38622,7 +38863,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
|
|
|
38622
38863
|
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
38623
38864
|
let names;
|
|
38624
38865
|
try {
|
|
38625
|
-
names = await
|
|
38866
|
+
names = await fs30.promises.readdir(dir);
|
|
38626
38867
|
} catch {
|
|
38627
38868
|
return;
|
|
38628
38869
|
}
|
|
@@ -38634,14 +38875,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
|
38634
38875
|
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
38635
38876
|
}
|
|
38636
38877
|
state.n++;
|
|
38637
|
-
const full =
|
|
38878
|
+
const full = path39.join(dir, name);
|
|
38638
38879
|
let stat3;
|
|
38639
38880
|
try {
|
|
38640
|
-
stat3 = await
|
|
38881
|
+
stat3 = await fs30.promises.stat(full);
|
|
38641
38882
|
} catch {
|
|
38642
38883
|
continue;
|
|
38643
38884
|
}
|
|
38644
|
-
const relative6 =
|
|
38885
|
+
const relative6 = path39.relative(baseDir, full).replace(/\\/g, "/");
|
|
38645
38886
|
if (stat3.isDirectory()) {
|
|
38646
38887
|
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
38647
38888
|
} else if (stat3.isFile()) {
|
|
@@ -38654,7 +38895,7 @@ function createWalkYieldState() {
|
|
|
38654
38895
|
}
|
|
38655
38896
|
|
|
38656
38897
|
// src/files/index/file-index-sqlite-lock.ts
|
|
38657
|
-
import
|
|
38898
|
+
import fs31 from "node:fs";
|
|
38658
38899
|
function isSqliteCorruptError(e) {
|
|
38659
38900
|
const msg = e instanceof Error ? e.message : String(e);
|
|
38660
38901
|
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
@@ -38668,7 +38909,7 @@ function withFileIndexSqliteLock(fn) {
|
|
|
38668
38909
|
if (!isSqliteCorruptError(e)) throw e;
|
|
38669
38910
|
closeAllCliSqliteConnections();
|
|
38670
38911
|
try {
|
|
38671
|
-
|
|
38912
|
+
fs31.unlinkSync(getCliSqlitePath());
|
|
38672
38913
|
} catch {
|
|
38673
38914
|
}
|
|
38674
38915
|
chain = Promise.resolve();
|
|
@@ -38743,7 +38984,7 @@ async function collectWorkspacePathsAsync(resolved) {
|
|
|
38743
38984
|
}
|
|
38744
38985
|
async function buildFileIndexAsync(cwd) {
|
|
38745
38986
|
return withFileIndexSqliteLock(async () => {
|
|
38746
|
-
const resolved =
|
|
38987
|
+
const resolved = path40.resolve(cwd);
|
|
38747
38988
|
await yieldToEventLoop();
|
|
38748
38989
|
assertNotShutdown();
|
|
38749
38990
|
const paths = await collectWorkspacePathsAsync(resolved);
|
|
@@ -38755,7 +38996,7 @@ async function buildFileIndexAsync(cwd) {
|
|
|
38755
38996
|
}
|
|
38756
38997
|
|
|
38757
38998
|
// src/files/index/ensure-file-index.ts
|
|
38758
|
-
import
|
|
38999
|
+
import path41 from "node:path";
|
|
38759
39000
|
|
|
38760
39001
|
// src/files/index/search-file-index.ts
|
|
38761
39002
|
function escapeLikePattern(fragment) {
|
|
@@ -38807,7 +39048,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
|
38807
39048
|
|
|
38808
39049
|
// src/files/index/ensure-file-index.ts
|
|
38809
39050
|
async function ensureFileIndexAsync(cwd) {
|
|
38810
|
-
const resolved =
|
|
39051
|
+
const resolved = path41.resolve(cwd);
|
|
38811
39052
|
if (await bridgeFileIndexIsPopulated(resolved)) {
|
|
38812
39053
|
return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
|
|
38813
39054
|
}
|
|
@@ -38851,7 +39092,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
38851
39092
|
}
|
|
38852
39093
|
}
|
|
38853
39094
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
38854
|
-
const resolved =
|
|
39095
|
+
const resolved = path42.resolve(cwd);
|
|
38855
39096
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
38856
39097
|
if (e instanceof CliSqliteInterrupted) return;
|
|
38857
39098
|
console.error("[file-index] Initial index build failed:", e);
|
|
@@ -38881,7 +39122,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
38881
39122
|
}
|
|
38882
39123
|
|
|
38883
39124
|
// src/connection/create-bridge-connection.ts
|
|
38884
|
-
import * as
|
|
39125
|
+
import * as path53 from "node:path";
|
|
38885
39126
|
|
|
38886
39127
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
38887
39128
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -38903,15 +39144,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
|
|
|
38903
39144
|
|
|
38904
39145
|
// src/dev-servers/process/terminate-child-process.ts
|
|
38905
39146
|
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
38906
|
-
const exited = new Promise((
|
|
38907
|
-
proc.once("exit", () =>
|
|
39147
|
+
const exited = new Promise((resolve28) => {
|
|
39148
|
+
proc.once("exit", () => resolve28());
|
|
38908
39149
|
});
|
|
38909
39150
|
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
|
|
38910
39151
|
try {
|
|
38911
39152
|
proc.kill("SIGTERM");
|
|
38912
39153
|
} catch {
|
|
38913
39154
|
}
|
|
38914
|
-
await Promise.race([exited, new Promise((
|
|
39155
|
+
await Promise.race([exited, new Promise((resolve28) => setTimeout(resolve28, graceMs))]);
|
|
38915
39156
|
}
|
|
38916
39157
|
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
38917
39158
|
log2(
|
|
@@ -38925,7 +39166,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
38925
39166
|
}
|
|
38926
39167
|
|
|
38927
39168
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
38928
|
-
import
|
|
39169
|
+
import fs32 from "node:fs";
|
|
38929
39170
|
|
|
38930
39171
|
// src/dev-servers/manager/forward-pipe.ts
|
|
38931
39172
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -38961,7 +39202,7 @@ function wireDevServerChildProcess(d) {
|
|
|
38961
39202
|
d.setPollInterval(void 0);
|
|
38962
39203
|
return;
|
|
38963
39204
|
}
|
|
38964
|
-
|
|
39205
|
+
fs32.readFile(d.mergedLogPath, (err, buf) => {
|
|
38965
39206
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
38966
39207
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
38967
39208
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -38999,7 +39240,7 @@ ${errTail}` : ""}`);
|
|
|
38999
39240
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
39000
39241
|
};
|
|
39001
39242
|
if (mergedPath) {
|
|
39002
|
-
|
|
39243
|
+
fs32.readFile(mergedPath, (err, buf) => {
|
|
39003
39244
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
39004
39245
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
39005
39246
|
if (chunk.length > 0) {
|
|
@@ -39101,13 +39342,13 @@ function parseDevServerDefs(servers) {
|
|
|
39101
39342
|
}
|
|
39102
39343
|
|
|
39103
39344
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
39104
|
-
import
|
|
39345
|
+
import fs33 from "node:fs";
|
|
39105
39346
|
function isSpawnEbadf(e) {
|
|
39106
39347
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
39107
39348
|
}
|
|
39108
39349
|
function rmDirQuiet(dir) {
|
|
39109
39350
|
try {
|
|
39110
|
-
|
|
39351
|
+
fs33.rmSync(dir, { recursive: true, force: true });
|
|
39111
39352
|
} catch {
|
|
39112
39353
|
}
|
|
39113
39354
|
}
|
|
@@ -39115,7 +39356,7 @@ var cachedDevNullReadFd;
|
|
|
39115
39356
|
function devNullReadFd() {
|
|
39116
39357
|
if (cachedDevNullReadFd === void 0) {
|
|
39117
39358
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
39118
|
-
cachedDevNullReadFd =
|
|
39359
|
+
cachedDevNullReadFd = fs33.openSync(devPath, "r");
|
|
39119
39360
|
}
|
|
39120
39361
|
return cachedDevNullReadFd;
|
|
39121
39362
|
}
|
|
@@ -39189,15 +39430,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
39189
39430
|
|
|
39190
39431
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
39191
39432
|
import { spawn as spawn7 } from "node:child_process";
|
|
39192
|
-
import
|
|
39433
|
+
import fs34 from "node:fs";
|
|
39193
39434
|
import { tmpdir } from "node:os";
|
|
39194
|
-
import
|
|
39435
|
+
import path43 from "node:path";
|
|
39195
39436
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
39196
|
-
const tmpRoot =
|
|
39197
|
-
const logPath =
|
|
39437
|
+
const tmpRoot = fs34.mkdtempSync(path43.join(tmpdir(), "ba-devsrv-log-"));
|
|
39438
|
+
const logPath = path43.join(tmpRoot, "combined.log");
|
|
39198
39439
|
let logFd;
|
|
39199
39440
|
try {
|
|
39200
|
-
logFd =
|
|
39441
|
+
logFd = fs34.openSync(logPath, "a");
|
|
39201
39442
|
} catch {
|
|
39202
39443
|
rmDirQuiet(tmpRoot);
|
|
39203
39444
|
return null;
|
|
@@ -39216,7 +39457,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
39216
39457
|
} else {
|
|
39217
39458
|
proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
39218
39459
|
}
|
|
39219
|
-
|
|
39460
|
+
fs34.closeSync(logFd);
|
|
39220
39461
|
return {
|
|
39221
39462
|
proc,
|
|
39222
39463
|
pipedStdoutStderr: true,
|
|
@@ -39225,7 +39466,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
39225
39466
|
};
|
|
39226
39467
|
} catch (e) {
|
|
39227
39468
|
try {
|
|
39228
|
-
|
|
39469
|
+
fs34.closeSync(logFd);
|
|
39229
39470
|
} catch {
|
|
39230
39471
|
}
|
|
39231
39472
|
rmDirQuiet(tmpRoot);
|
|
@@ -39236,22 +39477,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
39236
39477
|
|
|
39237
39478
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
39238
39479
|
import { spawn as spawn8 } from "node:child_process";
|
|
39239
|
-
import
|
|
39480
|
+
import fs35 from "node:fs";
|
|
39240
39481
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
39241
|
-
import
|
|
39482
|
+
import path44 from "node:path";
|
|
39242
39483
|
function shSingleQuote(s) {
|
|
39243
39484
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
39244
39485
|
}
|
|
39245
39486
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
39246
|
-
const tmpRoot =
|
|
39247
|
-
const logPath =
|
|
39248
|
-
const innerPath =
|
|
39249
|
-
const runnerPath =
|
|
39487
|
+
const tmpRoot = fs35.mkdtempSync(path44.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
39488
|
+
const logPath = path44.join(tmpRoot, "combined.log");
|
|
39489
|
+
const innerPath = path44.join(tmpRoot, "_cmd.sh");
|
|
39490
|
+
const runnerPath = path44.join(tmpRoot, "_run.sh");
|
|
39250
39491
|
try {
|
|
39251
|
-
|
|
39492
|
+
fs35.writeFileSync(innerPath, `#!/bin/sh
|
|
39252
39493
|
${command}
|
|
39253
39494
|
`);
|
|
39254
|
-
|
|
39495
|
+
fs35.writeFileSync(
|
|
39255
39496
|
runnerPath,
|
|
39256
39497
|
`#!/bin/sh
|
|
39257
39498
|
cd ${shSingleQuote(cwd)}
|
|
@@ -39277,13 +39518,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
39277
39518
|
}
|
|
39278
39519
|
}
|
|
39279
39520
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
39280
|
-
const tmpRoot =
|
|
39281
|
-
const logPath =
|
|
39282
|
-
const runnerPath =
|
|
39521
|
+
const tmpRoot = fs35.mkdtempSync(path44.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
39522
|
+
const logPath = path44.join(tmpRoot, "combined.log");
|
|
39523
|
+
const runnerPath = path44.join(tmpRoot, "_run.bat");
|
|
39283
39524
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
39284
39525
|
const com = process.env.ComSpec || "cmd.exe";
|
|
39285
39526
|
try {
|
|
39286
|
-
|
|
39527
|
+
fs35.writeFileSync(
|
|
39287
39528
|
runnerPath,
|
|
39288
39529
|
`@ECHO OFF\r
|
|
39289
39530
|
CD /D ${q(cwd)}\r
|
|
@@ -39792,7 +40033,7 @@ async function proxyToLocal(request) {
|
|
|
39792
40033
|
};
|
|
39793
40034
|
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
39794
40035
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
39795
|
-
const once = await new Promise((
|
|
40036
|
+
const once = await new Promise((resolve28) => {
|
|
39796
40037
|
const req = mod.request(opts, (res) => {
|
|
39797
40038
|
const chunks = [];
|
|
39798
40039
|
res.on("data", (c) => chunks.push(c));
|
|
@@ -39803,7 +40044,7 @@ async function proxyToLocal(request) {
|
|
|
39803
40044
|
if (typeof v === "string") headers[k] = v;
|
|
39804
40045
|
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
39805
40046
|
}
|
|
39806
|
-
|
|
40047
|
+
resolve28({
|
|
39807
40048
|
id: request.id,
|
|
39808
40049
|
statusCode: res.statusCode ?? 0,
|
|
39809
40050
|
headers,
|
|
@@ -39812,7 +40053,7 @@ async function proxyToLocal(request) {
|
|
|
39812
40053
|
});
|
|
39813
40054
|
});
|
|
39814
40055
|
req.on("error", (err) => {
|
|
39815
|
-
|
|
40056
|
+
resolve28({
|
|
39816
40057
|
id: request.id,
|
|
39817
40058
|
statusCode: 0,
|
|
39818
40059
|
headers: {},
|
|
@@ -40220,30 +40461,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
40220
40461
|
}
|
|
40221
40462
|
|
|
40222
40463
|
// src/skills/discover-local-agent-skills.ts
|
|
40223
|
-
import
|
|
40224
|
-
import
|
|
40464
|
+
import fs36 from "node:fs";
|
|
40465
|
+
import path45 from "node:path";
|
|
40225
40466
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
40226
40467
|
function discoverLocalSkills(cwd) {
|
|
40227
40468
|
const out = [];
|
|
40228
40469
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
40229
40470
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
40230
|
-
const base =
|
|
40231
|
-
if (!
|
|
40471
|
+
const base = path45.join(cwd, rel);
|
|
40472
|
+
if (!fs36.existsSync(base) || !fs36.statSync(base).isDirectory()) continue;
|
|
40232
40473
|
let entries = [];
|
|
40233
40474
|
try {
|
|
40234
|
-
entries =
|
|
40475
|
+
entries = fs36.readdirSync(base);
|
|
40235
40476
|
} catch {
|
|
40236
40477
|
continue;
|
|
40237
40478
|
}
|
|
40238
40479
|
for (const name of entries) {
|
|
40239
|
-
const dir =
|
|
40480
|
+
const dir = path45.join(base, name);
|
|
40240
40481
|
try {
|
|
40241
|
-
if (!
|
|
40482
|
+
if (!fs36.statSync(dir).isDirectory()) continue;
|
|
40242
40483
|
} catch {
|
|
40243
40484
|
continue;
|
|
40244
40485
|
}
|
|
40245
|
-
const skillMd =
|
|
40246
|
-
if (!
|
|
40486
|
+
const skillMd = path45.join(dir, "SKILL.md");
|
|
40487
|
+
if (!fs36.existsSync(skillMd)) continue;
|
|
40247
40488
|
const key = `${rel}/${name}`;
|
|
40248
40489
|
if (seenKeys.has(key)) continue;
|
|
40249
40490
|
seenKeys.add(key);
|
|
@@ -40255,23 +40496,23 @@ function discoverLocalSkills(cwd) {
|
|
|
40255
40496
|
function discoverSkillLayoutRoots(cwd) {
|
|
40256
40497
|
const roots = [];
|
|
40257
40498
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
40258
|
-
const base =
|
|
40259
|
-
if (!
|
|
40499
|
+
const base = path45.join(cwd, rel);
|
|
40500
|
+
if (!fs36.existsSync(base) || !fs36.statSync(base).isDirectory()) continue;
|
|
40260
40501
|
let entries = [];
|
|
40261
40502
|
try {
|
|
40262
|
-
entries =
|
|
40503
|
+
entries = fs36.readdirSync(base);
|
|
40263
40504
|
} catch {
|
|
40264
40505
|
continue;
|
|
40265
40506
|
}
|
|
40266
40507
|
const skills2 = [];
|
|
40267
40508
|
for (const name of entries) {
|
|
40268
|
-
const dir =
|
|
40509
|
+
const dir = path45.join(base, name);
|
|
40269
40510
|
try {
|
|
40270
|
-
if (!
|
|
40511
|
+
if (!fs36.statSync(dir).isDirectory()) continue;
|
|
40271
40512
|
} catch {
|
|
40272
40513
|
continue;
|
|
40273
40514
|
}
|
|
40274
|
-
if (!
|
|
40515
|
+
if (!fs36.existsSync(path45.join(dir, "SKILL.md"))) continue;
|
|
40275
40516
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
40276
40517
|
skills2.push({ name, relPath });
|
|
40277
40518
|
}
|
|
@@ -40627,7 +40868,7 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
|
|
|
40627
40868
|
}
|
|
40628
40869
|
|
|
40629
40870
|
// src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
|
|
40630
|
-
import
|
|
40871
|
+
import fs37 from "node:fs";
|
|
40631
40872
|
async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
40632
40873
|
if (next.serverState !== "requeued_with_revert") return true;
|
|
40633
40874
|
const sid = next.sessionId;
|
|
@@ -40636,7 +40877,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
40636
40877
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
40637
40878
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
40638
40879
|
try {
|
|
40639
|
-
await
|
|
40880
|
+
await fs37.promises.access(file2, fs37.constants.F_OK);
|
|
40640
40881
|
} catch {
|
|
40641
40882
|
deps.log(
|
|
40642
40883
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
@@ -40751,7 +40992,7 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
40751
40992
|
sendWsMessage(s, wire);
|
|
40752
40993
|
return true;
|
|
40753
40994
|
};
|
|
40754
|
-
const
|
|
40995
|
+
const sendResult = (result) => {
|
|
40755
40996
|
const skipEncryptForChangeSummaryFollowUp = result.type === "prompt_result" && result.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
|
|
40756
40997
|
const encryptedFields = result.type === "prompt_result" && !skipEncryptForChangeSummaryFollowUp ? ["output", "error"] : [];
|
|
40757
40998
|
sendBridgeMessage(result, encryptedFields);
|
|
@@ -40784,7 +41025,7 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
40784
41025
|
]) : payload;
|
|
40785
41026
|
sendWsMessage(s, wire);
|
|
40786
41027
|
};
|
|
40787
|
-
return { sendBridgeMessage, sendResult
|
|
41028
|
+
return { sendBridgeMessage, sendResult, sendSessionUpdate };
|
|
40788
41029
|
}
|
|
40789
41030
|
|
|
40790
41031
|
// src/agents/acp/from-bridge/handle-bridge-prompt/parse-bridge-attachments.ts
|
|
@@ -40888,7 +41129,7 @@ async function readGitBranch(cwd) {
|
|
|
40888
41129
|
async function runBridgePromptPreamble(params) {
|
|
40889
41130
|
const { getWs, log: log2, sessionWorktreeManager, sessionId, runId, effectiveCwd } = params;
|
|
40890
41131
|
const s = getWs();
|
|
40891
|
-
const repoCheckoutPaths = sessionWorktreeManager.
|
|
41132
|
+
const repoCheckoutPaths = await sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sessionId);
|
|
40892
41133
|
const repoRoots = await resolveSnapshotRepoRoots({
|
|
40893
41134
|
worktreePaths: repoCheckoutPaths,
|
|
40894
41135
|
fallbackCwd: effectiveCwd,
|
|
@@ -40924,9 +41165,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
40924
41165
|
for (const item of raw) {
|
|
40925
41166
|
if (!item || typeof item !== "object") continue;
|
|
40926
41167
|
const o = item;
|
|
40927
|
-
const
|
|
40928
|
-
if (!
|
|
40929
|
-
const row = { path:
|
|
41168
|
+
const path55 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
41169
|
+
if (!path55) continue;
|
|
41170
|
+
const row = { path: path55 };
|
|
40930
41171
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
40931
41172
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
40932
41173
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -40960,7 +41201,7 @@ async function runPreambleAndPrompt(params) {
|
|
|
40960
41201
|
agentId,
|
|
40961
41202
|
agentConfig,
|
|
40962
41203
|
resolvedCwd,
|
|
40963
|
-
senders: { sendResult
|
|
41204
|
+
senders: { sendResult, sendSessionUpdate }
|
|
40964
41205
|
} = params;
|
|
40965
41206
|
const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
|
|
40966
41207
|
await runBridgePromptPreamble({
|
|
@@ -40998,7 +41239,7 @@ async function runPreambleAndPrompt(params) {
|
|
|
40998
41239
|
agentId,
|
|
40999
41240
|
agentConfig,
|
|
41000
41241
|
sessionParentPath: effectiveCwd,
|
|
41001
|
-
sendResult
|
|
41242
|
+
sendResult,
|
|
41002
41243
|
sendSessionUpdate,
|
|
41003
41244
|
followUpCatalogPromptId,
|
|
41004
41245
|
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
@@ -41136,8 +41377,8 @@ function randomSecret() {
|
|
|
41136
41377
|
}
|
|
41137
41378
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
41138
41379
|
}
|
|
41139
|
-
async function requestPreviewApi(port, secret, method,
|
|
41140
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
41380
|
+
async function requestPreviewApi(port, secret, method, path55, body) {
|
|
41381
|
+
const url2 = `http://127.0.0.1:${port}${path55}`;
|
|
41141
41382
|
const headers = {
|
|
41142
41383
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
41143
41384
|
"Content-Type": "application/json"
|
|
@@ -41149,7 +41390,7 @@ async function requestPreviewApi(port, secret, method, path48, body) {
|
|
|
41149
41390
|
});
|
|
41150
41391
|
const data = await res.json().catch(() => ({}));
|
|
41151
41392
|
if (!res.ok) {
|
|
41152
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
41393
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path55}: ${res.status}`);
|
|
41153
41394
|
}
|
|
41154
41395
|
return data;
|
|
41155
41396
|
}
|
|
@@ -41314,14 +41555,14 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
41314
41555
|
};
|
|
41315
41556
|
|
|
41316
41557
|
// src/files/list-dir/index.ts
|
|
41317
|
-
import
|
|
41558
|
+
import fs39 from "node:fs";
|
|
41318
41559
|
|
|
41319
41560
|
// src/files/ensure-under-cwd.ts
|
|
41320
|
-
import
|
|
41561
|
+
import path46 from "node:path";
|
|
41321
41562
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
41322
|
-
const normalized =
|
|
41323
|
-
const resolved =
|
|
41324
|
-
if (!resolved.startsWith(cwd +
|
|
41563
|
+
const normalized = path46.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
41564
|
+
const resolved = path46.resolve(cwd, normalized);
|
|
41565
|
+
if (!resolved.startsWith(cwd + path46.sep) && resolved !== cwd) {
|
|
41325
41566
|
return null;
|
|
41326
41567
|
}
|
|
41327
41568
|
return resolved;
|
|
@@ -41331,15 +41572,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
|
41331
41572
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
41332
41573
|
|
|
41333
41574
|
// src/files/list-dir/map-dir-entry.ts
|
|
41334
|
-
import
|
|
41335
|
-
import
|
|
41575
|
+
import path47 from "node:path";
|
|
41576
|
+
import fs38 from "node:fs";
|
|
41336
41577
|
async function mapDirEntry(d, relativePath, resolved) {
|
|
41337
|
-
const entryPath =
|
|
41338
|
-
const fullPath =
|
|
41578
|
+
const entryPath = path47.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
41579
|
+
const fullPath = path47.join(resolved, d.name);
|
|
41339
41580
|
let isDir = d.isDirectory();
|
|
41340
41581
|
if (d.isSymbolicLink()) {
|
|
41341
41582
|
try {
|
|
41342
|
-
const targetStat = await
|
|
41583
|
+
const targetStat = await fs38.promises.stat(fullPath);
|
|
41343
41584
|
isDir = targetStat.isDirectory();
|
|
41344
41585
|
} catch {
|
|
41345
41586
|
isDir = false;
|
|
@@ -41369,7 +41610,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
|
41369
41610
|
return { error: "Path is outside working directory" };
|
|
41370
41611
|
}
|
|
41371
41612
|
try {
|
|
41372
|
-
const names = await
|
|
41613
|
+
const names = await fs39.promises.readdir(resolved, { withFileTypes: true });
|
|
41373
41614
|
const entries = [];
|
|
41374
41615
|
for (let i = 0; i < names.length; i++) {
|
|
41375
41616
|
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
@@ -41389,18 +41630,18 @@ var LINE_CHUNK_SIZE = 64 * 1024;
|
|
|
41389
41630
|
var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
|
|
41390
41631
|
|
|
41391
41632
|
// src/files/read-file/resolve-file-path.ts
|
|
41392
|
-
import
|
|
41633
|
+
import fs40 from "node:fs";
|
|
41393
41634
|
async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
41394
41635
|
const resolved = ensureUnderCwd(relativePath, sessionParentPath);
|
|
41395
41636
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
41396
41637
|
let real;
|
|
41397
41638
|
try {
|
|
41398
|
-
real = await
|
|
41639
|
+
real = await fs40.promises.realpath(resolved);
|
|
41399
41640
|
} catch {
|
|
41400
41641
|
real = resolved;
|
|
41401
41642
|
}
|
|
41402
41643
|
try {
|
|
41403
|
-
const stat3 = await
|
|
41644
|
+
const stat3 = await fs40.promises.stat(real);
|
|
41404
41645
|
if (!stat3.isFile()) return { error: "Not a file" };
|
|
41405
41646
|
return real;
|
|
41406
41647
|
} catch (err) {
|
|
@@ -41409,11 +41650,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
|
|
|
41409
41650
|
}
|
|
41410
41651
|
|
|
41411
41652
|
// src/files/read-file/read-file-range-async.ts
|
|
41412
|
-
import
|
|
41653
|
+
import fs41 from "node:fs";
|
|
41413
41654
|
import { StringDecoder } from "node:string_decoder";
|
|
41414
41655
|
async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
41415
|
-
const fileSize = (await
|
|
41416
|
-
const fd = await
|
|
41656
|
+
const fileSize = (await fs41.promises.stat(filePath)).size;
|
|
41657
|
+
const fd = await fs41.promises.open(filePath, "r");
|
|
41417
41658
|
const bufSize = 64 * 1024;
|
|
41418
41659
|
const buf = Buffer.alloc(bufSize);
|
|
41419
41660
|
const decoder = new StringDecoder("utf8");
|
|
@@ -41575,11 +41816,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
|
|
|
41575
41816
|
}
|
|
41576
41817
|
|
|
41577
41818
|
// src/files/read-file/read-file-buffer-full-async.ts
|
|
41578
|
-
import
|
|
41819
|
+
import fs42 from "node:fs";
|
|
41579
41820
|
var READ_CHUNK_BYTES = 256 * 1024;
|
|
41580
41821
|
async function readFileBufferFullAsync(filePath) {
|
|
41581
|
-
const stat3 = await
|
|
41582
|
-
const fd = await
|
|
41822
|
+
const stat3 = await fs42.promises.stat(filePath);
|
|
41823
|
+
const fd = await fs42.promises.open(filePath, "r");
|
|
41583
41824
|
const chunks = [];
|
|
41584
41825
|
let position = 0;
|
|
41585
41826
|
let bytesSinceYield = 0;
|
|
@@ -41675,10 +41916,10 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
|
|
|
41675
41916
|
}
|
|
41676
41917
|
|
|
41677
41918
|
// src/files/resolve-file-browser-session-parent.ts
|
|
41678
|
-
function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
41919
|
+
async function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
41679
41920
|
const sid = sessionId?.trim();
|
|
41680
41921
|
if (sid) {
|
|
41681
|
-
sessionWorktreeManager.
|
|
41922
|
+
await sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sid);
|
|
41682
41923
|
const worktreeRoot = sessionWorktreeManager.getSessionWorktreeRootForSession(sid);
|
|
41683
41924
|
if (worktreeRoot) return worktreeRoot;
|
|
41684
41925
|
}
|
|
@@ -41686,14 +41927,14 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
|
41686
41927
|
}
|
|
41687
41928
|
|
|
41688
41929
|
// src/files/handle-file-browser-search.ts
|
|
41689
|
-
import
|
|
41930
|
+
import path48 from "node:path";
|
|
41690
41931
|
var SEARCH_LIMIT = 100;
|
|
41691
41932
|
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
41692
41933
|
void (async () => {
|
|
41693
41934
|
await yieldToEventLoop();
|
|
41694
41935
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
41695
|
-
const sessionParentPath =
|
|
41696
|
-
sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
41936
|
+
const sessionParentPath = path48.resolve(
|
|
41937
|
+
sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
41697
41938
|
);
|
|
41698
41939
|
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
41699
41940
|
const payload2 = {
|
|
@@ -41731,7 +41972,7 @@ function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
|
41731
41972
|
void (async () => {
|
|
41732
41973
|
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
41733
41974
|
const op = msg.op === "read" ? "read" : "list";
|
|
41734
|
-
const sessionParentPath = sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
41975
|
+
const sessionParentPath = sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
41735
41976
|
if (op === "list") {
|
|
41736
41977
|
const result = await listDirAsync(reqPath, sessionParentPath);
|
|
41737
41978
|
if ("error" in result) {
|
|
@@ -41811,8 +42052,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
41811
42052
|
}
|
|
41812
42053
|
|
|
41813
42054
|
// src/skills/install-remote-skills.ts
|
|
41814
|
-
import
|
|
41815
|
-
import
|
|
42055
|
+
import fs43 from "node:fs";
|
|
42056
|
+
import path49 from "node:path";
|
|
41816
42057
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
41817
42058
|
const installed2 = [];
|
|
41818
42059
|
if (!Array.isArray(items)) {
|
|
@@ -41823,15 +42064,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
41823
42064
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
41824
42065
|
continue;
|
|
41825
42066
|
}
|
|
41826
|
-
const skillDir =
|
|
42067
|
+
const skillDir = path49.join(cwd, targetDir, item.skillName);
|
|
41827
42068
|
for (const f of item.files) {
|
|
41828
42069
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
41829
|
-
const dest =
|
|
41830
|
-
|
|
42070
|
+
const dest = path49.join(skillDir, f.path);
|
|
42071
|
+
fs43.mkdirSync(path49.dirname(dest), { recursive: true });
|
|
41831
42072
|
if (f.text !== void 0) {
|
|
41832
|
-
|
|
42073
|
+
fs43.writeFileSync(dest, f.text, "utf8");
|
|
41833
42074
|
} else if (f.base64) {
|
|
41834
|
-
|
|
42075
|
+
fs43.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
41835
42076
|
}
|
|
41836
42077
|
}
|
|
41837
42078
|
installed2.push({
|
|
@@ -41872,12 +42113,116 @@ var handleRefreshLocalSkills = (_msg, deps) => {
|
|
|
41872
42113
|
deps.sendLocalSkillsReport?.();
|
|
41873
42114
|
};
|
|
41874
42115
|
|
|
41875
|
-
// src/routing/handlers/session-git-
|
|
41876
|
-
function
|
|
42116
|
+
// src/routing/handlers/git/handle-session-git-commit.ts
|
|
42117
|
+
async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
|
|
42118
|
+
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
42119
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
42120
|
+
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
42121
|
+
if (!branch.trim() || !message.trim()) {
|
|
42122
|
+
reply({ ok: false, error: "branch and message are required for commit" });
|
|
42123
|
+
return;
|
|
42124
|
+
}
|
|
42125
|
+
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
42126
|
+
sessionId,
|
|
42127
|
+
branch: branch.trim(),
|
|
42128
|
+
message: message.trim(),
|
|
42129
|
+
push: pushAfterCommit
|
|
42130
|
+
});
|
|
42131
|
+
if (!commitRes.ok) {
|
|
42132
|
+
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
42133
|
+
return;
|
|
42134
|
+
}
|
|
42135
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
42136
|
+
reply({
|
|
42137
|
+
ok: true,
|
|
42138
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
42139
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
42140
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
42141
|
+
});
|
|
42142
|
+
}
|
|
42143
|
+
|
|
42144
|
+
// src/routing/handlers/git/coalesce-list-changes.ts
|
|
42145
|
+
var listChangesInflight = /* @__PURE__ */ new Map();
|
|
42146
|
+
function listChangesInflightKey(sessionId, opts) {
|
|
42147
|
+
const basis = opts?.basis;
|
|
42148
|
+
return [
|
|
42149
|
+
sessionId,
|
|
42150
|
+
opts?.repoRelPath ?? "",
|
|
42151
|
+
basis?.kind === "commit" ? `commit:${basis.sha}` : "working",
|
|
42152
|
+
String(opts?.recentCommitsLimit ?? "")
|
|
42153
|
+
].join("|");
|
|
42154
|
+
}
|
|
42155
|
+
function getSessionWorkingTreeChangeDetailsCoalesced(sessionWorktreeManager, sessionId, opts) {
|
|
42156
|
+
const key = listChangesInflightKey(sessionId, opts);
|
|
42157
|
+
const existing = listChangesInflight.get(key);
|
|
42158
|
+
if (existing) return existing;
|
|
42159
|
+
const promise2 = sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts).finally(() => {
|
|
42160
|
+
if (listChangesInflight.get(key) === promise2) listChangesInflight.delete(key);
|
|
42161
|
+
});
|
|
42162
|
+
listChangesInflight.set(key, promise2);
|
|
42163
|
+
return promise2;
|
|
42164
|
+
}
|
|
42165
|
+
|
|
42166
|
+
// src/routing/handlers/git/handle-session-git-list-changes.ts
|
|
42167
|
+
async function handleSessionGitListChangesAction(deps, msg, reply) {
|
|
42168
|
+
const repoRel = typeof msg.changesRepoRelPath === "string" ? msg.changesRepoRelPath.trim() : "";
|
|
42169
|
+
const view = msg.changesView === "commit" ? "commit" : "working";
|
|
42170
|
+
const commitSha = typeof msg.changesCommitSha === "string" ? msg.changesCommitSha.trim() : "";
|
|
42171
|
+
if (view === "commit") {
|
|
42172
|
+
if (!repoRel || !commitSha) {
|
|
42173
|
+
reply({ ok: false, error: "changesRepoRelPath and changesCommitSha are required for commit view" });
|
|
42174
|
+
return;
|
|
42175
|
+
}
|
|
42176
|
+
}
|
|
42177
|
+
const recentCommitsLimit = typeof msg.changesRecentCommitsLimit === "number" || typeof msg.changesRecentCommitsLimit === "string" ? msg.changesRecentCommitsLimit : void 0;
|
|
42178
|
+
const opts = repoRel && view === "commit" && commitSha ? {
|
|
42179
|
+
repoRelPath: repoRel,
|
|
42180
|
+
basis: { kind: "commit", sha: commitSha },
|
|
42181
|
+
recentCommitsLimit
|
|
42182
|
+
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
42183
|
+
const repos = await getSessionWorkingTreeChangeDetailsCoalesced(
|
|
42184
|
+
deps.sessionWorktreeManager,
|
|
42185
|
+
msg.sessionId,
|
|
42186
|
+
opts
|
|
42187
|
+
);
|
|
42188
|
+
reply({ ok: true, repos }, ["repos"]);
|
|
42189
|
+
}
|
|
42190
|
+
|
|
42191
|
+
// src/routing/handlers/git/handle-session-git-push.ts
|
|
42192
|
+
async function handleSessionGitPushAction(deps, sessionId, reply) {
|
|
42193
|
+
const pushRes = await deps.sessionWorktreeManager.pushSessionUpstream(sessionId);
|
|
42194
|
+
if (!pushRes.ok) {
|
|
42195
|
+
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
42196
|
+
return;
|
|
42197
|
+
}
|
|
42198
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
42199
|
+
reply({
|
|
42200
|
+
ok: true,
|
|
42201
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
42202
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
42203
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
42204
|
+
});
|
|
42205
|
+
}
|
|
42206
|
+
|
|
42207
|
+
// src/routing/handlers/git/handle-session-git-status.ts
|
|
42208
|
+
async function handleSessionGitStatusAction(deps, sessionId, reply) {
|
|
42209
|
+
const r = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
42210
|
+
reply({
|
|
42211
|
+
ok: true,
|
|
42212
|
+
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
42213
|
+
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
42214
|
+
uncommittedFileCount: r.uncommittedFileCount
|
|
42215
|
+
});
|
|
42216
|
+
}
|
|
42217
|
+
|
|
42218
|
+
// src/routing/handlers/git/send-session-git-result.ts
|
|
42219
|
+
function sendSessionGitResult(ws, id, payload, e2ee, encryptedFields = []) {
|
|
41877
42220
|
if (!ws) return;
|
|
41878
42221
|
const message = { type: "session_git_result", id, ...payload };
|
|
41879
42222
|
sendWsMessage(ws, e2ee && encryptedFields.length > 0 ? e2ee.encryptFields(message, encryptedFields) : message);
|
|
41880
42223
|
}
|
|
42224
|
+
|
|
42225
|
+
// src/routing/handlers/git/session-git-request.ts
|
|
41881
42226
|
var handleSessionGitRequestMessage = (msg, deps) => {
|
|
41882
42227
|
if (typeof msg.id !== "string") return;
|
|
41883
42228
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -41886,80 +42231,21 @@ var handleSessionGitRequestMessage = (msg, deps) => {
|
|
|
41886
42231
|
return;
|
|
41887
42232
|
void (async () => {
|
|
41888
42233
|
const ws = deps.getWs();
|
|
41889
|
-
const reply = (payload, encryptedFields = []) =>
|
|
42234
|
+
const reply = (payload, encryptedFields = []) => sendSessionGitResult(ws, msg.id, payload, deps.e2ee, encryptedFields);
|
|
41890
42235
|
try {
|
|
41891
42236
|
if (action === "status") {
|
|
41892
|
-
|
|
41893
|
-
reply({
|
|
41894
|
-
ok: true,
|
|
41895
|
-
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
41896
|
-
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
41897
|
-
uncommittedFileCount: r.uncommittedFileCount
|
|
41898
|
-
});
|
|
42237
|
+
await handleSessionGitStatusAction(deps, sessionId, reply);
|
|
41899
42238
|
return;
|
|
41900
42239
|
}
|
|
41901
42240
|
if (action === "list_changes") {
|
|
41902
|
-
|
|
41903
|
-
const view = msg.changesView === "commit" ? "commit" : "working";
|
|
41904
|
-
const commitSha = typeof msg.changesCommitSha === "string" ? msg.changesCommitSha.trim() : "";
|
|
41905
|
-
if (view === "commit") {
|
|
41906
|
-
if (!repoRel || !commitSha) {
|
|
41907
|
-
reply({ ok: false, error: "changesRepoRelPath and changesCommitSha are required for commit view" });
|
|
41908
|
-
return;
|
|
41909
|
-
}
|
|
41910
|
-
}
|
|
41911
|
-
const recentCommitsLimit = typeof msg.changesRecentCommitsLimit === "number" || typeof msg.changesRecentCommitsLimit === "string" ? msg.changesRecentCommitsLimit : void 0;
|
|
41912
|
-
const opts = repoRel && view === "commit" && commitSha ? {
|
|
41913
|
-
repoRelPath: repoRel,
|
|
41914
|
-
basis: { kind: "commit", sha: commitSha },
|
|
41915
|
-
recentCommitsLimit
|
|
41916
|
-
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
41917
|
-
const repos = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts);
|
|
41918
|
-
reply({
|
|
41919
|
-
ok: true,
|
|
41920
|
-
repos
|
|
41921
|
-
}, ["repos"]);
|
|
42241
|
+
await handleSessionGitListChangesAction(deps, { ...msg, sessionId }, reply);
|
|
41922
42242
|
return;
|
|
41923
42243
|
}
|
|
41924
42244
|
if (action === "push") {
|
|
41925
|
-
|
|
41926
|
-
if (!pushRes.ok) {
|
|
41927
|
-
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
41928
|
-
return;
|
|
41929
|
-
}
|
|
41930
|
-
const st2 = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
41931
|
-
reply({
|
|
41932
|
-
ok: true,
|
|
41933
|
-
hasUncommittedChanges: st2.hasUncommittedChanges,
|
|
41934
|
-
hasUnpushedCommits: st2.hasUnpushedCommits,
|
|
41935
|
-
uncommittedFileCount: st2.uncommittedFileCount
|
|
41936
|
-
});
|
|
41937
|
-
return;
|
|
41938
|
-
}
|
|
41939
|
-
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
41940
|
-
const message = typeof msg.message === "string" ? msg.message : "";
|
|
41941
|
-
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
41942
|
-
if (!branch.trim() || !message.trim()) {
|
|
41943
|
-
reply({ ok: false, error: "branch and message are required for commit" });
|
|
42245
|
+
await handleSessionGitPushAction(deps, sessionId, reply);
|
|
41944
42246
|
return;
|
|
41945
42247
|
}
|
|
41946
|
-
|
|
41947
|
-
sessionId,
|
|
41948
|
-
branch: branch.trim(),
|
|
41949
|
-
message: message.trim(),
|
|
41950
|
-
push: pushAfterCommit
|
|
41951
|
-
});
|
|
41952
|
-
if (!commitRes.ok) {
|
|
41953
|
-
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
41954
|
-
return;
|
|
41955
|
-
}
|
|
41956
|
-
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
41957
|
-
reply({
|
|
41958
|
-
ok: true,
|
|
41959
|
-
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
41960
|
-
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
41961
|
-
uncommittedFileCount: st.uncommittedFileCount
|
|
41962
|
-
});
|
|
42248
|
+
await handleSessionGitCommitAction(deps, sessionId, msg, reply);
|
|
41963
42249
|
} catch (e) {
|
|
41964
42250
|
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
41965
42251
|
}
|
|
@@ -41989,7 +42275,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
41989
42275
|
};
|
|
41990
42276
|
|
|
41991
42277
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
41992
|
-
import * as
|
|
42278
|
+
import * as fs44 from "node:fs";
|
|
41993
42279
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
41994
42280
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
41995
42281
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -42002,7 +42288,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
42002
42288
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
42003
42289
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
42004
42290
|
try {
|
|
42005
|
-
await
|
|
42291
|
+
await fs44.promises.access(file2, fs44.constants.F_OK);
|
|
42006
42292
|
} catch {
|
|
42007
42293
|
sendWsMessage(s, {
|
|
42008
42294
|
type: "revert_turn_snapshot_result",
|
|
@@ -42044,7 +42330,7 @@ var handleDevServersConfig = (msg, deps) => {
|
|
|
42044
42330
|
};
|
|
42045
42331
|
|
|
42046
42332
|
// src/git/bridge-git-context.ts
|
|
42047
|
-
import * as
|
|
42333
|
+
import * as path50 from "node:path";
|
|
42048
42334
|
|
|
42049
42335
|
// src/git/branches/get-current-branch.ts
|
|
42050
42336
|
async function getCurrentBranch(repoPath) {
|
|
@@ -42094,12 +42380,12 @@ async function listRepoBranchRefs(repoPath) {
|
|
|
42094
42380
|
// src/git/bridge-git-context.ts
|
|
42095
42381
|
function folderNameForRelPath(relPath, bridgeRoot) {
|
|
42096
42382
|
if (relPath === "." || relPath === "") {
|
|
42097
|
-
return
|
|
42383
|
+
return path50.basename(path50.resolve(bridgeRoot)) || "repo";
|
|
42098
42384
|
}
|
|
42099
|
-
return
|
|
42385
|
+
return path50.basename(relPath) || relPath;
|
|
42100
42386
|
}
|
|
42101
42387
|
async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
42102
|
-
const root =
|
|
42388
|
+
const root = path50.resolve(bridgeRoot);
|
|
42103
42389
|
if (await isGitRepoDirectory(root)) {
|
|
42104
42390
|
const remoteUrl = await getRemoteOriginUrl(root);
|
|
42105
42391
|
return [{ absolutePath: root, remoteUrl }];
|
|
@@ -42107,17 +42393,17 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
|
42107
42393
|
const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
|
|
42108
42394
|
const byPath = /* @__PURE__ */ new Map();
|
|
42109
42395
|
for (const repo of [...deep, ...shallow]) {
|
|
42110
|
-
byPath.set(
|
|
42396
|
+
byPath.set(path50.resolve(repo.absolutePath), repo);
|
|
42111
42397
|
}
|
|
42112
42398
|
return [...byPath.values()];
|
|
42113
42399
|
}
|
|
42114
42400
|
async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
42115
|
-
const bridgeResolved =
|
|
42401
|
+
const bridgeResolved = path50.resolve(bridgeRoot);
|
|
42116
42402
|
const repos = await discoverGitReposForBridgeContext(bridgeResolved);
|
|
42117
42403
|
const rows = [];
|
|
42118
42404
|
for (const repo of repos) {
|
|
42119
|
-
let rel =
|
|
42120
|
-
if (rel.startsWith("..") ||
|
|
42405
|
+
let rel = path50.relative(bridgeResolved, repo.absolutePath);
|
|
42406
|
+
if (rel.startsWith("..") || path50.isAbsolute(rel)) continue;
|
|
42121
42407
|
const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
42122
42408
|
const currentBranch = await getCurrentBranch(repo.absolutePath);
|
|
42123
42409
|
const remoteUrl = repo.remoteUrl.trim() || null;
|
|
@@ -42132,11 +42418,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
|
42132
42418
|
return rows;
|
|
42133
42419
|
}
|
|
42134
42420
|
async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
42135
|
-
const bridgeResolved =
|
|
42421
|
+
const bridgeResolved = path50.resolve(bridgeRoot);
|
|
42136
42422
|
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
42137
|
-
const repoPath = rel === "" ? bridgeResolved :
|
|
42138
|
-
const resolved =
|
|
42139
|
-
if (!resolved.startsWith(bridgeResolved +
|
|
42423
|
+
const repoPath = rel === "" ? bridgeResolved : path50.join(bridgeResolved, rel);
|
|
42424
|
+
const resolved = path50.resolve(repoPath);
|
|
42425
|
+
if (!resolved.startsWith(bridgeResolved + path50.sep) && resolved !== bridgeResolved) {
|
|
42140
42426
|
return [];
|
|
42141
42427
|
}
|
|
42142
42428
|
return listRepoBranchRefs(resolved);
|
|
@@ -42641,10 +42927,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
|
42641
42927
|
}
|
|
42642
42928
|
|
|
42643
42929
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
42644
|
-
import * as
|
|
42930
|
+
import * as path52 from "node:path";
|
|
42645
42931
|
|
|
42646
42932
|
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
42647
|
-
import * as
|
|
42933
|
+
import * as path51 from "node:path";
|
|
42648
42934
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
42649
42935
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
|
|
42650
42936
|
const canContinue = () => shouldContinue?.() !== false;
|
|
@@ -42682,7 +42968,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
42682
42968
|
if (!canContinue()) return false;
|
|
42683
42969
|
handle = await resolved.createClient({
|
|
42684
42970
|
command: resolved.command,
|
|
42685
|
-
cwd:
|
|
42971
|
+
cwd: path51.resolve(cwd),
|
|
42686
42972
|
backendAgentType: agentType,
|
|
42687
42973
|
sessionMode: "agent",
|
|
42688
42974
|
persistedAcpSessionId: null,
|
|
@@ -42760,7 +43046,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
42760
43046
|
const { workspaceId, log: log2, getWs } = params;
|
|
42761
43047
|
const isCurrent = beginAgentCapabilityWarmupRun();
|
|
42762
43048
|
if (!isCurrent()) return;
|
|
42763
|
-
const cwd =
|
|
43049
|
+
const cwd = path52.resolve(getBridgeRoot());
|
|
42764
43050
|
async function sendBatchFromCache() {
|
|
42765
43051
|
if (!isCurrent()) return;
|
|
42766
43052
|
const socket = getWs();
|
|
@@ -43106,18 +43392,18 @@ import * as http from "node:http";
|
|
|
43106
43392
|
|
|
43107
43393
|
// src/mcp/bridge-access/read-json-body.ts
|
|
43108
43394
|
function readJsonBody(req) {
|
|
43109
|
-
return new Promise((
|
|
43395
|
+
return new Promise((resolve28, reject) => {
|
|
43110
43396
|
const chunks = [];
|
|
43111
43397
|
req.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
43112
43398
|
req.on("end", () => {
|
|
43113
43399
|
try {
|
|
43114
43400
|
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
43115
43401
|
if (!raw) {
|
|
43116
|
-
|
|
43402
|
+
resolve28({});
|
|
43117
43403
|
return;
|
|
43118
43404
|
}
|
|
43119
43405
|
const parsed = JSON.parse(raw);
|
|
43120
|
-
|
|
43406
|
+
resolve28(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
|
|
43121
43407
|
} catch (e) {
|
|
43122
43408
|
reject(e);
|
|
43123
43409
|
}
|
|
@@ -43175,7 +43461,7 @@ function createBridgeAccessRequestHandler(registry2) {
|
|
|
43175
43461
|
// src/mcp/bridge-access/start-server.ts
|
|
43176
43462
|
function startBridgeAccessServer(registry2) {
|
|
43177
43463
|
const server = http.createServer(createBridgeAccessRequestHandler(registry2));
|
|
43178
|
-
return new Promise((
|
|
43464
|
+
return new Promise((resolve28, reject) => {
|
|
43179
43465
|
server.once("error", reject);
|
|
43180
43466
|
server.listen(0, "127.0.0.1", () => {
|
|
43181
43467
|
const addr = server.address();
|
|
@@ -43183,7 +43469,7 @@ function startBridgeAccessServer(registry2) {
|
|
|
43183
43469
|
reject(new Error("Bridge access server did not bind"));
|
|
43184
43470
|
return;
|
|
43185
43471
|
}
|
|
43186
|
-
|
|
43472
|
+
resolve28({
|
|
43187
43473
|
port: addr.port,
|
|
43188
43474
|
close: () => new Promise((closeResolve, closeReject) => {
|
|
43189
43475
|
server.close((err) => err ? closeReject(err) : closeResolve());
|
|
@@ -43323,8 +43609,8 @@ async function createBridgeConnection(options) {
|
|
|
43323
43609
|
getCloudAccessToken: () => tokens.accessToken
|
|
43324
43610
|
};
|
|
43325
43611
|
const identifyReportedPaths = {
|
|
43326
|
-
bridgeRootPath:
|
|
43327
|
-
worktreesRootPath:
|
|
43612
|
+
bridgeRootPath: path53.resolve(getBridgeRoot()),
|
|
43613
|
+
worktreesRootPath: path53.resolve(worktreesRootPath)
|
|
43328
43614
|
};
|
|
43329
43615
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
43330
43616
|
state,
|
|
@@ -43579,9 +43865,9 @@ async function runCliAction(program2, opts) {
|
|
|
43579
43865
|
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
43580
43866
|
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);
|
|
43581
43867
|
if (bridgeRootOpt) {
|
|
43582
|
-
const resolvedBridgeRoot =
|
|
43868
|
+
const resolvedBridgeRoot = path54.resolve(process.cwd(), bridgeRootOpt);
|
|
43583
43869
|
try {
|
|
43584
|
-
const st =
|
|
43870
|
+
const st = fs45.statSync(resolvedBridgeRoot);
|
|
43585
43871
|
if (!st.isDirectory()) {
|
|
43586
43872
|
console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
|
|
43587
43873
|
process.exit(1);
|
|
@@ -43601,7 +43887,7 @@ async function runCliAction(program2, opts) {
|
|
|
43601
43887
|
);
|
|
43602
43888
|
let worktreesRootPath;
|
|
43603
43889
|
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
43604
|
-
worktreesRootPath =
|
|
43890
|
+
worktreesRootPath = path54.resolve(opts.worktreesRoot.trim());
|
|
43605
43891
|
}
|
|
43606
43892
|
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
43607
43893
|
if (e2eCertificates) {
|