@buildautomaton/cli 0.1.48 → 0.1.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1665 -950
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1644 -929
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -973,8 +973,8 @@ var require_command = __commonJS({
|
|
|
973
973
|
"../../node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports) {
|
|
974
974
|
var EventEmitter2 = __require("node:events").EventEmitter;
|
|
975
975
|
var childProcess2 = __require("node:child_process");
|
|
976
|
-
var
|
|
977
|
-
var
|
|
976
|
+
var path55 = __require("node:path");
|
|
977
|
+
var fs46 = __require("node:fs");
|
|
978
978
|
var process8 = __require("node:process");
|
|
979
979
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
980
980
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1906,11 +1906,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1906
1906
|
let launchWithNode = false;
|
|
1907
1907
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1908
1908
|
function findFile(baseDir, baseName) {
|
|
1909
|
-
const localBin =
|
|
1910
|
-
if (
|
|
1911
|
-
if (sourceExt.includes(
|
|
1909
|
+
const localBin = path55.resolve(baseDir, baseName);
|
|
1910
|
+
if (fs46.existsSync(localBin)) return localBin;
|
|
1911
|
+
if (sourceExt.includes(path55.extname(baseName))) return void 0;
|
|
1912
1912
|
const foundExt = sourceExt.find(
|
|
1913
|
-
(ext) =>
|
|
1913
|
+
(ext) => fs46.existsSync(`${localBin}${ext}`)
|
|
1914
1914
|
);
|
|
1915
1915
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1916
1916
|
return void 0;
|
|
@@ -1922,21 +1922,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1922
1922
|
if (this._scriptPath) {
|
|
1923
1923
|
let resolvedScriptPath;
|
|
1924
1924
|
try {
|
|
1925
|
-
resolvedScriptPath =
|
|
1925
|
+
resolvedScriptPath = fs46.realpathSync(this._scriptPath);
|
|
1926
1926
|
} catch (err) {
|
|
1927
1927
|
resolvedScriptPath = this._scriptPath;
|
|
1928
1928
|
}
|
|
1929
|
-
executableDir =
|
|
1930
|
-
|
|
1929
|
+
executableDir = path55.resolve(
|
|
1930
|
+
path55.dirname(resolvedScriptPath),
|
|
1931
1931
|
executableDir
|
|
1932
1932
|
);
|
|
1933
1933
|
}
|
|
1934
1934
|
if (executableDir) {
|
|
1935
1935
|
let localFile = findFile(executableDir, executableFile);
|
|
1936
1936
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1937
|
-
const legacyName =
|
|
1937
|
+
const legacyName = path55.basename(
|
|
1938
1938
|
this._scriptPath,
|
|
1939
|
-
|
|
1939
|
+
path55.extname(this._scriptPath)
|
|
1940
1940
|
);
|
|
1941
1941
|
if (legacyName !== this._name) {
|
|
1942
1942
|
localFile = findFile(
|
|
@@ -1947,7 +1947,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1947
1947
|
}
|
|
1948
1948
|
executableFile = localFile || executableFile;
|
|
1949
1949
|
}
|
|
1950
|
-
launchWithNode = sourceExt.includes(
|
|
1950
|
+
launchWithNode = sourceExt.includes(path55.extname(executableFile));
|
|
1951
1951
|
let proc;
|
|
1952
1952
|
if (process8.platform !== "win32") {
|
|
1953
1953
|
if (launchWithNode) {
|
|
@@ -2787,7 +2787,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2787
2787
|
* @return {Command}
|
|
2788
2788
|
*/
|
|
2789
2789
|
nameFromFilename(filename) {
|
|
2790
|
-
this._name =
|
|
2790
|
+
this._name = path55.basename(filename, path55.extname(filename));
|
|
2791
2791
|
return this;
|
|
2792
2792
|
}
|
|
2793
2793
|
/**
|
|
@@ -2801,9 +2801,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2801
2801
|
* @param {string} [path]
|
|
2802
2802
|
* @return {(string|null|Command)}
|
|
2803
2803
|
*/
|
|
2804
|
-
executableDir(
|
|
2805
|
-
if (
|
|
2806
|
-
this._executableDir =
|
|
2804
|
+
executableDir(path56) {
|
|
2805
|
+
if (path56 === void 0) return this._executableDir;
|
|
2806
|
+
this._executableDir = path56;
|
|
2807
2807
|
return this;
|
|
2808
2808
|
}
|
|
2809
2809
|
/**
|
|
@@ -7061,8 +7061,8 @@ var init_parseUtil = __esm({
|
|
|
7061
7061
|
init_errors();
|
|
7062
7062
|
init_en();
|
|
7063
7063
|
makeIssue = (params) => {
|
|
7064
|
-
const { data, path:
|
|
7065
|
-
const fullPath = [...
|
|
7064
|
+
const { data, path: path55, errorMaps, issueData } = params;
|
|
7065
|
+
const fullPath = [...path55, ...issueData.path || []];
|
|
7066
7066
|
const fullIssue = {
|
|
7067
7067
|
...issueData,
|
|
7068
7068
|
path: fullPath
|
|
@@ -7370,11 +7370,11 @@ var init_types = __esm({
|
|
|
7370
7370
|
init_parseUtil();
|
|
7371
7371
|
init_util();
|
|
7372
7372
|
ParseInputLazyPath = class {
|
|
7373
|
-
constructor(parent, value,
|
|
7373
|
+
constructor(parent, value, path55, key) {
|
|
7374
7374
|
this._cachedPath = [];
|
|
7375
7375
|
this.parent = parent;
|
|
7376
7376
|
this.data = value;
|
|
7377
|
-
this._path =
|
|
7377
|
+
this._path = path55;
|
|
7378
7378
|
this._key = key;
|
|
7379
7379
|
}
|
|
7380
7380
|
get path() {
|
|
@@ -11099,15 +11099,15 @@ function assignProp(target, prop, value) {
|
|
|
11099
11099
|
configurable: true
|
|
11100
11100
|
});
|
|
11101
11101
|
}
|
|
11102
|
-
function getElementAtPath(obj,
|
|
11103
|
-
if (!
|
|
11102
|
+
function getElementAtPath(obj, path55) {
|
|
11103
|
+
if (!path55)
|
|
11104
11104
|
return obj;
|
|
11105
|
-
return
|
|
11105
|
+
return path55.reduce((acc, key) => acc?.[key], obj);
|
|
11106
11106
|
}
|
|
11107
11107
|
function promiseAllObject(promisesObj) {
|
|
11108
11108
|
const keys = Object.keys(promisesObj);
|
|
11109
|
-
const
|
|
11110
|
-
return Promise.all(
|
|
11109
|
+
const promises11 = keys.map((key) => promisesObj[key]);
|
|
11110
|
+
return Promise.all(promises11).then((results) => {
|
|
11111
11111
|
const resolvedObj = {};
|
|
11112
11112
|
for (let i = 0; i < keys.length; i++) {
|
|
11113
11113
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -11351,11 +11351,11 @@ function aborted(x, startIndex = 0) {
|
|
|
11351
11351
|
}
|
|
11352
11352
|
return false;
|
|
11353
11353
|
}
|
|
11354
|
-
function prefixIssues(
|
|
11354
|
+
function prefixIssues(path55, issues) {
|
|
11355
11355
|
return issues.map((iss) => {
|
|
11356
11356
|
var _a2;
|
|
11357
11357
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
11358
|
-
iss.path.unshift(
|
|
11358
|
+
iss.path.unshift(path55);
|
|
11359
11359
|
return iss;
|
|
11360
11360
|
});
|
|
11361
11361
|
}
|
|
@@ -11544,7 +11544,7 @@ function treeifyError(error40, _mapper) {
|
|
|
11544
11544
|
return issue2.message;
|
|
11545
11545
|
};
|
|
11546
11546
|
const result = { errors: [] };
|
|
11547
|
-
const processError = (error41,
|
|
11547
|
+
const processError = (error41, path55 = []) => {
|
|
11548
11548
|
var _a2, _b;
|
|
11549
11549
|
for (const issue2 of error41.issues) {
|
|
11550
11550
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -11554,7 +11554,7 @@ function treeifyError(error40, _mapper) {
|
|
|
11554
11554
|
} else if (issue2.code === "invalid_element") {
|
|
11555
11555
|
processError({ issues: issue2.issues }, issue2.path);
|
|
11556
11556
|
} else {
|
|
11557
|
-
const fullpath = [...
|
|
11557
|
+
const fullpath = [...path55, ...issue2.path];
|
|
11558
11558
|
if (fullpath.length === 0) {
|
|
11559
11559
|
result.errors.push(mapper(issue2));
|
|
11560
11560
|
continue;
|
|
@@ -11584,9 +11584,9 @@ function treeifyError(error40, _mapper) {
|
|
|
11584
11584
|
processError(error40);
|
|
11585
11585
|
return result;
|
|
11586
11586
|
}
|
|
11587
|
-
function toDotPath(
|
|
11587
|
+
function toDotPath(path55) {
|
|
11588
11588
|
const segs = [];
|
|
11589
|
-
for (const seg of
|
|
11589
|
+
for (const seg of path55) {
|
|
11590
11590
|
if (typeof seg === "number")
|
|
11591
11591
|
segs.push(`[${seg}]`);
|
|
11592
11592
|
else if (typeof seg === "symbol")
|
|
@@ -24049,8 +24049,8 @@ var init_acp = __esm({
|
|
|
24049
24049
|
this.#requestHandler = requestHandler;
|
|
24050
24050
|
this.#notificationHandler = notificationHandler;
|
|
24051
24051
|
this.#stream = stream;
|
|
24052
|
-
this.#closedPromise = new Promise((
|
|
24053
|
-
this.#abortController.signal.addEventListener("abort", () =>
|
|
24052
|
+
this.#closedPromise = new Promise((resolve28) => {
|
|
24053
|
+
this.#abortController.signal.addEventListener("abort", () => resolve28());
|
|
24054
24054
|
});
|
|
24055
24055
|
this.#receive();
|
|
24056
24056
|
}
|
|
@@ -24199,8 +24199,8 @@ var init_acp = __esm({
|
|
|
24199
24199
|
}
|
|
24200
24200
|
async sendRequest(method, params) {
|
|
24201
24201
|
const id = this.#nextRequestId++;
|
|
24202
|
-
const responsePromise = new Promise((
|
|
24203
|
-
this.#pendingResponses.set(id, { resolve:
|
|
24202
|
+
const responsePromise = new Promise((resolve28, reject) => {
|
|
24203
|
+
this.#pendingResponses.set(id, { resolve: resolve28, reject });
|
|
24204
24204
|
});
|
|
24205
24205
|
await this.#sendMessage({ jsonrpc: "2.0", id, method, params });
|
|
24206
24206
|
return responsePromise;
|
|
@@ -25069,10 +25069,10 @@ var require_src2 = __commonJS({
|
|
|
25069
25069
|
var fs_1 = __require("fs");
|
|
25070
25070
|
var debug_1 = __importDefault(require_src());
|
|
25071
25071
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
25072
|
-
function check2(
|
|
25073
|
-
log2(`checking %s`,
|
|
25072
|
+
function check2(path55, isFile, isDirectory) {
|
|
25073
|
+
log2(`checking %s`, path55);
|
|
25074
25074
|
try {
|
|
25075
|
-
const stat3 = fs_1.statSync(
|
|
25075
|
+
const stat3 = fs_1.statSync(path55);
|
|
25076
25076
|
if (stat3.isFile() && isFile) {
|
|
25077
25077
|
log2(`[OK] path represents a file`);
|
|
25078
25078
|
return true;
|
|
@@ -25092,8 +25092,8 @@ var require_src2 = __commonJS({
|
|
|
25092
25092
|
throw e;
|
|
25093
25093
|
}
|
|
25094
25094
|
}
|
|
25095
|
-
function exists2(
|
|
25096
|
-
return check2(
|
|
25095
|
+
function exists2(path55, type = exports.READABLE) {
|
|
25096
|
+
return check2(path55, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
25097
25097
|
}
|
|
25098
25098
|
exports.exists = exists2;
|
|
25099
25099
|
exports.FILE = 1;
|
|
@@ -25174,15 +25174,15 @@ var {
|
|
|
25174
25174
|
} = import_index.default;
|
|
25175
25175
|
|
|
25176
25176
|
// src/cli-version.ts
|
|
25177
|
-
var CLI_VERSION = "0.1.
|
|
25177
|
+
var CLI_VERSION = "0.1.50".length > 0 ? "0.1.50" : "0.0.0-dev";
|
|
25178
25178
|
|
|
25179
25179
|
// src/cli/defaults.ts
|
|
25180
25180
|
var DEFAULT_API_URL = process.env.BUILDAUTOMATON_API_URL ?? "https://api.buildautomaton.com";
|
|
25181
25181
|
var DEFAULT_FIREHOSE_URL = "https://buildautomaton-firehose.fly.dev";
|
|
25182
25182
|
|
|
25183
25183
|
// src/cli/run-cli-action.ts
|
|
25184
|
-
import * as
|
|
25185
|
-
import * as
|
|
25184
|
+
import * as fs45 from "node:fs";
|
|
25185
|
+
import * as path54 from "node:path";
|
|
25186
25186
|
|
|
25187
25187
|
// src/cli-log-level.ts
|
|
25188
25188
|
var verbosity = "info";
|
|
@@ -26297,14 +26297,14 @@ var baseOpen = async (options) => {
|
|
|
26297
26297
|
}
|
|
26298
26298
|
const subprocess = childProcess.spawn(command, cliArguments, childProcessOptions);
|
|
26299
26299
|
if (options.wait) {
|
|
26300
|
-
return new Promise((
|
|
26300
|
+
return new Promise((resolve28, reject) => {
|
|
26301
26301
|
subprocess.once("error", reject);
|
|
26302
26302
|
subprocess.once("close", (exitCode) => {
|
|
26303
26303
|
if (!options.allowNonzeroExitCode && exitCode > 0) {
|
|
26304
26304
|
reject(new Error(`Exited with code ${exitCode}`));
|
|
26305
26305
|
return;
|
|
26306
26306
|
}
|
|
26307
|
-
|
|
26307
|
+
resolve28(subprocess);
|
|
26308
26308
|
});
|
|
26309
26309
|
});
|
|
26310
26310
|
}
|
|
@@ -26848,8 +26848,8 @@ function runPendingAuth(options) {
|
|
|
26848
26848
|
let hasOpenedBrowser = false;
|
|
26849
26849
|
let resolved = false;
|
|
26850
26850
|
let resolveAuth;
|
|
26851
|
-
const authPromise = new Promise((
|
|
26852
|
-
resolveAuth =
|
|
26851
|
+
const authPromise = new Promise((resolve28) => {
|
|
26852
|
+
resolveAuth = resolve28;
|
|
26853
26853
|
});
|
|
26854
26854
|
let reconnectAttempt = 0;
|
|
26855
26855
|
const signInQuiet = createEmptyReconnectQuietSlot();
|
|
@@ -27000,7 +27000,7 @@ import sqliteWasm from "node-sqlite3-wasm";
|
|
|
27000
27000
|
|
|
27001
27001
|
// src/runtime/yield-to-event-loop.ts
|
|
27002
27002
|
function yieldToEventLoop() {
|
|
27003
|
-
return new Promise((
|
|
27003
|
+
return new Promise((resolve28) => setImmediate(resolve28));
|
|
27004
27004
|
}
|
|
27005
27005
|
|
|
27006
27006
|
// src/sqlite/cli-sqlite-paths.ts
|
|
@@ -27678,6 +27678,238 @@ var WebSocketMessageSchema = external_exports.object({
|
|
|
27678
27678
|
error: external_exports.string().optional()
|
|
27679
27679
|
});
|
|
27680
27680
|
|
|
27681
|
+
// ../types/src/integrations/link-detection/linear.ts
|
|
27682
|
+
function detectLinearLink(url2) {
|
|
27683
|
+
const linearMatch = url2.match(
|
|
27684
|
+
/https?:\/\/(?:app\.)?linear\.app\/([^/]+)\/issue\/([A-Z]+-\d+)/i
|
|
27685
|
+
);
|
|
27686
|
+
if (linearMatch) {
|
|
27687
|
+
return {
|
|
27688
|
+
url: url2,
|
|
27689
|
+
integrationType: "linear",
|
|
27690
|
+
resourceType: "work-item",
|
|
27691
|
+
resourceId: linearMatch[2],
|
|
27692
|
+
workspaceId: linearMatch[1]
|
|
27693
|
+
};
|
|
27694
|
+
}
|
|
27695
|
+
return null;
|
|
27696
|
+
}
|
|
27697
|
+
|
|
27698
|
+
// ../types/src/integrations/link-detection/github.ts
|
|
27699
|
+
function detectGitHubLink(url2) {
|
|
27700
|
+
const githubIssueMatch = url2.match(
|
|
27701
|
+
/https?:\/\/github\.com\/([^/]+)\/([^/]+)\/issues\/(\d+)/i
|
|
27702
|
+
);
|
|
27703
|
+
if (githubIssueMatch) {
|
|
27704
|
+
return {
|
|
27705
|
+
url: url2,
|
|
27706
|
+
integrationType: "github",
|
|
27707
|
+
resourceType: "issue",
|
|
27708
|
+
resourceId: githubIssueMatch[3],
|
|
27709
|
+
owner: githubIssueMatch[1],
|
|
27710
|
+
repo: githubIssueMatch[2]
|
|
27711
|
+
};
|
|
27712
|
+
}
|
|
27713
|
+
const githubPRMatch = url2.match(
|
|
27714
|
+
/https?:\/\/github\.com\/([^/]+)\/([^/]+)\/pull\/(\d+)/i
|
|
27715
|
+
);
|
|
27716
|
+
if (githubPRMatch) {
|
|
27717
|
+
return {
|
|
27718
|
+
url: url2,
|
|
27719
|
+
integrationType: "github",
|
|
27720
|
+
resourceType: "pull-request",
|
|
27721
|
+
resourceId: githubPRMatch[3],
|
|
27722
|
+
owner: githubPRMatch[1],
|
|
27723
|
+
repo: githubPRMatch[2]
|
|
27724
|
+
};
|
|
27725
|
+
}
|
|
27726
|
+
return null;
|
|
27727
|
+
}
|
|
27728
|
+
|
|
27729
|
+
// ../types/src/integrations/link-detection/jira.ts
|
|
27730
|
+
function detectJIRALink(url2) {
|
|
27731
|
+
const jiraMatch = url2.match(
|
|
27732
|
+
/https?:\/\/([^/]+)\.atlassian\.net\/(?:browse|jira\/software\/projects\/[^/]+\/issues)\/([A-Z]+-\d+)/i
|
|
27733
|
+
);
|
|
27734
|
+
if (jiraMatch) {
|
|
27735
|
+
return {
|
|
27736
|
+
url: url2,
|
|
27737
|
+
integrationType: "jira",
|
|
27738
|
+
resourceType: "issue",
|
|
27739
|
+
resourceId: jiraMatch[2],
|
|
27740
|
+
projectKey: jiraMatch[2].split("-")[0]
|
|
27741
|
+
};
|
|
27742
|
+
}
|
|
27743
|
+
return null;
|
|
27744
|
+
}
|
|
27745
|
+
|
|
27746
|
+
// ../types/src/integrations/link-detection/notion.ts
|
|
27747
|
+
function formatNotionPageId(hex) {
|
|
27748
|
+
if (hex.length !== 32) return hex;
|
|
27749
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
27750
|
+
}
|
|
27751
|
+
function detectNotionLink(url2) {
|
|
27752
|
+
const standardMatch = url2.match(
|
|
27753
|
+
/https?:\/\/(?:www\.)?notion\.(?:so|site)\/(?:[^/#?]+\/)?(?:[^/#?-]+-)?([a-f0-9]{32})/i
|
|
27754
|
+
);
|
|
27755
|
+
if (standardMatch) {
|
|
27756
|
+
return {
|
|
27757
|
+
url: url2,
|
|
27758
|
+
integrationType: "notion",
|
|
27759
|
+
resourceType: "page",
|
|
27760
|
+
resourceId: formatNotionPageId(standardMatch[1])
|
|
27761
|
+
};
|
|
27762
|
+
}
|
|
27763
|
+
const siteMatch = url2.match(
|
|
27764
|
+
/https?:\/\/([^.]+)\.notion\.(?:so|site)\/(?:[^/#?-]+-)?([a-f0-9]{32})/i
|
|
27765
|
+
);
|
|
27766
|
+
if (siteMatch) {
|
|
27767
|
+
return {
|
|
27768
|
+
url: url2,
|
|
27769
|
+
integrationType: "notion",
|
|
27770
|
+
resourceType: "page",
|
|
27771
|
+
resourceId: formatNotionPageId(siteMatch[2]),
|
|
27772
|
+
notionWorkspaceId: siteMatch[1]
|
|
27773
|
+
};
|
|
27774
|
+
}
|
|
27775
|
+
return null;
|
|
27776
|
+
}
|
|
27777
|
+
|
|
27778
|
+
// ../types/src/integrations/link-detection/slack.ts
|
|
27779
|
+
function detectSlackLink(url2) {
|
|
27780
|
+
const archiveThreadMatch = url2.match(
|
|
27781
|
+
/https?:\/\/(?:([^./]+)\.)?slack\.com\/archives\/([A-Z0-9]+)\/p(\d+)(?:\?.*)?$/i
|
|
27782
|
+
);
|
|
27783
|
+
if (archiveThreadMatch) {
|
|
27784
|
+
return {
|
|
27785
|
+
url: url2,
|
|
27786
|
+
integrationType: "slack",
|
|
27787
|
+
resourceType: "thread",
|
|
27788
|
+
resourceId: `${archiveThreadMatch[2]}-${archiveThreadMatch[3]}`,
|
|
27789
|
+
isChannel: false
|
|
27790
|
+
};
|
|
27791
|
+
}
|
|
27792
|
+
const appThreadMatch = url2.match(
|
|
27793
|
+
/https?:\/\/app\.slack\.com\/client\/([^/]+)\/([A-Z0-9]+)\/thread\/[A-Z0-9]+-(\d+)/i
|
|
27794
|
+
);
|
|
27795
|
+
if (appThreadMatch) {
|
|
27796
|
+
return {
|
|
27797
|
+
url: url2,
|
|
27798
|
+
integrationType: "slack",
|
|
27799
|
+
resourceType: "thread",
|
|
27800
|
+
resourceId: `${appThreadMatch[2]}-${appThreadMatch[3]}`,
|
|
27801
|
+
isChannel: false
|
|
27802
|
+
};
|
|
27803
|
+
}
|
|
27804
|
+
const channelOnlyMatch = url2.match(
|
|
27805
|
+
/https?:\/\/(?:app\.)?(?:([^./]+)\.)?slack\.com\/archives\/([A-Z0-9]+)\/?(\?.*)?$/i
|
|
27806
|
+
);
|
|
27807
|
+
if (channelOnlyMatch && !url2.includes("/p")) {
|
|
27808
|
+
return {
|
|
27809
|
+
url: url2,
|
|
27810
|
+
integrationType: "slack",
|
|
27811
|
+
resourceType: "channel",
|
|
27812
|
+
resourceId: channelOnlyMatch[2],
|
|
27813
|
+
isChannel: true
|
|
27814
|
+
};
|
|
27815
|
+
}
|
|
27816
|
+
return null;
|
|
27817
|
+
}
|
|
27818
|
+
|
|
27819
|
+
// ../types/src/integrations/link-detection/zoom.ts
|
|
27820
|
+
function detectZoomLink(url2) {
|
|
27821
|
+
try {
|
|
27822
|
+
const u = new URL(url2);
|
|
27823
|
+
const host = u.hostname.toLowerCase();
|
|
27824
|
+
if (!host.endsWith("zoom.us") && !host.endsWith("zoom.com")) return null;
|
|
27825
|
+
const pathParts = u.pathname.split("/").filter(Boolean);
|
|
27826
|
+
if (pathParts.length >= 2 && (pathParts[0] === "j" || pathParts[0] === "s" || pathParts[0] === "my")) {
|
|
27827
|
+
const meetingId = pathParts[1].replace(/\s/g, "");
|
|
27828
|
+
if (meetingId.length >= 9) {
|
|
27829
|
+
return {
|
|
27830
|
+
url: url2,
|
|
27831
|
+
integrationType: "zoom",
|
|
27832
|
+
resourceType: "meeting",
|
|
27833
|
+
resourceId: meetingId,
|
|
27834
|
+
zoomMeetingId: meetingId
|
|
27835
|
+
};
|
|
27836
|
+
}
|
|
27837
|
+
}
|
|
27838
|
+
} catch {
|
|
27839
|
+
}
|
|
27840
|
+
return null;
|
|
27841
|
+
}
|
|
27842
|
+
|
|
27843
|
+
// ../types/src/integrations/link-detection/asana.ts
|
|
27844
|
+
var ASANA_TASK_GID = /\d{10,}/;
|
|
27845
|
+
function parseAsanaTaskGid(segment) {
|
|
27846
|
+
const trimmed2 = segment.trim();
|
|
27847
|
+
if (!ASANA_TASK_GID.test(trimmed2)) return null;
|
|
27848
|
+
return trimmed2;
|
|
27849
|
+
}
|
|
27850
|
+
function detectAsanaLink(url2) {
|
|
27851
|
+
const v1ProjectMatch = url2.match(
|
|
27852
|
+
/https?:\/\/app\.asana\.com\/1\/[^/]+\/project\/([^/?#]+)\/task\/([^/?#]+)/i
|
|
27853
|
+
);
|
|
27854
|
+
if (v1ProjectMatch) {
|
|
27855
|
+
const taskGid = parseAsanaTaskGid(v1ProjectMatch[2]);
|
|
27856
|
+
if (!taskGid) return null;
|
|
27857
|
+
return {
|
|
27858
|
+
url: url2,
|
|
27859
|
+
integrationType: "asana",
|
|
27860
|
+
resourceType: "task",
|
|
27861
|
+
resourceId: taskGid,
|
|
27862
|
+
asanaProjectGid: v1ProjectMatch[1]
|
|
27863
|
+
};
|
|
27864
|
+
}
|
|
27865
|
+
const v1TaskMatch = url2.match(/https?:\/\/app\.asana\.com\/1\/[^/]+(?:\/[^/]+)*\/task\/([^/?#]+)/i);
|
|
27866
|
+
if (v1TaskMatch) {
|
|
27867
|
+
const taskGid = parseAsanaTaskGid(v1TaskMatch[1]);
|
|
27868
|
+
if (!taskGid) return null;
|
|
27869
|
+
return {
|
|
27870
|
+
url: url2,
|
|
27871
|
+
integrationType: "asana",
|
|
27872
|
+
resourceType: "task",
|
|
27873
|
+
resourceId: taskGid
|
|
27874
|
+
};
|
|
27875
|
+
}
|
|
27876
|
+
const legacyMatch = url2.match(/https?:\/\/app\.asana\.com\/0\/([^/?#]+)\/([^/?#]+)/i);
|
|
27877
|
+
if (legacyMatch) {
|
|
27878
|
+
const projectGid = legacyMatch[1];
|
|
27879
|
+
const taskGid = parseAsanaTaskGid(legacyMatch[2]);
|
|
27880
|
+
if (!taskGid) return null;
|
|
27881
|
+
if (projectGid === "inbox" || projectGid === "my_tasks") {
|
|
27882
|
+
return null;
|
|
27883
|
+
}
|
|
27884
|
+
return {
|
|
27885
|
+
url: url2,
|
|
27886
|
+
integrationType: "asana",
|
|
27887
|
+
resourceType: "task",
|
|
27888
|
+
resourceId: taskGid,
|
|
27889
|
+
asanaProjectGid: projectGid === "0" ? void 0 : projectGid
|
|
27890
|
+
};
|
|
27891
|
+
}
|
|
27892
|
+
return null;
|
|
27893
|
+
}
|
|
27894
|
+
|
|
27895
|
+
// ../types/src/integrations/link-detection/index.ts
|
|
27896
|
+
function detectIntegrationLink(url2) {
|
|
27897
|
+
return detectLinearLink(url2) || detectGitHubLink(url2) || detectJIRALink(url2) || detectNotionLink(url2) || detectSlackLink(url2) || detectZoomLink(url2) || detectAsanaLink(url2);
|
|
27898
|
+
}
|
|
27899
|
+
function extractIntegrationLinks(text) {
|
|
27900
|
+
const urlRegex = /https?:\/\/[^\s<>"{}|\\^`[\]]+/gi;
|
|
27901
|
+
const urls = text.match(urlRegex) || [];
|
|
27902
|
+
const links = [];
|
|
27903
|
+
for (const url2 of urls) {
|
|
27904
|
+
const detected = detectIntegrationLink(url2);
|
|
27905
|
+
if (detected) links.push(detected);
|
|
27906
|
+
}
|
|
27907
|
+
return links;
|
|
27908
|
+
}
|
|
27909
|
+
function extractFetchableIntegrationLinks(text) {
|
|
27910
|
+
return extractIntegrationLinks(text).filter((link) => !(link.integrationType === "slack" && link.isChannel));
|
|
27911
|
+
}
|
|
27912
|
+
|
|
27681
27913
|
// ../types/src/checkpoints.ts
|
|
27682
27914
|
init_zod();
|
|
27683
27915
|
var CheckpointKindSchema = external_exports.enum(["daily", "weekly", "overall"]);
|
|
@@ -27885,9 +28117,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
27885
28117
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
27886
28118
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
27887
28119
|
if (!rawPath || !summary) continue;
|
|
27888
|
-
const
|
|
27889
|
-
if (!
|
|
27890
|
-
rows.push({ path:
|
|
28120
|
+
const path55 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
28121
|
+
if (!path55) continue;
|
|
28122
|
+
rows.push({ path: path55, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
27891
28123
|
}
|
|
27892
28124
|
return rows;
|
|
27893
28125
|
}
|
|
@@ -28105,6 +28337,16 @@ var GitRepoMetaSchema = external_exports.object({
|
|
|
28105
28337
|
updatedAt: external_exports.string()
|
|
28106
28338
|
});
|
|
28107
28339
|
|
|
28340
|
+
// ../types/src/mcp/bridge-mcp-constants.ts
|
|
28341
|
+
var GET_INTEGRATION_CONTENT_TOOL = "get_integration_content";
|
|
28342
|
+
var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
|
|
28343
|
+
var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
|
|
28344
|
+
var BRIDGE_MCP_TOOL_LABELS = {
|
|
28345
|
+
[GET_INTEGRATION_CONTENT_TOOL]: "Fetch external ticket content",
|
|
28346
|
+
[LIST_PARENT_SESSION_PROMPTS_TOOL]: "List parent session prompts",
|
|
28347
|
+
[GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL]: "Read parent session transcript"
|
|
28348
|
+
};
|
|
28349
|
+
|
|
28108
28350
|
// ../types/src/claude-code-permission-mode.ts
|
|
28109
28351
|
var CLAUDE_CODE_PERMISSION_MODES = [
|
|
28110
28352
|
"default",
|
|
@@ -28389,10 +28631,10 @@ async function killChildProcessTreeGracefully(child, graceMs = ACP_PROCESS_TREE_
|
|
|
28389
28631
|
}
|
|
28390
28632
|
await killProcessTree(pid, "SIGTERM");
|
|
28391
28633
|
if (graceMs <= 0) return;
|
|
28392
|
-
const exited = new Promise((
|
|
28393
|
-
child.once("exit", () =>
|
|
28634
|
+
const exited = new Promise((resolve28) => {
|
|
28635
|
+
child.once("exit", () => resolve28());
|
|
28394
28636
|
});
|
|
28395
|
-
await Promise.race([exited, new Promise((
|
|
28637
|
+
await Promise.race([exited, new Promise((resolve28) => setTimeout(resolve28, graceMs))]);
|
|
28396
28638
|
if (child.exitCode == null && child.signalCode == null) {
|
|
28397
28639
|
await killProcessTree(pid, "SIGKILL");
|
|
28398
28640
|
}
|
|
@@ -28409,8 +28651,8 @@ async function gracefulAcpSubprocessDisconnect(params) {
|
|
|
28409
28651
|
await transport.closeSession?.(sessionId);
|
|
28410
28652
|
} catch {
|
|
28411
28653
|
}
|
|
28412
|
-
await new Promise((
|
|
28413
|
-
const timer = setTimeout(
|
|
28654
|
+
await new Promise((resolve28) => {
|
|
28655
|
+
const timer = setTimeout(resolve28, ACP_GRACEFUL_SESSION_CLOSE_WAIT_MS);
|
|
28414
28656
|
timer.unref?.();
|
|
28415
28657
|
});
|
|
28416
28658
|
}
|
|
@@ -28685,11 +28927,11 @@ function createSdkStdioExtNotificationHandler(options) {
|
|
|
28685
28927
|
// src/agents/acp/clients/sdk/sdk-stdio-permission-request-handshake.ts
|
|
28686
28928
|
function awaitSdkStdioPermissionRequestHandshake(params) {
|
|
28687
28929
|
const { requestId, paramsRecord, pending, onRequest } = params;
|
|
28688
|
-
return new Promise((
|
|
28689
|
-
pending.set(requestId, { resolve:
|
|
28930
|
+
return new Promise((resolve28) => {
|
|
28931
|
+
pending.set(requestId, { resolve: resolve28, params: paramsRecord });
|
|
28690
28932
|
if (onRequest == null) {
|
|
28691
28933
|
pending.delete(requestId);
|
|
28692
|
-
|
|
28934
|
+
resolve28({ outcome: { outcome: "denied" } });
|
|
28693
28935
|
return;
|
|
28694
28936
|
}
|
|
28695
28937
|
try {
|
|
@@ -29199,10 +29441,10 @@ function createSdkStdioInitSettle(child) {
|
|
|
29199
29441
|
forceAcpSubprocessDisconnect(child);
|
|
29200
29442
|
reject(err);
|
|
29201
29443
|
},
|
|
29202
|
-
settleResolve(
|
|
29444
|
+
settleResolve(resolve28, handle) {
|
|
29203
29445
|
if (initSettled) return;
|
|
29204
29446
|
initSettled = true;
|
|
29205
|
-
|
|
29447
|
+
resolve28(handle);
|
|
29206
29448
|
}
|
|
29207
29449
|
};
|
|
29208
29450
|
}
|
|
@@ -29271,7 +29513,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
29271
29513
|
onFileChange,
|
|
29272
29514
|
stderrCapture
|
|
29273
29515
|
});
|
|
29274
|
-
return new Promise((
|
|
29516
|
+
return new Promise((resolve28, reject) => {
|
|
29275
29517
|
const init = createSdkStdioInitSettle(child);
|
|
29276
29518
|
child.on("error", (err) => {
|
|
29277
29519
|
init.settleReject(reject, new Error(formatSpawnError(err, command[0])));
|
|
@@ -29296,7 +29538,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
29296
29538
|
protocolVersion: PROTOCOL_VERSION2
|
|
29297
29539
|
});
|
|
29298
29540
|
init.settleResolve(
|
|
29299
|
-
|
|
29541
|
+
resolve28,
|
|
29300
29542
|
createSdkStdioHandle({
|
|
29301
29543
|
child,
|
|
29302
29544
|
sessionId: established.sessionId,
|
|
@@ -29829,7 +30071,7 @@ async function createCursorAcpClient(options) {
|
|
|
29829
30071
|
onFileChange,
|
|
29830
30072
|
stderrCapture
|
|
29831
30073
|
});
|
|
29832
|
-
return new Promise((
|
|
30074
|
+
return new Promise((resolve28, reject) => {
|
|
29833
30075
|
child.on("error", (err) => {
|
|
29834
30076
|
killChildProcessTree(child, "SIGKILL");
|
|
29835
30077
|
reject(new Error(formatSpawnError(err, command[0])));
|
|
@@ -29841,7 +30083,7 @@ async function createCursorAcpClient(options) {
|
|
|
29841
30083
|
sessionCtx,
|
|
29842
30084
|
incomingDeps: { dbgFs, sessionCtx, onSessionUpdate, onRequest }
|
|
29843
30085
|
});
|
|
29844
|
-
|
|
30086
|
+
resolve28(
|
|
29845
30087
|
createCursorAcpHandle({
|
|
29846
30088
|
child,
|
|
29847
30089
|
sessionId: established.sessionId,
|
|
@@ -30779,7 +31021,7 @@ function computeAcpAgentKey(preferredAgentType, mode, agentConfig) {
|
|
|
30779
31021
|
}
|
|
30780
31022
|
|
|
30781
31023
|
// src/mcp/bridge-mcp-constants.ts
|
|
30782
|
-
var
|
|
31024
|
+
var BRIDGE_MCP_SERVER_NAME2 = "buildautomaton-bridge";
|
|
30783
31025
|
|
|
30784
31026
|
// src/mcp/resolve-bridge-mcp-server-path.ts
|
|
30785
31027
|
import { dirname as dirname4, join as join3 } from "node:path";
|
|
@@ -30794,7 +31036,7 @@ function buildAcpMcpServers(bridgeAccessPort) {
|
|
|
30794
31036
|
if (!Number.isFinite(bridgeAccessPort) || bridgeAccessPort <= 0) return [];
|
|
30795
31037
|
return [
|
|
30796
31038
|
{
|
|
30797
|
-
name:
|
|
31039
|
+
name: BRIDGE_MCP_SERVER_NAME2,
|
|
30798
31040
|
command: process.execPath,
|
|
30799
31041
|
args: [resolveBridgeMcpServerScriptPath(), String(bridgeAccessPort)],
|
|
30800
31042
|
env: []
|
|
@@ -31047,8 +31289,8 @@ function pathspec(...paths) {
|
|
|
31047
31289
|
cache.set(key, paths);
|
|
31048
31290
|
return key;
|
|
31049
31291
|
}
|
|
31050
|
-
function isPathSpec(
|
|
31051
|
-
return
|
|
31292
|
+
function isPathSpec(path55) {
|
|
31293
|
+
return path55 instanceof String && cache.has(path55);
|
|
31052
31294
|
}
|
|
31053
31295
|
function toPaths(pathSpec) {
|
|
31054
31296
|
return cache.get(pathSpec) || [];
|
|
@@ -31137,8 +31379,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
31137
31379
|
function forEachLineWithContent(input, callback) {
|
|
31138
31380
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
31139
31381
|
}
|
|
31140
|
-
function folderExists(
|
|
31141
|
-
return (0, import_file_exists.exists)(
|
|
31382
|
+
function folderExists(path55) {
|
|
31383
|
+
return (0, import_file_exists.exists)(path55, import_file_exists.FOLDER);
|
|
31142
31384
|
}
|
|
31143
31385
|
function append(target, item) {
|
|
31144
31386
|
if (Array.isArray(target)) {
|
|
@@ -31542,8 +31784,8 @@ function checkIsRepoRootTask() {
|
|
|
31542
31784
|
commands,
|
|
31543
31785
|
format: "utf-8",
|
|
31544
31786
|
onError,
|
|
31545
|
-
parser(
|
|
31546
|
-
return /^\.(git)?$/.test(
|
|
31787
|
+
parser(path55) {
|
|
31788
|
+
return /^\.(git)?$/.test(path55.trim());
|
|
31547
31789
|
}
|
|
31548
31790
|
};
|
|
31549
31791
|
}
|
|
@@ -31977,11 +32219,11 @@ function parseGrep(grep) {
|
|
|
31977
32219
|
const paths = /* @__PURE__ */ new Set();
|
|
31978
32220
|
const results = {};
|
|
31979
32221
|
forEachLineWithContent(grep, (input) => {
|
|
31980
|
-
const [
|
|
31981
|
-
paths.add(
|
|
31982
|
-
(results[
|
|
32222
|
+
const [path55, line, preview] = input.split(NULL);
|
|
32223
|
+
paths.add(path55);
|
|
32224
|
+
(results[path55] = results[path55] || []).push({
|
|
31983
32225
|
line: asNumber(line),
|
|
31984
|
-
path:
|
|
32226
|
+
path: path55,
|
|
31985
32227
|
preview
|
|
31986
32228
|
});
|
|
31987
32229
|
});
|
|
@@ -32746,14 +32988,14 @@ var init_hash_object = __esm2({
|
|
|
32746
32988
|
init_task();
|
|
32747
32989
|
}
|
|
32748
32990
|
});
|
|
32749
|
-
function parseInit(bare,
|
|
32991
|
+
function parseInit(bare, path55, text) {
|
|
32750
32992
|
const response = String(text).trim();
|
|
32751
32993
|
let result;
|
|
32752
32994
|
if (result = initResponseRegex.exec(response)) {
|
|
32753
|
-
return new InitSummary(bare,
|
|
32995
|
+
return new InitSummary(bare, path55, false, result[1]);
|
|
32754
32996
|
}
|
|
32755
32997
|
if (result = reInitResponseRegex.exec(response)) {
|
|
32756
|
-
return new InitSummary(bare,
|
|
32998
|
+
return new InitSummary(bare, path55, true, result[1]);
|
|
32757
32999
|
}
|
|
32758
33000
|
let gitDir = "";
|
|
32759
33001
|
const tokens = response.split(" ");
|
|
@@ -32764,7 +33006,7 @@ function parseInit(bare, path48, text) {
|
|
|
32764
33006
|
break;
|
|
32765
33007
|
}
|
|
32766
33008
|
}
|
|
32767
|
-
return new InitSummary(bare,
|
|
33009
|
+
return new InitSummary(bare, path55, /^re/i.test(response), gitDir);
|
|
32768
33010
|
}
|
|
32769
33011
|
var InitSummary;
|
|
32770
33012
|
var initResponseRegex;
|
|
@@ -32773,9 +33015,9 @@ var init_InitSummary = __esm2({
|
|
|
32773
33015
|
"src/lib/responses/InitSummary.ts"() {
|
|
32774
33016
|
"use strict";
|
|
32775
33017
|
InitSummary = class {
|
|
32776
|
-
constructor(bare,
|
|
33018
|
+
constructor(bare, path55, existing, gitDir) {
|
|
32777
33019
|
this.bare = bare;
|
|
32778
|
-
this.path =
|
|
33020
|
+
this.path = path55;
|
|
32779
33021
|
this.existing = existing;
|
|
32780
33022
|
this.gitDir = gitDir;
|
|
32781
33023
|
}
|
|
@@ -32787,7 +33029,7 @@ var init_InitSummary = __esm2({
|
|
|
32787
33029
|
function hasBareCommand(command) {
|
|
32788
33030
|
return command.includes(bareCommand);
|
|
32789
33031
|
}
|
|
32790
|
-
function initTask(bare = false,
|
|
33032
|
+
function initTask(bare = false, path55, customArgs) {
|
|
32791
33033
|
const commands = ["init", ...customArgs];
|
|
32792
33034
|
if (bare && !hasBareCommand(commands)) {
|
|
32793
33035
|
commands.splice(1, 0, bareCommand);
|
|
@@ -32796,7 +33038,7 @@ function initTask(bare = false, path48, customArgs) {
|
|
|
32796
33038
|
commands,
|
|
32797
33039
|
format: "utf-8",
|
|
32798
33040
|
parser(text) {
|
|
32799
|
-
return parseInit(commands.includes("--bare"),
|
|
33041
|
+
return parseInit(commands.includes("--bare"), path55, text);
|
|
32800
33042
|
}
|
|
32801
33043
|
};
|
|
32802
33044
|
}
|
|
@@ -33612,12 +33854,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
33612
33854
|
"use strict";
|
|
33613
33855
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
33614
33856
|
FileStatusSummary = class {
|
|
33615
|
-
constructor(
|
|
33616
|
-
this.path =
|
|
33857
|
+
constructor(path55, index, working_dir) {
|
|
33858
|
+
this.path = path55;
|
|
33617
33859
|
this.index = index;
|
|
33618
33860
|
this.working_dir = working_dir;
|
|
33619
33861
|
if (index === "R" || working_dir === "R") {
|
|
33620
|
-
const detail = fromPathRegex.exec(
|
|
33862
|
+
const detail = fromPathRegex.exec(path55) || [null, path55, path55];
|
|
33621
33863
|
this.from = detail[2] || "";
|
|
33622
33864
|
this.path = detail[1] || "";
|
|
33623
33865
|
}
|
|
@@ -33648,14 +33890,14 @@ function splitLine(result, lineStr) {
|
|
|
33648
33890
|
default:
|
|
33649
33891
|
return;
|
|
33650
33892
|
}
|
|
33651
|
-
function data(index, workingDir,
|
|
33893
|
+
function data(index, workingDir, path55) {
|
|
33652
33894
|
const raw = `${index}${workingDir}`;
|
|
33653
33895
|
const handler = parsers6.get(raw);
|
|
33654
33896
|
if (handler) {
|
|
33655
|
-
handler(result,
|
|
33897
|
+
handler(result, path55);
|
|
33656
33898
|
}
|
|
33657
33899
|
if (raw !== "##" && raw !== "!!") {
|
|
33658
|
-
result.files.push(new FileStatusSummary(
|
|
33900
|
+
result.files.push(new FileStatusSummary(path55, index, workingDir));
|
|
33659
33901
|
}
|
|
33660
33902
|
}
|
|
33661
33903
|
}
|
|
@@ -33964,9 +34206,9 @@ var init_simple_git_api = __esm2({
|
|
|
33964
34206
|
next
|
|
33965
34207
|
);
|
|
33966
34208
|
}
|
|
33967
|
-
hashObject(
|
|
34209
|
+
hashObject(path55, write) {
|
|
33968
34210
|
return this._runTask(
|
|
33969
|
-
hashObjectTask(
|
|
34211
|
+
hashObjectTask(path55, write === true),
|
|
33970
34212
|
trailingFunctionArgument(arguments)
|
|
33971
34213
|
);
|
|
33972
34214
|
}
|
|
@@ -34319,8 +34561,8 @@ var init_branch = __esm2({
|
|
|
34319
34561
|
}
|
|
34320
34562
|
});
|
|
34321
34563
|
function toPath(input) {
|
|
34322
|
-
const
|
|
34323
|
-
return
|
|
34564
|
+
const path55 = input.trim().replace(/^["']|["']$/g, "");
|
|
34565
|
+
return path55 && normalize3(path55);
|
|
34324
34566
|
}
|
|
34325
34567
|
var parseCheckIgnore;
|
|
34326
34568
|
var init_CheckIgnore = __esm2({
|
|
@@ -34634,8 +34876,8 @@ __export2(sub_module_exports, {
|
|
|
34634
34876
|
subModuleTask: () => subModuleTask,
|
|
34635
34877
|
updateSubModuleTask: () => updateSubModuleTask
|
|
34636
34878
|
});
|
|
34637
|
-
function addSubModuleTask(repo,
|
|
34638
|
-
return subModuleTask(["add", repo,
|
|
34879
|
+
function addSubModuleTask(repo, path55) {
|
|
34880
|
+
return subModuleTask(["add", repo, path55]);
|
|
34639
34881
|
}
|
|
34640
34882
|
function initSubModuleTask(customArgs) {
|
|
34641
34883
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -34968,8 +35210,8 @@ var require_git = __commonJS2({
|
|
|
34968
35210
|
}
|
|
34969
35211
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
34970
35212
|
};
|
|
34971
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
34972
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
35213
|
+
Git2.prototype.submoduleAdd = function(repo, path55, then) {
|
|
35214
|
+
return this._runTask(addSubModuleTask2(repo, path55), trailingFunctionArgument2(arguments));
|
|
34973
35215
|
};
|
|
34974
35216
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
34975
35217
|
return this._runTask(
|
|
@@ -35606,14 +35848,14 @@ async function runGitTask(fn) {
|
|
|
35606
35848
|
}
|
|
35607
35849
|
async function yieldToEventLoop2() {
|
|
35608
35850
|
throwIfGitShutdownRequested();
|
|
35609
|
-
await new Promise((
|
|
35610
|
-
setImmediate(
|
|
35851
|
+
await new Promise((resolve28) => {
|
|
35852
|
+
setImmediate(resolve28);
|
|
35611
35853
|
});
|
|
35612
35854
|
throwIfGitShutdownRequested();
|
|
35613
35855
|
}
|
|
35614
35856
|
async function forEachWithGitYield(items, fn) {
|
|
35615
35857
|
for (let i = 0; i < items.length; i++) {
|
|
35616
|
-
|
|
35858
|
+
await yieldToEventLoop2();
|
|
35617
35859
|
await fn(items[i], i);
|
|
35618
35860
|
}
|
|
35619
35861
|
}
|
|
@@ -35932,9 +36174,9 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
35932
36174
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
35933
36175
|
async function putEncryptedChangeSummaryRows(params) {
|
|
35934
36176
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
35935
|
-
const entries = params.rows.map(({ path:
|
|
36177
|
+
const entries = params.rows.map(({ path: path55, summary }) => {
|
|
35936
36178
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
35937
|
-
return { path:
|
|
36179
|
+
return { path: path55, summary: JSON.stringify(enc) };
|
|
35938
36180
|
});
|
|
35939
36181
|
const res = await fetch(
|
|
35940
36182
|
`${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
@@ -36155,7 +36397,15 @@ async function fetchInternalApiJson(params) {
|
|
|
36155
36397
|
const token = params.getCloudAccessToken();
|
|
36156
36398
|
if (!token) return { ok: false, error: "Missing cloud access token." };
|
|
36157
36399
|
const url2 = `${internalApiBase(params.cloudApiBaseUrl)}${params.path}`;
|
|
36158
|
-
const
|
|
36400
|
+
const method = params.method ?? "GET";
|
|
36401
|
+
const res = await fetch(url2, {
|
|
36402
|
+
method,
|
|
36403
|
+
headers: {
|
|
36404
|
+
Authorization: `Bearer ${token}`,
|
|
36405
|
+
...params.body != null ? { "Content-Type": "application/json" } : {}
|
|
36406
|
+
},
|
|
36407
|
+
...params.body != null ? { body: JSON.stringify(params.body) } : {}
|
|
36408
|
+
});
|
|
36159
36409
|
if (!res.ok) {
|
|
36160
36410
|
const t = await res.text().catch(() => "");
|
|
36161
36411
|
return { ok: false, error: `${params.errorLabel} (${res.status}): ${t.slice(0, 200)}` };
|
|
@@ -36272,6 +36522,39 @@ async function enrichForkedSessionPromptForAgent(params) {
|
|
|
36272
36522
|
return buildForkedSessionAgentPrompt(params.promptText, params.sessionId, parentSessionId);
|
|
36273
36523
|
}
|
|
36274
36524
|
|
|
36525
|
+
// src/agents/acp/build-integration-content-agent-prompt-note.ts
|
|
36526
|
+
function buildIntegrationContentAgentPromptNote(sessionId) {
|
|
36527
|
+
const sessionRef = sessionId.trim();
|
|
36528
|
+
return [
|
|
36529
|
+
"The user message includes link(s) to external integration resources (Linear, GitHub, Jira, Notion, Slack thread, Zoom, or Asana).",
|
|
36530
|
+
"Use the get_integration_content MCP tool on the buildautomaton-bridge server to fetch the full content of each link.",
|
|
36531
|
+
`When calling the tool, pass sessionId "${sessionRef}" and the URL as url.`,
|
|
36532
|
+
"By default the tool links the fetched URL as this session external ticket when the session has none yet. Pass associateAsSessionTicket: false when fetching additional links for context only (after the primary ticket is linked, or when you do not want association).",
|
|
36533
|
+
"If the tool reports unsupported_url, do not retry with the same URL. If it reports integration_reconnect_required, ask the user to reconnect the integration in workspace settings. If it reports temporarily_unavailable, you may retry later."
|
|
36534
|
+
].join("\n");
|
|
36535
|
+
}
|
|
36536
|
+
function injectIntegrationContentAgentPromptNote(agentPrompt, sessionId) {
|
|
36537
|
+
const note = buildIntegrationContentAgentPromptNote(sessionId);
|
|
36538
|
+
const marker = "\nUser request:\n";
|
|
36539
|
+
const idx = agentPrompt.indexOf(marker);
|
|
36540
|
+
if (idx >= 0) {
|
|
36541
|
+
return `${agentPrompt.slice(0, idx)}
|
|
36542
|
+
${note}${agentPrompt.slice(idx)}`;
|
|
36543
|
+
}
|
|
36544
|
+
return `${note}
|
|
36545
|
+
|
|
36546
|
+
${agentPrompt.trim()}`;
|
|
36547
|
+
}
|
|
36548
|
+
|
|
36549
|
+
// src/agents/acp/enrich-integration-content-prompt-for-agent.ts
|
|
36550
|
+
function enrichIntegrationContentPromptForAgent(params) {
|
|
36551
|
+
if (!params.sessionId.trim()) return params.agentPromptText;
|
|
36552
|
+
if (extractFetchableIntegrationLinks(params.originalPromptText).length === 0) {
|
|
36553
|
+
return params.agentPromptText;
|
|
36554
|
+
}
|
|
36555
|
+
return injectIntegrationContentAgentPromptNote(params.agentPromptText, params.sessionId);
|
|
36556
|
+
}
|
|
36557
|
+
|
|
36275
36558
|
// src/agents/acp/send-prompt-to-agent.ts
|
|
36276
36559
|
async function sendPromptToAgent(options) {
|
|
36277
36560
|
const {
|
|
@@ -36282,7 +36565,7 @@ async function sendPromptToAgent(options) {
|
|
|
36282
36565
|
runId,
|
|
36283
36566
|
agentType,
|
|
36284
36567
|
agentCwd,
|
|
36285
|
-
sendResult
|
|
36568
|
+
sendResult,
|
|
36286
36569
|
sendSessionUpdate,
|
|
36287
36570
|
log: log2,
|
|
36288
36571
|
followUpCatalogPromptId,
|
|
@@ -36302,10 +36585,17 @@ async function sendPromptToAgent(options) {
|
|
|
36302
36585
|
getCloudAccessToken
|
|
36303
36586
|
});
|
|
36304
36587
|
}
|
|
36588
|
+
if (sessionId) {
|
|
36589
|
+
agentPromptText = enrichIntegrationContentPromptForAgent({
|
|
36590
|
+
sessionId,
|
|
36591
|
+
originalPromptText: promptText,
|
|
36592
|
+
agentPromptText
|
|
36593
|
+
});
|
|
36594
|
+
}
|
|
36305
36595
|
let sendOpts = {};
|
|
36306
36596
|
if (attachments && attachments.length > 0) {
|
|
36307
36597
|
if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
|
|
36308
|
-
|
|
36598
|
+
sendResult({
|
|
36309
36599
|
type: "prompt_result",
|
|
36310
36600
|
id: promptId,
|
|
36311
36601
|
...sessionId ? { sessionId } : {},
|
|
@@ -36326,7 +36616,7 @@ async function sendPromptToAgent(options) {
|
|
|
36326
36616
|
log: log2
|
|
36327
36617
|
});
|
|
36328
36618
|
if (!resolved.ok) {
|
|
36329
|
-
|
|
36619
|
+
sendResult({
|
|
36330
36620
|
type: "prompt_result",
|
|
36331
36621
|
id: promptId,
|
|
36332
36622
|
...sessionId ? { sessionId } : {},
|
|
@@ -36365,7 +36655,7 @@ async function sendPromptToAgent(options) {
|
|
|
36365
36655
|
const errStr = typeof result.error === "string" ? result.error : void 0;
|
|
36366
36656
|
const resultStop = typeof result.stopReason === "string" ? result.stopReason.trim() : "";
|
|
36367
36657
|
const cancelledByAgent = resultStop.toLowerCase() === "cancelled" || errStr != null && isUserEndedSessionTurnErrorText(errStr);
|
|
36368
|
-
|
|
36658
|
+
sendResult({
|
|
36369
36659
|
type: "prompt_result",
|
|
36370
36660
|
id: promptId,
|
|
36371
36661
|
...sessionId ? { sessionId } : {},
|
|
@@ -36387,7 +36677,7 @@ async function sendPromptToAgent(options) {
|
|
|
36387
36677
|
} catch (err) {
|
|
36388
36678
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
36389
36679
|
log2(`[Agent] Send failed: ${errMsg}`);
|
|
36390
|
-
|
|
36680
|
+
sendResult({
|
|
36391
36681
|
type: "prompt_result",
|
|
36392
36682
|
id: promptId,
|
|
36393
36683
|
...sessionId ? { sessionId } : {},
|
|
@@ -36421,7 +36711,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36421
36711
|
agentType,
|
|
36422
36712
|
agentConfig,
|
|
36423
36713
|
sessionParentPath,
|
|
36424
|
-
sendResult
|
|
36714
|
+
sendResult,
|
|
36425
36715
|
sendSessionUpdate,
|
|
36426
36716
|
followUpCatalogPromptId,
|
|
36427
36717
|
sessionChangeSummaryFilePaths,
|
|
@@ -36438,7 +36728,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36438
36728
|
const activeRunId = runId;
|
|
36439
36729
|
const acpAgentKey = computeAcpAgentKey(preferredForPrompt, mode, agentConfig ?? null);
|
|
36440
36730
|
if (!acpAgentKey) {
|
|
36441
|
-
|
|
36731
|
+
sendResult({
|
|
36442
36732
|
type: "prompt_result",
|
|
36443
36733
|
id: promptId,
|
|
36444
36734
|
...sessionId ? { sessionId } : {},
|
|
@@ -36475,7 +36765,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36475
36765
|
const evaluated = Boolean(preferredForPrompt && errMsg.trim());
|
|
36476
36766
|
const suggestsAuth = evaluated ? localAgentErrorSuggestsAuth(preferredForPrompt, errMsg) : false;
|
|
36477
36767
|
const auth = suggestsAuth && preferredForPrompt ? { agentAuthRequired: true, agentType: preferredForPrompt } : {};
|
|
36478
|
-
|
|
36768
|
+
sendResult({
|
|
36479
36769
|
type: "prompt_result",
|
|
36480
36770
|
id: promptId,
|
|
36481
36771
|
...sessionId ? { sessionId } : {},
|
|
@@ -36495,7 +36785,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36495
36785
|
await handle.cancel?.();
|
|
36496
36786
|
} catch {
|
|
36497
36787
|
}
|
|
36498
|
-
|
|
36788
|
+
sendResult({
|
|
36499
36789
|
type: "prompt_result",
|
|
36500
36790
|
id: promptId,
|
|
36501
36791
|
...sessionId ? { sessionId } : {},
|
|
@@ -36516,7 +36806,7 @@ function handlePrompt(ctx, opts) {
|
|
|
36516
36806
|
runId: activeRunId,
|
|
36517
36807
|
agentType: preferredForPrompt,
|
|
36518
36808
|
agentCwd: resolveSessionParentPathForAgentProcess(sessionParentPath),
|
|
36519
|
-
sendResult
|
|
36809
|
+
sendResult,
|
|
36520
36810
|
sendSessionUpdate,
|
|
36521
36811
|
log: ctx.log,
|
|
36522
36812
|
followUpCatalogPromptId,
|
|
@@ -36572,6 +36862,563 @@ async function createAcpManager(options) {
|
|
|
36572
36862
|
};
|
|
36573
36863
|
}
|
|
36574
36864
|
|
|
36865
|
+
// src/worktrees/worktree-layout-file.ts
|
|
36866
|
+
import * as fs17 from "node:fs";
|
|
36867
|
+
import * as path20 from "node:path";
|
|
36868
|
+
import os7 from "node:os";
|
|
36869
|
+
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
36870
|
+
function defaultWorktreeLayoutPath() {
|
|
36871
|
+
return path20.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
36872
|
+
}
|
|
36873
|
+
function normalizeLoadedLayout(raw) {
|
|
36874
|
+
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
36875
|
+
const j = raw;
|
|
36876
|
+
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
36877
|
+
}
|
|
36878
|
+
return { launcherCwds: [] };
|
|
36879
|
+
}
|
|
36880
|
+
function loadWorktreeLayout() {
|
|
36881
|
+
try {
|
|
36882
|
+
const p = defaultWorktreeLayoutPath();
|
|
36883
|
+
if (!fs17.existsSync(p)) return { launcherCwds: [] };
|
|
36884
|
+
const raw = JSON.parse(fs17.readFileSync(p, "utf8"));
|
|
36885
|
+
return normalizeLoadedLayout(raw);
|
|
36886
|
+
} catch {
|
|
36887
|
+
return { launcherCwds: [] };
|
|
36888
|
+
}
|
|
36889
|
+
}
|
|
36890
|
+
function saveWorktreeLayout(layout) {
|
|
36891
|
+
try {
|
|
36892
|
+
const dir = path20.dirname(defaultWorktreeLayoutPath());
|
|
36893
|
+
fs17.mkdirSync(dir, { recursive: true });
|
|
36894
|
+
fs17.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
36895
|
+
} catch {
|
|
36896
|
+
}
|
|
36897
|
+
}
|
|
36898
|
+
function baseNameSafe(pathString) {
|
|
36899
|
+
return path20.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
36900
|
+
}
|
|
36901
|
+
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
36902
|
+
const norm = path20.resolve(bridgeRootPath2);
|
|
36903
|
+
const existing = layout.launcherCwds.find((e) => path20.resolve(e.absolutePath) === norm);
|
|
36904
|
+
return existing?.dirName;
|
|
36905
|
+
}
|
|
36906
|
+
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
36907
|
+
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
36908
|
+
if (existing) return existing;
|
|
36909
|
+
const norm = path20.resolve(bridgeRootPath2);
|
|
36910
|
+
const base = baseNameSafe(norm);
|
|
36911
|
+
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
36912
|
+
let name = base;
|
|
36913
|
+
let n = 2;
|
|
36914
|
+
while (used.has(name)) {
|
|
36915
|
+
name = `${base}-${n}`;
|
|
36916
|
+
n += 1;
|
|
36917
|
+
}
|
|
36918
|
+
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
36919
|
+
saveWorktreeLayout(layout);
|
|
36920
|
+
return name;
|
|
36921
|
+
}
|
|
36922
|
+
|
|
36923
|
+
// src/worktrees/discovery/discover-session-worktree-on-disk.ts
|
|
36924
|
+
import * as fs21 from "node:fs";
|
|
36925
|
+
import * as path25 from "node:path";
|
|
36926
|
+
|
|
36927
|
+
// src/worktrees/discovery/collect-worktree-paths.ts
|
|
36928
|
+
import * as fs19 from "node:fs";
|
|
36929
|
+
import * as path22 from "node:path";
|
|
36930
|
+
|
|
36931
|
+
// src/worktrees/discovery/disk-walk-constants.ts
|
|
36932
|
+
var DISK_WALK_YIELD_EVERY = 64;
|
|
36933
|
+
var LEGACY_WALK_MAX_DEPTH = 12;
|
|
36934
|
+
var SKIP_DISK_WALK_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
36935
|
+
"node_modules",
|
|
36936
|
+
"bower_components",
|
|
36937
|
+
"vendor",
|
|
36938
|
+
"Pods",
|
|
36939
|
+
"Carthage",
|
|
36940
|
+
"DerivedData",
|
|
36941
|
+
".yarn",
|
|
36942
|
+
".pnpm-store",
|
|
36943
|
+
"dist",
|
|
36944
|
+
"build",
|
|
36945
|
+
".next",
|
|
36946
|
+
"coverage",
|
|
36947
|
+
".turbo",
|
|
36948
|
+
".cache",
|
|
36949
|
+
"target",
|
|
36950
|
+
"__pycache__"
|
|
36951
|
+
]);
|
|
36952
|
+
function shouldSkipDiskWalkEntry(name) {
|
|
36953
|
+
return name.startsWith(".") || SKIP_DISK_WALK_DIR_NAMES.has(name);
|
|
36954
|
+
}
|
|
36955
|
+
|
|
36956
|
+
// src/worktrees/discovery/disk-walk-utils.ts
|
|
36957
|
+
import * as fs18 from "node:fs";
|
|
36958
|
+
import * as path21 from "node:path";
|
|
36959
|
+
async function yieldDuringDiskWalk(state) {
|
|
36960
|
+
state.entries++;
|
|
36961
|
+
if (state.entries % DISK_WALK_YIELD_EVERY !== 0) return true;
|
|
36962
|
+
if (isCliImmediateShutdownRequested()) return false;
|
|
36963
|
+
await yieldToEventLoop();
|
|
36964
|
+
return !isCliImmediateShutdownRequested();
|
|
36965
|
+
}
|
|
36966
|
+
async function isGitDir(dirPath) {
|
|
36967
|
+
try {
|
|
36968
|
+
await fs18.promises.access(path21.join(dirPath, ".git"));
|
|
36969
|
+
return true;
|
|
36970
|
+
} catch {
|
|
36971
|
+
return false;
|
|
36972
|
+
}
|
|
36973
|
+
}
|
|
36974
|
+
|
|
36975
|
+
// src/worktrees/discovery/collect-worktree-paths.ts
|
|
36976
|
+
async function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
36977
|
+
const out = [];
|
|
36978
|
+
const state = { entries: 0 };
|
|
36979
|
+
const walk = async (dir) => {
|
|
36980
|
+
if (!await yieldDuringDiskWalk(state)) return;
|
|
36981
|
+
if (await isGitDir(dir)) {
|
|
36982
|
+
out.push(path22.resolve(dir));
|
|
36983
|
+
return;
|
|
36984
|
+
}
|
|
36985
|
+
let entries;
|
|
36986
|
+
try {
|
|
36987
|
+
entries = await fs19.promises.readdir(dir, { withFileTypes: true });
|
|
36988
|
+
} catch {
|
|
36989
|
+
return;
|
|
36990
|
+
}
|
|
36991
|
+
for (const e of entries) {
|
|
36992
|
+
if (shouldSkipDiskWalkEntry(e.name)) continue;
|
|
36993
|
+
const full = path22.join(dir, e.name);
|
|
36994
|
+
if (!e.isDirectory()) continue;
|
|
36995
|
+
await walk(full);
|
|
36996
|
+
}
|
|
36997
|
+
};
|
|
36998
|
+
await walk(path22.resolve(rootPath));
|
|
36999
|
+
return { paths: [...new Set(out)], entriesVisited: state.entries };
|
|
37000
|
+
}
|
|
37001
|
+
async function collectWorktreeRootsNamed(root, sessionId, maxDepth = LEGACY_WALK_MAX_DEPTH) {
|
|
37002
|
+
const out = [];
|
|
37003
|
+
const state = { entries: 0 };
|
|
37004
|
+
const walk = async (dir, depth) => {
|
|
37005
|
+
if (depth > maxDepth) return;
|
|
37006
|
+
if (!await yieldDuringDiskWalk(state)) return;
|
|
37007
|
+
let entries;
|
|
37008
|
+
try {
|
|
37009
|
+
entries = await fs19.promises.readdir(dir, { withFileTypes: true });
|
|
37010
|
+
} catch {
|
|
37011
|
+
return;
|
|
37012
|
+
}
|
|
37013
|
+
for (const e of entries) {
|
|
37014
|
+
if (shouldSkipDiskWalkEntry(e.name)) continue;
|
|
37015
|
+
const full = path22.join(dir, e.name);
|
|
37016
|
+
if (!e.isDirectory()) continue;
|
|
37017
|
+
if (e.name === sessionId) {
|
|
37018
|
+
if (await isGitDir(full)) out.push(path22.resolve(full));
|
|
37019
|
+
continue;
|
|
37020
|
+
}
|
|
37021
|
+
if (await isGitDir(full)) continue;
|
|
37022
|
+
await walk(full, depth + 1);
|
|
37023
|
+
}
|
|
37024
|
+
};
|
|
37025
|
+
await walk(root, 0);
|
|
37026
|
+
return { paths: out, entriesVisited: state.entries };
|
|
37027
|
+
}
|
|
37028
|
+
|
|
37029
|
+
// src/worktrees/discovery/layout-keys-for-bridge-root.ts
|
|
37030
|
+
import * as path23 from "node:path";
|
|
37031
|
+
function layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk) {
|
|
37032
|
+
const bridge = path23.resolve(bridgeRoot);
|
|
37033
|
+
const preferred = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
37034
|
+
const relevant = layout.launcherCwds.filter((e) => {
|
|
37035
|
+
const entry = path23.resolve(e.absolutePath);
|
|
37036
|
+
return bridge === entry || bridge.startsWith(entry + path23.sep) || entry.startsWith(bridge + path23.sep);
|
|
37037
|
+
}).sort((a, b) => path23.resolve(b.absolutePath).length - path23.resolve(a.absolutePath).length).map((e) => e.dirName).filter((name) => keysOnDisk.includes(name));
|
|
37038
|
+
const ordered = [];
|
|
37039
|
+
const seen = /* @__PURE__ */ new Set();
|
|
37040
|
+
const add = (k) => {
|
|
37041
|
+
if (seen.has(k) || !keysOnDisk.includes(k)) return;
|
|
37042
|
+
seen.add(k);
|
|
37043
|
+
ordered.push(k);
|
|
37044
|
+
};
|
|
37045
|
+
if (preferred) add(preferred);
|
|
37046
|
+
for (const k of relevant) add(k);
|
|
37047
|
+
if (relevant.length > 0) {
|
|
37048
|
+
return ordered;
|
|
37049
|
+
}
|
|
37050
|
+
for (const k of keysOnDisk) add(k);
|
|
37051
|
+
return ordered;
|
|
37052
|
+
}
|
|
37053
|
+
|
|
37054
|
+
// src/worktrees/discovery/try-binding-from-session-directory.ts
|
|
37055
|
+
import * as fs20 from "node:fs";
|
|
37056
|
+
import * as path24 from "node:path";
|
|
37057
|
+
async function tryBindingFromSessionDirectory(sessionDir) {
|
|
37058
|
+
let st;
|
|
37059
|
+
try {
|
|
37060
|
+
st = await fs20.promises.stat(sessionDir);
|
|
37061
|
+
} catch {
|
|
37062
|
+
return null;
|
|
37063
|
+
}
|
|
37064
|
+
if (!st.isDirectory()) return null;
|
|
37065
|
+
const { paths: worktreePaths } = await collectGitRepoRootsUnderDirectory(sessionDir);
|
|
37066
|
+
if (worktreePaths.length === 0) return null;
|
|
37067
|
+
const abs = path24.resolve(sessionDir);
|
|
37068
|
+
return {
|
|
37069
|
+
sessionParentPath: abs,
|
|
37070
|
+
workingTreeRelRoot: abs,
|
|
37071
|
+
repoCheckoutPaths: worktreePaths
|
|
37072
|
+
};
|
|
37073
|
+
}
|
|
37074
|
+
|
|
37075
|
+
// src/worktrees/discovery/discover-session-worktree-on-disk.ts
|
|
37076
|
+
async function discoverSessionWorktreeOnDisk(options) {
|
|
37077
|
+
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
37078
|
+
const sid = sessionId.trim();
|
|
37079
|
+
if (!sid) return null;
|
|
37080
|
+
try {
|
|
37081
|
+
await fs21.promises.access(worktreesRootPath);
|
|
37082
|
+
} catch {
|
|
37083
|
+
return null;
|
|
37084
|
+
}
|
|
37085
|
+
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
37086
|
+
const keysOnDisk = [];
|
|
37087
|
+
if (preferredKey) keysOnDisk.push(preferredKey);
|
|
37088
|
+
try {
|
|
37089
|
+
for (const name of await fs21.promises.readdir(worktreesRootPath)) {
|
|
37090
|
+
if (name.startsWith(".")) continue;
|
|
37091
|
+
const p = path25.join(worktreesRootPath, name);
|
|
37092
|
+
let st;
|
|
37093
|
+
try {
|
|
37094
|
+
st = await fs21.promises.stat(p);
|
|
37095
|
+
} catch {
|
|
37096
|
+
continue;
|
|
37097
|
+
}
|
|
37098
|
+
if (!st.isDirectory()) continue;
|
|
37099
|
+
if (!keysOnDisk.includes(name)) keysOnDisk.push(name);
|
|
37100
|
+
}
|
|
37101
|
+
} catch {
|
|
37102
|
+
return null;
|
|
37103
|
+
}
|
|
37104
|
+
const keys = layoutKeysForBridgeRoot(layout, bridgeRoot, keysOnDisk);
|
|
37105
|
+
for (const key of keys) {
|
|
37106
|
+
if (isCliImmediateShutdownRequested()) return null;
|
|
37107
|
+
await yieldToEventLoop();
|
|
37108
|
+
const layoutRoot = path25.join(worktreesRootPath, key);
|
|
37109
|
+
let layoutSt;
|
|
37110
|
+
try {
|
|
37111
|
+
layoutSt = await fs21.promises.stat(layoutRoot);
|
|
37112
|
+
} catch {
|
|
37113
|
+
continue;
|
|
37114
|
+
}
|
|
37115
|
+
if (!layoutSt.isDirectory()) continue;
|
|
37116
|
+
const sessionDir = path25.join(layoutRoot, sid);
|
|
37117
|
+
const nested = await tryBindingFromSessionDirectory(sessionDir);
|
|
37118
|
+
if (nested) return nested;
|
|
37119
|
+
const legacy = await collectWorktreeRootsNamed(layoutRoot, sid);
|
|
37120
|
+
if (legacy.paths.length > 0) {
|
|
37121
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacy.paths) ?? path25.resolve(legacy.paths[0]);
|
|
37122
|
+
return {
|
|
37123
|
+
sessionParentPath: path25.resolve(isolated),
|
|
37124
|
+
workingTreeRelRoot: path25.resolve(layoutRoot),
|
|
37125
|
+
repoCheckoutPaths: legacy.paths.map((p) => path25.resolve(p))
|
|
37126
|
+
};
|
|
37127
|
+
}
|
|
37128
|
+
}
|
|
37129
|
+
return null;
|
|
37130
|
+
}
|
|
37131
|
+
|
|
37132
|
+
// src/worktrees/discovery/discover-session-worktrees-under-session-worktree-root.ts
|
|
37133
|
+
import * as fs22 from "node:fs";
|
|
37134
|
+
import * as path27 from "node:path";
|
|
37135
|
+
|
|
37136
|
+
// src/worktrees/discovery/discover-legacy-binding-ascending-from-checkout.ts
|
|
37137
|
+
import * as path26 from "node:path";
|
|
37138
|
+
async function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
37139
|
+
const sid = sessionId.trim();
|
|
37140
|
+
if (!sid) return null;
|
|
37141
|
+
const hintR = path26.resolve(checkoutPath);
|
|
37142
|
+
let best = null;
|
|
37143
|
+
let cur = path26.dirname(hintR);
|
|
37144
|
+
for (let i = 0; i < 40; i++) {
|
|
37145
|
+
if (isCliImmediateShutdownRequested()) return best;
|
|
37146
|
+
await yieldToEventLoop();
|
|
37147
|
+
const paths = await collectWorktreeRootsNamed(cur, sid);
|
|
37148
|
+
if (paths.paths.some((p) => path26.resolve(p) === hintR)) {
|
|
37149
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths.paths) ?? path26.resolve(paths.paths[0]);
|
|
37150
|
+
best = {
|
|
37151
|
+
sessionParentPath: path26.resolve(isolated),
|
|
37152
|
+
workingTreeRelRoot: path26.resolve(cur),
|
|
37153
|
+
repoCheckoutPaths: paths.paths.map((p) => path26.resolve(p))
|
|
37154
|
+
};
|
|
37155
|
+
}
|
|
37156
|
+
const next = path26.dirname(cur);
|
|
37157
|
+
if (next === cur) break;
|
|
37158
|
+
cur = next;
|
|
37159
|
+
}
|
|
37160
|
+
return best;
|
|
37161
|
+
}
|
|
37162
|
+
|
|
37163
|
+
// src/worktrees/discovery/discover-session-worktrees-under-session-worktree-root.ts
|
|
37164
|
+
async function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
37165
|
+
const sid = sessionId.trim();
|
|
37166
|
+
if (!sid) return null;
|
|
37167
|
+
const hint = path27.resolve(sessionWorktreeRootPathOrHint);
|
|
37168
|
+
const underHint = await tryBindingFromSessionDirectory(path27.join(hint, sid));
|
|
37169
|
+
if (underHint) return underHint;
|
|
37170
|
+
const direct = await tryBindingFromSessionDirectory(hint);
|
|
37171
|
+
if (direct) {
|
|
37172
|
+
if (path27.basename(hint) === sid && await isGitDir(hint)) {
|
|
37173
|
+
const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
37174
|
+
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
37175
|
+
return legacyFromCheckout;
|
|
37176
|
+
}
|
|
37177
|
+
}
|
|
37178
|
+
return direct;
|
|
37179
|
+
}
|
|
37180
|
+
if (path27.basename(hint) === sid && await isGitDir(hint)) {
|
|
37181
|
+
const legacyFromCheckout = await discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
37182
|
+
if (legacyFromCheckout) return legacyFromCheckout;
|
|
37183
|
+
}
|
|
37184
|
+
let st;
|
|
37185
|
+
try {
|
|
37186
|
+
st = await fs22.promises.stat(hint);
|
|
37187
|
+
} catch {
|
|
37188
|
+
return null;
|
|
37189
|
+
}
|
|
37190
|
+
if (!st.isDirectory()) return null;
|
|
37191
|
+
const legacyPaths = await collectWorktreeRootsNamed(hint, sid);
|
|
37192
|
+
if (legacyPaths.paths.length === 0) return null;
|
|
37193
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths.paths) ?? path27.resolve(legacyPaths.paths[0]);
|
|
37194
|
+
return {
|
|
37195
|
+
sessionParentPath: path27.resolve(isolated),
|
|
37196
|
+
workingTreeRelRoot: hint,
|
|
37197
|
+
repoCheckoutPaths: legacyPaths.paths.map((p) => path27.resolve(p))
|
|
37198
|
+
};
|
|
37199
|
+
}
|
|
37200
|
+
|
|
37201
|
+
// src/worktrees/manager/discover-session-binding.ts
|
|
37202
|
+
var discoverInflightBySessionId = /* @__PURE__ */ new Map();
|
|
37203
|
+
function discoverSessionBindingAsync(params) {
|
|
37204
|
+
const sid = params.sessionId.trim();
|
|
37205
|
+
if (!sid) return Promise.resolve(null);
|
|
37206
|
+
const existing = discoverInflightBySessionId.get(sid);
|
|
37207
|
+
if (existing) return existing;
|
|
37208
|
+
const promise2 = discoverSessionWorktreeOnDisk({
|
|
37209
|
+
sessionId: sid,
|
|
37210
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
37211
|
+
layout: params.layout,
|
|
37212
|
+
bridgeRoot: getBridgeRoot()
|
|
37213
|
+
}).finally(() => {
|
|
37214
|
+
if (discoverInflightBySessionId.get(sid) === promise2) {
|
|
37215
|
+
discoverInflightBySessionId.delete(sid);
|
|
37216
|
+
}
|
|
37217
|
+
});
|
|
37218
|
+
discoverInflightBySessionId.set(sid, promise2);
|
|
37219
|
+
return promise2;
|
|
37220
|
+
}
|
|
37221
|
+
|
|
37222
|
+
// src/worktrees/manager/resolve-isolated-session-parent-path.ts
|
|
37223
|
+
function resolveIsolatedSessionParentPath(sessionId, cache2, ensureRepoCheckoutPaths) {
|
|
37224
|
+
if (!sessionId) return null;
|
|
37225
|
+
const sid = sessionId.trim();
|
|
37226
|
+
const cached2 = cache2.getSessionParentPath(sid);
|
|
37227
|
+
if (cached2) return cached2;
|
|
37228
|
+
const paths = ensureRepoCheckoutPaths(sid);
|
|
37229
|
+
if (!paths?.length) return null;
|
|
37230
|
+
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
37231
|
+
}
|
|
37232
|
+
function ensureRepoCheckoutPathsForSession(sessionId, cache2) {
|
|
37233
|
+
if (!sessionId?.trim()) return void 0;
|
|
37234
|
+
const cached2 = cache2.getRepoCheckoutPaths(sessionId.trim());
|
|
37235
|
+
return cached2?.length ? [...cached2] : void 0;
|
|
37236
|
+
}
|
|
37237
|
+
async function ensureRepoCheckoutPathsForSessionAsync(sessionId, cache2, discover) {
|
|
37238
|
+
if (!sessionId?.trim()) return void 0;
|
|
37239
|
+
const sid = sessionId.trim();
|
|
37240
|
+
const cached2 = cache2.getRepoCheckoutPaths(sid);
|
|
37241
|
+
if (cached2?.length) return cached2;
|
|
37242
|
+
const disc = await discover(sid);
|
|
37243
|
+
if (disc?.repoCheckoutPaths.length) {
|
|
37244
|
+
cache2.remember(sid, disc);
|
|
37245
|
+
return [...disc.repoCheckoutPaths];
|
|
37246
|
+
}
|
|
37247
|
+
return void 0;
|
|
37248
|
+
}
|
|
37249
|
+
|
|
37250
|
+
// src/worktrees/manager/parse-session-parent.ts
|
|
37251
|
+
function parseSessionParent(v) {
|
|
37252
|
+
if (v === "bridge_root" || v === "worktrees_root") return v;
|
|
37253
|
+
if (v === "session_worktrees_root") return "worktrees_root";
|
|
37254
|
+
return null;
|
|
37255
|
+
}
|
|
37256
|
+
|
|
37257
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
37258
|
+
import * as fs23 from "node:fs";
|
|
37259
|
+
import * as path28 from "node:path";
|
|
37260
|
+
|
|
37261
|
+
// src/git/worktrees/worktree-add.ts
|
|
37262
|
+
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
37263
|
+
const mainGit = cliSimpleGit(mainRepoPath);
|
|
37264
|
+
const base = baseRef.trim() || "HEAD";
|
|
37265
|
+
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, base]);
|
|
37266
|
+
}
|
|
37267
|
+
|
|
37268
|
+
// src/worktrees/prepare-new-session-worktrees.ts
|
|
37269
|
+
function normalizeRepoRelPath(rel) {
|
|
37270
|
+
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
37271
|
+
}
|
|
37272
|
+
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
37273
|
+
if (!baseBranches) return "HEAD";
|
|
37274
|
+
const direct = baseBranches[relNorm]?.trim();
|
|
37275
|
+
if (direct) return direct;
|
|
37276
|
+
if (relNorm !== "." && baseBranches["."]?.trim()) return baseBranches["."].trim();
|
|
37277
|
+
return "HEAD";
|
|
37278
|
+
}
|
|
37279
|
+
async function prepareNewSessionWorktrees(options) {
|
|
37280
|
+
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
|
|
37281
|
+
const bridgeResolved = path28.resolve(bridgeRoot);
|
|
37282
|
+
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
37283
|
+
const bridgeKeyDir = path28.join(worktreesRootPath, cwdKey);
|
|
37284
|
+
const sessionDir = path28.join(bridgeKeyDir, sessionId);
|
|
37285
|
+
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
37286
|
+
if (repos.length === 0) {
|
|
37287
|
+
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
37288
|
+
return null;
|
|
37289
|
+
}
|
|
37290
|
+
const branch = `session-${sessionId}`;
|
|
37291
|
+
const worktreePaths = [];
|
|
37292
|
+
fs23.mkdirSync(sessionDir, { recursive: true });
|
|
37293
|
+
for (const repo of repos) {
|
|
37294
|
+
let rel = path28.relative(bridgeResolved, repo.absolutePath);
|
|
37295
|
+
if (rel.startsWith("..") || path28.isAbsolute(rel)) continue;
|
|
37296
|
+
const relNorm = normalizeRepoRelPath(rel === "" ? "." : rel);
|
|
37297
|
+
const wtPath = relNorm === "." ? sessionDir : path28.join(sessionDir, relNorm);
|
|
37298
|
+
if (relNorm !== ".") {
|
|
37299
|
+
fs23.mkdirSync(path28.dirname(wtPath), { recursive: true });
|
|
37300
|
+
}
|
|
37301
|
+
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
37302
|
+
try {
|
|
37303
|
+
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch, baseRef);
|
|
37304
|
+
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}, base ${baseRef}).`);
|
|
37305
|
+
worktreePaths.push(wtPath);
|
|
37306
|
+
} catch (e) {
|
|
37307
|
+
log2(
|
|
37308
|
+
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
37309
|
+
);
|
|
37310
|
+
}
|
|
37311
|
+
}
|
|
37312
|
+
if (worktreePaths.length === 0) return null;
|
|
37313
|
+
return {
|
|
37314
|
+
worktreePaths,
|
|
37315
|
+
sessionParentPath: sessionDir,
|
|
37316
|
+
workingTreeRelRoot: sessionDir
|
|
37317
|
+
};
|
|
37318
|
+
}
|
|
37319
|
+
|
|
37320
|
+
// src/worktrees/manager/prepare-and-remember-session-worktrees.ts
|
|
37321
|
+
async function prepareAndRememberSessionWorktrees(params) {
|
|
37322
|
+
const prep = await prepareNewSessionWorktrees({
|
|
37323
|
+
worktreesRootPath: params.worktreesRootPath,
|
|
37324
|
+
bridgeRoot: getBridgeRoot(),
|
|
37325
|
+
sessionId: params.sessionId,
|
|
37326
|
+
layout: params.layout,
|
|
37327
|
+
log: params.log,
|
|
37328
|
+
...params.worktreeBaseBranches && Object.keys(params.worktreeBaseBranches).length > 0 ? { worktreeBaseBranches: params.worktreeBaseBranches } : {}
|
|
37329
|
+
});
|
|
37330
|
+
if (!prep) return void 0;
|
|
37331
|
+
params.cache.remember(params.sessionId, {
|
|
37332
|
+
sessionParentPath: prep.sessionParentPath,
|
|
37333
|
+
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
37334
|
+
repoCheckoutPaths: prep.worktreePaths
|
|
37335
|
+
});
|
|
37336
|
+
return params.cache.getSessionParentPath(params.sessionId);
|
|
37337
|
+
}
|
|
37338
|
+
|
|
37339
|
+
// src/worktrees/manager/resolve-existing-session-parent-path.ts
|
|
37340
|
+
async function resolveExistingSessionParentPath(sessionId, cache2, discover) {
|
|
37341
|
+
const cached2 = cache2.getSessionParentPath(sessionId);
|
|
37342
|
+
if (cached2) return cached2;
|
|
37343
|
+
const disc = await discover();
|
|
37344
|
+
if (disc) {
|
|
37345
|
+
cache2.remember(sessionId, disc);
|
|
37346
|
+
return cache2.getSessionParentPath(sessionId);
|
|
37347
|
+
}
|
|
37348
|
+
return void 0;
|
|
37349
|
+
}
|
|
37350
|
+
|
|
37351
|
+
// src/worktrees/manager/resolve-explicit-session-parent-path.ts
|
|
37352
|
+
import * as path29 from "node:path";
|
|
37353
|
+
async function resolveExplicitSessionParentPath(params) {
|
|
37354
|
+
const resolved = path29.resolve(params.parentPathRaw);
|
|
37355
|
+
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
37356
|
+
return resolved;
|
|
37357
|
+
}
|
|
37358
|
+
const rememberAndReturn = (binding) => {
|
|
37359
|
+
params.cache.remember(params.sessionId, binding);
|
|
37360
|
+
return params.cache.getSessionParentPath(params.sessionId) ?? resolved;
|
|
37361
|
+
};
|
|
37362
|
+
const diskFirst = await params.discover();
|
|
37363
|
+
if (diskFirst) return rememberAndReturn(diskFirst);
|
|
37364
|
+
const fromRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, params.sessionId);
|
|
37365
|
+
if (fromRoot) return rememberAndReturn(fromRoot);
|
|
37366
|
+
let cur = resolved;
|
|
37367
|
+
for (let i = 0; i < 16; i++) {
|
|
37368
|
+
await yieldToEventLoop();
|
|
37369
|
+
const tryRoot = await discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
37370
|
+
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
37371
|
+
const next = path29.dirname(cur);
|
|
37372
|
+
if (next === cur) break;
|
|
37373
|
+
cur = next;
|
|
37374
|
+
}
|
|
37375
|
+
return resolved;
|
|
37376
|
+
}
|
|
37377
|
+
|
|
37378
|
+
// src/worktrees/manager/resolve-session-parent-path-for-prompt.ts
|
|
37379
|
+
async function resolveSessionParentPathForPrompt(params) {
|
|
37380
|
+
const { sessionId, cache: cache2, worktreesRootPath, layout, log: log2, discover, opts } = params;
|
|
37381
|
+
if (!sessionId) return void 0;
|
|
37382
|
+
const sid = sessionId.trim();
|
|
37383
|
+
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
37384
|
+
if (parentPathRaw) {
|
|
37385
|
+
return resolveExplicitSessionParentPath({
|
|
37386
|
+
sessionId: sid,
|
|
37387
|
+
sessionParent: opts.sessionParent,
|
|
37388
|
+
parentPathRaw,
|
|
37389
|
+
cache: cache2,
|
|
37390
|
+
discover: () => discover(sid)
|
|
37391
|
+
});
|
|
37392
|
+
}
|
|
37393
|
+
const parentKind = parseSessionParent(opts.sessionParent);
|
|
37394
|
+
if (parentKind === "bridge_root") {
|
|
37395
|
+
return void 0;
|
|
37396
|
+
}
|
|
37397
|
+
if (parentKind === "worktrees_root") {
|
|
37398
|
+
if (!opts.isNewSession) {
|
|
37399
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
37400
|
+
}
|
|
37401
|
+
return prepareAndRememberSessionWorktrees({
|
|
37402
|
+
cache: cache2,
|
|
37403
|
+
sessionId: sid,
|
|
37404
|
+
worktreesRootPath,
|
|
37405
|
+
layout,
|
|
37406
|
+
log: log2,
|
|
37407
|
+
...opts.worktreeBaseBranches ? { worktreeBaseBranches: opts.worktreeBaseBranches } : {}
|
|
37408
|
+
});
|
|
37409
|
+
}
|
|
37410
|
+
if (!opts.isNewSession) {
|
|
37411
|
+
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
37412
|
+
}
|
|
37413
|
+
return prepareAndRememberSessionWorktrees({
|
|
37414
|
+
cache: cache2,
|
|
37415
|
+
sessionId: sid,
|
|
37416
|
+
worktreesRootPath,
|
|
37417
|
+
layout,
|
|
37418
|
+
log: log2
|
|
37419
|
+
});
|
|
37420
|
+
}
|
|
37421
|
+
|
|
36575
37422
|
// src/git/changes/types.ts
|
|
36576
37423
|
var MAX_PATCH_CHARS = 35e4;
|
|
36577
37424
|
|
|
@@ -36629,8 +37476,11 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
36629
37476
|
return `origin \xB7 ${hostPath}`;
|
|
36630
37477
|
}
|
|
36631
37478
|
|
|
36632
|
-
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
36633
|
-
import * as
|
|
37479
|
+
// src/git/changes/repo/get-working-tree-change-repo-details.ts
|
|
37480
|
+
import * as path34 from "node:path";
|
|
37481
|
+
|
|
37482
|
+
// src/git/changes/repo/build-working-tree-change-repo-detail.ts
|
|
37483
|
+
import * as path33 from "node:path";
|
|
36634
37484
|
|
|
36635
37485
|
// src/git/commits/resolve-remote-tracking.ts
|
|
36636
37486
|
async function tryConfigGet(g, key) {
|
|
@@ -36801,8 +37651,8 @@ async function listRecentCommits(repoDir, limitInput) {
|
|
|
36801
37651
|
}
|
|
36802
37652
|
|
|
36803
37653
|
// src/git/changes/parse/normalize-git-diff-path.ts
|
|
36804
|
-
function normalizeGitDiffPath(
|
|
36805
|
-
return
|
|
37654
|
+
function normalizeGitDiffPath(path55) {
|
|
37655
|
+
return path55.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
|
|
36806
37656
|
}
|
|
36807
37657
|
|
|
36808
37658
|
// src/git/changes/parse/expand-git-rename-numstat-path.ts
|
|
@@ -36915,8 +37765,8 @@ async function unifiedDiffForFileInRange(repoCwd, range, pathInRepo, change, mov
|
|
|
36915
37765
|
}
|
|
36916
37766
|
|
|
36917
37767
|
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
36918
|
-
import * as
|
|
36919
|
-
import * as
|
|
37768
|
+
import * as fs24 from "node:fs";
|
|
37769
|
+
import * as path30 from "node:path";
|
|
36920
37770
|
|
|
36921
37771
|
// src/git/changes/lines/count-lines.ts
|
|
36922
37772
|
import { createReadStream } from "node:fs";
|
|
@@ -36962,13 +37812,13 @@ async function countLinesInGitRef(repoGitCwd, ref, pathInRepo) {
|
|
|
36962
37812
|
}
|
|
36963
37813
|
async function resolveWorkingTreeFileTotalLines(options) {
|
|
36964
37814
|
if (options.isBinary) return null;
|
|
36965
|
-
const filePath =
|
|
37815
|
+
const filePath = path30.join(options.repoGitCwd, options.pathInRepo);
|
|
36966
37816
|
if (options.change === "removed") {
|
|
36967
37817
|
return countLinesInGitRef(options.repoGitCwd, "HEAD", options.pathInRepo);
|
|
36968
37818
|
}
|
|
36969
37819
|
if (options.change === "moved" || options.change === "modified") {
|
|
36970
37820
|
try {
|
|
36971
|
-
const st = await
|
|
37821
|
+
const st = await fs24.promises.stat(filePath);
|
|
36972
37822
|
if (!st.isFile()) return null;
|
|
36973
37823
|
return await countTextFileLines(filePath);
|
|
36974
37824
|
} catch {
|
|
@@ -36997,7 +37847,7 @@ function pathInRepoFromLauncher(pathRelLauncher, repoRelPath) {
|
|
|
36997
37847
|
}
|
|
36998
37848
|
return pathRelLauncher;
|
|
36999
37849
|
}
|
|
37000
|
-
function
|
|
37850
|
+
function normalizeRepoRelPath2(repoRelPath) {
|
|
37001
37851
|
return repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
37002
37852
|
}
|
|
37003
37853
|
|
|
@@ -37099,8 +37949,8 @@ function parseNumstatEntries(lines) {
|
|
|
37099
37949
|
}
|
|
37100
37950
|
function parseNumstat(lines) {
|
|
37101
37951
|
const m = /* @__PURE__ */ new Map();
|
|
37102
|
-
for (const [
|
|
37103
|
-
m.set(
|
|
37952
|
+
for (const [path55, entry] of parseNumstatEntries(lines)) {
|
|
37953
|
+
m.set(path55, { additions: entry.additions, deletions: entry.deletions });
|
|
37104
37954
|
}
|
|
37105
37955
|
return m;
|
|
37106
37956
|
}
|
|
@@ -37231,7 +38081,7 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
37231
38081
|
g.raw(["diff", ...RENAME_DIFF_ARGS, "--numstat", range]).catch(() => "")
|
|
37232
38082
|
]);
|
|
37233
38083
|
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
37234
|
-
const normRel =
|
|
38084
|
+
const normRel = normalizeRepoRelPath2(repoRelPath);
|
|
37235
38085
|
const paths = collectChangedPaths({
|
|
37236
38086
|
nameEntries: parsed.nameEntries,
|
|
37237
38087
|
numByPath: parsed.numByPath
|
|
@@ -37259,14 +38109,14 @@ async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
|
37259
38109
|
}
|
|
37260
38110
|
|
|
37261
38111
|
// src/git/changes/listing/apply-untracked-file-stats.ts
|
|
37262
|
-
import * as
|
|
37263
|
-
import * as
|
|
38112
|
+
import * as fs25 from "node:fs";
|
|
38113
|
+
import * as path31 from "node:path";
|
|
37264
38114
|
function createUntrackedStatsApplier(options) {
|
|
37265
38115
|
return async (row, pathInRepo) => {
|
|
37266
38116
|
if (!options.untrackedSet.has(pathInRepo)) return;
|
|
37267
38117
|
if (options.nameByPath.has(pathInRepo)) return;
|
|
37268
38118
|
if (row.change === "moved") return;
|
|
37269
|
-
const repoFilePath =
|
|
38119
|
+
const repoFilePath = path31.join(options.repoGitCwd, pathInRepo);
|
|
37270
38120
|
const fromGit = await numstatFromGitNoIndex(options.g, pathInRepo);
|
|
37271
38121
|
if (fromGit) {
|
|
37272
38122
|
row.additions = fromGit.additions;
|
|
@@ -37274,7 +38124,7 @@ function createUntrackedStatsApplier(options) {
|
|
|
37274
38124
|
return;
|
|
37275
38125
|
}
|
|
37276
38126
|
try {
|
|
37277
|
-
const st = await
|
|
38127
|
+
const st = await fs25.promises.stat(repoFilePath);
|
|
37278
38128
|
row.additions = st.isFile() ? await countTextFileLines(repoFilePath) : 0;
|
|
37279
38129
|
} catch {
|
|
37280
38130
|
row.additions = 0;
|
|
@@ -37284,13 +38134,75 @@ function createUntrackedStatsApplier(options) {
|
|
|
37284
38134
|
}
|
|
37285
38135
|
|
|
37286
38136
|
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
37287
|
-
import * as
|
|
38137
|
+
import * as path32 from "node:path";
|
|
37288
38138
|
|
|
37289
|
-
// src/git/changes/patch/hydrate-
|
|
37290
|
-
|
|
38139
|
+
// src/git/changes/patch/hydrate/append-injected-context-lines.ts
|
|
38140
|
+
async function appendInjectedContextLines(out, inject, maybeYield, injectedTotal) {
|
|
38141
|
+
for (const t of inject) {
|
|
38142
|
+
out.push(` ${t}`);
|
|
38143
|
+
injectedTotal.value++;
|
|
38144
|
+
await maybeYield();
|
|
38145
|
+
}
|
|
38146
|
+
}
|
|
38147
|
+
|
|
38148
|
+
// src/git/changes/patch/hydrate/constants.ts
|
|
37291
38149
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
37292
38150
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
37293
38151
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
38152
|
+
var HYDRATE_YIELD_EVERY_LINES = 512;
|
|
38153
|
+
|
|
38154
|
+
// src/git/changes/patch/hydrate/collect-gap-inject-lines.ts
|
|
38155
|
+
async function collectGapInjectLines(options) {
|
|
38156
|
+
if (options.injectedTotal >= MAX_HYDRATE_LINES_PER_FILE) return null;
|
|
38157
|
+
const remaining = MAX_HYDRATE_LINES_PER_FILE - options.injectedTotal;
|
|
38158
|
+
if (options.gapNewEnd >= options.gapNewStart && options.change !== "removed") {
|
|
38159
|
+
const nNew = options.gapNewEnd - options.gapNewStart + 1;
|
|
38160
|
+
if (options.gapOldEnd < options.gapOldStart || options.gapOldEnd - options.gapOldStart + 1 === nNew) {
|
|
38161
|
+
const cap = Math.min(nNew, MAX_HYDRATE_LINES_PER_GAP, remaining);
|
|
38162
|
+
const dl = await options.diskLines();
|
|
38163
|
+
if (dl && cap > 0) {
|
|
38164
|
+
return dl.slice(options.gapNewStart - 1, options.gapNewStart - 1 + cap);
|
|
38165
|
+
}
|
|
38166
|
+
}
|
|
38167
|
+
return null;
|
|
38168
|
+
}
|
|
38169
|
+
if (options.gapOldEnd >= options.gapOldStart && options.change === "removed") {
|
|
38170
|
+
const nOld = options.gapOldEnd - options.gapOldStart + 1;
|
|
38171
|
+
const cap = Math.min(nOld, MAX_HYDRATE_LINES_PER_GAP, remaining);
|
|
38172
|
+
const bl = await options.blobLines();
|
|
38173
|
+
if (bl && cap > 0) {
|
|
38174
|
+
return bl.slice(options.gapOldStart - 1, options.gapOldStart - 1 + cap);
|
|
38175
|
+
}
|
|
38176
|
+
}
|
|
38177
|
+
return null;
|
|
38178
|
+
}
|
|
38179
|
+
|
|
38180
|
+
// src/git/changes/patch/hydrate/consume-unified-hunk-body.ts
|
|
38181
|
+
async function consumeUnifiedHunkBody(options) {
|
|
38182
|
+
let i = options.startIndex;
|
|
38183
|
+
let oldConsumed = 0;
|
|
38184
|
+
let newConsumed = 0;
|
|
38185
|
+
while (i < options.all.length) {
|
|
38186
|
+
await options.maybeYield();
|
|
38187
|
+
const bl = options.all[i];
|
|
38188
|
+
if (UNIFIED_HUNK_HEADER_RE.test(bl)) break;
|
|
38189
|
+
options.out.push(bl);
|
|
38190
|
+
i++;
|
|
38191
|
+
if (bl.startsWith("\\")) continue;
|
|
38192
|
+
const ch = bl[0];
|
|
38193
|
+
if (ch === " ") {
|
|
38194
|
+
oldConsumed++;
|
|
38195
|
+
newConsumed++;
|
|
38196
|
+
} else if (ch === "-") {
|
|
38197
|
+
oldConsumed++;
|
|
38198
|
+
} else if (ch === "+") {
|
|
38199
|
+
newConsumed++;
|
|
38200
|
+
}
|
|
38201
|
+
}
|
|
38202
|
+
return { nextIndex: i, oldConsumed, newConsumed };
|
|
38203
|
+
}
|
|
38204
|
+
|
|
38205
|
+
// src/git/changes/patch/hydrate/read-git-blob-lines.ts
|
|
37294
38206
|
async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
37295
38207
|
try {
|
|
37296
38208
|
const rel = pathInRepo.replace(/\\/g, "/");
|
|
@@ -37300,35 +38212,66 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
37300
38212
|
return null;
|
|
37301
38213
|
}
|
|
37302
38214
|
}
|
|
38215
|
+
|
|
38216
|
+
// src/git/changes/patch/hydrate/read-worktree-file-lines.ts
|
|
38217
|
+
import * as fs26 from "node:fs";
|
|
37303
38218
|
async function readWorktreeFileLines(filePath) {
|
|
37304
38219
|
try {
|
|
37305
|
-
const raw = await
|
|
38220
|
+
const raw = await fs26.promises.readFile(filePath, "utf8");
|
|
37306
38221
|
return raw.split(/\r?\n/);
|
|
37307
38222
|
} catch {
|
|
37308
38223
|
return null;
|
|
37309
38224
|
}
|
|
37310
38225
|
}
|
|
37311
|
-
|
|
37312
|
-
|
|
37313
|
-
|
|
37314
|
-
const out = [];
|
|
37315
|
-
let prevOldEnd = 0;
|
|
37316
|
-
let prevNewEnd = 0;
|
|
37317
|
-
let injectedTotal = 0;
|
|
37318
|
-
let i = 0;
|
|
38226
|
+
|
|
38227
|
+
// src/git/changes/patch/hydrate/create-hydrate-source-lines.ts
|
|
38228
|
+
function createHydrateSourceLines(options) {
|
|
37319
38229
|
let blobCache;
|
|
37320
38230
|
let diskCache;
|
|
37321
38231
|
const blobLines = async () => {
|
|
37322
38232
|
if (blobCache !== void 0) return blobCache;
|
|
37323
|
-
blobCache = await readGitBlobLines(repoGitCwd, pathInRepo);
|
|
38233
|
+
blobCache = await readGitBlobLines(options.repoGitCwd, options.pathInRepo);
|
|
37324
38234
|
return blobCache;
|
|
37325
38235
|
};
|
|
37326
38236
|
const diskLines = async () => {
|
|
37327
38237
|
if (diskCache !== void 0) return diskCache;
|
|
37328
|
-
diskCache = await readWorktreeFileLines(filePath);
|
|
38238
|
+
diskCache = await readWorktreeFileLines(options.filePath);
|
|
37329
38239
|
return diskCache;
|
|
37330
38240
|
};
|
|
38241
|
+
return { blobLines, diskLines };
|
|
38242
|
+
}
|
|
38243
|
+
|
|
38244
|
+
// src/git/changes/patch/hydrate/create-hydrate-yield.ts
|
|
38245
|
+
function createHydrateYield() {
|
|
38246
|
+
let processedLines = 0;
|
|
38247
|
+
return async () => {
|
|
38248
|
+
processedLines++;
|
|
38249
|
+
if (processedLines % HYDRATE_YIELD_EVERY_LINES === 0) {
|
|
38250
|
+
await yieldToEventLoop();
|
|
38251
|
+
}
|
|
38252
|
+
};
|
|
38253
|
+
}
|
|
38254
|
+
|
|
38255
|
+
// src/git/changes/patch/hydrate/update-hunk-line-ends.ts
|
|
38256
|
+
function updateHunkLineEnds(options) {
|
|
38257
|
+
const prevOldEnd = options.oldStart > 0 ? options.oldStart + options.oldConsumed - 1 : 0;
|
|
38258
|
+
const prevNewEnd = options.newStart > 0 ? options.newStart + options.newConsumed - 1 : 0;
|
|
38259
|
+
return { prevOldEnd, prevNewEnd };
|
|
38260
|
+
}
|
|
38261
|
+
|
|
38262
|
+
// src/git/changes/patch/hydrate/hydrate-unified-patch-with-file-context.ts
|
|
38263
|
+
async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, change) {
|
|
38264
|
+
if (!patch.trim() || patch.includes("Binary files")) return patch;
|
|
38265
|
+
const all = patch.split("\n");
|
|
38266
|
+
const out = [];
|
|
38267
|
+
let prevOldEnd = 0;
|
|
38268
|
+
let prevNewEnd = 0;
|
|
38269
|
+
const injectedTotal = { value: 0 };
|
|
38270
|
+
let i = 0;
|
|
38271
|
+
const maybeYield = createHydrateYield();
|
|
38272
|
+
const { blobLines, diskLines } = createHydrateSourceLines({ repoGitCwd, pathInRepo, filePath });
|
|
37331
38273
|
while (i < all.length) {
|
|
38274
|
+
await maybeYield();
|
|
37332
38275
|
const line = all[i];
|
|
37333
38276
|
const hm = line.match(UNIFIED_HUNK_HEADER_RE);
|
|
37334
38277
|
if (!hm) {
|
|
@@ -37338,66 +38281,31 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
37338
38281
|
}
|
|
37339
38282
|
const oldStart = parseInt(hm[1], 10) || 0;
|
|
37340
38283
|
const newStart = parseInt(hm[3], 10) || 0;
|
|
37341
|
-
const
|
|
37342
|
-
|
|
37343
|
-
|
|
37344
|
-
|
|
37345
|
-
|
|
37346
|
-
|
|
37347
|
-
|
|
37348
|
-
|
|
37349
|
-
|
|
37350
|
-
|
|
37351
|
-
|
|
37352
|
-
|
|
37353
|
-
inject = dl.slice(gapNewStart - 1, gapNewStart - 1 + cap);
|
|
37354
|
-
}
|
|
37355
|
-
}
|
|
37356
|
-
} else if (gapOldEnd >= gapOldStart && change === "removed") {
|
|
37357
|
-
const nOld = gapOldEnd - gapOldStart + 1;
|
|
37358
|
-
const cap = Math.min(nOld, MAX_HYDRATE_LINES_PER_GAP, MAX_HYDRATE_LINES_PER_FILE - injectedTotal);
|
|
37359
|
-
const bl = await blobLines();
|
|
37360
|
-
if (bl && cap > 0) {
|
|
37361
|
-
inject = bl.slice(gapOldStart - 1, gapOldStart - 1 + cap);
|
|
37362
|
-
}
|
|
37363
|
-
}
|
|
37364
|
-
if (inject && inject.length > 0) {
|
|
37365
|
-
for (const t of inject) {
|
|
37366
|
-
out.push(` ${t}`);
|
|
37367
|
-
injectedTotal++;
|
|
37368
|
-
}
|
|
37369
|
-
}
|
|
38284
|
+
const inject = await collectGapInjectLines({
|
|
38285
|
+
change,
|
|
38286
|
+
gapOldStart: prevOldEnd + 1,
|
|
38287
|
+
gapOldEnd: oldStart - 1,
|
|
38288
|
+
gapNewStart: prevNewEnd + 1,
|
|
38289
|
+
gapNewEnd: newStart - 1,
|
|
38290
|
+
injectedTotal: injectedTotal.value,
|
|
38291
|
+
blobLines,
|
|
38292
|
+
diskLines
|
|
38293
|
+
});
|
|
38294
|
+
if (inject && inject.length > 0) {
|
|
38295
|
+
await appendInjectedContextLines(out, inject, maybeYield, injectedTotal);
|
|
37370
38296
|
}
|
|
37371
38297
|
out.push(line);
|
|
37372
38298
|
i++;
|
|
37373
|
-
|
|
37374
|
-
|
|
37375
|
-
|
|
37376
|
-
|
|
37377
|
-
|
|
37378
|
-
|
|
37379
|
-
|
|
37380
|
-
|
|
37381
|
-
|
|
37382
|
-
|
|
37383
|
-
oldConsumed++;
|
|
37384
|
-
newConsumed++;
|
|
37385
|
-
} else if (ch === "-") {
|
|
37386
|
-
oldConsumed++;
|
|
37387
|
-
} else if (ch === "+") {
|
|
37388
|
-
newConsumed++;
|
|
37389
|
-
}
|
|
37390
|
-
}
|
|
37391
|
-
if (oldStart > 0) {
|
|
37392
|
-
prevOldEnd = oldStart + oldConsumed - 1;
|
|
37393
|
-
} else {
|
|
37394
|
-
prevOldEnd = 0;
|
|
37395
|
-
}
|
|
37396
|
-
if (newStart > 0) {
|
|
37397
|
-
prevNewEnd = newStart + newConsumed - 1;
|
|
37398
|
-
} else {
|
|
37399
|
-
prevNewEnd = 0;
|
|
37400
|
-
}
|
|
38299
|
+
const body = await consumeUnifiedHunkBody({ all, startIndex: i, out, maybeYield });
|
|
38300
|
+
i = body.nextIndex;
|
|
38301
|
+
const ends = updateHunkLineEnds({
|
|
38302
|
+
oldStart,
|
|
38303
|
+
newStart,
|
|
38304
|
+
oldConsumed: body.oldConsumed,
|
|
38305
|
+
newConsumed: body.newConsumed
|
|
38306
|
+
});
|
|
38307
|
+
prevOldEnd = ends.prevOldEnd;
|
|
38308
|
+
prevNewEnd = ends.prevNewEnd;
|
|
37401
38309
|
}
|
|
37402
38310
|
return truncatePatch(out.join("\n"));
|
|
37403
38311
|
}
|
|
@@ -37406,7 +38314,7 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
37406
38314
|
async function enrichWorkingTreeFileRows(options) {
|
|
37407
38315
|
await forEachWithGitYield(options.rows, async (row) => {
|
|
37408
38316
|
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
37409
|
-
const filePath =
|
|
38317
|
+
const filePath = path32.join(options.repoGitCwd, pathInRepo);
|
|
37410
38318
|
const hydrateKind = row.change === "moved" ? "modified" : row.change;
|
|
37411
38319
|
let patch = await unifiedDiffForFile(options.repoGitCwd, pathInRepo, row.change, row.movedFromPathInRepo);
|
|
37412
38320
|
if (patch) {
|
|
@@ -37468,14 +38376,76 @@ async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
|
37468
38376
|
return dedupeChangedFileRows(rows);
|
|
37469
38377
|
}
|
|
37470
38378
|
|
|
37471
|
-
// src/git/changes/
|
|
38379
|
+
// src/git/changes/repo/norm-repo-rel-path.ts
|
|
37472
38380
|
function normRepoRel(p) {
|
|
37473
38381
|
const x = p.replace(/\\/g, "/").trim();
|
|
37474
38382
|
return x === "" ? "." : x;
|
|
37475
38383
|
}
|
|
38384
|
+
|
|
38385
|
+
// src/git/changes/repo/build-working-tree-change-repo-detail.ts
|
|
38386
|
+
async function buildWorkingTreeChangeRepoDetail(options) {
|
|
38387
|
+
const t = path33.resolve(options.targetPath);
|
|
38388
|
+
if (!await isGitRepoDirectory(t)) return null;
|
|
38389
|
+
const g = cliSimpleGit(t);
|
|
38390
|
+
let branch = "HEAD";
|
|
38391
|
+
try {
|
|
38392
|
+
await yieldToEventLoop2();
|
|
38393
|
+
branch = (await g.raw(["rev-parse", "--abbrev-ref", "HEAD"])).trim() || "HEAD";
|
|
38394
|
+
} catch {
|
|
38395
|
+
branch = "HEAD";
|
|
38396
|
+
}
|
|
38397
|
+
await yieldToEventLoop2();
|
|
38398
|
+
const remoteUrl = await getRemoteOriginUrl(t);
|
|
38399
|
+
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
38400
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path33.resolve(options.sessionWorktreeRootPath) : null;
|
|
38401
|
+
const legacyNested = options.legacyRepoNestedSessionLayout;
|
|
38402
|
+
let repoRelPath;
|
|
38403
|
+
if (sessionWtRoot) {
|
|
38404
|
+
const anchor = legacyNested ? path33.dirname(t) : t;
|
|
38405
|
+
const relNorm = path33.relative(sessionWtRoot, anchor);
|
|
38406
|
+
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
38407
|
+
} else {
|
|
38408
|
+
let top = t;
|
|
38409
|
+
try {
|
|
38410
|
+
await yieldToEventLoop2();
|
|
38411
|
+
top = (await g.raw(["rev-parse", "--show-toplevel"])).trim();
|
|
38412
|
+
} catch {
|
|
38413
|
+
top = t;
|
|
38414
|
+
}
|
|
38415
|
+
const rel = path33.relative(options.bridgeRoot, path33.resolve(top)).replace(/\\/g, "/") || ".";
|
|
38416
|
+
repoRelPath = rel.startsWith("..") ? path33.basename(path33.resolve(top)) : rel;
|
|
38417
|
+
}
|
|
38418
|
+
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
38419
|
+
if (options.repoFilterRelPath && norm !== options.repoFilterRelPath) return null;
|
|
38420
|
+
const repoDisplayName = formatRepoShortTitle(remoteUrl, norm === "." ? "." : norm);
|
|
38421
|
+
const relForList = norm === "." ? "." : norm;
|
|
38422
|
+
const files = options.basis.kind === "commit" ? await listChangedFilesForCommit(t, relForList, options.basis.sha.trim()) : await listChangedFilesForRepo(t, relForList);
|
|
38423
|
+
const st = await g.status();
|
|
38424
|
+
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
38425
|
+
const [unpushedCommits, recentCommitList] = await Promise.all([
|
|
38426
|
+
listUnpushedCommits(t),
|
|
38427
|
+
listRecentCommits(t, options.recentCommitsLimit)
|
|
38428
|
+
]);
|
|
38429
|
+
return {
|
|
38430
|
+
repoRelPath: norm,
|
|
38431
|
+
repoDisplayName,
|
|
38432
|
+
branch,
|
|
38433
|
+
remoteUrl,
|
|
38434
|
+
remoteDisplay,
|
|
38435
|
+
files,
|
|
38436
|
+
hasUncommittedChanges,
|
|
38437
|
+
unpushedCommits,
|
|
38438
|
+
recentCommits: recentCommitList.commits,
|
|
38439
|
+
recentCommitsHasMore: recentCommitList.hasMore,
|
|
38440
|
+
changesView: options.basis.kind === "commit" ? "commit" : "working",
|
|
38441
|
+
changesCommitSha: options.basis.kind === "commit" ? options.basis.sha.trim() : null
|
|
38442
|
+
};
|
|
38443
|
+
}
|
|
38444
|
+
|
|
38445
|
+
// src/git/changes/repo/get-working-tree-change-repo-details.ts
|
|
37476
38446
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
37477
|
-
const bridgeRoot =
|
|
37478
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
38447
|
+
const bridgeRoot = path34.resolve(getBridgeRoot());
|
|
38448
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path34.resolve(options.sessionWorktreeRootPath) : null;
|
|
37479
38449
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
37480
38450
|
const out = [];
|
|
37481
38451
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -37488,59 +38458,18 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
37488
38458
|
}
|
|
37489
38459
|
const basis = filter == null && basisInput.kind === "commit" ? { kind: "working" } : basisInput;
|
|
37490
38460
|
for (let i = 0; i < options.commitTargetPaths.length; i++) {
|
|
37491
|
-
|
|
37492
|
-
const
|
|
37493
|
-
|
|
37494
|
-
|
|
37495
|
-
|
|
37496
|
-
|
|
37497
|
-
|
|
37498
|
-
|
|
37499
|
-
|
|
37500
|
-
|
|
37501
|
-
|
|
37502
|
-
|
|
37503
|
-
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
37504
|
-
let repoRelPath;
|
|
37505
|
-
if (sessionWtRoot) {
|
|
37506
|
-
const anchor = legacyNested ? path23.dirname(t) : t;
|
|
37507
|
-
const relNorm = path23.relative(sessionWtRoot, anchor);
|
|
37508
|
-
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
37509
|
-
} else {
|
|
37510
|
-
let top = t;
|
|
37511
|
-
try {
|
|
37512
|
-
top = (await g.raw(["rev-parse", "--show-toplevel"])).trim();
|
|
37513
|
-
} catch {
|
|
37514
|
-
top = t;
|
|
37515
|
-
}
|
|
37516
|
-
const rel = path23.relative(bridgeRoot, path23.resolve(top)).replace(/\\/g, "/") || ".";
|
|
37517
|
-
repoRelPath = rel.startsWith("..") ? path23.basename(path23.resolve(top)) : rel;
|
|
37518
|
-
}
|
|
37519
|
-
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
37520
|
-
if (filter && norm !== filter) continue;
|
|
37521
|
-
const repoDisplayName = formatRepoShortTitle(remoteUrl, norm === "." ? "." : norm);
|
|
37522
|
-
const relForList = norm === "." ? "." : norm;
|
|
37523
|
-
const files = basis.kind === "commit" ? await listChangedFilesForCommit(t, relForList, basis.sha.trim()) : await listChangedFilesForRepo(t, relForList);
|
|
37524
|
-
const st = await g.status();
|
|
37525
|
-
const hasUncommittedChanges = (st.files?.length ?? 0) > 0;
|
|
37526
|
-
const [unpushedCommits, recentCommitList] = await Promise.all([
|
|
37527
|
-
listUnpushedCommits(t),
|
|
37528
|
-
listRecentCommits(t, options.recentCommitsLimit)
|
|
37529
|
-
]);
|
|
37530
|
-
out.push({
|
|
37531
|
-
repoRelPath: norm,
|
|
37532
|
-
repoDisplayName,
|
|
37533
|
-
branch,
|
|
37534
|
-
remoteUrl,
|
|
37535
|
-
remoteDisplay,
|
|
37536
|
-
files,
|
|
37537
|
-
hasUncommittedChanges,
|
|
37538
|
-
unpushedCommits,
|
|
37539
|
-
recentCommits: recentCommitList.commits,
|
|
37540
|
-
recentCommitsHasMore: recentCommitList.hasMore,
|
|
37541
|
-
changesView: basis.kind === "commit" ? "commit" : "working",
|
|
37542
|
-
changesCommitSha: basis.kind === "commit" ? basis.sha.trim() : null
|
|
37543
|
-
});
|
|
38461
|
+
await yieldToEventLoop2();
|
|
38462
|
+
const detail = await buildWorkingTreeChangeRepoDetail({
|
|
38463
|
+
targetPath: options.commitTargetPaths[i],
|
|
38464
|
+
bridgeRoot,
|
|
38465
|
+
sessionWorktreeRootPath: sessionWtRoot,
|
|
38466
|
+
legacyRepoNestedSessionLayout: legacyNested,
|
|
38467
|
+
repoFilterRelPath: filter,
|
|
38468
|
+
basis,
|
|
38469
|
+
recentCommitsLimit: options.recentCommitsLimit
|
|
38470
|
+
});
|
|
38471
|
+
if (!detail) continue;
|
|
38472
|
+
out.push(detail);
|
|
37544
38473
|
if (filter) return out;
|
|
37545
38474
|
}
|
|
37546
38475
|
return out;
|
|
@@ -37642,23 +38571,23 @@ async function commitSessionWorktrees(options) {
|
|
|
37642
38571
|
}
|
|
37643
38572
|
|
|
37644
38573
|
// src/worktrees/remove-session-worktrees.ts
|
|
37645
|
-
import * as
|
|
38574
|
+
import * as fs29 from "node:fs";
|
|
37646
38575
|
|
|
37647
38576
|
// src/git/worktrees/worktree-remove.ts
|
|
37648
|
-
import * as
|
|
38577
|
+
import * as fs28 from "node:fs";
|
|
37649
38578
|
|
|
37650
38579
|
// src/git/worktrees/resolve-main-repo-from-git-file.ts
|
|
37651
|
-
import * as
|
|
37652
|
-
import * as
|
|
38580
|
+
import * as fs27 from "node:fs";
|
|
38581
|
+
import * as path35 from "node:path";
|
|
37653
38582
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
37654
|
-
const gitDirFile =
|
|
37655
|
-
if (!
|
|
37656
|
-
const first2 =
|
|
38583
|
+
const gitDirFile = path35.join(wt, ".git");
|
|
38584
|
+
if (!fs27.existsSync(gitDirFile) || !fs27.statSync(gitDirFile).isFile()) return "";
|
|
38585
|
+
const first2 = fs27.readFileSync(gitDirFile, "utf8").trim();
|
|
37657
38586
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
37658
38587
|
if (!m) return "";
|
|
37659
|
-
const gitWorktreePath =
|
|
37660
|
-
const gitDir =
|
|
37661
|
-
return
|
|
38588
|
+
const gitWorktreePath = path35.resolve(wt, m[1].trim());
|
|
38589
|
+
const gitDir = path35.dirname(path35.dirname(gitWorktreePath));
|
|
38590
|
+
return path35.dirname(gitDir);
|
|
37662
38591
|
}
|
|
37663
38592
|
|
|
37664
38593
|
// src/git/worktrees/worktree-remove.ts
|
|
@@ -37667,7 +38596,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
37667
38596
|
if (mainRepo) {
|
|
37668
38597
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
37669
38598
|
} else {
|
|
37670
|
-
|
|
38599
|
+
fs28.rmSync(worktreePath, { recursive: true, force: true });
|
|
37671
38600
|
}
|
|
37672
38601
|
}
|
|
37673
38602
|
|
|
@@ -37680,7 +38609,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
37680
38609
|
} catch (e) {
|
|
37681
38610
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
37682
38611
|
try {
|
|
37683
|
-
|
|
38612
|
+
fs29.rmSync(wt, { recursive: true, force: true });
|
|
37684
38613
|
} catch {
|
|
37685
38614
|
}
|
|
37686
38615
|
}
|
|
@@ -37708,458 +38637,86 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
37708
38637
|
}
|
|
37709
38638
|
}
|
|
37710
38639
|
|
|
37711
|
-
// src/worktrees/
|
|
37712
|
-
|
|
37713
|
-
import * as path25 from "node:path";
|
|
37714
|
-
import os7 from "node:os";
|
|
37715
|
-
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
37716
|
-
function defaultWorktreeLayoutPath() {
|
|
37717
|
-
return path25.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
37718
|
-
}
|
|
37719
|
-
function normalizeLoadedLayout(raw) {
|
|
37720
|
-
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
37721
|
-
const j = raw;
|
|
37722
|
-
if (Array.isArray(j.launcherCwds)) return { launcherCwds: j.launcherCwds };
|
|
37723
|
-
}
|
|
37724
|
-
return { launcherCwds: [] };
|
|
37725
|
-
}
|
|
37726
|
-
function loadWorktreeLayout() {
|
|
37727
|
-
try {
|
|
37728
|
-
const p = defaultWorktreeLayoutPath();
|
|
37729
|
-
if (!fs23.existsSync(p)) return { launcherCwds: [] };
|
|
37730
|
-
const raw = JSON.parse(fs23.readFileSync(p, "utf8"));
|
|
37731
|
-
return normalizeLoadedLayout(raw);
|
|
37732
|
-
} catch {
|
|
37733
|
-
return { launcherCwds: [] };
|
|
37734
|
-
}
|
|
37735
|
-
}
|
|
37736
|
-
function saveWorktreeLayout(layout) {
|
|
37737
|
-
try {
|
|
37738
|
-
const dir = path25.dirname(defaultWorktreeLayoutPath());
|
|
37739
|
-
fs23.mkdirSync(dir, { recursive: true });
|
|
37740
|
-
fs23.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
37741
|
-
} catch {
|
|
37742
|
-
}
|
|
37743
|
-
}
|
|
37744
|
-
function baseNameSafe(pathString) {
|
|
37745
|
-
return path25.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
37746
|
-
}
|
|
37747
|
-
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
37748
|
-
const norm = path25.resolve(bridgeRootPath2);
|
|
37749
|
-
const existing = layout.launcherCwds.find((e) => path25.resolve(e.absolutePath) === norm);
|
|
37750
|
-
return existing?.dirName;
|
|
37751
|
-
}
|
|
37752
|
-
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
37753
|
-
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
37754
|
-
if (existing) return existing;
|
|
37755
|
-
const norm = path25.resolve(bridgeRootPath2);
|
|
37756
|
-
const base = baseNameSafe(norm);
|
|
37757
|
-
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
37758
|
-
let name = base;
|
|
37759
|
-
let n = 2;
|
|
37760
|
-
while (used.has(name)) {
|
|
37761
|
-
name = `${base}-${n}`;
|
|
37762
|
-
n += 1;
|
|
37763
|
-
}
|
|
37764
|
-
layout.launcherCwds.push({ absolutePath: norm, dirName: name });
|
|
37765
|
-
saveWorktreeLayout(layout);
|
|
37766
|
-
return name;
|
|
37767
|
-
}
|
|
37768
|
-
|
|
37769
|
-
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
37770
|
-
import * as fs24 from "node:fs";
|
|
37771
|
-
import * as path26 from "node:path";
|
|
37772
|
-
function isGitDir(dirPath) {
|
|
37773
|
-
try {
|
|
37774
|
-
return fs24.existsSync(path26.join(dirPath, ".git"));
|
|
37775
|
-
} catch {
|
|
37776
|
-
return false;
|
|
37777
|
-
}
|
|
37778
|
-
}
|
|
37779
|
-
function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
37780
|
-
const out = [];
|
|
37781
|
-
const walk = (dir) => {
|
|
37782
|
-
if (isGitDir(dir)) {
|
|
37783
|
-
out.push(path26.resolve(dir));
|
|
37784
|
-
return;
|
|
37785
|
-
}
|
|
37786
|
-
let entries;
|
|
37787
|
-
try {
|
|
37788
|
-
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
37789
|
-
} catch {
|
|
37790
|
-
return;
|
|
37791
|
-
}
|
|
37792
|
-
for (const e of entries) {
|
|
37793
|
-
if (e.name.startsWith(".")) continue;
|
|
37794
|
-
const full = path26.join(dir, e.name);
|
|
37795
|
-
if (!e.isDirectory()) continue;
|
|
37796
|
-
walk(full);
|
|
37797
|
-
}
|
|
37798
|
-
};
|
|
37799
|
-
walk(path26.resolve(rootPath));
|
|
37800
|
-
return [...new Set(out)];
|
|
37801
|
-
}
|
|
37802
|
-
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
37803
|
-
const out = [];
|
|
37804
|
-
const walk = (dir, depth) => {
|
|
37805
|
-
if (depth > maxDepth) return;
|
|
37806
|
-
let entries;
|
|
37807
|
-
try {
|
|
37808
|
-
entries = fs24.readdirSync(dir, { withFileTypes: true });
|
|
37809
|
-
} catch {
|
|
37810
|
-
return;
|
|
37811
|
-
}
|
|
37812
|
-
for (const e of entries) {
|
|
37813
|
-
if (e.name.startsWith(".")) continue;
|
|
37814
|
-
const full = path26.join(dir, e.name);
|
|
37815
|
-
if (!e.isDirectory()) continue;
|
|
37816
|
-
if (e.name === sessionId) {
|
|
37817
|
-
if (isGitDir(full)) out.push(path26.resolve(full));
|
|
37818
|
-
} else {
|
|
37819
|
-
walk(full, depth + 1);
|
|
37820
|
-
}
|
|
37821
|
-
}
|
|
37822
|
-
};
|
|
37823
|
-
walk(root, 0);
|
|
37824
|
-
return out;
|
|
37825
|
-
}
|
|
37826
|
-
function tryBindingFromSessionDirectory(sessionDir) {
|
|
37827
|
-
let st;
|
|
37828
|
-
try {
|
|
37829
|
-
st = fs24.statSync(sessionDir);
|
|
37830
|
-
} catch {
|
|
37831
|
-
return null;
|
|
37832
|
-
}
|
|
37833
|
-
if (!st.isDirectory()) return null;
|
|
37834
|
-
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
37835
|
-
if (worktreePaths.length === 0) return null;
|
|
37836
|
-
const abs = path26.resolve(sessionDir);
|
|
37837
|
-
return {
|
|
37838
|
-
sessionParentPath: abs,
|
|
37839
|
-
workingTreeRelRoot: abs,
|
|
37840
|
-
repoCheckoutPaths: worktreePaths
|
|
37841
|
-
};
|
|
37842
|
-
}
|
|
37843
|
-
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
37844
|
-
const sid = sessionId.trim();
|
|
37845
|
-
if (!sid) return null;
|
|
37846
|
-
const hintR = path26.resolve(checkoutPath);
|
|
37847
|
-
let best = null;
|
|
37848
|
-
let cur = path26.dirname(hintR);
|
|
37849
|
-
for (let i = 0; i < 40; i++) {
|
|
37850
|
-
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
37851
|
-
if (paths.some((p) => path26.resolve(p) === hintR)) {
|
|
37852
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path26.resolve(paths[0]);
|
|
37853
|
-
best = {
|
|
37854
|
-
sessionParentPath: path26.resolve(isolated),
|
|
37855
|
-
workingTreeRelRoot: path26.resolve(cur),
|
|
37856
|
-
repoCheckoutPaths: paths.map((p) => path26.resolve(p))
|
|
37857
|
-
};
|
|
37858
|
-
}
|
|
37859
|
-
const next = path26.dirname(cur);
|
|
37860
|
-
if (next === cur) break;
|
|
37861
|
-
cur = next;
|
|
37862
|
-
}
|
|
37863
|
-
return best;
|
|
37864
|
-
}
|
|
37865
|
-
function discoverSessionWorktreeOnDisk(options) {
|
|
37866
|
-
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
37867
|
-
if (!sessionId.trim() || !fs24.existsSync(worktreesRootPath)) return null;
|
|
37868
|
-
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
37869
|
-
const keys = [];
|
|
37870
|
-
if (preferredKey) keys.push(preferredKey);
|
|
37871
|
-
try {
|
|
37872
|
-
for (const name of fs24.readdirSync(worktreesRootPath)) {
|
|
37873
|
-
if (name.startsWith(".")) continue;
|
|
37874
|
-
const p = path26.join(worktreesRootPath, name);
|
|
37875
|
-
if (!fs24.statSync(p).isDirectory()) continue;
|
|
37876
|
-
if (name !== preferredKey) keys.push(name);
|
|
37877
|
-
}
|
|
37878
|
-
} catch {
|
|
37879
|
-
return null;
|
|
37880
|
-
}
|
|
37881
|
-
for (const key of keys) {
|
|
37882
|
-
const layoutRoot = path26.join(worktreesRootPath, key);
|
|
37883
|
-
if (!fs24.existsSync(layoutRoot) || !fs24.statSync(layoutRoot).isDirectory()) continue;
|
|
37884
|
-
const sessionDir = path26.join(layoutRoot, sessionId);
|
|
37885
|
-
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
37886
|
-
if (nested) return nested;
|
|
37887
|
-
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
37888
|
-
if (legacyPaths.length > 0) {
|
|
37889
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
|
|
37890
|
-
return {
|
|
37891
|
-
sessionParentPath: path26.resolve(isolated),
|
|
37892
|
-
workingTreeRelRoot: path26.resolve(layoutRoot),
|
|
37893
|
-
repoCheckoutPaths: legacyPaths.map((p) => path26.resolve(p))
|
|
37894
|
-
};
|
|
37895
|
-
}
|
|
37896
|
-
}
|
|
37897
|
-
return null;
|
|
37898
|
-
}
|
|
37899
|
-
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
37900
|
-
const sid = sessionId.trim();
|
|
37901
|
-
if (!sid) return null;
|
|
37902
|
-
const hint = path26.resolve(sessionWorktreeRootPathOrHint);
|
|
37903
|
-
const underHint = tryBindingFromSessionDirectory(path26.join(hint, sid));
|
|
37904
|
-
if (underHint) return underHint;
|
|
37905
|
-
const direct = tryBindingFromSessionDirectory(hint);
|
|
37906
|
-
if (direct) {
|
|
37907
|
-
if (path26.basename(hint) === sid && isGitDir(hint)) {
|
|
37908
|
-
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
37909
|
-
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
37910
|
-
return legacyFromCheckout;
|
|
37911
|
-
}
|
|
37912
|
-
}
|
|
37913
|
-
return direct;
|
|
37914
|
-
}
|
|
37915
|
-
if (path26.basename(hint) === sid && isGitDir(hint)) {
|
|
37916
|
-
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
37917
|
-
if (legacyFromCheckout) return legacyFromCheckout;
|
|
37918
|
-
}
|
|
37919
|
-
let st;
|
|
37920
|
-
try {
|
|
37921
|
-
st = fs24.statSync(hint);
|
|
37922
|
-
} catch {
|
|
37923
|
-
return null;
|
|
37924
|
-
}
|
|
37925
|
-
if (!st.isDirectory()) return null;
|
|
37926
|
-
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
37927
|
-
if (legacyPaths.length === 0) return null;
|
|
37928
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path26.resolve(legacyPaths[0]);
|
|
38640
|
+
// src/worktrees/manager/resolve-commit-targets.ts
|
|
38641
|
+
function bridgeRootBinding(bridgeRoot) {
|
|
37929
38642
|
return {
|
|
37930
|
-
sessionParentPath:
|
|
37931
|
-
workingTreeRelRoot:
|
|
37932
|
-
repoCheckoutPaths:
|
|
38643
|
+
sessionParentPath: bridgeRoot,
|
|
38644
|
+
workingTreeRelRoot: bridgeRoot,
|
|
38645
|
+
repoCheckoutPaths: [bridgeRoot]
|
|
37933
38646
|
};
|
|
37934
38647
|
}
|
|
37935
|
-
|
|
37936
|
-
// src/worktrees/manager/discover-session-binding.ts
|
|
37937
|
-
function discoverSessionBinding(params) {
|
|
37938
|
-
return discoverSessionWorktreeOnDisk({
|
|
37939
|
-
sessionId: params.sessionId,
|
|
37940
|
-
worktreesRootPath: params.worktreesRootPath,
|
|
37941
|
-
layout: params.layout,
|
|
37942
|
-
bridgeRoot: getBridgeRoot()
|
|
37943
|
-
});
|
|
37944
|
-
}
|
|
37945
|
-
|
|
37946
|
-
// src/worktrees/manager/resolve-isolated-session-parent-path.ts
|
|
37947
|
-
function resolveIsolatedSessionParentPath(sessionId, cache2, ensureRepoCheckoutPaths) {
|
|
37948
|
-
if (!sessionId) return null;
|
|
37949
|
-
const sid = sessionId.trim();
|
|
37950
|
-
const cached2 = cache2.getSessionParentPath(sid);
|
|
37951
|
-
if (cached2) return cached2;
|
|
37952
|
-
const paths = ensureRepoCheckoutPaths(sid);
|
|
37953
|
-
if (!paths?.length) return null;
|
|
37954
|
-
return resolveIsolatedSessionParentPathFromCheckouts(paths);
|
|
37955
|
-
}
|
|
37956
|
-
function ensureRepoCheckoutPathsForSession(sessionId, cache2, discover) {
|
|
37957
|
-
if (!sessionId?.trim()) return void 0;
|
|
38648
|
+
async function resolveCommitTargetsAsync(sessionId, cache2, discover) {
|
|
37958
38649
|
const sid = sessionId.trim();
|
|
37959
|
-
const
|
|
37960
|
-
if (cached2?.length) return cached2;
|
|
37961
|
-
const disc = discover(sid);
|
|
37962
|
-
if (disc?.repoCheckoutPaths.length) {
|
|
37963
|
-
cache2.remember(sid, disc);
|
|
37964
|
-
return [...disc.repoCheckoutPaths];
|
|
37965
|
-
}
|
|
37966
|
-
return void 0;
|
|
37967
|
-
}
|
|
37968
|
-
|
|
37969
|
-
// src/worktrees/manager/resolve-commit-targets.ts
|
|
37970
|
-
function resolveCommitTargets(sessionId, cache2, discover) {
|
|
37971
|
-
const paths = cache2.getRepoCheckoutPathsRef(sessionId);
|
|
38650
|
+
const paths = cache2.getRepoCheckoutPathsRef(sid);
|
|
37972
38651
|
if (paths?.length) return paths;
|
|
37973
|
-
const disc = discover(
|
|
38652
|
+
const disc = await discover(sid);
|
|
37974
38653
|
if (disc?.repoCheckoutPaths.length) {
|
|
37975
|
-
cache2.remember(
|
|
38654
|
+
cache2.remember(sid, disc);
|
|
37976
38655
|
return disc.repoCheckoutPaths;
|
|
37977
38656
|
}
|
|
37978
|
-
|
|
38657
|
+
const bridgeRoot = getBridgeRoot();
|
|
38658
|
+
cache2.remember(sid, bridgeRootBinding(bridgeRoot));
|
|
38659
|
+
return [bridgeRoot];
|
|
37979
38660
|
}
|
|
37980
38661
|
|
|
37981
|
-
// src/worktrees/manager/
|
|
37982
|
-
function
|
|
37983
|
-
|
|
37984
|
-
|
|
37985
|
-
return
|
|
37986
|
-
|
|
37987
|
-
|
|
37988
|
-
|
|
37989
|
-
|
|
37990
|
-
|
|
37991
|
-
|
|
37992
|
-
// src/git/worktrees/worktree-add.ts
|
|
37993
|
-
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
37994
|
-
const mainGit = cliSimpleGit(mainRepoPath);
|
|
37995
|
-
const base = baseRef.trim() || "HEAD";
|
|
37996
|
-
await mainGit.raw(["worktree", "add", "-b", branch, worktreePath, base]);
|
|
37997
|
-
}
|
|
37998
|
-
|
|
37999
|
-
// src/worktrees/prepare-new-session-worktrees.ts
|
|
38000
|
-
function normalizeRepoRelPath2(rel) {
|
|
38001
|
-
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
38002
|
-
}
|
|
38003
|
-
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
38004
|
-
if (!baseBranches) return "HEAD";
|
|
38005
|
-
const direct = baseBranches[relNorm]?.trim();
|
|
38006
|
-
if (direct) return direct;
|
|
38007
|
-
if (relNorm !== "." && baseBranches["."]?.trim()) return baseBranches["."].trim();
|
|
38008
|
-
return "HEAD";
|
|
38662
|
+
// src/worktrees/manager/session-git-ops.ts
|
|
38663
|
+
async function commitSessionWorktree(cache2, params) {
|
|
38664
|
+
const paths = cache2.getRepoCheckoutPathsRef(params.sessionId);
|
|
38665
|
+
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
38666
|
+
return commitSessionWorktrees({
|
|
38667
|
+
paths: targets,
|
|
38668
|
+
branch: params.branch,
|
|
38669
|
+
message: params.message,
|
|
38670
|
+
push: params.push
|
|
38671
|
+
});
|
|
38009
38672
|
}
|
|
38010
|
-
async function
|
|
38011
|
-
|
|
38012
|
-
|
|
38013
|
-
|
|
38014
|
-
const bridgeKeyDir = path27.join(worktreesRootPath, cwdKey);
|
|
38015
|
-
const sessionDir = path27.join(bridgeKeyDir, sessionId);
|
|
38016
|
-
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
38017
|
-
if (repos.length === 0) {
|
|
38018
|
-
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
38019
|
-
return null;
|
|
38020
|
-
}
|
|
38021
|
-
const branch = `session-${sessionId}`;
|
|
38022
|
-
const worktreePaths = [];
|
|
38023
|
-
fs25.mkdirSync(sessionDir, { recursive: true });
|
|
38024
|
-
for (const repo of repos) {
|
|
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);
|
|
38029
|
-
if (relNorm !== ".") {
|
|
38030
|
-
fs25.mkdirSync(path27.dirname(wtPath), { recursive: true });
|
|
38031
|
-
}
|
|
38032
|
-
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
38033
|
-
try {
|
|
38034
|
-
await gitWorktreeAddBranch(repo.absolutePath, wtPath, branch, baseRef);
|
|
38035
|
-
log2(`[worktrees] Added worktree ${wtPath} (branch ${branch}, base ${baseRef}).`);
|
|
38036
|
-
worktreePaths.push(wtPath);
|
|
38037
|
-
} catch (e) {
|
|
38038
|
-
log2(
|
|
38039
|
-
`[worktrees] Worktree add failed for ${repo.absolutePath}: ${e instanceof Error ? e.message : String(e)}`
|
|
38040
|
-
);
|
|
38041
|
-
}
|
|
38042
|
-
}
|
|
38043
|
-
if (worktreePaths.length === 0) return null;
|
|
38044
|
-
return {
|
|
38045
|
-
worktreePaths,
|
|
38046
|
-
sessionParentPath: sessionDir,
|
|
38047
|
-
workingTreeRelRoot: sessionDir
|
|
38048
|
-
};
|
|
38673
|
+
async function getSessionWorkingTreeStatus(cache2, sessionId, discover) {
|
|
38674
|
+
return aggregateSessionPathsWorkingTreeStatus(
|
|
38675
|
+
await resolveCommitTargetsAsync(sessionId, cache2, discover)
|
|
38676
|
+
);
|
|
38049
38677
|
}
|
|
38050
|
-
|
|
38051
|
-
|
|
38052
|
-
|
|
38053
|
-
|
|
38054
|
-
|
|
38055
|
-
|
|
38056
|
-
|
|
38057
|
-
|
|
38058
|
-
|
|
38059
|
-
...params.worktreeBaseBranches && Object.keys(params.worktreeBaseBranches).length > 0 ? { worktreeBaseBranches: params.worktreeBaseBranches } : {}
|
|
38678
|
+
async function getSessionWorkingTreeChangeDetails(cache2, sessionId, discover, opts) {
|
|
38679
|
+
const targets = await resolveCommitTargetsAsync(sessionId, cache2, discover);
|
|
38680
|
+
return getWorkingTreeChangeRepoDetails({
|
|
38681
|
+
commitTargetPaths: targets,
|
|
38682
|
+
sessionWorktreeRootPath: cache2.getWorkingTreeRelRoot(sessionId),
|
|
38683
|
+
legacyRepoNestedSessionLayout: cache2.isLegacyNestedLayout(sessionId),
|
|
38684
|
+
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
38685
|
+
basis: opts?.basis,
|
|
38686
|
+
recentCommitsLimit: opts?.recentCommitsLimit
|
|
38060
38687
|
});
|
|
38061
|
-
if (!prep) return void 0;
|
|
38062
|
-
params.cache.remember(params.sessionId, {
|
|
38063
|
-
sessionParentPath: prep.sessionParentPath,
|
|
38064
|
-
workingTreeRelRoot: prep.workingTreeRelRoot,
|
|
38065
|
-
repoCheckoutPaths: prep.worktreePaths
|
|
38066
|
-
});
|
|
38067
|
-
return params.cache.getSessionParentPath(params.sessionId);
|
|
38068
38688
|
}
|
|
38069
|
-
|
|
38070
|
-
|
|
38071
|
-
|
|
38072
|
-
|
|
38073
|
-
|
|
38074
|
-
|
|
38075
|
-
|
|
38076
|
-
cache2.remember(sessionId, disc);
|
|
38077
|
-
return cache2.getSessionParentPath(sessionId);
|
|
38689
|
+
async function pushSessionUpstream(cache2, sessionId, discover) {
|
|
38690
|
+
try {
|
|
38691
|
+
await pushAheadOfUpstreamForPaths(await resolveCommitTargetsAsync(sessionId, cache2, discover));
|
|
38692
|
+
return { ok: true };
|
|
38693
|
+
} catch (e) {
|
|
38694
|
+
const err = e instanceof Error ? e.message : String(e);
|
|
38695
|
+
return { ok: false, error: err };
|
|
38078
38696
|
}
|
|
38079
|
-
return void 0;
|
|
38080
38697
|
}
|
|
38081
|
-
|
|
38082
|
-
|
|
38083
|
-
|
|
38084
|
-
|
|
38085
|
-
const resolved = path28.resolve(params.parentPathRaw);
|
|
38086
|
-
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
38087
|
-
return resolved;
|
|
38088
|
-
}
|
|
38089
|
-
const rememberAndReturn = (binding) => {
|
|
38090
|
-
params.cache.remember(params.sessionId, binding);
|
|
38091
|
-
return params.cache.getSessionParentPath(params.sessionId) ?? resolved;
|
|
38092
|
-
};
|
|
38093
|
-
const diskFirst = params.discover();
|
|
38094
|
-
if (diskFirst) return rememberAndReturn(diskFirst);
|
|
38095
|
-
const fromRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(resolved, params.sessionId);
|
|
38096
|
-
if (fromRoot) return rememberAndReturn(fromRoot);
|
|
38097
|
-
let cur = resolved;
|
|
38098
|
-
for (let i = 0; i < 16; i++) {
|
|
38099
|
-
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
38100
|
-
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
38101
|
-
const next = path28.dirname(cur);
|
|
38102
|
-
if (next === cur) break;
|
|
38103
|
-
cur = next;
|
|
38104
|
-
}
|
|
38105
|
-
return resolved;
|
|
38698
|
+
async function removeSessionWorktreeCheckouts(cache2, sessionId, log2) {
|
|
38699
|
+
const paths = cache2.clearSession(sessionId);
|
|
38700
|
+
if (!paths?.length) return;
|
|
38701
|
+
await removeSessionWorktrees(paths, log2);
|
|
38106
38702
|
}
|
|
38107
|
-
|
|
38108
|
-
|
|
38109
|
-
|
|
38110
|
-
|
|
38111
|
-
if (!sessionId) return void 0;
|
|
38112
|
-
const sid = sessionId.trim();
|
|
38113
|
-
const parentPathRaw = opts.sessionParentPath?.trim();
|
|
38114
|
-
if (parentPathRaw) {
|
|
38115
|
-
return resolveExplicitSessionParentPath({
|
|
38116
|
-
sessionId: sid,
|
|
38117
|
-
sessionParent: opts.sessionParent,
|
|
38118
|
-
parentPathRaw,
|
|
38119
|
-
cache: cache2,
|
|
38120
|
-
discover: () => discover(sid)
|
|
38121
|
-
});
|
|
38122
|
-
}
|
|
38123
|
-
const parentKind = parseSessionParent(opts.sessionParent);
|
|
38124
|
-
if (parentKind === "bridge_root") {
|
|
38125
|
-
return void 0;
|
|
38126
|
-
}
|
|
38127
|
-
if (parentKind === "worktrees_root") {
|
|
38128
|
-
if (!opts.isNewSession) {
|
|
38129
|
-
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
38130
|
-
}
|
|
38131
|
-
return prepareAndRememberSessionWorktrees({
|
|
38132
|
-
cache: cache2,
|
|
38133
|
-
sessionId: sid,
|
|
38134
|
-
worktreesRootPath,
|
|
38135
|
-
layout,
|
|
38136
|
-
log: log2,
|
|
38137
|
-
...opts.worktreeBaseBranches ? { worktreeBaseBranches: opts.worktreeBaseBranches } : {}
|
|
38138
|
-
});
|
|
38139
|
-
}
|
|
38140
|
-
if (!opts.isNewSession) {
|
|
38141
|
-
return resolveExistingSessionParentPath(sid, cache2, () => discover(sid));
|
|
38142
|
-
}
|
|
38143
|
-
return prepareAndRememberSessionWorktrees({
|
|
38144
|
-
cache: cache2,
|
|
38145
|
-
sessionId: sid,
|
|
38146
|
-
worktreesRootPath,
|
|
38147
|
-
layout,
|
|
38148
|
-
log: log2
|
|
38149
|
-
});
|
|
38703
|
+
async function renameSessionWorktreeBranch(cache2, sessionId, newBranch, log2) {
|
|
38704
|
+
const paths = cache2.getRepoCheckoutPathsRef(sessionId);
|
|
38705
|
+
if (!paths?.length) return;
|
|
38706
|
+
await renameSessionWorktreeBranches(paths, newBranch, log2);
|
|
38150
38707
|
}
|
|
38151
38708
|
|
|
38152
38709
|
// src/worktrees/manager/session-worktree-cache.ts
|
|
38153
|
-
import * as
|
|
38710
|
+
import * as path36 from "node:path";
|
|
38154
38711
|
var SessionWorktreeCache = class {
|
|
38155
38712
|
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
38156
38713
|
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
38157
38714
|
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
38158
38715
|
remember(sessionId, binding) {
|
|
38159
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
38716
|
+
const paths = binding.repoCheckoutPaths.map((p) => path36.resolve(p));
|
|
38160
38717
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
38161
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
38162
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
38718
|
+
this.sessionParentPathBySession.set(sessionId, path36.resolve(binding.sessionParentPath));
|
|
38719
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path36.resolve(binding.workingTreeRelRoot));
|
|
38163
38720
|
}
|
|
38164
38721
|
clearSession(sessionId) {
|
|
38165
38722
|
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
@@ -38189,7 +38746,7 @@ var SessionWorktreeCache = class {
|
|
|
38189
38746
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
38190
38747
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
38191
38748
|
if (!parent || !relRoot) return false;
|
|
38192
|
-
return
|
|
38749
|
+
return path36.resolve(parent) !== path36.resolve(relRoot);
|
|
38193
38750
|
}
|
|
38194
38751
|
};
|
|
38195
38752
|
|
|
@@ -38204,8 +38761,8 @@ var SessionWorktreeManager = class {
|
|
|
38204
38761
|
this.log = options.log;
|
|
38205
38762
|
this.layout = loadWorktreeLayout();
|
|
38206
38763
|
}
|
|
38207
|
-
|
|
38208
|
-
return
|
|
38764
|
+
discoverAsync(sessionId) {
|
|
38765
|
+
return discoverSessionBindingAsync({
|
|
38209
38766
|
sessionId,
|
|
38210
38767
|
worktreesRootPath: this.worktreesRootPath,
|
|
38211
38768
|
layout: this.layout
|
|
@@ -38225,14 +38782,12 @@ var SessionWorktreeManager = class {
|
|
|
38225
38782
|
worktreesRootPath: this.worktreesRootPath,
|
|
38226
38783
|
layout: this.layout,
|
|
38227
38784
|
log: this.log,
|
|
38228
|
-
discover: (sid) => this.
|
|
38785
|
+
discover: (sid) => this.discoverAsync(sid),
|
|
38229
38786
|
opts
|
|
38230
38787
|
});
|
|
38231
38788
|
}
|
|
38232
38789
|
async renameSessionBranch(sessionId, newBranch) {
|
|
38233
|
-
|
|
38234
|
-
if (!paths?.length) return;
|
|
38235
|
-
await renameSessionWorktreeBranches(paths, newBranch, this.log);
|
|
38790
|
+
await renameSessionWorktreeBranch(this.cache, sessionId, newBranch, this.log);
|
|
38236
38791
|
}
|
|
38237
38792
|
usesWorktreeSession(sessionId) {
|
|
38238
38793
|
if (!sessionId) return false;
|
|
@@ -38243,79 +38798,55 @@ var SessionWorktreeManager = class {
|
|
|
38243
38798
|
return this.cache.getRepoCheckoutPaths(sessionId);
|
|
38244
38799
|
}
|
|
38245
38800
|
ensureRepoCheckoutPathsForSession(sessionId) {
|
|
38246
|
-
return ensureRepoCheckoutPathsForSession(sessionId, this.cache
|
|
38801
|
+
return ensureRepoCheckoutPathsForSession(sessionId, this.cache);
|
|
38802
|
+
}
|
|
38803
|
+
async ensureRepoCheckoutPathsForSessionAsync(sessionId) {
|
|
38804
|
+
return ensureRepoCheckoutPathsForSessionAsync(sessionId, this.cache, (sid) => this.discoverAsync(sid));
|
|
38247
38805
|
}
|
|
38248
38806
|
getSessionWorktreeRootForSession(sessionId) {
|
|
38249
38807
|
return this.getIsolatedSessionParentPathForSession(sessionId);
|
|
38250
38808
|
}
|
|
38251
38809
|
async removeSessionWorktrees(sessionId) {
|
|
38252
|
-
|
|
38253
|
-
if (!paths?.length) return;
|
|
38254
|
-
await removeSessionWorktrees(paths, this.log);
|
|
38810
|
+
await removeSessionWorktreeCheckouts(this.cache, sessionId, this.log);
|
|
38255
38811
|
}
|
|
38256
38812
|
async commitSession(params) {
|
|
38257
|
-
|
|
38258
|
-
const targets = paths?.length ? paths : [getBridgeRoot()];
|
|
38259
|
-
return commitSessionWorktrees({
|
|
38260
|
-
paths: targets,
|
|
38261
|
-
branch: params.branch,
|
|
38262
|
-
message: params.message,
|
|
38263
|
-
push: params.push
|
|
38264
|
-
});
|
|
38813
|
+
return commitSessionWorktree(this.cache, params);
|
|
38265
38814
|
}
|
|
38266
38815
|
async getSessionWorkingTreeStatus(sessionId) {
|
|
38267
|
-
return
|
|
38268
|
-
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
38269
|
-
);
|
|
38816
|
+
return getSessionWorkingTreeStatus(this.cache, sessionId, (sid) => this.discoverAsync(sid));
|
|
38270
38817
|
}
|
|
38271
38818
|
async getSessionWorkingTreeChangeDetails(sessionId, opts) {
|
|
38272
|
-
|
|
38273
|
-
return getWorkingTreeChangeRepoDetails({
|
|
38274
|
-
commitTargetPaths: targets,
|
|
38275
|
-
sessionWorktreeRootPath: this.cache.getWorkingTreeRelRoot(sessionId),
|
|
38276
|
-
legacyRepoNestedSessionLayout: this.cache.isLegacyNestedLayout(sessionId),
|
|
38277
|
-
repoFilterRelPath: opts?.repoRelPath?.trim() ? opts.repoRelPath.trim() : null,
|
|
38278
|
-
basis: opts?.basis,
|
|
38279
|
-
recentCommitsLimit: opts?.recentCommitsLimit
|
|
38280
|
-
});
|
|
38819
|
+
return getSessionWorkingTreeChangeDetails(this.cache, sessionId, (sid) => this.discoverAsync(sid), opts);
|
|
38281
38820
|
}
|
|
38282
38821
|
async pushSessionUpstream(sessionId) {
|
|
38283
|
-
|
|
38284
|
-
await pushAheadOfUpstreamForPaths(
|
|
38285
|
-
resolveCommitTargets(sessionId, this.cache, (sid) => this.discover(sid))
|
|
38286
|
-
);
|
|
38287
|
-
return { ok: true };
|
|
38288
|
-
} catch (e) {
|
|
38289
|
-
const err = e instanceof Error ? e.message : String(e);
|
|
38290
|
-
return { ok: false, error: err };
|
|
38291
|
-
}
|
|
38822
|
+
return pushSessionUpstream(this.cache, sessionId, (sid) => this.discoverAsync(sid));
|
|
38292
38823
|
}
|
|
38293
38824
|
};
|
|
38294
38825
|
|
|
38295
38826
|
// src/worktrees/manager/default-worktrees-root-path.ts
|
|
38296
|
-
import * as
|
|
38827
|
+
import * as path37 from "node:path";
|
|
38297
38828
|
import os8 from "node:os";
|
|
38298
38829
|
function defaultWorktreesRootPath() {
|
|
38299
|
-
return
|
|
38830
|
+
return path37.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
38300
38831
|
}
|
|
38301
38832
|
|
|
38302
38833
|
// src/files/watch-file-index.ts
|
|
38303
38834
|
import { watch } from "node:fs";
|
|
38304
|
-
import
|
|
38835
|
+
import path42 from "node:path";
|
|
38305
38836
|
|
|
38306
38837
|
// src/files/index/paths.ts
|
|
38307
|
-
import
|
|
38838
|
+
import path38 from "node:path";
|
|
38308
38839
|
import crypto2 from "node:crypto";
|
|
38309
38840
|
function getCwdHashForFileIndex(resolvedCwd) {
|
|
38310
|
-
return crypto2.createHash("sha256").update(
|
|
38841
|
+
return crypto2.createHash("sha256").update(path38.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
38311
38842
|
}
|
|
38312
38843
|
|
|
38313
38844
|
// src/files/index/build-file-index.ts
|
|
38314
|
-
import
|
|
38845
|
+
import path40 from "node:path";
|
|
38315
38846
|
|
|
38316
38847
|
// src/files/index/walk-workspace-tree.ts
|
|
38317
|
-
import
|
|
38318
|
-
import
|
|
38848
|
+
import fs30 from "node:fs";
|
|
38849
|
+
import path39 from "node:path";
|
|
38319
38850
|
var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
38320
38851
|
"node_modules",
|
|
38321
38852
|
"bower_components",
|
|
@@ -38332,7 +38863,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
|
|
|
38332
38863
|
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
38333
38864
|
let names;
|
|
38334
38865
|
try {
|
|
38335
|
-
names = await
|
|
38866
|
+
names = await fs30.promises.readdir(dir);
|
|
38336
38867
|
} catch {
|
|
38337
38868
|
return;
|
|
38338
38869
|
}
|
|
@@ -38344,14 +38875,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
|
38344
38875
|
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
38345
38876
|
}
|
|
38346
38877
|
state.n++;
|
|
38347
|
-
const full =
|
|
38878
|
+
const full = path39.join(dir, name);
|
|
38348
38879
|
let stat3;
|
|
38349
38880
|
try {
|
|
38350
|
-
stat3 = await
|
|
38881
|
+
stat3 = await fs30.promises.stat(full);
|
|
38351
38882
|
} catch {
|
|
38352
38883
|
continue;
|
|
38353
38884
|
}
|
|
38354
|
-
const relative6 =
|
|
38885
|
+
const relative6 = path39.relative(baseDir, full).replace(/\\/g, "/");
|
|
38355
38886
|
if (stat3.isDirectory()) {
|
|
38356
38887
|
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
38357
38888
|
} else if (stat3.isFile()) {
|
|
@@ -38364,7 +38895,7 @@ function createWalkYieldState() {
|
|
|
38364
38895
|
}
|
|
38365
38896
|
|
|
38366
38897
|
// src/files/index/file-index-sqlite-lock.ts
|
|
38367
|
-
import
|
|
38898
|
+
import fs31 from "node:fs";
|
|
38368
38899
|
function isSqliteCorruptError(e) {
|
|
38369
38900
|
const msg = e instanceof Error ? e.message : String(e);
|
|
38370
38901
|
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
@@ -38378,7 +38909,7 @@ function withFileIndexSqliteLock(fn) {
|
|
|
38378
38909
|
if (!isSqliteCorruptError(e)) throw e;
|
|
38379
38910
|
closeAllCliSqliteConnections();
|
|
38380
38911
|
try {
|
|
38381
|
-
|
|
38912
|
+
fs31.unlinkSync(getCliSqlitePath());
|
|
38382
38913
|
} catch {
|
|
38383
38914
|
}
|
|
38384
38915
|
chain = Promise.resolve();
|
|
@@ -38453,7 +38984,7 @@ async function collectWorkspacePathsAsync(resolved) {
|
|
|
38453
38984
|
}
|
|
38454
38985
|
async function buildFileIndexAsync(cwd) {
|
|
38455
38986
|
return withFileIndexSqliteLock(async () => {
|
|
38456
|
-
const resolved =
|
|
38987
|
+
const resolved = path40.resolve(cwd);
|
|
38457
38988
|
await yieldToEventLoop();
|
|
38458
38989
|
assertNotShutdown();
|
|
38459
38990
|
const paths = await collectWorkspacePathsAsync(resolved);
|
|
@@ -38465,7 +38996,7 @@ async function buildFileIndexAsync(cwd) {
|
|
|
38465
38996
|
}
|
|
38466
38997
|
|
|
38467
38998
|
// src/files/index/ensure-file-index.ts
|
|
38468
|
-
import
|
|
38999
|
+
import path41 from "node:path";
|
|
38469
39000
|
|
|
38470
39001
|
// src/files/index/search-file-index.ts
|
|
38471
39002
|
function escapeLikePattern(fragment) {
|
|
@@ -38517,7 +39048,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
|
38517
39048
|
|
|
38518
39049
|
// src/files/index/ensure-file-index.ts
|
|
38519
39050
|
async function ensureFileIndexAsync(cwd) {
|
|
38520
|
-
const resolved =
|
|
39051
|
+
const resolved = path41.resolve(cwd);
|
|
38521
39052
|
if (await bridgeFileIndexIsPopulated(resolved)) {
|
|
38522
39053
|
return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
|
|
38523
39054
|
}
|
|
@@ -38561,7 +39092,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
38561
39092
|
}
|
|
38562
39093
|
}
|
|
38563
39094
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
38564
|
-
const resolved =
|
|
39095
|
+
const resolved = path42.resolve(cwd);
|
|
38565
39096
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
38566
39097
|
if (e instanceof CliSqliteInterrupted) return;
|
|
38567
39098
|
console.error("[file-index] Initial index build failed:", e);
|
|
@@ -38591,7 +39122,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
38591
39122
|
}
|
|
38592
39123
|
|
|
38593
39124
|
// src/connection/create-bridge-connection.ts
|
|
38594
|
-
import * as
|
|
39125
|
+
import * as path53 from "node:path";
|
|
38595
39126
|
|
|
38596
39127
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
38597
39128
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -38613,15 +39144,15 @@ function sendDevServerStatus(getWs, serverId, status, options) {
|
|
|
38613
39144
|
|
|
38614
39145
|
// src/dev-servers/process/terminate-child-process.ts
|
|
38615
39146
|
async function sigtermAndWaitForExit(proc, graceMs, log2, shortId) {
|
|
38616
|
-
const exited = new Promise((
|
|
38617
|
-
proc.once("exit", () =>
|
|
39147
|
+
const exited = new Promise((resolve28) => {
|
|
39148
|
+
proc.once("exit", () => resolve28());
|
|
38618
39149
|
});
|
|
38619
39150
|
log2(`[dev-server] Sending SIGTERM to ${shortId} (pid=${proc.pid ?? "?"}).`);
|
|
38620
39151
|
try {
|
|
38621
39152
|
proc.kill("SIGTERM");
|
|
38622
39153
|
} catch {
|
|
38623
39154
|
}
|
|
38624
|
-
await Promise.race([exited, new Promise((
|
|
39155
|
+
await Promise.race([exited, new Promise((resolve28) => setTimeout(resolve28, graceMs))]);
|
|
38625
39156
|
}
|
|
38626
39157
|
function forceKillChild(proc, log2, shortId, graceMs) {
|
|
38627
39158
|
log2(
|
|
@@ -38635,7 +39166,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
38635
39166
|
}
|
|
38636
39167
|
|
|
38637
39168
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
38638
|
-
import
|
|
39169
|
+
import fs32 from "node:fs";
|
|
38639
39170
|
|
|
38640
39171
|
// src/dev-servers/manager/forward-pipe.ts
|
|
38641
39172
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -38671,7 +39202,7 @@ function wireDevServerChildProcess(d) {
|
|
|
38671
39202
|
d.setPollInterval(void 0);
|
|
38672
39203
|
return;
|
|
38673
39204
|
}
|
|
38674
|
-
|
|
39205
|
+
fs32.readFile(d.mergedLogPath, (err, buf) => {
|
|
38675
39206
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
38676
39207
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
38677
39208
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -38709,7 +39240,7 @@ ${errTail}` : ""}`);
|
|
|
38709
39240
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
38710
39241
|
};
|
|
38711
39242
|
if (mergedPath) {
|
|
38712
|
-
|
|
39243
|
+
fs32.readFile(mergedPath, (err, buf) => {
|
|
38713
39244
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
38714
39245
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
38715
39246
|
if (chunk.length > 0) {
|
|
@@ -38811,13 +39342,13 @@ function parseDevServerDefs(servers) {
|
|
|
38811
39342
|
}
|
|
38812
39343
|
|
|
38813
39344
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
38814
|
-
import
|
|
39345
|
+
import fs33 from "node:fs";
|
|
38815
39346
|
function isSpawnEbadf(e) {
|
|
38816
39347
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
38817
39348
|
}
|
|
38818
39349
|
function rmDirQuiet(dir) {
|
|
38819
39350
|
try {
|
|
38820
|
-
|
|
39351
|
+
fs33.rmSync(dir, { recursive: true, force: true });
|
|
38821
39352
|
} catch {
|
|
38822
39353
|
}
|
|
38823
39354
|
}
|
|
@@ -38825,7 +39356,7 @@ var cachedDevNullReadFd;
|
|
|
38825
39356
|
function devNullReadFd() {
|
|
38826
39357
|
if (cachedDevNullReadFd === void 0) {
|
|
38827
39358
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
38828
|
-
cachedDevNullReadFd =
|
|
39359
|
+
cachedDevNullReadFd = fs33.openSync(devPath, "r");
|
|
38829
39360
|
}
|
|
38830
39361
|
return cachedDevNullReadFd;
|
|
38831
39362
|
}
|
|
@@ -38899,15 +39430,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
38899
39430
|
|
|
38900
39431
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
38901
39432
|
import { spawn as spawn7 } from "node:child_process";
|
|
38902
|
-
import
|
|
39433
|
+
import fs34 from "node:fs";
|
|
38903
39434
|
import { tmpdir } from "node:os";
|
|
38904
|
-
import
|
|
39435
|
+
import path43 from "node:path";
|
|
38905
39436
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
38906
|
-
const tmpRoot =
|
|
38907
|
-
const logPath =
|
|
39437
|
+
const tmpRoot = fs34.mkdtempSync(path43.join(tmpdir(), "ba-devsrv-log-"));
|
|
39438
|
+
const logPath = path43.join(tmpRoot, "combined.log");
|
|
38908
39439
|
let logFd;
|
|
38909
39440
|
try {
|
|
38910
|
-
logFd =
|
|
39441
|
+
logFd = fs34.openSync(logPath, "a");
|
|
38911
39442
|
} catch {
|
|
38912
39443
|
rmDirQuiet(tmpRoot);
|
|
38913
39444
|
return null;
|
|
@@ -38926,7 +39457,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
38926
39457
|
} else {
|
|
38927
39458
|
proc = spawn7("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
38928
39459
|
}
|
|
38929
|
-
|
|
39460
|
+
fs34.closeSync(logFd);
|
|
38930
39461
|
return {
|
|
38931
39462
|
proc,
|
|
38932
39463
|
pipedStdoutStderr: true,
|
|
@@ -38935,7 +39466,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
38935
39466
|
};
|
|
38936
39467
|
} catch (e) {
|
|
38937
39468
|
try {
|
|
38938
|
-
|
|
39469
|
+
fs34.closeSync(logFd);
|
|
38939
39470
|
} catch {
|
|
38940
39471
|
}
|
|
38941
39472
|
rmDirQuiet(tmpRoot);
|
|
@@ -38946,22 +39477,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
38946
39477
|
|
|
38947
39478
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
38948
39479
|
import { spawn as spawn8 } from "node:child_process";
|
|
38949
|
-
import
|
|
39480
|
+
import fs35 from "node:fs";
|
|
38950
39481
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
38951
|
-
import
|
|
39482
|
+
import path44 from "node:path";
|
|
38952
39483
|
function shSingleQuote(s) {
|
|
38953
39484
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
38954
39485
|
}
|
|
38955
39486
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
38956
|
-
const tmpRoot =
|
|
38957
|
-
const logPath =
|
|
38958
|
-
const innerPath =
|
|
38959
|
-
const runnerPath =
|
|
39487
|
+
const tmpRoot = fs35.mkdtempSync(path44.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
39488
|
+
const logPath = path44.join(tmpRoot, "combined.log");
|
|
39489
|
+
const innerPath = path44.join(tmpRoot, "_cmd.sh");
|
|
39490
|
+
const runnerPath = path44.join(tmpRoot, "_run.sh");
|
|
38960
39491
|
try {
|
|
38961
|
-
|
|
39492
|
+
fs35.writeFileSync(innerPath, `#!/bin/sh
|
|
38962
39493
|
${command}
|
|
38963
39494
|
`);
|
|
38964
|
-
|
|
39495
|
+
fs35.writeFileSync(
|
|
38965
39496
|
runnerPath,
|
|
38966
39497
|
`#!/bin/sh
|
|
38967
39498
|
cd ${shSingleQuote(cwd)}
|
|
@@ -38987,13 +39518,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
38987
39518
|
}
|
|
38988
39519
|
}
|
|
38989
39520
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
38990
|
-
const tmpRoot =
|
|
38991
|
-
const logPath =
|
|
38992
|
-
const runnerPath =
|
|
39521
|
+
const tmpRoot = fs35.mkdtempSync(path44.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
39522
|
+
const logPath = path44.join(tmpRoot, "combined.log");
|
|
39523
|
+
const runnerPath = path44.join(tmpRoot, "_run.bat");
|
|
38993
39524
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
38994
39525
|
const com = process.env.ComSpec || "cmd.exe";
|
|
38995
39526
|
try {
|
|
38996
|
-
|
|
39527
|
+
fs35.writeFileSync(
|
|
38997
39528
|
runnerPath,
|
|
38998
39529
|
`@ECHO OFF\r
|
|
38999
39530
|
CD /D ${q(cwd)}\r
|
|
@@ -39502,7 +40033,7 @@ async function proxyToLocal(request) {
|
|
|
39502
40033
|
};
|
|
39503
40034
|
const maxAttempts = isIdempotentProxyMethod(request.method) ? LOCAL_PREVIEW_FETCH_RETRY_DELAYS_MS.length + 1 : 1;
|
|
39504
40035
|
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
39505
|
-
const once = await new Promise((
|
|
40036
|
+
const once = await new Promise((resolve28) => {
|
|
39506
40037
|
const req = mod.request(opts, (res) => {
|
|
39507
40038
|
const chunks = [];
|
|
39508
40039
|
res.on("data", (c) => chunks.push(c));
|
|
@@ -39513,7 +40044,7 @@ async function proxyToLocal(request) {
|
|
|
39513
40044
|
if (typeof v === "string") headers[k] = v;
|
|
39514
40045
|
else if (Array.isArray(v) && v[0]) headers[k] = v[0];
|
|
39515
40046
|
}
|
|
39516
|
-
|
|
40047
|
+
resolve28({
|
|
39517
40048
|
id: request.id,
|
|
39518
40049
|
statusCode: res.statusCode ?? 0,
|
|
39519
40050
|
headers,
|
|
@@ -39522,7 +40053,7 @@ async function proxyToLocal(request) {
|
|
|
39522
40053
|
});
|
|
39523
40054
|
});
|
|
39524
40055
|
req.on("error", (err) => {
|
|
39525
|
-
|
|
40056
|
+
resolve28({
|
|
39526
40057
|
id: request.id,
|
|
39527
40058
|
statusCode: 0,
|
|
39528
40059
|
headers: {},
|
|
@@ -39930,30 +40461,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
39930
40461
|
}
|
|
39931
40462
|
|
|
39932
40463
|
// src/skills/discover-local-agent-skills.ts
|
|
39933
|
-
import
|
|
39934
|
-
import
|
|
40464
|
+
import fs36 from "node:fs";
|
|
40465
|
+
import path45 from "node:path";
|
|
39935
40466
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
39936
40467
|
function discoverLocalSkills(cwd) {
|
|
39937
40468
|
const out = [];
|
|
39938
40469
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
39939
40470
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
39940
|
-
const base =
|
|
39941
|
-
if (!
|
|
40471
|
+
const base = path45.join(cwd, rel);
|
|
40472
|
+
if (!fs36.existsSync(base) || !fs36.statSync(base).isDirectory()) continue;
|
|
39942
40473
|
let entries = [];
|
|
39943
40474
|
try {
|
|
39944
|
-
entries =
|
|
40475
|
+
entries = fs36.readdirSync(base);
|
|
39945
40476
|
} catch {
|
|
39946
40477
|
continue;
|
|
39947
40478
|
}
|
|
39948
40479
|
for (const name of entries) {
|
|
39949
|
-
const dir =
|
|
40480
|
+
const dir = path45.join(base, name);
|
|
39950
40481
|
try {
|
|
39951
|
-
if (!
|
|
40482
|
+
if (!fs36.statSync(dir).isDirectory()) continue;
|
|
39952
40483
|
} catch {
|
|
39953
40484
|
continue;
|
|
39954
40485
|
}
|
|
39955
|
-
const skillMd =
|
|
39956
|
-
if (!
|
|
40486
|
+
const skillMd = path45.join(dir, "SKILL.md");
|
|
40487
|
+
if (!fs36.existsSync(skillMd)) continue;
|
|
39957
40488
|
const key = `${rel}/${name}`;
|
|
39958
40489
|
if (seenKeys.has(key)) continue;
|
|
39959
40490
|
seenKeys.add(key);
|
|
@@ -39965,23 +40496,23 @@ function discoverLocalSkills(cwd) {
|
|
|
39965
40496
|
function discoverSkillLayoutRoots(cwd) {
|
|
39966
40497
|
const roots = [];
|
|
39967
40498
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
39968
|
-
const base =
|
|
39969
|
-
if (!
|
|
40499
|
+
const base = path45.join(cwd, rel);
|
|
40500
|
+
if (!fs36.existsSync(base) || !fs36.statSync(base).isDirectory()) continue;
|
|
39970
40501
|
let entries = [];
|
|
39971
40502
|
try {
|
|
39972
|
-
entries =
|
|
40503
|
+
entries = fs36.readdirSync(base);
|
|
39973
40504
|
} catch {
|
|
39974
40505
|
continue;
|
|
39975
40506
|
}
|
|
39976
40507
|
const skills2 = [];
|
|
39977
40508
|
for (const name of entries) {
|
|
39978
|
-
const dir =
|
|
40509
|
+
const dir = path45.join(base, name);
|
|
39979
40510
|
try {
|
|
39980
|
-
if (!
|
|
40511
|
+
if (!fs36.statSync(dir).isDirectory()) continue;
|
|
39981
40512
|
} catch {
|
|
39982
40513
|
continue;
|
|
39983
40514
|
}
|
|
39984
|
-
if (!
|
|
40515
|
+
if (!fs36.existsSync(path45.join(dir, "SKILL.md"))) continue;
|
|
39985
40516
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
39986
40517
|
skills2.push({ name, relPath });
|
|
39987
40518
|
}
|
|
@@ -40337,7 +40868,7 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
|
|
|
40337
40868
|
}
|
|
40338
40869
|
|
|
40339
40870
|
// src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
|
|
40340
|
-
import
|
|
40871
|
+
import fs37 from "node:fs";
|
|
40341
40872
|
async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
40342
40873
|
if (next.serverState !== "requeued_with_revert") return true;
|
|
40343
40874
|
const sid = next.sessionId;
|
|
@@ -40346,7 +40877,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
40346
40877
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
40347
40878
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
40348
40879
|
try {
|
|
40349
|
-
await
|
|
40880
|
+
await fs37.promises.access(file2, fs37.constants.F_OK);
|
|
40350
40881
|
} catch {
|
|
40351
40882
|
deps.log(
|
|
40352
40883
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
@@ -40461,7 +40992,7 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
40461
40992
|
sendWsMessage(s, wire);
|
|
40462
40993
|
return true;
|
|
40463
40994
|
};
|
|
40464
|
-
const
|
|
40995
|
+
const sendResult = (result) => {
|
|
40465
40996
|
const skipEncryptForChangeSummaryFollowUp = result.type === "prompt_result" && result.followUpCatalogPromptId === BUILTIN_SESSION_CHANGE_SUMMARY_FOLLOW_UP_CATALOG_PROMPT_ID;
|
|
40466
40997
|
const encryptedFields = result.type === "prompt_result" && !skipEncryptForChangeSummaryFollowUp ? ["output", "error"] : [];
|
|
40467
40998
|
sendBridgeMessage(result, encryptedFields);
|
|
@@ -40494,7 +41025,7 @@ function createBridgePromptSenders(deps, getWs) {
|
|
|
40494
41025
|
]) : payload;
|
|
40495
41026
|
sendWsMessage(s, wire);
|
|
40496
41027
|
};
|
|
40497
|
-
return { sendBridgeMessage, sendResult
|
|
41028
|
+
return { sendBridgeMessage, sendResult, sendSessionUpdate };
|
|
40498
41029
|
}
|
|
40499
41030
|
|
|
40500
41031
|
// src/agents/acp/from-bridge/handle-bridge-prompt/parse-bridge-attachments.ts
|
|
@@ -40598,7 +41129,7 @@ async function readGitBranch(cwd) {
|
|
|
40598
41129
|
async function runBridgePromptPreamble(params) {
|
|
40599
41130
|
const { getWs, log: log2, sessionWorktreeManager, sessionId, runId, effectiveCwd } = params;
|
|
40600
41131
|
const s = getWs();
|
|
40601
|
-
const repoCheckoutPaths = sessionWorktreeManager.
|
|
41132
|
+
const repoCheckoutPaths = await sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sessionId);
|
|
40602
41133
|
const repoRoots = await resolveSnapshotRepoRoots({
|
|
40603
41134
|
worktreePaths: repoCheckoutPaths,
|
|
40604
41135
|
fallbackCwd: effectiveCwd,
|
|
@@ -40634,9 +41165,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
40634
41165
|
for (const item of raw) {
|
|
40635
41166
|
if (!item || typeof item !== "object") continue;
|
|
40636
41167
|
const o = item;
|
|
40637
|
-
const
|
|
40638
|
-
if (!
|
|
40639
|
-
const row = { path:
|
|
41168
|
+
const path55 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
41169
|
+
if (!path55) continue;
|
|
41170
|
+
const row = { path: path55 };
|
|
40640
41171
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
40641
41172
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
40642
41173
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -40670,7 +41201,7 @@ async function runPreambleAndPrompt(params) {
|
|
|
40670
41201
|
agentId,
|
|
40671
41202
|
agentConfig,
|
|
40672
41203
|
resolvedCwd,
|
|
40673
|
-
senders: { sendResult
|
|
41204
|
+
senders: { sendResult, sendSessionUpdate }
|
|
40674
41205
|
} = params;
|
|
40675
41206
|
const effectiveCwd = resolveSessionParentPathForAgentProcess(resolvedCwd);
|
|
40676
41207
|
await runBridgePromptPreamble({
|
|
@@ -40708,7 +41239,7 @@ async function runPreambleAndPrompt(params) {
|
|
|
40708
41239
|
agentId,
|
|
40709
41240
|
agentConfig,
|
|
40710
41241
|
sessionParentPath: effectiveCwd,
|
|
40711
|
-
sendResult
|
|
41242
|
+
sendResult,
|
|
40712
41243
|
sendSessionUpdate,
|
|
40713
41244
|
followUpCatalogPromptId,
|
|
40714
41245
|
sessionChangeSummaryFilePaths: pathsForUpload,
|
|
@@ -40846,8 +41377,8 @@ function randomSecret() {
|
|
|
40846
41377
|
}
|
|
40847
41378
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
40848
41379
|
}
|
|
40849
|
-
async function requestPreviewApi(port, secret, method,
|
|
40850
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
41380
|
+
async function requestPreviewApi(port, secret, method, path55, body) {
|
|
41381
|
+
const url2 = `http://127.0.0.1:${port}${path55}`;
|
|
40851
41382
|
const headers = {
|
|
40852
41383
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
40853
41384
|
"Content-Type": "application/json"
|
|
@@ -40859,7 +41390,7 @@ async function requestPreviewApi(port, secret, method, path48, body) {
|
|
|
40859
41390
|
});
|
|
40860
41391
|
const data = await res.json().catch(() => ({}));
|
|
40861
41392
|
if (!res.ok) {
|
|
40862
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
41393
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path55}: ${res.status}`);
|
|
40863
41394
|
}
|
|
40864
41395
|
return data;
|
|
40865
41396
|
}
|
|
@@ -41024,14 +41555,14 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
41024
41555
|
};
|
|
41025
41556
|
|
|
41026
41557
|
// src/files/list-dir/index.ts
|
|
41027
|
-
import
|
|
41558
|
+
import fs39 from "node:fs";
|
|
41028
41559
|
|
|
41029
41560
|
// src/files/ensure-under-cwd.ts
|
|
41030
|
-
import
|
|
41561
|
+
import path46 from "node:path";
|
|
41031
41562
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
41032
|
-
const normalized =
|
|
41033
|
-
const resolved =
|
|
41034
|
-
if (!resolved.startsWith(cwd +
|
|
41563
|
+
const normalized = path46.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
41564
|
+
const resolved = path46.resolve(cwd, normalized);
|
|
41565
|
+
if (!resolved.startsWith(cwd + path46.sep) && resolved !== cwd) {
|
|
41035
41566
|
return null;
|
|
41036
41567
|
}
|
|
41037
41568
|
return resolved;
|
|
@@ -41041,15 +41572,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
|
41041
41572
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
41042
41573
|
|
|
41043
41574
|
// src/files/list-dir/map-dir-entry.ts
|
|
41044
|
-
import
|
|
41045
|
-
import
|
|
41575
|
+
import path47 from "node:path";
|
|
41576
|
+
import fs38 from "node:fs";
|
|
41046
41577
|
async function mapDirEntry(d, relativePath, resolved) {
|
|
41047
|
-
const entryPath =
|
|
41048
|
-
const fullPath =
|
|
41578
|
+
const entryPath = path47.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
41579
|
+
const fullPath = path47.join(resolved, d.name);
|
|
41049
41580
|
let isDir = d.isDirectory();
|
|
41050
41581
|
if (d.isSymbolicLink()) {
|
|
41051
41582
|
try {
|
|
41052
|
-
const targetStat = await
|
|
41583
|
+
const targetStat = await fs38.promises.stat(fullPath);
|
|
41053
41584
|
isDir = targetStat.isDirectory();
|
|
41054
41585
|
} catch {
|
|
41055
41586
|
isDir = false;
|
|
@@ -41079,7 +41610,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
|
41079
41610
|
return { error: "Path is outside working directory" };
|
|
41080
41611
|
}
|
|
41081
41612
|
try {
|
|
41082
|
-
const names = await
|
|
41613
|
+
const names = await fs39.promises.readdir(resolved, { withFileTypes: true });
|
|
41083
41614
|
const entries = [];
|
|
41084
41615
|
for (let i = 0; i < names.length; i++) {
|
|
41085
41616
|
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
@@ -41099,18 +41630,18 @@ var LINE_CHUNK_SIZE = 64 * 1024;
|
|
|
41099
41630
|
var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
|
|
41100
41631
|
|
|
41101
41632
|
// src/files/read-file/resolve-file-path.ts
|
|
41102
|
-
import
|
|
41633
|
+
import fs40 from "node:fs";
|
|
41103
41634
|
async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
41104
41635
|
const resolved = ensureUnderCwd(relativePath, sessionParentPath);
|
|
41105
41636
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
41106
41637
|
let real;
|
|
41107
41638
|
try {
|
|
41108
|
-
real = await
|
|
41639
|
+
real = await fs40.promises.realpath(resolved);
|
|
41109
41640
|
} catch {
|
|
41110
41641
|
real = resolved;
|
|
41111
41642
|
}
|
|
41112
41643
|
try {
|
|
41113
|
-
const stat3 = await
|
|
41644
|
+
const stat3 = await fs40.promises.stat(real);
|
|
41114
41645
|
if (!stat3.isFile()) return { error: "Not a file" };
|
|
41115
41646
|
return real;
|
|
41116
41647
|
} catch (err) {
|
|
@@ -41119,11 +41650,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
|
|
|
41119
41650
|
}
|
|
41120
41651
|
|
|
41121
41652
|
// src/files/read-file/read-file-range-async.ts
|
|
41122
|
-
import
|
|
41653
|
+
import fs41 from "node:fs";
|
|
41123
41654
|
import { StringDecoder } from "node:string_decoder";
|
|
41124
41655
|
async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
41125
|
-
const fileSize = (await
|
|
41126
|
-
const fd = await
|
|
41656
|
+
const fileSize = (await fs41.promises.stat(filePath)).size;
|
|
41657
|
+
const fd = await fs41.promises.open(filePath, "r");
|
|
41127
41658
|
const bufSize = 64 * 1024;
|
|
41128
41659
|
const buf = Buffer.alloc(bufSize);
|
|
41129
41660
|
const decoder = new StringDecoder("utf8");
|
|
@@ -41285,11 +41816,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
|
|
|
41285
41816
|
}
|
|
41286
41817
|
|
|
41287
41818
|
// src/files/read-file/read-file-buffer-full-async.ts
|
|
41288
|
-
import
|
|
41819
|
+
import fs42 from "node:fs";
|
|
41289
41820
|
var READ_CHUNK_BYTES = 256 * 1024;
|
|
41290
41821
|
async function readFileBufferFullAsync(filePath) {
|
|
41291
|
-
const stat3 = await
|
|
41292
|
-
const fd = await
|
|
41822
|
+
const stat3 = await fs42.promises.stat(filePath);
|
|
41823
|
+
const fd = await fs42.promises.open(filePath, "r");
|
|
41293
41824
|
const chunks = [];
|
|
41294
41825
|
let position = 0;
|
|
41295
41826
|
let bytesSinceYield = 0;
|
|
@@ -41385,10 +41916,10 @@ async function readFileAsync(relativePath, startLine, endLine, lineOffset, lineC
|
|
|
41385
41916
|
}
|
|
41386
41917
|
|
|
41387
41918
|
// src/files/resolve-file-browser-session-parent.ts
|
|
41388
|
-
function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
41919
|
+
async function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
41389
41920
|
const sid = sessionId?.trim();
|
|
41390
41921
|
if (sid) {
|
|
41391
|
-
sessionWorktreeManager.
|
|
41922
|
+
await sessionWorktreeManager.ensureRepoCheckoutPathsForSessionAsync(sid);
|
|
41392
41923
|
const worktreeRoot = sessionWorktreeManager.getSessionWorktreeRootForSession(sid);
|
|
41393
41924
|
if (worktreeRoot) return worktreeRoot;
|
|
41394
41925
|
}
|
|
@@ -41396,14 +41927,14 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
|
41396
41927
|
}
|
|
41397
41928
|
|
|
41398
41929
|
// src/files/handle-file-browser-search.ts
|
|
41399
|
-
import
|
|
41930
|
+
import path48 from "node:path";
|
|
41400
41931
|
var SEARCH_LIMIT = 100;
|
|
41401
41932
|
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
41402
41933
|
void (async () => {
|
|
41403
41934
|
await yieldToEventLoop();
|
|
41404
41935
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
41405
|
-
const sessionParentPath =
|
|
41406
|
-
sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
41936
|
+
const sessionParentPath = path48.resolve(
|
|
41937
|
+
sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
41407
41938
|
);
|
|
41408
41939
|
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
41409
41940
|
const payload2 = {
|
|
@@ -41441,7 +41972,7 @@ function handleFileBrowserRequest(msg, socket, e2ee, sessionWorktreeManager) {
|
|
|
41441
41972
|
void (async () => {
|
|
41442
41973
|
const reqPath = msg.path.replace(/^\/+/, "") || ".";
|
|
41443
41974
|
const op = msg.op === "read" ? "read" : "list";
|
|
41444
|
-
const sessionParentPath = sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
41975
|
+
const sessionParentPath = sessionWorktreeManager != null ? await resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : void 0;
|
|
41445
41976
|
if (op === "list") {
|
|
41446
41977
|
const result = await listDirAsync(reqPath, sessionParentPath);
|
|
41447
41978
|
if ("error" in result) {
|
|
@@ -41521,8 +42052,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
41521
42052
|
}
|
|
41522
42053
|
|
|
41523
42054
|
// src/skills/install-remote-skills.ts
|
|
41524
|
-
import
|
|
41525
|
-
import
|
|
42055
|
+
import fs43 from "node:fs";
|
|
42056
|
+
import path49 from "node:path";
|
|
41526
42057
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
41527
42058
|
const installed2 = [];
|
|
41528
42059
|
if (!Array.isArray(items)) {
|
|
@@ -41533,15 +42064,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
41533
42064
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
41534
42065
|
continue;
|
|
41535
42066
|
}
|
|
41536
|
-
const skillDir =
|
|
42067
|
+
const skillDir = path49.join(cwd, targetDir, item.skillName);
|
|
41537
42068
|
for (const f of item.files) {
|
|
41538
42069
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
41539
|
-
const dest =
|
|
41540
|
-
|
|
42070
|
+
const dest = path49.join(skillDir, f.path);
|
|
42071
|
+
fs43.mkdirSync(path49.dirname(dest), { recursive: true });
|
|
41541
42072
|
if (f.text !== void 0) {
|
|
41542
|
-
|
|
42073
|
+
fs43.writeFileSync(dest, f.text, "utf8");
|
|
41543
42074
|
} else if (f.base64) {
|
|
41544
|
-
|
|
42075
|
+
fs43.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
41545
42076
|
}
|
|
41546
42077
|
}
|
|
41547
42078
|
installed2.push({
|
|
@@ -41582,12 +42113,116 @@ var handleRefreshLocalSkills = (_msg, deps) => {
|
|
|
41582
42113
|
deps.sendLocalSkillsReport?.();
|
|
41583
42114
|
};
|
|
41584
42115
|
|
|
41585
|
-
// src/routing/handlers/session-git-
|
|
41586
|
-
function
|
|
42116
|
+
// src/routing/handlers/git/handle-session-git-commit.ts
|
|
42117
|
+
async function handleSessionGitCommitAction(deps, sessionId, msg, reply) {
|
|
42118
|
+
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
42119
|
+
const message = typeof msg.message === "string" ? msg.message : "";
|
|
42120
|
+
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
42121
|
+
if (!branch.trim() || !message.trim()) {
|
|
42122
|
+
reply({ ok: false, error: "branch and message are required for commit" });
|
|
42123
|
+
return;
|
|
42124
|
+
}
|
|
42125
|
+
const commitRes = await deps.sessionWorktreeManager.commitSession({
|
|
42126
|
+
sessionId,
|
|
42127
|
+
branch: branch.trim(),
|
|
42128
|
+
message: message.trim(),
|
|
42129
|
+
push: pushAfterCommit
|
|
42130
|
+
});
|
|
42131
|
+
if (!commitRes.ok) {
|
|
42132
|
+
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
42133
|
+
return;
|
|
42134
|
+
}
|
|
42135
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
42136
|
+
reply({
|
|
42137
|
+
ok: true,
|
|
42138
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
42139
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
42140
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
42141
|
+
});
|
|
42142
|
+
}
|
|
42143
|
+
|
|
42144
|
+
// src/routing/handlers/git/coalesce-list-changes.ts
|
|
42145
|
+
var listChangesInflight = /* @__PURE__ */ new Map();
|
|
42146
|
+
function listChangesInflightKey(sessionId, opts) {
|
|
42147
|
+
const basis = opts?.basis;
|
|
42148
|
+
return [
|
|
42149
|
+
sessionId,
|
|
42150
|
+
opts?.repoRelPath ?? "",
|
|
42151
|
+
basis?.kind === "commit" ? `commit:${basis.sha}` : "working",
|
|
42152
|
+
String(opts?.recentCommitsLimit ?? "")
|
|
42153
|
+
].join("|");
|
|
42154
|
+
}
|
|
42155
|
+
function getSessionWorkingTreeChangeDetailsCoalesced(sessionWorktreeManager, sessionId, opts) {
|
|
42156
|
+
const key = listChangesInflightKey(sessionId, opts);
|
|
42157
|
+
const existing = listChangesInflight.get(key);
|
|
42158
|
+
if (existing) return existing;
|
|
42159
|
+
const promise2 = sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts).finally(() => {
|
|
42160
|
+
if (listChangesInflight.get(key) === promise2) listChangesInflight.delete(key);
|
|
42161
|
+
});
|
|
42162
|
+
listChangesInflight.set(key, promise2);
|
|
42163
|
+
return promise2;
|
|
42164
|
+
}
|
|
42165
|
+
|
|
42166
|
+
// src/routing/handlers/git/handle-session-git-list-changes.ts
|
|
42167
|
+
async function handleSessionGitListChangesAction(deps, msg, reply) {
|
|
42168
|
+
const repoRel = typeof msg.changesRepoRelPath === "string" ? msg.changesRepoRelPath.trim() : "";
|
|
42169
|
+
const view = msg.changesView === "commit" ? "commit" : "working";
|
|
42170
|
+
const commitSha = typeof msg.changesCommitSha === "string" ? msg.changesCommitSha.trim() : "";
|
|
42171
|
+
if (view === "commit") {
|
|
42172
|
+
if (!repoRel || !commitSha) {
|
|
42173
|
+
reply({ ok: false, error: "changesRepoRelPath and changesCommitSha are required for commit view" });
|
|
42174
|
+
return;
|
|
42175
|
+
}
|
|
42176
|
+
}
|
|
42177
|
+
const recentCommitsLimit = typeof msg.changesRecentCommitsLimit === "number" || typeof msg.changesRecentCommitsLimit === "string" ? msg.changesRecentCommitsLimit : void 0;
|
|
42178
|
+
const opts = repoRel && view === "commit" && commitSha ? {
|
|
42179
|
+
repoRelPath: repoRel,
|
|
42180
|
+
basis: { kind: "commit", sha: commitSha },
|
|
42181
|
+
recentCommitsLimit
|
|
42182
|
+
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
42183
|
+
const repos = await getSessionWorkingTreeChangeDetailsCoalesced(
|
|
42184
|
+
deps.sessionWorktreeManager,
|
|
42185
|
+
msg.sessionId,
|
|
42186
|
+
opts
|
|
42187
|
+
);
|
|
42188
|
+
reply({ ok: true, repos }, ["repos"]);
|
|
42189
|
+
}
|
|
42190
|
+
|
|
42191
|
+
// src/routing/handlers/git/handle-session-git-push.ts
|
|
42192
|
+
async function handleSessionGitPushAction(deps, sessionId, reply) {
|
|
42193
|
+
const pushRes = await deps.sessionWorktreeManager.pushSessionUpstream(sessionId);
|
|
42194
|
+
if (!pushRes.ok) {
|
|
42195
|
+
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
42196
|
+
return;
|
|
42197
|
+
}
|
|
42198
|
+
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
42199
|
+
reply({
|
|
42200
|
+
ok: true,
|
|
42201
|
+
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
42202
|
+
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
42203
|
+
uncommittedFileCount: st.uncommittedFileCount
|
|
42204
|
+
});
|
|
42205
|
+
}
|
|
42206
|
+
|
|
42207
|
+
// src/routing/handlers/git/handle-session-git-status.ts
|
|
42208
|
+
async function handleSessionGitStatusAction(deps, sessionId, reply) {
|
|
42209
|
+
const r = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
42210
|
+
reply({
|
|
42211
|
+
ok: true,
|
|
42212
|
+
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
42213
|
+
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
42214
|
+
uncommittedFileCount: r.uncommittedFileCount
|
|
42215
|
+
});
|
|
42216
|
+
}
|
|
42217
|
+
|
|
42218
|
+
// src/routing/handlers/git/send-session-git-result.ts
|
|
42219
|
+
function sendSessionGitResult(ws, id, payload, e2ee, encryptedFields = []) {
|
|
41587
42220
|
if (!ws) return;
|
|
41588
42221
|
const message = { type: "session_git_result", id, ...payload };
|
|
41589
42222
|
sendWsMessage(ws, e2ee && encryptedFields.length > 0 ? e2ee.encryptFields(message, encryptedFields) : message);
|
|
41590
42223
|
}
|
|
42224
|
+
|
|
42225
|
+
// src/routing/handlers/git/session-git-request.ts
|
|
41591
42226
|
var handleSessionGitRequestMessage = (msg, deps) => {
|
|
41592
42227
|
if (typeof msg.id !== "string") return;
|
|
41593
42228
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -41596,80 +42231,21 @@ var handleSessionGitRequestMessage = (msg, deps) => {
|
|
|
41596
42231
|
return;
|
|
41597
42232
|
void (async () => {
|
|
41598
42233
|
const ws = deps.getWs();
|
|
41599
|
-
const reply = (payload, encryptedFields = []) =>
|
|
42234
|
+
const reply = (payload, encryptedFields = []) => sendSessionGitResult(ws, msg.id, payload, deps.e2ee, encryptedFields);
|
|
41600
42235
|
try {
|
|
41601
42236
|
if (action === "status") {
|
|
41602
|
-
|
|
41603
|
-
reply({
|
|
41604
|
-
ok: true,
|
|
41605
|
-
hasUncommittedChanges: r.hasUncommittedChanges,
|
|
41606
|
-
hasUnpushedCommits: r.hasUnpushedCommits,
|
|
41607
|
-
uncommittedFileCount: r.uncommittedFileCount
|
|
41608
|
-
});
|
|
42237
|
+
await handleSessionGitStatusAction(deps, sessionId, reply);
|
|
41609
42238
|
return;
|
|
41610
42239
|
}
|
|
41611
42240
|
if (action === "list_changes") {
|
|
41612
|
-
|
|
41613
|
-
const view = msg.changesView === "commit" ? "commit" : "working";
|
|
41614
|
-
const commitSha = typeof msg.changesCommitSha === "string" ? msg.changesCommitSha.trim() : "";
|
|
41615
|
-
if (view === "commit") {
|
|
41616
|
-
if (!repoRel || !commitSha) {
|
|
41617
|
-
reply({ ok: false, error: "changesRepoRelPath and changesCommitSha are required for commit view" });
|
|
41618
|
-
return;
|
|
41619
|
-
}
|
|
41620
|
-
}
|
|
41621
|
-
const recentCommitsLimit = typeof msg.changesRecentCommitsLimit === "number" || typeof msg.changesRecentCommitsLimit === "string" ? msg.changesRecentCommitsLimit : void 0;
|
|
41622
|
-
const opts = repoRel && view === "commit" && commitSha ? {
|
|
41623
|
-
repoRelPath: repoRel,
|
|
41624
|
-
basis: { kind: "commit", sha: commitSha },
|
|
41625
|
-
recentCommitsLimit
|
|
41626
|
-
} : repoRel ? { repoRelPath: repoRel, basis: { kind: "working" }, recentCommitsLimit } : recentCommitsLimit !== void 0 ? { recentCommitsLimit } : void 0;
|
|
41627
|
-
const repos = await deps.sessionWorktreeManager.getSessionWorkingTreeChangeDetails(sessionId, opts);
|
|
41628
|
-
reply({
|
|
41629
|
-
ok: true,
|
|
41630
|
-
repos
|
|
41631
|
-
}, ["repos"]);
|
|
42241
|
+
await handleSessionGitListChangesAction(deps, { ...msg, sessionId }, reply);
|
|
41632
42242
|
return;
|
|
41633
42243
|
}
|
|
41634
42244
|
if (action === "push") {
|
|
41635
|
-
|
|
41636
|
-
if (!pushRes.ok) {
|
|
41637
|
-
reply({ ok: false, error: pushRes.error ?? "Push failed" });
|
|
41638
|
-
return;
|
|
41639
|
-
}
|
|
41640
|
-
const st2 = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
41641
|
-
reply({
|
|
41642
|
-
ok: true,
|
|
41643
|
-
hasUncommittedChanges: st2.hasUncommittedChanges,
|
|
41644
|
-
hasUnpushedCommits: st2.hasUnpushedCommits,
|
|
41645
|
-
uncommittedFileCount: st2.uncommittedFileCount
|
|
41646
|
-
});
|
|
41647
|
-
return;
|
|
41648
|
-
}
|
|
41649
|
-
const branch = typeof msg.branch === "string" ? msg.branch : "";
|
|
41650
|
-
const message = typeof msg.message === "string" ? msg.message : "";
|
|
41651
|
-
const pushAfterCommit = msg.pushAfterCommit === true;
|
|
41652
|
-
if (!branch.trim() || !message.trim()) {
|
|
41653
|
-
reply({ ok: false, error: "branch and message are required for commit" });
|
|
42245
|
+
await handleSessionGitPushAction(deps, sessionId, reply);
|
|
41654
42246
|
return;
|
|
41655
42247
|
}
|
|
41656
|
-
|
|
41657
|
-
sessionId,
|
|
41658
|
-
branch: branch.trim(),
|
|
41659
|
-
message: message.trim(),
|
|
41660
|
-
push: pushAfterCommit
|
|
41661
|
-
});
|
|
41662
|
-
if (!commitRes.ok) {
|
|
41663
|
-
reply({ ok: false, error: commitRes.error ?? "Commit failed" });
|
|
41664
|
-
return;
|
|
41665
|
-
}
|
|
41666
|
-
const st = await deps.sessionWorktreeManager.getSessionWorkingTreeStatus(sessionId);
|
|
41667
|
-
reply({
|
|
41668
|
-
ok: true,
|
|
41669
|
-
hasUncommittedChanges: st.hasUncommittedChanges,
|
|
41670
|
-
hasUnpushedCommits: st.hasUnpushedCommits,
|
|
41671
|
-
uncommittedFileCount: st.uncommittedFileCount
|
|
41672
|
-
});
|
|
42248
|
+
await handleSessionGitCommitAction(deps, sessionId, msg, reply);
|
|
41673
42249
|
} catch (e) {
|
|
41674
42250
|
reply({ ok: false, error: e instanceof Error ? e.message : String(e) });
|
|
41675
42251
|
}
|
|
@@ -41699,7 +42275,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
41699
42275
|
};
|
|
41700
42276
|
|
|
41701
42277
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
41702
|
-
import * as
|
|
42278
|
+
import * as fs44 from "node:fs";
|
|
41703
42279
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
41704
42280
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
41705
42281
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -41712,7 +42288,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
41712
42288
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
41713
42289
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
41714
42290
|
try {
|
|
41715
|
-
await
|
|
42291
|
+
await fs44.promises.access(file2, fs44.constants.F_OK);
|
|
41716
42292
|
} catch {
|
|
41717
42293
|
sendWsMessage(s, {
|
|
41718
42294
|
type: "revert_turn_snapshot_result",
|
|
@@ -41754,7 +42330,7 @@ var handleDevServersConfig = (msg, deps) => {
|
|
|
41754
42330
|
};
|
|
41755
42331
|
|
|
41756
42332
|
// src/git/bridge-git-context.ts
|
|
41757
|
-
import * as
|
|
42333
|
+
import * as path50 from "node:path";
|
|
41758
42334
|
|
|
41759
42335
|
// src/git/branches/get-current-branch.ts
|
|
41760
42336
|
async function getCurrentBranch(repoPath) {
|
|
@@ -41804,12 +42380,12 @@ async function listRepoBranchRefs(repoPath) {
|
|
|
41804
42380
|
// src/git/bridge-git-context.ts
|
|
41805
42381
|
function folderNameForRelPath(relPath, bridgeRoot) {
|
|
41806
42382
|
if (relPath === "." || relPath === "") {
|
|
41807
|
-
return
|
|
42383
|
+
return path50.basename(path50.resolve(bridgeRoot)) || "repo";
|
|
41808
42384
|
}
|
|
41809
|
-
return
|
|
42385
|
+
return path50.basename(relPath) || relPath;
|
|
41810
42386
|
}
|
|
41811
42387
|
async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
41812
|
-
const root =
|
|
42388
|
+
const root = path50.resolve(bridgeRoot);
|
|
41813
42389
|
if (await isGitRepoDirectory(root)) {
|
|
41814
42390
|
const remoteUrl = await getRemoteOriginUrl(root);
|
|
41815
42391
|
return [{ absolutePath: root, remoteUrl }];
|
|
@@ -41817,17 +42393,17 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
|
41817
42393
|
const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
|
|
41818
42394
|
const byPath = /* @__PURE__ */ new Map();
|
|
41819
42395
|
for (const repo of [...deep, ...shallow]) {
|
|
41820
|
-
byPath.set(
|
|
42396
|
+
byPath.set(path50.resolve(repo.absolutePath), repo);
|
|
41821
42397
|
}
|
|
41822
42398
|
return [...byPath.values()];
|
|
41823
42399
|
}
|
|
41824
42400
|
async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
41825
|
-
const bridgeResolved =
|
|
42401
|
+
const bridgeResolved = path50.resolve(bridgeRoot);
|
|
41826
42402
|
const repos = await discoverGitReposForBridgeContext(bridgeResolved);
|
|
41827
42403
|
const rows = [];
|
|
41828
42404
|
for (const repo of repos) {
|
|
41829
|
-
let rel =
|
|
41830
|
-
if (rel.startsWith("..") ||
|
|
42405
|
+
let rel = path50.relative(bridgeResolved, repo.absolutePath);
|
|
42406
|
+
if (rel.startsWith("..") || path50.isAbsolute(rel)) continue;
|
|
41831
42407
|
const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
41832
42408
|
const currentBranch = await getCurrentBranch(repo.absolutePath);
|
|
41833
42409
|
const remoteUrl = repo.remoteUrl.trim() || null;
|
|
@@ -41842,11 +42418,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
|
41842
42418
|
return rows;
|
|
41843
42419
|
}
|
|
41844
42420
|
async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
41845
|
-
const bridgeResolved =
|
|
42421
|
+
const bridgeResolved = path50.resolve(bridgeRoot);
|
|
41846
42422
|
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
41847
|
-
const repoPath = rel === "" ? bridgeResolved :
|
|
41848
|
-
const resolved =
|
|
41849
|
-
if (!resolved.startsWith(bridgeResolved +
|
|
42423
|
+
const repoPath = rel === "" ? bridgeResolved : path50.join(bridgeResolved, rel);
|
|
42424
|
+
const resolved = path50.resolve(repoPath);
|
|
42425
|
+
if (!resolved.startsWith(bridgeResolved + path50.sep) && resolved !== bridgeResolved) {
|
|
41850
42426
|
return [];
|
|
41851
42427
|
}
|
|
41852
42428
|
return listRepoBranchRefs(resolved);
|
|
@@ -42351,10 +42927,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
|
42351
42927
|
}
|
|
42352
42928
|
|
|
42353
42929
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
42354
|
-
import * as
|
|
42930
|
+
import * as path52 from "node:path";
|
|
42355
42931
|
|
|
42356
42932
|
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
42357
|
-
import * as
|
|
42933
|
+
import * as path51 from "node:path";
|
|
42358
42934
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
42359
42935
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
|
|
42360
42936
|
const canContinue = () => shouldContinue?.() !== false;
|
|
@@ -42392,7 +42968,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
42392
42968
|
if (!canContinue()) return false;
|
|
42393
42969
|
handle = await resolved.createClient({
|
|
42394
42970
|
command: resolved.command,
|
|
42395
|
-
cwd:
|
|
42971
|
+
cwd: path51.resolve(cwd),
|
|
42396
42972
|
backendAgentType: agentType,
|
|
42397
42973
|
sessionMode: "agent",
|
|
42398
42974
|
persistedAcpSessionId: null,
|
|
@@ -42470,7 +43046,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
42470
43046
|
const { workspaceId, log: log2, getWs } = params;
|
|
42471
43047
|
const isCurrent = beginAgentCapabilityWarmupRun();
|
|
42472
43048
|
if (!isCurrent()) return;
|
|
42473
|
-
const cwd =
|
|
43049
|
+
const cwd = path52.resolve(getBridgeRoot());
|
|
42474
43050
|
async function sendBatchFromCache() {
|
|
42475
43051
|
if (!isCurrent()) return;
|
|
42476
43052
|
const socket = getWs();
|
|
@@ -42576,8 +43152,8 @@ async function callListParentSessionPromptsTool(ctx, cloud, childSessionId, pare
|
|
|
42576
43152
|
}
|
|
42577
43153
|
|
|
42578
43154
|
// src/mcp/tools/session-history/fork/tool-names.ts
|
|
42579
|
-
var
|
|
42580
|
-
var
|
|
43155
|
+
var LIST_PARENT_SESSION_PROMPTS_TOOL2 = "list_parent_session_prompts";
|
|
43156
|
+
var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL2 = "get_parent_session_turn_transcript";
|
|
42581
43157
|
|
|
42582
43158
|
// src/mcp/tools/session-history/fork/call-fork-session-mcp-tool.ts
|
|
42583
43159
|
async function callForkSessionMcpTool(ctx, cloud, name, args) {
|
|
@@ -42594,10 +43170,10 @@ async function callForkSessionMcpTool(ctx, cloud, name, args) {
|
|
|
42594
43170
|
return mcpTextResult(parentResolved.error, true);
|
|
42595
43171
|
}
|
|
42596
43172
|
const parentSessionId = parentResolved.parentSessionId;
|
|
42597
|
-
if (name ===
|
|
43173
|
+
if (name === LIST_PARENT_SESSION_PROMPTS_TOOL2) {
|
|
42598
43174
|
return callListParentSessionPromptsTool(ctx, cloud, childSessionId, parentSessionId);
|
|
42599
43175
|
}
|
|
42600
|
-
if (name ===
|
|
43176
|
+
if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL2) {
|
|
42601
43177
|
return callGetParentSessionTurnTranscriptTool(ctx, cloud, childSessionId, args);
|
|
42602
43178
|
}
|
|
42603
43179
|
return mcpTextResult(`Unknown fork session tool: ${name}`, true);
|
|
@@ -42610,7 +43186,7 @@ var SESSION_ID_SCHEMA = {
|
|
|
42610
43186
|
};
|
|
42611
43187
|
var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
|
|
42612
43188
|
{
|
|
42613
|
-
name:
|
|
43189
|
+
name: LIST_PARENT_SESSION_PROMPTS_TOOL2,
|
|
42614
43190
|
description: "List user prompts (main turns) from the parent session a fork was created from. Requires sessionId. Returns an error if the session has no parent history (not a fork).",
|
|
42615
43191
|
inputSchema: {
|
|
42616
43192
|
type: "object",
|
|
@@ -42620,7 +43196,7 @@ var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
|
|
|
42620
43196
|
}
|
|
42621
43197
|
},
|
|
42622
43198
|
{
|
|
42623
|
-
name:
|
|
43199
|
+
name: GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL2,
|
|
42624
43200
|
description: "Full transcript for one parent-session turn, including tool calls and agent messages. Requires sessionId and turnId. Returns an error if the session has no parent history (not a fork).",
|
|
42625
43201
|
inputSchema: {
|
|
42626
43202
|
type: "object",
|
|
@@ -42636,7 +43212,130 @@ var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
|
|
|
42636
43212
|
|
|
42637
43213
|
// src/mcp/tools/session-history/fork/is-fork-session-mcp-tool-name.ts
|
|
42638
43214
|
function isForkSessionMcpToolName(name) {
|
|
42639
|
-
return name ===
|
|
43215
|
+
return name === LIST_PARENT_SESSION_PROMPTS_TOOL2 || name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL2;
|
|
43216
|
+
}
|
|
43217
|
+
|
|
43218
|
+
// src/mcp/tools/integration-content/tool-names.ts
|
|
43219
|
+
var GET_INTEGRATION_CONTENT_TOOL2 = "get_integration_content";
|
|
43220
|
+
|
|
43221
|
+
// src/mcp/tools/integration-content/cloud/fetch-integration-content.ts
|
|
43222
|
+
async function fetchCloudIntegrationContent(params) {
|
|
43223
|
+
return fetchInternalApiJson({
|
|
43224
|
+
...params,
|
|
43225
|
+
path: `/internal/sessions/${encodeURIComponent(params.sessionId)}/integrations/content`,
|
|
43226
|
+
errorLabel: "Integration content fetch failed",
|
|
43227
|
+
method: "POST",
|
|
43228
|
+
body: {
|
|
43229
|
+
url: params.url,
|
|
43230
|
+
associateAsSessionTicket: params.associateAsSessionTicket !== false
|
|
43231
|
+
}
|
|
43232
|
+
});
|
|
43233
|
+
}
|
|
43234
|
+
|
|
43235
|
+
// src/mcp/tools/integration-content/format-integration-content-for-mcp.ts
|
|
43236
|
+
function formatIntegrationContentForMcp(result) {
|
|
43237
|
+
if (!result.ok) {
|
|
43238
|
+
const lines2 = [`status: ${result.code}`, `message: ${result.message}`];
|
|
43239
|
+
if (result.integrationType) lines2.push(`integrationType: ${result.integrationType}`);
|
|
43240
|
+
if (result.retryable) lines2.push("retryable: true");
|
|
43241
|
+
lines2.push(...formatSessionTicketAssociationLines(result.sessionTicketAssociation));
|
|
43242
|
+
return lines2.join("\n");
|
|
43243
|
+
}
|
|
43244
|
+
const lines = [
|
|
43245
|
+
formatIntegrationContentBody(result.integrationType, result.content),
|
|
43246
|
+
...formatSessionTicketAssociationLines(result.sessionTicketAssociation)
|
|
43247
|
+
];
|
|
43248
|
+
return lines.join("\n");
|
|
43249
|
+
}
|
|
43250
|
+
function formatSessionTicketAssociationLines(association) {
|
|
43251
|
+
if (association.status === "associated") {
|
|
43252
|
+
const title = association.externalTicket.displayTitle?.trim() || association.externalTicket.normalizedUrl;
|
|
43253
|
+
return ["", "--- session ticket ---", "status: associated", `displayTitle: ${title}`];
|
|
43254
|
+
}
|
|
43255
|
+
if (association.status === "failed") {
|
|
43256
|
+
return ["", "--- session ticket ---", "status: failed", `reason: ${association.reason}`];
|
|
43257
|
+
}
|
|
43258
|
+
return ["", "--- session ticket ---", `status: ${association.status}`, `reason: ${association.reason}`];
|
|
43259
|
+
}
|
|
43260
|
+
function formatIntegrationContentBody(integrationType, content) {
|
|
43261
|
+
const lines = [
|
|
43262
|
+
`integrationType: ${integrationType}`,
|
|
43263
|
+
`title: ${content.title}`,
|
|
43264
|
+
`url: ${content.url}`,
|
|
43265
|
+
"",
|
|
43266
|
+
"--- body ---",
|
|
43267
|
+
content.body
|
|
43268
|
+
];
|
|
43269
|
+
if (content.comments?.length) {
|
|
43270
|
+
lines.push("", "--- comments ---");
|
|
43271
|
+
for (const comment of content.comments) {
|
|
43272
|
+
lines.push(`[${comment.createdAt}] ${comment.author}:`, comment.body, "");
|
|
43273
|
+
}
|
|
43274
|
+
}
|
|
43275
|
+
const threadMessages = content.threadMessages;
|
|
43276
|
+
if (threadMessages?.length) {
|
|
43277
|
+
lines.push("", "--- thread messages ---");
|
|
43278
|
+
for (const msg of threadMessages) {
|
|
43279
|
+
lines.push(`[${msg.ts}] ${msg.displayName}: ${msg.text}`);
|
|
43280
|
+
}
|
|
43281
|
+
}
|
|
43282
|
+
if (content.metadata && Object.keys(content.metadata).length > 0) {
|
|
43283
|
+
lines.push("", "--- metadata ---", JSON.stringify(content.metadata, null, 2));
|
|
43284
|
+
}
|
|
43285
|
+
return lines.join("\n");
|
|
43286
|
+
}
|
|
43287
|
+
|
|
43288
|
+
// src/mcp/tools/integration-content/call-integration-content-mcp-tool.ts
|
|
43289
|
+
async function callIntegrationContentMcpTool(ctx, cloud, name, args) {
|
|
43290
|
+
if (name !== GET_INTEGRATION_CONTENT_TOOL2) {
|
|
43291
|
+
return mcpTextResult(`Unknown integration content tool: ${name}`, true);
|
|
43292
|
+
}
|
|
43293
|
+
const sessionId = ctx.sessionId.trim();
|
|
43294
|
+
if (!sessionId) return mcpTextResult("sessionId is required.", true);
|
|
43295
|
+
const url2 = typeof args.url === "string" ? args.url.trim() : "";
|
|
43296
|
+
if (!url2) return mcpTextResult("url is required.", true);
|
|
43297
|
+
const associateAsSessionTicket = args.associateAsSessionTicket !== false;
|
|
43298
|
+
const fetched = await fetchCloudIntegrationContent({
|
|
43299
|
+
sessionId,
|
|
43300
|
+
url: url2,
|
|
43301
|
+
associateAsSessionTicket,
|
|
43302
|
+
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
43303
|
+
getCloudAccessToken: cloud.getCloudAccessToken
|
|
43304
|
+
});
|
|
43305
|
+
if (!fetched.ok) return mcpTextResult(fetched.error, true);
|
|
43306
|
+
const text = formatIntegrationContentForMcp(fetched.data);
|
|
43307
|
+
const isError = !fetched.data.ok;
|
|
43308
|
+
return mcpTextResult(text, isError);
|
|
43309
|
+
}
|
|
43310
|
+
|
|
43311
|
+
// src/mcp/tools/integration-content/tool-definitions.ts
|
|
43312
|
+
var SESSION_ID_SCHEMA2 = {
|
|
43313
|
+
type: "string",
|
|
43314
|
+
description: "Id of the current session. Required on every tool call so the workspace integration credentials can be resolved."
|
|
43315
|
+
};
|
|
43316
|
+
var INTEGRATION_CONTENT_MCP_TOOL_DEFINITIONS = [
|
|
43317
|
+
{
|
|
43318
|
+
name: GET_INTEGRATION_CONTENT_TOOL2,
|
|
43319
|
+
description: "Fetch the full content of a supported external integration link (Linear, GitHub, Jira, Notion, Slack thread, Zoom meeting, Asana). Requires sessionId and url. By default, links the URL as this session external ticket when the session has none yet. Pass associateAsSessionTicket: false to fetch content only (e.g. additional context links). Returns an error when the URL is unsupported, the integration is not connected, or content is temporarily unavailable (retry may succeed).",
|
|
43320
|
+
inputSchema: {
|
|
43321
|
+
type: "object",
|
|
43322
|
+
properties: {
|
|
43323
|
+
sessionId: SESSION_ID_SCHEMA2,
|
|
43324
|
+
url: { type: "string", description: "External integration URL to fetch" },
|
|
43325
|
+
associateAsSessionTicket: {
|
|
43326
|
+
type: "boolean",
|
|
43327
|
+
description: "Defaults to true. When true and the session has no linked external ticket yet, links this URL as the session external ticket. Pass false when fetching additional links for context only."
|
|
43328
|
+
}
|
|
43329
|
+
},
|
|
43330
|
+
required: ["sessionId", "url"],
|
|
43331
|
+
additionalProperties: false
|
|
43332
|
+
}
|
|
43333
|
+
}
|
|
43334
|
+
];
|
|
43335
|
+
|
|
43336
|
+
// src/mcp/tools/integration-content/index.ts
|
|
43337
|
+
function isIntegrationContentMcpToolName(name) {
|
|
43338
|
+
return name === GET_INTEGRATION_CONTENT_TOOL2;
|
|
42640
43339
|
}
|
|
42641
43340
|
|
|
42642
43341
|
// src/mcp/bridge-mcp-tools.ts
|
|
@@ -42649,7 +43348,7 @@ function requireCloud(shared) {
|
|
|
42649
43348
|
function createBridgeMcpToolRegistry(shared) {
|
|
42650
43349
|
const cloud = requireCloud(shared);
|
|
42651
43350
|
return {
|
|
42652
|
-
listTools: async () => [...FORK_SESSION_MCP_TOOL_DEFINITIONS],
|
|
43351
|
+
listTools: async () => [...FORK_SESSION_MCP_TOOL_DEFINITIONS, ...INTEGRATION_CONTENT_MCP_TOOL_DEFINITIONS],
|
|
42653
43352
|
callTool: async (name, args) => {
|
|
42654
43353
|
if (isForkSessionMcpToolName(name)) {
|
|
42655
43354
|
if (!cloud) {
|
|
@@ -42667,6 +43366,22 @@ function createBridgeMcpToolRegistry(shared) {
|
|
|
42667
43366
|
}
|
|
42668
43367
|
return callForkSessionMcpTool({ ...shared, sessionId }, cloud, name, args);
|
|
42669
43368
|
}
|
|
43369
|
+
if (isIntegrationContentMcpToolName(name)) {
|
|
43370
|
+
if (!cloud) {
|
|
43371
|
+
return {
|
|
43372
|
+
content: [{ type: "text", text: "Bridge MCP tools require cloud API credentials." }],
|
|
43373
|
+
isError: true
|
|
43374
|
+
};
|
|
43375
|
+
}
|
|
43376
|
+
const sessionId = typeof args.sessionId === "string" ? args.sessionId.trim() : "";
|
|
43377
|
+
if (!sessionId) {
|
|
43378
|
+
return {
|
|
43379
|
+
content: [{ type: "text", text: "sessionId is required." }],
|
|
43380
|
+
isError: true
|
|
43381
|
+
};
|
|
43382
|
+
}
|
|
43383
|
+
return callIntegrationContentMcpTool({ ...shared, sessionId }, cloud, name, args);
|
|
43384
|
+
}
|
|
42670
43385
|
throw new Error(`Unknown bridge MCP tool: ${name}`);
|
|
42671
43386
|
}
|
|
42672
43387
|
};
|
|
@@ -42677,18 +43392,18 @@ import * as http from "node:http";
|
|
|
42677
43392
|
|
|
42678
43393
|
// src/mcp/bridge-access/read-json-body.ts
|
|
42679
43394
|
function readJsonBody(req) {
|
|
42680
|
-
return new Promise((
|
|
43395
|
+
return new Promise((resolve28, reject) => {
|
|
42681
43396
|
const chunks = [];
|
|
42682
43397
|
req.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
42683
43398
|
req.on("end", () => {
|
|
42684
43399
|
try {
|
|
42685
43400
|
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
42686
43401
|
if (!raw) {
|
|
42687
|
-
|
|
43402
|
+
resolve28({});
|
|
42688
43403
|
return;
|
|
42689
43404
|
}
|
|
42690
43405
|
const parsed = JSON.parse(raw);
|
|
42691
|
-
|
|
43406
|
+
resolve28(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
|
|
42692
43407
|
} catch (e) {
|
|
42693
43408
|
reject(e);
|
|
42694
43409
|
}
|
|
@@ -42746,7 +43461,7 @@ function createBridgeAccessRequestHandler(registry2) {
|
|
|
42746
43461
|
// src/mcp/bridge-access/start-server.ts
|
|
42747
43462
|
function startBridgeAccessServer(registry2) {
|
|
42748
43463
|
const server = http.createServer(createBridgeAccessRequestHandler(registry2));
|
|
42749
|
-
return new Promise((
|
|
43464
|
+
return new Promise((resolve28, reject) => {
|
|
42750
43465
|
server.once("error", reject);
|
|
42751
43466
|
server.listen(0, "127.0.0.1", () => {
|
|
42752
43467
|
const addr = server.address();
|
|
@@ -42754,7 +43469,7 @@ function startBridgeAccessServer(registry2) {
|
|
|
42754
43469
|
reject(new Error("Bridge access server did not bind"));
|
|
42755
43470
|
return;
|
|
42756
43471
|
}
|
|
42757
|
-
|
|
43472
|
+
resolve28({
|
|
42758
43473
|
port: addr.port,
|
|
42759
43474
|
close: () => new Promise((closeResolve, closeReject) => {
|
|
42760
43475
|
server.close((err) => err ? closeReject(err) : closeResolve());
|
|
@@ -42894,8 +43609,8 @@ async function createBridgeConnection(options) {
|
|
|
42894
43609
|
getCloudAccessToken: () => tokens.accessToken
|
|
42895
43610
|
};
|
|
42896
43611
|
const identifyReportedPaths = {
|
|
42897
|
-
bridgeRootPath:
|
|
42898
|
-
worktreesRootPath:
|
|
43612
|
+
bridgeRootPath: path53.resolve(getBridgeRoot()),
|
|
43613
|
+
worktreesRootPath: path53.resolve(worktreesRootPath)
|
|
42899
43614
|
};
|
|
42900
43615
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
42901
43616
|
state,
|
|
@@ -43150,9 +43865,9 @@ async function runCliAction(program2, opts) {
|
|
|
43150
43865
|
const firehoseServerUrl = opts.firehoseUrl ?? opts.proxyUrl ?? process.env.BUILDAUTOMATON_FIREHOSE_URL ?? process.env.BUILDAUTOMATON_PROXY_URL ?? DEFAULT_FIREHOSE_URL;
|
|
43151
43866
|
const bridgeRootOpt = (opts.bridgeRoot && typeof opts.bridgeRoot === "string" && opts.bridgeRoot.trim() ? opts.bridgeRoot.trim() : null) ?? (opts.cwd && typeof opts.cwd === "string" && opts.cwd.trim() ? opts.cwd.trim() : null);
|
|
43152
43867
|
if (bridgeRootOpt) {
|
|
43153
|
-
const resolvedBridgeRoot =
|
|
43868
|
+
const resolvedBridgeRoot = path54.resolve(process.cwd(), bridgeRootOpt);
|
|
43154
43869
|
try {
|
|
43155
|
-
const st =
|
|
43870
|
+
const st = fs45.statSync(resolvedBridgeRoot);
|
|
43156
43871
|
if (!st.isDirectory()) {
|
|
43157
43872
|
console.error(`Bridge root is not a directory: ${resolvedBridgeRoot}`);
|
|
43158
43873
|
process.exit(1);
|
|
@@ -43172,7 +43887,7 @@ async function runCliAction(program2, opts) {
|
|
|
43172
43887
|
);
|
|
43173
43888
|
let worktreesRootPath;
|
|
43174
43889
|
if (opts.worktreesRoot && opts.worktreesRoot.trim()) {
|
|
43175
|
-
worktreesRootPath =
|
|
43890
|
+
worktreesRootPath = path54.resolve(opts.worktreesRoot.trim());
|
|
43176
43891
|
}
|
|
43177
43892
|
const e2eCertificates = opts.e2eeCertificatesDir?.trim() ? await loadOrCreateE2eCertificates(opts.e2eeCertificatesDir.trim()) : void 0;
|
|
43178
43893
|
if (e2eCertificates) {
|