@buildautomaton/cli 0.1.46 → 0.1.48
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 +979 -515
- package/dist/cli.js.map +4 -4
- package/dist/index.js +958 -494
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -973,8 +973,8 @@ var require_command = __commonJS({
|
|
|
973
973
|
"../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
|
|
974
974
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
975
975
|
var childProcess2 = __require("node:child_process");
|
|
976
|
-
var
|
|
977
|
-
var
|
|
976
|
+
var path48 = __require("node:path");
|
|
977
|
+
var fs42 = __require("node:fs");
|
|
978
978
|
var process8 = __require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
980
980
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1906,11 +1906,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1906
1906
|
let launchWithNode = false;
|
|
1907
1907
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1908
1908
|
function findFile(baseDir, baseName) {
|
|
1909
|
-
const localBin =
|
|
1910
|
-
if (
|
|
1911
|
-
if (sourceExt.includes(
|
|
1909
|
+
const localBin = path48.resolve(baseDir, baseName);
|
|
1910
|
+
if (fs42.existsSync(localBin)) return localBin;
|
|
1911
|
+
if (sourceExt.includes(path48.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
|
-
(ext) =>
|
|
1913
|
+
(ext) => fs42.existsSync(`${localBin}${ext}`)
|
|
1914
1914
|
);
|
|
1915
1915
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1916
1916
|
return void 0;
|
|
@@ -1922,21 +1922,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1922
1922
|
if (this._scriptPath) {
|
|
1923
1923
|
let resolvedScriptPath;
|
|
1924
1924
|
try {
|
|
1925
|
-
resolvedScriptPath =
|
|
1925
|
+
resolvedScriptPath = fs42.realpathSync(this._scriptPath);
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
1929
|
-
executableDir =
|
|
1930
|
-
|
|
1929
|
+
executableDir = path48.resolve(
|
|
1930
|
+
path48.dirname(resolvedScriptPath),
|
|
1931
1931
|
executableDir
|
|
1932
1932
|
);
|
|
1933
1933
|
}
|
|
1934
1934
|
if (executableDir) {
|
|
1935
1935
|
let localFile = findFile(executableDir, executableFile);
|
|
1936
1936
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1937
|
-
const legacyName =
|
|
1937
|
+
const legacyName = path48.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path48.extname(this._scriptPath)
|
|
1940
1940
|
);
|
|
1941
1941
|
if (legacyName !== this._name) {
|
|
1942
1942
|
localFile = findFile(
|
|
@@ -1947,7 +1947,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1947
1947
|
}
|
|
1948
1948
|
executableFile = localFile || executableFile;
|
|
1949
1949
|
}
|
|
1950
|
-
launchWithNode = sourceExt.includes(
|
|
1950
|
+
launchWithNode = sourceExt.includes(path48.extname(executableFile));
|
|
1951
1951
|
let proc;
|
|
1952
1952
|
if (process8.platform !== "win32") {
|
|
1953
1953
|
if (launchWithNode) {
|
|
@@ -2787,7 +2787,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2787
2787
|
* @return {Command}
|
|
2788
2788
|
*/
|
|
2789
2789
|
nameFromFilename(filename) {
|
|
2790
|
-
this._name =
|
|
2790
|
+
this._name = path48.basename(filename, path48.extname(filename));
|
|
2791
2791
|
return this;
|
|
2792
2792
|
}
|
|
2793
2793
|
/**
|
|
@@ -2801,9 +2801,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2801
2801
|
* @param {string} [path]
|
|
2802
2802
|
* @return {(string|null|Command)}
|
|
2803
2803
|
*/
|
|
2804
|
-
executableDir(
|
|
2805
|
-
if (
|
|
2806
|
-
this._executableDir =
|
|
2804
|
+
executableDir(path49) {
|
|
2805
|
+
if (path49 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path49;
|
|
2807
2807
|
return this;
|
|
2808
2808
|
}
|
|
2809
2809
|
/**
|
|
@@ -7061,8 +7061,8 @@ var init_parseUtil = __esm({
|
|
|
7061
7061
|
init_errors();
|
|
7062
7062
|
init_en();
|
|
7063
7063
|
makeIssue = (params) => {
|
|
7064
|
-
const { data, path:
|
|
7065
|
-
const fullPath = [...
|
|
7064
|
+
const { data, path: path48, errorMaps, issueData } = params;
|
|
7065
|
+
const fullPath = [...path48, ...issueData.path || []];
|
|
7066
7066
|
const fullIssue = {
|
|
7067
7067
|
...issueData,
|
|
7068
7068
|
path: fullPath
|
|
@@ -7370,11 +7370,11 @@ var init_types = __esm({
|
|
|
7370
7370
|
init_parseUtil();
|
|
7371
7371
|
init_util();
|
|
7372
7372
|
ParseInputLazyPath = class {
|
|
7373
|
-
constructor(parent, value,
|
|
7373
|
+
constructor(parent, value, path48, key) {
|
|
7374
7374
|
this._cachedPath = [];
|
|
7375
7375
|
this.parent = parent;
|
|
7376
7376
|
this.data = value;
|
|
7377
|
-
this._path =
|
|
7377
|
+
this._path = path48;
|
|
7378
7378
|
this._key = key;
|
|
7379
7379
|
}
|
|
7380
7380
|
get path() {
|
|
@@ -11099,15 +11099,15 @@ function assignProp(target, prop, value) {
|
|
|
11099
11099
|
configurable: true
|
|
11100
11100
|
});
|
|
11101
11101
|
}
|
|
11102
|
-
function getElementAtPath(obj,
|
|
11103
|
-
if (!
|
|
11102
|
+
function getElementAtPath(obj, path48) {
|
|
11103
|
+
if (!path48)
|
|
11104
11104
|
return obj;
|
|
11105
|
-
return
|
|
11105
|
+
return path48.reduce((acc, key) => acc?.[key], obj);
|
|
11106
11106
|
}
|
|
11107
11107
|
function promiseAllObject(promisesObj) {
|
|
11108
11108
|
const keys = Object.keys(promisesObj);
|
|
11109
|
-
const
|
|
11110
|
-
return Promise.all(
|
|
11109
|
+
const promises6 = keys.map((key) => promisesObj[key]);
|
|
11110
|
+
return Promise.all(promises6).then((results) => {
|
|
11111
11111
|
const resolvedObj = {};
|
|
11112
11112
|
for (let i = 0; i < keys.length; i++) {
|
|
11113
11113
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -11351,11 +11351,11 @@ function aborted(x, startIndex = 0) {
|
|
|
11351
11351
|
}
|
|
11352
11352
|
return false;
|
|
11353
11353
|
}
|
|
11354
|
-
function prefixIssues(
|
|
11354
|
+
function prefixIssues(path48, issues) {
|
|
11355
11355
|
return issues.map((iss) => {
|
|
11356
11356
|
var _a2;
|
|
11357
11357
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
11358
|
-
iss.path.unshift(
|
|
11358
|
+
iss.path.unshift(path48);
|
|
11359
11359
|
return iss;
|
|
11360
11360
|
});
|
|
11361
11361
|
}
|
|
@@ -11544,7 +11544,7 @@ function treeifyError(error40, _mapper) {
|
|
|
11544
11544
|
return issue2.message;
|
|
11545
11545
|
};
|
|
11546
11546
|
const result = { errors: [] };
|
|
11547
|
-
const processError = (error41,
|
|
11547
|
+
const processError = (error41, path48 = []) => {
|
|
11548
11548
|
var _a2, _b;
|
|
11549
11549
|
for (const issue2 of error41.issues) {
|
|
11550
11550
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -11554,7 +11554,7 @@ function treeifyError(error40, _mapper) {
|
|
|
11554
11554
|
} else if (issue2.code === "invalid_element") {
|
|
11555
11555
|
processError({ issues: issue2.issues }, issue2.path);
|
|
11556
11556
|
} else {
|
|
11557
|
-
const fullpath = [...
|
|
11557
|
+
const fullpath = [...path48, ...issue2.path];
|
|
11558
11558
|
if (fullpath.length === 0) {
|
|
11559
11559
|
result.errors.push(mapper(issue2));
|
|
11560
11560
|
continue;
|
|
@@ -11584,9 +11584,9 @@ function treeifyError(error40, _mapper) {
|
|
|
11584
11584
|
processError(error40);
|
|
11585
11585
|
return result;
|
|
11586
11586
|
}
|
|
11587
|
-
function toDotPath(
|
|
11587
|
+
function toDotPath(path48) {
|
|
11588
11588
|
const segs = [];
|
|
11589
|
-
for (const seg of
|
|
11589
|
+
for (const seg of path48) {
|
|
11590
11590
|
if (typeof seg === "number")
|
|
11591
11591
|
segs.push(`[${seg}]`);
|
|
11592
11592
|
else if (typeof seg === "symbol")
|
|
@@ -25069,10 +25069,10 @@ var require_src2 = __commonJS({
|
|
|
25069
25069
|
var fs_1 = __require("fs");
|
|
25070
25070
|
var debug_1 = __importDefault(require_src());
|
|
25071
25071
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
25072
|
-
function check2(
|
|
25073
|
-
log2(`checking %s`,
|
|
25072
|
+
function check2(path48, isFile, isDirectory) {
|
|
25073
|
+
log2(`checking %s`, path48);
|
|
25074
25074
|
try {
|
|
25075
|
-
const stat3 = fs_1.statSync(
|
|
25075
|
+
const stat3 = fs_1.statSync(path48);
|
|
25076
25076
|
if (stat3.isFile() && isFile) {
|
|
25077
25077
|
log2(`[OK] path represents a file`);
|
|
25078
25078
|
return true;
|
|
@@ -25092,8 +25092,8 @@ var require_src2 = __commonJS({
|
|
|
25092
25092
|
throw e;
|
|
25093
25093
|
}
|
|
25094
25094
|
}
|
|
25095
|
-
function exists2(
|
|
25096
|
-
return check2(
|
|
25095
|
+
function exists2(path48, type = exports.READABLE) {
|
|
25096
|
+
return check2(path48, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
25097
25097
|
}
|
|
25098
25098
|
exports.exists = exists2;
|
|
25099
25099
|
exports.FILE = 1;
|
|
@@ -25174,15 +25174,15 @@ var {
|
|
|
25174
25174
|
} = import_index.default;
|
|
25175
25175
|
|
|
25176
25176
|
// src/cli-version.ts
|
|
25177
|
-
var CLI_VERSION = "0.1.
|
|
25177
|
+
var CLI_VERSION = "0.1.48".length > 0 ? "0.1.48" : "0.0.0-dev";
|
|
25178
25178
|
|
|
25179
25179
|
// src/cli/defaults.ts
|
|
25180
25180
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
25181
25181
|
var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
25182
25182
|
|
|
25183
25183
|
// src/cli/run-cli-action.ts
|
|
25184
|
-
import * as
|
|
25185
|
-
import * as
|
|
25184
|
+
import * as fs41 from "node:fs";
|
|
25185
|
+
import * as path47 from "node:path";
|
|
25186
25186
|
|
|
25187
25187
|
// src/cli-log-level.ts
|
|
25188
25188
|
var verbosity = "info";
|
|
@@ -25477,6 +25477,72 @@ function createCliE2eeRuntime(key) {
|
|
|
25477
25477
|
};
|
|
25478
25478
|
}
|
|
25479
25479
|
|
|
25480
|
+
// src/lib/e2ee/decrypt-stored-e2ee-content.ts
|
|
25481
|
+
function parseJsonObject(raw) {
|
|
25482
|
+
try {
|
|
25483
|
+
const parsed = JSON.parse(raw);
|
|
25484
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
25485
|
+
return parsed;
|
|
25486
|
+
}
|
|
25487
|
+
} catch {
|
|
25488
|
+
return null;
|
|
25489
|
+
}
|
|
25490
|
+
return null;
|
|
25491
|
+
}
|
|
25492
|
+
function storedStringHasE2eeEnvelope(raw) {
|
|
25493
|
+
const record2 = parseJsonObject(raw);
|
|
25494
|
+
return record2 != null && isE2eeEnvelope(record2.ee);
|
|
25495
|
+
}
|
|
25496
|
+
function e2eeKeyIdFromStoredString(raw) {
|
|
25497
|
+
const record2 = parseJsonObject(raw);
|
|
25498
|
+
if (record2 != null && isE2eeEnvelope(record2.ee)) return record2.ee.k;
|
|
25499
|
+
return null;
|
|
25500
|
+
}
|
|
25501
|
+
function decryptStoredE2eeRecord(record2, e2ee) {
|
|
25502
|
+
if (!isE2eeEnvelope(record2.ee)) return record2;
|
|
25503
|
+
if (!e2ee) {
|
|
25504
|
+
throw new Error(`E2EE_REQUIRED:${record2.ee.k}`);
|
|
25505
|
+
}
|
|
25506
|
+
if (record2.ee.k !== e2ee.keyId) {
|
|
25507
|
+
throw new Error(`E2EE_KEY_MISMATCH:encrypted=${record2.ee.k}:cli=${e2ee.keyId}`);
|
|
25508
|
+
}
|
|
25509
|
+
return e2ee.decryptMessage(record2);
|
|
25510
|
+
}
|
|
25511
|
+
function formatCliE2eeDecryptError(error40, e2ee) {
|
|
25512
|
+
const message = error40 instanceof Error ? error40.message : String(error40);
|
|
25513
|
+
const required2 = /^E2EE_REQUIRED:(.+)$/.exec(message.trim());
|
|
25514
|
+
if (required2) {
|
|
25515
|
+
const keyId = required2[1]?.trim() || "unknown";
|
|
25516
|
+
return `Parent session content is encrypted (key ${keyId}) but this bridge was not started with E2EE certificates. Restart the CLI with your E2EE certificate to read fork parent history.`;
|
|
25517
|
+
}
|
|
25518
|
+
const mismatch = /^E2EE_KEY_MISMATCH:encrypted=(.+):cli=(.*)$/.exec(message.trim());
|
|
25519
|
+
if (mismatch) {
|
|
25520
|
+
const encryptedKeyId = mismatch[1]?.trim() || "unknown";
|
|
25521
|
+
const cliKeyId = mismatch[2]?.trim() || e2ee?.keyId || "none";
|
|
25522
|
+
return `Parent session content is encrypted with key ${encryptedKeyId}, but this bridge certificate key is ${cliKeyId}. Use the same E2EE certificate that was used for the parent session.`;
|
|
25523
|
+
}
|
|
25524
|
+
if (message.includes("E2EE key mismatch")) {
|
|
25525
|
+
return `Parent session content could not be decrypted: ${message}`;
|
|
25526
|
+
}
|
|
25527
|
+
return `Parent session content could not be decrypted: ${message}`;
|
|
25528
|
+
}
|
|
25529
|
+
function decryptCliE2eeTranscriptPayload(payload, e2ee) {
|
|
25530
|
+
const record2 = parseJsonObject(payload);
|
|
25531
|
+
if (!record2 || !isE2eeEnvelope(record2.ee)) return payload;
|
|
25532
|
+
const decrypted = decryptStoredE2eeRecord(record2, e2ee);
|
|
25533
|
+
if (typeof decrypted.payload === "string") return decrypted.payload;
|
|
25534
|
+
return JSON.stringify(decrypted.payload ?? decrypted);
|
|
25535
|
+
}
|
|
25536
|
+
function decryptCliE2eeMessageField(payload, field, e2ee) {
|
|
25537
|
+
if (payload == null) return null;
|
|
25538
|
+
const record2 = parseJsonObject(payload);
|
|
25539
|
+
if (!record2 || !isE2eeEnvelope(record2.ee)) return payload;
|
|
25540
|
+
const decrypted = decryptStoredE2eeRecord(record2, e2ee);
|
|
25541
|
+
const value = decrypted[field];
|
|
25542
|
+
if (value == null) return null;
|
|
25543
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
25544
|
+
}
|
|
25545
|
+
|
|
25480
25546
|
// src/e2e-certificates/certificates.ts
|
|
25481
25547
|
var E2E_CERTIFICATE_ALGORITHM = "A1";
|
|
25482
25548
|
var CERTIFICATE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".pem", ".key", ".crt"]);
|
|
@@ -27819,9 +27885,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
27819
27885
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
27820
27886
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
27821
27887
|
if (!rawPath || !summary) continue;
|
|
27822
|
-
const
|
|
27823
|
-
if (!
|
|
27824
|
-
rows.push({ path:
|
|
27888
|
+
const path48 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
27889
|
+
if (!path48) continue;
|
|
27890
|
+
rows.push({ path: path48, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
27825
27891
|
}
|
|
27826
27892
|
return rows;
|
|
27827
27893
|
}
|
|
@@ -30981,8 +31047,8 @@ function pathspec(...paths) {
|
|
|
30981
31047
|
cache.set(key, paths);
|
|
30982
31048
|
return key;
|
|
30983
31049
|
}
|
|
30984
|
-
function isPathSpec(
|
|
30985
|
-
return
|
|
31050
|
+
function isPathSpec(path48) {
|
|
31051
|
+
return path48 instanceof String && cache.has(path48);
|
|
30986
31052
|
}
|
|
30987
31053
|
function toPaths(pathSpec) {
|
|
30988
31054
|
return cache.get(pathSpec) || [];
|
|
@@ -31071,8 +31137,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
31071
31137
|
function forEachLineWithContent(input, callback) {
|
|
31072
31138
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
31073
31139
|
}
|
|
31074
|
-
function folderExists(
|
|
31075
|
-
return (0, import_file_exists.exists)(
|
|
31140
|
+
function folderExists(path48) {
|
|
31141
|
+
return (0, import_file_exists.exists)(path48, import_file_exists.FOLDER);
|
|
31076
31142
|
}
|
|
31077
31143
|
function append(target, item) {
|
|
31078
31144
|
if (Array.isArray(target)) {
|
|
@@ -31476,8 +31542,8 @@ function checkIsRepoRootTask() {
|
|
|
31476
31542
|
commands,
|
|
31477
31543
|
format: "utf-8",
|
|
31478
31544
|
onError,
|
|
31479
|
-
parser(
|
|
31480
|
-
return /^\.(git)?$/.test(
|
|
31545
|
+
parser(path48) {
|
|
31546
|
+
return /^\.(git)?$/.test(path48.trim());
|
|
31481
31547
|
}
|
|
31482
31548
|
};
|
|
31483
31549
|
}
|
|
@@ -31911,11 +31977,11 @@ function parseGrep(grep) {
|
|
|
31911
31977
|
const paths = /* @__PURE__ */ new Set();
|
|
31912
31978
|
const results = {};
|
|
31913
31979
|
forEachLineWithContent(grep, (input) => {
|
|
31914
|
-
const [
|
|
31915
|
-
paths.add(
|
|
31916
|
-
(results[
|
|
31980
|
+
const [path48, line, preview] = input.split(NULL);
|
|
31981
|
+
paths.add(path48);
|
|
31982
|
+
(results[path48] = results[path48] || []).push({
|
|
31917
31983
|
line: asNumber(line),
|
|
31918
|
-
path:
|
|
31984
|
+
path: path48,
|
|
31919
31985
|
preview
|
|
31920
31986
|
});
|
|
31921
31987
|
});
|
|
@@ -32680,14 +32746,14 @@ var init_hash_object = __esm2({
|
|
|
32680
32746
|
init_task();
|
|
32681
32747
|
}
|
|
32682
32748
|
});
|
|
32683
|
-
function parseInit(bare,
|
|
32749
|
+
function parseInit(bare, path48, text) {
|
|
32684
32750
|
const response = String(text).trim();
|
|
32685
32751
|
let result;
|
|
32686
32752
|
if (result = initResponseRegex.exec(response)) {
|
|
32687
|
-
return new InitSummary(bare,
|
|
32753
|
+
return new InitSummary(bare, path48, false, result[1]);
|
|
32688
32754
|
}
|
|
32689
32755
|
if (result = reInitResponseRegex.exec(response)) {
|
|
32690
|
-
return new InitSummary(bare,
|
|
32756
|
+
return new InitSummary(bare, path48, true, result[1]);
|
|
32691
32757
|
}
|
|
32692
32758
|
let gitDir = "";
|
|
32693
32759
|
const tokens = response.split(" ");
|
|
@@ -32698,7 +32764,7 @@ function parseInit(bare, path46, text) {
|
|
|
32698
32764
|
break;
|
|
32699
32765
|
}
|
|
32700
32766
|
}
|
|
32701
|
-
return new InitSummary(bare,
|
|
32767
|
+
return new InitSummary(bare, path48, /^re/i.test(response), gitDir);
|
|
32702
32768
|
}
|
|
32703
32769
|
var InitSummary;
|
|
32704
32770
|
var initResponseRegex;
|
|
@@ -32707,9 +32773,9 @@ var init_InitSummary = __esm2({
|
|
|
32707
32773
|
"src/lib/responses/InitSummary.ts"() {
|
|
32708
32774
|
"use strict";
|
|
32709
32775
|
InitSummary = class {
|
|
32710
|
-
constructor(bare,
|
|
32776
|
+
constructor(bare, path48, existing, gitDir) {
|
|
32711
32777
|
this.bare = bare;
|
|
32712
|
-
this.path =
|
|
32778
|
+
this.path = path48;
|
|
32713
32779
|
this.existing = existing;
|
|
32714
32780
|
this.gitDir = gitDir;
|
|
32715
32781
|
}
|
|
@@ -32721,7 +32787,7 @@ var init_InitSummary = __esm2({
|
|
|
32721
32787
|
function hasBareCommand(command) {
|
|
32722
32788
|
return command.includes(bareCommand);
|
|
32723
32789
|
}
|
|
32724
|
-
function initTask(bare = false,
|
|
32790
|
+
function initTask(bare = false, path48, customArgs) {
|
|
32725
32791
|
const commands = ["init", ...customArgs];
|
|
32726
32792
|
if (bare && !hasBareCommand(commands)) {
|
|
32727
32793
|
commands.splice(1, 0, bareCommand);
|
|
@@ -32730,7 +32796,7 @@ function initTask(bare = false, path46, customArgs) {
|
|
|
32730
32796
|
commands,
|
|
32731
32797
|
format: "utf-8",
|
|
32732
32798
|
parser(text) {
|
|
32733
|
-
return parseInit(commands.includes("--bare"),
|
|
32799
|
+
return parseInit(commands.includes("--bare"), path48, text);
|
|
32734
32800
|
}
|
|
32735
32801
|
};
|
|
32736
32802
|
}
|
|
@@ -33546,12 +33612,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
33546
33612
|
"use strict";
|
|
33547
33613
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
33548
33614
|
FileStatusSummary = class {
|
|
33549
|
-
constructor(
|
|
33550
|
-
this.path =
|
|
33615
|
+
constructor(path48, index, working_dir) {
|
|
33616
|
+
this.path = path48;
|
|
33551
33617
|
this.index = index;
|
|
33552
33618
|
this.working_dir = working_dir;
|
|
33553
33619
|
if (index === "R" || working_dir === "R") {
|
|
33554
|
-
const detail = fromPathRegex.exec(
|
|
33620
|
+
const detail = fromPathRegex.exec(path48) || [null, path48, path48];
|
|
33555
33621
|
this.from = detail[2] || "";
|
|
33556
33622
|
this.path = detail[1] || "";
|
|
33557
33623
|
}
|
|
@@ -33582,14 +33648,14 @@ function splitLine(result, lineStr) {
|
|
|
33582
33648
|
default:
|
|
33583
33649
|
return;
|
|
33584
33650
|
}
|
|
33585
|
-
function data(index, workingDir,
|
|
33651
|
+
function data(index, workingDir, path48) {
|
|
33586
33652
|
const raw = `${index}${workingDir}`;
|
|
33587
33653
|
const handler = parsers6.get(raw);
|
|
33588
33654
|
if (handler) {
|
|
33589
|
-
handler(result,
|
|
33655
|
+
handler(result, path48);
|
|
33590
33656
|
}
|
|
33591
33657
|
if (raw !== "##" && raw !== "!!") {
|
|
33592
|
-
result.files.push(new FileStatusSummary(
|
|
33658
|
+
result.files.push(new FileStatusSummary(path48, index, workingDir));
|
|
33593
33659
|
}
|
|
33594
33660
|
}
|
|
33595
33661
|
}
|
|
@@ -33898,9 +33964,9 @@ var init_simple_git_api = __esm2({
|
|
|
33898
33964
|
next
|
|
33899
33965
|
);
|
|
33900
33966
|
}
|
|
33901
|
-
hashObject(
|
|
33967
|
+
hashObject(path48, write) {
|
|
33902
33968
|
return this._runTask(
|
|
33903
|
-
hashObjectTask(
|
|
33969
|
+
hashObjectTask(path48, write === true),
|
|
33904
33970
|
trailingFunctionArgument(arguments)
|
|
33905
33971
|
);
|
|
33906
33972
|
}
|
|
@@ -34253,8 +34319,8 @@ var init_branch = __esm2({
|
|
|
34253
34319
|
}
|
|
34254
34320
|
});
|
|
34255
34321
|
function toPath(input) {
|
|
34256
|
-
const
|
|
34257
|
-
return
|
|
34322
|
+
const path48 = input.trim().replace(/^["']|["']$/g, "");
|
|
34323
|
+
return path48 && normalize3(path48);
|
|
34258
34324
|
}
|
|
34259
34325
|
var parseCheckIgnore;
|
|
34260
34326
|
var init_CheckIgnore = __esm2({
|
|
@@ -34568,8 +34634,8 @@ __export2(sub_module_exports, {
|
|
|
34568
34634
|
subModuleTask: () => subModuleTask,
|
|
34569
34635
|
updateSubModuleTask: () => updateSubModuleTask
|
|
34570
34636
|
});
|
|
34571
|
-
function addSubModuleTask(repo,
|
|
34572
|
-
return subModuleTask(["add", repo,
|
|
34637
|
+
function addSubModuleTask(repo, path48) {
|
|
34638
|
+
return subModuleTask(["add", repo, path48]);
|
|
34573
34639
|
}
|
|
34574
34640
|
function initSubModuleTask(customArgs) {
|
|
34575
34641
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -34902,8 +34968,8 @@ var require_git = __commonJS2({
|
|
|
34902
34968
|
}
|
|
34903
34969
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
34904
34970
|
};
|
|
34905
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
34906
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
34971
|
+
Git2.prototype.submoduleAdd = function(repo, path48, then) {
|
|
34972
|
+
return this._runTask(addSubModuleTask2(repo, path48), trailingFunctionArgument2(arguments));
|
|
34907
34973
|
};
|
|
34908
34974
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
34909
34975
|
return this._runTask(
|
|
@@ -35866,9 +35932,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
35866
35932
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
35867
35933
|
async function putEncryptedChangeSummaryRows(params) {
|
|
35868
35934
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
35869
|
-
const entries = params.rows.map(({ path:
|
|
35935
|
+
const entries = params.rows.map(({ path: path48, summary }) => {
|
|
35870
35936
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
35871
|
-
return { path:
|
|
35937
|
+
return { path: path48, summary: JSON.stringify(enc) };
|
|
35872
35938
|
});
|
|
35873
35939
|
const res = await fetch(
|
|
35874
35940
|
`${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -36081,54 +36147,101 @@ function buildForkedSessionAgentPrompt(userPrompt, childSessionId, parentSession
|
|
|
36081
36147
|
].join("\n");
|
|
36082
36148
|
}
|
|
36083
36149
|
|
|
36084
|
-
// src/mcp/tools/session-history/
|
|
36150
|
+
// src/mcp/tools/session-history/cloud/internal-api.ts
|
|
36085
36151
|
function internalApiBase(cloudApiBaseUrl) {
|
|
36086
36152
|
return cloudApiBaseUrl.replace(/\/+$/, "");
|
|
36087
36153
|
}
|
|
36088
|
-
async function
|
|
36154
|
+
async function fetchInternalApiJson(params) {
|
|
36089
36155
|
const token = params.getCloudAccessToken();
|
|
36090
36156
|
if (!token) return { ok: false, error: "Missing cloud access token." };
|
|
36091
|
-
const url2 = `${internalApiBase(params.cloudApiBaseUrl)}
|
|
36157
|
+
const url2 = `${internalApiBase(params.cloudApiBaseUrl)}${params.path}`;
|
|
36092
36158
|
const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
|
|
36093
36159
|
if (!res.ok) {
|
|
36094
36160
|
const t = await res.text().catch(() => "");
|
|
36095
|
-
return { ok: false, error:
|
|
36161
|
+
return { ok: false, error: `${params.errorLabel} (${res.status}): ${t.slice(0, 200)}` };
|
|
36096
36162
|
}
|
|
36097
36163
|
const data = await res.json().catch(() => null);
|
|
36098
|
-
if (!data) return { ok: false, error:
|
|
36164
|
+
if (!data) return { ok: false, error: `Invalid ${params.errorLabel.toLowerCase()} response.` };
|
|
36099
36165
|
return { ok: true, data };
|
|
36100
36166
|
}
|
|
36101
|
-
|
|
36102
|
-
|
|
36103
|
-
|
|
36104
|
-
|
|
36105
|
-
|
|
36106
|
-
|
|
36107
|
-
|
|
36108
|
-
|
|
36167
|
+
|
|
36168
|
+
// src/mcp/tools/session-history/cloud/fetch-session-meta.ts
|
|
36169
|
+
async function fetchCloudSessionMeta(params) {
|
|
36170
|
+
return fetchInternalApiJson({
|
|
36171
|
+
...params,
|
|
36172
|
+
path: `/internal/sessions/${encodeURIComponent(params.sessionId)}/meta`,
|
|
36173
|
+
errorLabel: "Session meta fetch failed"
|
|
36174
|
+
});
|
|
36175
|
+
}
|
|
36176
|
+
|
|
36177
|
+
// src/mcp/tools/session-history/cloud/decrypt-parent-prompt-turns.ts
|
|
36178
|
+
function assertE2eeRuntimeForEnvelope(raw, e2ee) {
|
|
36179
|
+
if (storedStringHasE2eeEnvelope(raw) && !e2ee) {
|
|
36180
|
+
throw new Error(`E2EE_REQUIRED:${e2eeKeyIdFromStoredString(raw) ?? "unknown"}`);
|
|
36109
36181
|
}
|
|
36110
|
-
const data = await res.json().catch(() => null);
|
|
36111
|
-
if (!data) return { ok: false, error: "Invalid parent prompts response." };
|
|
36112
|
-
return { ok: true, data };
|
|
36113
36182
|
}
|
|
36114
|
-
|
|
36115
|
-
|
|
36116
|
-
|
|
36117
|
-
|
|
36118
|
-
|
|
36119
|
-
|
|
36120
|
-
|
|
36121
|
-
|
|
36183
|
+
function decryptParentPromptTurns(turns, e2ee) {
|
|
36184
|
+
return turns.map((turn) => {
|
|
36185
|
+
const promptRaw = typeof turn.promptText === "string" ? turn.promptText : null;
|
|
36186
|
+
const titleRaw = typeof turn.title === "string" ? turn.title : null;
|
|
36187
|
+
if (promptRaw) assertE2eeRuntimeForEnvelope(promptRaw, e2ee);
|
|
36188
|
+
if (titleRaw) assertE2eeRuntimeForEnvelope(titleRaw, e2ee);
|
|
36189
|
+
return {
|
|
36190
|
+
...turn,
|
|
36191
|
+
promptText: decryptCliE2eeMessageField(promptRaw, "prompt", e2ee),
|
|
36192
|
+
title: decryptCliE2eeMessageField(titleRaw, "title", e2ee)
|
|
36193
|
+
};
|
|
36194
|
+
});
|
|
36195
|
+
}
|
|
36196
|
+
|
|
36197
|
+
// src/mcp/tools/session-history/cloud/fetch-parent-prompts.ts
|
|
36198
|
+
async function fetchCloudParentSessionPrompts(params) {
|
|
36199
|
+
const fetched = await fetchInternalApiJson({
|
|
36200
|
+
...params,
|
|
36201
|
+
path: `/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/prompts`,
|
|
36202
|
+
errorLabel: "Parent prompts fetch failed"
|
|
36203
|
+
});
|
|
36204
|
+
if (!fetched.ok) return fetched;
|
|
36205
|
+
const turns = Array.isArray(fetched.data.turns) ? fetched.data.turns : [];
|
|
36206
|
+
try {
|
|
36207
|
+
const decryptedTurns = decryptParentPromptTurns(turns, params.e2ee);
|
|
36208
|
+
return { ok: true, data: { ...fetched.data, turns: decryptedTurns } };
|
|
36209
|
+
} catch (error40) {
|
|
36210
|
+
return { ok: false, error: formatCliE2eeDecryptError(error40, params.e2ee) };
|
|
36122
36211
|
}
|
|
36123
|
-
|
|
36124
|
-
|
|
36212
|
+
}
|
|
36213
|
+
|
|
36214
|
+
// src/mcp/tools/session-history/cloud/format-parent-transcript-text.ts
|
|
36215
|
+
function formatParentTranscriptText(rows, e2ee) {
|
|
36125
36216
|
const lines = rows.map((row) => {
|
|
36126
36217
|
const kind = typeof row.kind === "string" ? row.kind : "event";
|
|
36127
|
-
const
|
|
36218
|
+
const rawPayload = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload ?? "");
|
|
36219
|
+
if (storedStringHasE2eeEnvelope(rawPayload) && !e2ee) {
|
|
36220
|
+
throw new Error(`E2EE_REQUIRED:${e2eeKeyIdFromStoredString(rawPayload) ?? "unknown"}`);
|
|
36221
|
+
}
|
|
36222
|
+
const payload = decryptCliE2eeTranscriptPayload(rawPayload, e2ee);
|
|
36128
36223
|
return `[${kind}] ${payload}`;
|
|
36129
36224
|
});
|
|
36130
|
-
return
|
|
36225
|
+
return lines.join("\n");
|
|
36131
36226
|
}
|
|
36227
|
+
|
|
36228
|
+
// src/mcp/tools/session-history/cloud/fetch-parent-transcript.ts
|
|
36229
|
+
async function fetchCloudParentTurnTranscript(params) {
|
|
36230
|
+
const fetched = await fetchInternalApiJson({
|
|
36231
|
+
...params,
|
|
36232
|
+
path: `/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/turns/${encodeURIComponent(params.turnId)}/transcript`,
|
|
36233
|
+
errorLabel: "Transcript fetch failed"
|
|
36234
|
+
});
|
|
36235
|
+
if (!fetched.ok) return fetched;
|
|
36236
|
+
const rows = Array.isArray(fetched.data.transcript) ? fetched.data.transcript : [];
|
|
36237
|
+
try {
|
|
36238
|
+
return { ok: true, text: formatParentTranscriptText(rows, params.e2ee) };
|
|
36239
|
+
} catch (error40) {
|
|
36240
|
+
return { ok: false, error: formatCliE2eeDecryptError(error40, params.e2ee) };
|
|
36241
|
+
}
|
|
36242
|
+
}
|
|
36243
|
+
|
|
36244
|
+
// src/mcp/tools/session-history/cloud/resolve-parent-session-id.ts
|
|
36132
36245
|
async function resolveParentSessionIdForChild(params) {
|
|
36133
36246
|
const meta = await fetchCloudSessionMeta({
|
|
36134
36247
|
sessionId: params.childSessionId,
|
|
@@ -36462,7 +36575,7 @@ async function createAcpManager(options) {
|
|
|
36462
36575
|
// src/git/changes/types.ts
|
|
36463
36576
|
var MAX_PATCH_CHARS = 35e4;
|
|
36464
36577
|
|
|
36465
|
-
// src/git/changes/
|
|
36578
|
+
// src/git/changes/paths/repo-format.ts
|
|
36466
36579
|
function posixJoinDirFile(dir, file2) {
|
|
36467
36580
|
const d = dir === "." || dir === "" ? "" : dir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
36468
36581
|
const f = file2.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
@@ -36517,7 +36630,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
36517
36630
|
}
|
|
36518
36631
|
|
|
36519
36632
|
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
36520
|
-
import * as
|
|
36633
|
+
import * as path23 from "node:path";
|
|
36521
36634
|
|
|
36522
36635
|
// src/git/commits/resolve-remote-tracking.ts
|
|
36523
36636
|
async function tryConfigGet(g, key) {
|
|
@@ -36687,9 +36800,232 @@ async function listRecentCommits(repoDir, limitInput) {
|
|
|
36687
36800
|
}
|
|
36688
36801
|
}
|
|
36689
36802
|
|
|
36690
|
-
// src/git/changes/
|
|
36691
|
-
function
|
|
36692
|
-
|
|
36803
|
+
// src/git/changes/parse/normalize-git-diff-path.ts
|
|
36804
|
+
function normalizeGitDiffPath(path48) {
|
|
36805
|
+
return path48.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
|
|
36806
|
+
}
|
|
36807
|
+
|
|
36808
|
+
// src/git/changes/parse/expand-git-rename-numstat-path.ts
|
|
36809
|
+
function expandGitRenameNumstatPath(rawPath) {
|
|
36810
|
+
const open2 = rawPath.indexOf("{");
|
|
36811
|
+
const arrow = rawPath.indexOf("=>");
|
|
36812
|
+
const close = rawPath.lastIndexOf("}");
|
|
36813
|
+
if (open2 === -1 || arrow === -1 || close === -1 || open2 > arrow || arrow > close) {
|
|
36814
|
+
return null;
|
|
36815
|
+
}
|
|
36816
|
+
const prefix = rawPath.slice(0, open2);
|
|
36817
|
+
const suffix = rawPath.slice(close + 1);
|
|
36818
|
+
const oldPart = rawPath.slice(open2 + 1, arrow).trim();
|
|
36819
|
+
const newPart = rawPath.slice(arrow + 2, close).trim();
|
|
36820
|
+
return {
|
|
36821
|
+
oldPath: normalizeGitDiffPath(`${prefix}${oldPart}${suffix}`),
|
|
36822
|
+
newPath: normalizeGitDiffPath(`${prefix}${newPart}${suffix}`)
|
|
36823
|
+
};
|
|
36824
|
+
}
|
|
36825
|
+
function isGitRenameNumstatPath(rawPath) {
|
|
36826
|
+
return expandGitRenameNumstatPath(rawPath) != null;
|
|
36827
|
+
}
|
|
36828
|
+
|
|
36829
|
+
// src/git/changes/rows/build-changed-file-row.ts
|
|
36830
|
+
function buildChangedFileRow(options) {
|
|
36831
|
+
const pathInRepo = normalizeGitDiffPath(options.pathInRepo);
|
|
36832
|
+
const relLauncher = posixJoinDirFile(options.repoRelPath, pathInRepo);
|
|
36833
|
+
const additions = options.numEntry?.additions ?? 0;
|
|
36834
|
+
const deletions = options.numEntry?.deletions ?? 0;
|
|
36835
|
+
let change = options.nameEntry?.change ?? "modified";
|
|
36836
|
+
let movedFromPathRelLauncher;
|
|
36837
|
+
let movedFromPathInRepo;
|
|
36838
|
+
const oldPathInRepo = options.nameEntry?.oldPathInRepo ?? options.numEntry?.oldPathInRepo;
|
|
36839
|
+
if (change === "moved" && oldPathInRepo) {
|
|
36840
|
+
movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
|
|
36841
|
+
movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
|
|
36842
|
+
} else if (oldPathInRepo && change === "modified") {
|
|
36843
|
+
change = "moved";
|
|
36844
|
+
movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
|
|
36845
|
+
movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
|
|
36846
|
+
}
|
|
36847
|
+
if (options.untracked && !options.nameEntry) {
|
|
36848
|
+
change = "added";
|
|
36849
|
+
} else if (!options.nameEntry && options.numEntry && change !== "moved") {
|
|
36850
|
+
if (additions > 0 && deletions === 0) change = "added";
|
|
36851
|
+
else if (deletions > 0 && additions === 0) change = "removed";
|
|
36852
|
+
else change = "modified";
|
|
36853
|
+
}
|
|
36854
|
+
return {
|
|
36855
|
+
pathRelLauncher: relLauncher,
|
|
36856
|
+
additions,
|
|
36857
|
+
deletions,
|
|
36858
|
+
change,
|
|
36859
|
+
...movedFromPathRelLauncher ? { movedFromPathRelLauncher } : {},
|
|
36860
|
+
...movedFromPathInRepo ? { movedFromPathInRepo } : {}
|
|
36861
|
+
};
|
|
36862
|
+
}
|
|
36863
|
+
|
|
36864
|
+
// src/git/changes/listing/build-changed-file-rows.ts
|
|
36865
|
+
async function buildChangedFileRowsFromPaths(options) {
|
|
36866
|
+
const rows = [];
|
|
36867
|
+
await forEachWithGitYield([...options.paths], async (pathInRepo) => {
|
|
36868
|
+
if (isGitRenameNumstatPath(pathInRepo)) return;
|
|
36869
|
+
if (options.movedSourcePaths.has(pathInRepo)) return;
|
|
36870
|
+
const nameEntry = options.nameByPath.get(pathInRepo);
|
|
36871
|
+
const numEntry = options.numByPath.get(pathInRepo);
|
|
36872
|
+
const row = buildChangedFileRow({
|
|
36873
|
+
pathInRepo,
|
|
36874
|
+
repoRelPath: options.repoRelPath,
|
|
36875
|
+
nameEntry,
|
|
36876
|
+
numEntry,
|
|
36877
|
+
untracked: options.untrackedSet?.has(pathInRepo)
|
|
36878
|
+
});
|
|
36879
|
+
if (options.applyUntrackedStats) {
|
|
36880
|
+
await options.applyUntrackedStats(row, pathInRepo);
|
|
36881
|
+
}
|
|
36882
|
+
rows.push(row);
|
|
36883
|
+
});
|
|
36884
|
+
return rows;
|
|
36885
|
+
}
|
|
36886
|
+
|
|
36887
|
+
// src/git/changes/patch/patch-truncate.ts
|
|
36888
|
+
function truncatePatch(s) {
|
|
36889
|
+
if (s.length <= MAX_PATCH_CHARS) return s;
|
|
36890
|
+
return `${s.slice(0, MAX_PATCH_CHARS)}
|
|
36891
|
+
|
|
36892
|
+
\u2026 (diff truncated)`;
|
|
36893
|
+
}
|
|
36894
|
+
|
|
36895
|
+
// src/git/changes/patch/unified-diff-for-file.ts
|
|
36896
|
+
function patchTextFromGitDiffOutput(raw) {
|
|
36897
|
+
if (raw.trim() === "") return void 0;
|
|
36898
|
+
return normalizePatchContent(raw);
|
|
36899
|
+
}
|
|
36900
|
+
async function unifiedDiffForFile(repoCwd, pathInRepo, change, movedFromPathInRepo) {
|
|
36901
|
+
const g = cliSimpleGit(repoCwd);
|
|
36902
|
+
const renameArgs = ["-M", "--find-renames"];
|
|
36903
|
+
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];
|
|
36904
|
+
const raw = await g.raw([...args]).catch(() => "");
|
|
36905
|
+
const patch = patchTextFromGitDiffOutput(String(raw));
|
|
36906
|
+
return patch ? truncatePatch(patch) : void 0;
|
|
36907
|
+
}
|
|
36908
|
+
async function unifiedDiffForFileInRange(repoCwd, range, pathInRepo, change, movedFromPathInRepo) {
|
|
36909
|
+
const g = cliSimpleGit(repoCwd);
|
|
36910
|
+
const renameArgs = ["-M", "--find-renames"];
|
|
36911
|
+
const args = change === "moved" && movedFromPathInRepo ? ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", movedFromPathInRepo, pathInRepo] : ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", pathInRepo];
|
|
36912
|
+
const raw = await g.raw([...args]).catch(() => "");
|
|
36913
|
+
const patch = patchTextFromGitDiffOutput(String(raw));
|
|
36914
|
+
return patch ? truncatePatch(patch) : void 0;
|
|
36915
|
+
}
|
|
36916
|
+
|
|
36917
|
+
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
36918
|
+
import * as fs17 from "node:fs";
|
|
36919
|
+
import * as path20 from "node:path";
|
|
36920
|
+
|
|
36921
|
+
// src/git/changes/lines/count-lines.ts
|
|
36922
|
+
import { createReadStream } from "node:fs";
|
|
36923
|
+
import * as readline2 from "node:readline";
|
|
36924
|
+
function countLinesInText(text) {
|
|
36925
|
+
return splitTextIntoDiffLines(text).length;
|
|
36926
|
+
}
|
|
36927
|
+
async function countTextFileLines(filePath) {
|
|
36928
|
+
let bytes = 0;
|
|
36929
|
+
const maxBytes = 512e3;
|
|
36930
|
+
let lines = 0;
|
|
36931
|
+
const stream = createReadStream(filePath, { encoding: "utf8" });
|
|
36932
|
+
const rl = readline2.createInterface({ input: stream, crlfDelay: Infinity });
|
|
36933
|
+
for await (const _line of rl) {
|
|
36934
|
+
lines += 1;
|
|
36935
|
+
bytes += Buffer.byteLength(String(_line), "utf8") + 1;
|
|
36936
|
+
if (bytes > maxBytes) {
|
|
36937
|
+
rl.close();
|
|
36938
|
+
stream.destroy();
|
|
36939
|
+
return lines;
|
|
36940
|
+
}
|
|
36941
|
+
}
|
|
36942
|
+
return lines;
|
|
36943
|
+
}
|
|
36944
|
+
|
|
36945
|
+
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
36946
|
+
var MAX_BYTES = 512e3;
|
|
36947
|
+
async function countLinesInGitRef(repoGitCwd, ref, pathInRepo) {
|
|
36948
|
+
const spec = `${ref}:${pathInRepo}`;
|
|
36949
|
+
const g = cliSimpleGit(repoGitCwd);
|
|
36950
|
+
try {
|
|
36951
|
+
await g.raw(["cat-file", "-e", spec]);
|
|
36952
|
+
} catch {
|
|
36953
|
+
return null;
|
|
36954
|
+
}
|
|
36955
|
+
try {
|
|
36956
|
+
const raw = String(await g.raw(["show", spec]));
|
|
36957
|
+
const capped = raw.length > MAX_BYTES ? raw.slice(0, MAX_BYTES) : raw;
|
|
36958
|
+
return countLinesInText(capped);
|
|
36959
|
+
} catch {
|
|
36960
|
+
return null;
|
|
36961
|
+
}
|
|
36962
|
+
}
|
|
36963
|
+
async function resolveWorkingTreeFileTotalLines(options) {
|
|
36964
|
+
if (options.isBinary) return null;
|
|
36965
|
+
const filePath = path20.join(options.repoGitCwd, options.pathInRepo);
|
|
36966
|
+
if (options.change === "removed") {
|
|
36967
|
+
return countLinesInGitRef(options.repoGitCwd, "HEAD", options.pathInRepo);
|
|
36968
|
+
}
|
|
36969
|
+
if (options.change === "moved" || options.change === "modified") {
|
|
36970
|
+
try {
|
|
36971
|
+
const st = await fs17.promises.stat(filePath);
|
|
36972
|
+
if (!st.isFile()) return null;
|
|
36973
|
+
return await countTextFileLines(filePath);
|
|
36974
|
+
} catch {
|
|
36975
|
+
return null;
|
|
36976
|
+
}
|
|
36977
|
+
}
|
|
36978
|
+
return null;
|
|
36979
|
+
}
|
|
36980
|
+
async function resolveCommitFileTotalLines(options) {
|
|
36981
|
+
if (options.isBinary) return null;
|
|
36982
|
+
if (options.change === "removed") {
|
|
36983
|
+
return countLinesInGitRef(options.repoGitCwd, options.parentSha, options.pathInRepo);
|
|
36984
|
+
}
|
|
36985
|
+
if (options.change === "moved" || options.change === "modified") {
|
|
36986
|
+
return countLinesInGitRef(options.repoGitCwd, options.commitSha, options.pathInRepo);
|
|
36987
|
+
}
|
|
36988
|
+
return null;
|
|
36989
|
+
}
|
|
36990
|
+
|
|
36991
|
+
// src/git/changes/listing/path-in-repo-from-launcher.ts
|
|
36992
|
+
function pathInRepoFromLauncher(pathRelLauncher, repoRelPath) {
|
|
36993
|
+
const normRel = repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
36994
|
+
if (normRel === ".") return pathRelLauncher;
|
|
36995
|
+
if (pathRelLauncher.startsWith(`${normRel}/`)) {
|
|
36996
|
+
return pathRelLauncher.slice(normRel.length + 1);
|
|
36997
|
+
}
|
|
36998
|
+
return pathRelLauncher;
|
|
36999
|
+
}
|
|
37000
|
+
function normalizeRepoRelPath(repoRelPath) {
|
|
37001
|
+
return repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
37002
|
+
}
|
|
37003
|
+
|
|
37004
|
+
// src/git/changes/listing/enrich-commit-file-rows.ts
|
|
37005
|
+
async function enrichCommitFileRows(options) {
|
|
37006
|
+
await forEachWithGitYield(options.rows, async (row) => {
|
|
37007
|
+
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
37008
|
+
row.patchContent = await unifiedDiffForFileInRange(
|
|
37009
|
+
options.repoGitCwd,
|
|
37010
|
+
options.range,
|
|
37011
|
+
pathInRepo,
|
|
37012
|
+
row.change,
|
|
37013
|
+
row.movedFromPathInRepo
|
|
37014
|
+
);
|
|
37015
|
+
row.totalLines = await resolveCommitFileTotalLines({
|
|
37016
|
+
repoGitCwd: options.repoGitCwd,
|
|
37017
|
+
pathInRepo,
|
|
37018
|
+
change: row.change,
|
|
37019
|
+
commitSha: options.commitSha,
|
|
37020
|
+
parentSha: options.parentSha,
|
|
37021
|
+
isBinary: options.binaryByPath.has(pathInRepo)
|
|
37022
|
+
});
|
|
37023
|
+
});
|
|
37024
|
+
}
|
|
37025
|
+
|
|
37026
|
+
// src/git/changes/parse/parse-name-status-entries.ts
|
|
37027
|
+
function parseNameStatusEntries(lines) {
|
|
37028
|
+
const entries = [];
|
|
36693
37029
|
for (const line of lines) {
|
|
36694
37030
|
if (!line.trim()) continue;
|
|
36695
37031
|
const tabParts = line.split(" ");
|
|
@@ -36697,58 +37033,143 @@ function parseNameStatusLines(lines) {
|
|
|
36697
37033
|
const status = tabParts[0].trim();
|
|
36698
37034
|
const code = status[0];
|
|
36699
37035
|
if (code === "A") {
|
|
36700
|
-
|
|
37036
|
+
entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "added" });
|
|
36701
37037
|
} else if (code === "D") {
|
|
36702
|
-
|
|
37038
|
+
entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "removed" });
|
|
36703
37039
|
} else if (code === "R" || code === "C") {
|
|
36704
|
-
if (tabParts.length >= 3)
|
|
37040
|
+
if (tabParts.length >= 3) {
|
|
37041
|
+
entries.push({
|
|
37042
|
+
pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]),
|
|
37043
|
+
oldPathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 2]),
|
|
37044
|
+
change: "moved"
|
|
37045
|
+
});
|
|
37046
|
+
}
|
|
36705
37047
|
} else if (code === "M" || code === "U" || code === "T") {
|
|
36706
|
-
|
|
37048
|
+
entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "modified" });
|
|
36707
37049
|
}
|
|
36708
37050
|
}
|
|
37051
|
+
return entries;
|
|
37052
|
+
}
|
|
37053
|
+
function parseNameStatusLines(lines) {
|
|
37054
|
+
const m = /* @__PURE__ */ new Map();
|
|
37055
|
+
for (const entry of parseNameStatusEntries(lines)) {
|
|
37056
|
+
m.set(entry.pathInRepo, entry.change);
|
|
37057
|
+
}
|
|
36709
37058
|
return m;
|
|
36710
37059
|
}
|
|
36711
|
-
|
|
37060
|
+
|
|
37061
|
+
// src/git/changes/parse/parse-numstat-entries.ts
|
|
37062
|
+
function parseNumstatCounts(parts) {
|
|
37063
|
+
const [a, d] = parts;
|
|
37064
|
+
return {
|
|
37065
|
+
additions: a === "-" ? 0 : parseInt(String(a), 10) || 0,
|
|
37066
|
+
deletions: d === "-" ? 0 : parseInt(String(d), 10) || 0
|
|
37067
|
+
};
|
|
37068
|
+
}
|
|
37069
|
+
function parseNumstatLine(line) {
|
|
36712
37070
|
const parts = line.split(" ");
|
|
36713
37071
|
if (parts.length < 3) return null;
|
|
36714
|
-
const
|
|
36715
|
-
const additions
|
|
36716
|
-
const
|
|
36717
|
-
|
|
37072
|
+
const rawPath = parts[parts.length - 1];
|
|
37073
|
+
const { additions, deletions } = parseNumstatCounts(parts);
|
|
37074
|
+
const expanded = expandGitRenameNumstatPath(rawPath);
|
|
37075
|
+
const pathInRepo = normalizeGitDiffPath(expanded?.newPath ?? rawPath);
|
|
37076
|
+
return {
|
|
37077
|
+
pathInRepo,
|
|
37078
|
+
additions,
|
|
37079
|
+
deletions,
|
|
37080
|
+
...expanded ? { oldPathInRepo: expanded.oldPath } : {}
|
|
37081
|
+
};
|
|
36718
37082
|
}
|
|
36719
|
-
function
|
|
37083
|
+
function parseNumstatEntries(lines) {
|
|
36720
37084
|
const m = /* @__PURE__ */ new Map();
|
|
36721
37085
|
for (const line of lines) {
|
|
36722
37086
|
if (!line.trim()) continue;
|
|
36723
37087
|
const parts = line.split(" ");
|
|
36724
37088
|
if (parts.length < 3) continue;
|
|
36725
|
-
const [
|
|
36726
|
-
const
|
|
36727
|
-
const
|
|
36728
|
-
|
|
37089
|
+
const rawPath = parts[parts.length - 1];
|
|
37090
|
+
const expanded = expandGitRenameNumstatPath(rawPath);
|
|
37091
|
+
const entry = parseNumstatLine(line);
|
|
37092
|
+
if (!entry) continue;
|
|
37093
|
+
const existing = m.get(entry.pathInRepo);
|
|
37094
|
+
if (!existing || expanded) {
|
|
37095
|
+
m.set(entry.pathInRepo, entry);
|
|
37096
|
+
}
|
|
36729
37097
|
}
|
|
36730
37098
|
return m;
|
|
36731
37099
|
}
|
|
37100
|
+
function parseNumstat(lines) {
|
|
37101
|
+
const m = /* @__PURE__ */ new Map();
|
|
37102
|
+
for (const [path48, entry] of parseNumstatEntries(lines)) {
|
|
37103
|
+
m.set(path48, { additions: entry.additions, deletions: entry.deletions });
|
|
37104
|
+
}
|
|
37105
|
+
return m;
|
|
37106
|
+
}
|
|
37107
|
+
|
|
37108
|
+
// src/git/changes/parse/numstat-from-git-no-index.ts
|
|
36732
37109
|
async function numstatFromGitNoIndex(g, pathInRepo) {
|
|
36733
37110
|
const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
36734
37111
|
try {
|
|
36735
37112
|
const out = await g.raw(["diff", "--numstat", "--no-index", "--", devNull, pathInRepo]);
|
|
36736
37113
|
const first2 = String(out).split("\n").find((l) => l.trim()) ?? "";
|
|
36737
|
-
|
|
37114
|
+
const parsed = parseNumstatLine(first2);
|
|
37115
|
+
if (!parsed) return null;
|
|
37116
|
+
return { additions: parsed.additions, deletions: parsed.deletions };
|
|
36738
37117
|
} catch {
|
|
36739
37118
|
return null;
|
|
36740
37119
|
}
|
|
36741
37120
|
}
|
|
36742
37121
|
|
|
36743
|
-
// src/git/changes/
|
|
36744
|
-
function
|
|
36745
|
-
|
|
36746
|
-
|
|
37122
|
+
// src/git/changes/rows/collect-moved-source-paths.ts
|
|
37123
|
+
function collectMovedSourcePaths(nameEntries, numByPath) {
|
|
37124
|
+
const sources = /* @__PURE__ */ new Set();
|
|
37125
|
+
for (const entry of nameEntries) {
|
|
37126
|
+
if (entry.change === "moved" && entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
|
|
37127
|
+
}
|
|
37128
|
+
for (const entry of numByPath.values()) {
|
|
37129
|
+
if (entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
|
|
37130
|
+
}
|
|
37131
|
+
return sources;
|
|
37132
|
+
}
|
|
36747
37133
|
|
|
36748
|
-
|
|
37134
|
+
// src/git/changes/numstat/is-binary-numstat-line.ts
|
|
37135
|
+
function isBinaryNumstatLine(line) {
|
|
37136
|
+
const parts = line.split(" ");
|
|
37137
|
+
if (parts.length < 3) return false;
|
|
37138
|
+
return parts[0] === "-" || parts[1] === "-";
|
|
37139
|
+
}
|
|
37140
|
+
|
|
37141
|
+
// src/git/changes/listing/collect-binary-paths-from-numstat.ts
|
|
37142
|
+
function collectBinaryPathsFromNumstat(numstatRaw) {
|
|
37143
|
+
const binaryByPath = /* @__PURE__ */ new Set();
|
|
37144
|
+
for (const line of numstatRaw.split("\n")) {
|
|
37145
|
+
if (!line.trim()) continue;
|
|
37146
|
+
const parts = line.split(" ");
|
|
37147
|
+
if (parts.length < 3) continue;
|
|
37148
|
+
const rawPath = parts[parts.length - 1];
|
|
37149
|
+
const expanded = expandGitRenameNumstatPath(rawPath);
|
|
37150
|
+
if (isBinaryNumstatLine(line)) binaryByPath.add(expanded?.newPath ?? rawPath);
|
|
37151
|
+
}
|
|
37152
|
+
return binaryByPath;
|
|
37153
|
+
}
|
|
37154
|
+
|
|
37155
|
+
// src/git/changes/listing/parse-diff-output.ts
|
|
37156
|
+
function parseDiffOutput(nameStatusRaw, numstatRaw) {
|
|
37157
|
+
const nameEntries = parseNameStatusEntries(nameStatusRaw.split("\n"));
|
|
37158
|
+
const nameByPath = new Map(nameEntries.map((entry) => [entry.pathInRepo, entry]));
|
|
37159
|
+
const numByPath = parseNumstatEntries(numstatRaw.split("\n"));
|
|
37160
|
+
const movedSourcePaths = collectMovedSourcePaths(nameEntries, numByPath);
|
|
37161
|
+
const binaryByPath = collectBinaryPathsFromNumstat(numstatRaw);
|
|
37162
|
+
return { nameEntries, nameByPath, numByPath, movedSourcePaths, binaryByPath };
|
|
37163
|
+
}
|
|
37164
|
+
function collectChangedPaths(options) {
|
|
37165
|
+
const paths = /* @__PURE__ */ new Set();
|
|
37166
|
+
for (const entry of options.nameEntries) paths.add(entry.pathInRepo);
|
|
37167
|
+
for (const pathInRepo of options.numByPath.keys()) paths.add(pathInRepo);
|
|
37168
|
+
for (const pathInRepo of options.untracked ?? []) paths.add(pathInRepo);
|
|
37169
|
+
return paths;
|
|
36749
37170
|
}
|
|
36750
37171
|
|
|
36751
|
-
// src/git/
|
|
37172
|
+
// src/git/changes/listing/parent-for-commit-diff.ts
|
|
36752
37173
|
var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
36753
37174
|
async function parentForCommitDiff(g, sha) {
|
|
36754
37175
|
try {
|
|
@@ -36761,76 +37182,112 @@ async function parentForCommitDiff(g, sha) {
|
|
|
36761
37182
|
}
|
|
36762
37183
|
}
|
|
36763
37184
|
}
|
|
37185
|
+
|
|
37186
|
+
// src/git/changes/listing/rename-diff-args.ts
|
|
37187
|
+
var RENAME_DIFF_ARGS = ["-M", "--find-renames"];
|
|
37188
|
+
|
|
37189
|
+
// src/git/changes/rows/pick-preferred-changed-file-row.ts
|
|
37190
|
+
function rowRank(row) {
|
|
37191
|
+
if (row.change === "moved") return 3;
|
|
37192
|
+
if (row.change === "modified") return 2;
|
|
37193
|
+
if (row.change === "added") return 1;
|
|
37194
|
+
return 0;
|
|
37195
|
+
}
|
|
37196
|
+
function pickPreferredChangedFileRow(a, b) {
|
|
37197
|
+
if (rowRank(a) !== rowRank(b)) return rowRank(a) > rowRank(b) ? a : b;
|
|
37198
|
+
const aHasPatch = Boolean(a.patchContent?.trim());
|
|
37199
|
+
const bHasPatch = Boolean(b.patchContent?.trim());
|
|
37200
|
+
if (aHasPatch !== bHasPatch) return aHasPatch ? a : b;
|
|
37201
|
+
const aHasMoveMeta = Boolean(a.movedFromPathInRepo || a.movedFromPathRelLauncher);
|
|
37202
|
+
const bHasMoveMeta = Boolean(b.movedFromPathInRepo || b.movedFromPathRelLauncher);
|
|
37203
|
+
if (aHasMoveMeta !== bHasMoveMeta) return aHasMoveMeta ? a : b;
|
|
37204
|
+
return a;
|
|
37205
|
+
}
|
|
37206
|
+
|
|
37207
|
+
// src/git/changes/rows/dedupe-changed-file-rows.ts
|
|
37208
|
+
function dedupeChangedFileRows(rows) {
|
|
37209
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
37210
|
+
for (const row of rows) {
|
|
37211
|
+
const key = normalizeGitDiffPath(row.pathRelLauncher);
|
|
37212
|
+
const normalizedRow = key === row.pathRelLauncher ? row : { ...row, pathRelLauncher: key };
|
|
37213
|
+
const existing = byPath.get(key);
|
|
37214
|
+
if (!existing) {
|
|
37215
|
+
byPath.set(key, normalizedRow);
|
|
37216
|
+
continue;
|
|
37217
|
+
}
|
|
37218
|
+
const preferRow = pickPreferredChangedFileRow(existing, normalizedRow);
|
|
37219
|
+
byPath.set(key, { ...preferRow, pathRelLauncher: key });
|
|
37220
|
+
}
|
|
37221
|
+
return [...byPath.values()];
|
|
37222
|
+
}
|
|
37223
|
+
|
|
37224
|
+
// src/git/changes/listing/list-changed-files-for-commit.ts
|
|
36764
37225
|
async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
36765
37226
|
const g = cliSimpleGit(repoGitCwd);
|
|
36766
37227
|
const parent = await parentForCommitDiff(g, commitSha);
|
|
36767
37228
|
const range = `${parent}..${commitSha}`;
|
|
36768
37229
|
const [nameStatusRaw, numstatRaw] = await Promise.all([
|
|
36769
|
-
g.raw(["diff", "--name-status", range]).catch(() => ""),
|
|
36770
|
-
g.raw(["diff", "--numstat", range]).catch(() => "")
|
|
37230
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", range]).catch(() => ""),
|
|
37231
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "--numstat", range]).catch(() => "")
|
|
36771
37232
|
]);
|
|
36772
|
-
const
|
|
36773
|
-
const
|
|
36774
|
-
const paths =
|
|
36775
|
-
|
|
36776
|
-
|
|
36777
|
-
await forEachWithGitYield([...paths], async (pathInRepo) => {
|
|
36778
|
-
const relLauncher = posixJoinDirFile(normRel, pathInRepo.replace(/\\/g, "/"));
|
|
36779
|
-
const nums = numByPath.get(pathInRepo);
|
|
36780
|
-
let additions = nums?.additions ?? 0;
|
|
36781
|
-
let deletions = nums?.deletions ?? 0;
|
|
36782
|
-
let change = kindByPath.get(pathInRepo) ?? "modified";
|
|
36783
|
-
if (!kindByPath.has(pathInRepo) && nums) {
|
|
36784
|
-
if (additions > 0 && deletions === 0) change = "added";
|
|
36785
|
-
else if (deletions > 0 && additions === 0) change = "removed";
|
|
36786
|
-
else change = "modified";
|
|
36787
|
-
}
|
|
36788
|
-
rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
|
|
36789
|
-
});
|
|
36790
|
-
await forEachWithGitYield(rows, async (row) => {
|
|
36791
|
-
let pathInRepo;
|
|
36792
|
-
if (normRel === ".") {
|
|
36793
|
-
pathInRepo = row.pathRelLauncher;
|
|
36794
|
-
} else if (row.pathRelLauncher.startsWith(`${normRel}/`)) {
|
|
36795
|
-
pathInRepo = row.pathRelLauncher.slice(normRel.length + 1);
|
|
36796
|
-
} else {
|
|
36797
|
-
pathInRepo = row.pathRelLauncher;
|
|
36798
|
-
}
|
|
36799
|
-
const raw = await g.raw(["diff", "-U20000", range, "--", pathInRepo]).catch(() => "");
|
|
36800
|
-
const t = String(raw).trim();
|
|
36801
|
-
row.patchContent = t ? truncatePatch(t) : void 0;
|
|
37233
|
+
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
37234
|
+
const normRel = normalizeRepoRelPath(repoRelPath);
|
|
37235
|
+
const paths = collectChangedPaths({
|
|
37236
|
+
nameEntries: parsed.nameEntries,
|
|
37237
|
+
numByPath: parsed.numByPath
|
|
36802
37238
|
});
|
|
36803
|
-
rows
|
|
36804
|
-
|
|
36805
|
-
|
|
36806
|
-
|
|
36807
|
-
|
|
37239
|
+
let rows = await buildChangedFileRowsFromPaths({
|
|
37240
|
+
paths,
|
|
37241
|
+
repoRelPath: normRel,
|
|
37242
|
+
nameByPath: parsed.nameByPath,
|
|
37243
|
+
numByPath: parsed.numByPath,
|
|
37244
|
+
movedSourcePaths: parsed.movedSourcePaths
|
|
37245
|
+
});
|
|
37246
|
+
rows = dedupeChangedFileRows(rows);
|
|
37247
|
+
await enrichCommitFileRows({
|
|
37248
|
+
rows,
|
|
37249
|
+
repoGitCwd,
|
|
37250
|
+
repoRelPath: normRel,
|
|
37251
|
+
range,
|
|
37252
|
+
commitSha,
|
|
37253
|
+
parentSha: parent,
|
|
37254
|
+
binaryByPath: parsed.binaryByPath
|
|
37255
|
+
});
|
|
37256
|
+
const finalRows = dedupeChangedFileRows(rows);
|
|
37257
|
+
finalRows.sort((a, b) => a.pathRelLauncher.localeCompare(b.pathRelLauncher));
|
|
37258
|
+
return finalRows;
|
|
37259
|
+
}
|
|
37260
|
+
|
|
37261
|
+
// src/git/changes/listing/apply-untracked-file-stats.ts
|
|
36808
37262
|
import * as fs18 from "node:fs";
|
|
36809
|
-
import * as
|
|
36810
|
-
|
|
36811
|
-
|
|
36812
|
-
|
|
36813
|
-
|
|
36814
|
-
|
|
36815
|
-
|
|
36816
|
-
|
|
36817
|
-
|
|
36818
|
-
|
|
36819
|
-
|
|
36820
|
-
|
|
36821
|
-
lines += 1;
|
|
36822
|
-
bytes += Buffer.byteLength(String(_line), "utf8") + 1;
|
|
36823
|
-
if (bytes > maxBytes) {
|
|
36824
|
-
rl.close();
|
|
36825
|
-
stream.destroy();
|
|
36826
|
-
return lines;
|
|
37263
|
+
import * as path21 from "node:path";
|
|
37264
|
+
function createUntrackedStatsApplier(options) {
|
|
37265
|
+
return async (row, pathInRepo) => {
|
|
37266
|
+
if (!options.untrackedSet.has(pathInRepo)) return;
|
|
37267
|
+
if (options.nameByPath.has(pathInRepo)) return;
|
|
37268
|
+
if (row.change === "moved") return;
|
|
37269
|
+
const repoFilePath = path21.join(options.repoGitCwd, pathInRepo);
|
|
37270
|
+
const fromGit = await numstatFromGitNoIndex(options.g, pathInRepo);
|
|
37271
|
+
if (fromGit) {
|
|
37272
|
+
row.additions = fromGit.additions;
|
|
37273
|
+
row.deletions = fromGit.deletions;
|
|
37274
|
+
return;
|
|
36827
37275
|
}
|
|
36828
|
-
|
|
36829
|
-
|
|
37276
|
+
try {
|
|
37277
|
+
const st = await fs18.promises.stat(repoFilePath);
|
|
37278
|
+
row.additions = st.isFile() ? await countTextFileLines(repoFilePath) : 0;
|
|
37279
|
+
} catch {
|
|
37280
|
+
row.additions = 0;
|
|
37281
|
+
}
|
|
37282
|
+
row.deletions = 0;
|
|
37283
|
+
};
|
|
36830
37284
|
}
|
|
36831
37285
|
|
|
36832
|
-
// src/git/changes/
|
|
36833
|
-
import * as
|
|
37286
|
+
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
37287
|
+
import * as path22 from "node:path";
|
|
37288
|
+
|
|
37289
|
+
// src/git/changes/patch/hydrate-patch.ts
|
|
37290
|
+
import * as fs19 from "node:fs";
|
|
36834
37291
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
36835
37292
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
36836
37293
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -36845,7 +37302,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
36845
37302
|
}
|
|
36846
37303
|
async function readWorktreeFileLines(filePath) {
|
|
36847
37304
|
try {
|
|
36848
|
-
const raw = await
|
|
37305
|
+
const raw = await fs19.promises.readFile(filePath, "utf8");
|
|
36849
37306
|
return raw.split(/\r?\n/);
|
|
36850
37307
|
} catch {
|
|
36851
37308
|
return null;
|
|
@@ -36945,82 +37402,70 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
36945
37402
|
return truncatePatch(out.join("\n"));
|
|
36946
37403
|
}
|
|
36947
37404
|
|
|
36948
|
-
// src/git/changes/
|
|
36949
|
-
function
|
|
36950
|
-
|
|
36951
|
-
|
|
36952
|
-
|
|
36953
|
-
|
|
36954
|
-
|
|
36955
|
-
|
|
36956
|
-
|
|
36957
|
-
|
|
36958
|
-
|
|
37405
|
+
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
37406
|
+
async function enrichWorkingTreeFileRows(options) {
|
|
37407
|
+
await forEachWithGitYield(options.rows, async (row) => {
|
|
37408
|
+
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
37409
|
+
const filePath = path22.join(options.repoGitCwd, pathInRepo);
|
|
37410
|
+
const hydrateKind = row.change === "moved" ? "modified" : row.change;
|
|
37411
|
+
let patch = await unifiedDiffForFile(options.repoGitCwd, pathInRepo, row.change, row.movedFromPathInRepo);
|
|
37412
|
+
if (patch) {
|
|
37413
|
+
patch = await hydrateUnifiedPatchWithFileContext(
|
|
37414
|
+
patch,
|
|
37415
|
+
filePath,
|
|
37416
|
+
options.repoGitCwd,
|
|
37417
|
+
pathInRepo,
|
|
37418
|
+
hydrateKind
|
|
37419
|
+
);
|
|
37420
|
+
}
|
|
37421
|
+
row.patchContent = patch;
|
|
37422
|
+
row.totalLines = await resolveWorkingTreeFileTotalLines({
|
|
37423
|
+
repoGitCwd: options.repoGitCwd,
|
|
37424
|
+
pathInRepo,
|
|
37425
|
+
change: row.change,
|
|
37426
|
+
isBinary: options.binaryByPath.has(pathInRepo)
|
|
37427
|
+
});
|
|
37428
|
+
});
|
|
36959
37429
|
}
|
|
36960
37430
|
|
|
36961
|
-
// src/git/changes/list-changed-files-for-repo.ts
|
|
37431
|
+
// src/git/changes/listing/list-changed-files-for-repo.ts
|
|
36962
37432
|
async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
36963
37433
|
const g = cliSimpleGit(repoGitCwd);
|
|
36964
37434
|
const [nameStatusRaw, numstatRaw, untrackedRaw] = await Promise.all([
|
|
36965
|
-
g.raw(["diff", "--name-status", "HEAD"]).catch(() => ""),
|
|
36966
|
-
g.raw(["diff", "HEAD", "--numstat"]).catch(() => ""),
|
|
37435
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", "HEAD"]).catch(() => ""),
|
|
37436
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "HEAD", "--numstat"]).catch(() => ""),
|
|
36967
37437
|
g.raw(["ls-files", "--others", "--exclude-standard"]).catch(() => "")
|
|
36968
37438
|
]);
|
|
36969
|
-
const
|
|
36970
|
-
const numByPath = parseNumstat(String(numstatRaw).split("\n"));
|
|
36971
|
-
const paths = /* @__PURE__ */ new Set([...kindByPath.keys(), ...numByPath.keys()]);
|
|
37439
|
+
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
36972
37440
|
const untracked = String(untrackedRaw).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
36973
|
-
|
|
36974
|
-
const
|
|
36975
|
-
|
|
36976
|
-
|
|
36977
|
-
|
|
36978
|
-
const nums = numByPath.get(pathInRepo);
|
|
36979
|
-
let additions = nums?.additions ?? 0;
|
|
36980
|
-
let deletions = nums?.deletions ?? 0;
|
|
36981
|
-
let change = kindByPath.get(pathInRepo) ?? "modified";
|
|
36982
|
-
if (untracked.includes(pathInRepo) && !kindByPath.has(pathInRepo)) {
|
|
36983
|
-
change = "added";
|
|
36984
|
-
const fromGit = await numstatFromGitNoIndex(g, pathInRepo);
|
|
36985
|
-
if (fromGit) {
|
|
36986
|
-
additions = fromGit.additions;
|
|
36987
|
-
deletions = fromGit.deletions;
|
|
36988
|
-
} else {
|
|
36989
|
-
try {
|
|
36990
|
-
const st = await fs18.promises.stat(repoFilePath);
|
|
36991
|
-
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
36992
|
-
else additions = 0;
|
|
36993
|
-
} catch {
|
|
36994
|
-
additions = 0;
|
|
36995
|
-
}
|
|
36996
|
-
deletions = 0;
|
|
36997
|
-
}
|
|
36998
|
-
}
|
|
36999
|
-
if (!kindByPath.has(pathInRepo) && nums) {
|
|
37000
|
-
if (additions > 0 && deletions === 0) change = "added";
|
|
37001
|
-
else if (deletions > 0 && additions === 0) change = "removed";
|
|
37002
|
-
else change = "modified";
|
|
37003
|
-
}
|
|
37004
|
-
rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
|
|
37441
|
+
const untrackedSet = new Set(untracked);
|
|
37442
|
+
const paths = collectChangedPaths({
|
|
37443
|
+
nameEntries: parsed.nameEntries,
|
|
37444
|
+
numByPath: parsed.numByPath,
|
|
37445
|
+
untracked
|
|
37005
37446
|
});
|
|
37006
|
-
|
|
37007
|
-
|
|
37008
|
-
|
|
37009
|
-
|
|
37010
|
-
|
|
37011
|
-
|
|
37012
|
-
|
|
37013
|
-
|
|
37014
|
-
|
|
37015
|
-
|
|
37016
|
-
|
|
37017
|
-
|
|
37018
|
-
|
|
37019
|
-
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
37020
|
-
}
|
|
37021
|
-
row.patchContent = patch;
|
|
37447
|
+
let rows = await buildChangedFileRowsFromPaths({
|
|
37448
|
+
paths,
|
|
37449
|
+
repoRelPath,
|
|
37450
|
+
nameByPath: parsed.nameByPath,
|
|
37451
|
+
numByPath: parsed.numByPath,
|
|
37452
|
+
movedSourcePaths: parsed.movedSourcePaths,
|
|
37453
|
+
untrackedSet,
|
|
37454
|
+
applyUntrackedStats: createUntrackedStatsApplier({
|
|
37455
|
+
g,
|
|
37456
|
+
repoGitCwd,
|
|
37457
|
+
untrackedSet,
|
|
37458
|
+
nameByPath: parsed.nameByPath
|
|
37459
|
+
})
|
|
37022
37460
|
});
|
|
37023
|
-
|
|
37461
|
+
rows = dedupeChangedFileRows(rows);
|
|
37462
|
+
await enrichWorkingTreeFileRows({
|
|
37463
|
+
rows,
|
|
37464
|
+
repoGitCwd,
|
|
37465
|
+
repoRelPath,
|
|
37466
|
+
binaryByPath: parsed.binaryByPath
|
|
37467
|
+
});
|
|
37468
|
+
return dedupeChangedFileRows(rows);
|
|
37024
37469
|
}
|
|
37025
37470
|
|
|
37026
37471
|
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
@@ -37029,8 +37474,8 @@ function normRepoRel(p) {
|
|
|
37029
37474
|
return x === "" ? "." : x;
|
|
37030
37475
|
}
|
|
37031
37476
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
37032
|
-
const bridgeRoot =
|
|
37033
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
37477
|
+
const bridgeRoot = path23.resolve(getBridgeRoot());
|
|
37478
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path23.resolve(options.sessionWorktreeRootPath) : null;
|
|
37034
37479
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
37035
37480
|
const out = [];
|
|
37036
37481
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -37045,7 +37490,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
37045
37490
|
for (let i = 0; i < options.commitTargetPaths.length; i++) {
|
|
37046
37491
|
if (i > 0) await yieldToEventLoop2();
|
|
37047
37492
|
const target = options.commitTargetPaths[i];
|
|
37048
|
-
const t =
|
|
37493
|
+
const t = path23.resolve(target);
|
|
37049
37494
|
if (!await isGitRepoDirectory(t)) continue;
|
|
37050
37495
|
const g = cliSimpleGit(t);
|
|
37051
37496
|
let branch = "HEAD";
|
|
@@ -37058,8 +37503,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
37058
37503
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
37059
37504
|
let repoRelPath;
|
|
37060
37505
|
if (sessionWtRoot) {
|
|
37061
|
-
const anchor = legacyNested ?
|
|
37062
|
-
const relNorm =
|
|
37506
|
+
const anchor = legacyNested ? path23.dirname(t) : t;
|
|
37507
|
+
const relNorm = path23.relative(sessionWtRoot, anchor);
|
|
37063
37508
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
37064
37509
|
} else {
|
|
37065
37510
|
let top = t;
|
|
@@ -37068,8 +37513,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
37068
37513
|
} catch {
|
|
37069
37514
|
top = t;
|
|
37070
37515
|
}
|
|
37071
|
-
const rel =
|
|
37072
|
-
repoRelPath = rel.startsWith("..") ?
|
|
37516
|
+
const rel = path23.relative(bridgeRoot, path23.resolve(top)).replace(/\\/g, "/") || ".";
|
|
37517
|
+
repoRelPath = rel.startsWith("..") ? path23.basename(path23.resolve(top)) : rel;
|
|
37073
37518
|
}
|
|
37074
37519
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
37075
37520
|
if (filter && norm !== filter) continue;
|
|
@@ -37101,7 +37546,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
37101
37546
|
return out;
|
|
37102
37547
|
}
|
|
37103
37548
|
|
|
37104
|
-
// src/git/changes/
|
|
37549
|
+
// src/git/changes/status/working-tree-changed-path-count.ts
|
|
37105
37550
|
function workingTreeChangedPathCount(nameStatusLines, numstatLines, untrackedLines) {
|
|
37106
37551
|
const kindByPath = parseNameStatusLines(nameStatusLines);
|
|
37107
37552
|
const numByPath = parseNumstat(numstatLines);
|
|
@@ -37197,23 +37642,23 @@ async function commitSessionWorktrees(options) {
|
|
|
37197
37642
|
}
|
|
37198
37643
|
|
|
37199
37644
|
// src/worktrees/remove-session-worktrees.ts
|
|
37200
|
-
import * as
|
|
37645
|
+
import * as fs22 from "node:fs";
|
|
37201
37646
|
|
|
37202
37647
|
// src/git/worktrees/worktree-remove.ts
|
|
37203
|
-
import * as
|
|
37648
|
+
import * as fs21 from "node:fs";
|
|
37204
37649
|
|
|
37205
37650
|
// src/git/worktrees/resolve-main-repo-from-git-file.ts
|
|
37206
|
-
import * as
|
|
37207
|
-
import * as
|
|
37651
|
+
import * as fs20 from "node:fs";
|
|
37652
|
+
import * as path24 from "node:path";
|
|
37208
37653
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
37209
|
-
const gitDirFile =
|
|
37210
|
-
if (!
|
|
37211
|
-
const first2 =
|
|
37654
|
+
const gitDirFile = path24.join(wt, ".git");
|
|
37655
|
+
if (!fs20.existsSync(gitDirFile) || !fs20.statSync(gitDirFile).isFile()) return "";
|
|
37656
|
+
const first2 = fs20.readFileSync(gitDirFile, "utf8").trim();
|
|
37212
37657
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
37213
37658
|
if (!m) return "";
|
|
37214
|
-
const gitWorktreePath =
|
|
37215
|
-
const gitDir =
|
|
37216
|
-
return
|
|
37659
|
+
const gitWorktreePath = path24.resolve(wt, m[1].trim());
|
|
37660
|
+
const gitDir = path24.dirname(path24.dirname(gitWorktreePath));
|
|
37661
|
+
return path24.dirname(gitDir);
|
|
37217
37662
|
}
|
|
37218
37663
|
|
|
37219
37664
|
// src/git/worktrees/worktree-remove.ts
|
|
@@ -37222,7 +37667,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
37222
37667
|
if (mainRepo) {
|
|
37223
37668
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
37224
37669
|
} else {
|
|
37225
|
-
|
|
37670
|
+
fs21.rmSync(worktreePath, { recursive: true, force: true });
|
|
37226
37671
|
}
|
|
37227
37672
|
}
|
|
37228
37673
|
|
|
@@ -37235,7 +37680,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
37235
37680
|
} catch (e) {
|
|
37236
37681
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
37237
37682
|
try {
|
|
37238
|
-
|
|
37683
|
+
fs22.rmSync(wt, { recursive: true, force: true });
|
|
37239
37684
|
} catch {
|
|
37240
37685
|
}
|
|
37241
37686
|
}
|
|
@@ -37264,12 +37709,12 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
37264
37709
|
}
|
|
37265
37710
|
|
|
37266
37711
|
// src/worktrees/worktree-layout-file.ts
|
|
37267
|
-
import * as
|
|
37268
|
-
import * as
|
|
37712
|
+
import * as fs23 from "node:fs";
|
|
37713
|
+
import * as path25 from "node:path";
|
|
37269
37714
|
import os7 from "node:os";
|
|
37270
37715
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
37271
37716
|
function defaultWorktreeLayoutPath() {
|
|
37272
|
-
return
|
|
37717
|
+
return path25.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
37273
37718
|
}
|
|
37274
37719
|
function normalizeLoadedLayout(raw) {
|
|
37275
37720
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -37281,8 +37726,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
37281
37726
|
function loadWorktreeLayout() {
|
|
37282
37727
|
try {
|
|
37283
37728
|
const p = defaultWorktreeLayoutPath();
|
|
37284
|
-
if (!
|
|
37285
|
-
const raw = JSON.parse(
|
|
37729
|
+
if (!fs23.existsSync(p)) return { launcherCwds: [] };
|
|
37730
|
+
const raw = JSON.parse(fs23.readFileSync(p, "utf8"));
|
|
37286
37731
|
return normalizeLoadedLayout(raw);
|
|
37287
37732
|
} catch {
|
|
37288
37733
|
return { launcherCwds: [] };
|
|
@@ -37290,24 +37735,24 @@ function loadWorktreeLayout() {
|
|
|
37290
37735
|
}
|
|
37291
37736
|
function saveWorktreeLayout(layout) {
|
|
37292
37737
|
try {
|
|
37293
|
-
const dir =
|
|
37294
|
-
|
|
37295
|
-
|
|
37738
|
+
const dir = path25.dirname(defaultWorktreeLayoutPath());
|
|
37739
|
+
fs23.mkdirSync(dir, { recursive: true });
|
|
37740
|
+
fs23.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
37296
37741
|
} catch {
|
|
37297
37742
|
}
|
|
37298
37743
|
}
|
|
37299
37744
|
function baseNameSafe(pathString) {
|
|
37300
|
-
return
|
|
37745
|
+
return path25.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
37301
37746
|
}
|
|
37302
37747
|
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
37303
|
-
const norm =
|
|
37304
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
37748
|
+
const norm = path25.resolve(bridgeRootPath2);
|
|
37749
|
+
const existing = layout.launcherCwds.find((e) => path25.resolve(e.absolutePath) === norm);
|
|
37305
37750
|
return existing?.dirName;
|
|
37306
37751
|
}
|
|
37307
37752
|
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
37308
37753
|
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
37309
37754
|
if (existing) return existing;
|
|
37310
|
-
const norm =
|
|
37755
|
+
const norm = path25.resolve(bridgeRootPath2);
|
|
37311
37756
|
const base = baseNameSafe(norm);
|
|
37312
37757
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
37313
37758
|
let name = base;
|
|
@@ -37322,11 +37767,11 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
|
37322
37767
|
}
|
|
37323
37768
|
|
|
37324
37769
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
37325
|
-
import * as
|
|
37326
|
-
import * as
|
|
37770
|
+
import * as fs24 from "node:fs";
|
|
37771
|
+
import * as path26 from "node:path";
|
|
37327
37772
|
function isGitDir(dirPath) {
|
|
37328
37773
|
try {
|
|
37329
|
-
return
|
|
37774
|
+
return fs24.existsSync(path26.join(dirPath, ".git"));
|
|
37330
37775
|
} catch {
|
|
37331
37776
|
return false;
|
|
37332
37777
|
}
|
|
@@ -37335,23 +37780,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
37335
37780
|
const out = [];
|
|
37336
37781
|
const walk = (dir) => {
|
|
37337
37782
|
if (isGitDir(dir)) {
|
|
37338
|
-
out.push(
|
|
37783
|
+
out.push(path26.resolve(dir));
|
|
37339
37784
|
return;
|
|
37340
37785
|
}
|
|
37341
37786
|
let entries;
|
|
37342
37787
|
try {
|
|
37343
|
-
entries =
|
|
37788
|
+
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
37344
37789
|
} catch {
|
|
37345
37790
|
return;
|
|
37346
37791
|
}
|
|
37347
37792
|
for (const e of entries) {
|
|
37348
37793
|
if (e.name.startsWith(".")) continue;
|
|
37349
|
-
const full =
|
|
37794
|
+
const full = path26.join(dir, e.name);
|
|
37350
37795
|
if (!e.isDirectory()) continue;
|
|
37351
37796
|
walk(full);
|
|
37352
37797
|
}
|
|
37353
37798
|
};
|
|
37354
|
-
walk(
|
|
37799
|
+
walk(path26.resolve(rootPath));
|
|
37355
37800
|
return [...new Set(out)];
|
|
37356
37801
|
}
|
|
37357
37802
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -37360,16 +37805,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
37360
37805
|
if (depth > maxDepth) return;
|
|
37361
37806
|
let entries;
|
|
37362
37807
|
try {
|
|
37363
|
-
entries =
|
|
37808
|
+
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
37364
37809
|
} catch {
|
|
37365
37810
|
return;
|
|
37366
37811
|
}
|
|
37367
37812
|
for (const e of entries) {
|
|
37368
37813
|
if (e.name.startsWith(".")) continue;
|
|
37369
|
-
const full =
|
|
37814
|
+
const full = path26.join(dir, e.name);
|
|
37370
37815
|
if (!e.isDirectory()) continue;
|
|
37371
37816
|
if (e.name === sessionId) {
|
|
37372
|
-
if (isGitDir(full)) out.push(
|
|
37817
|
+
if (isGitDir(full)) out.push(path26.resolve(full));
|
|
37373
37818
|
} else {
|
|
37374
37819
|
walk(full, depth + 1);
|
|
37375
37820
|
}
|
|
@@ -37381,14 +37826,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
37381
37826
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
37382
37827
|
let st;
|
|
37383
37828
|
try {
|
|
37384
|
-
st =
|
|
37829
|
+
st = fs24.statSync(sessionDir);
|
|
37385
37830
|
} catch {
|
|
37386
37831
|
return null;
|
|
37387
37832
|
}
|
|
37388
37833
|
if (!st.isDirectory()) return null;
|
|
37389
37834
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
37390
37835
|
if (worktreePaths.length === 0) return null;
|
|
37391
|
-
const abs =
|
|
37836
|
+
const abs = path26.resolve(sessionDir);
|
|
37392
37837
|
return {
|
|
37393
37838
|
sessionParentPath: abs,
|
|
37394
37839
|
workingTreeRelRoot: abs,
|
|
@@ -37398,20 +37843,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
37398
37843
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
37399
37844
|
const sid = sessionId.trim();
|
|
37400
37845
|
if (!sid) return null;
|
|
37401
|
-
const hintR =
|
|
37846
|
+
const hintR = path26.resolve(checkoutPath);
|
|
37402
37847
|
let best = null;
|
|
37403
|
-
let cur =
|
|
37848
|
+
let cur = path26.dirname(hintR);
|
|
37404
37849
|
for (let i = 0; i < 40; i++) {
|
|
37405
37850
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
37406
|
-
if (paths.some((p) =>
|
|
37407
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
37851
|
+
if (paths.some((p) => path26.resolve(p) === hintR)) {
|
|
37852
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path26.resolve(paths[0]);
|
|
37408
37853
|
best = {
|
|
37409
|
-
sessionParentPath:
|
|
37410
|
-
workingTreeRelRoot:
|
|
37411
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
37854
|
+
sessionParentPath: path26.resolve(isolated),
|
|
37855
|
+
workingTreeRelRoot: path26.resolve(cur),
|
|
37856
|
+
repoCheckoutPaths: paths.map((p) => path26.resolve(p))
|
|
37412
37857
|
};
|
|
37413
37858
|
}
|
|
37414
|
-
const next =
|
|
37859
|
+
const next = path26.dirname(cur);
|
|
37415
37860
|
if (next === cur) break;
|
|
37416
37861
|
cur = next;
|
|
37417
37862
|
}
|
|
@@ -37419,33 +37864,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
37419
37864
|
}
|
|
37420
37865
|
function discoverSessionWorktreeOnDisk(options) {
|
|
37421
37866
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
37422
|
-
if (!sessionId.trim() || !
|
|
37867
|
+
if (!sessionId.trim() || !fs24.existsSync(worktreesRootPath)) return null;
|
|
37423
37868
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
37424
37869
|
const keys = [];
|
|
37425
37870
|
if (preferredKey) keys.push(preferredKey);
|
|
37426
37871
|
try {
|
|
37427
|
-
for (const name of
|
|
37872
|
+
for (const name of fs24.readdirSync(worktreesRootPath)) {
|
|
37428
37873
|
if (name.startsWith(".")) continue;
|
|
37429
|
-
const p =
|
|
37430
|
-
if (!
|
|
37874
|
+
const p = path26.join(worktreesRootPath, name);
|
|
37875
|
+
if (!fs24.statSync(p).isDirectory()) continue;
|
|
37431
37876
|
if (name !== preferredKey) keys.push(name);
|
|
37432
37877
|
}
|
|
37433
37878
|
} catch {
|
|
37434
37879
|
return null;
|
|
37435
37880
|
}
|
|
37436
37881
|
for (const key of keys) {
|
|
37437
|
-
const layoutRoot =
|
|
37438
|
-
if (!
|
|
37439
|
-
const sessionDir =
|
|
37882
|
+
const layoutRoot = path26.join(worktreesRootPath, key);
|
|
37883
|
+
if (!fs24.existsSync(layoutRoot) || !fs24.statSync(layoutRoot).isDirectory()) continue;
|
|
37884
|
+
const sessionDir = path26.join(layoutRoot, sessionId);
|
|
37440
37885
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
37441
37886
|
if (nested) return nested;
|
|
37442
37887
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
37443
37888
|
if (legacyPaths.length > 0) {
|
|
37444
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
37889
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
|
|
37445
37890
|
return {
|
|
37446
|
-
sessionParentPath:
|
|
37447
|
-
workingTreeRelRoot:
|
|
37448
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
37891
|
+
sessionParentPath: path26.resolve(isolated),
|
|
37892
|
+
workingTreeRelRoot: path26.resolve(layoutRoot),
|
|
37893
|
+
repoCheckoutPaths: legacyPaths.map((p) => path26.resolve(p))
|
|
37449
37894
|
};
|
|
37450
37895
|
}
|
|
37451
37896
|
}
|
|
@@ -37454,12 +37899,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
37454
37899
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
37455
37900
|
const sid = sessionId.trim();
|
|
37456
37901
|
if (!sid) return null;
|
|
37457
|
-
const hint =
|
|
37458
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
37902
|
+
const hint = path26.resolve(sessionWorktreeRootPathOrHint);
|
|
37903
|
+
const underHint = tryBindingFromSessionDirectory(path26.join(hint, sid));
|
|
37459
37904
|
if (underHint) return underHint;
|
|
37460
37905
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
37461
37906
|
if (direct) {
|
|
37462
|
-
if (
|
|
37907
|
+
if (path26.basename(hint) === sid && isGitDir(hint)) {
|
|
37463
37908
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
37464
37909
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
37465
37910
|
return legacyFromCheckout;
|
|
@@ -37467,24 +37912,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
37467
37912
|
}
|
|
37468
37913
|
return direct;
|
|
37469
37914
|
}
|
|
37470
|
-
if (
|
|
37915
|
+
if (path26.basename(hint) === sid && isGitDir(hint)) {
|
|
37471
37916
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
37472
37917
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
37473
37918
|
}
|
|
37474
37919
|
let st;
|
|
37475
37920
|
try {
|
|
37476
|
-
st =
|
|
37921
|
+
st = fs24.statSync(hint);
|
|
37477
37922
|
} catch {
|
|
37478
37923
|
return null;
|
|
37479
37924
|
}
|
|
37480
37925
|
if (!st.isDirectory()) return null;
|
|
37481
37926
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
37482
37927
|
if (legacyPaths.length === 0) return null;
|
|
37483
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
37928
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
|
|
37484
37929
|
return {
|
|
37485
|
-
sessionParentPath:
|
|
37930
|
+
sessionParentPath: path26.resolve(isolated),
|
|
37486
37931
|
workingTreeRelRoot: hint,
|
|
37487
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
37932
|
+
repoCheckoutPaths: legacyPaths.map((p) => path26.resolve(p))
|
|
37488
37933
|
};
|
|
37489
37934
|
}
|
|
37490
37935
|
|
|
@@ -37541,8 +37986,8 @@ function parseSessionParent(v) {
|
|
|
37541
37986
|
}
|
|
37542
37987
|
|
|
37543
37988
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
37544
|
-
import * as
|
|
37545
|
-
import * as
|
|
37989
|
+
import * as fs25 from "node:fs";
|
|
37990
|
+
import * as path27 from "node:path";
|
|
37546
37991
|
|
|
37547
37992
|
// src/git/worktrees/worktree-add.ts
|
|
37548
37993
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
@@ -37552,7 +37997,7 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef
|
|
|
37552
37997
|
}
|
|
37553
37998
|
|
|
37554
37999
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
37555
|
-
function
|
|
38000
|
+
function normalizeRepoRelPath2(rel) {
|
|
37556
38001
|
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
37557
38002
|
}
|
|
37558
38003
|
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
@@ -37564,10 +38009,10 @@ function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
|
37564
38009
|
}
|
|
37565
38010
|
async function prepareNewSessionWorktrees(options) {
|
|
37566
38011
|
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
|
|
37567
|
-
const bridgeResolved =
|
|
38012
|
+
const bridgeResolved = path27.resolve(bridgeRoot);
|
|
37568
38013
|
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
37569
|
-
const bridgeKeyDir =
|
|
37570
|
-
const sessionDir =
|
|
38014
|
+
const bridgeKeyDir = path27.join(worktreesRootPath, cwdKey);
|
|
38015
|
+
const sessionDir = path27.join(bridgeKeyDir, sessionId);
|
|
37571
38016
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
37572
38017
|
if (repos.length === 0) {
|
|
37573
38018
|
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
@@ -37575,14 +38020,14 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
37575
38020
|
}
|
|
37576
38021
|
const branch = `session-${sessionId}`;
|
|
37577
38022
|
const worktreePaths = [];
|
|
37578
|
-
|
|
38023
|
+
fs25.mkdirSync(sessionDir, { recursive: true });
|
|
37579
38024
|
for (const repo of repos) {
|
|
37580
|
-
let rel =
|
|
37581
|
-
if (rel.startsWith("..") ||
|
|
37582
|
-
const relNorm =
|
|
37583
|
-
const wtPath = relNorm === "." ? sessionDir :
|
|
38025
|
+
let rel = path27.relative(bridgeResolved, repo.absolutePath);
|
|
38026
|
+
if (rel.startsWith("..") || path27.isAbsolute(rel)) continue;
|
|
38027
|
+
const relNorm = normalizeRepoRelPath2(rel === "" ? "." : rel);
|
|
38028
|
+
const wtPath = relNorm === "." ? sessionDir : path27.join(sessionDir, relNorm);
|
|
37584
38029
|
if (relNorm !== ".") {
|
|
37585
|
-
|
|
38030
|
+
fs25.mkdirSync(path27.dirname(wtPath), { recursive: true });
|
|
37586
38031
|
}
|
|
37587
38032
|
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
37588
38033
|
try {
|
|
@@ -37635,9 +38080,9 @@ function resolveExistingSessionParentPath(sessionId, cache2, discover) {
|
|
|
37635
38080
|
}
|
|
37636
38081
|
|
|
37637
38082
|
// src/worktrees/manager/resolve-explicit-session-parent-path.ts
|
|
37638
|
-
import * as
|
|
38083
|
+
import * as path28 from "node:path";
|
|
37639
38084
|
function resolveExplicitSessionParentPath(params) {
|
|
37640
|
-
const resolved =
|
|
38085
|
+
const resolved = path28.resolve(params.parentPathRaw);
|
|
37641
38086
|
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
37642
38087
|
return resolved;
|
|
37643
38088
|
}
|
|
@@ -37653,7 +38098,7 @@ function resolveExplicitSessionParentPath(params) {
|
|
|
37653
38098
|
for (let i = 0; i < 16; i++) {
|
|
37654
38099
|
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
37655
38100
|
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
37656
|
-
const next =
|
|
38101
|
+
const next = path28.dirname(cur);
|
|
37657
38102
|
if (next === cur) break;
|
|
37658
38103
|
cur = next;
|
|
37659
38104
|
}
|
|
@@ -37705,16 +38150,16 @@ async function resolveSessionParentPathForPrompt(params) {
|
|
|
37705
38150
|
}
|
|
37706
38151
|
|
|
37707
38152
|
// src/worktrees/manager/session-worktree-cache.ts
|
|
37708
|
-
import * as
|
|
38153
|
+
import * as path29 from "node:path";
|
|
37709
38154
|
var SessionWorktreeCache = class {
|
|
37710
38155
|
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
37711
38156
|
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
37712
38157
|
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
37713
38158
|
remember(sessionId, binding) {
|
|
37714
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
38159
|
+
const paths = binding.repoCheckoutPaths.map((p) => path29.resolve(p));
|
|
37715
38160
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
37716
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
37717
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
38161
|
+
this.sessionParentPathBySession.set(sessionId, path29.resolve(binding.sessionParentPath));
|
|
38162
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path29.resolve(binding.workingTreeRelRoot));
|
|
37718
38163
|
}
|
|
37719
38164
|
clearSession(sessionId) {
|
|
37720
38165
|
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
@@ -37744,7 +38189,7 @@ var SessionWorktreeCache = class {
|
|
|
37744
38189
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
37745
38190
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
37746
38191
|
if (!parent || !relRoot) return false;
|
|
37747
|
-
return
|
|
38192
|
+
return path29.resolve(parent) !== path29.resolve(relRoot);
|
|
37748
38193
|
}
|
|
37749
38194
|
};
|
|
37750
38195
|
|
|
@@ -37848,29 +38293,29 @@ var SessionWorktreeManager = class {
|
|
|
37848
38293
|
};
|
|
37849
38294
|
|
|
37850
38295
|
// src/worktrees/manager/default-worktrees-root-path.ts
|
|
37851
|
-
import * as
|
|
38296
|
+
import * as path30 from "node:path";
|
|
37852
38297
|
import os8 from "node:os";
|
|
37853
38298
|
function defaultWorktreesRootPath() {
|
|
37854
|
-
return
|
|
38299
|
+
return path30.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
37855
38300
|
}
|
|
37856
38301
|
|
|
37857
38302
|
// src/files/watch-file-index.ts
|
|
37858
38303
|
import { watch } from "node:fs";
|
|
37859
|
-
import
|
|
38304
|
+
import path35 from "node:path";
|
|
37860
38305
|
|
|
37861
38306
|
// src/files/index/paths.ts
|
|
37862
|
-
import
|
|
38307
|
+
import path31 from "node:path";
|
|
37863
38308
|
import crypto2 from "node:crypto";
|
|
37864
38309
|
function getCwdHashForFileIndex(resolvedCwd) {
|
|
37865
|
-
return crypto2.createHash("sha256").update(
|
|
38310
|
+
return crypto2.createHash("sha256").update(path31.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
37866
38311
|
}
|
|
37867
38312
|
|
|
37868
38313
|
// src/files/index/build-file-index.ts
|
|
37869
|
-
import
|
|
38314
|
+
import path33 from "node:path";
|
|
37870
38315
|
|
|
37871
38316
|
// src/files/index/walk-workspace-tree.ts
|
|
37872
|
-
import
|
|
37873
|
-
import
|
|
38317
|
+
import fs26 from "node:fs";
|
|
38318
|
+
import path32 from "node:path";
|
|
37874
38319
|
var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
37875
38320
|
"node_modules",
|
|
37876
38321
|
"bower_components",
|
|
@@ -37887,7 +38332,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
|
|
|
37887
38332
|
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
37888
38333
|
let names;
|
|
37889
38334
|
try {
|
|
37890
|
-
names = await
|
|
38335
|
+
names = await fs26.promises.readdir(dir);
|
|
37891
38336
|
} catch {
|
|
37892
38337
|
return;
|
|
37893
38338
|
}
|
|
@@ -37899,14 +38344,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
|
37899
38344
|
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
37900
38345
|
}
|
|
37901
38346
|
state.n++;
|
|
37902
|
-
const full =
|
|
38347
|
+
const full = path32.join(dir, name);
|
|
37903
38348
|
let stat3;
|
|
37904
38349
|
try {
|
|
37905
|
-
stat3 = await
|
|
38350
|
+
stat3 = await fs26.promises.stat(full);
|
|
37906
38351
|
} catch {
|
|
37907
38352
|
continue;
|
|
37908
38353
|
}
|
|
37909
|
-
const relative6 =
|
|
38354
|
+
const relative6 = path32.relative(baseDir, full).replace(/\\/g, "/");
|
|
37910
38355
|
if (stat3.isDirectory()) {
|
|
37911
38356
|
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
37912
38357
|
} else if (stat3.isFile()) {
|
|
@@ -37919,7 +38364,7 @@ function createWalkYieldState() {
|
|
|
37919
38364
|
}
|
|
37920
38365
|
|
|
37921
38366
|
// src/files/index/file-index-sqlite-lock.ts
|
|
37922
|
-
import
|
|
38367
|
+
import fs27 from "node:fs";
|
|
37923
38368
|
function isSqliteCorruptError(e) {
|
|
37924
38369
|
const msg = e instanceof Error ? e.message : String(e);
|
|
37925
38370
|
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
@@ -37933,7 +38378,7 @@ function withFileIndexSqliteLock(fn) {
|
|
|
37933
38378
|
if (!isSqliteCorruptError(e)) throw e;
|
|
37934
38379
|
closeAllCliSqliteConnections();
|
|
37935
38380
|
try {
|
|
37936
|
-
|
|
38381
|
+
fs27.unlinkSync(getCliSqlitePath());
|
|
37937
38382
|
} catch {
|
|
37938
38383
|
}
|
|
37939
38384
|
chain = Promise.resolve();
|
|
@@ -38008,7 +38453,7 @@ async function collectWorkspacePathsAsync(resolved) {
|
|
|
38008
38453
|
}
|
|
38009
38454
|
async function buildFileIndexAsync(cwd) {
|
|
38010
38455
|
return withFileIndexSqliteLock(async () => {
|
|
38011
|
-
const resolved =
|
|
38456
|
+
const resolved = path33.resolve(cwd);
|
|
38012
38457
|
await yieldToEventLoop();
|
|
38013
38458
|
assertNotShutdown();
|
|
38014
38459
|
const paths = await collectWorkspacePathsAsync(resolved);
|
|
@@ -38020,7 +38465,7 @@ async function buildFileIndexAsync(cwd) {
|
|
|
38020
38465
|
}
|
|
38021
38466
|
|
|
38022
38467
|
// src/files/index/ensure-file-index.ts
|
|
38023
|
-
import
|
|
38468
|
+
import path34 from "node:path";
|
|
38024
38469
|
|
|
38025
38470
|
// src/files/index/search-file-index.ts
|
|
38026
38471
|
function escapeLikePattern(fragment) {
|
|
@@ -38072,7 +38517,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
|
38072
38517
|
|
|
38073
38518
|
// src/files/index/ensure-file-index.ts
|
|
38074
38519
|
async function ensureFileIndexAsync(cwd) {
|
|
38075
|
-
const resolved =
|
|
38520
|
+
const resolved = path34.resolve(cwd);
|
|
38076
38521
|
if (await bridgeFileIndexIsPopulated(resolved)) {
|
|
38077
38522
|
return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
|
|
38078
38523
|
}
|
|
@@ -38116,7 +38561,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
38116
38561
|
}
|
|
38117
38562
|
}
|
|
38118
38563
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
38119
|
-
const resolved =
|
|
38564
|
+
const resolved = path35.resolve(cwd);
|
|
38120
38565
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
38121
38566
|
if (e instanceof CliSqliteInterrupted) return;
|
|
38122
38567
|
console.error("[file-index] Initial index build failed:", e);
|
|
@@ -38146,7 +38591,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
38146
38591
|
}
|
|
38147
38592
|
|
|
38148
38593
|
// src/connection/create-bridge-connection.ts
|
|
38149
|
-
import * as
|
|
38594
|
+
import * as path46 from "node:path";
|
|
38150
38595
|
|
|
38151
38596
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
38152
38597
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -38190,7 +38635,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
38190
38635
|
}
|
|
38191
38636
|
|
|
38192
38637
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
38193
|
-
import
|
|
38638
|
+
import fs28 from "node:fs";
|
|
38194
38639
|
|
|
38195
38640
|
// src/dev-servers/manager/forward-pipe.ts
|
|
38196
38641
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -38226,7 +38671,7 @@ function wireDevServerChildProcess(d) {
|
|
|
38226
38671
|
d.setPollInterval(void 0);
|
|
38227
38672
|
return;
|
|
38228
38673
|
}
|
|
38229
|
-
|
|
38674
|
+
fs28.readFile(d.mergedLogPath, (err, buf) => {
|
|
38230
38675
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
38231
38676
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
38232
38677
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -38264,7 +38709,7 @@ ${errTail}` : ""}`);
|
|
|
38264
38709
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
38265
38710
|
};
|
|
38266
38711
|
if (mergedPath) {
|
|
38267
|
-
|
|
38712
|
+
fs28.readFile(mergedPath, (err, buf) => {
|
|
38268
38713
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
38269
38714
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
38270
38715
|
if (chunk.length > 0) {
|
|
@@ -38366,13 +38811,13 @@ function parseDevServerDefs(servers) {
|
|
|
38366
38811
|
}
|
|
38367
38812
|
|
|
38368
38813
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
38369
|
-
import
|
|
38814
|
+
import fs29 from "node:fs";
|
|
38370
38815
|
function isSpawnEbadf(e) {
|
|
38371
38816
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
38372
38817
|
}
|
|
38373
38818
|
function rmDirQuiet(dir) {
|
|
38374
38819
|
try {
|
|
38375
|
-
|
|
38820
|
+
fs29.rmSync(dir, { recursive: true, force: true });
|
|
38376
38821
|
} catch {
|
|
38377
38822
|
}
|
|
38378
38823
|
}
|
|
@@ -38380,7 +38825,7 @@ var cachedDevNullReadFd;
|
|
|
38380
38825
|
function devNullReadFd() {
|
|
38381
38826
|
if (cachedDevNullReadFd === void 0) {
|
|
38382
38827
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
38383
|
-
cachedDevNullReadFd =
|
|
38828
|
+
cachedDevNullReadFd = fs29.openSync(devPath, "r");
|
|
38384
38829
|
}
|
|
38385
38830
|
return cachedDevNullReadFd;
|
|
38386
38831
|
}
|
|
@@ -38454,15 +38899,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
38454
38899
|
|
|
38455
38900
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
38456
38901
|
import { spawn as spawn7 } from "node:child_process";
|
|
38457
|
-
import
|
|
38902
|
+
import fs30 from "node:fs";
|
|
38458
38903
|
import { tmpdir } from "node:os";
|
|
38459
|
-
import
|
|
38904
|
+
import path36 from "node:path";
|
|
38460
38905
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
38461
|
-
const tmpRoot =
|
|
38462
|
-
const logPath =
|
|
38906
|
+
const tmpRoot = fs30.mkdtempSync(path36.join(tmpdir(), "ba-devsrv-log-"));
|
|
38907
|
+
const logPath = path36.join(tmpRoot, "combined.log");
|
|
38463
38908
|
let logFd;
|
|
38464
38909
|
try {
|
|
38465
|
-
logFd =
|
|
38910
|
+
logFd = fs30.openSync(logPath, "a");
|
|
38466
38911
|
} catch {
|
|
38467
38912
|
rmDirQuiet(tmpRoot);
|
|
38468
38913
|
return null;
|
|
@@ -38481,7 +38926,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
38481
38926
|
} else {
|
|
38482
38927
|
proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
38483
38928
|
}
|
|
38484
|
-
|
|
38929
|
+
fs30.closeSync(logFd);
|
|
38485
38930
|
return {
|
|
38486
38931
|
proc,
|
|
38487
38932
|
pipedStdoutStderr: true,
|
|
@@ -38490,7 +38935,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
38490
38935
|
};
|
|
38491
38936
|
} catch (e) {
|
|
38492
38937
|
try {
|
|
38493
|
-
|
|
38938
|
+
fs30.closeSync(logFd);
|
|
38494
38939
|
} catch {
|
|
38495
38940
|
}
|
|
38496
38941
|
rmDirQuiet(tmpRoot);
|
|
@@ -38501,22 +38946,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
38501
38946
|
|
|
38502
38947
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
38503
38948
|
import { spawn as spawn8 } from "node:child_process";
|
|
38504
|
-
import
|
|
38949
|
+
import fs31 from "node:fs";
|
|
38505
38950
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
38506
|
-
import
|
|
38951
|
+
import path37 from "node:path";
|
|
38507
38952
|
function shSingleQuote(s) {
|
|
38508
38953
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
38509
38954
|
}
|
|
38510
38955
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
38511
|
-
const tmpRoot =
|
|
38512
|
-
const logPath =
|
|
38513
|
-
const innerPath =
|
|
38514
|
-
const runnerPath =
|
|
38956
|
+
const tmpRoot = fs31.mkdtempSync(path37.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
38957
|
+
const logPath = path37.join(tmpRoot, "combined.log");
|
|
38958
|
+
const innerPath = path37.join(tmpRoot, "_cmd.sh");
|
|
38959
|
+
const runnerPath = path37.join(tmpRoot, "_run.sh");
|
|
38515
38960
|
try {
|
|
38516
|
-
|
|
38961
|
+
fs31.writeFileSync(innerPath, `#!/bin/sh
|
|
38517
38962
|
${command}
|
|
38518
38963
|
`);
|
|
38519
|
-
|
|
38964
|
+
fs31.writeFileSync(
|
|
38520
38965
|
runnerPath,
|
|
38521
38966
|
`#!/bin/sh
|
|
38522
38967
|
cd ${shSingleQuote(cwd)}
|
|
@@ -38542,13 +38987,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
38542
38987
|
}
|
|
38543
38988
|
}
|
|
38544
38989
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
38545
|
-
const tmpRoot =
|
|
38546
|
-
const logPath =
|
|
38547
|
-
const runnerPath =
|
|
38990
|
+
const tmpRoot = fs31.mkdtempSync(path37.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
38991
|
+
const logPath = path37.join(tmpRoot, "combined.log");
|
|
38992
|
+
const runnerPath = path37.join(tmpRoot, "_run.bat");
|
|
38548
38993
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
38549
38994
|
const com = process.env.ComSpec || "cmd.exe";
|
|
38550
38995
|
try {
|
|
38551
|
-
|
|
38996
|
+
fs31.writeFileSync(
|
|
38552
38997
|
runnerPath,
|
|
38553
38998
|
`@ECHO OFF\r
|
|
38554
38999
|
CD /D ${q(cwd)}\r
|
|
@@ -39485,30 +39930,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
39485
39930
|
}
|
|
39486
39931
|
|
|
39487
39932
|
// src/skills/discover-local-agent-skills.ts
|
|
39488
|
-
import
|
|
39489
|
-
import
|
|
39933
|
+
import fs32 from "node:fs";
|
|
39934
|
+
import path38 from "node:path";
|
|
39490
39935
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
39491
39936
|
function discoverLocalSkills(cwd) {
|
|
39492
39937
|
const out = [];
|
|
39493
39938
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
39494
39939
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
39495
|
-
const base =
|
|
39496
|
-
if (!
|
|
39940
|
+
const base = path38.join(cwd, rel);
|
|
39941
|
+
if (!fs32.existsSync(base) || !fs32.statSync(base).isDirectory()) continue;
|
|
39497
39942
|
let entries = [];
|
|
39498
39943
|
try {
|
|
39499
|
-
entries =
|
|
39944
|
+
entries = fs32.readdirSync(base);
|
|
39500
39945
|
} catch {
|
|
39501
39946
|
continue;
|
|
39502
39947
|
}
|
|
39503
39948
|
for (const name of entries) {
|
|
39504
|
-
const dir =
|
|
39949
|
+
const dir = path38.join(base, name);
|
|
39505
39950
|
try {
|
|
39506
|
-
if (!
|
|
39951
|
+
if (!fs32.statSync(dir).isDirectory()) continue;
|
|
39507
39952
|
} catch {
|
|
39508
39953
|
continue;
|
|
39509
39954
|
}
|
|
39510
|
-
const skillMd =
|
|
39511
|
-
if (!
|
|
39955
|
+
const skillMd = path38.join(dir, "SKILL.md");
|
|
39956
|
+
if (!fs32.existsSync(skillMd)) continue;
|
|
39512
39957
|
const key = `${rel}/${name}`;
|
|
39513
39958
|
if (seenKeys.has(key)) continue;
|
|
39514
39959
|
seenKeys.add(key);
|
|
@@ -39520,23 +39965,23 @@ function discoverLocalSkills(cwd) {
|
|
|
39520
39965
|
function discoverSkillLayoutRoots(cwd) {
|
|
39521
39966
|
const roots = [];
|
|
39522
39967
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
39523
|
-
const base =
|
|
39524
|
-
if (!
|
|
39968
|
+
const base = path38.join(cwd, rel);
|
|
39969
|
+
if (!fs32.existsSync(base) || !fs32.statSync(base).isDirectory()) continue;
|
|
39525
39970
|
let entries = [];
|
|
39526
39971
|
try {
|
|
39527
|
-
entries =
|
|
39972
|
+
entries = fs32.readdirSync(base);
|
|
39528
39973
|
} catch {
|
|
39529
39974
|
continue;
|
|
39530
39975
|
}
|
|
39531
39976
|
const skills2 = [];
|
|
39532
39977
|
for (const name of entries) {
|
|
39533
|
-
const dir =
|
|
39978
|
+
const dir = path38.join(base, name);
|
|
39534
39979
|
try {
|
|
39535
|
-
if (!
|
|
39980
|
+
if (!fs32.statSync(dir).isDirectory()) continue;
|
|
39536
39981
|
} catch {
|
|
39537
39982
|
continue;
|
|
39538
39983
|
}
|
|
39539
|
-
if (!
|
|
39984
|
+
if (!fs32.existsSync(path38.join(dir, "SKILL.md"))) continue;
|
|
39540
39985
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
39541
39986
|
skills2.push({ name, relPath });
|
|
39542
39987
|
}
|
|
@@ -39892,7 +40337,7 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
|
|
|
39892
40337
|
}
|
|
39893
40338
|
|
|
39894
40339
|
// src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
|
|
39895
|
-
import
|
|
40340
|
+
import fs33 from "node:fs";
|
|
39896
40341
|
async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
39897
40342
|
if (next.serverState !== "requeued_with_revert") return true;
|
|
39898
40343
|
const sid = next.sessionId;
|
|
@@ -39901,7 +40346,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
39901
40346
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
39902
40347
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
39903
40348
|
try {
|
|
39904
|
-
await
|
|
40349
|
+
await fs33.promises.access(file2, fs33.constants.F_OK);
|
|
39905
40350
|
} catch {
|
|
39906
40351
|
deps.log(
|
|
39907
40352
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
@@ -40189,9 +40634,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
40189
40634
|
for (const item of raw) {
|
|
40190
40635
|
if (!item || typeof item !== "object") continue;
|
|
40191
40636
|
const o = item;
|
|
40192
|
-
const
|
|
40193
|
-
if (!
|
|
40194
|
-
const row = { path:
|
|
40637
|
+
const path48 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
40638
|
+
if (!path48) continue;
|
|
40639
|
+
const row = { path: path48 };
|
|
40195
40640
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
40196
40641
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
40197
40642
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -40401,8 +40846,8 @@ function randomSecret() {
|
|
|
40401
40846
|
}
|
|
40402
40847
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
40403
40848
|
}
|
|
40404
|
-
async function requestPreviewApi(port, secret, method,
|
|
40405
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
40849
|
+
async function requestPreviewApi(port, secret, method, path48, body) {
|
|
40850
|
+
const url2 = `http://127.0.0.1:${port}${path48}`;
|
|
40406
40851
|
const headers = {
|
|
40407
40852
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
40408
40853
|
"Content-Type": "application/json"
|
|
@@ -40414,7 +40859,7 @@ async function requestPreviewApi(port, secret, method, path46, body) {
|
|
|
40414
40859
|
});
|
|
40415
40860
|
const data = await res.json().catch(() => ({}));
|
|
40416
40861
|
if (!res.ok) {
|
|
40417
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
40862
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path48}: ${res.status}`);
|
|
40418
40863
|
}
|
|
40419
40864
|
return data;
|
|
40420
40865
|
}
|
|
@@ -40579,14 +41024,14 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
40579
41024
|
};
|
|
40580
41025
|
|
|
40581
41026
|
// src/files/list-dir/index.ts
|
|
40582
|
-
import
|
|
41027
|
+
import fs35 from "node:fs";
|
|
40583
41028
|
|
|
40584
41029
|
// src/files/ensure-under-cwd.ts
|
|
40585
|
-
import
|
|
41030
|
+
import path39 from "node:path";
|
|
40586
41031
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
40587
|
-
const normalized =
|
|
40588
|
-
const resolved =
|
|
40589
|
-
if (!resolved.startsWith(cwd +
|
|
41032
|
+
const normalized = path39.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
41033
|
+
const resolved = path39.resolve(cwd, normalized);
|
|
41034
|
+
if (!resolved.startsWith(cwd + path39.sep) && resolved !== cwd) {
|
|
40590
41035
|
return null;
|
|
40591
41036
|
}
|
|
40592
41037
|
return resolved;
|
|
@@ -40596,15 +41041,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
|
40596
41041
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
40597
41042
|
|
|
40598
41043
|
// src/files/list-dir/map-dir-entry.ts
|
|
40599
|
-
import
|
|
40600
|
-
import
|
|
41044
|
+
import path40 from "node:path";
|
|
41045
|
+
import fs34 from "node:fs";
|
|
40601
41046
|
async function mapDirEntry(d, relativePath, resolved) {
|
|
40602
|
-
const entryPath =
|
|
40603
|
-
const fullPath =
|
|
41047
|
+
const entryPath = path40.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
41048
|
+
const fullPath = path40.join(resolved, d.name);
|
|
40604
41049
|
let isDir = d.isDirectory();
|
|
40605
41050
|
if (d.isSymbolicLink()) {
|
|
40606
41051
|
try {
|
|
40607
|
-
const targetStat = await
|
|
41052
|
+
const targetStat = await fs34.promises.stat(fullPath);
|
|
40608
41053
|
isDir = targetStat.isDirectory();
|
|
40609
41054
|
} catch {
|
|
40610
41055
|
isDir = false;
|
|
@@ -40634,7 +41079,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
|
40634
41079
|
return { error: "Path is outside working directory" };
|
|
40635
41080
|
}
|
|
40636
41081
|
try {
|
|
40637
|
-
const names = await
|
|
41082
|
+
const names = await fs35.promises.readdir(resolved, { withFileTypes: true });
|
|
40638
41083
|
const entries = [];
|
|
40639
41084
|
for (let i = 0; i < names.length; i++) {
|
|
40640
41085
|
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
@@ -40654,18 +41099,18 @@ var LINE_CHUNK_SIZE = 64 * 1024;
|
|
|
40654
41099
|
var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
|
|
40655
41100
|
|
|
40656
41101
|
// src/files/read-file/resolve-file-path.ts
|
|
40657
|
-
import
|
|
41102
|
+
import fs36 from "node:fs";
|
|
40658
41103
|
async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
40659
41104
|
const resolved = ensureUnderCwd(relativePath, sessionParentPath);
|
|
40660
41105
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
40661
41106
|
let real;
|
|
40662
41107
|
try {
|
|
40663
|
-
real = await
|
|
41108
|
+
real = await fs36.promises.realpath(resolved);
|
|
40664
41109
|
} catch {
|
|
40665
41110
|
real = resolved;
|
|
40666
41111
|
}
|
|
40667
41112
|
try {
|
|
40668
|
-
const stat3 = await
|
|
41113
|
+
const stat3 = await fs36.promises.stat(real);
|
|
40669
41114
|
if (!stat3.isFile()) return { error: "Not a file" };
|
|
40670
41115
|
return real;
|
|
40671
41116
|
} catch (err) {
|
|
@@ -40674,11 +41119,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
|
|
|
40674
41119
|
}
|
|
40675
41120
|
|
|
40676
41121
|
// src/files/read-file/read-file-range-async.ts
|
|
40677
|
-
import
|
|
41122
|
+
import fs37 from "node:fs";
|
|
40678
41123
|
import { StringDecoder } from "node:string_decoder";
|
|
40679
41124
|
async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
40680
|
-
const fileSize = (await
|
|
40681
|
-
const fd = await
|
|
41125
|
+
const fileSize = (await fs37.promises.stat(filePath)).size;
|
|
41126
|
+
const fd = await fs37.promises.open(filePath, "r");
|
|
40682
41127
|
const bufSize = 64 * 1024;
|
|
40683
41128
|
const buf = Buffer.alloc(bufSize);
|
|
40684
41129
|
const decoder = new StringDecoder("utf8");
|
|
@@ -40840,11 +41285,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
|
|
|
40840
41285
|
}
|
|
40841
41286
|
|
|
40842
41287
|
// src/files/read-file/read-file-buffer-full-async.ts
|
|
40843
|
-
import
|
|
41288
|
+
import fs38 from "node:fs";
|
|
40844
41289
|
var READ_CHUNK_BYTES = 256 * 1024;
|
|
40845
41290
|
async function readFileBufferFullAsync(filePath) {
|
|
40846
|
-
const stat3 = await
|
|
40847
|
-
const fd = await
|
|
41291
|
+
const stat3 = await fs38.promises.stat(filePath);
|
|
41292
|
+
const fd = await fs38.promises.open(filePath, "r");
|
|
40848
41293
|
const chunks = [];
|
|
40849
41294
|
let position = 0;
|
|
40850
41295
|
let bytesSinceYield = 0;
|
|
@@ -40951,13 +41396,13 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
|
40951
41396
|
}
|
|
40952
41397
|
|
|
40953
41398
|
// src/files/handle-file-browser-search.ts
|
|
40954
|
-
import
|
|
41399
|
+
import path41 from "node:path";
|
|
40955
41400
|
var SEARCH_LIMIT = 100;
|
|
40956
41401
|
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
40957
41402
|
void (async () => {
|
|
40958
41403
|
await yieldToEventLoop();
|
|
40959
41404
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
40960
|
-
const sessionParentPath =
|
|
41405
|
+
const sessionParentPath = path41.resolve(
|
|
40961
41406
|
sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
40962
41407
|
);
|
|
40963
41408
|
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
@@ -41076,8 +41521,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
41076
41521
|
}
|
|
41077
41522
|
|
|
41078
41523
|
// src/skills/install-remote-skills.ts
|
|
41079
|
-
import
|
|
41080
|
-
import
|
|
41524
|
+
import fs39 from "node:fs";
|
|
41525
|
+
import path42 from "node:path";
|
|
41081
41526
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
41082
41527
|
const installed2 = [];
|
|
41083
41528
|
if (!Array.isArray(items)) {
|
|
@@ -41088,15 +41533,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
41088
41533
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
41089
41534
|
continue;
|
|
41090
41535
|
}
|
|
41091
|
-
const skillDir =
|
|
41536
|
+
const skillDir = path42.join(cwd, targetDir, item.skillName);
|
|
41092
41537
|
for (const f of item.files) {
|
|
41093
41538
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
41094
|
-
const dest =
|
|
41095
|
-
|
|
41539
|
+
const dest = path42.join(skillDir, f.path);
|
|
41540
|
+
fs39.mkdirSync(path42.dirname(dest), { recursive: true });
|
|
41096
41541
|
if (f.text !== void 0) {
|
|
41097
|
-
|
|
41542
|
+
fs39.writeFileSync(dest, f.text, "utf8");
|
|
41098
41543
|
} else if (f.base64) {
|
|
41099
|
-
|
|
41544
|
+
fs39.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
41100
41545
|
}
|
|
41101
41546
|
}
|
|
41102
41547
|
installed2.push({
|
|
@@ -41254,7 +41699,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
41254
41699
|
};
|
|
41255
41700
|
|
|
41256
41701
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
41257
|
-
import * as
|
|
41702
|
+
import * as fs40 from "node:fs";
|
|
41258
41703
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
41259
41704
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
41260
41705
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -41267,7 +41712,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
41267
41712
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
41268
41713
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
41269
41714
|
try {
|
|
41270
|
-
await
|
|
41715
|
+
await fs40.promises.access(file2, fs40.constants.F_OK);
|
|
41271
41716
|
} catch {
|
|
41272
41717
|
sendWsMessage(s, {
|
|
41273
41718
|
type: "revert_turn_snapshot_result",
|
|
@@ -41309,7 +41754,7 @@ var handleDevServersConfig = (msg, deps) => {
|
|
|
41309
41754
|
};
|
|
41310
41755
|
|
|
41311
41756
|
// src/git/bridge-git-context.ts
|
|
41312
|
-
import * as
|
|
41757
|
+
import * as path43 from "node:path";
|
|
41313
41758
|
|
|
41314
41759
|
// src/git/branches/get-current-branch.ts
|
|
41315
41760
|
async function getCurrentBranch(repoPath) {
|
|
@@ -41359,12 +41804,12 @@ async function listRepoBranchRefs(repoPath) {
|
|
|
41359
41804
|
// src/git/bridge-git-context.ts
|
|
41360
41805
|
function folderNameForRelPath(relPath, bridgeRoot) {
|
|
41361
41806
|
if (relPath === "." || relPath === "") {
|
|
41362
|
-
return
|
|
41807
|
+
return path43.basename(path43.resolve(bridgeRoot)) || "repo";
|
|
41363
41808
|
}
|
|
41364
|
-
return
|
|
41809
|
+
return path43.basename(relPath) || relPath;
|
|
41365
41810
|
}
|
|
41366
41811
|
async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
41367
|
-
const root =
|
|
41812
|
+
const root = path43.resolve(bridgeRoot);
|
|
41368
41813
|
if (await isGitRepoDirectory(root)) {
|
|
41369
41814
|
const remoteUrl = await getRemoteOriginUrl(root);
|
|
41370
41815
|
return [{ absolutePath: root, remoteUrl }];
|
|
@@ -41372,17 +41817,17 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
|
41372
41817
|
const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
|
|
41373
41818
|
const byPath = /* @__PURE__ */ new Map();
|
|
41374
41819
|
for (const repo of [...deep, ...shallow]) {
|
|
41375
|
-
byPath.set(
|
|
41820
|
+
byPath.set(path43.resolve(repo.absolutePath), repo);
|
|
41376
41821
|
}
|
|
41377
41822
|
return [...byPath.values()];
|
|
41378
41823
|
}
|
|
41379
41824
|
async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
41380
|
-
const bridgeResolved =
|
|
41825
|
+
const bridgeResolved = path43.resolve(bridgeRoot);
|
|
41381
41826
|
const repos = await discoverGitReposForBridgeContext(bridgeResolved);
|
|
41382
41827
|
const rows = [];
|
|
41383
41828
|
for (const repo of repos) {
|
|
41384
|
-
let rel =
|
|
41385
|
-
if (rel.startsWith("..") ||
|
|
41829
|
+
let rel = path43.relative(bridgeResolved, repo.absolutePath);
|
|
41830
|
+
if (rel.startsWith("..") || path43.isAbsolute(rel)) continue;
|
|
41386
41831
|
const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
41387
41832
|
const currentBranch = await getCurrentBranch(repo.absolutePath);
|
|
41388
41833
|
const remoteUrl = repo.remoteUrl.trim() || null;
|
|
@@ -41397,11 +41842,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
|
41397
41842
|
return rows;
|
|
41398
41843
|
}
|
|
41399
41844
|
async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
41400
|
-
const bridgeResolved =
|
|
41845
|
+
const bridgeResolved = path43.resolve(bridgeRoot);
|
|
41401
41846
|
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
41402
|
-
const repoPath = rel === "" ? bridgeResolved :
|
|
41403
|
-
const resolved =
|
|
41404
|
-
if (!resolved.startsWith(bridgeResolved +
|
|
41847
|
+
const repoPath = rel === "" ? bridgeResolved : path43.join(bridgeResolved, rel);
|
|
41848
|
+
const resolved = path43.resolve(repoPath);
|
|
41849
|
+
if (!resolved.startsWith(bridgeResolved + path43.sep) && resolved !== bridgeResolved) {
|
|
41405
41850
|
return [];
|
|
41406
41851
|
}
|
|
41407
41852
|
return listRepoBranchRefs(resolved);
|
|
@@ -41906,10 +42351,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
|
41906
42351
|
}
|
|
41907
42352
|
|
|
41908
42353
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
41909
|
-
import * as
|
|
42354
|
+
import * as path45 from "node:path";
|
|
41910
42355
|
|
|
41911
42356
|
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
41912
|
-
import * as
|
|
42357
|
+
import * as path44 from "node:path";
|
|
41913
42358
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
41914
42359
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
|
|
41915
42360
|
const canContinue = () => shouldContinue?.() !== false;
|
|
@@ -41947,7 +42392,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
41947
42392
|
if (!canContinue()) return false;
|
|
41948
42393
|
handle = await resolved.createClient({
|
|
41949
42394
|
command: resolved.command,
|
|
41950
|
-
cwd:
|
|
42395
|
+
cwd: path44.resolve(cwd),
|
|
41951
42396
|
backendAgentType: agentType,
|
|
41952
42397
|
sessionMode: "agent",
|
|
41953
42398
|
persistedAcpSessionId: null,
|
|
@@ -42025,7 +42470,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
42025
42470
|
const { workspaceId, log: log2, getWs } = params;
|
|
42026
42471
|
const isCurrent = beginAgentCapabilityWarmupRun();
|
|
42027
42472
|
if (!isCurrent()) return;
|
|
42028
|
-
const cwd =
|
|
42473
|
+
const cwd = path45.resolve(getBridgeRoot());
|
|
42029
42474
|
async function sendBatchFromCache() {
|
|
42030
42475
|
if (!isCurrent()) return;
|
|
42031
42476
|
const socket = getWs();
|
|
@@ -42091,9 +42536,74 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
42091
42536
|
})();
|
|
42092
42537
|
}
|
|
42093
42538
|
|
|
42094
|
-
// src/mcp/tools/session-history/fork-
|
|
42539
|
+
// src/mcp/tools/session-history/fork/mcp-text-result.ts
|
|
42540
|
+
function mcpTextResult(text, isError = false) {
|
|
42541
|
+
return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
|
|
42542
|
+
}
|
|
42543
|
+
|
|
42544
|
+
// src/mcp/tools/session-history/fork/call-get-parent-session-turn-transcript.ts
|
|
42545
|
+
async function callGetParentSessionTurnTranscriptTool(ctx, cloud, childSessionId, args) {
|
|
42546
|
+
const turnId = typeof args.turnId === "string" ? args.turnId.trim() : "";
|
|
42547
|
+
if (!turnId) return mcpTextResult("turnId is required.", true);
|
|
42548
|
+
const transcript = await fetchCloudParentTurnTranscript({
|
|
42549
|
+
childSessionId,
|
|
42550
|
+
turnId,
|
|
42551
|
+
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
42552
|
+
getCloudAccessToken: cloud.getCloudAccessToken,
|
|
42553
|
+
e2ee: ctx.e2ee
|
|
42554
|
+
});
|
|
42555
|
+
if (!transcript.ok) return mcpTextResult(transcript.error, true);
|
|
42556
|
+
return mcpTextResult(transcript.text);
|
|
42557
|
+
}
|
|
42558
|
+
|
|
42559
|
+
// src/mcp/tools/session-history/fork/call-list-parent-session-prompts.ts
|
|
42560
|
+
async function callListParentSessionPromptsTool(ctx, cloud, childSessionId, parentSessionId) {
|
|
42561
|
+
const detail = await fetchCloudParentSessionPrompts({
|
|
42562
|
+
childSessionId,
|
|
42563
|
+
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
42564
|
+
getCloudAccessToken: cloud.getCloudAccessToken,
|
|
42565
|
+
e2ee: ctx.e2ee
|
|
42566
|
+
});
|
|
42567
|
+
if (!detail.ok) return mcpTextResult(detail.error, true);
|
|
42568
|
+
const turns = Array.isArray(detail.data.turns) ? detail.data.turns : [];
|
|
42569
|
+
const payload = turns.map((t) => ({
|
|
42570
|
+
turnId: typeof t.turnId === "string" ? t.turnId : "",
|
|
42571
|
+
title: typeof t.title === "string" ? t.title : null,
|
|
42572
|
+
status: typeof t.status === "string" ? t.status : null,
|
|
42573
|
+
promptText: typeof t.promptText === "string" ? t.promptText : null
|
|
42574
|
+
}));
|
|
42575
|
+
return mcpTextResult(JSON.stringify({ parentSessionId, turns: payload }, null, 2));
|
|
42576
|
+
}
|
|
42577
|
+
|
|
42578
|
+
// src/mcp/tools/session-history/fork/tool-names.ts
|
|
42095
42579
|
var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
|
|
42096
42580
|
var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
|
|
42581
|
+
|
|
42582
|
+
// src/mcp/tools/session-history/fork/call-fork-session-mcp-tool.ts
|
|
42583
|
+
async function callForkSessionMcpTool(ctx, cloud, name, args) {
|
|
42584
|
+
const childSessionId = ctx.sessionId.trim();
|
|
42585
|
+
if (!childSessionId) {
|
|
42586
|
+
return mcpTextResult("sessionId is required.", true);
|
|
42587
|
+
}
|
|
42588
|
+
const parentResolved = await resolveParentSessionIdForChild({
|
|
42589
|
+
childSessionId,
|
|
42590
|
+
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
42591
|
+
getCloudAccessToken: cloud.getCloudAccessToken
|
|
42592
|
+
});
|
|
42593
|
+
if (!parentResolved.ok) {
|
|
42594
|
+
return mcpTextResult(parentResolved.error, true);
|
|
42595
|
+
}
|
|
42596
|
+
const parentSessionId = parentResolved.parentSessionId;
|
|
42597
|
+
if (name === LIST_PARENT_SESSION_PROMPTS_TOOL) {
|
|
42598
|
+
return callListParentSessionPromptsTool(ctx, cloud, childSessionId, parentSessionId);
|
|
42599
|
+
}
|
|
42600
|
+
if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL) {
|
|
42601
|
+
return callGetParentSessionTurnTranscriptTool(ctx, cloud, childSessionId, args);
|
|
42602
|
+
}
|
|
42603
|
+
return mcpTextResult(`Unknown fork session tool: ${name}`, true);
|
|
42604
|
+
}
|
|
42605
|
+
|
|
42606
|
+
// src/mcp/tools/session-history/fork/tool-definitions.ts
|
|
42097
42607
|
var SESSION_ID_SCHEMA = {
|
|
42098
42608
|
type: "string",
|
|
42099
42609
|
description: "Id of this forked (child) session \u2014 not the parent session id. Required on every tool call."
|
|
@@ -42123,57 +42633,11 @@ var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
|
|
|
42123
42633
|
}
|
|
42124
42634
|
}
|
|
42125
42635
|
];
|
|
42126
|
-
|
|
42127
|
-
|
|
42128
|
-
}
|
|
42636
|
+
|
|
42637
|
+
// src/mcp/tools/session-history/fork/is-fork-session-mcp-tool-name.ts
|
|
42129
42638
|
function isForkSessionMcpToolName(name) {
|
|
42130
42639
|
return name === LIST_PARENT_SESSION_PROMPTS_TOOL || name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL;
|
|
42131
42640
|
}
|
|
42132
|
-
async function callForkSessionMcpTool(ctx, cloud, name, args) {
|
|
42133
|
-
const childSessionId = ctx.sessionId.trim();
|
|
42134
|
-
if (!childSessionId) {
|
|
42135
|
-
return textResult("sessionId is required.", true);
|
|
42136
|
-
}
|
|
42137
|
-
const parentResolved = await resolveParentSessionIdForChild({
|
|
42138
|
-
childSessionId,
|
|
42139
|
-
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
42140
|
-
getCloudAccessToken: cloud.getCloudAccessToken
|
|
42141
|
-
});
|
|
42142
|
-
if (!parentResolved.ok) {
|
|
42143
|
-
return textResult(parentResolved.error, true);
|
|
42144
|
-
}
|
|
42145
|
-
const parentSessionId = parentResolved.parentSessionId;
|
|
42146
|
-
if (name === LIST_PARENT_SESSION_PROMPTS_TOOL) {
|
|
42147
|
-
const detail = await fetchCloudParentSessionPrompts({
|
|
42148
|
-
childSessionId,
|
|
42149
|
-
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
42150
|
-
getCloudAccessToken: cloud.getCloudAccessToken
|
|
42151
|
-
});
|
|
42152
|
-
if (!detail.ok) return textResult(detail.error, true);
|
|
42153
|
-
const turns = Array.isArray(detail.data.turns) ? detail.data.turns : [];
|
|
42154
|
-
const payload = turns.map((t) => ({
|
|
42155
|
-
turnId: typeof t.turnId === "string" ? t.turnId : "",
|
|
42156
|
-
title: typeof t.title === "string" ? t.title : null,
|
|
42157
|
-
status: typeof t.status === "string" ? t.status : null,
|
|
42158
|
-
promptText: typeof t.promptText === "string" ? t.promptText : null
|
|
42159
|
-
}));
|
|
42160
|
-
return textResult(JSON.stringify({ parentSessionId, turns: payload }, null, 2));
|
|
42161
|
-
}
|
|
42162
|
-
if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL) {
|
|
42163
|
-
const turnId = typeof args.turnId === "string" ? args.turnId.trim() : "";
|
|
42164
|
-
if (!turnId) return textResult("turnId is required.", true);
|
|
42165
|
-
const transcript = await fetchCloudParentTurnTranscript({
|
|
42166
|
-
childSessionId,
|
|
42167
|
-
turnId,
|
|
42168
|
-
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
42169
|
-
getCloudAccessToken: cloud.getCloudAccessToken,
|
|
42170
|
-
e2ee: ctx.e2ee
|
|
42171
|
-
});
|
|
42172
|
-
if (!transcript.ok) return textResult(transcript.error, true);
|
|
42173
|
-
return textResult(transcript.text);
|
|
42174
|
-
}
|
|
42175
|
-
return textResult(`Unknown fork session tool: ${name}`, true);
|
|
42176
|
-
}
|
|
42177
42641
|
|
|
42178
42642
|
// src/mcp/bridge-mcp-tools.ts
|
|
42179
42643
|
function requireCloud(shared) {
|
|
@@ -42430,8 +42894,8 @@ async function createBridgeConnection(options) {
|
|
|
42430
42894
|
getCloudAccessToken: () => tokens.accessToken
|
|
42431
42895
|
};
|
|
42432
42896
|
const identifyReportedPaths = {
|
|
42433
|
-
bridgeRootPath:
|
|
42434
|
-
worktreesRootPath:
|
|
42897
|
+
bridgeRootPath: path46.resolve(getBridgeRoot()),
|
|
42898
|
+
worktreesRootPath: path46.resolve(worktreesRootPath)
|
|
42435
42899
|
};
|
|
42436
42900
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
42437
42901
|
state,
|
|
@@ -42686,9 +43150,9 @@ async function runCliAction(program2, opts) {
|
|
|
42686
43150
|
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
42687
43151
|
const bridgeRootOpt = (opts.bridgeRoot && typeof opts.bridgeRoot === "string" && opts.bridgeRoot.trim() ? opts.bridgeRoot.trim() : null) ?? (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim() ? opts.cwd.trim() : null);
|
|
42688
43152
|
if (bridgeRootOpt) {
|
|
42689
|
-
const resolvedBridgeRoot =
|
|
43153
|
+
const resolvedBridgeRoot = path47.resolve(process.cwd(), bridgeRootOpt);
|
|
42690
43154
|
try {
|
|
42691
|
-
const st =
|
|
43155
|
+
const st = fs41.statSync(resolvedBridgeRoot);
|
|
42692
43156
|
if (!st.isDirectory()) {
|
|
42693
43157
|
console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
|
|
42694
43158
|
process.exit(1);
|
|
@@ -42708,7 +43172,7 @@ async function runCliAction(program2, opts) {
|
|
|
42708
43172
|
);
|
|
42709
43173
|
let worktreesRootPath;
|
|
42710
43174
|
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
42711
|
-
worktreesRootPath =
|
|
43175
|
+
worktreesRootPath = path47.resolve(opts.worktreesRoot.trim());
|
|
42712
43176
|
}
|
|
42713
43177
|
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
42714
43178
|
if (e2eCertificates) {
|