@buildautomaton/cli 0.1.46 → 0.1.47
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 +770 -438
- package/dist/cli.js.map +4 -4
- package/dist/index.js +749 -417
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4175,8 +4175,8 @@ var init_parseUtil = __esm({
|
|
|
4175
4175
|
init_errors();
|
|
4176
4176
|
init_en();
|
|
4177
4177
|
makeIssue = (params) => {
|
|
4178
|
-
const { data, path:
|
|
4179
|
-
const fullPath = [...
|
|
4178
|
+
const { data, path: path46, errorMaps, issueData } = params;
|
|
4179
|
+
const fullPath = [...path46, ...issueData.path || []];
|
|
4180
4180
|
const fullIssue = {
|
|
4181
4181
|
...issueData,
|
|
4182
4182
|
path: fullPath
|
|
@@ -4484,11 +4484,11 @@ var init_types = __esm({
|
|
|
4484
4484
|
init_parseUtil();
|
|
4485
4485
|
init_util();
|
|
4486
4486
|
ParseInputLazyPath = class {
|
|
4487
|
-
constructor(parent, value,
|
|
4487
|
+
constructor(parent, value, path46, key) {
|
|
4488
4488
|
this._cachedPath = [];
|
|
4489
4489
|
this.parent = parent;
|
|
4490
4490
|
this.data = value;
|
|
4491
|
-
this._path =
|
|
4491
|
+
this._path = path46;
|
|
4492
4492
|
this._key = key;
|
|
4493
4493
|
}
|
|
4494
4494
|
get path() {
|
|
@@ -8103,15 +8103,15 @@ function assignProp(target, prop, value) {
|
|
|
8103
8103
|
configurable: true
|
|
8104
8104
|
});
|
|
8105
8105
|
}
|
|
8106
|
-
function getElementAtPath(obj,
|
|
8107
|
-
if (!
|
|
8106
|
+
function getElementAtPath(obj, path46) {
|
|
8107
|
+
if (!path46)
|
|
8108
8108
|
return obj;
|
|
8109
|
-
return
|
|
8109
|
+
return path46.reduce((acc, key) => acc?.[key], obj);
|
|
8110
8110
|
}
|
|
8111
8111
|
function promiseAllObject(promisesObj) {
|
|
8112
8112
|
const keys = Object.keys(promisesObj);
|
|
8113
|
-
const
|
|
8114
|
-
return Promise.all(
|
|
8113
|
+
const promises6 = keys.map((key) => promisesObj[key]);
|
|
8114
|
+
return Promise.all(promises6).then((results) => {
|
|
8115
8115
|
const resolvedObj = {};
|
|
8116
8116
|
for (let i = 0; i < keys.length; i++) {
|
|
8117
8117
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -8355,11 +8355,11 @@ function aborted(x, startIndex = 0) {
|
|
|
8355
8355
|
}
|
|
8356
8356
|
return false;
|
|
8357
8357
|
}
|
|
8358
|
-
function prefixIssues(
|
|
8358
|
+
function prefixIssues(path46, issues) {
|
|
8359
8359
|
return issues.map((iss) => {
|
|
8360
8360
|
var _a2;
|
|
8361
8361
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
8362
|
-
iss.path.unshift(
|
|
8362
|
+
iss.path.unshift(path46);
|
|
8363
8363
|
return iss;
|
|
8364
8364
|
});
|
|
8365
8365
|
}
|
|
@@ -8548,7 +8548,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8548
8548
|
return issue2.message;
|
|
8549
8549
|
};
|
|
8550
8550
|
const result = { errors: [] };
|
|
8551
|
-
const processError = (error41,
|
|
8551
|
+
const processError = (error41, path46 = []) => {
|
|
8552
8552
|
var _a2, _b;
|
|
8553
8553
|
for (const issue2 of error41.issues) {
|
|
8554
8554
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -8558,7 +8558,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8558
8558
|
} else if (issue2.code === "invalid_element") {
|
|
8559
8559
|
processError({ issues: issue2.issues }, issue2.path);
|
|
8560
8560
|
} else {
|
|
8561
|
-
const fullpath = [...
|
|
8561
|
+
const fullpath = [...path46, ...issue2.path];
|
|
8562
8562
|
if (fullpath.length === 0) {
|
|
8563
8563
|
result.errors.push(mapper(issue2));
|
|
8564
8564
|
continue;
|
|
@@ -8588,9 +8588,9 @@ function treeifyError(error40, _mapper) {
|
|
|
8588
8588
|
processError(error40);
|
|
8589
8589
|
return result;
|
|
8590
8590
|
}
|
|
8591
|
-
function toDotPath(
|
|
8591
|
+
function toDotPath(path46) {
|
|
8592
8592
|
const segs = [];
|
|
8593
|
-
for (const seg of
|
|
8593
|
+
for (const seg of path46) {
|
|
8594
8594
|
if (typeof seg === "number")
|
|
8595
8595
|
segs.push(`[${seg}]`);
|
|
8596
8596
|
else if (typeof seg === "symbol")
|
|
@@ -22073,10 +22073,10 @@ var require_src2 = __commonJS({
|
|
|
22073
22073
|
var fs_1 = __require("fs");
|
|
22074
22074
|
var debug_1 = __importDefault(require_src());
|
|
22075
22075
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
22076
|
-
function check2(
|
|
22077
|
-
log2(`checking %s`,
|
|
22076
|
+
function check2(path46, isFile, isDirectory) {
|
|
22077
|
+
log2(`checking %s`, path46);
|
|
22078
22078
|
try {
|
|
22079
|
-
const stat2 = fs_1.statSync(
|
|
22079
|
+
const stat2 = fs_1.statSync(path46);
|
|
22080
22080
|
if (stat2.isFile() && isFile) {
|
|
22081
22081
|
log2(`[OK] path represents a file`);
|
|
22082
22082
|
return true;
|
|
@@ -22096,8 +22096,8 @@ var require_src2 = __commonJS({
|
|
|
22096
22096
|
throw e;
|
|
22097
22097
|
}
|
|
22098
22098
|
}
|
|
22099
|
-
function exists2(
|
|
22100
|
-
return check2(
|
|
22099
|
+
function exists2(path46, type = exports.READABLE) {
|
|
22100
|
+
return check2(path46, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
22101
22101
|
}
|
|
22102
22102
|
exports.exists = exists2;
|
|
22103
22103
|
exports.FILE = 1;
|
|
@@ -22940,9 +22940,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
22940
22940
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
22941
22941
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
22942
22942
|
if (!rawPath || !summary) continue;
|
|
22943
|
-
const
|
|
22944
|
-
if (!
|
|
22945
|
-
rows.push({ path:
|
|
22943
|
+
const path46 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
22944
|
+
if (!path46) continue;
|
|
22945
|
+
rows.push({ path: path46, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
22946
22946
|
}
|
|
22947
22947
|
return rows;
|
|
22948
22948
|
}
|
|
@@ -24241,8 +24241,8 @@ function randomSecret() {
|
|
|
24241
24241
|
}
|
|
24242
24242
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
24243
24243
|
}
|
|
24244
|
-
async function requestPreviewApi(port, secret, method,
|
|
24245
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
24244
|
+
async function requestPreviewApi(port, secret, method, path46, body) {
|
|
24245
|
+
const url2 = `http://127.0.0.1:${port}${path46}`;
|
|
24246
24246
|
const headers = {
|
|
24247
24247
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
24248
24248
|
"Content-Type": "application/json"
|
|
@@ -24254,7 +24254,7 @@ async function requestPreviewApi(port, secret, method, path44, body) {
|
|
|
24254
24254
|
});
|
|
24255
24255
|
const data = await res.json().catch(() => ({}));
|
|
24256
24256
|
if (!res.ok) {
|
|
24257
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
24257
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path46}: ${res.status}`);
|
|
24258
24258
|
}
|
|
24259
24259
|
return data;
|
|
24260
24260
|
}
|
|
@@ -24469,7 +24469,7 @@ function installBridgeProcessResilience() {
|
|
|
24469
24469
|
}
|
|
24470
24470
|
|
|
24471
24471
|
// src/cli-version.ts
|
|
24472
|
-
var CLI_VERSION = "0.1.
|
|
24472
|
+
var CLI_VERSION = "0.1.47".length > 0 ? "0.1.47" : "0.0.0-dev";
|
|
24473
24473
|
|
|
24474
24474
|
// src/connection/heartbeat/constants.ts
|
|
24475
24475
|
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -27995,8 +27995,8 @@ function pathspec(...paths) {
|
|
|
27995
27995
|
cache.set(key, paths);
|
|
27996
27996
|
return key;
|
|
27997
27997
|
}
|
|
27998
|
-
function isPathSpec(
|
|
27999
|
-
return
|
|
27998
|
+
function isPathSpec(path46) {
|
|
27999
|
+
return path46 instanceof String && cache.has(path46);
|
|
28000
28000
|
}
|
|
28001
28001
|
function toPaths(pathSpec) {
|
|
28002
28002
|
return cache.get(pathSpec) || [];
|
|
@@ -28085,8 +28085,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
28085
28085
|
function forEachLineWithContent(input, callback) {
|
|
28086
28086
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
28087
28087
|
}
|
|
28088
|
-
function folderExists(
|
|
28089
|
-
return (0, import_file_exists.exists)(
|
|
28088
|
+
function folderExists(path46) {
|
|
28089
|
+
return (0, import_file_exists.exists)(path46, import_file_exists.FOLDER);
|
|
28090
28090
|
}
|
|
28091
28091
|
function append(target, item) {
|
|
28092
28092
|
if (Array.isArray(target)) {
|
|
@@ -28490,8 +28490,8 @@ function checkIsRepoRootTask() {
|
|
|
28490
28490
|
commands,
|
|
28491
28491
|
format: "utf-8",
|
|
28492
28492
|
onError,
|
|
28493
|
-
parser(
|
|
28494
|
-
return /^\.(git)?$/.test(
|
|
28493
|
+
parser(path46) {
|
|
28494
|
+
return /^\.(git)?$/.test(path46.trim());
|
|
28495
28495
|
}
|
|
28496
28496
|
};
|
|
28497
28497
|
}
|
|
@@ -28925,11 +28925,11 @@ function parseGrep(grep) {
|
|
|
28925
28925
|
const paths = /* @__PURE__ */ new Set();
|
|
28926
28926
|
const results = {};
|
|
28927
28927
|
forEachLineWithContent(grep, (input) => {
|
|
28928
|
-
const [
|
|
28929
|
-
paths.add(
|
|
28930
|
-
(results[
|
|
28928
|
+
const [path46, line, preview] = input.split(NULL);
|
|
28929
|
+
paths.add(path46);
|
|
28930
|
+
(results[path46] = results[path46] || []).push({
|
|
28931
28931
|
line: asNumber(line),
|
|
28932
|
-
path:
|
|
28932
|
+
path: path46,
|
|
28933
28933
|
preview
|
|
28934
28934
|
});
|
|
28935
28935
|
});
|
|
@@ -29694,14 +29694,14 @@ var init_hash_object = __esm2({
|
|
|
29694
29694
|
init_task();
|
|
29695
29695
|
}
|
|
29696
29696
|
});
|
|
29697
|
-
function parseInit(bare,
|
|
29697
|
+
function parseInit(bare, path46, text) {
|
|
29698
29698
|
const response = String(text).trim();
|
|
29699
29699
|
let result;
|
|
29700
29700
|
if (result = initResponseRegex.exec(response)) {
|
|
29701
|
-
return new InitSummary(bare,
|
|
29701
|
+
return new InitSummary(bare, path46, false, result[1]);
|
|
29702
29702
|
}
|
|
29703
29703
|
if (result = reInitResponseRegex.exec(response)) {
|
|
29704
|
-
return new InitSummary(bare,
|
|
29704
|
+
return new InitSummary(bare, path46, true, result[1]);
|
|
29705
29705
|
}
|
|
29706
29706
|
let gitDir = "";
|
|
29707
29707
|
const tokens = response.split(" ");
|
|
@@ -29712,7 +29712,7 @@ function parseInit(bare, path44, text) {
|
|
|
29712
29712
|
break;
|
|
29713
29713
|
}
|
|
29714
29714
|
}
|
|
29715
|
-
return new InitSummary(bare,
|
|
29715
|
+
return new InitSummary(bare, path46, /^re/i.test(response), gitDir);
|
|
29716
29716
|
}
|
|
29717
29717
|
var InitSummary;
|
|
29718
29718
|
var initResponseRegex;
|
|
@@ -29721,9 +29721,9 @@ var init_InitSummary = __esm2({
|
|
|
29721
29721
|
"src/lib/responses/InitSummary.ts"() {
|
|
29722
29722
|
"use strict";
|
|
29723
29723
|
InitSummary = class {
|
|
29724
|
-
constructor(bare,
|
|
29724
|
+
constructor(bare, path46, existing, gitDir) {
|
|
29725
29725
|
this.bare = bare;
|
|
29726
|
-
this.path =
|
|
29726
|
+
this.path = path46;
|
|
29727
29727
|
this.existing = existing;
|
|
29728
29728
|
this.gitDir = gitDir;
|
|
29729
29729
|
}
|
|
@@ -29735,7 +29735,7 @@ var init_InitSummary = __esm2({
|
|
|
29735
29735
|
function hasBareCommand(command) {
|
|
29736
29736
|
return command.includes(bareCommand);
|
|
29737
29737
|
}
|
|
29738
|
-
function initTask(bare = false,
|
|
29738
|
+
function initTask(bare = false, path46, customArgs) {
|
|
29739
29739
|
const commands = ["init", ...customArgs];
|
|
29740
29740
|
if (bare && !hasBareCommand(commands)) {
|
|
29741
29741
|
commands.splice(1, 0, bareCommand);
|
|
@@ -29744,7 +29744,7 @@ function initTask(bare = false, path44, customArgs) {
|
|
|
29744
29744
|
commands,
|
|
29745
29745
|
format: "utf-8",
|
|
29746
29746
|
parser(text) {
|
|
29747
|
-
return parseInit(commands.includes("--bare"),
|
|
29747
|
+
return parseInit(commands.includes("--bare"), path46, text);
|
|
29748
29748
|
}
|
|
29749
29749
|
};
|
|
29750
29750
|
}
|
|
@@ -30560,12 +30560,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
30560
30560
|
"use strict";
|
|
30561
30561
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
30562
30562
|
FileStatusSummary = class {
|
|
30563
|
-
constructor(
|
|
30564
|
-
this.path =
|
|
30563
|
+
constructor(path46, index, working_dir) {
|
|
30564
|
+
this.path = path46;
|
|
30565
30565
|
this.index = index;
|
|
30566
30566
|
this.working_dir = working_dir;
|
|
30567
30567
|
if (index === "R" || working_dir === "R") {
|
|
30568
|
-
const detail = fromPathRegex.exec(
|
|
30568
|
+
const detail = fromPathRegex.exec(path46) || [null, path46, path46];
|
|
30569
30569
|
this.from = detail[2] || "";
|
|
30570
30570
|
this.path = detail[1] || "";
|
|
30571
30571
|
}
|
|
@@ -30596,14 +30596,14 @@ function splitLine(result, lineStr) {
|
|
|
30596
30596
|
default:
|
|
30597
30597
|
return;
|
|
30598
30598
|
}
|
|
30599
|
-
function data(index, workingDir,
|
|
30599
|
+
function data(index, workingDir, path46) {
|
|
30600
30600
|
const raw = `${index}${workingDir}`;
|
|
30601
30601
|
const handler = parsers6.get(raw);
|
|
30602
30602
|
if (handler) {
|
|
30603
|
-
handler(result,
|
|
30603
|
+
handler(result, path46);
|
|
30604
30604
|
}
|
|
30605
30605
|
if (raw !== "##" && raw !== "!!") {
|
|
30606
|
-
result.files.push(new FileStatusSummary(
|
|
30606
|
+
result.files.push(new FileStatusSummary(path46, index, workingDir));
|
|
30607
30607
|
}
|
|
30608
30608
|
}
|
|
30609
30609
|
}
|
|
@@ -30912,9 +30912,9 @@ var init_simple_git_api = __esm2({
|
|
|
30912
30912
|
next
|
|
30913
30913
|
);
|
|
30914
30914
|
}
|
|
30915
|
-
hashObject(
|
|
30915
|
+
hashObject(path46, write) {
|
|
30916
30916
|
return this._runTask(
|
|
30917
|
-
hashObjectTask(
|
|
30917
|
+
hashObjectTask(path46, write === true),
|
|
30918
30918
|
trailingFunctionArgument(arguments)
|
|
30919
30919
|
);
|
|
30920
30920
|
}
|
|
@@ -31267,8 +31267,8 @@ var init_branch = __esm2({
|
|
|
31267
31267
|
}
|
|
31268
31268
|
});
|
|
31269
31269
|
function toPath(input) {
|
|
31270
|
-
const
|
|
31271
|
-
return
|
|
31270
|
+
const path46 = input.trim().replace(/^["']|["']$/g, "");
|
|
31271
|
+
return path46 && normalize3(path46);
|
|
31272
31272
|
}
|
|
31273
31273
|
var parseCheckIgnore;
|
|
31274
31274
|
var init_CheckIgnore = __esm2({
|
|
@@ -31582,8 +31582,8 @@ __export2(sub_module_exports, {
|
|
|
31582
31582
|
subModuleTask: () => subModuleTask,
|
|
31583
31583
|
updateSubModuleTask: () => updateSubModuleTask
|
|
31584
31584
|
});
|
|
31585
|
-
function addSubModuleTask(repo,
|
|
31586
|
-
return subModuleTask(["add", repo,
|
|
31585
|
+
function addSubModuleTask(repo, path46) {
|
|
31586
|
+
return subModuleTask(["add", repo, path46]);
|
|
31587
31587
|
}
|
|
31588
31588
|
function initSubModuleTask(customArgs) {
|
|
31589
31589
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -31916,8 +31916,8 @@ var require_git = __commonJS2({
|
|
|
31916
31916
|
}
|
|
31917
31917
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
31918
31918
|
};
|
|
31919
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
31920
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
31919
|
+
Git2.prototype.submoduleAdd = function(repo, path46, then) {
|
|
31920
|
+
return this._runTask(addSubModuleTask2(repo, path46), trailingFunctionArgument2(arguments));
|
|
31921
31921
|
};
|
|
31922
31922
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
31923
31923
|
return this._runTask(
|
|
@@ -32880,9 +32880,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32880
32880
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
32881
32881
|
async function putEncryptedChangeSummaryRows(params) {
|
|
32882
32882
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
32883
|
-
const entries = params.rows.map(({ path:
|
|
32883
|
+
const entries = params.rows.map(({ path: path46, summary }) => {
|
|
32884
32884
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
32885
|
-
return { path:
|
|
32885
|
+
return { path: path46, summary: JSON.stringify(enc) };
|
|
32886
32886
|
});
|
|
32887
32887
|
const res = await fetch(
|
|
32888
32888
|
`${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -33502,7 +33502,7 @@ async function createAcpManager(options) {
|
|
|
33502
33502
|
// src/git/changes/types.ts
|
|
33503
33503
|
var MAX_PATCH_CHARS = 35e4;
|
|
33504
33504
|
|
|
33505
|
-
// src/git/changes/
|
|
33505
|
+
// src/git/changes/paths/repo-format.ts
|
|
33506
33506
|
function posixJoinDirFile(dir, file2) {
|
|
33507
33507
|
const d = dir === "." || dir === "" ? "" : dir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
33508
33508
|
const f = file2.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
@@ -33557,7 +33557,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
33557
33557
|
}
|
|
33558
33558
|
|
|
33559
33559
|
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
33560
|
-
import * as
|
|
33560
|
+
import * as path22 from "node:path";
|
|
33561
33561
|
|
|
33562
33562
|
// src/git/commits/resolve-remote-tracking.ts
|
|
33563
33563
|
async function tryConfigGet(g, key) {
|
|
@@ -33727,9 +33727,232 @@ async function listRecentCommits(repoDir, limitInput) {
|
|
|
33727
33727
|
}
|
|
33728
33728
|
}
|
|
33729
33729
|
|
|
33730
|
-
// src/git/changes/
|
|
33731
|
-
function
|
|
33732
|
-
|
|
33730
|
+
// src/git/changes/parse/normalize-git-diff-path.ts
|
|
33731
|
+
function normalizeGitDiffPath(path46) {
|
|
33732
|
+
return path46.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
|
|
33733
|
+
}
|
|
33734
|
+
|
|
33735
|
+
// src/git/changes/parse/expand-git-rename-numstat-path.ts
|
|
33736
|
+
function expandGitRenameNumstatPath(rawPath) {
|
|
33737
|
+
const open2 = rawPath.indexOf("{");
|
|
33738
|
+
const arrow = rawPath.indexOf("=>");
|
|
33739
|
+
const close = rawPath.lastIndexOf("}");
|
|
33740
|
+
if (open2 === -1 || arrow === -1 || close === -1 || open2 > arrow || arrow > close) {
|
|
33741
|
+
return null;
|
|
33742
|
+
}
|
|
33743
|
+
const prefix = rawPath.slice(0, open2);
|
|
33744
|
+
const suffix = rawPath.slice(close + 1);
|
|
33745
|
+
const oldPart = rawPath.slice(open2 + 1, arrow).trim();
|
|
33746
|
+
const newPart = rawPath.slice(arrow + 2, close).trim();
|
|
33747
|
+
return {
|
|
33748
|
+
oldPath: normalizeGitDiffPath(`${prefix}${oldPart}${suffix}`),
|
|
33749
|
+
newPath: normalizeGitDiffPath(`${prefix}${newPart}${suffix}`)
|
|
33750
|
+
};
|
|
33751
|
+
}
|
|
33752
|
+
function isGitRenameNumstatPath(rawPath) {
|
|
33753
|
+
return expandGitRenameNumstatPath(rawPath) != null;
|
|
33754
|
+
}
|
|
33755
|
+
|
|
33756
|
+
// src/git/changes/rows/build-changed-file-row.ts
|
|
33757
|
+
function buildChangedFileRow(options) {
|
|
33758
|
+
const pathInRepo = normalizeGitDiffPath(options.pathInRepo);
|
|
33759
|
+
const relLauncher = posixJoinDirFile(options.repoRelPath, pathInRepo);
|
|
33760
|
+
const additions = options.numEntry?.additions ?? 0;
|
|
33761
|
+
const deletions = options.numEntry?.deletions ?? 0;
|
|
33762
|
+
let change = options.nameEntry?.change ?? "modified";
|
|
33763
|
+
let movedFromPathRelLauncher;
|
|
33764
|
+
let movedFromPathInRepo;
|
|
33765
|
+
const oldPathInRepo = options.nameEntry?.oldPathInRepo ?? options.numEntry?.oldPathInRepo;
|
|
33766
|
+
if (change === "moved" && oldPathInRepo) {
|
|
33767
|
+
movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
|
|
33768
|
+
movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
|
|
33769
|
+
} else if (oldPathInRepo && change === "modified") {
|
|
33770
|
+
change = "moved";
|
|
33771
|
+
movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
|
|
33772
|
+
movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
|
|
33773
|
+
}
|
|
33774
|
+
if (options.untracked && !options.nameEntry) {
|
|
33775
|
+
change = "added";
|
|
33776
|
+
} else if (!options.nameEntry && options.numEntry && change !== "moved") {
|
|
33777
|
+
if (additions > 0 && deletions === 0) change = "added";
|
|
33778
|
+
else if (deletions > 0 && additions === 0) change = "removed";
|
|
33779
|
+
else change = "modified";
|
|
33780
|
+
}
|
|
33781
|
+
return {
|
|
33782
|
+
pathRelLauncher: relLauncher,
|
|
33783
|
+
additions,
|
|
33784
|
+
deletions,
|
|
33785
|
+
change,
|
|
33786
|
+
...movedFromPathRelLauncher ? { movedFromPathRelLauncher } : {},
|
|
33787
|
+
...movedFromPathInRepo ? { movedFromPathInRepo } : {}
|
|
33788
|
+
};
|
|
33789
|
+
}
|
|
33790
|
+
|
|
33791
|
+
// src/git/changes/listing/build-changed-file-rows.ts
|
|
33792
|
+
async function buildChangedFileRowsFromPaths(options) {
|
|
33793
|
+
const rows = [];
|
|
33794
|
+
await forEachWithGitYield([...options.paths], async (pathInRepo) => {
|
|
33795
|
+
if (isGitRenameNumstatPath(pathInRepo)) return;
|
|
33796
|
+
if (options.movedSourcePaths.has(pathInRepo)) return;
|
|
33797
|
+
const nameEntry = options.nameByPath.get(pathInRepo);
|
|
33798
|
+
const numEntry = options.numByPath.get(pathInRepo);
|
|
33799
|
+
const row = buildChangedFileRow({
|
|
33800
|
+
pathInRepo,
|
|
33801
|
+
repoRelPath: options.repoRelPath,
|
|
33802
|
+
nameEntry,
|
|
33803
|
+
numEntry,
|
|
33804
|
+
untracked: options.untrackedSet?.has(pathInRepo)
|
|
33805
|
+
});
|
|
33806
|
+
if (options.applyUntrackedStats) {
|
|
33807
|
+
await options.applyUntrackedStats(row, pathInRepo);
|
|
33808
|
+
}
|
|
33809
|
+
rows.push(row);
|
|
33810
|
+
});
|
|
33811
|
+
return rows;
|
|
33812
|
+
}
|
|
33813
|
+
|
|
33814
|
+
// src/git/changes/patch/patch-truncate.ts
|
|
33815
|
+
function truncatePatch(s) {
|
|
33816
|
+
if (s.length <= MAX_PATCH_CHARS) return s;
|
|
33817
|
+
return `${s.slice(0, MAX_PATCH_CHARS)}
|
|
33818
|
+
|
|
33819
|
+
\u2026 (diff truncated)`;
|
|
33820
|
+
}
|
|
33821
|
+
|
|
33822
|
+
// src/git/changes/patch/unified-diff-for-file.ts
|
|
33823
|
+
function patchTextFromGitDiffOutput(raw) {
|
|
33824
|
+
if (raw.trim() === "") return void 0;
|
|
33825
|
+
return normalizePatchContent(raw);
|
|
33826
|
+
}
|
|
33827
|
+
async function unifiedDiffForFile(repoCwd, pathInRepo, change, movedFromPathInRepo) {
|
|
33828
|
+
const g = cliSimpleGit(repoCwd);
|
|
33829
|
+
const renameArgs = ["-M", "--find-renames"];
|
|
33830
|
+
const args = change === "moved" && movedFromPathInRepo ? ["diff", "--no-color", ...renameArgs, "HEAD", "--", movedFromPathInRepo, pathInRepo] : change === "removed" ? ["diff", "--no-color", ...renameArgs, "HEAD", "--", pathInRepo] : ["diff", "--no-color", ...renameArgs, "HEAD", "--", pathInRepo];
|
|
33831
|
+
const raw = await g.raw([...args]).catch(() => "");
|
|
33832
|
+
const patch = patchTextFromGitDiffOutput(String(raw));
|
|
33833
|
+
return patch ? truncatePatch(patch) : void 0;
|
|
33834
|
+
}
|
|
33835
|
+
async function unifiedDiffForFileInRange(repoCwd, range, pathInRepo, change, movedFromPathInRepo) {
|
|
33836
|
+
const g = cliSimpleGit(repoCwd);
|
|
33837
|
+
const renameArgs = ["-M", "--find-renames"];
|
|
33838
|
+
const args = change === "moved" && movedFromPathInRepo ? ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", movedFromPathInRepo, pathInRepo] : ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", pathInRepo];
|
|
33839
|
+
const raw = await g.raw([...args]).catch(() => "");
|
|
33840
|
+
const patch = patchTextFromGitDiffOutput(String(raw));
|
|
33841
|
+
return patch ? truncatePatch(patch) : void 0;
|
|
33842
|
+
}
|
|
33843
|
+
|
|
33844
|
+
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
33845
|
+
import * as fs16 from "node:fs";
|
|
33846
|
+
import * as path19 from "node:path";
|
|
33847
|
+
|
|
33848
|
+
// src/git/changes/lines/count-lines.ts
|
|
33849
|
+
import { createReadStream } from "node:fs";
|
|
33850
|
+
import * as readline2 from "node:readline";
|
|
33851
|
+
function countLinesInText(text) {
|
|
33852
|
+
return splitTextIntoDiffLines(text).length;
|
|
33853
|
+
}
|
|
33854
|
+
async function countTextFileLines(filePath) {
|
|
33855
|
+
let bytes = 0;
|
|
33856
|
+
const maxBytes = 512e3;
|
|
33857
|
+
let lines = 0;
|
|
33858
|
+
const stream = createReadStream(filePath, { encoding: "utf8" });
|
|
33859
|
+
const rl = readline2.createInterface({ input: stream, crlfDelay: Infinity });
|
|
33860
|
+
for await (const _line of rl) {
|
|
33861
|
+
lines += 1;
|
|
33862
|
+
bytes += Buffer.byteLength(String(_line), "utf8") + 1;
|
|
33863
|
+
if (bytes > maxBytes) {
|
|
33864
|
+
rl.close();
|
|
33865
|
+
stream.destroy();
|
|
33866
|
+
return lines;
|
|
33867
|
+
}
|
|
33868
|
+
}
|
|
33869
|
+
return lines;
|
|
33870
|
+
}
|
|
33871
|
+
|
|
33872
|
+
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
33873
|
+
var MAX_BYTES = 512e3;
|
|
33874
|
+
async function countLinesInGitRef(repoGitCwd, ref, pathInRepo) {
|
|
33875
|
+
const spec = `${ref}:${pathInRepo}`;
|
|
33876
|
+
const g = cliSimpleGit(repoGitCwd);
|
|
33877
|
+
try {
|
|
33878
|
+
await g.raw(["cat-file", "-e", spec]);
|
|
33879
|
+
} catch {
|
|
33880
|
+
return null;
|
|
33881
|
+
}
|
|
33882
|
+
try {
|
|
33883
|
+
const raw = String(await g.raw(["show", spec]));
|
|
33884
|
+
const capped = raw.length > MAX_BYTES ? raw.slice(0, MAX_BYTES) : raw;
|
|
33885
|
+
return countLinesInText(capped);
|
|
33886
|
+
} catch {
|
|
33887
|
+
return null;
|
|
33888
|
+
}
|
|
33889
|
+
}
|
|
33890
|
+
async function resolveWorkingTreeFileTotalLines(options) {
|
|
33891
|
+
if (options.isBinary) return null;
|
|
33892
|
+
const filePath = path19.join(options.repoGitCwd, options.pathInRepo);
|
|
33893
|
+
if (options.change === "removed") {
|
|
33894
|
+
return countLinesInGitRef(options.repoGitCwd, "HEAD", options.pathInRepo);
|
|
33895
|
+
}
|
|
33896
|
+
if (options.change === "moved" || options.change === "modified") {
|
|
33897
|
+
try {
|
|
33898
|
+
const st = await fs16.promises.stat(filePath);
|
|
33899
|
+
if (!st.isFile()) return null;
|
|
33900
|
+
return await countTextFileLines(filePath);
|
|
33901
|
+
} catch {
|
|
33902
|
+
return null;
|
|
33903
|
+
}
|
|
33904
|
+
}
|
|
33905
|
+
return null;
|
|
33906
|
+
}
|
|
33907
|
+
async function resolveCommitFileTotalLines(options) {
|
|
33908
|
+
if (options.isBinary) return null;
|
|
33909
|
+
if (options.change === "removed") {
|
|
33910
|
+
return countLinesInGitRef(options.repoGitCwd, options.parentSha, options.pathInRepo);
|
|
33911
|
+
}
|
|
33912
|
+
if (options.change === "moved" || options.change === "modified") {
|
|
33913
|
+
return countLinesInGitRef(options.repoGitCwd, options.commitSha, options.pathInRepo);
|
|
33914
|
+
}
|
|
33915
|
+
return null;
|
|
33916
|
+
}
|
|
33917
|
+
|
|
33918
|
+
// src/git/changes/listing/path-in-repo-from-launcher.ts
|
|
33919
|
+
function pathInRepoFromLauncher(pathRelLauncher, repoRelPath) {
|
|
33920
|
+
const normRel = repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
33921
|
+
if (normRel === ".") return pathRelLauncher;
|
|
33922
|
+
if (pathRelLauncher.startsWith(`${normRel}/`)) {
|
|
33923
|
+
return pathRelLauncher.slice(normRel.length + 1);
|
|
33924
|
+
}
|
|
33925
|
+
return pathRelLauncher;
|
|
33926
|
+
}
|
|
33927
|
+
function normalizeRepoRelPath(repoRelPath) {
|
|
33928
|
+
return repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
33929
|
+
}
|
|
33930
|
+
|
|
33931
|
+
// src/git/changes/listing/enrich-commit-file-rows.ts
|
|
33932
|
+
async function enrichCommitFileRows(options) {
|
|
33933
|
+
await forEachWithGitYield(options.rows, async (row) => {
|
|
33934
|
+
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
33935
|
+
row.patchContent = await unifiedDiffForFileInRange(
|
|
33936
|
+
options.repoGitCwd,
|
|
33937
|
+
options.range,
|
|
33938
|
+
pathInRepo,
|
|
33939
|
+
row.change,
|
|
33940
|
+
row.movedFromPathInRepo
|
|
33941
|
+
);
|
|
33942
|
+
row.totalLines = await resolveCommitFileTotalLines({
|
|
33943
|
+
repoGitCwd: options.repoGitCwd,
|
|
33944
|
+
pathInRepo,
|
|
33945
|
+
change: row.change,
|
|
33946
|
+
commitSha: options.commitSha,
|
|
33947
|
+
parentSha: options.parentSha,
|
|
33948
|
+
isBinary: options.binaryByPath.has(pathInRepo)
|
|
33949
|
+
});
|
|
33950
|
+
});
|
|
33951
|
+
}
|
|
33952
|
+
|
|
33953
|
+
// src/git/changes/parse/parse-name-status-entries.ts
|
|
33954
|
+
function parseNameStatusEntries(lines) {
|
|
33955
|
+
const entries = [];
|
|
33733
33956
|
for (const line of lines) {
|
|
33734
33957
|
if (!line.trim()) continue;
|
|
33735
33958
|
const tabParts = line.split(" ");
|
|
@@ -33737,58 +33960,143 @@ function parseNameStatusLines(lines) {
|
|
|
33737
33960
|
const status = tabParts[0].trim();
|
|
33738
33961
|
const code = status[0];
|
|
33739
33962
|
if (code === "A") {
|
|
33740
|
-
|
|
33963
|
+
entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "added" });
|
|
33741
33964
|
} else if (code === "D") {
|
|
33742
|
-
|
|
33965
|
+
entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "removed" });
|
|
33743
33966
|
} else if (code === "R" || code === "C") {
|
|
33744
|
-
if (tabParts.length >= 3)
|
|
33967
|
+
if (tabParts.length >= 3) {
|
|
33968
|
+
entries.push({
|
|
33969
|
+
pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]),
|
|
33970
|
+
oldPathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 2]),
|
|
33971
|
+
change: "moved"
|
|
33972
|
+
});
|
|
33973
|
+
}
|
|
33745
33974
|
} else if (code === "M" || code === "U" || code === "T") {
|
|
33746
|
-
|
|
33975
|
+
entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "modified" });
|
|
33747
33976
|
}
|
|
33748
33977
|
}
|
|
33978
|
+
return entries;
|
|
33979
|
+
}
|
|
33980
|
+
function parseNameStatusLines(lines) {
|
|
33981
|
+
const m = /* @__PURE__ */ new Map();
|
|
33982
|
+
for (const entry of parseNameStatusEntries(lines)) {
|
|
33983
|
+
m.set(entry.pathInRepo, entry.change);
|
|
33984
|
+
}
|
|
33749
33985
|
return m;
|
|
33750
33986
|
}
|
|
33751
|
-
|
|
33987
|
+
|
|
33988
|
+
// src/git/changes/parse/parse-numstat-entries.ts
|
|
33989
|
+
function parseNumstatCounts(parts) {
|
|
33990
|
+
const [a, d] = parts;
|
|
33991
|
+
return {
|
|
33992
|
+
additions: a === "-" ? 0 : parseInt(String(a), 10) || 0,
|
|
33993
|
+
deletions: d === "-" ? 0 : parseInt(String(d), 10) || 0
|
|
33994
|
+
};
|
|
33995
|
+
}
|
|
33996
|
+
function parseNumstatLine(line) {
|
|
33752
33997
|
const parts = line.split(" ");
|
|
33753
33998
|
if (parts.length < 3) return null;
|
|
33754
|
-
const
|
|
33755
|
-
const additions
|
|
33756
|
-
const
|
|
33757
|
-
|
|
33999
|
+
const rawPath = parts[parts.length - 1];
|
|
34000
|
+
const { additions, deletions } = parseNumstatCounts(parts);
|
|
34001
|
+
const expanded = expandGitRenameNumstatPath(rawPath);
|
|
34002
|
+
const pathInRepo = normalizeGitDiffPath(expanded?.newPath ?? rawPath);
|
|
34003
|
+
return {
|
|
34004
|
+
pathInRepo,
|
|
34005
|
+
additions,
|
|
34006
|
+
deletions,
|
|
34007
|
+
...expanded ? { oldPathInRepo: expanded.oldPath } : {}
|
|
34008
|
+
};
|
|
33758
34009
|
}
|
|
33759
|
-
function
|
|
34010
|
+
function parseNumstatEntries(lines) {
|
|
33760
34011
|
const m = /* @__PURE__ */ new Map();
|
|
33761
34012
|
for (const line of lines) {
|
|
33762
34013
|
if (!line.trim()) continue;
|
|
33763
34014
|
const parts = line.split(" ");
|
|
33764
34015
|
if (parts.length < 3) continue;
|
|
33765
|
-
const [
|
|
33766
|
-
const
|
|
33767
|
-
const
|
|
33768
|
-
|
|
34016
|
+
const rawPath = parts[parts.length - 1];
|
|
34017
|
+
const expanded = expandGitRenameNumstatPath(rawPath);
|
|
34018
|
+
const entry = parseNumstatLine(line);
|
|
34019
|
+
if (!entry) continue;
|
|
34020
|
+
const existing = m.get(entry.pathInRepo);
|
|
34021
|
+
if (!existing || expanded) {
|
|
34022
|
+
m.set(entry.pathInRepo, entry);
|
|
34023
|
+
}
|
|
33769
34024
|
}
|
|
33770
34025
|
return m;
|
|
33771
34026
|
}
|
|
34027
|
+
function parseNumstat(lines) {
|
|
34028
|
+
const m = /* @__PURE__ */ new Map();
|
|
34029
|
+
for (const [path46, entry] of parseNumstatEntries(lines)) {
|
|
34030
|
+
m.set(path46, { additions: entry.additions, deletions: entry.deletions });
|
|
34031
|
+
}
|
|
34032
|
+
return m;
|
|
34033
|
+
}
|
|
34034
|
+
|
|
34035
|
+
// src/git/changes/parse/numstat-from-git-no-index.ts
|
|
33772
34036
|
async function numstatFromGitNoIndex(g, pathInRepo) {
|
|
33773
34037
|
const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
33774
34038
|
try {
|
|
33775
34039
|
const out = await g.raw(["diff", "--numstat", "--no-index", "--", devNull, pathInRepo]);
|
|
33776
34040
|
const first2 = String(out).split("\n").find((l) => l.trim()) ?? "";
|
|
33777
|
-
|
|
34041
|
+
const parsed = parseNumstatLine(first2);
|
|
34042
|
+
if (!parsed) return null;
|
|
34043
|
+
return { additions: parsed.additions, deletions: parsed.deletions };
|
|
33778
34044
|
} catch {
|
|
33779
34045
|
return null;
|
|
33780
34046
|
}
|
|
33781
34047
|
}
|
|
33782
34048
|
|
|
33783
|
-
// src/git/changes/
|
|
33784
|
-
function
|
|
33785
|
-
|
|
33786
|
-
|
|
34049
|
+
// src/git/changes/rows/collect-moved-source-paths.ts
|
|
34050
|
+
function collectMovedSourcePaths(nameEntries, numByPath) {
|
|
34051
|
+
const sources = /* @__PURE__ */ new Set();
|
|
34052
|
+
for (const entry of nameEntries) {
|
|
34053
|
+
if (entry.change === "moved" && entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
|
|
34054
|
+
}
|
|
34055
|
+
for (const entry of numByPath.values()) {
|
|
34056
|
+
if (entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
|
|
34057
|
+
}
|
|
34058
|
+
return sources;
|
|
34059
|
+
}
|
|
33787
34060
|
|
|
33788
|
-
|
|
34061
|
+
// src/git/changes/numstat/is-binary-numstat-line.ts
|
|
34062
|
+
function isBinaryNumstatLine(line) {
|
|
34063
|
+
const parts = line.split(" ");
|
|
34064
|
+
if (parts.length < 3) return false;
|
|
34065
|
+
return parts[0] === "-" || parts[1] === "-";
|
|
33789
34066
|
}
|
|
33790
34067
|
|
|
33791
|
-
// src/git/
|
|
34068
|
+
// src/git/changes/listing/collect-binary-paths-from-numstat.ts
|
|
34069
|
+
function collectBinaryPathsFromNumstat(numstatRaw) {
|
|
34070
|
+
const binaryByPath = /* @__PURE__ */ new Set();
|
|
34071
|
+
for (const line of numstatRaw.split("\n")) {
|
|
34072
|
+
if (!line.trim()) continue;
|
|
34073
|
+
const parts = line.split(" ");
|
|
34074
|
+
if (parts.length < 3) continue;
|
|
34075
|
+
const rawPath = parts[parts.length - 1];
|
|
34076
|
+
const expanded = expandGitRenameNumstatPath(rawPath);
|
|
34077
|
+
if (isBinaryNumstatLine(line)) binaryByPath.add(expanded?.newPath ?? rawPath);
|
|
34078
|
+
}
|
|
34079
|
+
return binaryByPath;
|
|
34080
|
+
}
|
|
34081
|
+
|
|
34082
|
+
// src/git/changes/listing/parse-diff-output.ts
|
|
34083
|
+
function parseDiffOutput(nameStatusRaw, numstatRaw) {
|
|
34084
|
+
const nameEntries = parseNameStatusEntries(nameStatusRaw.split("\n"));
|
|
34085
|
+
const nameByPath = new Map(nameEntries.map((entry) => [entry.pathInRepo, entry]));
|
|
34086
|
+
const numByPath = parseNumstatEntries(numstatRaw.split("\n"));
|
|
34087
|
+
const movedSourcePaths = collectMovedSourcePaths(nameEntries, numByPath);
|
|
34088
|
+
const binaryByPath = collectBinaryPathsFromNumstat(numstatRaw);
|
|
34089
|
+
return { nameEntries, nameByPath, numByPath, movedSourcePaths, binaryByPath };
|
|
34090
|
+
}
|
|
34091
|
+
function collectChangedPaths(options) {
|
|
34092
|
+
const paths = /* @__PURE__ */ new Set();
|
|
34093
|
+
for (const entry of options.nameEntries) paths.add(entry.pathInRepo);
|
|
34094
|
+
for (const pathInRepo of options.numByPath.keys()) paths.add(pathInRepo);
|
|
34095
|
+
for (const pathInRepo of options.untracked ?? []) paths.add(pathInRepo);
|
|
34096
|
+
return paths;
|
|
34097
|
+
}
|
|
34098
|
+
|
|
34099
|
+
// src/git/changes/listing/parent-for-commit-diff.ts
|
|
33792
34100
|
var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
33793
34101
|
async function parentForCommitDiff(g, sha) {
|
|
33794
34102
|
try {
|
|
@@ -33801,76 +34109,112 @@ async function parentForCommitDiff(g, sha) {
|
|
|
33801
34109
|
}
|
|
33802
34110
|
}
|
|
33803
34111
|
}
|
|
34112
|
+
|
|
34113
|
+
// src/git/changes/listing/rename-diff-args.ts
|
|
34114
|
+
var RENAME_DIFF_ARGS = ["-M", "--find-renames"];
|
|
34115
|
+
|
|
34116
|
+
// src/git/changes/rows/pick-preferred-changed-file-row.ts
|
|
34117
|
+
function rowRank(row) {
|
|
34118
|
+
if (row.change === "moved") return 3;
|
|
34119
|
+
if (row.change === "modified") return 2;
|
|
34120
|
+
if (row.change === "added") return 1;
|
|
34121
|
+
return 0;
|
|
34122
|
+
}
|
|
34123
|
+
function pickPreferredChangedFileRow(a, b) {
|
|
34124
|
+
if (rowRank(a) !== rowRank(b)) return rowRank(a) > rowRank(b) ? a : b;
|
|
34125
|
+
const aHasPatch = Boolean(a.patchContent?.trim());
|
|
34126
|
+
const bHasPatch = Boolean(b.patchContent?.trim());
|
|
34127
|
+
if (aHasPatch !== bHasPatch) return aHasPatch ? a : b;
|
|
34128
|
+
const aHasMoveMeta = Boolean(a.movedFromPathInRepo || a.movedFromPathRelLauncher);
|
|
34129
|
+
const bHasMoveMeta = Boolean(b.movedFromPathInRepo || b.movedFromPathRelLauncher);
|
|
34130
|
+
if (aHasMoveMeta !== bHasMoveMeta) return aHasMoveMeta ? a : b;
|
|
34131
|
+
return a;
|
|
34132
|
+
}
|
|
34133
|
+
|
|
34134
|
+
// src/git/changes/rows/dedupe-changed-file-rows.ts
|
|
34135
|
+
function dedupeChangedFileRows(rows) {
|
|
34136
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
34137
|
+
for (const row of rows) {
|
|
34138
|
+
const key = normalizeGitDiffPath(row.pathRelLauncher);
|
|
34139
|
+
const normalizedRow = key === row.pathRelLauncher ? row : { ...row, pathRelLauncher: key };
|
|
34140
|
+
const existing = byPath.get(key);
|
|
34141
|
+
if (!existing) {
|
|
34142
|
+
byPath.set(key, normalizedRow);
|
|
34143
|
+
continue;
|
|
34144
|
+
}
|
|
34145
|
+
const preferRow = pickPreferredChangedFileRow(existing, normalizedRow);
|
|
34146
|
+
byPath.set(key, { ...preferRow, pathRelLauncher: key });
|
|
34147
|
+
}
|
|
34148
|
+
return [...byPath.values()];
|
|
34149
|
+
}
|
|
34150
|
+
|
|
34151
|
+
// src/git/changes/listing/list-changed-files-for-commit.ts
|
|
33804
34152
|
async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
33805
34153
|
const g = cliSimpleGit(repoGitCwd);
|
|
33806
34154
|
const parent = await parentForCommitDiff(g, commitSha);
|
|
33807
34155
|
const range = `${parent}..${commitSha}`;
|
|
33808
34156
|
const [nameStatusRaw, numstatRaw] = await Promise.all([
|
|
33809
|
-
g.raw(["diff", "--name-status", range]).catch(() => ""),
|
|
33810
|
-
g.raw(["diff", "--numstat", range]).catch(() => "")
|
|
34157
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", range]).catch(() => ""),
|
|
34158
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "--numstat", range]).catch(() => "")
|
|
33811
34159
|
]);
|
|
33812
|
-
const
|
|
33813
|
-
const
|
|
33814
|
-
const paths =
|
|
33815
|
-
|
|
33816
|
-
|
|
33817
|
-
await forEachWithGitYield([...paths], async (pathInRepo) => {
|
|
33818
|
-
const relLauncher = posixJoinDirFile(normRel, pathInRepo.replace(/\\/g, "/"));
|
|
33819
|
-
const nums = numByPath.get(pathInRepo);
|
|
33820
|
-
let additions = nums?.additions ?? 0;
|
|
33821
|
-
let deletions = nums?.deletions ?? 0;
|
|
33822
|
-
let change = kindByPath.get(pathInRepo) ?? "modified";
|
|
33823
|
-
if (!kindByPath.has(pathInRepo) && nums) {
|
|
33824
|
-
if (additions > 0 && deletions === 0) change = "added";
|
|
33825
|
-
else if (deletions > 0 && additions === 0) change = "removed";
|
|
33826
|
-
else change = "modified";
|
|
33827
|
-
}
|
|
33828
|
-
rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
|
|
33829
|
-
});
|
|
33830
|
-
await forEachWithGitYield(rows, async (row) => {
|
|
33831
|
-
let pathInRepo;
|
|
33832
|
-
if (normRel === ".") {
|
|
33833
|
-
pathInRepo = row.pathRelLauncher;
|
|
33834
|
-
} else if (row.pathRelLauncher.startsWith(`${normRel}/`)) {
|
|
33835
|
-
pathInRepo = row.pathRelLauncher.slice(normRel.length + 1);
|
|
33836
|
-
} else {
|
|
33837
|
-
pathInRepo = row.pathRelLauncher;
|
|
33838
|
-
}
|
|
33839
|
-
const raw = await g.raw(["diff", "-U20000", range, "--", pathInRepo]).catch(() => "");
|
|
33840
|
-
const t = String(raw).trim();
|
|
33841
|
-
row.patchContent = t ? truncatePatch(t) : void 0;
|
|
34160
|
+
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
34161
|
+
const normRel = normalizeRepoRelPath(repoRelPath);
|
|
34162
|
+
const paths = collectChangedPaths({
|
|
34163
|
+
nameEntries: parsed.nameEntries,
|
|
34164
|
+
numByPath: parsed.numByPath
|
|
33842
34165
|
});
|
|
33843
|
-
rows
|
|
33844
|
-
|
|
33845
|
-
|
|
33846
|
-
|
|
33847
|
-
|
|
34166
|
+
let rows = await buildChangedFileRowsFromPaths({
|
|
34167
|
+
paths,
|
|
34168
|
+
repoRelPath: normRel,
|
|
34169
|
+
nameByPath: parsed.nameByPath,
|
|
34170
|
+
numByPath: parsed.numByPath,
|
|
34171
|
+
movedSourcePaths: parsed.movedSourcePaths
|
|
34172
|
+
});
|
|
34173
|
+
rows = dedupeChangedFileRows(rows);
|
|
34174
|
+
await enrichCommitFileRows({
|
|
34175
|
+
rows,
|
|
34176
|
+
repoGitCwd,
|
|
34177
|
+
repoRelPath: normRel,
|
|
34178
|
+
range,
|
|
34179
|
+
commitSha,
|
|
34180
|
+
parentSha: parent,
|
|
34181
|
+
binaryByPath: parsed.binaryByPath
|
|
34182
|
+
});
|
|
34183
|
+
const finalRows = dedupeChangedFileRows(rows);
|
|
34184
|
+
finalRows.sort((a, b) => a.pathRelLauncher.localeCompare(b.pathRelLauncher));
|
|
34185
|
+
return finalRows;
|
|
34186
|
+
}
|
|
34187
|
+
|
|
34188
|
+
// src/git/changes/listing/apply-untracked-file-stats.ts
|
|
33848
34189
|
import * as fs17 from "node:fs";
|
|
33849
|
-
import * as
|
|
33850
|
-
|
|
33851
|
-
|
|
33852
|
-
|
|
33853
|
-
|
|
33854
|
-
|
|
33855
|
-
|
|
33856
|
-
|
|
33857
|
-
|
|
33858
|
-
|
|
33859
|
-
|
|
33860
|
-
|
|
33861
|
-
lines += 1;
|
|
33862
|
-
bytes += Buffer.byteLength(String(_line), "utf8") + 1;
|
|
33863
|
-
if (bytes > maxBytes) {
|
|
33864
|
-
rl.close();
|
|
33865
|
-
stream.destroy();
|
|
33866
|
-
return lines;
|
|
34190
|
+
import * as path20 from "node:path";
|
|
34191
|
+
function createUntrackedStatsApplier(options) {
|
|
34192
|
+
return async (row, pathInRepo) => {
|
|
34193
|
+
if (!options.untrackedSet.has(pathInRepo)) return;
|
|
34194
|
+
if (options.nameByPath.has(pathInRepo)) return;
|
|
34195
|
+
if (row.change === "moved") return;
|
|
34196
|
+
const repoFilePath = path20.join(options.repoGitCwd, pathInRepo);
|
|
34197
|
+
const fromGit = await numstatFromGitNoIndex(options.g, pathInRepo);
|
|
34198
|
+
if (fromGit) {
|
|
34199
|
+
row.additions = fromGit.additions;
|
|
34200
|
+
row.deletions = fromGit.deletions;
|
|
34201
|
+
return;
|
|
33867
34202
|
}
|
|
33868
|
-
|
|
33869
|
-
|
|
34203
|
+
try {
|
|
34204
|
+
const st = await fs17.promises.stat(repoFilePath);
|
|
34205
|
+
row.additions = st.isFile() ? await countTextFileLines(repoFilePath) : 0;
|
|
34206
|
+
} catch {
|
|
34207
|
+
row.additions = 0;
|
|
34208
|
+
}
|
|
34209
|
+
row.deletions = 0;
|
|
34210
|
+
};
|
|
33870
34211
|
}
|
|
33871
34212
|
|
|
33872
|
-
// src/git/changes/
|
|
33873
|
-
import * as
|
|
34213
|
+
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
34214
|
+
import * as path21 from "node:path";
|
|
34215
|
+
|
|
34216
|
+
// src/git/changes/patch/hydrate-patch.ts
|
|
34217
|
+
import * as fs18 from "node:fs";
|
|
33874
34218
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
33875
34219
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
33876
34220
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -33885,7 +34229,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
33885
34229
|
}
|
|
33886
34230
|
async function readWorktreeFileLines(filePath) {
|
|
33887
34231
|
try {
|
|
33888
|
-
const raw = await
|
|
34232
|
+
const raw = await fs18.promises.readFile(filePath, "utf8");
|
|
33889
34233
|
return raw.split(/\r?\n/);
|
|
33890
34234
|
} catch {
|
|
33891
34235
|
return null;
|
|
@@ -33985,82 +34329,70 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
33985
34329
|
return truncatePatch(out.join("\n"));
|
|
33986
34330
|
}
|
|
33987
34331
|
|
|
33988
|
-
// src/git/changes/
|
|
33989
|
-
function
|
|
33990
|
-
|
|
33991
|
-
|
|
33992
|
-
|
|
33993
|
-
|
|
33994
|
-
|
|
33995
|
-
|
|
33996
|
-
|
|
33997
|
-
|
|
33998
|
-
|
|
34332
|
+
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
34333
|
+
async function enrichWorkingTreeFileRows(options) {
|
|
34334
|
+
await forEachWithGitYield(options.rows, async (row) => {
|
|
34335
|
+
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
34336
|
+
const filePath = path21.join(options.repoGitCwd, pathInRepo);
|
|
34337
|
+
const hydrateKind = row.change === "moved" ? "modified" : row.change;
|
|
34338
|
+
let patch = await unifiedDiffForFile(options.repoGitCwd, pathInRepo, row.change, row.movedFromPathInRepo);
|
|
34339
|
+
if (patch) {
|
|
34340
|
+
patch = await hydrateUnifiedPatchWithFileContext(
|
|
34341
|
+
patch,
|
|
34342
|
+
filePath,
|
|
34343
|
+
options.repoGitCwd,
|
|
34344
|
+
pathInRepo,
|
|
34345
|
+
hydrateKind
|
|
34346
|
+
);
|
|
34347
|
+
}
|
|
34348
|
+
row.patchContent = patch;
|
|
34349
|
+
row.totalLines = await resolveWorkingTreeFileTotalLines({
|
|
34350
|
+
repoGitCwd: options.repoGitCwd,
|
|
34351
|
+
pathInRepo,
|
|
34352
|
+
change: row.change,
|
|
34353
|
+
isBinary: options.binaryByPath.has(pathInRepo)
|
|
34354
|
+
});
|
|
34355
|
+
});
|
|
33999
34356
|
}
|
|
34000
34357
|
|
|
34001
|
-
// src/git/changes/list-changed-files-for-repo.ts
|
|
34358
|
+
// src/git/changes/listing/list-changed-files-for-repo.ts
|
|
34002
34359
|
async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
34003
34360
|
const g = cliSimpleGit(repoGitCwd);
|
|
34004
34361
|
const [nameStatusRaw, numstatRaw, untrackedRaw] = await Promise.all([
|
|
34005
|
-
g.raw(["diff", "--name-status", "HEAD"]).catch(() => ""),
|
|
34006
|
-
g.raw(["diff", "HEAD", "--numstat"]).catch(() => ""),
|
|
34362
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", "HEAD"]).catch(() => ""),
|
|
34363
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "HEAD", "--numstat"]).catch(() => ""),
|
|
34007
34364
|
g.raw(["ls-files", "--others", "--exclude-standard"]).catch(() => "")
|
|
34008
34365
|
]);
|
|
34009
|
-
const
|
|
34010
|
-
const numByPath = parseNumstat(String(numstatRaw).split("\n"));
|
|
34011
|
-
const paths = /* @__PURE__ */ new Set([...kindByPath.keys(), ...numByPath.keys()]);
|
|
34366
|
+
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
34012
34367
|
const untracked = String(untrackedRaw).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
34013
|
-
|
|
34014
|
-
const
|
|
34015
|
-
|
|
34016
|
-
|
|
34017
|
-
|
|
34018
|
-
const nums = numByPath.get(pathInRepo);
|
|
34019
|
-
let additions = nums?.additions ?? 0;
|
|
34020
|
-
let deletions = nums?.deletions ?? 0;
|
|
34021
|
-
let change = kindByPath.get(pathInRepo) ?? "modified";
|
|
34022
|
-
if (untracked.includes(pathInRepo) && !kindByPath.has(pathInRepo)) {
|
|
34023
|
-
change = "added";
|
|
34024
|
-
const fromGit = await numstatFromGitNoIndex(g, pathInRepo);
|
|
34025
|
-
if (fromGit) {
|
|
34026
|
-
additions = fromGit.additions;
|
|
34027
|
-
deletions = fromGit.deletions;
|
|
34028
|
-
} else {
|
|
34029
|
-
try {
|
|
34030
|
-
const st = await fs17.promises.stat(repoFilePath);
|
|
34031
|
-
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
34032
|
-
else additions = 0;
|
|
34033
|
-
} catch {
|
|
34034
|
-
additions = 0;
|
|
34035
|
-
}
|
|
34036
|
-
deletions = 0;
|
|
34037
|
-
}
|
|
34038
|
-
}
|
|
34039
|
-
if (!kindByPath.has(pathInRepo) && nums) {
|
|
34040
|
-
if (additions > 0 && deletions === 0) change = "added";
|
|
34041
|
-
else if (deletions > 0 && additions === 0) change = "removed";
|
|
34042
|
-
else change = "modified";
|
|
34043
|
-
}
|
|
34044
|
-
rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
|
|
34368
|
+
const untrackedSet = new Set(untracked);
|
|
34369
|
+
const paths = collectChangedPaths({
|
|
34370
|
+
nameEntries: parsed.nameEntries,
|
|
34371
|
+
numByPath: parsed.numByPath,
|
|
34372
|
+
untracked
|
|
34045
34373
|
});
|
|
34046
|
-
|
|
34047
|
-
|
|
34048
|
-
|
|
34049
|
-
|
|
34050
|
-
|
|
34051
|
-
|
|
34052
|
-
|
|
34053
|
-
|
|
34054
|
-
|
|
34055
|
-
|
|
34056
|
-
|
|
34057
|
-
|
|
34058
|
-
|
|
34059
|
-
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
34060
|
-
}
|
|
34061
|
-
row.patchContent = patch;
|
|
34374
|
+
let rows = await buildChangedFileRowsFromPaths({
|
|
34375
|
+
paths,
|
|
34376
|
+
repoRelPath,
|
|
34377
|
+
nameByPath: parsed.nameByPath,
|
|
34378
|
+
numByPath: parsed.numByPath,
|
|
34379
|
+
movedSourcePaths: parsed.movedSourcePaths,
|
|
34380
|
+
untrackedSet,
|
|
34381
|
+
applyUntrackedStats: createUntrackedStatsApplier({
|
|
34382
|
+
g,
|
|
34383
|
+
repoGitCwd,
|
|
34384
|
+
untrackedSet,
|
|
34385
|
+
nameByPath: parsed.nameByPath
|
|
34386
|
+
})
|
|
34062
34387
|
});
|
|
34063
|
-
|
|
34388
|
+
rows = dedupeChangedFileRows(rows);
|
|
34389
|
+
await enrichWorkingTreeFileRows({
|
|
34390
|
+
rows,
|
|
34391
|
+
repoGitCwd,
|
|
34392
|
+
repoRelPath,
|
|
34393
|
+
binaryByPath: parsed.binaryByPath
|
|
34394
|
+
});
|
|
34395
|
+
return dedupeChangedFileRows(rows);
|
|
34064
34396
|
}
|
|
34065
34397
|
|
|
34066
34398
|
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
@@ -34069,8 +34401,8 @@ function normRepoRel(p) {
|
|
|
34069
34401
|
return x === "" ? "." : x;
|
|
34070
34402
|
}
|
|
34071
34403
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
34072
|
-
const bridgeRoot =
|
|
34073
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
34404
|
+
const bridgeRoot = path22.resolve(getBridgeRoot());
|
|
34405
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path22.resolve(options.sessionWorktreeRootPath) : null;
|
|
34074
34406
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
34075
34407
|
const out = [];
|
|
34076
34408
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -34085,7 +34417,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34085
34417
|
for (let i = 0; i < options.commitTargetPaths.length; i++) {
|
|
34086
34418
|
if (i > 0) await yieldToEventLoop2();
|
|
34087
34419
|
const target = options.commitTargetPaths[i];
|
|
34088
|
-
const t =
|
|
34420
|
+
const t = path22.resolve(target);
|
|
34089
34421
|
if (!await isGitRepoDirectory(t)) continue;
|
|
34090
34422
|
const g = cliSimpleGit(t);
|
|
34091
34423
|
let branch = "HEAD";
|
|
@@ -34098,8 +34430,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34098
34430
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
34099
34431
|
let repoRelPath;
|
|
34100
34432
|
if (sessionWtRoot) {
|
|
34101
|
-
const anchor = legacyNested ?
|
|
34102
|
-
const relNorm =
|
|
34433
|
+
const anchor = legacyNested ? path22.dirname(t) : t;
|
|
34434
|
+
const relNorm = path22.relative(sessionWtRoot, anchor);
|
|
34103
34435
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
34104
34436
|
} else {
|
|
34105
34437
|
let top = t;
|
|
@@ -34108,8 +34440,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34108
34440
|
} catch {
|
|
34109
34441
|
top = t;
|
|
34110
34442
|
}
|
|
34111
|
-
const rel =
|
|
34112
|
-
repoRelPath = rel.startsWith("..") ?
|
|
34443
|
+
const rel = path22.relative(bridgeRoot, path22.resolve(top)).replace(/\\/g, "/") || ".";
|
|
34444
|
+
repoRelPath = rel.startsWith("..") ? path22.basename(path22.resolve(top)) : rel;
|
|
34113
34445
|
}
|
|
34114
34446
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
34115
34447
|
if (filter && norm !== filter) continue;
|
|
@@ -34141,7 +34473,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34141
34473
|
return out;
|
|
34142
34474
|
}
|
|
34143
34475
|
|
|
34144
|
-
// src/git/changes/
|
|
34476
|
+
// src/git/changes/status/working-tree-changed-path-count.ts
|
|
34145
34477
|
function workingTreeChangedPathCount(nameStatusLines, numstatLines, untrackedLines) {
|
|
34146
34478
|
const kindByPath = parseNameStatusLines(nameStatusLines);
|
|
34147
34479
|
const numByPath = parseNumstat(numstatLines);
|
|
@@ -34237,23 +34569,23 @@ async function commitSessionWorktrees(options) {
|
|
|
34237
34569
|
}
|
|
34238
34570
|
|
|
34239
34571
|
// src/worktrees/remove-session-worktrees.ts
|
|
34240
|
-
import * as
|
|
34572
|
+
import * as fs21 from "node:fs";
|
|
34241
34573
|
|
|
34242
34574
|
// src/git/worktrees/worktree-remove.ts
|
|
34243
|
-
import * as
|
|
34575
|
+
import * as fs20 from "node:fs";
|
|
34244
34576
|
|
|
34245
34577
|
// src/git/worktrees/resolve-main-repo-from-git-file.ts
|
|
34246
|
-
import * as
|
|
34247
|
-
import * as
|
|
34578
|
+
import * as fs19 from "node:fs";
|
|
34579
|
+
import * as path23 from "node:path";
|
|
34248
34580
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
34249
|
-
const gitDirFile =
|
|
34250
|
-
if (!
|
|
34251
|
-
const first2 =
|
|
34581
|
+
const gitDirFile = path23.join(wt, ".git");
|
|
34582
|
+
if (!fs19.existsSync(gitDirFile) || !fs19.statSync(gitDirFile).isFile()) return "";
|
|
34583
|
+
const first2 = fs19.readFileSync(gitDirFile, "utf8").trim();
|
|
34252
34584
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
34253
34585
|
if (!m) return "";
|
|
34254
|
-
const gitWorktreePath =
|
|
34255
|
-
const gitDir =
|
|
34256
|
-
return
|
|
34586
|
+
const gitWorktreePath = path23.resolve(wt, m[1].trim());
|
|
34587
|
+
const gitDir = path23.dirname(path23.dirname(gitWorktreePath));
|
|
34588
|
+
return path23.dirname(gitDir);
|
|
34257
34589
|
}
|
|
34258
34590
|
|
|
34259
34591
|
// src/git/worktrees/worktree-remove.ts
|
|
@@ -34262,7 +34594,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
34262
34594
|
if (mainRepo) {
|
|
34263
34595
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
34264
34596
|
} else {
|
|
34265
|
-
|
|
34597
|
+
fs20.rmSync(worktreePath, { recursive: true, force: true });
|
|
34266
34598
|
}
|
|
34267
34599
|
}
|
|
34268
34600
|
|
|
@@ -34275,7 +34607,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
34275
34607
|
} catch (e) {
|
|
34276
34608
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
34277
34609
|
try {
|
|
34278
|
-
|
|
34610
|
+
fs21.rmSync(wt, { recursive: true, force: true });
|
|
34279
34611
|
} catch {
|
|
34280
34612
|
}
|
|
34281
34613
|
}
|
|
@@ -34304,12 +34636,12 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
34304
34636
|
}
|
|
34305
34637
|
|
|
34306
34638
|
// src/worktrees/worktree-layout-file.ts
|
|
34307
|
-
import * as
|
|
34308
|
-
import * as
|
|
34639
|
+
import * as fs22 from "node:fs";
|
|
34640
|
+
import * as path24 from "node:path";
|
|
34309
34641
|
import os7 from "node:os";
|
|
34310
34642
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
34311
34643
|
function defaultWorktreeLayoutPath() {
|
|
34312
|
-
return
|
|
34644
|
+
return path24.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
34313
34645
|
}
|
|
34314
34646
|
function normalizeLoadedLayout(raw) {
|
|
34315
34647
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -34321,8 +34653,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
34321
34653
|
function loadWorktreeLayout() {
|
|
34322
34654
|
try {
|
|
34323
34655
|
const p = defaultWorktreeLayoutPath();
|
|
34324
|
-
if (!
|
|
34325
|
-
const raw = JSON.parse(
|
|
34656
|
+
if (!fs22.existsSync(p)) return { launcherCwds: [] };
|
|
34657
|
+
const raw = JSON.parse(fs22.readFileSync(p, "utf8"));
|
|
34326
34658
|
return normalizeLoadedLayout(raw);
|
|
34327
34659
|
} catch {
|
|
34328
34660
|
return { launcherCwds: [] };
|
|
@@ -34330,24 +34662,24 @@ function loadWorktreeLayout() {
|
|
|
34330
34662
|
}
|
|
34331
34663
|
function saveWorktreeLayout(layout) {
|
|
34332
34664
|
try {
|
|
34333
|
-
const dir =
|
|
34334
|
-
|
|
34335
|
-
|
|
34665
|
+
const dir = path24.dirname(defaultWorktreeLayoutPath());
|
|
34666
|
+
fs22.mkdirSync(dir, { recursive: true });
|
|
34667
|
+
fs22.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
34336
34668
|
} catch {
|
|
34337
34669
|
}
|
|
34338
34670
|
}
|
|
34339
34671
|
function baseNameSafe(pathString) {
|
|
34340
|
-
return
|
|
34672
|
+
return path24.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
34341
34673
|
}
|
|
34342
34674
|
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
34343
|
-
const norm =
|
|
34344
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
34675
|
+
const norm = path24.resolve(bridgeRootPath2);
|
|
34676
|
+
const existing = layout.launcherCwds.find((e) => path24.resolve(e.absolutePath) === norm);
|
|
34345
34677
|
return existing?.dirName;
|
|
34346
34678
|
}
|
|
34347
34679
|
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
34348
34680
|
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
34349
34681
|
if (existing) return existing;
|
|
34350
|
-
const norm =
|
|
34682
|
+
const norm = path24.resolve(bridgeRootPath2);
|
|
34351
34683
|
const base = baseNameSafe(norm);
|
|
34352
34684
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
34353
34685
|
let name = base;
|
|
@@ -34362,11 +34694,11 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
|
34362
34694
|
}
|
|
34363
34695
|
|
|
34364
34696
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
34365
|
-
import * as
|
|
34366
|
-
import * as
|
|
34697
|
+
import * as fs23 from "node:fs";
|
|
34698
|
+
import * as path25 from "node:path";
|
|
34367
34699
|
function isGitDir(dirPath) {
|
|
34368
34700
|
try {
|
|
34369
|
-
return
|
|
34701
|
+
return fs23.existsSync(path25.join(dirPath, ".git"));
|
|
34370
34702
|
} catch {
|
|
34371
34703
|
return false;
|
|
34372
34704
|
}
|
|
@@ -34375,23 +34707,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
34375
34707
|
const out = [];
|
|
34376
34708
|
const walk = (dir) => {
|
|
34377
34709
|
if (isGitDir(dir)) {
|
|
34378
|
-
out.push(
|
|
34710
|
+
out.push(path25.resolve(dir));
|
|
34379
34711
|
return;
|
|
34380
34712
|
}
|
|
34381
34713
|
let entries;
|
|
34382
34714
|
try {
|
|
34383
|
-
entries =
|
|
34715
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
34384
34716
|
} catch {
|
|
34385
34717
|
return;
|
|
34386
34718
|
}
|
|
34387
34719
|
for (const e of entries) {
|
|
34388
34720
|
if (e.name.startsWith(".")) continue;
|
|
34389
|
-
const full =
|
|
34721
|
+
const full = path25.join(dir, e.name);
|
|
34390
34722
|
if (!e.isDirectory()) continue;
|
|
34391
34723
|
walk(full);
|
|
34392
34724
|
}
|
|
34393
34725
|
};
|
|
34394
|
-
walk(
|
|
34726
|
+
walk(path25.resolve(rootPath));
|
|
34395
34727
|
return [...new Set(out)];
|
|
34396
34728
|
}
|
|
34397
34729
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -34400,16 +34732,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
34400
34732
|
if (depth > maxDepth) return;
|
|
34401
34733
|
let entries;
|
|
34402
34734
|
try {
|
|
34403
|
-
entries =
|
|
34735
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
34404
34736
|
} catch {
|
|
34405
34737
|
return;
|
|
34406
34738
|
}
|
|
34407
34739
|
for (const e of entries) {
|
|
34408
34740
|
if (e.name.startsWith(".")) continue;
|
|
34409
|
-
const full =
|
|
34741
|
+
const full = path25.join(dir, e.name);
|
|
34410
34742
|
if (!e.isDirectory()) continue;
|
|
34411
34743
|
if (e.name === sessionId) {
|
|
34412
|
-
if (isGitDir(full)) out.push(
|
|
34744
|
+
if (isGitDir(full)) out.push(path25.resolve(full));
|
|
34413
34745
|
} else {
|
|
34414
34746
|
walk(full, depth + 1);
|
|
34415
34747
|
}
|
|
@@ -34421,14 +34753,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
34421
34753
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
34422
34754
|
let st;
|
|
34423
34755
|
try {
|
|
34424
|
-
st =
|
|
34756
|
+
st = fs23.statSync(sessionDir);
|
|
34425
34757
|
} catch {
|
|
34426
34758
|
return null;
|
|
34427
34759
|
}
|
|
34428
34760
|
if (!st.isDirectory()) return null;
|
|
34429
34761
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
34430
34762
|
if (worktreePaths.length === 0) return null;
|
|
34431
|
-
const abs =
|
|
34763
|
+
const abs = path25.resolve(sessionDir);
|
|
34432
34764
|
return {
|
|
34433
34765
|
sessionParentPath: abs,
|
|
34434
34766
|
workingTreeRelRoot: abs,
|
|
@@ -34438,20 +34770,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
34438
34770
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
34439
34771
|
const sid = sessionId.trim();
|
|
34440
34772
|
if (!sid) return null;
|
|
34441
|
-
const hintR =
|
|
34773
|
+
const hintR = path25.resolve(checkoutPath);
|
|
34442
34774
|
let best = null;
|
|
34443
|
-
let cur =
|
|
34775
|
+
let cur = path25.dirname(hintR);
|
|
34444
34776
|
for (let i = 0; i < 40; i++) {
|
|
34445
34777
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
34446
|
-
if (paths.some((p) =>
|
|
34447
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
34778
|
+
if (paths.some((p) => path25.resolve(p) === hintR)) {
|
|
34779
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path25.resolve(paths[0]);
|
|
34448
34780
|
best = {
|
|
34449
|
-
sessionParentPath:
|
|
34450
|
-
workingTreeRelRoot:
|
|
34451
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
34781
|
+
sessionParentPath: path25.resolve(isolated),
|
|
34782
|
+
workingTreeRelRoot: path25.resolve(cur),
|
|
34783
|
+
repoCheckoutPaths: paths.map((p) => path25.resolve(p))
|
|
34452
34784
|
};
|
|
34453
34785
|
}
|
|
34454
|
-
const next =
|
|
34786
|
+
const next = path25.dirname(cur);
|
|
34455
34787
|
if (next === cur) break;
|
|
34456
34788
|
cur = next;
|
|
34457
34789
|
}
|
|
@@ -34459,33 +34791,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
34459
34791
|
}
|
|
34460
34792
|
function discoverSessionWorktreeOnDisk(options) {
|
|
34461
34793
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
34462
|
-
if (!sessionId.trim() || !
|
|
34794
|
+
if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
|
|
34463
34795
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
34464
34796
|
const keys = [];
|
|
34465
34797
|
if (preferredKey) keys.push(preferredKey);
|
|
34466
34798
|
try {
|
|
34467
|
-
for (const name of
|
|
34799
|
+
for (const name of fs23.readdirSync(worktreesRootPath)) {
|
|
34468
34800
|
if (name.startsWith(".")) continue;
|
|
34469
|
-
const p =
|
|
34470
|
-
if (!
|
|
34801
|
+
const p = path25.join(worktreesRootPath, name);
|
|
34802
|
+
if (!fs23.statSync(p).isDirectory()) continue;
|
|
34471
34803
|
if (name !== preferredKey) keys.push(name);
|
|
34472
34804
|
}
|
|
34473
34805
|
} catch {
|
|
34474
34806
|
return null;
|
|
34475
34807
|
}
|
|
34476
34808
|
for (const key of keys) {
|
|
34477
|
-
const layoutRoot =
|
|
34478
|
-
if (!
|
|
34479
|
-
const sessionDir =
|
|
34809
|
+
const layoutRoot = path25.join(worktreesRootPath, key);
|
|
34810
|
+
if (!fs23.existsSync(layoutRoot) || !fs23.statSync(layoutRoot).isDirectory()) continue;
|
|
34811
|
+
const sessionDir = path25.join(layoutRoot, sessionId);
|
|
34480
34812
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
34481
34813
|
if (nested) return nested;
|
|
34482
34814
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
34483
34815
|
if (legacyPaths.length > 0) {
|
|
34484
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
34816
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
34485
34817
|
return {
|
|
34486
|
-
sessionParentPath:
|
|
34487
|
-
workingTreeRelRoot:
|
|
34488
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
34818
|
+
sessionParentPath: path25.resolve(isolated),
|
|
34819
|
+
workingTreeRelRoot: path25.resolve(layoutRoot),
|
|
34820
|
+
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
34489
34821
|
};
|
|
34490
34822
|
}
|
|
34491
34823
|
}
|
|
@@ -34494,12 +34826,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
34494
34826
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
34495
34827
|
const sid = sessionId.trim();
|
|
34496
34828
|
if (!sid) return null;
|
|
34497
|
-
const hint =
|
|
34498
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
34829
|
+
const hint = path25.resolve(sessionWorktreeRootPathOrHint);
|
|
34830
|
+
const underHint = tryBindingFromSessionDirectory(path25.join(hint, sid));
|
|
34499
34831
|
if (underHint) return underHint;
|
|
34500
34832
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
34501
34833
|
if (direct) {
|
|
34502
|
-
if (
|
|
34834
|
+
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
34503
34835
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34504
34836
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
34505
34837
|
return legacyFromCheckout;
|
|
@@ -34507,24 +34839,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
34507
34839
|
}
|
|
34508
34840
|
return direct;
|
|
34509
34841
|
}
|
|
34510
|
-
if (
|
|
34842
|
+
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
34511
34843
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34512
34844
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
34513
34845
|
}
|
|
34514
34846
|
let st;
|
|
34515
34847
|
try {
|
|
34516
|
-
st =
|
|
34848
|
+
st = fs23.statSync(hint);
|
|
34517
34849
|
} catch {
|
|
34518
34850
|
return null;
|
|
34519
34851
|
}
|
|
34520
34852
|
if (!st.isDirectory()) return null;
|
|
34521
34853
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
34522
34854
|
if (legacyPaths.length === 0) return null;
|
|
34523
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
34855
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
34524
34856
|
return {
|
|
34525
|
-
sessionParentPath:
|
|
34857
|
+
sessionParentPath: path25.resolve(isolated),
|
|
34526
34858
|
workingTreeRelRoot: hint,
|
|
34527
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
34859
|
+
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
34528
34860
|
};
|
|
34529
34861
|
}
|
|
34530
34862
|
|
|
@@ -34581,8 +34913,8 @@ function parseSessionParent(v) {
|
|
|
34581
34913
|
}
|
|
34582
34914
|
|
|
34583
34915
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34584
|
-
import * as
|
|
34585
|
-
import * as
|
|
34916
|
+
import * as fs24 from "node:fs";
|
|
34917
|
+
import * as path26 from "node:path";
|
|
34586
34918
|
|
|
34587
34919
|
// src/git/worktrees/worktree-add.ts
|
|
34588
34920
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
@@ -34592,7 +34924,7 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef
|
|
|
34592
34924
|
}
|
|
34593
34925
|
|
|
34594
34926
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34595
|
-
function
|
|
34927
|
+
function normalizeRepoRelPath2(rel) {
|
|
34596
34928
|
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
34597
34929
|
}
|
|
34598
34930
|
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
@@ -34604,10 +34936,10 @@ function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
|
34604
34936
|
}
|
|
34605
34937
|
async function prepareNewSessionWorktrees(options) {
|
|
34606
34938
|
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
|
|
34607
|
-
const bridgeResolved =
|
|
34939
|
+
const bridgeResolved = path26.resolve(bridgeRoot);
|
|
34608
34940
|
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
34609
|
-
const bridgeKeyDir =
|
|
34610
|
-
const sessionDir =
|
|
34941
|
+
const bridgeKeyDir = path26.join(worktreesRootPath, cwdKey);
|
|
34942
|
+
const sessionDir = path26.join(bridgeKeyDir, sessionId);
|
|
34611
34943
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
34612
34944
|
if (repos.length === 0) {
|
|
34613
34945
|
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
@@ -34615,14 +34947,14 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
34615
34947
|
}
|
|
34616
34948
|
const branch = `session-${sessionId}`;
|
|
34617
34949
|
const worktreePaths = [];
|
|
34618
|
-
|
|
34950
|
+
fs24.mkdirSync(sessionDir, { recursive: true });
|
|
34619
34951
|
for (const repo of repos) {
|
|
34620
|
-
let rel =
|
|
34621
|
-
if (rel.startsWith("..") ||
|
|
34622
|
-
const relNorm =
|
|
34623
|
-
const wtPath = relNorm === "." ? sessionDir :
|
|
34952
|
+
let rel = path26.relative(bridgeResolved, repo.absolutePath);
|
|
34953
|
+
if (rel.startsWith("..") || path26.isAbsolute(rel)) continue;
|
|
34954
|
+
const relNorm = normalizeRepoRelPath2(rel === "" ? "." : rel);
|
|
34955
|
+
const wtPath = relNorm === "." ? sessionDir : path26.join(sessionDir, relNorm);
|
|
34624
34956
|
if (relNorm !== ".") {
|
|
34625
|
-
|
|
34957
|
+
fs24.mkdirSync(path26.dirname(wtPath), { recursive: true });
|
|
34626
34958
|
}
|
|
34627
34959
|
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
34628
34960
|
try {
|
|
@@ -34675,9 +35007,9 @@ function resolveExistingSessionParentPath(sessionId, cache2, discover) {
|
|
|
34675
35007
|
}
|
|
34676
35008
|
|
|
34677
35009
|
// src/worktrees/manager/resolve-explicit-session-parent-path.ts
|
|
34678
|
-
import * as
|
|
35010
|
+
import * as path27 from "node:path";
|
|
34679
35011
|
function resolveExplicitSessionParentPath(params) {
|
|
34680
|
-
const resolved =
|
|
35012
|
+
const resolved = path27.resolve(params.parentPathRaw);
|
|
34681
35013
|
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
34682
35014
|
return resolved;
|
|
34683
35015
|
}
|
|
@@ -34693,7 +35025,7 @@ function resolveExplicitSessionParentPath(params) {
|
|
|
34693
35025
|
for (let i = 0; i < 16; i++) {
|
|
34694
35026
|
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
34695
35027
|
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
34696
|
-
const next =
|
|
35028
|
+
const next = path27.dirname(cur);
|
|
34697
35029
|
if (next === cur) break;
|
|
34698
35030
|
cur = next;
|
|
34699
35031
|
}
|
|
@@ -34745,16 +35077,16 @@ async function resolveSessionParentPathForPrompt(params) {
|
|
|
34745
35077
|
}
|
|
34746
35078
|
|
|
34747
35079
|
// src/worktrees/manager/session-worktree-cache.ts
|
|
34748
|
-
import * as
|
|
35080
|
+
import * as path28 from "node:path";
|
|
34749
35081
|
var SessionWorktreeCache = class {
|
|
34750
35082
|
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
34751
35083
|
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
34752
35084
|
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
34753
35085
|
remember(sessionId, binding) {
|
|
34754
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
35086
|
+
const paths = binding.repoCheckoutPaths.map((p) => path28.resolve(p));
|
|
34755
35087
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
34756
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
34757
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
35088
|
+
this.sessionParentPathBySession.set(sessionId, path28.resolve(binding.sessionParentPath));
|
|
35089
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path28.resolve(binding.workingTreeRelRoot));
|
|
34758
35090
|
}
|
|
34759
35091
|
clearSession(sessionId) {
|
|
34760
35092
|
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
@@ -34784,7 +35116,7 @@ var SessionWorktreeCache = class {
|
|
|
34784
35116
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
34785
35117
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
34786
35118
|
if (!parent || !relRoot) return false;
|
|
34787
|
-
return
|
|
35119
|
+
return path28.resolve(parent) !== path28.resolve(relRoot);
|
|
34788
35120
|
}
|
|
34789
35121
|
};
|
|
34790
35122
|
|
|
@@ -34888,29 +35220,29 @@ var SessionWorktreeManager = class {
|
|
|
34888
35220
|
};
|
|
34889
35221
|
|
|
34890
35222
|
// src/worktrees/manager/default-worktrees-root-path.ts
|
|
34891
|
-
import * as
|
|
35223
|
+
import * as path29 from "node:path";
|
|
34892
35224
|
import os8 from "node:os";
|
|
34893
35225
|
function defaultWorktreesRootPath() {
|
|
34894
|
-
return
|
|
35226
|
+
return path29.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
34895
35227
|
}
|
|
34896
35228
|
|
|
34897
35229
|
// src/files/watch-file-index.ts
|
|
34898
35230
|
import { watch } from "node:fs";
|
|
34899
|
-
import
|
|
35231
|
+
import path34 from "node:path";
|
|
34900
35232
|
|
|
34901
35233
|
// src/files/index/paths.ts
|
|
34902
|
-
import
|
|
35234
|
+
import path30 from "node:path";
|
|
34903
35235
|
import crypto2 from "node:crypto";
|
|
34904
35236
|
function getCwdHashForFileIndex(resolvedCwd) {
|
|
34905
|
-
return crypto2.createHash("sha256").update(
|
|
35237
|
+
return crypto2.createHash("sha256").update(path30.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
34906
35238
|
}
|
|
34907
35239
|
|
|
34908
35240
|
// src/files/index/build-file-index.ts
|
|
34909
|
-
import
|
|
35241
|
+
import path32 from "node:path";
|
|
34910
35242
|
|
|
34911
35243
|
// src/files/index/walk-workspace-tree.ts
|
|
34912
|
-
import
|
|
34913
|
-
import
|
|
35244
|
+
import fs25 from "node:fs";
|
|
35245
|
+
import path31 from "node:path";
|
|
34914
35246
|
var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
34915
35247
|
"node_modules",
|
|
34916
35248
|
"bower_components",
|
|
@@ -34927,7 +35259,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
|
|
|
34927
35259
|
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
34928
35260
|
let names;
|
|
34929
35261
|
try {
|
|
34930
|
-
names = await
|
|
35262
|
+
names = await fs25.promises.readdir(dir);
|
|
34931
35263
|
} catch {
|
|
34932
35264
|
return;
|
|
34933
35265
|
}
|
|
@@ -34939,14 +35271,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
|
34939
35271
|
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
34940
35272
|
}
|
|
34941
35273
|
state.n++;
|
|
34942
|
-
const full =
|
|
35274
|
+
const full = path31.join(dir, name);
|
|
34943
35275
|
let stat2;
|
|
34944
35276
|
try {
|
|
34945
|
-
stat2 = await
|
|
35277
|
+
stat2 = await fs25.promises.stat(full);
|
|
34946
35278
|
} catch {
|
|
34947
35279
|
continue;
|
|
34948
35280
|
}
|
|
34949
|
-
const relative6 =
|
|
35281
|
+
const relative6 = path31.relative(baseDir, full).replace(/\\/g, "/");
|
|
34950
35282
|
if (stat2.isDirectory()) {
|
|
34951
35283
|
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
34952
35284
|
} else if (stat2.isFile()) {
|
|
@@ -34959,7 +35291,7 @@ function createWalkYieldState() {
|
|
|
34959
35291
|
}
|
|
34960
35292
|
|
|
34961
35293
|
// src/files/index/file-index-sqlite-lock.ts
|
|
34962
|
-
import
|
|
35294
|
+
import fs26 from "node:fs";
|
|
34963
35295
|
function isSqliteCorruptError(e) {
|
|
34964
35296
|
const msg = e instanceof Error ? e.message : String(e);
|
|
34965
35297
|
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
@@ -34973,7 +35305,7 @@ function withFileIndexSqliteLock(fn) {
|
|
|
34973
35305
|
if (!isSqliteCorruptError(e)) throw e;
|
|
34974
35306
|
closeAllCliSqliteConnections();
|
|
34975
35307
|
try {
|
|
34976
|
-
|
|
35308
|
+
fs26.unlinkSync(getCliSqlitePath());
|
|
34977
35309
|
} catch {
|
|
34978
35310
|
}
|
|
34979
35311
|
chain = Promise.resolve();
|
|
@@ -35048,7 +35380,7 @@ async function collectWorkspacePathsAsync(resolved) {
|
|
|
35048
35380
|
}
|
|
35049
35381
|
async function buildFileIndexAsync(cwd) {
|
|
35050
35382
|
return withFileIndexSqliteLock(async () => {
|
|
35051
|
-
const resolved =
|
|
35383
|
+
const resolved = path32.resolve(cwd);
|
|
35052
35384
|
await yieldToEventLoop();
|
|
35053
35385
|
assertNotShutdown();
|
|
35054
35386
|
const paths = await collectWorkspacePathsAsync(resolved);
|
|
@@ -35060,7 +35392,7 @@ async function buildFileIndexAsync(cwd) {
|
|
|
35060
35392
|
}
|
|
35061
35393
|
|
|
35062
35394
|
// src/files/index/ensure-file-index.ts
|
|
35063
|
-
import
|
|
35395
|
+
import path33 from "node:path";
|
|
35064
35396
|
|
|
35065
35397
|
// src/files/index/search-file-index.ts
|
|
35066
35398
|
function escapeLikePattern(fragment) {
|
|
@@ -35112,7 +35444,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
|
35112
35444
|
|
|
35113
35445
|
// src/files/index/ensure-file-index.ts
|
|
35114
35446
|
async function ensureFileIndexAsync(cwd) {
|
|
35115
|
-
const resolved =
|
|
35447
|
+
const resolved = path33.resolve(cwd);
|
|
35116
35448
|
if (await bridgeFileIndexIsPopulated(resolved)) {
|
|
35117
35449
|
return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
|
|
35118
35450
|
}
|
|
@@ -35156,7 +35488,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
35156
35488
|
}
|
|
35157
35489
|
}
|
|
35158
35490
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
35159
|
-
const resolved =
|
|
35491
|
+
const resolved = path34.resolve(cwd);
|
|
35160
35492
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
35161
35493
|
if (e instanceof CliSqliteInterrupted) return;
|
|
35162
35494
|
console.error("[file-index] Initial index build failed:", e);
|
|
@@ -35186,7 +35518,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
35186
35518
|
}
|
|
35187
35519
|
|
|
35188
35520
|
// src/connection/create-bridge-connection.ts
|
|
35189
|
-
import * as
|
|
35521
|
+
import * as path45 from "node:path";
|
|
35190
35522
|
|
|
35191
35523
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
35192
35524
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -35230,7 +35562,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
35230
35562
|
}
|
|
35231
35563
|
|
|
35232
35564
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
35233
|
-
import
|
|
35565
|
+
import fs27 from "node:fs";
|
|
35234
35566
|
|
|
35235
35567
|
// src/dev-servers/manager/forward-pipe.ts
|
|
35236
35568
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -35266,7 +35598,7 @@ function wireDevServerChildProcess(d) {
|
|
|
35266
35598
|
d.setPollInterval(void 0);
|
|
35267
35599
|
return;
|
|
35268
35600
|
}
|
|
35269
|
-
|
|
35601
|
+
fs27.readFile(d.mergedLogPath, (err, buf) => {
|
|
35270
35602
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
35271
35603
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
35272
35604
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -35304,7 +35636,7 @@ ${errTail}` : ""}`);
|
|
|
35304
35636
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
35305
35637
|
};
|
|
35306
35638
|
if (mergedPath) {
|
|
35307
|
-
|
|
35639
|
+
fs27.readFile(mergedPath, (err, buf) => {
|
|
35308
35640
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
35309
35641
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
35310
35642
|
if (chunk.length > 0) {
|
|
@@ -35406,13 +35738,13 @@ function parseDevServerDefs(servers) {
|
|
|
35406
35738
|
}
|
|
35407
35739
|
|
|
35408
35740
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
35409
|
-
import
|
|
35741
|
+
import fs28 from "node:fs";
|
|
35410
35742
|
function isSpawnEbadf(e) {
|
|
35411
35743
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
35412
35744
|
}
|
|
35413
35745
|
function rmDirQuiet(dir) {
|
|
35414
35746
|
try {
|
|
35415
|
-
|
|
35747
|
+
fs28.rmSync(dir, { recursive: true, force: true });
|
|
35416
35748
|
} catch {
|
|
35417
35749
|
}
|
|
35418
35750
|
}
|
|
@@ -35420,7 +35752,7 @@ var cachedDevNullReadFd;
|
|
|
35420
35752
|
function devNullReadFd() {
|
|
35421
35753
|
if (cachedDevNullReadFd === void 0) {
|
|
35422
35754
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
35423
|
-
cachedDevNullReadFd =
|
|
35755
|
+
cachedDevNullReadFd = fs28.openSync(devPath, "r");
|
|
35424
35756
|
}
|
|
35425
35757
|
return cachedDevNullReadFd;
|
|
35426
35758
|
}
|
|
@@ -35494,15 +35826,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
35494
35826
|
|
|
35495
35827
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
35496
35828
|
import { spawn as spawn8 } from "node:child_process";
|
|
35497
|
-
import
|
|
35829
|
+
import fs29 from "node:fs";
|
|
35498
35830
|
import { tmpdir } from "node:os";
|
|
35499
|
-
import
|
|
35831
|
+
import path35 from "node:path";
|
|
35500
35832
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
35501
|
-
const tmpRoot =
|
|
35502
|
-
const logPath =
|
|
35833
|
+
const tmpRoot = fs29.mkdtempSync(path35.join(tmpdir(), "ba-devsrv-log-"));
|
|
35834
|
+
const logPath = path35.join(tmpRoot, "combined.log");
|
|
35503
35835
|
let logFd;
|
|
35504
35836
|
try {
|
|
35505
|
-
logFd =
|
|
35837
|
+
logFd = fs29.openSync(logPath, "a");
|
|
35506
35838
|
} catch {
|
|
35507
35839
|
rmDirQuiet(tmpRoot);
|
|
35508
35840
|
return null;
|
|
@@ -35521,7 +35853,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35521
35853
|
} else {
|
|
35522
35854
|
proc = spawn8("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
35523
35855
|
}
|
|
35524
|
-
|
|
35856
|
+
fs29.closeSync(logFd);
|
|
35525
35857
|
return {
|
|
35526
35858
|
proc,
|
|
35527
35859
|
pipedStdoutStderr: true,
|
|
@@ -35530,7 +35862,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35530
35862
|
};
|
|
35531
35863
|
} catch (e) {
|
|
35532
35864
|
try {
|
|
35533
|
-
|
|
35865
|
+
fs29.closeSync(logFd);
|
|
35534
35866
|
} catch {
|
|
35535
35867
|
}
|
|
35536
35868
|
rmDirQuiet(tmpRoot);
|
|
@@ -35541,22 +35873,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35541
35873
|
|
|
35542
35874
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
35543
35875
|
import { spawn as spawn9 } from "node:child_process";
|
|
35544
|
-
import
|
|
35876
|
+
import fs30 from "node:fs";
|
|
35545
35877
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
35546
|
-
import
|
|
35878
|
+
import path36 from "node:path";
|
|
35547
35879
|
function shSingleQuote(s) {
|
|
35548
35880
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
35549
35881
|
}
|
|
35550
35882
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
35551
|
-
const tmpRoot =
|
|
35552
|
-
const logPath =
|
|
35553
|
-
const innerPath =
|
|
35554
|
-
const runnerPath =
|
|
35883
|
+
const tmpRoot = fs30.mkdtempSync(path36.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
35884
|
+
const logPath = path36.join(tmpRoot, "combined.log");
|
|
35885
|
+
const innerPath = path36.join(tmpRoot, "_cmd.sh");
|
|
35886
|
+
const runnerPath = path36.join(tmpRoot, "_run.sh");
|
|
35555
35887
|
try {
|
|
35556
|
-
|
|
35888
|
+
fs30.writeFileSync(innerPath, `#!/bin/sh
|
|
35557
35889
|
${command}
|
|
35558
35890
|
`);
|
|
35559
|
-
|
|
35891
|
+
fs30.writeFileSync(
|
|
35560
35892
|
runnerPath,
|
|
35561
35893
|
`#!/bin/sh
|
|
35562
35894
|
cd ${shSingleQuote(cwd)}
|
|
@@ -35582,13 +35914,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
35582
35914
|
}
|
|
35583
35915
|
}
|
|
35584
35916
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
35585
|
-
const tmpRoot =
|
|
35586
|
-
const logPath =
|
|
35587
|
-
const runnerPath =
|
|
35917
|
+
const tmpRoot = fs30.mkdtempSync(path36.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
35918
|
+
const logPath = path36.join(tmpRoot, "combined.log");
|
|
35919
|
+
const runnerPath = path36.join(tmpRoot, "_run.bat");
|
|
35588
35920
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
35589
35921
|
const com = process.env.ComSpec || "cmd.exe";
|
|
35590
35922
|
try {
|
|
35591
|
-
|
|
35923
|
+
fs30.writeFileSync(
|
|
35592
35924
|
runnerPath,
|
|
35593
35925
|
`@ECHO OFF\r
|
|
35594
35926
|
CD /D ${q(cwd)}\r
|
|
@@ -36357,30 +36689,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
36357
36689
|
}
|
|
36358
36690
|
|
|
36359
36691
|
// src/skills/discover-local-agent-skills.ts
|
|
36360
|
-
import
|
|
36361
|
-
import
|
|
36692
|
+
import fs31 from "node:fs";
|
|
36693
|
+
import path37 from "node:path";
|
|
36362
36694
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
36363
36695
|
function discoverLocalSkills(cwd) {
|
|
36364
36696
|
const out = [];
|
|
36365
36697
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
36366
36698
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
36367
|
-
const base =
|
|
36368
|
-
if (!
|
|
36699
|
+
const base = path37.join(cwd, rel);
|
|
36700
|
+
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
36369
36701
|
let entries = [];
|
|
36370
36702
|
try {
|
|
36371
|
-
entries =
|
|
36703
|
+
entries = fs31.readdirSync(base);
|
|
36372
36704
|
} catch {
|
|
36373
36705
|
continue;
|
|
36374
36706
|
}
|
|
36375
36707
|
for (const name of entries) {
|
|
36376
|
-
const dir =
|
|
36708
|
+
const dir = path37.join(base, name);
|
|
36377
36709
|
try {
|
|
36378
|
-
if (!
|
|
36710
|
+
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
36379
36711
|
} catch {
|
|
36380
36712
|
continue;
|
|
36381
36713
|
}
|
|
36382
|
-
const skillMd =
|
|
36383
|
-
if (!
|
|
36714
|
+
const skillMd = path37.join(dir, "SKILL.md");
|
|
36715
|
+
if (!fs31.existsSync(skillMd)) continue;
|
|
36384
36716
|
const key = `${rel}/${name}`;
|
|
36385
36717
|
if (seenKeys.has(key)) continue;
|
|
36386
36718
|
seenKeys.add(key);
|
|
@@ -36392,23 +36724,23 @@ function discoverLocalSkills(cwd) {
|
|
|
36392
36724
|
function discoverSkillLayoutRoots(cwd) {
|
|
36393
36725
|
const roots = [];
|
|
36394
36726
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
36395
|
-
const base =
|
|
36396
|
-
if (!
|
|
36727
|
+
const base = path37.join(cwd, rel);
|
|
36728
|
+
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
36397
36729
|
let entries = [];
|
|
36398
36730
|
try {
|
|
36399
|
-
entries =
|
|
36731
|
+
entries = fs31.readdirSync(base);
|
|
36400
36732
|
} catch {
|
|
36401
36733
|
continue;
|
|
36402
36734
|
}
|
|
36403
36735
|
const skills2 = [];
|
|
36404
36736
|
for (const name of entries) {
|
|
36405
|
-
const dir =
|
|
36737
|
+
const dir = path37.join(base, name);
|
|
36406
36738
|
try {
|
|
36407
|
-
if (!
|
|
36739
|
+
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
36408
36740
|
} catch {
|
|
36409
36741
|
continue;
|
|
36410
36742
|
}
|
|
36411
|
-
if (!
|
|
36743
|
+
if (!fs31.existsSync(path37.join(dir, "SKILL.md"))) continue;
|
|
36412
36744
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
36413
36745
|
skills2.push({ name, relPath });
|
|
36414
36746
|
}
|
|
@@ -36764,7 +37096,7 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
|
|
|
36764
37096
|
}
|
|
36765
37097
|
|
|
36766
37098
|
// src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
|
|
36767
|
-
import
|
|
37099
|
+
import fs32 from "node:fs";
|
|
36768
37100
|
async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
36769
37101
|
if (next.serverState !== "requeued_with_revert") return true;
|
|
36770
37102
|
const sid = next.sessionId;
|
|
@@ -36773,7 +37105,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
36773
37105
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
36774
37106
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
36775
37107
|
try {
|
|
36776
|
-
await
|
|
37108
|
+
await fs32.promises.access(file2, fs32.constants.F_OK);
|
|
36777
37109
|
} catch {
|
|
36778
37110
|
deps.log(
|
|
36779
37111
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
@@ -37061,9 +37393,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
37061
37393
|
for (const item of raw) {
|
|
37062
37394
|
if (!item || typeof item !== "object") continue;
|
|
37063
37395
|
const o = item;
|
|
37064
|
-
const
|
|
37065
|
-
if (!
|
|
37066
|
-
const row = { path:
|
|
37396
|
+
const path46 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
37397
|
+
if (!path46) continue;
|
|
37398
|
+
const row = { path: path46 };
|
|
37067
37399
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
37068
37400
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
37069
37401
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -37277,14 +37609,14 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
37277
37609
|
};
|
|
37278
37610
|
|
|
37279
37611
|
// src/files/list-dir/index.ts
|
|
37280
|
-
import
|
|
37612
|
+
import fs34 from "node:fs";
|
|
37281
37613
|
|
|
37282
37614
|
// src/files/ensure-under-cwd.ts
|
|
37283
|
-
import
|
|
37615
|
+
import path38 from "node:path";
|
|
37284
37616
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
37285
|
-
const normalized =
|
|
37286
|
-
const resolved =
|
|
37287
|
-
if (!resolved.startsWith(cwd +
|
|
37617
|
+
const normalized = path38.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
37618
|
+
const resolved = path38.resolve(cwd, normalized);
|
|
37619
|
+
if (!resolved.startsWith(cwd + path38.sep) && resolved !== cwd) {
|
|
37288
37620
|
return null;
|
|
37289
37621
|
}
|
|
37290
37622
|
return resolved;
|
|
@@ -37294,15 +37626,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
|
37294
37626
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
37295
37627
|
|
|
37296
37628
|
// src/files/list-dir/map-dir-entry.ts
|
|
37297
|
-
import
|
|
37298
|
-
import
|
|
37629
|
+
import path39 from "node:path";
|
|
37630
|
+
import fs33 from "node:fs";
|
|
37299
37631
|
async function mapDirEntry(d, relativePath, resolved) {
|
|
37300
|
-
const entryPath =
|
|
37301
|
-
const fullPath =
|
|
37632
|
+
const entryPath = path39.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
37633
|
+
const fullPath = path39.join(resolved, d.name);
|
|
37302
37634
|
let isDir = d.isDirectory();
|
|
37303
37635
|
if (d.isSymbolicLink()) {
|
|
37304
37636
|
try {
|
|
37305
|
-
const targetStat = await
|
|
37637
|
+
const targetStat = await fs33.promises.stat(fullPath);
|
|
37306
37638
|
isDir = targetStat.isDirectory();
|
|
37307
37639
|
} catch {
|
|
37308
37640
|
isDir = false;
|
|
@@ -37332,7 +37664,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
|
37332
37664
|
return { error: "Path is outside working directory" };
|
|
37333
37665
|
}
|
|
37334
37666
|
try {
|
|
37335
|
-
const names = await
|
|
37667
|
+
const names = await fs34.promises.readdir(resolved, { withFileTypes: true });
|
|
37336
37668
|
const entries = [];
|
|
37337
37669
|
for (let i = 0; i < names.length; i++) {
|
|
37338
37670
|
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
@@ -37352,18 +37684,18 @@ var LINE_CHUNK_SIZE = 64 * 1024;
|
|
|
37352
37684
|
var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
|
|
37353
37685
|
|
|
37354
37686
|
// src/files/read-file/resolve-file-path.ts
|
|
37355
|
-
import
|
|
37687
|
+
import fs35 from "node:fs";
|
|
37356
37688
|
async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
37357
37689
|
const resolved = ensureUnderCwd(relativePath, sessionParentPath);
|
|
37358
37690
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
37359
37691
|
let real;
|
|
37360
37692
|
try {
|
|
37361
|
-
real = await
|
|
37693
|
+
real = await fs35.promises.realpath(resolved);
|
|
37362
37694
|
} catch {
|
|
37363
37695
|
real = resolved;
|
|
37364
37696
|
}
|
|
37365
37697
|
try {
|
|
37366
|
-
const stat2 = await
|
|
37698
|
+
const stat2 = await fs35.promises.stat(real);
|
|
37367
37699
|
if (!stat2.isFile()) return { error: "Not a file" };
|
|
37368
37700
|
return real;
|
|
37369
37701
|
} catch (err) {
|
|
@@ -37372,11 +37704,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
|
|
|
37372
37704
|
}
|
|
37373
37705
|
|
|
37374
37706
|
// src/files/read-file/read-file-range-async.ts
|
|
37375
|
-
import
|
|
37707
|
+
import fs36 from "node:fs";
|
|
37376
37708
|
import { StringDecoder } from "node:string_decoder";
|
|
37377
37709
|
async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
37378
|
-
const fileSize = (await
|
|
37379
|
-
const fd = await
|
|
37710
|
+
const fileSize = (await fs36.promises.stat(filePath)).size;
|
|
37711
|
+
const fd = await fs36.promises.open(filePath, "r");
|
|
37380
37712
|
const bufSize = 64 * 1024;
|
|
37381
37713
|
const buf = Buffer.alloc(bufSize);
|
|
37382
37714
|
const decoder = new StringDecoder("utf8");
|
|
@@ -37538,11 +37870,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
|
|
|
37538
37870
|
}
|
|
37539
37871
|
|
|
37540
37872
|
// src/files/read-file/read-file-buffer-full-async.ts
|
|
37541
|
-
import
|
|
37873
|
+
import fs37 from "node:fs";
|
|
37542
37874
|
var READ_CHUNK_BYTES = 256 * 1024;
|
|
37543
37875
|
async function readFileBufferFullAsync(filePath) {
|
|
37544
|
-
const stat2 = await
|
|
37545
|
-
const fd = await
|
|
37876
|
+
const stat2 = await fs37.promises.stat(filePath);
|
|
37877
|
+
const fd = await fs37.promises.open(filePath, "r");
|
|
37546
37878
|
const chunks = [];
|
|
37547
37879
|
let position = 0;
|
|
37548
37880
|
let bytesSinceYield = 0;
|
|
@@ -37649,13 +37981,13 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
|
37649
37981
|
}
|
|
37650
37982
|
|
|
37651
37983
|
// src/files/handle-file-browser-search.ts
|
|
37652
|
-
import
|
|
37984
|
+
import path40 from "node:path";
|
|
37653
37985
|
var SEARCH_LIMIT = 100;
|
|
37654
37986
|
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
37655
37987
|
void (async () => {
|
|
37656
37988
|
await yieldToEventLoop();
|
|
37657
37989
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
37658
|
-
const sessionParentPath =
|
|
37990
|
+
const sessionParentPath = path40.resolve(
|
|
37659
37991
|
sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
37660
37992
|
);
|
|
37661
37993
|
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
@@ -37774,8 +38106,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
37774
38106
|
}
|
|
37775
38107
|
|
|
37776
38108
|
// src/skills/install-remote-skills.ts
|
|
37777
|
-
import
|
|
37778
|
-
import
|
|
38109
|
+
import fs38 from "node:fs";
|
|
38110
|
+
import path41 from "node:path";
|
|
37779
38111
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
37780
38112
|
const installed2 = [];
|
|
37781
38113
|
if (!Array.isArray(items)) {
|
|
@@ -37786,15 +38118,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
37786
38118
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
37787
38119
|
continue;
|
|
37788
38120
|
}
|
|
37789
|
-
const skillDir =
|
|
38121
|
+
const skillDir = path41.join(cwd, targetDir, item.skillName);
|
|
37790
38122
|
for (const f of item.files) {
|
|
37791
38123
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
37792
|
-
const dest =
|
|
37793
|
-
|
|
38124
|
+
const dest = path41.join(skillDir, f.path);
|
|
38125
|
+
fs38.mkdirSync(path41.dirname(dest), { recursive: true });
|
|
37794
38126
|
if (f.text !== void 0) {
|
|
37795
|
-
|
|
38127
|
+
fs38.writeFileSync(dest, f.text, "utf8");
|
|
37796
38128
|
} else if (f.base64) {
|
|
37797
|
-
|
|
38129
|
+
fs38.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
37798
38130
|
}
|
|
37799
38131
|
}
|
|
37800
38132
|
installed2.push({
|
|
@@ -37952,7 +38284,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
37952
38284
|
};
|
|
37953
38285
|
|
|
37954
38286
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
37955
|
-
import * as
|
|
38287
|
+
import * as fs39 from "node:fs";
|
|
37956
38288
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
37957
38289
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
37958
38290
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -37965,7 +38297,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
37965
38297
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
37966
38298
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
37967
38299
|
try {
|
|
37968
|
-
await
|
|
38300
|
+
await fs39.promises.access(file2, fs39.constants.F_OK);
|
|
37969
38301
|
} catch {
|
|
37970
38302
|
sendWsMessage(s, {
|
|
37971
38303
|
type: "revert_turn_snapshot_result",
|
|
@@ -38007,7 +38339,7 @@ var handleDevServersConfig = (msg, deps) => {
|
|
|
38007
38339
|
};
|
|
38008
38340
|
|
|
38009
38341
|
// src/git/bridge-git-context.ts
|
|
38010
|
-
import * as
|
|
38342
|
+
import * as path42 from "node:path";
|
|
38011
38343
|
|
|
38012
38344
|
// src/git/branches/get-current-branch.ts
|
|
38013
38345
|
async function getCurrentBranch(repoPath) {
|
|
@@ -38057,12 +38389,12 @@ async function listRepoBranchRefs(repoPath) {
|
|
|
38057
38389
|
// src/git/bridge-git-context.ts
|
|
38058
38390
|
function folderNameForRelPath(relPath, bridgeRoot) {
|
|
38059
38391
|
if (relPath === "." || relPath === "") {
|
|
38060
|
-
return
|
|
38392
|
+
return path42.basename(path42.resolve(bridgeRoot)) || "repo";
|
|
38061
38393
|
}
|
|
38062
|
-
return
|
|
38394
|
+
return path42.basename(relPath) || relPath;
|
|
38063
38395
|
}
|
|
38064
38396
|
async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
38065
|
-
const root =
|
|
38397
|
+
const root = path42.resolve(bridgeRoot);
|
|
38066
38398
|
if (await isGitRepoDirectory(root)) {
|
|
38067
38399
|
const remoteUrl = await getRemoteOriginUrl(root);
|
|
38068
38400
|
return [{ absolutePath: root, remoteUrl }];
|
|
@@ -38070,17 +38402,17 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
|
38070
38402
|
const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
|
|
38071
38403
|
const byPath = /* @__PURE__ */ new Map();
|
|
38072
38404
|
for (const repo of [...deep, ...shallow]) {
|
|
38073
|
-
byPath.set(
|
|
38405
|
+
byPath.set(path42.resolve(repo.absolutePath), repo);
|
|
38074
38406
|
}
|
|
38075
38407
|
return [...byPath.values()];
|
|
38076
38408
|
}
|
|
38077
38409
|
async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
38078
|
-
const bridgeResolved =
|
|
38410
|
+
const bridgeResolved = path42.resolve(bridgeRoot);
|
|
38079
38411
|
const repos = await discoverGitReposForBridgeContext(bridgeResolved);
|
|
38080
38412
|
const rows = [];
|
|
38081
38413
|
for (const repo of repos) {
|
|
38082
|
-
let rel =
|
|
38083
|
-
if (rel.startsWith("..") ||
|
|
38414
|
+
let rel = path42.relative(bridgeResolved, repo.absolutePath);
|
|
38415
|
+
if (rel.startsWith("..") || path42.isAbsolute(rel)) continue;
|
|
38084
38416
|
const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
38085
38417
|
const currentBranch = await getCurrentBranch(repo.absolutePath);
|
|
38086
38418
|
const remoteUrl = repo.remoteUrl.trim() || null;
|
|
@@ -38095,11 +38427,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
|
38095
38427
|
return rows;
|
|
38096
38428
|
}
|
|
38097
38429
|
async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
38098
|
-
const bridgeResolved =
|
|
38430
|
+
const bridgeResolved = path42.resolve(bridgeRoot);
|
|
38099
38431
|
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
38100
|
-
const repoPath = rel === "" ? bridgeResolved :
|
|
38101
|
-
const resolved =
|
|
38102
|
-
if (!resolved.startsWith(bridgeResolved +
|
|
38432
|
+
const repoPath = rel === "" ? bridgeResolved : path42.join(bridgeResolved, rel);
|
|
38433
|
+
const resolved = path42.resolve(repoPath);
|
|
38434
|
+
if (!resolved.startsWith(bridgeResolved + path42.sep) && resolved !== bridgeResolved) {
|
|
38103
38435
|
return [];
|
|
38104
38436
|
}
|
|
38105
38437
|
return listRepoBranchRefs(resolved);
|
|
@@ -38683,10 +39015,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
|
38683
39015
|
}
|
|
38684
39016
|
|
|
38685
39017
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
38686
|
-
import * as
|
|
39018
|
+
import * as path44 from "node:path";
|
|
38687
39019
|
|
|
38688
39020
|
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
38689
|
-
import * as
|
|
39021
|
+
import * as path43 from "node:path";
|
|
38690
39022
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
38691
39023
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
|
|
38692
39024
|
const canContinue = () => shouldContinue?.() !== false;
|
|
@@ -38724,7 +39056,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
38724
39056
|
if (!canContinue()) return false;
|
|
38725
39057
|
handle = await resolved.createClient({
|
|
38726
39058
|
command: resolved.command,
|
|
38727
|
-
cwd:
|
|
39059
|
+
cwd: path43.resolve(cwd),
|
|
38728
39060
|
backendAgentType: agentType,
|
|
38729
39061
|
sessionMode: "agent",
|
|
38730
39062
|
persistedAcpSessionId: null,
|
|
@@ -38802,7 +39134,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
38802
39134
|
const { workspaceId, log: log2, getWs } = params;
|
|
38803
39135
|
const isCurrent = beginAgentCapabilityWarmupRun();
|
|
38804
39136
|
if (!isCurrent()) return;
|
|
38805
|
-
const cwd =
|
|
39137
|
+
const cwd = path44.resolve(getBridgeRoot());
|
|
38806
39138
|
async function sendBatchFromCache() {
|
|
38807
39139
|
if (!isCurrent()) return;
|
|
38808
39140
|
const socket = getWs();
|
|
@@ -39207,8 +39539,8 @@ async function createBridgeConnection(options) {
|
|
|
39207
39539
|
getCloudAccessToken: () => tokens.accessToken
|
|
39208
39540
|
};
|
|
39209
39541
|
const identifyReportedPaths = {
|
|
39210
|
-
bridgeRootPath:
|
|
39211
|
-
worktreesRootPath:
|
|
39542
|
+
bridgeRootPath: path45.resolve(getBridgeRoot()),
|
|
39543
|
+
worktreesRootPath: path45.resolve(worktreesRootPath)
|
|
39212
39544
|
};
|
|
39213
39545
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
39214
39546
|
state,
|