@buildautomaton/cli 0.1.45 → 0.1.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bridge-mcp-server.js +161 -0
- package/dist/bridge-mcp-server.js.map +7 -0
- package/dist/cli.js +1159 -453
- package/dist/cli.js.map +4 -4
- package/dist/fork-history-mcp-server.js +132 -0
- package/dist/fork-history-mcp-server.js.map +7 -0
- package/dist/index.js +1138 -432
- package/dist/index.js.map +4 -4
- package/dist/migrations/004_bridge_runtime.sql +14 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2237,7 +2237,7 @@ var require_websocket = __commonJS({
|
|
|
2237
2237
|
"use strict";
|
|
2238
2238
|
var EventEmitter2 = __require("events");
|
|
2239
2239
|
var https2 = __require("https");
|
|
2240
|
-
var
|
|
2240
|
+
var http2 = __require("http");
|
|
2241
2241
|
var net = __require("net");
|
|
2242
2242
|
var tls = __require("tls");
|
|
2243
2243
|
var { randomBytes: randomBytes2, createHash: createHash2 } = __require("crypto");
|
|
@@ -2771,7 +2771,7 @@ var require_websocket = __commonJS({
|
|
|
2771
2771
|
}
|
|
2772
2772
|
const defaultPort = isSecure ? 443 : 80;
|
|
2773
2773
|
const key = randomBytes2(16).toString("base64");
|
|
2774
|
-
const request = isSecure ? https2.request :
|
|
2774
|
+
const request = isSecure ? https2.request : http2.request;
|
|
2775
2775
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
2776
2776
|
let perMessageDeflate;
|
|
2777
2777
|
opts.createConnection = opts.createConnection || (isSecure ? tlsConnect : netConnect);
|
|
@@ -3265,7 +3265,7 @@ var require_websocket_server = __commonJS({
|
|
|
3265
3265
|
"../../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js"(exports, module) {
|
|
3266
3266
|
"use strict";
|
|
3267
3267
|
var EventEmitter2 = __require("events");
|
|
3268
|
-
var
|
|
3268
|
+
var http2 = __require("http");
|
|
3269
3269
|
var { Duplex } = __require("stream");
|
|
3270
3270
|
var { createHash: createHash2 } = __require("crypto");
|
|
3271
3271
|
var extension = require_extension();
|
|
@@ -3340,8 +3340,8 @@ var require_websocket_server = __commonJS({
|
|
|
3340
3340
|
);
|
|
3341
3341
|
}
|
|
3342
3342
|
if (options.port != null) {
|
|
3343
|
-
this._server =
|
|
3344
|
-
const body =
|
|
3343
|
+
this._server = http2.createServer((req, res) => {
|
|
3344
|
+
const body = http2.STATUS_CODES[426];
|
|
3345
3345
|
res.writeHead(426, {
|
|
3346
3346
|
"Content-Length": body.length,
|
|
3347
3347
|
"Content-Type": "text/plain"
|
|
@@ -3628,7 +3628,7 @@ var require_websocket_server = __commonJS({
|
|
|
3628
3628
|
this.destroy();
|
|
3629
3629
|
}
|
|
3630
3630
|
function abortHandshake(socket, code, message, headers) {
|
|
3631
|
-
message = message ||
|
|
3631
|
+
message = message || http2.STATUS_CODES[code];
|
|
3632
3632
|
headers = {
|
|
3633
3633
|
Connection: "close",
|
|
3634
3634
|
"Content-Type": "text/html",
|
|
@@ -3637,7 +3637,7 @@ var require_websocket_server = __commonJS({
|
|
|
3637
3637
|
};
|
|
3638
3638
|
socket.once("finish", socket.destroy);
|
|
3639
3639
|
socket.end(
|
|
3640
|
-
`HTTP/1.1 ${code} ${
|
|
3640
|
+
`HTTP/1.1 ${code} ${http2.STATUS_CODES[code]}\r
|
|
3641
3641
|
` + Object.keys(headers).map((h) => `${h}: ${headers[h]}`).join("\r\n") + "\r\n\r\n" + message
|
|
3642
3642
|
);
|
|
3643
3643
|
}
|
|
@@ -4175,8 +4175,8 @@ var init_parseUtil = __esm({
|
|
|
4175
4175
|
init_errors();
|
|
4176
4176
|
init_en();
|
|
4177
4177
|
makeIssue = (params) => {
|
|
4178
|
-
const { data, path:
|
|
4179
|
-
const fullPath = [...
|
|
4178
|
+
const { data, path: path46, errorMaps, issueData } = params;
|
|
4179
|
+
const fullPath = [...path46, ...issueData.path || []];
|
|
4180
4180
|
const fullIssue = {
|
|
4181
4181
|
...issueData,
|
|
4182
4182
|
path: fullPath
|
|
@@ -4484,11 +4484,11 @@ var init_types = __esm({
|
|
|
4484
4484
|
init_parseUtil();
|
|
4485
4485
|
init_util();
|
|
4486
4486
|
ParseInputLazyPath = class {
|
|
4487
|
-
constructor(parent, value,
|
|
4487
|
+
constructor(parent, value, path46, key) {
|
|
4488
4488
|
this._cachedPath = [];
|
|
4489
4489
|
this.parent = parent;
|
|
4490
4490
|
this.data = value;
|
|
4491
|
-
this._path =
|
|
4491
|
+
this._path = path46;
|
|
4492
4492
|
this._key = key;
|
|
4493
4493
|
}
|
|
4494
4494
|
get path() {
|
|
@@ -8103,15 +8103,15 @@ function assignProp(target, prop, value) {
|
|
|
8103
8103
|
configurable: true
|
|
8104
8104
|
});
|
|
8105
8105
|
}
|
|
8106
|
-
function getElementAtPath(obj,
|
|
8107
|
-
if (!
|
|
8106
|
+
function getElementAtPath(obj, path46) {
|
|
8107
|
+
if (!path46)
|
|
8108
8108
|
return obj;
|
|
8109
|
-
return
|
|
8109
|
+
return path46.reduce((acc, key) => acc?.[key], obj);
|
|
8110
8110
|
}
|
|
8111
8111
|
function promiseAllObject(promisesObj) {
|
|
8112
8112
|
const keys = Object.keys(promisesObj);
|
|
8113
|
-
const
|
|
8114
|
-
return Promise.all(
|
|
8113
|
+
const promises6 = keys.map((key) => promisesObj[key]);
|
|
8114
|
+
return Promise.all(promises6).then((results) => {
|
|
8115
8115
|
const resolvedObj = {};
|
|
8116
8116
|
for (let i = 0; i < keys.length; i++) {
|
|
8117
8117
|
resolvedObj[keys[i]] = results[i];
|
|
@@ -8355,11 +8355,11 @@ function aborted(x, startIndex = 0) {
|
|
|
8355
8355
|
}
|
|
8356
8356
|
return false;
|
|
8357
8357
|
}
|
|
8358
|
-
function prefixIssues(
|
|
8358
|
+
function prefixIssues(path46, issues) {
|
|
8359
8359
|
return issues.map((iss) => {
|
|
8360
8360
|
var _a2;
|
|
8361
8361
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
8362
|
-
iss.path.unshift(
|
|
8362
|
+
iss.path.unshift(path46);
|
|
8363
8363
|
return iss;
|
|
8364
8364
|
});
|
|
8365
8365
|
}
|
|
@@ -8548,7 +8548,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8548
8548
|
return issue2.message;
|
|
8549
8549
|
};
|
|
8550
8550
|
const result = { errors: [] };
|
|
8551
|
-
const processError = (error41,
|
|
8551
|
+
const processError = (error41, path46 = []) => {
|
|
8552
8552
|
var _a2, _b;
|
|
8553
8553
|
for (const issue2 of error41.issues) {
|
|
8554
8554
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -8558,7 +8558,7 @@ function treeifyError(error40, _mapper) {
|
|
|
8558
8558
|
} else if (issue2.code === "invalid_element") {
|
|
8559
8559
|
processError({ issues: issue2.issues }, issue2.path);
|
|
8560
8560
|
} else {
|
|
8561
|
-
const fullpath = [...
|
|
8561
|
+
const fullpath = [...path46, ...issue2.path];
|
|
8562
8562
|
if (fullpath.length === 0) {
|
|
8563
8563
|
result.errors.push(mapper(issue2));
|
|
8564
8564
|
continue;
|
|
@@ -8588,9 +8588,9 @@ function treeifyError(error40, _mapper) {
|
|
|
8588
8588
|
processError(error40);
|
|
8589
8589
|
return result;
|
|
8590
8590
|
}
|
|
8591
|
-
function toDotPath(
|
|
8591
|
+
function toDotPath(path46) {
|
|
8592
8592
|
const segs = [];
|
|
8593
|
-
for (const seg of
|
|
8593
|
+
for (const seg of path46) {
|
|
8594
8594
|
if (typeof seg === "number")
|
|
8595
8595
|
segs.push(`[${seg}]`);
|
|
8596
8596
|
else if (typeof seg === "symbol")
|
|
@@ -22073,10 +22073,10 @@ var require_src2 = __commonJS({
|
|
|
22073
22073
|
var fs_1 = __require("fs");
|
|
22074
22074
|
var debug_1 = __importDefault(require_src());
|
|
22075
22075
|
var log2 = debug_1.default("@kwsites/file-exists");
|
|
22076
|
-
function check2(
|
|
22077
|
-
log2(`checking %s`,
|
|
22076
|
+
function check2(path46, isFile, isDirectory) {
|
|
22077
|
+
log2(`checking %s`, path46);
|
|
22078
22078
|
try {
|
|
22079
|
-
const stat2 = fs_1.statSync(
|
|
22079
|
+
const stat2 = fs_1.statSync(path46);
|
|
22080
22080
|
if (stat2.isFile() && isFile) {
|
|
22081
22081
|
log2(`[OK] path represents a file`);
|
|
22082
22082
|
return true;
|
|
@@ -22096,8 +22096,8 @@ var require_src2 = __commonJS({
|
|
|
22096
22096
|
throw e;
|
|
22097
22097
|
}
|
|
22098
22098
|
}
|
|
22099
|
-
function exists2(
|
|
22100
|
-
return check2(
|
|
22099
|
+
function exists2(path46, type = exports.READABLE) {
|
|
22100
|
+
return check2(path46, (type & exports.FILE) > 0, (type & exports.FOLDER) > 0);
|
|
22101
22101
|
}
|
|
22102
22102
|
exports.exists = exists2;
|
|
22103
22103
|
exports.FILE = 1;
|
|
@@ -22940,9 +22940,9 @@ function parseChangeSummaryJson(raw, allowedPaths, options) {
|
|
|
22940
22940
|
const rawPath = typeof o.path === "string" ? o.path.trim() : "";
|
|
22941
22941
|
const summary = typeof o.summary === "string" ? o.summary.trim() : "";
|
|
22942
22942
|
if (!rawPath || !summary) continue;
|
|
22943
|
-
const
|
|
22944
|
-
if (!
|
|
22945
|
-
rows.push({ path:
|
|
22943
|
+
const path46 = skip ? normalizeRepoRelativePath(rawPath) || rawPath : resolveChangeSummaryPathAgainstAllowed(rawPath, allowedPaths);
|
|
22944
|
+
if (!path46) continue;
|
|
22945
|
+
rows.push({ path: path46, summary: clampSummaryToAtMostTwoLines(summary) });
|
|
22946
22946
|
}
|
|
22947
22947
|
return rows;
|
|
22948
22948
|
}
|
|
@@ -23553,7 +23553,7 @@ function createSdkStdioSessionContext(options) {
|
|
|
23553
23553
|
return {
|
|
23554
23554
|
cwd: options.cwd,
|
|
23555
23555
|
onFileChange: options.onFileChange,
|
|
23556
|
-
mcpServers: [],
|
|
23556
|
+
mcpServers: options.mcpServers ?? [],
|
|
23557
23557
|
persistedAcpSessionId: options.persistedAcpSessionId,
|
|
23558
23558
|
agentLabel: "ACP",
|
|
23559
23559
|
suppressLoadReplay: suppressLoadReplayRef,
|
|
@@ -23996,6 +23996,7 @@ async function createSdkStdioAcpClient(options) {
|
|
|
23996
23996
|
});
|
|
23997
23997
|
const sessionCtx = createSdkStdioSessionContext({
|
|
23998
23998
|
cwd,
|
|
23999
|
+
mcpServers: options.mcpServers,
|
|
23999
24000
|
persistedAcpSessionId,
|
|
24000
24001
|
backendAgentType,
|
|
24001
24002
|
agentConfig,
|
|
@@ -24240,8 +24241,8 @@ function randomSecret() {
|
|
|
24240
24241
|
}
|
|
24241
24242
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
24242
24243
|
}
|
|
24243
|
-
async function requestPreviewApi(port, secret, method,
|
|
24244
|
-
const url2 = `http://127.0.0.1:${port}${
|
|
24244
|
+
async function requestPreviewApi(port, secret, method, path46, body) {
|
|
24245
|
+
const url2 = `http://127.0.0.1:${port}${path46}`;
|
|
24245
24246
|
const headers = {
|
|
24246
24247
|
[PREVIEW_SECRET_HEADER]: secret,
|
|
24247
24248
|
"Content-Type": "application/json"
|
|
@@ -24253,7 +24254,7 @@ async function requestPreviewApi(port, secret, method, path44, body) {
|
|
|
24253
24254
|
});
|
|
24254
24255
|
const data = await res.json().catch(() => ({}));
|
|
24255
24256
|
if (!res.ok) {
|
|
24256
|
-
throw new Error(data?.error ?? `Preview API ${method} ${
|
|
24257
|
+
throw new Error(data?.error ?? `Preview API ${method} ${path46}: ${res.status}`);
|
|
24257
24258
|
}
|
|
24258
24259
|
return data;
|
|
24259
24260
|
}
|
|
@@ -24468,7 +24469,7 @@ function installBridgeProcessResilience() {
|
|
|
24468
24469
|
}
|
|
24469
24470
|
|
|
24470
24471
|
// src/cli-version.ts
|
|
24471
|
-
var CLI_VERSION = "0.1.
|
|
24472
|
+
var CLI_VERSION = "0.1.47".length > 0 ? "0.1.47" : "0.0.0-dev";
|
|
24472
24473
|
|
|
24473
24474
|
// src/connection/heartbeat/constants.ts
|
|
24474
24475
|
var BRIDGE_APP_HEARTBEAT_INTERVAL_MS = 1e4;
|
|
@@ -26157,6 +26158,7 @@ var AcpPromptRoutingRegistry = class {
|
|
|
26157
26158
|
function createAcpManagerContext(options) {
|
|
26158
26159
|
return {
|
|
26159
26160
|
log: options.log,
|
|
26161
|
+
getBridgeAccessPort: options.getBridgeAccessPort,
|
|
26160
26162
|
reportAgentCapabilities: options.reportAgentCapabilities,
|
|
26161
26163
|
backendFallbackAgentType: null,
|
|
26162
26164
|
acpAgents: /* @__PURE__ */ new Map(),
|
|
@@ -26339,7 +26341,7 @@ function createCursorAcpSessionContext(options) {
|
|
|
26339
26341
|
return {
|
|
26340
26342
|
cwd: options.cwd,
|
|
26341
26343
|
onFileChange: options.onFileChange,
|
|
26342
|
-
mcpServers: [],
|
|
26344
|
+
mcpServers: options.mcpServers ?? [],
|
|
26343
26345
|
persistedAcpSessionId: options.persistedAcpSessionId,
|
|
26344
26346
|
agentLabel: "Cursor",
|
|
26345
26347
|
suppressLoadReplay: suppressLoadReplayRef,
|
|
@@ -26765,6 +26767,7 @@ async function createCursorAcpClient(options) {
|
|
|
26765
26767
|
});
|
|
26766
26768
|
const sessionCtx = createCursorAcpSessionContext({
|
|
26767
26769
|
cwd,
|
|
26770
|
+
mcpServers: options.mcpServers,
|
|
26768
26771
|
persistedAcpSessionId,
|
|
26769
26772
|
backendAgentType,
|
|
26770
26773
|
agentConfig: options.agentConfig,
|
|
@@ -27723,6 +27726,30 @@ function computeAcpAgentKey(preferredAgentType, mode, agentConfig) {
|
|
|
27723
27726
|
return `${resolved.label}::${fullCmd.join("\0")}${cacheConfig}`;
|
|
27724
27727
|
}
|
|
27725
27728
|
|
|
27729
|
+
// src/mcp/bridge-mcp-constants.ts
|
|
27730
|
+
var BRIDGE_MCP_SERVER_NAME = "buildautomaton-bridge";
|
|
27731
|
+
|
|
27732
|
+
// src/mcp/resolve-bridge-mcp-server-path.ts
|
|
27733
|
+
import { dirname as dirname4, join as join2 } from "node:path";
|
|
27734
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
27735
|
+
function resolveBridgeMcpServerScriptPath() {
|
|
27736
|
+
const cliDir = dirname4(fileURLToPath4(import.meta.url));
|
|
27737
|
+
return join2(cliDir, "bridge-mcp-server.js");
|
|
27738
|
+
}
|
|
27739
|
+
|
|
27740
|
+
// src/mcp/build-acp-mcp-servers.ts
|
|
27741
|
+
function buildAcpMcpServers(bridgeAccessPort) {
|
|
27742
|
+
if (!Number.isFinite(bridgeAccessPort) || bridgeAccessPort <= 0) return [];
|
|
27743
|
+
return [
|
|
27744
|
+
{
|
|
27745
|
+
name: BRIDGE_MCP_SERVER_NAME,
|
|
27746
|
+
command: process.execPath,
|
|
27747
|
+
args: [resolveBridgeMcpServerScriptPath(), String(bridgeAccessPort)],
|
|
27748
|
+
env: []
|
|
27749
|
+
}
|
|
27750
|
+
];
|
|
27751
|
+
}
|
|
27752
|
+
|
|
27726
27753
|
// src/agents/acp/ensure-acp-client.ts
|
|
27727
27754
|
function invalidateAcpClientState(state) {
|
|
27728
27755
|
state.clientEpoch += 1;
|
|
@@ -27754,11 +27781,13 @@ async function ensureAcpClient(options) {
|
|
|
27754
27781
|
sessionParentPath,
|
|
27755
27782
|
resolveRouting,
|
|
27756
27783
|
cloudSessionId,
|
|
27784
|
+
bridgeAccessPort,
|
|
27757
27785
|
reportAgentCapabilities,
|
|
27758
27786
|
sendSessionUpdate,
|
|
27759
27787
|
sendRequest,
|
|
27760
27788
|
log: log2
|
|
27761
27789
|
} = options;
|
|
27790
|
+
const mcpServers = buildAcpMcpServers(bridgeAccessPort ?? 0);
|
|
27762
27791
|
state.latestAgentConfigForBridgeHooks = agentConfig != null && typeof agentConfig === "object" && !Array.isArray(agentConfig) ? agentConfig : null;
|
|
27763
27792
|
const targetSessionParentPath = resolveSessionParentPathForAgentProcess(sessionParentPath);
|
|
27764
27793
|
if (state.acpStartPromise && !state.acpHandle) {
|
|
@@ -27874,7 +27903,8 @@ async function ensureAcpClient(options) {
|
|
|
27874
27903
|
state.lastAcpStartError = "Agent subprocess exited";
|
|
27875
27904
|
},
|
|
27876
27905
|
...hooks,
|
|
27877
|
-
cwd: targetSessionParentPath
|
|
27906
|
+
cwd: targetSessionParentPath,
|
|
27907
|
+
mcpServers
|
|
27878
27908
|
}).then(async (h) => {
|
|
27879
27909
|
if (spawnEpoch !== state.clientEpoch || isCliImmediateShutdownRequested()) {
|
|
27880
27910
|
try {
|
|
@@ -27965,8 +27995,8 @@ function pathspec(...paths) {
|
|
|
27965
27995
|
cache.set(key, paths);
|
|
27966
27996
|
return key;
|
|
27967
27997
|
}
|
|
27968
|
-
function isPathSpec(
|
|
27969
|
-
return
|
|
27998
|
+
function isPathSpec(path46) {
|
|
27999
|
+
return path46 instanceof String && cache.has(path46);
|
|
27970
28000
|
}
|
|
27971
28001
|
function toPaths(pathSpec) {
|
|
27972
28002
|
return cache.get(pathSpec) || [];
|
|
@@ -28055,8 +28085,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
|
|
|
28055
28085
|
function forEachLineWithContent(input, callback) {
|
|
28056
28086
|
return toLinesWithContent(input, true).map((line) => callback(line));
|
|
28057
28087
|
}
|
|
28058
|
-
function folderExists(
|
|
28059
|
-
return (0, import_file_exists.exists)(
|
|
28088
|
+
function folderExists(path46) {
|
|
28089
|
+
return (0, import_file_exists.exists)(path46, import_file_exists.FOLDER);
|
|
28060
28090
|
}
|
|
28061
28091
|
function append(target, item) {
|
|
28062
28092
|
if (Array.isArray(target)) {
|
|
@@ -28460,8 +28490,8 @@ function checkIsRepoRootTask() {
|
|
|
28460
28490
|
commands,
|
|
28461
28491
|
format: "utf-8",
|
|
28462
28492
|
onError,
|
|
28463
|
-
parser(
|
|
28464
|
-
return /^\.(git)?$/.test(
|
|
28493
|
+
parser(path46) {
|
|
28494
|
+
return /^\.(git)?$/.test(path46.trim());
|
|
28465
28495
|
}
|
|
28466
28496
|
};
|
|
28467
28497
|
}
|
|
@@ -28895,11 +28925,11 @@ function parseGrep(grep) {
|
|
|
28895
28925
|
const paths = /* @__PURE__ */ new Set();
|
|
28896
28926
|
const results = {};
|
|
28897
28927
|
forEachLineWithContent(grep, (input) => {
|
|
28898
|
-
const [
|
|
28899
|
-
paths.add(
|
|
28900
|
-
(results[
|
|
28928
|
+
const [path46, line, preview] = input.split(NULL);
|
|
28929
|
+
paths.add(path46);
|
|
28930
|
+
(results[path46] = results[path46] || []).push({
|
|
28901
28931
|
line: asNumber(line),
|
|
28902
|
-
path:
|
|
28932
|
+
path: path46,
|
|
28903
28933
|
preview
|
|
28904
28934
|
});
|
|
28905
28935
|
});
|
|
@@ -29664,14 +29694,14 @@ var init_hash_object = __esm2({
|
|
|
29664
29694
|
init_task();
|
|
29665
29695
|
}
|
|
29666
29696
|
});
|
|
29667
|
-
function parseInit(bare,
|
|
29697
|
+
function parseInit(bare, path46, text) {
|
|
29668
29698
|
const response = String(text).trim();
|
|
29669
29699
|
let result;
|
|
29670
29700
|
if (result = initResponseRegex.exec(response)) {
|
|
29671
|
-
return new InitSummary(bare,
|
|
29701
|
+
return new InitSummary(bare, path46, false, result[1]);
|
|
29672
29702
|
}
|
|
29673
29703
|
if (result = reInitResponseRegex.exec(response)) {
|
|
29674
|
-
return new InitSummary(bare,
|
|
29704
|
+
return new InitSummary(bare, path46, true, result[1]);
|
|
29675
29705
|
}
|
|
29676
29706
|
let gitDir = "";
|
|
29677
29707
|
const tokens = response.split(" ");
|
|
@@ -29682,7 +29712,7 @@ function parseInit(bare, path44, text) {
|
|
|
29682
29712
|
break;
|
|
29683
29713
|
}
|
|
29684
29714
|
}
|
|
29685
|
-
return new InitSummary(bare,
|
|
29715
|
+
return new InitSummary(bare, path46, /^re/i.test(response), gitDir);
|
|
29686
29716
|
}
|
|
29687
29717
|
var InitSummary;
|
|
29688
29718
|
var initResponseRegex;
|
|
@@ -29691,9 +29721,9 @@ var init_InitSummary = __esm2({
|
|
|
29691
29721
|
"src/lib/responses/InitSummary.ts"() {
|
|
29692
29722
|
"use strict";
|
|
29693
29723
|
InitSummary = class {
|
|
29694
|
-
constructor(bare,
|
|
29724
|
+
constructor(bare, path46, existing, gitDir) {
|
|
29695
29725
|
this.bare = bare;
|
|
29696
|
-
this.path =
|
|
29726
|
+
this.path = path46;
|
|
29697
29727
|
this.existing = existing;
|
|
29698
29728
|
this.gitDir = gitDir;
|
|
29699
29729
|
}
|
|
@@ -29705,7 +29735,7 @@ var init_InitSummary = __esm2({
|
|
|
29705
29735
|
function hasBareCommand(command) {
|
|
29706
29736
|
return command.includes(bareCommand);
|
|
29707
29737
|
}
|
|
29708
|
-
function initTask(bare = false,
|
|
29738
|
+
function initTask(bare = false, path46, customArgs) {
|
|
29709
29739
|
const commands = ["init", ...customArgs];
|
|
29710
29740
|
if (bare && !hasBareCommand(commands)) {
|
|
29711
29741
|
commands.splice(1, 0, bareCommand);
|
|
@@ -29714,7 +29744,7 @@ function initTask(bare = false, path44, customArgs) {
|
|
|
29714
29744
|
commands,
|
|
29715
29745
|
format: "utf-8",
|
|
29716
29746
|
parser(text) {
|
|
29717
|
-
return parseInit(commands.includes("--bare"),
|
|
29747
|
+
return parseInit(commands.includes("--bare"), path46, text);
|
|
29718
29748
|
}
|
|
29719
29749
|
};
|
|
29720
29750
|
}
|
|
@@ -30530,12 +30560,12 @@ var init_FileStatusSummary = __esm2({
|
|
|
30530
30560
|
"use strict";
|
|
30531
30561
|
fromPathRegex = /^(.+)\0(.+)$/;
|
|
30532
30562
|
FileStatusSummary = class {
|
|
30533
|
-
constructor(
|
|
30534
|
-
this.path =
|
|
30563
|
+
constructor(path46, index, working_dir) {
|
|
30564
|
+
this.path = path46;
|
|
30535
30565
|
this.index = index;
|
|
30536
30566
|
this.working_dir = working_dir;
|
|
30537
30567
|
if (index === "R" || working_dir === "R") {
|
|
30538
|
-
const detail = fromPathRegex.exec(
|
|
30568
|
+
const detail = fromPathRegex.exec(path46) || [null, path46, path46];
|
|
30539
30569
|
this.from = detail[2] || "";
|
|
30540
30570
|
this.path = detail[1] || "";
|
|
30541
30571
|
}
|
|
@@ -30566,14 +30596,14 @@ function splitLine(result, lineStr) {
|
|
|
30566
30596
|
default:
|
|
30567
30597
|
return;
|
|
30568
30598
|
}
|
|
30569
|
-
function data(index, workingDir,
|
|
30599
|
+
function data(index, workingDir, path46) {
|
|
30570
30600
|
const raw = `${index}${workingDir}`;
|
|
30571
30601
|
const handler = parsers6.get(raw);
|
|
30572
30602
|
if (handler) {
|
|
30573
|
-
handler(result,
|
|
30603
|
+
handler(result, path46);
|
|
30574
30604
|
}
|
|
30575
30605
|
if (raw !== "##" && raw !== "!!") {
|
|
30576
|
-
result.files.push(new FileStatusSummary(
|
|
30606
|
+
result.files.push(new FileStatusSummary(path46, index, workingDir));
|
|
30577
30607
|
}
|
|
30578
30608
|
}
|
|
30579
30609
|
}
|
|
@@ -30882,9 +30912,9 @@ var init_simple_git_api = __esm2({
|
|
|
30882
30912
|
next
|
|
30883
30913
|
);
|
|
30884
30914
|
}
|
|
30885
|
-
hashObject(
|
|
30915
|
+
hashObject(path46, write) {
|
|
30886
30916
|
return this._runTask(
|
|
30887
|
-
hashObjectTask(
|
|
30917
|
+
hashObjectTask(path46, write === true),
|
|
30888
30918
|
trailingFunctionArgument(arguments)
|
|
30889
30919
|
);
|
|
30890
30920
|
}
|
|
@@ -31237,8 +31267,8 @@ var init_branch = __esm2({
|
|
|
31237
31267
|
}
|
|
31238
31268
|
});
|
|
31239
31269
|
function toPath(input) {
|
|
31240
|
-
const
|
|
31241
|
-
return
|
|
31270
|
+
const path46 = input.trim().replace(/^["']|["']$/g, "");
|
|
31271
|
+
return path46 && normalize3(path46);
|
|
31242
31272
|
}
|
|
31243
31273
|
var parseCheckIgnore;
|
|
31244
31274
|
var init_CheckIgnore = __esm2({
|
|
@@ -31552,8 +31582,8 @@ __export2(sub_module_exports, {
|
|
|
31552
31582
|
subModuleTask: () => subModuleTask,
|
|
31553
31583
|
updateSubModuleTask: () => updateSubModuleTask
|
|
31554
31584
|
});
|
|
31555
|
-
function addSubModuleTask(repo,
|
|
31556
|
-
return subModuleTask(["add", repo,
|
|
31585
|
+
function addSubModuleTask(repo, path46) {
|
|
31586
|
+
return subModuleTask(["add", repo, path46]);
|
|
31557
31587
|
}
|
|
31558
31588
|
function initSubModuleTask(customArgs) {
|
|
31559
31589
|
return subModuleTask(["init", ...customArgs]);
|
|
@@ -31886,8 +31916,8 @@ var require_git = __commonJS2({
|
|
|
31886
31916
|
}
|
|
31887
31917
|
return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
|
|
31888
31918
|
};
|
|
31889
|
-
Git2.prototype.submoduleAdd = function(repo,
|
|
31890
|
-
return this._runTask(addSubModuleTask2(repo,
|
|
31919
|
+
Git2.prototype.submoduleAdd = function(repo, path46, then) {
|
|
31920
|
+
return this._runTask(addSubModuleTask2(repo, path46), trailingFunctionArgument2(arguments));
|
|
31891
31921
|
};
|
|
31892
31922
|
Git2.prototype.submoduleUpdate = function(args, then) {
|
|
31893
31923
|
return this._runTask(
|
|
@@ -32850,12 +32880,12 @@ async function collectTurnGitDiffFromPreTurnSnapshot(options) {
|
|
|
32850
32880
|
// src/agents/acp/put-summarize-change-summaries.ts
|
|
32851
32881
|
async function putEncryptedChangeSummaryRows(params) {
|
|
32852
32882
|
const base = params.apiBaseUrl.replace(/\/+$/, "");
|
|
32853
|
-
const entries = params.rows.map(({ path:
|
|
32883
|
+
const entries = params.rows.map(({ path: path46, summary }) => {
|
|
32854
32884
|
const enc = params.e2ee.encryptFields({ summary }, ["summary"]);
|
|
32855
|
-
return { path:
|
|
32885
|
+
return { path: path46, summary: JSON.stringify(enc) };
|
|
32856
32886
|
});
|
|
32857
32887
|
const res = await fetch(
|
|
32858
|
-
`${base}/
|
|
32888
|
+
`${base}/internal/sessions/${encodeURIComponent(params.sessionId)}/follow-ups/summarize-changes`,
|
|
32859
32889
|
{
|
|
32860
32890
|
method: "PUT",
|
|
32861
32891
|
headers: {
|
|
@@ -33020,8 +33050,8 @@ async function fetchSessionAttachmentPayloadsForAgent(params) {
|
|
|
33020
33050
|
for (const a of attachments) {
|
|
33021
33051
|
const id = typeof a.attachmentId === "string" ? a.attachmentId.trim() : "";
|
|
33022
33052
|
if (!id) continue;
|
|
33023
|
-
const metaUrl = `${base}/
|
|
33024
|
-
const blobUrl = `${base}/
|
|
33053
|
+
const metaUrl = `${base}/internal/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/meta`;
|
|
33054
|
+
const blobUrl = `${base}/internal/sessions/${encodeURIComponent(sessionId)}/attachments/${encodeURIComponent(id)}/blob`;
|
|
33025
33055
|
const metaRes = await fetch(metaUrl, { headers: { Authorization: `Bearer ${token}` } });
|
|
33026
33056
|
if (!metaRes.ok) {
|
|
33027
33057
|
const t = await metaRes.text().catch(() => "");
|
|
@@ -33069,6 +33099,106 @@ async function fetchSessionAttachmentPayloadsForAgent(params) {
|
|
|
33069
33099
|
return { ok: true, images: out };
|
|
33070
33100
|
}
|
|
33071
33101
|
|
|
33102
|
+
// src/agents/acp/build-forked-session-agent-prompt.ts
|
|
33103
|
+
function buildForkedSessionAgentPrompt(userPrompt, childSessionId, parentSessionId) {
|
|
33104
|
+
const childRef = childSessionId.trim();
|
|
33105
|
+
const parentRef = parentSessionId.trim();
|
|
33106
|
+
return [
|
|
33107
|
+
"You are working in a new session that was forked from a prior session.",
|
|
33108
|
+
`This forked session id: ${childRef}`,
|
|
33109
|
+
`Parent session id: ${parentRef}`,
|
|
33110
|
+
"",
|
|
33111
|
+
"The parent session history is available through MCP tools on the buildautomaton-bridge server:",
|
|
33112
|
+
"- list_parent_session_prompts \u2014 list each user prompt / turn in the parent session",
|
|
33113
|
+
"- get_parent_session_turn_transcript \u2014 full transcript for one turn (including tool calls); requires turnId",
|
|
33114
|
+
"",
|
|
33115
|
+
"When calling these tools, always pass this forked session id as sessionId (not the parent session id).",
|
|
33116
|
+
"",
|
|
33117
|
+
"Use these tools when you need prior context instead of guessing.",
|
|
33118
|
+
"",
|
|
33119
|
+
"User request:",
|
|
33120
|
+
userPrompt.trim()
|
|
33121
|
+
].join("\n");
|
|
33122
|
+
}
|
|
33123
|
+
|
|
33124
|
+
// src/mcp/tools/session-history/fetch-parent-session-cloud.ts
|
|
33125
|
+
function internalApiBase(cloudApiBaseUrl) {
|
|
33126
|
+
return cloudApiBaseUrl.replace(/\/+$/, "");
|
|
33127
|
+
}
|
|
33128
|
+
async function fetchCloudSessionMeta(params) {
|
|
33129
|
+
const token = params.getCloudAccessToken();
|
|
33130
|
+
if (!token) return { ok: false, error: "Missing cloud access token." };
|
|
33131
|
+
const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.sessionId)}/meta`;
|
|
33132
|
+
const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
|
|
33133
|
+
if (!res.ok) {
|
|
33134
|
+
const t = await res.text().catch(() => "");
|
|
33135
|
+
return { ok: false, error: `Session meta fetch failed (${res.status}): ${t.slice(0, 200)}` };
|
|
33136
|
+
}
|
|
33137
|
+
const data = await res.json().catch(() => null);
|
|
33138
|
+
if (!data) return { ok: false, error: "Invalid session meta response." };
|
|
33139
|
+
return { ok: true, data };
|
|
33140
|
+
}
|
|
33141
|
+
async function fetchCloudParentSessionPrompts(params) {
|
|
33142
|
+
const token = params.getCloudAccessToken();
|
|
33143
|
+
if (!token) return { ok: false, error: "Missing cloud access token." };
|
|
33144
|
+
const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/prompts`;
|
|
33145
|
+
const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
|
|
33146
|
+
if (!res.ok) {
|
|
33147
|
+
const t = await res.text().catch(() => "");
|
|
33148
|
+
return { ok: false, error: `Parent prompts fetch failed (${res.status}): ${t.slice(0, 200)}` };
|
|
33149
|
+
}
|
|
33150
|
+
const data = await res.json().catch(() => null);
|
|
33151
|
+
if (!data) return { ok: false, error: "Invalid parent prompts response." };
|
|
33152
|
+
return { ok: true, data };
|
|
33153
|
+
}
|
|
33154
|
+
async function fetchCloudParentTurnTranscript(params) {
|
|
33155
|
+
const token = params.getCloudAccessToken();
|
|
33156
|
+
if (!token) return { ok: false, error: "Missing cloud access token." };
|
|
33157
|
+
const url2 = `${internalApiBase(params.cloudApiBaseUrl)}/internal/sessions/${encodeURIComponent(params.childSessionId)}/parent/turns/${encodeURIComponent(params.turnId)}/transcript`;
|
|
33158
|
+
const res = await fetch(url2, { headers: { Authorization: `Bearer ${token}` } });
|
|
33159
|
+
if (!res.ok) {
|
|
33160
|
+
const t = await res.text().catch(() => "");
|
|
33161
|
+
return { ok: false, error: `Transcript fetch failed (${res.status}): ${t.slice(0, 200)}` };
|
|
33162
|
+
}
|
|
33163
|
+
const data = await res.json().catch(() => null);
|
|
33164
|
+
const rows = Array.isArray(data?.transcript) ? data.transcript : [];
|
|
33165
|
+
const lines = rows.map((row) => {
|
|
33166
|
+
const kind = typeof row.kind === "string" ? row.kind : "event";
|
|
33167
|
+
const payload = typeof row.payload === "string" ? row.payload : JSON.stringify(row.payload ?? "");
|
|
33168
|
+
return `[${kind}] ${payload}`;
|
|
33169
|
+
});
|
|
33170
|
+
return { ok: true, text: lines.join("\n") };
|
|
33171
|
+
}
|
|
33172
|
+
async function resolveParentSessionIdForChild(params) {
|
|
33173
|
+
const meta = await fetchCloudSessionMeta({
|
|
33174
|
+
sessionId: params.childSessionId,
|
|
33175
|
+
cloudApiBaseUrl: params.cloudApiBaseUrl,
|
|
33176
|
+
getCloudAccessToken: params.getCloudAccessToken
|
|
33177
|
+
});
|
|
33178
|
+
if (!meta.ok) return meta;
|
|
33179
|
+
const parent = meta.data.parentSessionId?.trim() ?? "";
|
|
33180
|
+
if (!parent) {
|
|
33181
|
+
return {
|
|
33182
|
+
ok: false,
|
|
33183
|
+
error: `Session ${params.childSessionId} has no parent session history. It was not forked from another session (no parent_session_id). Pass the forked child session id as sessionId, not the parent session id.`
|
|
33184
|
+
};
|
|
33185
|
+
}
|
|
33186
|
+
return { ok: true, parentSessionId: parent };
|
|
33187
|
+
}
|
|
33188
|
+
|
|
33189
|
+
// src/agents/acp/enrich-forked-session-prompt-for-agent.ts
|
|
33190
|
+
async function enrichForkedSessionPromptForAgent(params) {
|
|
33191
|
+
const meta = await fetchCloudSessionMeta({
|
|
33192
|
+
sessionId: params.sessionId,
|
|
33193
|
+
cloudApiBaseUrl: params.cloudApiBaseUrl,
|
|
33194
|
+
getCloudAccessToken: params.getCloudAccessToken
|
|
33195
|
+
});
|
|
33196
|
+
if (!meta.ok) return params.promptText;
|
|
33197
|
+
const parentSessionId = meta.data.parentSessionId?.trim() ?? "";
|
|
33198
|
+
if (!parentSessionId) return params.promptText;
|
|
33199
|
+
return buildForkedSessionAgentPrompt(params.promptText, params.sessionId, parentSessionId);
|
|
33200
|
+
}
|
|
33201
|
+
|
|
33072
33202
|
// src/agents/acp/send-prompt-to-agent.ts
|
|
33073
33203
|
async function sendPromptToAgent(options) {
|
|
33074
33204
|
const {
|
|
@@ -33090,6 +33220,15 @@ async function sendPromptToAgent(options) {
|
|
|
33090
33220
|
attachments
|
|
33091
33221
|
} = options;
|
|
33092
33222
|
try {
|
|
33223
|
+
let agentPromptText = promptText;
|
|
33224
|
+
if (sessionId && cloudApiBaseUrl && getCloudAccessToken) {
|
|
33225
|
+
agentPromptText = await enrichForkedSessionPromptForAgent({
|
|
33226
|
+
sessionId,
|
|
33227
|
+
promptText,
|
|
33228
|
+
cloudApiBaseUrl,
|
|
33229
|
+
getCloudAccessToken
|
|
33230
|
+
});
|
|
33231
|
+
}
|
|
33093
33232
|
let sendOpts = {};
|
|
33094
33233
|
if (attachments && attachments.length > 0) {
|
|
33095
33234
|
if (!sessionId || !cloudApiBaseUrl || !getCloudAccessToken) {
|
|
@@ -33128,7 +33267,7 @@ async function sendPromptToAgent(options) {
|
|
|
33128
33267
|
}
|
|
33129
33268
|
sendOpts = { images: resolved.images };
|
|
33130
33269
|
}
|
|
33131
|
-
const result = await handle.sendPrompt(
|
|
33270
|
+
const result = await handle.sendPrompt(agentPromptText, sendOpts);
|
|
33132
33271
|
if (sessionId && runId && sendSessionUpdate && agentCwd && result.success) {
|
|
33133
33272
|
await collectTurnGitDiffFromPreTurnSnapshot({
|
|
33134
33273
|
sessionId,
|
|
@@ -33252,6 +33391,7 @@ function handlePrompt(ctx, opts) {
|
|
|
33252
33391
|
sessionParentPath,
|
|
33253
33392
|
resolveRouting: () => ctx.promptRouting.resolveRouting(activeAcpSessionAgentKey),
|
|
33254
33393
|
cloudSessionId: sessionId,
|
|
33394
|
+
bridgeAccessPort: ctx.getBridgeAccessPort(),
|
|
33255
33395
|
sendSessionUpdate,
|
|
33256
33396
|
sendRequest: sendSessionUpdate,
|
|
33257
33397
|
log: ctx.log,
|
|
@@ -33338,6 +33478,7 @@ function logPromptReceivedFromBridge(ctx, opts) {
|
|
|
33338
33478
|
async function createAcpManager(options) {
|
|
33339
33479
|
const ctx = createAcpManagerContext({
|
|
33340
33480
|
log: options.log,
|
|
33481
|
+
getBridgeAccessPort: options.getBridgeAccessPort,
|
|
33341
33482
|
reportAgentCapabilities: options.reportAgentCapabilities
|
|
33342
33483
|
});
|
|
33343
33484
|
return {
|
|
@@ -33361,7 +33502,7 @@ async function createAcpManager(options) {
|
|
|
33361
33502
|
// src/git/changes/types.ts
|
|
33362
33503
|
var MAX_PATCH_CHARS = 35e4;
|
|
33363
33504
|
|
|
33364
|
-
// src/git/changes/
|
|
33505
|
+
// src/git/changes/paths/repo-format.ts
|
|
33365
33506
|
function posixJoinDirFile(dir, file2) {
|
|
33366
33507
|
const d = dir === "." || dir === "" ? "" : dir.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
33367
33508
|
const f = file2.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
@@ -33416,7 +33557,7 @@ function formatRemoteDisplayLabel(remoteUrl) {
|
|
|
33416
33557
|
}
|
|
33417
33558
|
|
|
33418
33559
|
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
33419
|
-
import * as
|
|
33560
|
+
import * as path22 from "node:path";
|
|
33420
33561
|
|
|
33421
33562
|
// src/git/commits/resolve-remote-tracking.ts
|
|
33422
33563
|
async function tryConfigGet(g, key) {
|
|
@@ -33586,9 +33727,232 @@ async function listRecentCommits(repoDir, limitInput) {
|
|
|
33586
33727
|
}
|
|
33587
33728
|
}
|
|
33588
33729
|
|
|
33589
|
-
// src/git/changes/
|
|
33590
|
-
function
|
|
33591
|
-
|
|
33730
|
+
// src/git/changes/parse/normalize-git-diff-path.ts
|
|
33731
|
+
function normalizeGitDiffPath(path46) {
|
|
33732
|
+
return path46.replace(/\\/g, "/").replace(/\/ +/g, "/").trim();
|
|
33733
|
+
}
|
|
33734
|
+
|
|
33735
|
+
// src/git/changes/parse/expand-git-rename-numstat-path.ts
|
|
33736
|
+
function expandGitRenameNumstatPath(rawPath) {
|
|
33737
|
+
const open2 = rawPath.indexOf("{");
|
|
33738
|
+
const arrow = rawPath.indexOf("=>");
|
|
33739
|
+
const close = rawPath.lastIndexOf("}");
|
|
33740
|
+
if (open2 === -1 || arrow === -1 || close === -1 || open2 > arrow || arrow > close) {
|
|
33741
|
+
return null;
|
|
33742
|
+
}
|
|
33743
|
+
const prefix = rawPath.slice(0, open2);
|
|
33744
|
+
const suffix = rawPath.slice(close + 1);
|
|
33745
|
+
const oldPart = rawPath.slice(open2 + 1, arrow).trim();
|
|
33746
|
+
const newPart = rawPath.slice(arrow + 2, close).trim();
|
|
33747
|
+
return {
|
|
33748
|
+
oldPath: normalizeGitDiffPath(`${prefix}${oldPart}${suffix}`),
|
|
33749
|
+
newPath: normalizeGitDiffPath(`${prefix}${newPart}${suffix}`)
|
|
33750
|
+
};
|
|
33751
|
+
}
|
|
33752
|
+
function isGitRenameNumstatPath(rawPath) {
|
|
33753
|
+
return expandGitRenameNumstatPath(rawPath) != null;
|
|
33754
|
+
}
|
|
33755
|
+
|
|
33756
|
+
// src/git/changes/rows/build-changed-file-row.ts
|
|
33757
|
+
function buildChangedFileRow(options) {
|
|
33758
|
+
const pathInRepo = normalizeGitDiffPath(options.pathInRepo);
|
|
33759
|
+
const relLauncher = posixJoinDirFile(options.repoRelPath, pathInRepo);
|
|
33760
|
+
const additions = options.numEntry?.additions ?? 0;
|
|
33761
|
+
const deletions = options.numEntry?.deletions ?? 0;
|
|
33762
|
+
let change = options.nameEntry?.change ?? "modified";
|
|
33763
|
+
let movedFromPathRelLauncher;
|
|
33764
|
+
let movedFromPathInRepo;
|
|
33765
|
+
const oldPathInRepo = options.nameEntry?.oldPathInRepo ?? options.numEntry?.oldPathInRepo;
|
|
33766
|
+
if (change === "moved" && oldPathInRepo) {
|
|
33767
|
+
movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
|
|
33768
|
+
movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
|
|
33769
|
+
} else if (oldPathInRepo && change === "modified") {
|
|
33770
|
+
change = "moved";
|
|
33771
|
+
movedFromPathInRepo = normalizeGitDiffPath(oldPathInRepo);
|
|
33772
|
+
movedFromPathRelLauncher = posixJoinDirFile(options.repoRelPath, movedFromPathInRepo);
|
|
33773
|
+
}
|
|
33774
|
+
if (options.untracked && !options.nameEntry) {
|
|
33775
|
+
change = "added";
|
|
33776
|
+
} else if (!options.nameEntry && options.numEntry && change !== "moved") {
|
|
33777
|
+
if (additions > 0 && deletions === 0) change = "added";
|
|
33778
|
+
else if (deletions > 0 && additions === 0) change = "removed";
|
|
33779
|
+
else change = "modified";
|
|
33780
|
+
}
|
|
33781
|
+
return {
|
|
33782
|
+
pathRelLauncher: relLauncher,
|
|
33783
|
+
additions,
|
|
33784
|
+
deletions,
|
|
33785
|
+
change,
|
|
33786
|
+
...movedFromPathRelLauncher ? { movedFromPathRelLauncher } : {},
|
|
33787
|
+
...movedFromPathInRepo ? { movedFromPathInRepo } : {}
|
|
33788
|
+
};
|
|
33789
|
+
}
|
|
33790
|
+
|
|
33791
|
+
// src/git/changes/listing/build-changed-file-rows.ts
|
|
33792
|
+
async function buildChangedFileRowsFromPaths(options) {
|
|
33793
|
+
const rows = [];
|
|
33794
|
+
await forEachWithGitYield([...options.paths], async (pathInRepo) => {
|
|
33795
|
+
if (isGitRenameNumstatPath(pathInRepo)) return;
|
|
33796
|
+
if (options.movedSourcePaths.has(pathInRepo)) return;
|
|
33797
|
+
const nameEntry = options.nameByPath.get(pathInRepo);
|
|
33798
|
+
const numEntry = options.numByPath.get(pathInRepo);
|
|
33799
|
+
const row = buildChangedFileRow({
|
|
33800
|
+
pathInRepo,
|
|
33801
|
+
repoRelPath: options.repoRelPath,
|
|
33802
|
+
nameEntry,
|
|
33803
|
+
numEntry,
|
|
33804
|
+
untracked: options.untrackedSet?.has(pathInRepo)
|
|
33805
|
+
});
|
|
33806
|
+
if (options.applyUntrackedStats) {
|
|
33807
|
+
await options.applyUntrackedStats(row, pathInRepo);
|
|
33808
|
+
}
|
|
33809
|
+
rows.push(row);
|
|
33810
|
+
});
|
|
33811
|
+
return rows;
|
|
33812
|
+
}
|
|
33813
|
+
|
|
33814
|
+
// src/git/changes/patch/patch-truncate.ts
|
|
33815
|
+
function truncatePatch(s) {
|
|
33816
|
+
if (s.length <= MAX_PATCH_CHARS) return s;
|
|
33817
|
+
return `${s.slice(0, MAX_PATCH_CHARS)}
|
|
33818
|
+
|
|
33819
|
+
\u2026 (diff truncated)`;
|
|
33820
|
+
}
|
|
33821
|
+
|
|
33822
|
+
// src/git/changes/patch/unified-diff-for-file.ts
|
|
33823
|
+
function patchTextFromGitDiffOutput(raw) {
|
|
33824
|
+
if (raw.trim() === "") return void 0;
|
|
33825
|
+
return normalizePatchContent(raw);
|
|
33826
|
+
}
|
|
33827
|
+
async function unifiedDiffForFile(repoCwd, pathInRepo, change, movedFromPathInRepo) {
|
|
33828
|
+
const g = cliSimpleGit(repoCwd);
|
|
33829
|
+
const renameArgs = ["-M", "--find-renames"];
|
|
33830
|
+
const args = change === "moved" && movedFromPathInRepo ? ["diff", "--no-color", ...renameArgs, "HEAD", "--", movedFromPathInRepo, pathInRepo] : change === "removed" ? ["diff", "--no-color", ...renameArgs, "HEAD", "--", pathInRepo] : ["diff", "--no-color", ...renameArgs, "HEAD", "--", pathInRepo];
|
|
33831
|
+
const raw = await g.raw([...args]).catch(() => "");
|
|
33832
|
+
const patch = patchTextFromGitDiffOutput(String(raw));
|
|
33833
|
+
return patch ? truncatePatch(patch) : void 0;
|
|
33834
|
+
}
|
|
33835
|
+
async function unifiedDiffForFileInRange(repoCwd, range, pathInRepo, change, movedFromPathInRepo) {
|
|
33836
|
+
const g = cliSimpleGit(repoCwd);
|
|
33837
|
+
const renameArgs = ["-M", "--find-renames"];
|
|
33838
|
+
const args = change === "moved" && movedFromPathInRepo ? ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", movedFromPathInRepo, pathInRepo] : ["diff", "--no-color", ...renameArgs, "-U20000", range, "--", pathInRepo];
|
|
33839
|
+
const raw = await g.raw([...args]).catch(() => "");
|
|
33840
|
+
const patch = patchTextFromGitDiffOutput(String(raw));
|
|
33841
|
+
return patch ? truncatePatch(patch) : void 0;
|
|
33842
|
+
}
|
|
33843
|
+
|
|
33844
|
+
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
33845
|
+
import * as fs16 from "node:fs";
|
|
33846
|
+
import * as path19 from "node:path";
|
|
33847
|
+
|
|
33848
|
+
// src/git/changes/lines/count-lines.ts
|
|
33849
|
+
import { createReadStream } from "node:fs";
|
|
33850
|
+
import * as readline2 from "node:readline";
|
|
33851
|
+
function countLinesInText(text) {
|
|
33852
|
+
return splitTextIntoDiffLines(text).length;
|
|
33853
|
+
}
|
|
33854
|
+
async function countTextFileLines(filePath) {
|
|
33855
|
+
let bytes = 0;
|
|
33856
|
+
const maxBytes = 512e3;
|
|
33857
|
+
let lines = 0;
|
|
33858
|
+
const stream = createReadStream(filePath, { encoding: "utf8" });
|
|
33859
|
+
const rl = readline2.createInterface({ input: stream, crlfDelay: Infinity });
|
|
33860
|
+
for await (const _line of rl) {
|
|
33861
|
+
lines += 1;
|
|
33862
|
+
bytes += Buffer.byteLength(String(_line), "utf8") + 1;
|
|
33863
|
+
if (bytes > maxBytes) {
|
|
33864
|
+
rl.close();
|
|
33865
|
+
stream.destroy();
|
|
33866
|
+
return lines;
|
|
33867
|
+
}
|
|
33868
|
+
}
|
|
33869
|
+
return lines;
|
|
33870
|
+
}
|
|
33871
|
+
|
|
33872
|
+
// src/git/changes/total-lines/resolve-changed-file-total-lines.ts
|
|
33873
|
+
var MAX_BYTES = 512e3;
|
|
33874
|
+
async function countLinesInGitRef(repoGitCwd, ref, pathInRepo) {
|
|
33875
|
+
const spec = `${ref}:${pathInRepo}`;
|
|
33876
|
+
const g = cliSimpleGit(repoGitCwd);
|
|
33877
|
+
try {
|
|
33878
|
+
await g.raw(["cat-file", "-e", spec]);
|
|
33879
|
+
} catch {
|
|
33880
|
+
return null;
|
|
33881
|
+
}
|
|
33882
|
+
try {
|
|
33883
|
+
const raw = String(await g.raw(["show", spec]));
|
|
33884
|
+
const capped = raw.length > MAX_BYTES ? raw.slice(0, MAX_BYTES) : raw;
|
|
33885
|
+
return countLinesInText(capped);
|
|
33886
|
+
} catch {
|
|
33887
|
+
return null;
|
|
33888
|
+
}
|
|
33889
|
+
}
|
|
33890
|
+
async function resolveWorkingTreeFileTotalLines(options) {
|
|
33891
|
+
if (options.isBinary) return null;
|
|
33892
|
+
const filePath = path19.join(options.repoGitCwd, options.pathInRepo);
|
|
33893
|
+
if (options.change === "removed") {
|
|
33894
|
+
return countLinesInGitRef(options.repoGitCwd, "HEAD", options.pathInRepo);
|
|
33895
|
+
}
|
|
33896
|
+
if (options.change === "moved" || options.change === "modified") {
|
|
33897
|
+
try {
|
|
33898
|
+
const st = await fs16.promises.stat(filePath);
|
|
33899
|
+
if (!st.isFile()) return null;
|
|
33900
|
+
return await countTextFileLines(filePath);
|
|
33901
|
+
} catch {
|
|
33902
|
+
return null;
|
|
33903
|
+
}
|
|
33904
|
+
}
|
|
33905
|
+
return null;
|
|
33906
|
+
}
|
|
33907
|
+
async function resolveCommitFileTotalLines(options) {
|
|
33908
|
+
if (options.isBinary) return null;
|
|
33909
|
+
if (options.change === "removed") {
|
|
33910
|
+
return countLinesInGitRef(options.repoGitCwd, options.parentSha, options.pathInRepo);
|
|
33911
|
+
}
|
|
33912
|
+
if (options.change === "moved" || options.change === "modified") {
|
|
33913
|
+
return countLinesInGitRef(options.repoGitCwd, options.commitSha, options.pathInRepo);
|
|
33914
|
+
}
|
|
33915
|
+
return null;
|
|
33916
|
+
}
|
|
33917
|
+
|
|
33918
|
+
// src/git/changes/listing/path-in-repo-from-launcher.ts
|
|
33919
|
+
function pathInRepoFromLauncher(pathRelLauncher, repoRelPath) {
|
|
33920
|
+
const normRel = repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
33921
|
+
if (normRel === ".") return pathRelLauncher;
|
|
33922
|
+
if (pathRelLauncher.startsWith(`${normRel}/`)) {
|
|
33923
|
+
return pathRelLauncher.slice(normRel.length + 1);
|
|
33924
|
+
}
|
|
33925
|
+
return pathRelLauncher;
|
|
33926
|
+
}
|
|
33927
|
+
function normalizeRepoRelPath(repoRelPath) {
|
|
33928
|
+
return repoRelPath === "." || repoRelPath === "" ? "." : repoRelPath;
|
|
33929
|
+
}
|
|
33930
|
+
|
|
33931
|
+
// src/git/changes/listing/enrich-commit-file-rows.ts
|
|
33932
|
+
async function enrichCommitFileRows(options) {
|
|
33933
|
+
await forEachWithGitYield(options.rows, async (row) => {
|
|
33934
|
+
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
33935
|
+
row.patchContent = await unifiedDiffForFileInRange(
|
|
33936
|
+
options.repoGitCwd,
|
|
33937
|
+
options.range,
|
|
33938
|
+
pathInRepo,
|
|
33939
|
+
row.change,
|
|
33940
|
+
row.movedFromPathInRepo
|
|
33941
|
+
);
|
|
33942
|
+
row.totalLines = await resolveCommitFileTotalLines({
|
|
33943
|
+
repoGitCwd: options.repoGitCwd,
|
|
33944
|
+
pathInRepo,
|
|
33945
|
+
change: row.change,
|
|
33946
|
+
commitSha: options.commitSha,
|
|
33947
|
+
parentSha: options.parentSha,
|
|
33948
|
+
isBinary: options.binaryByPath.has(pathInRepo)
|
|
33949
|
+
});
|
|
33950
|
+
});
|
|
33951
|
+
}
|
|
33952
|
+
|
|
33953
|
+
// src/git/changes/parse/parse-name-status-entries.ts
|
|
33954
|
+
function parseNameStatusEntries(lines) {
|
|
33955
|
+
const entries = [];
|
|
33592
33956
|
for (const line of lines) {
|
|
33593
33957
|
if (!line.trim()) continue;
|
|
33594
33958
|
const tabParts = line.split(" ");
|
|
@@ -33596,58 +33960,143 @@ function parseNameStatusLines(lines) {
|
|
|
33596
33960
|
const status = tabParts[0].trim();
|
|
33597
33961
|
const code = status[0];
|
|
33598
33962
|
if (code === "A") {
|
|
33599
|
-
|
|
33963
|
+
entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "added" });
|
|
33600
33964
|
} else if (code === "D") {
|
|
33601
|
-
|
|
33965
|
+
entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "removed" });
|
|
33602
33966
|
} else if (code === "R" || code === "C") {
|
|
33603
|
-
if (tabParts.length >= 3)
|
|
33967
|
+
if (tabParts.length >= 3) {
|
|
33968
|
+
entries.push({
|
|
33969
|
+
pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]),
|
|
33970
|
+
oldPathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 2]),
|
|
33971
|
+
change: "moved"
|
|
33972
|
+
});
|
|
33973
|
+
}
|
|
33604
33974
|
} else if (code === "M" || code === "U" || code === "T") {
|
|
33605
|
-
|
|
33975
|
+
entries.push({ pathInRepo: normalizeGitDiffPath(tabParts[tabParts.length - 1]), change: "modified" });
|
|
33606
33976
|
}
|
|
33607
33977
|
}
|
|
33978
|
+
return entries;
|
|
33979
|
+
}
|
|
33980
|
+
function parseNameStatusLines(lines) {
|
|
33981
|
+
const m = /* @__PURE__ */ new Map();
|
|
33982
|
+
for (const entry of parseNameStatusEntries(lines)) {
|
|
33983
|
+
m.set(entry.pathInRepo, entry.change);
|
|
33984
|
+
}
|
|
33608
33985
|
return m;
|
|
33609
33986
|
}
|
|
33610
|
-
|
|
33987
|
+
|
|
33988
|
+
// src/git/changes/parse/parse-numstat-entries.ts
|
|
33989
|
+
function parseNumstatCounts(parts) {
|
|
33990
|
+
const [a, d] = parts;
|
|
33991
|
+
return {
|
|
33992
|
+
additions: a === "-" ? 0 : parseInt(String(a), 10) || 0,
|
|
33993
|
+
deletions: d === "-" ? 0 : parseInt(String(d), 10) || 0
|
|
33994
|
+
};
|
|
33995
|
+
}
|
|
33996
|
+
function parseNumstatLine(line) {
|
|
33611
33997
|
const parts = line.split(" ");
|
|
33612
33998
|
if (parts.length < 3) return null;
|
|
33613
|
-
const
|
|
33614
|
-
const additions
|
|
33615
|
-
const
|
|
33616
|
-
|
|
33999
|
+
const rawPath = parts[parts.length - 1];
|
|
34000
|
+
const { additions, deletions } = parseNumstatCounts(parts);
|
|
34001
|
+
const expanded = expandGitRenameNumstatPath(rawPath);
|
|
34002
|
+
const pathInRepo = normalizeGitDiffPath(expanded?.newPath ?? rawPath);
|
|
34003
|
+
return {
|
|
34004
|
+
pathInRepo,
|
|
34005
|
+
additions,
|
|
34006
|
+
deletions,
|
|
34007
|
+
...expanded ? { oldPathInRepo: expanded.oldPath } : {}
|
|
34008
|
+
};
|
|
33617
34009
|
}
|
|
33618
|
-
function
|
|
34010
|
+
function parseNumstatEntries(lines) {
|
|
33619
34011
|
const m = /* @__PURE__ */ new Map();
|
|
33620
34012
|
for (const line of lines) {
|
|
33621
34013
|
if (!line.trim()) continue;
|
|
33622
34014
|
const parts = line.split(" ");
|
|
33623
34015
|
if (parts.length < 3) continue;
|
|
33624
|
-
const [
|
|
33625
|
-
const
|
|
33626
|
-
const
|
|
33627
|
-
|
|
34016
|
+
const rawPath = parts[parts.length - 1];
|
|
34017
|
+
const expanded = expandGitRenameNumstatPath(rawPath);
|
|
34018
|
+
const entry = parseNumstatLine(line);
|
|
34019
|
+
if (!entry) continue;
|
|
34020
|
+
const existing = m.get(entry.pathInRepo);
|
|
34021
|
+
if (!existing || expanded) {
|
|
34022
|
+
m.set(entry.pathInRepo, entry);
|
|
34023
|
+
}
|
|
33628
34024
|
}
|
|
33629
34025
|
return m;
|
|
33630
34026
|
}
|
|
34027
|
+
function parseNumstat(lines) {
|
|
34028
|
+
const m = /* @__PURE__ */ new Map();
|
|
34029
|
+
for (const [path46, entry] of parseNumstatEntries(lines)) {
|
|
34030
|
+
m.set(path46, { additions: entry.additions, deletions: entry.deletions });
|
|
34031
|
+
}
|
|
34032
|
+
return m;
|
|
34033
|
+
}
|
|
34034
|
+
|
|
34035
|
+
// src/git/changes/parse/numstat-from-git-no-index.ts
|
|
33631
34036
|
async function numstatFromGitNoIndex(g, pathInRepo) {
|
|
33632
34037
|
const devNull = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
33633
34038
|
try {
|
|
33634
34039
|
const out = await g.raw(["diff", "--numstat", "--no-index", "--", devNull, pathInRepo]);
|
|
33635
34040
|
const first2 = String(out).split("\n").find((l) => l.trim()) ?? "";
|
|
33636
|
-
|
|
34041
|
+
const parsed = parseNumstatLine(first2);
|
|
34042
|
+
if (!parsed) return null;
|
|
34043
|
+
return { additions: parsed.additions, deletions: parsed.deletions };
|
|
33637
34044
|
} catch {
|
|
33638
34045
|
return null;
|
|
33639
34046
|
}
|
|
33640
34047
|
}
|
|
33641
34048
|
|
|
33642
|
-
// src/git/changes/
|
|
33643
|
-
function
|
|
33644
|
-
|
|
33645
|
-
|
|
34049
|
+
// src/git/changes/rows/collect-moved-source-paths.ts
|
|
34050
|
+
function collectMovedSourcePaths(nameEntries, numByPath) {
|
|
34051
|
+
const sources = /* @__PURE__ */ new Set();
|
|
34052
|
+
for (const entry of nameEntries) {
|
|
34053
|
+
if (entry.change === "moved" && entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
|
|
34054
|
+
}
|
|
34055
|
+
for (const entry of numByPath.values()) {
|
|
34056
|
+
if (entry.oldPathInRepo) sources.add(entry.oldPathInRepo);
|
|
34057
|
+
}
|
|
34058
|
+
return sources;
|
|
34059
|
+
}
|
|
33646
34060
|
|
|
33647
|
-
|
|
34061
|
+
// src/git/changes/numstat/is-binary-numstat-line.ts
|
|
34062
|
+
function isBinaryNumstatLine(line) {
|
|
34063
|
+
const parts = line.split(" ");
|
|
34064
|
+
if (parts.length < 3) return false;
|
|
34065
|
+
return parts[0] === "-" || parts[1] === "-";
|
|
34066
|
+
}
|
|
34067
|
+
|
|
34068
|
+
// src/git/changes/listing/collect-binary-paths-from-numstat.ts
|
|
34069
|
+
function collectBinaryPathsFromNumstat(numstatRaw) {
|
|
34070
|
+
const binaryByPath = /* @__PURE__ */ new Set();
|
|
34071
|
+
for (const line of numstatRaw.split("\n")) {
|
|
34072
|
+
if (!line.trim()) continue;
|
|
34073
|
+
const parts = line.split(" ");
|
|
34074
|
+
if (parts.length < 3) continue;
|
|
34075
|
+
const rawPath = parts[parts.length - 1];
|
|
34076
|
+
const expanded = expandGitRenameNumstatPath(rawPath);
|
|
34077
|
+
if (isBinaryNumstatLine(line)) binaryByPath.add(expanded?.newPath ?? rawPath);
|
|
34078
|
+
}
|
|
34079
|
+
return binaryByPath;
|
|
34080
|
+
}
|
|
34081
|
+
|
|
34082
|
+
// src/git/changes/listing/parse-diff-output.ts
|
|
34083
|
+
function parseDiffOutput(nameStatusRaw, numstatRaw) {
|
|
34084
|
+
const nameEntries = parseNameStatusEntries(nameStatusRaw.split("\n"));
|
|
34085
|
+
const nameByPath = new Map(nameEntries.map((entry) => [entry.pathInRepo, entry]));
|
|
34086
|
+
const numByPath = parseNumstatEntries(numstatRaw.split("\n"));
|
|
34087
|
+
const movedSourcePaths = collectMovedSourcePaths(nameEntries, numByPath);
|
|
34088
|
+
const binaryByPath = collectBinaryPathsFromNumstat(numstatRaw);
|
|
34089
|
+
return { nameEntries, nameByPath, numByPath, movedSourcePaths, binaryByPath };
|
|
34090
|
+
}
|
|
34091
|
+
function collectChangedPaths(options) {
|
|
34092
|
+
const paths = /* @__PURE__ */ new Set();
|
|
34093
|
+
for (const entry of options.nameEntries) paths.add(entry.pathInRepo);
|
|
34094
|
+
for (const pathInRepo of options.numByPath.keys()) paths.add(pathInRepo);
|
|
34095
|
+
for (const pathInRepo of options.untracked ?? []) paths.add(pathInRepo);
|
|
34096
|
+
return paths;
|
|
33648
34097
|
}
|
|
33649
34098
|
|
|
33650
|
-
// src/git/
|
|
34099
|
+
// src/git/changes/listing/parent-for-commit-diff.ts
|
|
33651
34100
|
var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
33652
34101
|
async function parentForCommitDiff(g, sha) {
|
|
33653
34102
|
try {
|
|
@@ -33660,76 +34109,112 @@ async function parentForCommitDiff(g, sha) {
|
|
|
33660
34109
|
}
|
|
33661
34110
|
}
|
|
33662
34111
|
}
|
|
34112
|
+
|
|
34113
|
+
// src/git/changes/listing/rename-diff-args.ts
|
|
34114
|
+
var RENAME_DIFF_ARGS = ["-M", "--find-renames"];
|
|
34115
|
+
|
|
34116
|
+
// src/git/changes/rows/pick-preferred-changed-file-row.ts
|
|
34117
|
+
function rowRank(row) {
|
|
34118
|
+
if (row.change === "moved") return 3;
|
|
34119
|
+
if (row.change === "modified") return 2;
|
|
34120
|
+
if (row.change === "added") return 1;
|
|
34121
|
+
return 0;
|
|
34122
|
+
}
|
|
34123
|
+
function pickPreferredChangedFileRow(a, b) {
|
|
34124
|
+
if (rowRank(a) !== rowRank(b)) return rowRank(a) > rowRank(b) ? a : b;
|
|
34125
|
+
const aHasPatch = Boolean(a.patchContent?.trim());
|
|
34126
|
+
const bHasPatch = Boolean(b.patchContent?.trim());
|
|
34127
|
+
if (aHasPatch !== bHasPatch) return aHasPatch ? a : b;
|
|
34128
|
+
const aHasMoveMeta = Boolean(a.movedFromPathInRepo || a.movedFromPathRelLauncher);
|
|
34129
|
+
const bHasMoveMeta = Boolean(b.movedFromPathInRepo || b.movedFromPathRelLauncher);
|
|
34130
|
+
if (aHasMoveMeta !== bHasMoveMeta) return aHasMoveMeta ? a : b;
|
|
34131
|
+
return a;
|
|
34132
|
+
}
|
|
34133
|
+
|
|
34134
|
+
// src/git/changes/rows/dedupe-changed-file-rows.ts
|
|
34135
|
+
function dedupeChangedFileRows(rows) {
|
|
34136
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
34137
|
+
for (const row of rows) {
|
|
34138
|
+
const key = normalizeGitDiffPath(row.pathRelLauncher);
|
|
34139
|
+
const normalizedRow = key === row.pathRelLauncher ? row : { ...row, pathRelLauncher: key };
|
|
34140
|
+
const existing = byPath.get(key);
|
|
34141
|
+
if (!existing) {
|
|
34142
|
+
byPath.set(key, normalizedRow);
|
|
34143
|
+
continue;
|
|
34144
|
+
}
|
|
34145
|
+
const preferRow = pickPreferredChangedFileRow(existing, normalizedRow);
|
|
34146
|
+
byPath.set(key, { ...preferRow, pathRelLauncher: key });
|
|
34147
|
+
}
|
|
34148
|
+
return [...byPath.values()];
|
|
34149
|
+
}
|
|
34150
|
+
|
|
34151
|
+
// src/git/changes/listing/list-changed-files-for-commit.ts
|
|
33663
34152
|
async function listChangedFilesForCommit(repoGitCwd, repoRelPath, commitSha) {
|
|
33664
34153
|
const g = cliSimpleGit(repoGitCwd);
|
|
33665
34154
|
const parent = await parentForCommitDiff(g, commitSha);
|
|
33666
34155
|
const range = `${parent}..${commitSha}`;
|
|
33667
34156
|
const [nameStatusRaw, numstatRaw] = await Promise.all([
|
|
33668
|
-
g.raw(["diff", "--name-status", range]).catch(() => ""),
|
|
33669
|
-
g.raw(["diff", "--numstat", range]).catch(() => "")
|
|
34157
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", range]).catch(() => ""),
|
|
34158
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "--numstat", range]).catch(() => "")
|
|
33670
34159
|
]);
|
|
33671
|
-
const
|
|
33672
|
-
const
|
|
33673
|
-
const paths =
|
|
33674
|
-
|
|
33675
|
-
|
|
33676
|
-
await forEachWithGitYield([...paths], async (pathInRepo) => {
|
|
33677
|
-
const relLauncher = posixJoinDirFile(normRel, pathInRepo.replace(/\\/g, "/"));
|
|
33678
|
-
const nums = numByPath.get(pathInRepo);
|
|
33679
|
-
let additions = nums?.additions ?? 0;
|
|
33680
|
-
let deletions = nums?.deletions ?? 0;
|
|
33681
|
-
let change = kindByPath.get(pathInRepo) ?? "modified";
|
|
33682
|
-
if (!kindByPath.has(pathInRepo) && nums) {
|
|
33683
|
-
if (additions > 0 && deletions === 0) change = "added";
|
|
33684
|
-
else if (deletions > 0 && additions === 0) change = "removed";
|
|
33685
|
-
else change = "modified";
|
|
33686
|
-
}
|
|
33687
|
-
rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
|
|
33688
|
-
});
|
|
33689
|
-
await forEachWithGitYield(rows, async (row) => {
|
|
33690
|
-
let pathInRepo;
|
|
33691
|
-
if (normRel === ".") {
|
|
33692
|
-
pathInRepo = row.pathRelLauncher;
|
|
33693
|
-
} else if (row.pathRelLauncher.startsWith(`${normRel}/`)) {
|
|
33694
|
-
pathInRepo = row.pathRelLauncher.slice(normRel.length + 1);
|
|
33695
|
-
} else {
|
|
33696
|
-
pathInRepo = row.pathRelLauncher;
|
|
33697
|
-
}
|
|
33698
|
-
const raw = await g.raw(["diff", "-U20000", range, "--", pathInRepo]).catch(() => "");
|
|
33699
|
-
const t = String(raw).trim();
|
|
33700
|
-
row.patchContent = t ? truncatePatch(t) : void 0;
|
|
34160
|
+
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
34161
|
+
const normRel = normalizeRepoRelPath(repoRelPath);
|
|
34162
|
+
const paths = collectChangedPaths({
|
|
34163
|
+
nameEntries: parsed.nameEntries,
|
|
34164
|
+
numByPath: parsed.numByPath
|
|
33701
34165
|
});
|
|
33702
|
-
rows
|
|
33703
|
-
|
|
33704
|
-
|
|
33705
|
-
|
|
33706
|
-
|
|
34166
|
+
let rows = await buildChangedFileRowsFromPaths({
|
|
34167
|
+
paths,
|
|
34168
|
+
repoRelPath: normRel,
|
|
34169
|
+
nameByPath: parsed.nameByPath,
|
|
34170
|
+
numByPath: parsed.numByPath,
|
|
34171
|
+
movedSourcePaths: parsed.movedSourcePaths
|
|
34172
|
+
});
|
|
34173
|
+
rows = dedupeChangedFileRows(rows);
|
|
34174
|
+
await enrichCommitFileRows({
|
|
34175
|
+
rows,
|
|
34176
|
+
repoGitCwd,
|
|
34177
|
+
repoRelPath: normRel,
|
|
34178
|
+
range,
|
|
34179
|
+
commitSha,
|
|
34180
|
+
parentSha: parent,
|
|
34181
|
+
binaryByPath: parsed.binaryByPath
|
|
34182
|
+
});
|
|
34183
|
+
const finalRows = dedupeChangedFileRows(rows);
|
|
34184
|
+
finalRows.sort((a, b) => a.pathRelLauncher.localeCompare(b.pathRelLauncher));
|
|
34185
|
+
return finalRows;
|
|
34186
|
+
}
|
|
34187
|
+
|
|
34188
|
+
// src/git/changes/listing/apply-untracked-file-stats.ts
|
|
33707
34189
|
import * as fs17 from "node:fs";
|
|
33708
|
-
import * as
|
|
33709
|
-
|
|
33710
|
-
|
|
33711
|
-
|
|
33712
|
-
|
|
33713
|
-
|
|
33714
|
-
|
|
33715
|
-
|
|
33716
|
-
|
|
33717
|
-
|
|
33718
|
-
|
|
33719
|
-
|
|
33720
|
-
lines += 1;
|
|
33721
|
-
bytes += Buffer.byteLength(String(_line), "utf8") + 1;
|
|
33722
|
-
if (bytes > maxBytes) {
|
|
33723
|
-
rl.close();
|
|
33724
|
-
stream.destroy();
|
|
33725
|
-
return lines;
|
|
34190
|
+
import * as path20 from "node:path";
|
|
34191
|
+
function createUntrackedStatsApplier(options) {
|
|
34192
|
+
return async (row, pathInRepo) => {
|
|
34193
|
+
if (!options.untrackedSet.has(pathInRepo)) return;
|
|
34194
|
+
if (options.nameByPath.has(pathInRepo)) return;
|
|
34195
|
+
if (row.change === "moved") return;
|
|
34196
|
+
const repoFilePath = path20.join(options.repoGitCwd, pathInRepo);
|
|
34197
|
+
const fromGit = await numstatFromGitNoIndex(options.g, pathInRepo);
|
|
34198
|
+
if (fromGit) {
|
|
34199
|
+
row.additions = fromGit.additions;
|
|
34200
|
+
row.deletions = fromGit.deletions;
|
|
34201
|
+
return;
|
|
33726
34202
|
}
|
|
33727
|
-
|
|
33728
|
-
|
|
34203
|
+
try {
|
|
34204
|
+
const st = await fs17.promises.stat(repoFilePath);
|
|
34205
|
+
row.additions = st.isFile() ? await countTextFileLines(repoFilePath) : 0;
|
|
34206
|
+
} catch {
|
|
34207
|
+
row.additions = 0;
|
|
34208
|
+
}
|
|
34209
|
+
row.deletions = 0;
|
|
34210
|
+
};
|
|
33729
34211
|
}
|
|
33730
34212
|
|
|
33731
|
-
// src/git/changes/
|
|
33732
|
-
import * as
|
|
34213
|
+
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
34214
|
+
import * as path21 from "node:path";
|
|
34215
|
+
|
|
34216
|
+
// src/git/changes/patch/hydrate-patch.ts
|
|
34217
|
+
import * as fs18 from "node:fs";
|
|
33733
34218
|
var UNIFIED_HUNK_HEADER_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
33734
34219
|
var MAX_HYDRATE_LINES_PER_GAP = 8e3;
|
|
33735
34220
|
var MAX_HYDRATE_LINES_PER_FILE = 8e4;
|
|
@@ -33744,7 +34229,7 @@ async function readGitBlobLines(repoCwd, pathInRepo) {
|
|
|
33744
34229
|
}
|
|
33745
34230
|
async function readWorktreeFileLines(filePath) {
|
|
33746
34231
|
try {
|
|
33747
|
-
const raw = await
|
|
34232
|
+
const raw = await fs18.promises.readFile(filePath, "utf8");
|
|
33748
34233
|
return raw.split(/\r?\n/);
|
|
33749
34234
|
} catch {
|
|
33750
34235
|
return null;
|
|
@@ -33844,82 +34329,70 @@ async function hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, p
|
|
|
33844
34329
|
return truncatePatch(out.join("\n"));
|
|
33845
34330
|
}
|
|
33846
34331
|
|
|
33847
|
-
// src/git/changes/
|
|
33848
|
-
function
|
|
33849
|
-
|
|
33850
|
-
|
|
33851
|
-
|
|
33852
|
-
|
|
33853
|
-
|
|
33854
|
-
|
|
33855
|
-
|
|
33856
|
-
|
|
33857
|
-
|
|
34332
|
+
// src/git/changes/listing/enrich-working-tree-file-rows.ts
|
|
34333
|
+
async function enrichWorkingTreeFileRows(options) {
|
|
34334
|
+
await forEachWithGitYield(options.rows, async (row) => {
|
|
34335
|
+
const pathInRepo = pathInRepoFromLauncher(row.pathRelLauncher, options.repoRelPath);
|
|
34336
|
+
const filePath = path21.join(options.repoGitCwd, pathInRepo);
|
|
34337
|
+
const hydrateKind = row.change === "moved" ? "modified" : row.change;
|
|
34338
|
+
let patch = await unifiedDiffForFile(options.repoGitCwd, pathInRepo, row.change, row.movedFromPathInRepo);
|
|
34339
|
+
if (patch) {
|
|
34340
|
+
patch = await hydrateUnifiedPatchWithFileContext(
|
|
34341
|
+
patch,
|
|
34342
|
+
filePath,
|
|
34343
|
+
options.repoGitCwd,
|
|
34344
|
+
pathInRepo,
|
|
34345
|
+
hydrateKind
|
|
34346
|
+
);
|
|
34347
|
+
}
|
|
34348
|
+
row.patchContent = patch;
|
|
34349
|
+
row.totalLines = await resolveWorkingTreeFileTotalLines({
|
|
34350
|
+
repoGitCwd: options.repoGitCwd,
|
|
34351
|
+
pathInRepo,
|
|
34352
|
+
change: row.change,
|
|
34353
|
+
isBinary: options.binaryByPath.has(pathInRepo)
|
|
34354
|
+
});
|
|
34355
|
+
});
|
|
33858
34356
|
}
|
|
33859
34357
|
|
|
33860
|
-
// src/git/changes/list-changed-files-for-repo.ts
|
|
34358
|
+
// src/git/changes/listing/list-changed-files-for-repo.ts
|
|
33861
34359
|
async function listChangedFilesForRepo(repoGitCwd, repoRelPath) {
|
|
33862
34360
|
const g = cliSimpleGit(repoGitCwd);
|
|
33863
34361
|
const [nameStatusRaw, numstatRaw, untrackedRaw] = await Promise.all([
|
|
33864
|
-
g.raw(["diff", "--name-status", "HEAD"]).catch(() => ""),
|
|
33865
|
-
g.raw(["diff", "HEAD", "--numstat"]).catch(() => ""),
|
|
34362
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "--name-status", "HEAD"]).catch(() => ""),
|
|
34363
|
+
g.raw(["diff", ...RENAME_DIFF_ARGS, "HEAD", "--numstat"]).catch(() => ""),
|
|
33866
34364
|
g.raw(["ls-files", "--others", "--exclude-standard"]).catch(() => "")
|
|
33867
34365
|
]);
|
|
33868
|
-
const
|
|
33869
|
-
const numByPath = parseNumstat(String(numstatRaw).split("\n"));
|
|
33870
|
-
const paths = /* @__PURE__ */ new Set([...kindByPath.keys(), ...numByPath.keys()]);
|
|
34366
|
+
const parsed = parseDiffOutput(String(nameStatusRaw), String(numstatRaw));
|
|
33871
34367
|
const untracked = String(untrackedRaw).split("\n").map((s) => s.trim()).filter(Boolean);
|
|
33872
|
-
|
|
33873
|
-
const
|
|
33874
|
-
|
|
33875
|
-
|
|
33876
|
-
|
|
33877
|
-
const nums = numByPath.get(pathInRepo);
|
|
33878
|
-
let additions = nums?.additions ?? 0;
|
|
33879
|
-
let deletions = nums?.deletions ?? 0;
|
|
33880
|
-
let change = kindByPath.get(pathInRepo) ?? "modified";
|
|
33881
|
-
if (untracked.includes(pathInRepo) && !kindByPath.has(pathInRepo)) {
|
|
33882
|
-
change = "added";
|
|
33883
|
-
const fromGit = await numstatFromGitNoIndex(g, pathInRepo);
|
|
33884
|
-
if (fromGit) {
|
|
33885
|
-
additions = fromGit.additions;
|
|
33886
|
-
deletions = fromGit.deletions;
|
|
33887
|
-
} else {
|
|
33888
|
-
try {
|
|
33889
|
-
const st = await fs17.promises.stat(repoFilePath);
|
|
33890
|
-
if (st.isFile()) additions = await countTextFileLines(repoFilePath);
|
|
33891
|
-
else additions = 0;
|
|
33892
|
-
} catch {
|
|
33893
|
-
additions = 0;
|
|
33894
|
-
}
|
|
33895
|
-
deletions = 0;
|
|
33896
|
-
}
|
|
33897
|
-
}
|
|
33898
|
-
if (!kindByPath.has(pathInRepo) && nums) {
|
|
33899
|
-
if (additions > 0 && deletions === 0) change = "added";
|
|
33900
|
-
else if (deletions > 0 && additions === 0) change = "removed";
|
|
33901
|
-
else change = "modified";
|
|
33902
|
-
}
|
|
33903
|
-
rows.push({ pathRelLauncher: relLauncher, additions, deletions, change });
|
|
34368
|
+
const untrackedSet = new Set(untracked);
|
|
34369
|
+
const paths = collectChangedPaths({
|
|
34370
|
+
nameEntries: parsed.nameEntries,
|
|
34371
|
+
numByPath: parsed.numByPath,
|
|
34372
|
+
untracked
|
|
33904
34373
|
});
|
|
33905
|
-
|
|
33906
|
-
|
|
33907
|
-
|
|
33908
|
-
|
|
33909
|
-
|
|
33910
|
-
|
|
33911
|
-
|
|
33912
|
-
|
|
33913
|
-
|
|
33914
|
-
|
|
33915
|
-
|
|
33916
|
-
|
|
33917
|
-
|
|
33918
|
-
patch = await hydrateUnifiedPatchWithFileContext(patch, filePath, repoGitCwd, pathInRepo, row.change);
|
|
33919
|
-
}
|
|
33920
|
-
row.patchContent = patch;
|
|
34374
|
+
let rows = await buildChangedFileRowsFromPaths({
|
|
34375
|
+
paths,
|
|
34376
|
+
repoRelPath,
|
|
34377
|
+
nameByPath: parsed.nameByPath,
|
|
34378
|
+
numByPath: parsed.numByPath,
|
|
34379
|
+
movedSourcePaths: parsed.movedSourcePaths,
|
|
34380
|
+
untrackedSet,
|
|
34381
|
+
applyUntrackedStats: createUntrackedStatsApplier({
|
|
34382
|
+
g,
|
|
34383
|
+
repoGitCwd,
|
|
34384
|
+
untrackedSet,
|
|
34385
|
+
nameByPath: parsed.nameByPath
|
|
34386
|
+
})
|
|
33921
34387
|
});
|
|
33922
|
-
|
|
34388
|
+
rows = dedupeChangedFileRows(rows);
|
|
34389
|
+
await enrichWorkingTreeFileRows({
|
|
34390
|
+
rows,
|
|
34391
|
+
repoGitCwd,
|
|
34392
|
+
repoRelPath,
|
|
34393
|
+
binaryByPath: parsed.binaryByPath
|
|
34394
|
+
});
|
|
34395
|
+
return dedupeChangedFileRows(rows);
|
|
33923
34396
|
}
|
|
33924
34397
|
|
|
33925
34398
|
// src/git/changes/get-working-tree-change-repo-details.ts
|
|
@@ -33928,8 +34401,8 @@ function normRepoRel(p) {
|
|
|
33928
34401
|
return x === "" ? "." : x;
|
|
33929
34402
|
}
|
|
33930
34403
|
async function getWorkingTreeChangeRepoDetails(options) {
|
|
33931
|
-
const bridgeRoot =
|
|
33932
|
-
const sessionWtRoot = options.sessionWorktreeRootPath ?
|
|
34404
|
+
const bridgeRoot = path22.resolve(getBridgeRoot());
|
|
34405
|
+
const sessionWtRoot = options.sessionWorktreeRootPath ? path22.resolve(options.sessionWorktreeRootPath) : null;
|
|
33933
34406
|
const legacyNested = options.legacyRepoNestedSessionLayout === true;
|
|
33934
34407
|
const out = [];
|
|
33935
34408
|
const filter = options.repoFilterRelPath != null ? normRepoRel(options.repoFilterRelPath) : null;
|
|
@@ -33944,7 +34417,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
33944
34417
|
for (let i = 0; i < options.commitTargetPaths.length; i++) {
|
|
33945
34418
|
if (i > 0) await yieldToEventLoop2();
|
|
33946
34419
|
const target = options.commitTargetPaths[i];
|
|
33947
|
-
const t =
|
|
34420
|
+
const t = path22.resolve(target);
|
|
33948
34421
|
if (!await isGitRepoDirectory(t)) continue;
|
|
33949
34422
|
const g = cliSimpleGit(t);
|
|
33950
34423
|
let branch = "HEAD";
|
|
@@ -33957,8 +34430,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
33957
34430
|
const remoteDisplay = formatRemoteDisplayLabel(remoteUrl);
|
|
33958
34431
|
let repoRelPath;
|
|
33959
34432
|
if (sessionWtRoot) {
|
|
33960
|
-
const anchor = legacyNested ?
|
|
33961
|
-
const relNorm =
|
|
34433
|
+
const anchor = legacyNested ? path22.dirname(t) : t;
|
|
34434
|
+
const relNorm = path22.relative(sessionWtRoot, anchor);
|
|
33962
34435
|
repoRelPath = relNorm === "" ? "." : relNorm.replace(/\\/g, "/");
|
|
33963
34436
|
} else {
|
|
33964
34437
|
let top = t;
|
|
@@ -33967,8 +34440,8 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
33967
34440
|
} catch {
|
|
33968
34441
|
top = t;
|
|
33969
34442
|
}
|
|
33970
|
-
const rel =
|
|
33971
|
-
repoRelPath = rel.startsWith("..") ?
|
|
34443
|
+
const rel = path22.relative(bridgeRoot, path22.resolve(top)).replace(/\\/g, "/") || ".";
|
|
34444
|
+
repoRelPath = rel.startsWith("..") ? path22.basename(path22.resolve(top)) : rel;
|
|
33972
34445
|
}
|
|
33973
34446
|
const norm = normRepoRel(repoRelPath === "" ? "." : repoRelPath);
|
|
33974
34447
|
if (filter && norm !== filter) continue;
|
|
@@ -34000,7 +34473,7 @@ async function getWorkingTreeChangeRepoDetails(options) {
|
|
|
34000
34473
|
return out;
|
|
34001
34474
|
}
|
|
34002
34475
|
|
|
34003
|
-
// src/git/changes/
|
|
34476
|
+
// src/git/changes/status/working-tree-changed-path-count.ts
|
|
34004
34477
|
function workingTreeChangedPathCount(nameStatusLines, numstatLines, untrackedLines) {
|
|
34005
34478
|
const kindByPath = parseNameStatusLines(nameStatusLines);
|
|
34006
34479
|
const numByPath = parseNumstat(numstatLines);
|
|
@@ -34096,23 +34569,23 @@ async function commitSessionWorktrees(options) {
|
|
|
34096
34569
|
}
|
|
34097
34570
|
|
|
34098
34571
|
// src/worktrees/remove-session-worktrees.ts
|
|
34099
|
-
import * as
|
|
34572
|
+
import * as fs21 from "node:fs";
|
|
34100
34573
|
|
|
34101
34574
|
// src/git/worktrees/worktree-remove.ts
|
|
34102
|
-
import * as
|
|
34575
|
+
import * as fs20 from "node:fs";
|
|
34103
34576
|
|
|
34104
34577
|
// src/git/worktrees/resolve-main-repo-from-git-file.ts
|
|
34105
|
-
import * as
|
|
34106
|
-
import * as
|
|
34578
|
+
import * as fs19 from "node:fs";
|
|
34579
|
+
import * as path23 from "node:path";
|
|
34107
34580
|
function resolveMainRepoFromWorktreeGitFile(wt) {
|
|
34108
|
-
const gitDirFile =
|
|
34109
|
-
if (!
|
|
34110
|
-
const first2 =
|
|
34581
|
+
const gitDirFile = path23.join(wt, ".git");
|
|
34582
|
+
if (!fs19.existsSync(gitDirFile) || !fs19.statSync(gitDirFile).isFile()) return "";
|
|
34583
|
+
const first2 = fs19.readFileSync(gitDirFile, "utf8").trim();
|
|
34111
34584
|
const m = first2.match(/^gitdir:\s*(.+)$/im);
|
|
34112
34585
|
if (!m) return "";
|
|
34113
|
-
const gitWorktreePath =
|
|
34114
|
-
const gitDir =
|
|
34115
|
-
return
|
|
34586
|
+
const gitWorktreePath = path23.resolve(wt, m[1].trim());
|
|
34587
|
+
const gitDir = path23.dirname(path23.dirname(gitWorktreePath));
|
|
34588
|
+
return path23.dirname(gitDir);
|
|
34116
34589
|
}
|
|
34117
34590
|
|
|
34118
34591
|
// src/git/worktrees/worktree-remove.ts
|
|
@@ -34121,7 +34594,7 @@ async function gitWorktreeRemoveForce(worktreePath) {
|
|
|
34121
34594
|
if (mainRepo) {
|
|
34122
34595
|
await cliSimpleGit(mainRepo).raw(["worktree", "remove", "--force", worktreePath]);
|
|
34123
34596
|
} else {
|
|
34124
|
-
|
|
34597
|
+
fs20.rmSync(worktreePath, { recursive: true, force: true });
|
|
34125
34598
|
}
|
|
34126
34599
|
}
|
|
34127
34600
|
|
|
@@ -34134,7 +34607,7 @@ async function removeSessionWorktrees(paths, log2) {
|
|
|
34134
34607
|
} catch (e) {
|
|
34135
34608
|
log2(`[worktrees] Remove failed for ${wt}: ${e instanceof Error ? e.message : String(e)}`);
|
|
34136
34609
|
try {
|
|
34137
|
-
|
|
34610
|
+
fs21.rmSync(wt, { recursive: true, force: true });
|
|
34138
34611
|
} catch {
|
|
34139
34612
|
}
|
|
34140
34613
|
}
|
|
@@ -34163,12 +34636,12 @@ async function renameSessionWorktreeBranches(paths, newBranch, log2) {
|
|
|
34163
34636
|
}
|
|
34164
34637
|
|
|
34165
34638
|
// src/worktrees/worktree-layout-file.ts
|
|
34166
|
-
import * as
|
|
34167
|
-
import * as
|
|
34639
|
+
import * as fs22 from "node:fs";
|
|
34640
|
+
import * as path24 from "node:path";
|
|
34168
34641
|
import os7 from "node:os";
|
|
34169
34642
|
var LAYOUT_FILENAME = "worktree-launcher-layout.json";
|
|
34170
34643
|
function defaultWorktreeLayoutPath() {
|
|
34171
|
-
return
|
|
34644
|
+
return path24.join(os7.homedir(), ".buildautomaton", LAYOUT_FILENAME);
|
|
34172
34645
|
}
|
|
34173
34646
|
function normalizeLoadedLayout(raw) {
|
|
34174
34647
|
if (raw && typeof raw === "object" && "launcherCwds" in raw) {
|
|
@@ -34180,8 +34653,8 @@ function normalizeLoadedLayout(raw) {
|
|
|
34180
34653
|
function loadWorktreeLayout() {
|
|
34181
34654
|
try {
|
|
34182
34655
|
const p = defaultWorktreeLayoutPath();
|
|
34183
|
-
if (!
|
|
34184
|
-
const raw = JSON.parse(
|
|
34656
|
+
if (!fs22.existsSync(p)) return { launcherCwds: [] };
|
|
34657
|
+
const raw = JSON.parse(fs22.readFileSync(p, "utf8"));
|
|
34185
34658
|
return normalizeLoadedLayout(raw);
|
|
34186
34659
|
} catch {
|
|
34187
34660
|
return { launcherCwds: [] };
|
|
@@ -34189,24 +34662,24 @@ function loadWorktreeLayout() {
|
|
|
34189
34662
|
}
|
|
34190
34663
|
function saveWorktreeLayout(layout) {
|
|
34191
34664
|
try {
|
|
34192
|
-
const dir =
|
|
34193
|
-
|
|
34194
|
-
|
|
34665
|
+
const dir = path24.dirname(defaultWorktreeLayoutPath());
|
|
34666
|
+
fs22.mkdirSync(dir, { recursive: true });
|
|
34667
|
+
fs22.writeFileSync(defaultWorktreeLayoutPath(), JSON.stringify(layout, null, 2), "utf8");
|
|
34195
34668
|
} catch {
|
|
34196
34669
|
}
|
|
34197
34670
|
}
|
|
34198
34671
|
function baseNameSafe(pathString) {
|
|
34199
|
-
return
|
|
34672
|
+
return path24.basename(pathString).replace(/[^a-zA-Z0-9._-]+/g, "-") || "cwd";
|
|
34200
34673
|
}
|
|
34201
34674
|
function getLauncherDirNameIfPresent(layout, bridgeRootPath2) {
|
|
34202
|
-
const norm =
|
|
34203
|
-
const existing = layout.launcherCwds.find((e) =>
|
|
34675
|
+
const norm = path24.resolve(bridgeRootPath2);
|
|
34676
|
+
const existing = layout.launcherCwds.find((e) => path24.resolve(e.absolutePath) === norm);
|
|
34204
34677
|
return existing?.dirName;
|
|
34205
34678
|
}
|
|
34206
34679
|
function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
34207
34680
|
const existing = getLauncherDirNameIfPresent(layout, bridgeRootPath2);
|
|
34208
34681
|
if (existing) return existing;
|
|
34209
|
-
const norm =
|
|
34682
|
+
const norm = path24.resolve(bridgeRootPath2);
|
|
34210
34683
|
const base = baseNameSafe(norm);
|
|
34211
34684
|
const used = new Set(layout.launcherCwds.map((e) => e.dirName));
|
|
34212
34685
|
let name = base;
|
|
@@ -34221,11 +34694,11 @@ function allocateDirNameForLauncherCwd(layout, bridgeRootPath2) {
|
|
|
34221
34694
|
}
|
|
34222
34695
|
|
|
34223
34696
|
// src/worktrees/discover-session-worktree-on-disk.ts
|
|
34224
|
-
import * as
|
|
34225
|
-
import * as
|
|
34697
|
+
import * as fs23 from "node:fs";
|
|
34698
|
+
import * as path25 from "node:path";
|
|
34226
34699
|
function isGitDir(dirPath) {
|
|
34227
34700
|
try {
|
|
34228
|
-
return
|
|
34701
|
+
return fs23.existsSync(path25.join(dirPath, ".git"));
|
|
34229
34702
|
} catch {
|
|
34230
34703
|
return false;
|
|
34231
34704
|
}
|
|
@@ -34234,23 +34707,23 @@ function collectGitRepoRootsUnderDirectory(rootPath) {
|
|
|
34234
34707
|
const out = [];
|
|
34235
34708
|
const walk = (dir) => {
|
|
34236
34709
|
if (isGitDir(dir)) {
|
|
34237
|
-
out.push(
|
|
34710
|
+
out.push(path25.resolve(dir));
|
|
34238
34711
|
return;
|
|
34239
34712
|
}
|
|
34240
34713
|
let entries;
|
|
34241
34714
|
try {
|
|
34242
|
-
entries =
|
|
34715
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
34243
34716
|
} catch {
|
|
34244
34717
|
return;
|
|
34245
34718
|
}
|
|
34246
34719
|
for (const e of entries) {
|
|
34247
34720
|
if (e.name.startsWith(".")) continue;
|
|
34248
|
-
const full =
|
|
34721
|
+
const full = path25.join(dir, e.name);
|
|
34249
34722
|
if (!e.isDirectory()) continue;
|
|
34250
34723
|
walk(full);
|
|
34251
34724
|
}
|
|
34252
34725
|
};
|
|
34253
|
-
walk(
|
|
34726
|
+
walk(path25.resolve(rootPath));
|
|
34254
34727
|
return [...new Set(out)];
|
|
34255
34728
|
}
|
|
34256
34729
|
function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
@@ -34259,16 +34732,16 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
34259
34732
|
if (depth > maxDepth) return;
|
|
34260
34733
|
let entries;
|
|
34261
34734
|
try {
|
|
34262
|
-
entries =
|
|
34735
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
34263
34736
|
} catch {
|
|
34264
34737
|
return;
|
|
34265
34738
|
}
|
|
34266
34739
|
for (const e of entries) {
|
|
34267
34740
|
if (e.name.startsWith(".")) continue;
|
|
34268
|
-
const full =
|
|
34741
|
+
const full = path25.join(dir, e.name);
|
|
34269
34742
|
if (!e.isDirectory()) continue;
|
|
34270
34743
|
if (e.name === sessionId) {
|
|
34271
|
-
if (isGitDir(full)) out.push(
|
|
34744
|
+
if (isGitDir(full)) out.push(path25.resolve(full));
|
|
34272
34745
|
} else {
|
|
34273
34746
|
walk(full, depth + 1);
|
|
34274
34747
|
}
|
|
@@ -34280,14 +34753,14 @@ function collectWorktreeRootsNamed(root, sessionId, maxDepth) {
|
|
|
34280
34753
|
function tryBindingFromSessionDirectory(sessionDir) {
|
|
34281
34754
|
let st;
|
|
34282
34755
|
try {
|
|
34283
|
-
st =
|
|
34756
|
+
st = fs23.statSync(sessionDir);
|
|
34284
34757
|
} catch {
|
|
34285
34758
|
return null;
|
|
34286
34759
|
}
|
|
34287
34760
|
if (!st.isDirectory()) return null;
|
|
34288
34761
|
const worktreePaths = collectGitRepoRootsUnderDirectory(sessionDir);
|
|
34289
34762
|
if (worktreePaths.length === 0) return null;
|
|
34290
|
-
const abs =
|
|
34763
|
+
const abs = path25.resolve(sessionDir);
|
|
34291
34764
|
return {
|
|
34292
34765
|
sessionParentPath: abs,
|
|
34293
34766
|
workingTreeRelRoot: abs,
|
|
@@ -34297,20 +34770,20 @@ function tryBindingFromSessionDirectory(sessionDir) {
|
|
|
34297
34770
|
function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
34298
34771
|
const sid = sessionId.trim();
|
|
34299
34772
|
if (!sid) return null;
|
|
34300
|
-
const hintR =
|
|
34773
|
+
const hintR = path25.resolve(checkoutPath);
|
|
34301
34774
|
let best = null;
|
|
34302
|
-
let cur =
|
|
34775
|
+
let cur = path25.dirname(hintR);
|
|
34303
34776
|
for (let i = 0; i < 40; i++) {
|
|
34304
34777
|
const paths = collectWorktreeRootsNamed(cur, sid, 24);
|
|
34305
|
-
if (paths.some((p) =>
|
|
34306
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ??
|
|
34778
|
+
if (paths.some((p) => path25.resolve(p) === hintR)) {
|
|
34779
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(paths) ?? path25.resolve(paths[0]);
|
|
34307
34780
|
best = {
|
|
34308
|
-
sessionParentPath:
|
|
34309
|
-
workingTreeRelRoot:
|
|
34310
|
-
repoCheckoutPaths: paths.map((p) =>
|
|
34781
|
+
sessionParentPath: path25.resolve(isolated),
|
|
34782
|
+
workingTreeRelRoot: path25.resolve(cur),
|
|
34783
|
+
repoCheckoutPaths: paths.map((p) => path25.resolve(p))
|
|
34311
34784
|
};
|
|
34312
34785
|
}
|
|
34313
|
-
const next =
|
|
34786
|
+
const next = path25.dirname(cur);
|
|
34314
34787
|
if (next === cur) break;
|
|
34315
34788
|
cur = next;
|
|
34316
34789
|
}
|
|
@@ -34318,33 +34791,33 @@ function discoverLegacyBindingAscendingFromCheckout(sessionId, checkoutPath) {
|
|
|
34318
34791
|
}
|
|
34319
34792
|
function discoverSessionWorktreeOnDisk(options) {
|
|
34320
34793
|
const { sessionId, worktreesRootPath, layout, bridgeRoot } = options;
|
|
34321
|
-
if (!sessionId.trim() || !
|
|
34794
|
+
if (!sessionId.trim() || !fs23.existsSync(worktreesRootPath)) return null;
|
|
34322
34795
|
const preferredKey = getLauncherDirNameIfPresent(layout, bridgeRoot);
|
|
34323
34796
|
const keys = [];
|
|
34324
34797
|
if (preferredKey) keys.push(preferredKey);
|
|
34325
34798
|
try {
|
|
34326
|
-
for (const name of
|
|
34799
|
+
for (const name of fs23.readdirSync(worktreesRootPath)) {
|
|
34327
34800
|
if (name.startsWith(".")) continue;
|
|
34328
|
-
const p =
|
|
34329
|
-
if (!
|
|
34801
|
+
const p = path25.join(worktreesRootPath, name);
|
|
34802
|
+
if (!fs23.statSync(p).isDirectory()) continue;
|
|
34330
34803
|
if (name !== preferredKey) keys.push(name);
|
|
34331
34804
|
}
|
|
34332
34805
|
} catch {
|
|
34333
34806
|
return null;
|
|
34334
34807
|
}
|
|
34335
34808
|
for (const key of keys) {
|
|
34336
|
-
const layoutRoot =
|
|
34337
|
-
if (!
|
|
34338
|
-
const sessionDir =
|
|
34809
|
+
const layoutRoot = path25.join(worktreesRootPath, key);
|
|
34810
|
+
if (!fs23.existsSync(layoutRoot) || !fs23.statSync(layoutRoot).isDirectory()) continue;
|
|
34811
|
+
const sessionDir = path25.join(layoutRoot, sessionId);
|
|
34339
34812
|
const nested = tryBindingFromSessionDirectory(sessionDir);
|
|
34340
34813
|
if (nested) return nested;
|
|
34341
34814
|
const legacyPaths = collectWorktreeRootsNamed(layoutRoot, sessionId, 24);
|
|
34342
34815
|
if (legacyPaths.length > 0) {
|
|
34343
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
34816
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
34344
34817
|
return {
|
|
34345
|
-
sessionParentPath:
|
|
34346
|
-
workingTreeRelRoot:
|
|
34347
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
34818
|
+
sessionParentPath: path25.resolve(isolated),
|
|
34819
|
+
workingTreeRelRoot: path25.resolve(layoutRoot),
|
|
34820
|
+
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
34348
34821
|
};
|
|
34349
34822
|
}
|
|
34350
34823
|
}
|
|
@@ -34353,12 +34826,12 @@ function discoverSessionWorktreeOnDisk(options) {
|
|
|
34353
34826
|
function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPathOrHint, sessionId) {
|
|
34354
34827
|
const sid = sessionId.trim();
|
|
34355
34828
|
if (!sid) return null;
|
|
34356
|
-
const hint =
|
|
34357
|
-
const underHint = tryBindingFromSessionDirectory(
|
|
34829
|
+
const hint = path25.resolve(sessionWorktreeRootPathOrHint);
|
|
34830
|
+
const underHint = tryBindingFromSessionDirectory(path25.join(hint, sid));
|
|
34358
34831
|
if (underHint) return underHint;
|
|
34359
34832
|
const direct = tryBindingFromSessionDirectory(hint);
|
|
34360
34833
|
if (direct) {
|
|
34361
|
-
if (
|
|
34834
|
+
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
34362
34835
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34363
34836
|
if (legacyFromCheckout && legacyFromCheckout.repoCheckoutPaths.length > direct.repoCheckoutPaths.length) {
|
|
34364
34837
|
return legacyFromCheckout;
|
|
@@ -34366,24 +34839,24 @@ function discoverSessionWorktreesUnderSessionWorktreeRoot(sessionWorktreeRootPat
|
|
|
34366
34839
|
}
|
|
34367
34840
|
return direct;
|
|
34368
34841
|
}
|
|
34369
|
-
if (
|
|
34842
|
+
if (path25.basename(hint) === sid && isGitDir(hint)) {
|
|
34370
34843
|
const legacyFromCheckout = discoverLegacyBindingAscendingFromCheckout(sid, hint);
|
|
34371
34844
|
if (legacyFromCheckout) return legacyFromCheckout;
|
|
34372
34845
|
}
|
|
34373
34846
|
let st;
|
|
34374
34847
|
try {
|
|
34375
|
-
st =
|
|
34848
|
+
st = fs23.statSync(hint);
|
|
34376
34849
|
} catch {
|
|
34377
34850
|
return null;
|
|
34378
34851
|
}
|
|
34379
34852
|
if (!st.isDirectory()) return null;
|
|
34380
34853
|
const legacyPaths = collectWorktreeRootsNamed(hint, sid, 24);
|
|
34381
34854
|
if (legacyPaths.length === 0) return null;
|
|
34382
|
-
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ??
|
|
34855
|
+
const isolated = resolveIsolatedSessionParentPathFromCheckouts(legacyPaths) ?? path25.resolve(legacyPaths[0]);
|
|
34383
34856
|
return {
|
|
34384
|
-
sessionParentPath:
|
|
34857
|
+
sessionParentPath: path25.resolve(isolated),
|
|
34385
34858
|
workingTreeRelRoot: hint,
|
|
34386
|
-
repoCheckoutPaths: legacyPaths.map((p) =>
|
|
34859
|
+
repoCheckoutPaths: legacyPaths.map((p) => path25.resolve(p))
|
|
34387
34860
|
};
|
|
34388
34861
|
}
|
|
34389
34862
|
|
|
@@ -34440,8 +34913,8 @@ function parseSessionParent(v) {
|
|
|
34440
34913
|
}
|
|
34441
34914
|
|
|
34442
34915
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34443
|
-
import * as
|
|
34444
|
-
import * as
|
|
34916
|
+
import * as fs24 from "node:fs";
|
|
34917
|
+
import * as path26 from "node:path";
|
|
34445
34918
|
|
|
34446
34919
|
// src/git/worktrees/worktree-add.ts
|
|
34447
34920
|
async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef = "HEAD") {
|
|
@@ -34451,7 +34924,7 @@ async function gitWorktreeAddBranch(mainRepoPath, worktreePath, branch, baseRef
|
|
|
34451
34924
|
}
|
|
34452
34925
|
|
|
34453
34926
|
// src/worktrees/prepare-new-session-worktrees.ts
|
|
34454
|
-
function
|
|
34927
|
+
function normalizeRepoRelPath2(rel) {
|
|
34455
34928
|
return rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
34456
34929
|
}
|
|
34457
34930
|
function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
@@ -34463,10 +34936,10 @@ function resolveBaseRefForRepo(relNorm, baseBranches) {
|
|
|
34463
34936
|
}
|
|
34464
34937
|
async function prepareNewSessionWorktrees(options) {
|
|
34465
34938
|
const { worktreesRootPath, bridgeRoot, sessionId, layout, log: log2, worktreeBaseBranches } = options;
|
|
34466
|
-
const bridgeResolved =
|
|
34939
|
+
const bridgeResolved = path26.resolve(bridgeRoot);
|
|
34467
34940
|
const cwdKey = allocateDirNameForLauncherCwd(layout, bridgeResolved);
|
|
34468
|
-
const bridgeKeyDir =
|
|
34469
|
-
const sessionDir =
|
|
34941
|
+
const bridgeKeyDir = path26.join(worktreesRootPath, cwdKey);
|
|
34942
|
+
const sessionDir = path26.join(bridgeKeyDir, sessionId);
|
|
34470
34943
|
const repos = await discoverGitReposUnderRoot(bridgeResolved);
|
|
34471
34944
|
if (repos.length === 0) {
|
|
34472
34945
|
log2("[worktrees] No Git repositories under bridge root; skipping worktree creation.");
|
|
@@ -34474,14 +34947,14 @@ async function prepareNewSessionWorktrees(options) {
|
|
|
34474
34947
|
}
|
|
34475
34948
|
const branch = `session-${sessionId}`;
|
|
34476
34949
|
const worktreePaths = [];
|
|
34477
|
-
|
|
34950
|
+
fs24.mkdirSync(sessionDir, { recursive: true });
|
|
34478
34951
|
for (const repo of repos) {
|
|
34479
|
-
let rel =
|
|
34480
|
-
if (rel.startsWith("..") ||
|
|
34481
|
-
const relNorm =
|
|
34482
|
-
const wtPath = relNorm === "." ? sessionDir :
|
|
34952
|
+
let rel = path26.relative(bridgeResolved, repo.absolutePath);
|
|
34953
|
+
if (rel.startsWith("..") || path26.isAbsolute(rel)) continue;
|
|
34954
|
+
const relNorm = normalizeRepoRelPath2(rel === "" ? "." : rel);
|
|
34955
|
+
const wtPath = relNorm === "." ? sessionDir : path26.join(sessionDir, relNorm);
|
|
34483
34956
|
if (relNorm !== ".") {
|
|
34484
|
-
|
|
34957
|
+
fs24.mkdirSync(path26.dirname(wtPath), { recursive: true });
|
|
34485
34958
|
}
|
|
34486
34959
|
const baseRef = resolveBaseRefForRepo(relNorm, worktreeBaseBranches);
|
|
34487
34960
|
try {
|
|
@@ -34534,9 +35007,9 @@ function resolveExistingSessionParentPath(sessionId, cache2, discover) {
|
|
|
34534
35007
|
}
|
|
34535
35008
|
|
|
34536
35009
|
// src/worktrees/manager/resolve-explicit-session-parent-path.ts
|
|
34537
|
-
import * as
|
|
35010
|
+
import * as path27 from "node:path";
|
|
34538
35011
|
function resolveExplicitSessionParentPath(params) {
|
|
34539
|
-
const resolved =
|
|
35012
|
+
const resolved = path27.resolve(params.parentPathRaw);
|
|
34540
35013
|
if (parseSessionParent(params.sessionParent) !== "worktrees_root") {
|
|
34541
35014
|
return resolved;
|
|
34542
35015
|
}
|
|
@@ -34552,7 +35025,7 @@ function resolveExplicitSessionParentPath(params) {
|
|
|
34552
35025
|
for (let i = 0; i < 16; i++) {
|
|
34553
35026
|
const tryRoot = discoverSessionWorktreesUnderSessionWorktreeRoot(cur, params.sessionId);
|
|
34554
35027
|
if (tryRoot) return rememberAndReturn(tryRoot);
|
|
34555
|
-
const next =
|
|
35028
|
+
const next = path27.dirname(cur);
|
|
34556
35029
|
if (next === cur) break;
|
|
34557
35030
|
cur = next;
|
|
34558
35031
|
}
|
|
@@ -34604,16 +35077,16 @@ async function resolveSessionParentPathForPrompt(params) {
|
|
|
34604
35077
|
}
|
|
34605
35078
|
|
|
34606
35079
|
// src/worktrees/manager/session-worktree-cache.ts
|
|
34607
|
-
import * as
|
|
35080
|
+
import * as path28 from "node:path";
|
|
34608
35081
|
var SessionWorktreeCache = class {
|
|
34609
35082
|
sessionRepoCheckoutPaths = /* @__PURE__ */ new Map();
|
|
34610
35083
|
sessionParentPathBySession = /* @__PURE__ */ new Map();
|
|
34611
35084
|
sessionWorkingTreeRelRootBySession = /* @__PURE__ */ new Map();
|
|
34612
35085
|
remember(sessionId, binding) {
|
|
34613
|
-
const paths = binding.repoCheckoutPaths.map((p) =>
|
|
35086
|
+
const paths = binding.repoCheckoutPaths.map((p) => path28.resolve(p));
|
|
34614
35087
|
this.sessionRepoCheckoutPaths.set(sessionId, paths);
|
|
34615
|
-
this.sessionParentPathBySession.set(sessionId,
|
|
34616
|
-
this.sessionWorkingTreeRelRootBySession.set(sessionId,
|
|
35088
|
+
this.sessionParentPathBySession.set(sessionId, path28.resolve(binding.sessionParentPath));
|
|
35089
|
+
this.sessionWorkingTreeRelRootBySession.set(sessionId, path28.resolve(binding.workingTreeRelRoot));
|
|
34617
35090
|
}
|
|
34618
35091
|
clearSession(sessionId) {
|
|
34619
35092
|
const paths = this.sessionRepoCheckoutPaths.get(sessionId);
|
|
@@ -34643,7 +35116,7 @@ var SessionWorktreeCache = class {
|
|
|
34643
35116
|
const parent = this.sessionParentPathBySession.get(sessionId);
|
|
34644
35117
|
const relRoot = this.sessionWorkingTreeRelRootBySession.get(sessionId);
|
|
34645
35118
|
if (!parent || !relRoot) return false;
|
|
34646
|
-
return
|
|
35119
|
+
return path28.resolve(parent) !== path28.resolve(relRoot);
|
|
34647
35120
|
}
|
|
34648
35121
|
};
|
|
34649
35122
|
|
|
@@ -34747,29 +35220,29 @@ var SessionWorktreeManager = class {
|
|
|
34747
35220
|
};
|
|
34748
35221
|
|
|
34749
35222
|
// src/worktrees/manager/default-worktrees-root-path.ts
|
|
34750
|
-
import * as
|
|
35223
|
+
import * as path29 from "node:path";
|
|
34751
35224
|
import os8 from "node:os";
|
|
34752
35225
|
function defaultWorktreesRootPath() {
|
|
34753
|
-
return
|
|
35226
|
+
return path29.join(os8.homedir(), ".buildautomaton", "worktrees");
|
|
34754
35227
|
}
|
|
34755
35228
|
|
|
34756
35229
|
// src/files/watch-file-index.ts
|
|
34757
35230
|
import { watch } from "node:fs";
|
|
34758
|
-
import
|
|
35231
|
+
import path34 from "node:path";
|
|
34759
35232
|
|
|
34760
35233
|
// src/files/index/paths.ts
|
|
34761
|
-
import
|
|
35234
|
+
import path30 from "node:path";
|
|
34762
35235
|
import crypto2 from "node:crypto";
|
|
34763
35236
|
function getCwdHashForFileIndex(resolvedCwd) {
|
|
34764
|
-
return crypto2.createHash("sha256").update(
|
|
35237
|
+
return crypto2.createHash("sha256").update(path30.resolve(resolvedCwd)).digest("hex").slice(0, INDEX_HASH_LEN);
|
|
34765
35238
|
}
|
|
34766
35239
|
|
|
34767
35240
|
// src/files/index/build-file-index.ts
|
|
34768
|
-
import
|
|
35241
|
+
import path32 from "node:path";
|
|
34769
35242
|
|
|
34770
35243
|
// src/files/index/walk-workspace-tree.ts
|
|
34771
|
-
import
|
|
34772
|
-
import
|
|
35244
|
+
import fs25 from "node:fs";
|
|
35245
|
+
import path31 from "node:path";
|
|
34773
35246
|
var DEPENDENCY_INSTALL_DIR_NAMES = /* @__PURE__ */ new Set([
|
|
34774
35247
|
"node_modules",
|
|
34775
35248
|
"bower_components",
|
|
@@ -34786,7 +35259,7 @@ function shouldSkipWorkspaceWalkEntry(name) {
|
|
|
34786
35259
|
async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
34787
35260
|
let names;
|
|
34788
35261
|
try {
|
|
34789
|
-
names = await
|
|
35262
|
+
names = await fs25.promises.readdir(dir);
|
|
34790
35263
|
} catch {
|
|
34791
35264
|
return;
|
|
34792
35265
|
}
|
|
@@ -34798,14 +35271,14 @@ async function walkWorkspaceTreeAsync(dir, baseDir, onFile, state) {
|
|
|
34798
35271
|
if (isCliImmediateShutdownRequested()) throw new CliSqliteInterrupted();
|
|
34799
35272
|
}
|
|
34800
35273
|
state.n++;
|
|
34801
|
-
const full =
|
|
35274
|
+
const full = path31.join(dir, name);
|
|
34802
35275
|
let stat2;
|
|
34803
35276
|
try {
|
|
34804
|
-
stat2 = await
|
|
35277
|
+
stat2 = await fs25.promises.stat(full);
|
|
34805
35278
|
} catch {
|
|
34806
35279
|
continue;
|
|
34807
35280
|
}
|
|
34808
|
-
const relative6 =
|
|
35281
|
+
const relative6 = path31.relative(baseDir, full).replace(/\\/g, "/");
|
|
34809
35282
|
if (stat2.isDirectory()) {
|
|
34810
35283
|
await walkWorkspaceTreeAsync(full, baseDir, onFile, state);
|
|
34811
35284
|
} else if (stat2.isFile()) {
|
|
@@ -34818,7 +35291,7 @@ function createWalkYieldState() {
|
|
|
34818
35291
|
}
|
|
34819
35292
|
|
|
34820
35293
|
// src/files/index/file-index-sqlite-lock.ts
|
|
34821
|
-
import
|
|
35294
|
+
import fs26 from "node:fs";
|
|
34822
35295
|
function isSqliteCorruptError(e) {
|
|
34823
35296
|
const msg = e instanceof Error ? e.message : String(e);
|
|
34824
35297
|
return msg.includes("malformed") || msg.includes("database disk image is malformed") || msg.includes("corrupt");
|
|
@@ -34832,7 +35305,7 @@ function withFileIndexSqliteLock(fn) {
|
|
|
34832
35305
|
if (!isSqliteCorruptError(e)) throw e;
|
|
34833
35306
|
closeAllCliSqliteConnections();
|
|
34834
35307
|
try {
|
|
34835
|
-
|
|
35308
|
+
fs26.unlinkSync(getCliSqlitePath());
|
|
34836
35309
|
} catch {
|
|
34837
35310
|
}
|
|
34838
35311
|
chain = Promise.resolve();
|
|
@@ -34907,7 +35380,7 @@ async function collectWorkspacePathsAsync(resolved) {
|
|
|
34907
35380
|
}
|
|
34908
35381
|
async function buildFileIndexAsync(cwd) {
|
|
34909
35382
|
return withFileIndexSqliteLock(async () => {
|
|
34910
|
-
const resolved =
|
|
35383
|
+
const resolved = path32.resolve(cwd);
|
|
34911
35384
|
await yieldToEventLoop();
|
|
34912
35385
|
assertNotShutdown();
|
|
34913
35386
|
const paths = await collectWorkspacePathsAsync(resolved);
|
|
@@ -34919,7 +35392,7 @@ async function buildFileIndexAsync(cwd) {
|
|
|
34919
35392
|
}
|
|
34920
35393
|
|
|
34921
35394
|
// src/files/index/ensure-file-index.ts
|
|
34922
|
-
import
|
|
35395
|
+
import path33 from "node:path";
|
|
34923
35396
|
|
|
34924
35397
|
// src/files/index/search-file-index.ts
|
|
34925
35398
|
function escapeLikePattern(fragment) {
|
|
@@ -34971,7 +35444,7 @@ async function searchBridgeFilePathsAsync(resolvedCwd, query, limit = 100) {
|
|
|
34971
35444
|
|
|
34972
35445
|
// src/files/index/ensure-file-index.ts
|
|
34973
35446
|
async function ensureFileIndexAsync(cwd) {
|
|
34974
|
-
const resolved =
|
|
35447
|
+
const resolved = path33.resolve(cwd);
|
|
34975
35448
|
if (await bridgeFileIndexIsPopulated(resolved)) {
|
|
34976
35449
|
return { fromCache: true, pathCount: await bridgeFileIndexPathCount(resolved) };
|
|
34977
35450
|
}
|
|
@@ -35015,7 +35488,7 @@ function createFsWatcher(resolved, schedule) {
|
|
|
35015
35488
|
}
|
|
35016
35489
|
}
|
|
35017
35490
|
function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
35018
|
-
const resolved =
|
|
35491
|
+
const resolved = path34.resolve(cwd);
|
|
35019
35492
|
void buildFileIndexAsync(resolved).catch((e) => {
|
|
35020
35493
|
if (e instanceof CliSqliteInterrupted) return;
|
|
35021
35494
|
console.error("[file-index] Initial index build failed:", e);
|
|
@@ -35045,7 +35518,7 @@ function startFileIndexWatcher(cwd = getBridgeRoot()) {
|
|
|
35045
35518
|
}
|
|
35046
35519
|
|
|
35047
35520
|
// src/connection/create-bridge-connection.ts
|
|
35048
|
-
import * as
|
|
35521
|
+
import * as path45 from "node:path";
|
|
35049
35522
|
|
|
35050
35523
|
// src/dev-servers/manager/dev-server-manager.ts
|
|
35051
35524
|
import { rm as rm2 } from "node:fs/promises";
|
|
@@ -35089,7 +35562,7 @@ function forceKillChild(proc, log2, shortId, graceMs) {
|
|
|
35089
35562
|
}
|
|
35090
35563
|
|
|
35091
35564
|
// src/dev-servers/process/wire-dev-server-child-process.ts
|
|
35092
|
-
import
|
|
35565
|
+
import fs27 from "node:fs";
|
|
35093
35566
|
|
|
35094
35567
|
// src/dev-servers/manager/forward-pipe.ts
|
|
35095
35568
|
function forwardChildPipe(childReadable, terminal, onData) {
|
|
@@ -35125,7 +35598,7 @@ function wireDevServerChildProcess(d) {
|
|
|
35125
35598
|
d.setPollInterval(void 0);
|
|
35126
35599
|
return;
|
|
35127
35600
|
}
|
|
35128
|
-
|
|
35601
|
+
fs27.readFile(d.mergedLogPath, (err, buf) => {
|
|
35129
35602
|
if (err || (d.getSpawnGeneration() ?? 0) !== d.scheduledGen) return;
|
|
35130
35603
|
if (buf.length <= d.mergedReadPos.value) return;
|
|
35131
35604
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
@@ -35163,7 +35636,7 @@ ${errTail}` : ""}`);
|
|
|
35163
35636
|
d.sendStatus(code === 0 || code == null ? "stopped" : "error", detail, tails);
|
|
35164
35637
|
};
|
|
35165
35638
|
if (mergedPath) {
|
|
35166
|
-
|
|
35639
|
+
fs27.readFile(mergedPath, (err, buf) => {
|
|
35167
35640
|
if (!err && buf.length > d.mergedReadPos.value) {
|
|
35168
35641
|
const chunk = Buffer.from(buf.subarray(d.mergedReadPos.value));
|
|
35169
35642
|
if (chunk.length > 0) {
|
|
@@ -35265,13 +35738,13 @@ function parseDevServerDefs(servers) {
|
|
|
35265
35738
|
}
|
|
35266
35739
|
|
|
35267
35740
|
// src/dev-servers/manager/shell-spawn/utils.ts
|
|
35268
|
-
import
|
|
35741
|
+
import fs28 from "node:fs";
|
|
35269
35742
|
function isSpawnEbadf(e) {
|
|
35270
35743
|
return typeof e === "object" && e !== null && "code" in e && e.code === "EBADF";
|
|
35271
35744
|
}
|
|
35272
35745
|
function rmDirQuiet(dir) {
|
|
35273
35746
|
try {
|
|
35274
|
-
|
|
35747
|
+
fs28.rmSync(dir, { recursive: true, force: true });
|
|
35275
35748
|
} catch {
|
|
35276
35749
|
}
|
|
35277
35750
|
}
|
|
@@ -35279,7 +35752,7 @@ var cachedDevNullReadFd;
|
|
|
35279
35752
|
function devNullReadFd() {
|
|
35280
35753
|
if (cachedDevNullReadFd === void 0) {
|
|
35281
35754
|
const devPath = process.platform === "win32" ? "nul" : "/dev/null";
|
|
35282
|
-
cachedDevNullReadFd =
|
|
35755
|
+
cachedDevNullReadFd = fs28.openSync(devPath, "r");
|
|
35283
35756
|
}
|
|
35284
35757
|
return cachedDevNullReadFd;
|
|
35285
35758
|
}
|
|
@@ -35353,15 +35826,15 @@ function trySpawnShellTruePiped(command, env, cwd, devNullFd, signal) {
|
|
|
35353
35826
|
|
|
35354
35827
|
// src/dev-servers/manager/shell-spawn/try-spawn-merged-log-file.ts
|
|
35355
35828
|
import { spawn as spawn8 } from "node:child_process";
|
|
35356
|
-
import
|
|
35829
|
+
import fs29 from "node:fs";
|
|
35357
35830
|
import { tmpdir } from "node:os";
|
|
35358
|
-
import
|
|
35831
|
+
import path35 from "node:path";
|
|
35359
35832
|
function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
35360
|
-
const tmpRoot =
|
|
35361
|
-
const logPath =
|
|
35833
|
+
const tmpRoot = fs29.mkdtempSync(path35.join(tmpdir(), "ba-devsrv-log-"));
|
|
35834
|
+
const logPath = path35.join(tmpRoot, "combined.log");
|
|
35362
35835
|
let logFd;
|
|
35363
35836
|
try {
|
|
35364
|
-
logFd =
|
|
35837
|
+
logFd = fs29.openSync(logPath, "a");
|
|
35365
35838
|
} catch {
|
|
35366
35839
|
rmDirQuiet(tmpRoot);
|
|
35367
35840
|
return null;
|
|
@@ -35380,7 +35853,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35380
35853
|
} else {
|
|
35381
35854
|
proc = spawn8("/bin/sh", ["-c", command], { env, cwd, stdio, ...signal ? { signal } : {} });
|
|
35382
35855
|
}
|
|
35383
|
-
|
|
35856
|
+
fs29.closeSync(logFd);
|
|
35384
35857
|
return {
|
|
35385
35858
|
proc,
|
|
35386
35859
|
pipedStdoutStderr: true,
|
|
@@ -35389,7 +35862,7 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35389
35862
|
};
|
|
35390
35863
|
} catch (e) {
|
|
35391
35864
|
try {
|
|
35392
|
-
|
|
35865
|
+
fs29.closeSync(logFd);
|
|
35393
35866
|
} catch {
|
|
35394
35867
|
}
|
|
35395
35868
|
rmDirQuiet(tmpRoot);
|
|
@@ -35400,22 +35873,22 @@ function trySpawnMergedLogFile(command, env, cwd, signal) {
|
|
|
35400
35873
|
|
|
35401
35874
|
// src/dev-servers/manager/shell-spawn/try-spawn-shell-script-log-redirect.ts
|
|
35402
35875
|
import { spawn as spawn9 } from "node:child_process";
|
|
35403
|
-
import
|
|
35876
|
+
import fs30 from "node:fs";
|
|
35404
35877
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
35405
|
-
import
|
|
35878
|
+
import path36 from "node:path";
|
|
35406
35879
|
function shSingleQuote(s) {
|
|
35407
35880
|
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
35408
35881
|
}
|
|
35409
35882
|
function trySpawnShellScriptLogRedirectUnix(command, env, cwd, signal) {
|
|
35410
|
-
const tmpRoot =
|
|
35411
|
-
const logPath =
|
|
35412
|
-
const innerPath =
|
|
35413
|
-
const runnerPath =
|
|
35883
|
+
const tmpRoot = fs30.mkdtempSync(path36.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
35884
|
+
const logPath = path36.join(tmpRoot, "combined.log");
|
|
35885
|
+
const innerPath = path36.join(tmpRoot, "_cmd.sh");
|
|
35886
|
+
const runnerPath = path36.join(tmpRoot, "_run.sh");
|
|
35414
35887
|
try {
|
|
35415
|
-
|
|
35888
|
+
fs30.writeFileSync(innerPath, `#!/bin/sh
|
|
35416
35889
|
${command}
|
|
35417
35890
|
`);
|
|
35418
|
-
|
|
35891
|
+
fs30.writeFileSync(
|
|
35419
35892
|
runnerPath,
|
|
35420
35893
|
`#!/bin/sh
|
|
35421
35894
|
cd ${shSingleQuote(cwd)}
|
|
@@ -35441,13 +35914,13 @@ cd ${shSingleQuote(cwd)}
|
|
|
35441
35914
|
}
|
|
35442
35915
|
}
|
|
35443
35916
|
function trySpawnShellScriptLogRedirectWin(command, env, cwd, signal) {
|
|
35444
|
-
const tmpRoot =
|
|
35445
|
-
const logPath =
|
|
35446
|
-
const runnerPath =
|
|
35917
|
+
const tmpRoot = fs30.mkdtempSync(path36.join(tmpdir2(), "ba-devsrv-sh-"));
|
|
35918
|
+
const logPath = path36.join(tmpRoot, "combined.log");
|
|
35919
|
+
const runnerPath = path36.join(tmpRoot, "_run.bat");
|
|
35447
35920
|
const q = (p) => `"${p.replace(/"/g, '""')}"`;
|
|
35448
35921
|
const com = process.env.ComSpec || "cmd.exe";
|
|
35449
35922
|
try {
|
|
35450
|
-
|
|
35923
|
+
fs30.writeFileSync(
|
|
35451
35924
|
runnerPath,
|
|
35452
35925
|
`@ECHO OFF\r
|
|
35453
35926
|
CD /D ${q(cwd)}\r
|
|
@@ -36216,30 +36689,30 @@ function createOnBridgeIdentified(opts) {
|
|
|
36216
36689
|
}
|
|
36217
36690
|
|
|
36218
36691
|
// src/skills/discover-local-agent-skills.ts
|
|
36219
|
-
import
|
|
36220
|
-
import
|
|
36692
|
+
import fs31 from "node:fs";
|
|
36693
|
+
import path37 from "node:path";
|
|
36221
36694
|
var SKILL_DISCOVERY_ROOTS = [".agents/skills", ".claude/skills", ".cursor/skills", "skills"];
|
|
36222
36695
|
function discoverLocalSkills(cwd) {
|
|
36223
36696
|
const out = [];
|
|
36224
36697
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
36225
36698
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
36226
|
-
const base =
|
|
36227
|
-
if (!
|
|
36699
|
+
const base = path37.join(cwd, rel);
|
|
36700
|
+
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
36228
36701
|
let entries = [];
|
|
36229
36702
|
try {
|
|
36230
|
-
entries =
|
|
36703
|
+
entries = fs31.readdirSync(base);
|
|
36231
36704
|
} catch {
|
|
36232
36705
|
continue;
|
|
36233
36706
|
}
|
|
36234
36707
|
for (const name of entries) {
|
|
36235
|
-
const dir =
|
|
36708
|
+
const dir = path37.join(base, name);
|
|
36236
36709
|
try {
|
|
36237
|
-
if (!
|
|
36710
|
+
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
36238
36711
|
} catch {
|
|
36239
36712
|
continue;
|
|
36240
36713
|
}
|
|
36241
|
-
const skillMd =
|
|
36242
|
-
if (!
|
|
36714
|
+
const skillMd = path37.join(dir, "SKILL.md");
|
|
36715
|
+
if (!fs31.existsSync(skillMd)) continue;
|
|
36243
36716
|
const key = `${rel}/${name}`;
|
|
36244
36717
|
if (seenKeys.has(key)) continue;
|
|
36245
36718
|
seenKeys.add(key);
|
|
@@ -36251,23 +36724,23 @@ function discoverLocalSkills(cwd) {
|
|
|
36251
36724
|
function discoverSkillLayoutRoots(cwd) {
|
|
36252
36725
|
const roots = [];
|
|
36253
36726
|
for (const rel of SKILL_DISCOVERY_ROOTS) {
|
|
36254
|
-
const base =
|
|
36255
|
-
if (!
|
|
36727
|
+
const base = path37.join(cwd, rel);
|
|
36728
|
+
if (!fs31.existsSync(base) || !fs31.statSync(base).isDirectory()) continue;
|
|
36256
36729
|
let entries = [];
|
|
36257
36730
|
try {
|
|
36258
|
-
entries =
|
|
36731
|
+
entries = fs31.readdirSync(base);
|
|
36259
36732
|
} catch {
|
|
36260
36733
|
continue;
|
|
36261
36734
|
}
|
|
36262
36735
|
const skills2 = [];
|
|
36263
36736
|
for (const name of entries) {
|
|
36264
|
-
const dir =
|
|
36737
|
+
const dir = path37.join(base, name);
|
|
36265
36738
|
try {
|
|
36266
|
-
if (!
|
|
36739
|
+
if (!fs31.statSync(dir).isDirectory()) continue;
|
|
36267
36740
|
} catch {
|
|
36268
36741
|
continue;
|
|
36269
36742
|
}
|
|
36270
|
-
if (!
|
|
36743
|
+
if (!fs31.existsSync(path37.join(dir, "SKILL.md"))) continue;
|
|
36271
36744
|
const relPath = `${rel}/${name}`.replace(/\\/g, "/");
|
|
36272
36745
|
skills2.push({ name, relPath });
|
|
36273
36746
|
}
|
|
@@ -36623,7 +37096,7 @@ function syncRunningTurnQueueKeys(turns, queueKey) {
|
|
|
36623
37096
|
}
|
|
36624
37097
|
|
|
36625
37098
|
// src/prompt-turn-queue/runner/run-local-revert-before-queued-prompt.ts
|
|
36626
|
-
import
|
|
37099
|
+
import fs32 from "node:fs";
|
|
36627
37100
|
async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
36628
37101
|
if (next.serverState !== "requeued_with_revert") return true;
|
|
36629
37102
|
const sid = next.sessionId;
|
|
@@ -36632,7 +37105,7 @@ async function runLocalRevertBeforeQueuedPrompt(next, deps) {
|
|
|
36632
37105
|
const agentBase = deps.sessionWorktreeManager.getSessionWorktreeRootForSession(sid) ?? getBridgeRoot();
|
|
36633
37106
|
const file2 = snapshotFilePath(agentBase, tid);
|
|
36634
37107
|
try {
|
|
36635
|
-
await
|
|
37108
|
+
await fs32.promises.access(file2, fs32.constants.F_OK);
|
|
36636
37109
|
} catch {
|
|
36637
37110
|
deps.log(
|
|
36638
37111
|
`[Queue] requeued_with_revert: no pre-turn snapshot for ${tid.slice(0, 8)}\u2026; continuing without revert.`
|
|
@@ -36920,9 +37393,9 @@ function parseChangeSummarySnapshots(raw) {
|
|
|
36920
37393
|
for (const item of raw) {
|
|
36921
37394
|
if (!item || typeof item !== "object") continue;
|
|
36922
37395
|
const o = item;
|
|
36923
|
-
const
|
|
36924
|
-
if (!
|
|
36925
|
-
const row = { path:
|
|
37396
|
+
const path46 = typeof o.path === "string" && o.path.trim() !== "" ? o.path.trim() : "";
|
|
37397
|
+
if (!path46) continue;
|
|
37398
|
+
const row = { path: path46 };
|
|
36926
37399
|
if (typeof o.patchContent === "string") row.patchContent = o.patchContent;
|
|
36927
37400
|
if (typeof o.oldText === "string") row.oldText = o.oldText;
|
|
36928
37401
|
if (typeof o.newText === "string") row.newText = o.newText;
|
|
@@ -37136,14 +37609,14 @@ var handleSkillCallMessage = (msg, { getWs, log: log2 }) => {
|
|
|
37136
37609
|
};
|
|
37137
37610
|
|
|
37138
37611
|
// src/files/list-dir/index.ts
|
|
37139
|
-
import
|
|
37612
|
+
import fs34 from "node:fs";
|
|
37140
37613
|
|
|
37141
37614
|
// src/files/ensure-under-cwd.ts
|
|
37142
|
-
import
|
|
37615
|
+
import path38 from "node:path";
|
|
37143
37616
|
function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
37144
|
-
const normalized =
|
|
37145
|
-
const resolved =
|
|
37146
|
-
if (!resolved.startsWith(cwd +
|
|
37617
|
+
const normalized = path38.normalize(relativePath).replace(/^(\.\/)+/, "");
|
|
37618
|
+
const resolved = path38.resolve(cwd, normalized);
|
|
37619
|
+
if (!resolved.startsWith(cwd + path38.sep) && resolved !== cwd) {
|
|
37147
37620
|
return null;
|
|
37148
37621
|
}
|
|
37149
37622
|
return resolved;
|
|
@@ -37153,15 +37626,15 @@ function ensureUnderCwd(relativePath, cwd = getBridgeRoot()) {
|
|
|
37153
37626
|
var LIST_DIR_YIELD_EVERY = 256;
|
|
37154
37627
|
|
|
37155
37628
|
// src/files/list-dir/map-dir-entry.ts
|
|
37156
|
-
import
|
|
37157
|
-
import
|
|
37629
|
+
import path39 from "node:path";
|
|
37630
|
+
import fs33 from "node:fs";
|
|
37158
37631
|
async function mapDirEntry(d, relativePath, resolved) {
|
|
37159
|
-
const entryPath =
|
|
37160
|
-
const fullPath =
|
|
37632
|
+
const entryPath = path39.join(relativePath || ".", d.name).replace(/\\/g, "/");
|
|
37633
|
+
const fullPath = path39.join(resolved, d.name);
|
|
37161
37634
|
let isDir = d.isDirectory();
|
|
37162
37635
|
if (d.isSymbolicLink()) {
|
|
37163
37636
|
try {
|
|
37164
|
-
const targetStat = await
|
|
37637
|
+
const targetStat = await fs33.promises.stat(fullPath);
|
|
37165
37638
|
isDir = targetStat.isDirectory();
|
|
37166
37639
|
} catch {
|
|
37167
37640
|
isDir = false;
|
|
@@ -37191,7 +37664,7 @@ async function listDirAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
|
37191
37664
|
return { error: "Path is outside working directory" };
|
|
37192
37665
|
}
|
|
37193
37666
|
try {
|
|
37194
|
-
const names = await
|
|
37667
|
+
const names = await fs34.promises.readdir(resolved, { withFileTypes: true });
|
|
37195
37668
|
const entries = [];
|
|
37196
37669
|
for (let i = 0; i < names.length; i++) {
|
|
37197
37670
|
if (i > 0 && i % LIST_DIR_YIELD_EVERY === 0) {
|
|
@@ -37211,18 +37684,18 @@ var LINE_CHUNK_SIZE = 64 * 1024;
|
|
|
37211
37684
|
var READ_RANGE_YIELD_EVERY_BYTES = 256 * 1024;
|
|
37212
37685
|
|
|
37213
37686
|
// src/files/read-file/resolve-file-path.ts
|
|
37214
|
-
import
|
|
37687
|
+
import fs35 from "node:fs";
|
|
37215
37688
|
async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeRoot()) {
|
|
37216
37689
|
const resolved = ensureUnderCwd(relativePath, sessionParentPath);
|
|
37217
37690
|
if (!resolved) return { error: "Path is outside working directory" };
|
|
37218
37691
|
let real;
|
|
37219
37692
|
try {
|
|
37220
|
-
real = await
|
|
37693
|
+
real = await fs35.promises.realpath(resolved);
|
|
37221
37694
|
} catch {
|
|
37222
37695
|
real = resolved;
|
|
37223
37696
|
}
|
|
37224
37697
|
try {
|
|
37225
|
-
const stat2 = await
|
|
37698
|
+
const stat2 = await fs35.promises.stat(real);
|
|
37226
37699
|
if (!stat2.isFile()) return { error: "Not a file" };
|
|
37227
37700
|
return real;
|
|
37228
37701
|
} catch (err) {
|
|
@@ -37231,11 +37704,11 @@ async function resolveFilePathAsync(relativePath, sessionParentPath = getBridgeR
|
|
|
37231
37704
|
}
|
|
37232
37705
|
|
|
37233
37706
|
// src/files/read-file/read-file-range-async.ts
|
|
37234
|
-
import
|
|
37707
|
+
import fs36 from "node:fs";
|
|
37235
37708
|
import { StringDecoder } from "node:string_decoder";
|
|
37236
37709
|
async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, lineChunkSize = LINE_CHUNK_SIZE) {
|
|
37237
|
-
const fileSize = (await
|
|
37238
|
-
const fd = await
|
|
37710
|
+
const fileSize = (await fs36.promises.stat(filePath)).size;
|
|
37711
|
+
const fd = await fs36.promises.open(filePath, "r");
|
|
37239
37712
|
const bufSize = 64 * 1024;
|
|
37240
37713
|
const buf = Buffer.alloc(bufSize);
|
|
37241
37714
|
const decoder = new StringDecoder("utf8");
|
|
@@ -37397,11 +37870,11 @@ async function readFileRangeAsync(filePath, startLine, endLine, lineOffsetIn, li
|
|
|
37397
37870
|
}
|
|
37398
37871
|
|
|
37399
37872
|
// src/files/read-file/read-file-buffer-full-async.ts
|
|
37400
|
-
import
|
|
37873
|
+
import fs37 from "node:fs";
|
|
37401
37874
|
var READ_CHUNK_BYTES = 256 * 1024;
|
|
37402
37875
|
async function readFileBufferFullAsync(filePath) {
|
|
37403
|
-
const stat2 = await
|
|
37404
|
-
const fd = await
|
|
37876
|
+
const stat2 = await fs37.promises.stat(filePath);
|
|
37877
|
+
const fd = await fs37.promises.open(filePath, "r");
|
|
37405
37878
|
const chunks = [];
|
|
37406
37879
|
let position = 0;
|
|
37407
37880
|
let bytesSinceYield = 0;
|
|
@@ -37508,13 +37981,13 @@ function resolveFileBrowserSessionParent(sessionWorktreeManager, sessionId) {
|
|
|
37508
37981
|
}
|
|
37509
37982
|
|
|
37510
37983
|
// src/files/handle-file-browser-search.ts
|
|
37511
|
-
import
|
|
37984
|
+
import path40 from "node:path";
|
|
37512
37985
|
var SEARCH_LIMIT = 100;
|
|
37513
37986
|
function handleFileBrowserSearch(msg, socket, e2ee, sessionWorktreeManager) {
|
|
37514
37987
|
void (async () => {
|
|
37515
37988
|
await yieldToEventLoop();
|
|
37516
37989
|
const q = typeof msg.q === "string" ? msg.q : "";
|
|
37517
|
-
const sessionParentPath =
|
|
37990
|
+
const sessionParentPath = path40.resolve(
|
|
37518
37991
|
sessionWorktreeManager != null ? resolveFileBrowserSessionParent(sessionWorktreeManager, msg.sessionId) : getBridgeRoot()
|
|
37519
37992
|
);
|
|
37520
37993
|
if (!await bridgeFileIndexIsPopulated(sessionParentPath)) {
|
|
@@ -37633,8 +38106,8 @@ function handleSkillLayoutRequest(msg, deps) {
|
|
|
37633
38106
|
}
|
|
37634
38107
|
|
|
37635
38108
|
// src/skills/install-remote-skills.ts
|
|
37636
|
-
import
|
|
37637
|
-
import
|
|
38109
|
+
import fs38 from "node:fs";
|
|
38110
|
+
import path41 from "node:path";
|
|
37638
38111
|
function installRemoteSkills(cwd, targetDir, items) {
|
|
37639
38112
|
const installed2 = [];
|
|
37640
38113
|
if (!Array.isArray(items)) {
|
|
@@ -37645,15 +38118,15 @@ function installRemoteSkills(cwd, targetDir, items) {
|
|
|
37645
38118
|
if (typeof item.sourceId !== "string" || typeof item.skillName !== "string" || typeof item.versionHash !== "string" || !Array.isArray(item.files)) {
|
|
37646
38119
|
continue;
|
|
37647
38120
|
}
|
|
37648
|
-
const skillDir =
|
|
38121
|
+
const skillDir = path41.join(cwd, targetDir, item.skillName);
|
|
37649
38122
|
for (const f of item.files) {
|
|
37650
38123
|
if (typeof f.path !== "string" || !f.text && !f.base64) continue;
|
|
37651
|
-
const dest =
|
|
37652
|
-
|
|
38124
|
+
const dest = path41.join(skillDir, f.path);
|
|
38125
|
+
fs38.mkdirSync(path41.dirname(dest), { recursive: true });
|
|
37653
38126
|
if (f.text !== void 0) {
|
|
37654
|
-
|
|
38127
|
+
fs38.writeFileSync(dest, f.text, "utf8");
|
|
37655
38128
|
} else if (f.base64) {
|
|
37656
|
-
|
|
38129
|
+
fs38.writeFileSync(dest, Buffer.from(f.base64, "base64"));
|
|
37657
38130
|
}
|
|
37658
38131
|
}
|
|
37659
38132
|
installed2.push({
|
|
@@ -37811,7 +38284,7 @@ var handleSessionDiscardedMessage = (msg, deps) => {
|
|
|
37811
38284
|
};
|
|
37812
38285
|
|
|
37813
38286
|
// src/routing/handlers/revert-turn-snapshot.ts
|
|
37814
|
-
import * as
|
|
38287
|
+
import * as fs39 from "node:fs";
|
|
37815
38288
|
var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
37816
38289
|
const id = typeof msg.id === "string" ? msg.id : "";
|
|
37817
38290
|
const sessionId = typeof msg.sessionId === "string" ? msg.sessionId : "";
|
|
@@ -37824,7 +38297,7 @@ var handleRevertTurnSnapshotMessage = (msg, deps) => {
|
|
|
37824
38297
|
const agentBase = sessionWorktreeManager.getSessionWorktreeRootForSession(sessionId) ?? getBridgeRoot();
|
|
37825
38298
|
const file2 = snapshotFilePath(agentBase, turnId);
|
|
37826
38299
|
try {
|
|
37827
|
-
await
|
|
38300
|
+
await fs39.promises.access(file2, fs39.constants.F_OK);
|
|
37828
38301
|
} catch {
|
|
37829
38302
|
sendWsMessage(s, {
|
|
37830
38303
|
type: "revert_turn_snapshot_result",
|
|
@@ -37866,7 +38339,7 @@ var handleDevServersConfig = (msg, deps) => {
|
|
|
37866
38339
|
};
|
|
37867
38340
|
|
|
37868
38341
|
// src/git/bridge-git-context.ts
|
|
37869
|
-
import * as
|
|
38342
|
+
import * as path42 from "node:path";
|
|
37870
38343
|
|
|
37871
38344
|
// src/git/branches/get-current-branch.ts
|
|
37872
38345
|
async function getCurrentBranch(repoPath) {
|
|
@@ -37916,12 +38389,12 @@ async function listRepoBranchRefs(repoPath) {
|
|
|
37916
38389
|
// src/git/bridge-git-context.ts
|
|
37917
38390
|
function folderNameForRelPath(relPath, bridgeRoot) {
|
|
37918
38391
|
if (relPath === "." || relPath === "") {
|
|
37919
|
-
return
|
|
38392
|
+
return path42.basename(path42.resolve(bridgeRoot)) || "repo";
|
|
37920
38393
|
}
|
|
37921
|
-
return
|
|
38394
|
+
return path42.basename(relPath) || relPath;
|
|
37922
38395
|
}
|
|
37923
38396
|
async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
37924
|
-
const root =
|
|
38397
|
+
const root = path42.resolve(bridgeRoot);
|
|
37925
38398
|
if (await isGitRepoDirectory(root)) {
|
|
37926
38399
|
const remoteUrl = await getRemoteOriginUrl(root);
|
|
37927
38400
|
return [{ absolutePath: root, remoteUrl }];
|
|
@@ -37929,17 +38402,17 @@ async function discoverGitReposForBridgeContext(bridgeRoot) {
|
|
|
37929
38402
|
const [deep, shallow] = await Promise.all([discoverGitReposUnderRoot(root), discoverGitRepos(root)]);
|
|
37930
38403
|
const byPath = /* @__PURE__ */ new Map();
|
|
37931
38404
|
for (const repo of [...deep, ...shallow]) {
|
|
37932
|
-
byPath.set(
|
|
38405
|
+
byPath.set(path42.resolve(repo.absolutePath), repo);
|
|
37933
38406
|
}
|
|
37934
38407
|
return [...byPath.values()];
|
|
37935
38408
|
}
|
|
37936
38409
|
async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
37937
|
-
const bridgeResolved =
|
|
38410
|
+
const bridgeResolved = path42.resolve(bridgeRoot);
|
|
37938
38411
|
const repos = await discoverGitReposForBridgeContext(bridgeResolved);
|
|
37939
38412
|
const rows = [];
|
|
37940
38413
|
for (const repo of repos) {
|
|
37941
|
-
let rel =
|
|
37942
|
-
if (rel.startsWith("..") ||
|
|
38414
|
+
let rel = path42.relative(bridgeResolved, repo.absolutePath);
|
|
38415
|
+
if (rel.startsWith("..") || path42.isAbsolute(rel)) continue;
|
|
37943
38416
|
const relPath = rel === "" ? "." : rel.replace(/\\/g, "/");
|
|
37944
38417
|
const currentBranch = await getCurrentBranch(repo.absolutePath);
|
|
37945
38418
|
const remoteUrl = repo.remoteUrl.trim() || null;
|
|
@@ -37954,11 +38427,11 @@ async function getBridgeGitContext(bridgeRoot = getBridgeRoot()) {
|
|
|
37954
38427
|
return rows;
|
|
37955
38428
|
}
|
|
37956
38429
|
async function listRepoBranchesForBridge(repoRelPath, bridgeRoot = getBridgeRoot()) {
|
|
37957
|
-
const bridgeResolved =
|
|
38430
|
+
const bridgeResolved = path42.resolve(bridgeRoot);
|
|
37958
38431
|
const rel = repoRelPath.trim() === "." ? "" : repoRelPath.trim().replace(/\\/g, "/");
|
|
37959
|
-
const repoPath = rel === "" ? bridgeResolved :
|
|
37960
|
-
const resolved =
|
|
37961
|
-
if (!resolved.startsWith(bridgeResolved +
|
|
38432
|
+
const repoPath = rel === "" ? bridgeResolved : path42.join(bridgeResolved, rel);
|
|
38433
|
+
const resolved = path42.resolve(repoPath);
|
|
38434
|
+
if (!resolved.startsWith(bridgeResolved + path42.sep) && resolved !== bridgeResolved) {
|
|
37962
38435
|
return [];
|
|
37963
38436
|
}
|
|
37964
38437
|
return listRepoBranchRefs(resolved);
|
|
@@ -38542,10 +39015,10 @@ function listCliAgentCapabilityCacheForWorkspace(db, workspaceId) {
|
|
|
38542
39015
|
}
|
|
38543
39016
|
|
|
38544
39017
|
// src/agents/capabilities/warmup-agent-capabilities-on-connect.ts
|
|
38545
|
-
import * as
|
|
39018
|
+
import * as path44 from "node:path";
|
|
38546
39019
|
|
|
38547
39020
|
// src/agents/capabilities/probe-one-agent-type-for-capabilities.ts
|
|
38548
|
-
import * as
|
|
39021
|
+
import * as path43 from "node:path";
|
|
38549
39022
|
async function probeOneAgentTypeForCapabilities(params) {
|
|
38550
39023
|
const { agentType, cwd, workspaceId, log: log2, reportAgentCapabilities, bridgeReport = true, shouldContinue } = params;
|
|
38551
39024
|
const canContinue = () => shouldContinue?.() !== false;
|
|
@@ -38583,7 +39056,7 @@ async function probeOneAgentTypeForCapabilities(params) {
|
|
|
38583
39056
|
if (!canContinue()) return false;
|
|
38584
39057
|
handle = await resolved.createClient({
|
|
38585
39058
|
command: resolved.command,
|
|
38586
|
-
cwd:
|
|
39059
|
+
cwd: path43.resolve(cwd),
|
|
38587
39060
|
backendAgentType: agentType,
|
|
38588
39061
|
sessionMode: "agent",
|
|
38589
39062
|
persistedAcpSessionId: null,
|
|
@@ -38661,7 +39134,7 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
38661
39134
|
const { workspaceId, log: log2, getWs } = params;
|
|
38662
39135
|
const isCurrent = beginAgentCapabilityWarmupRun();
|
|
38663
39136
|
if (!isCurrent()) return;
|
|
38664
|
-
const cwd =
|
|
39137
|
+
const cwd = path44.resolve(getBridgeRoot());
|
|
38665
39138
|
async function sendBatchFromCache() {
|
|
38666
39139
|
if (!isCurrent()) return;
|
|
38667
39140
|
const socket = getWs();
|
|
@@ -38727,6 +39200,232 @@ async function warmupAgentCapabilitiesOnConnect(params) {
|
|
|
38727
39200
|
})();
|
|
38728
39201
|
}
|
|
38729
39202
|
|
|
39203
|
+
// src/mcp/tools/session-history/fork-session-mcp-tools.ts
|
|
39204
|
+
var LIST_PARENT_SESSION_PROMPTS_TOOL = "list_parent_session_prompts";
|
|
39205
|
+
var GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL = "get_parent_session_turn_transcript";
|
|
39206
|
+
var SESSION_ID_SCHEMA = {
|
|
39207
|
+
type: "string",
|
|
39208
|
+
description: "Id of this forked (child) session \u2014 not the parent session id. Required on every tool call."
|
|
39209
|
+
};
|
|
39210
|
+
var FORK_SESSION_MCP_TOOL_DEFINITIONS = [
|
|
39211
|
+
{
|
|
39212
|
+
name: LIST_PARENT_SESSION_PROMPTS_TOOL,
|
|
39213
|
+
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).",
|
|
39214
|
+
inputSchema: {
|
|
39215
|
+
type: "object",
|
|
39216
|
+
properties: { sessionId: SESSION_ID_SCHEMA },
|
|
39217
|
+
required: ["sessionId"],
|
|
39218
|
+
additionalProperties: false
|
|
39219
|
+
}
|
|
39220
|
+
},
|
|
39221
|
+
{
|
|
39222
|
+
name: GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL,
|
|
39223
|
+
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).",
|
|
39224
|
+
inputSchema: {
|
|
39225
|
+
type: "object",
|
|
39226
|
+
properties: {
|
|
39227
|
+
sessionId: SESSION_ID_SCHEMA,
|
|
39228
|
+
turnId: { type: "string", description: "Turn id from list_parent_session_prompts" }
|
|
39229
|
+
},
|
|
39230
|
+
required: ["sessionId", "turnId"],
|
|
39231
|
+
additionalProperties: false
|
|
39232
|
+
}
|
|
39233
|
+
}
|
|
39234
|
+
];
|
|
39235
|
+
function textResult(text, isError = false) {
|
|
39236
|
+
return { content: [{ type: "text", text }], ...isError ? { isError: true } : {} };
|
|
39237
|
+
}
|
|
39238
|
+
function isForkSessionMcpToolName(name) {
|
|
39239
|
+
return name === LIST_PARENT_SESSION_PROMPTS_TOOL || name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL;
|
|
39240
|
+
}
|
|
39241
|
+
async function callForkSessionMcpTool(ctx, cloud, name, args) {
|
|
39242
|
+
const childSessionId = ctx.sessionId.trim();
|
|
39243
|
+
if (!childSessionId) {
|
|
39244
|
+
return textResult("sessionId is required.", true);
|
|
39245
|
+
}
|
|
39246
|
+
const parentResolved = await resolveParentSessionIdForChild({
|
|
39247
|
+
childSessionId,
|
|
39248
|
+
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
39249
|
+
getCloudAccessToken: cloud.getCloudAccessToken
|
|
39250
|
+
});
|
|
39251
|
+
if (!parentResolved.ok) {
|
|
39252
|
+
return textResult(parentResolved.error, true);
|
|
39253
|
+
}
|
|
39254
|
+
const parentSessionId = parentResolved.parentSessionId;
|
|
39255
|
+
if (name === LIST_PARENT_SESSION_PROMPTS_TOOL) {
|
|
39256
|
+
const detail = await fetchCloudParentSessionPrompts({
|
|
39257
|
+
childSessionId,
|
|
39258
|
+
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
39259
|
+
getCloudAccessToken: cloud.getCloudAccessToken
|
|
39260
|
+
});
|
|
39261
|
+
if (!detail.ok) return textResult(detail.error, true);
|
|
39262
|
+
const turns = Array.isArray(detail.data.turns) ? detail.data.turns : [];
|
|
39263
|
+
const payload = turns.map((t) => ({
|
|
39264
|
+
turnId: typeof t.turnId === "string" ? t.turnId : "",
|
|
39265
|
+
title: typeof t.title === "string" ? t.title : null,
|
|
39266
|
+
status: typeof t.status === "string" ? t.status : null,
|
|
39267
|
+
promptText: typeof t.promptText === "string" ? t.promptText : null
|
|
39268
|
+
}));
|
|
39269
|
+
return textResult(JSON.stringify({ parentSessionId, turns: payload }, null, 2));
|
|
39270
|
+
}
|
|
39271
|
+
if (name === GET_PARENT_SESSION_TURN_TRANSCRIPT_TOOL) {
|
|
39272
|
+
const turnId = typeof args.turnId === "string" ? args.turnId.trim() : "";
|
|
39273
|
+
if (!turnId) return textResult("turnId is required.", true);
|
|
39274
|
+
const transcript = await fetchCloudParentTurnTranscript({
|
|
39275
|
+
childSessionId,
|
|
39276
|
+
turnId,
|
|
39277
|
+
cloudApiBaseUrl: cloud.cloudApiBaseUrl,
|
|
39278
|
+
getCloudAccessToken: cloud.getCloudAccessToken,
|
|
39279
|
+
e2ee: ctx.e2ee
|
|
39280
|
+
});
|
|
39281
|
+
if (!transcript.ok) return textResult(transcript.error, true);
|
|
39282
|
+
return textResult(transcript.text);
|
|
39283
|
+
}
|
|
39284
|
+
return textResult(`Unknown fork session tool: ${name}`, true);
|
|
39285
|
+
}
|
|
39286
|
+
|
|
39287
|
+
// src/mcp/bridge-mcp-tools.ts
|
|
39288
|
+
function requireCloud(shared) {
|
|
39289
|
+
const cloudApiBaseUrl = shared.cloudApiBaseUrl?.trim() ?? "";
|
|
39290
|
+
const getCloudAccessToken = shared.getCloudAccessToken;
|
|
39291
|
+
if (!cloudApiBaseUrl || !getCloudAccessToken) return null;
|
|
39292
|
+
return { cloudApiBaseUrl, getCloudAccessToken };
|
|
39293
|
+
}
|
|
39294
|
+
function createBridgeMcpToolRegistry(shared) {
|
|
39295
|
+
const cloud = requireCloud(shared);
|
|
39296
|
+
return {
|
|
39297
|
+
listTools: async () => [...FORK_SESSION_MCP_TOOL_DEFINITIONS],
|
|
39298
|
+
callTool: async (name, args) => {
|
|
39299
|
+
if (isForkSessionMcpToolName(name)) {
|
|
39300
|
+
if (!cloud) {
|
|
39301
|
+
return {
|
|
39302
|
+
content: [{ type: "text", text: "Bridge MCP tools require cloud API credentials." }],
|
|
39303
|
+
isError: true
|
|
39304
|
+
};
|
|
39305
|
+
}
|
|
39306
|
+
const sessionId = typeof args.sessionId === "string" ? args.sessionId.trim() : "";
|
|
39307
|
+
if (!sessionId) {
|
|
39308
|
+
return {
|
|
39309
|
+
content: [{ type: "text", text: "sessionId is required." }],
|
|
39310
|
+
isError: true
|
|
39311
|
+
};
|
|
39312
|
+
}
|
|
39313
|
+
return callForkSessionMcpTool({ ...shared, sessionId }, cloud, name, args);
|
|
39314
|
+
}
|
|
39315
|
+
throw new Error(`Unknown bridge MCP tool: ${name}`);
|
|
39316
|
+
}
|
|
39317
|
+
};
|
|
39318
|
+
}
|
|
39319
|
+
|
|
39320
|
+
// src/mcp/bridge-access/start-server.ts
|
|
39321
|
+
import * as http from "node:http";
|
|
39322
|
+
|
|
39323
|
+
// src/mcp/bridge-access/read-json-body.ts
|
|
39324
|
+
function readJsonBody(req) {
|
|
39325
|
+
return new Promise((resolve20, reject) => {
|
|
39326
|
+
const chunks = [];
|
|
39327
|
+
req.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
39328
|
+
req.on("end", () => {
|
|
39329
|
+
try {
|
|
39330
|
+
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
39331
|
+
if (!raw) {
|
|
39332
|
+
resolve20({});
|
|
39333
|
+
return;
|
|
39334
|
+
}
|
|
39335
|
+
const parsed = JSON.parse(raw);
|
|
39336
|
+
resolve20(parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {});
|
|
39337
|
+
} catch (e) {
|
|
39338
|
+
reject(e);
|
|
39339
|
+
}
|
|
39340
|
+
});
|
|
39341
|
+
req.on("error", reject);
|
|
39342
|
+
});
|
|
39343
|
+
}
|
|
39344
|
+
|
|
39345
|
+
// src/mcp/bridge-access/send-json-response.ts
|
|
39346
|
+
function sendJsonResponse(res, status, body) {
|
|
39347
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
39348
|
+
res.end(JSON.stringify(body));
|
|
39349
|
+
}
|
|
39350
|
+
|
|
39351
|
+
// src/mcp/bridge-access/handle-request.ts
|
|
39352
|
+
function createBridgeAccessRequestHandler(registry2) {
|
|
39353
|
+
return (req, res) => {
|
|
39354
|
+
void (async () => {
|
|
39355
|
+
if (req.method !== "POST") {
|
|
39356
|
+
sendJsonResponse(res, 405, { ok: false, error: "Method not allowed" });
|
|
39357
|
+
return;
|
|
39358
|
+
}
|
|
39359
|
+
try {
|
|
39360
|
+
const body = await readJsonBody(req);
|
|
39361
|
+
if (req.url === "/tools/list") {
|
|
39362
|
+
const tools = await Promise.resolve(registry2.listTools());
|
|
39363
|
+
sendJsonResponse(res, 200, { ok: true, data: tools });
|
|
39364
|
+
return;
|
|
39365
|
+
}
|
|
39366
|
+
if (req.url === "/tools/call") {
|
|
39367
|
+
const sessionId = typeof body.sessionId === "string" ? body.sessionId.trim() : "";
|
|
39368
|
+
if (!sessionId) {
|
|
39369
|
+
sendJsonResponse(res, 400, { ok: false, error: "sessionId is required" });
|
|
39370
|
+
return;
|
|
39371
|
+
}
|
|
39372
|
+
const name = typeof body.name === "string" ? body.name.trim() : "";
|
|
39373
|
+
const args = body.args && typeof body.args === "object" && !Array.isArray(body.args) ? body.args : {};
|
|
39374
|
+
if (!name) {
|
|
39375
|
+
sendJsonResponse(res, 400, { ok: false, error: "name is required" });
|
|
39376
|
+
return;
|
|
39377
|
+
}
|
|
39378
|
+
const data = await registry2.callTool(name, { ...args, sessionId });
|
|
39379
|
+
sendJsonResponse(res, 200, { ok: true, data });
|
|
39380
|
+
return;
|
|
39381
|
+
}
|
|
39382
|
+
sendJsonResponse(res, 404, { ok: false, error: "Not found" });
|
|
39383
|
+
} catch (err) {
|
|
39384
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
39385
|
+
sendJsonResponse(res, 500, { ok: false, error: message });
|
|
39386
|
+
}
|
|
39387
|
+
})();
|
|
39388
|
+
};
|
|
39389
|
+
}
|
|
39390
|
+
|
|
39391
|
+
// src/mcp/bridge-access/start-server.ts
|
|
39392
|
+
function startBridgeAccessServer(registry2) {
|
|
39393
|
+
const server = http.createServer(createBridgeAccessRequestHandler(registry2));
|
|
39394
|
+
return new Promise((resolve20, reject) => {
|
|
39395
|
+
server.once("error", reject);
|
|
39396
|
+
server.listen(0, "127.0.0.1", () => {
|
|
39397
|
+
const addr = server.address();
|
|
39398
|
+
if (!addr || typeof addr === "string") {
|
|
39399
|
+
reject(new Error("Bridge access server did not bind"));
|
|
39400
|
+
return;
|
|
39401
|
+
}
|
|
39402
|
+
resolve20({
|
|
39403
|
+
port: addr.port,
|
|
39404
|
+
close: () => new Promise((closeResolve, closeReject) => {
|
|
39405
|
+
server.close((err) => err ? closeReject(err) : closeResolve());
|
|
39406
|
+
})
|
|
39407
|
+
});
|
|
39408
|
+
});
|
|
39409
|
+
});
|
|
39410
|
+
}
|
|
39411
|
+
|
|
39412
|
+
// src/mcp/bridge-access/create-state.ts
|
|
39413
|
+
async function createBridgeAccessState(options = {}) {
|
|
39414
|
+
const registry2 = createBridgeMcpToolRegistry({
|
|
39415
|
+
cloudApiBaseUrl: options.cloudApiBaseUrl,
|
|
39416
|
+
getCloudAccessToken: options.getCloudAccessToken,
|
|
39417
|
+
e2ee: options.e2ee
|
|
39418
|
+
});
|
|
39419
|
+
const server = await startBridgeAccessServer(registry2);
|
|
39420
|
+
return {
|
|
39421
|
+
getPort: () => server.port,
|
|
39422
|
+
getRegistry: () => registry2,
|
|
39423
|
+
close: async () => {
|
|
39424
|
+
await server.close();
|
|
39425
|
+
}
|
|
39426
|
+
};
|
|
39427
|
+
}
|
|
39428
|
+
|
|
38730
39429
|
// src/connection/create-bridge-connection.ts
|
|
38731
39430
|
async function createBridgeConnection(options) {
|
|
38732
39431
|
const { apiUrl, workspaceId, justAuthenticated, onAuthInvalid, persistTokens } = options;
|
|
@@ -38789,12 +39488,18 @@ async function createBridgeConnection(options) {
|
|
|
38789
39488
|
worktreesRootPath,
|
|
38790
39489
|
log: logFn
|
|
38791
39490
|
});
|
|
39491
|
+
const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
|
|
39492
|
+
const bridgeAccess = await createBridgeAccessState({
|
|
39493
|
+
cloudApiBaseUrl: apiUrl,
|
|
39494
|
+
getCloudAccessToken: () => tokens.accessToken,
|
|
39495
|
+
e2ee
|
|
39496
|
+
});
|
|
38792
39497
|
const acpManager = await createAcpManager({
|
|
38793
39498
|
log: logFn,
|
|
39499
|
+
getBridgeAccessPort: () => bridgeAccess.getPort(),
|
|
38794
39500
|
reportAgentCapabilities: sendAgentCapabilitiesToBridge
|
|
38795
39501
|
});
|
|
38796
39502
|
logFn("CLI running. Press Ctrl+C to exit.");
|
|
38797
|
-
const e2ee = options.e2eCertificate ? createCliE2eeRuntime(options.e2eCertificate) : void 0;
|
|
38798
39503
|
const devServerManager = new DevServerManager({ getWs, log: logFn, getBridgeRoot, e2ee });
|
|
38799
39504
|
const bridgeHeartbeat = createBridgeHeartbeatController({ getWs, log: logFn });
|
|
38800
39505
|
const baseOnBridgeIdentified = createOnBridgeIdentified({
|
|
@@ -38834,8 +39539,8 @@ async function createBridgeConnection(options) {
|
|
|
38834
39539
|
getCloudAccessToken: () => tokens.accessToken
|
|
38835
39540
|
};
|
|
38836
39541
|
const identifyReportedPaths = {
|
|
38837
|
-
bridgeRootPath:
|
|
38838
|
-
worktreesRootPath:
|
|
39542
|
+
bridgeRootPath: path45.resolve(getBridgeRoot()),
|
|
39543
|
+
worktreesRootPath: path45.resolve(worktreesRootPath)
|
|
38839
39544
|
};
|
|
38840
39545
|
const { connect } = createMainBridgeWebSocketLifecycle({
|
|
38841
39546
|
state,
|
|
@@ -38860,6 +39565,7 @@ async function createBridgeConnection(options) {
|
|
|
38860
39565
|
stopFileIndexWatcher();
|
|
38861
39566
|
bridgeHeartbeat.stop();
|
|
38862
39567
|
await closeBridgeConnection(state, acpManager, devServerManager, logFn);
|
|
39568
|
+
await bridgeAccess.close();
|
|
38863
39569
|
}
|
|
38864
39570
|
};
|
|
38865
39571
|
}
|